|
@@ -0,0 +1,634 @@
|
|
|
+//
|
|
|
+// LBXScanWrapper.swift
|
|
|
+// swiftScan
|
|
|
+//
|
|
|
+// Created by lbxia on 15/12/10.
|
|
|
+// Copyright © 2015年 xialibing. All rights reserved.
|
|
|
+//
|
|
|
+
|
|
|
+import UIKit
|
|
|
+import AVFoundation
|
|
|
+
|
|
|
+public struct LBXScanResult {
|
|
|
+
|
|
|
+ //码内容
|
|
|
+ public var strScanned: String? = ""
|
|
|
+ //扫描图像
|
|
|
+ public var imgScanned: UIImage?
|
|
|
+ //码的类型
|
|
|
+ public var strBarCodeType: String? = ""
|
|
|
+
|
|
|
+ //码在图像中的位置
|
|
|
+ public var arrayCorner: [AnyObject]?
|
|
|
+
|
|
|
+ public init(str: String?, img: UIImage?, barCodeType: String?, corner: [AnyObject]?) {
|
|
|
+ self.strScanned = str
|
|
|
+ self.imgScanned = img
|
|
|
+ self.strBarCodeType = barCodeType
|
|
|
+ self.arrayCorner = corner
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+public enum ScannerError: Error {
|
|
|
+ case noCaptureDevice
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+open class LBXScanWrapper: NSObject, AVCaptureMetadataOutputObjectsDelegate,AVCaptureVideoDataOutputSampleBufferDelegate {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ let device: AVCaptureDevice
|
|
|
+
|
|
|
+ var input: AVCaptureDeviceInput
|
|
|
+ var output: AVCaptureMetadataOutput
|
|
|
+ var videoDataOutput : AVCaptureVideoDataOutput
|
|
|
+ let session = AVCaptureSession()
|
|
|
+ var previewLayer: AVCaptureVideoPreviewLayer?
|
|
|
+ var stillImageOutput: AVCaptureStillImageOutput?
|
|
|
+
|
|
|
+
|
|
|
+ //存储返回结果
|
|
|
+ var arrayResult: [LBXScanResult] = []
|
|
|
+
|
|
|
+ //扫码结果返回block
|
|
|
+ var successBlock: ([LBXScanResult]) -> Void
|
|
|
+
|
|
|
+ typealias BrightnessValueBlock = (_ brightnessValue: Float) -> Void
|
|
|
+ var brightnessValueBlock : BrightnessValueBlock?
|
|
|
+
|
|
|
+ //是否需要拍照
|
|
|
+ var isNeedCaptureImage: Bool
|
|
|
+
|
|
|
+ //当前扫码结果是否处理
|
|
|
+ var isNeedScanResult: Bool = true
|
|
|
+
|
|
|
+ /**
|
|
|
+ 初始化设备
|
|
|
+ - parameter videoPreView: 视频显示UIView
|
|
|
+ - parameter objType: 识别码的类型,缺省值 QR二维码
|
|
|
+ - parameter isCaptureImg: 识别后是否采集当前照片
|
|
|
+ - parameter cropRect: 识别区域
|
|
|
+ - parameter success: 返回识别信息
|
|
|
+ - returns:
|
|
|
+ */
|
|
|
+ init(videoPreView: UIView, objType: [AVMetadataObject.ObjectType] = [.qr], isCaptureImg: Bool, cropRect: CGRect=CGRect.zero, success:@escaping ( ([LBXScanResult]) -> Void) )
|
|
|
+ throws {
|
|
|
+
|
|
|
+ guard let device = AVCaptureDevice.default(for: AVMediaType.video) else {
|
|
|
+ throw ScannerError.noCaptureDevice
|
|
|
+ }
|
|
|
+ self.device = device
|
|
|
+
|
|
|
+ do {
|
|
|
+ input = try AVCaptureDeviceInput(device: device)
|
|
|
+ } catch let error as NSError {
|
|
|
+ throw error
|
|
|
+ }
|
|
|
+
|
|
|
+ successBlock = success
|
|
|
+
|
|
|
+ // Output
|
|
|
+ output = AVCaptureMetadataOutput()
|
|
|
+ isNeedCaptureImage = isCaptureImg
|
|
|
+ stillImageOutput = AVCaptureStillImageOutput()
|
|
|
+ videoDataOutput = AVCaptureVideoDataOutput()
|
|
|
+
|
|
|
+ super.init()
|
|
|
+
|
|
|
+ if session.canAddInput(input) {
|
|
|
+ session.addInput(input)
|
|
|
+ }
|
|
|
+ if session.canAddOutput(output) {
|
|
|
+ session.addOutput(output)
|
|
|
+ }
|
|
|
+ if session.canAddOutput(stillImageOutput!) {
|
|
|
+ session.addOutput(stillImageOutput!)
|
|
|
+ }
|
|
|
+ if session.canAddOutput(videoDataOutput) {
|
|
|
+ session.addOutput(videoDataOutput)
|
|
|
+ }
|
|
|
+
|
|
|
+ let outputSettings: Dictionary = [AVVideoCodecJPEG: AVVideoCodecKey]
|
|
|
+ stillImageOutput?.outputSettings = outputSettings
|
|
|
+
|
|
|
+ session.sessionPreset = AVCaptureSession.Preset.high
|
|
|
+
|
|
|
+ //参数设置
|
|
|
+ output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
|
|
|
+ videoDataOutput.setSampleBufferDelegate(self, queue: .main)
|
|
|
+
|
|
|
+
|
|
|
+ output.metadataObjectTypes = objType
|
|
|
+
|
|
|
+ // output.metadataObjectTypes = [AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code]
|
|
|
+
|
|
|
+ if !cropRect.equalTo(CGRect.zero) {
|
|
|
+ //启动相机后,直接修改该参数无效
|
|
|
+ output.rectOfInterest = cropRect
|
|
|
+ }
|
|
|
+
|
|
|
+ previewLayer = AVCaptureVideoPreviewLayer(session: session)
|
|
|
+ previewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
|
|
|
+
|
|
|
+ var frame: CGRect = videoPreView.frame
|
|
|
+ frame.origin = CGPoint.zero
|
|
|
+ previewLayer?.frame = frame
|
|
|
+
|
|
|
+ videoPreView.layer .insertSublayer(previewLayer!, at: 0)
|
|
|
+
|
|
|
+ if (device.isFocusPointOfInterestSupported && device.isFocusModeSupported(AVCaptureDevice.FocusMode.continuousAutoFocus) ) {
|
|
|
+ do {
|
|
|
+ try input.device.lockForConfiguration()
|
|
|
+
|
|
|
+ input.device.focusMode = AVCaptureDevice.FocusMode.continuousAutoFocus
|
|
|
+
|
|
|
+ input.device.unlockForConfiguration()
|
|
|
+ } catch let error as NSError {
|
|
|
+ print("device.lockForConfiguration(): \(error)")
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
|
|
|
+ captureOutput(output, didOutputMetadataObjects: metadataObjects, from: connection)
|
|
|
+ }
|
|
|
+
|
|
|
+ func start() {
|
|
|
+ if !session.isRunning {
|
|
|
+ isNeedScanResult = true
|
|
|
+ session.startRunning()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ func stop() {
|
|
|
+ if session.isRunning {
|
|
|
+ isNeedScanResult = false
|
|
|
+ session.stopRunning()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ open func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
|
|
|
+
|
|
|
+ if !isNeedScanResult {
|
|
|
+ //上一帧处理中
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ isNeedScanResult = false
|
|
|
+
|
|
|
+ arrayResult.removeAll()
|
|
|
+
|
|
|
+ //识别扫码类型
|
|
|
+ for current: Any in metadataObjects {
|
|
|
+ if (current as AnyObject).isKind(of: AVMetadataMachineReadableCodeObject.self) {
|
|
|
+ let code = current as! AVMetadataMachineReadableCodeObject
|
|
|
+
|
|
|
+ //码类型
|
|
|
+ let codeType = code.type
|
|
|
+ // print("code type:%@",codeType)
|
|
|
+ //码内容
|
|
|
+ let codeContent = code.stringValue
|
|
|
+ // print("code string:%@",codeContent)
|
|
|
+
|
|
|
+ //4个字典,分别 左上角-右上角-右下角-左下角的 坐标百分百,可以使用这个比例抠出码的图像
|
|
|
+ // let arrayRatio = code.corners
|
|
|
+
|
|
|
+ arrayResult.append(LBXScanResult(str: codeContent, img: UIImage(), barCodeType: codeType.rawValue, corner: code.corners as [AnyObject]?))
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if arrayResult.count > 0 {
|
|
|
+ if isNeedCaptureImage {
|
|
|
+ captureImage()
|
|
|
+ } else {
|
|
|
+ stop()
|
|
|
+ successBlock(arrayResult)
|
|
|
+ }
|
|
|
+
|
|
|
+ } else {
|
|
|
+ isNeedScanResult = true
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ //监听光线亮度
|
|
|
+ open func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
|
|
|
+ let metadataDict = CMCopyDictionaryOfAttachments(allocator: nil, target: sampleBuffer, attachmentMode: kCMAttachmentMode_ShouldPropagate)
|
|
|
+
|
|
|
+
|
|
|
+ if let metadata = metadataDict as? [AnyHashable: Any] {
|
|
|
+ if let exifMetadata = metadata[kCGImagePropertyExifDictionary as String] as? [AnyHashable: Any] {
|
|
|
+ if let brightness = exifMetadata[kCGImagePropertyExifBrightnessValue as String] as? NSNumber {
|
|
|
+ // 亮度值
|
|
|
+ let brightnessValue = brightness.floatValue
|
|
|
+
|
|
|
+// if self.brightnessValueBlock != nil {
|
|
|
+ self.brightnessValueBlock!(brightnessValue)
|
|
|
+// }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // MARK: - ---拍照
|
|
|
+ open func captureImage() {
|
|
|
+ let stillImageConnection: AVCaptureConnection? = connectionWithMediaType(mediaType: AVMediaType.video as AVMediaType, connections: (stillImageOutput?.connections)! as [AnyObject])
|
|
|
+
|
|
|
+ stillImageOutput?.captureStillImageAsynchronously(from: stillImageConnection!, completionHandler: { (imageDataSampleBuffer, error) -> Void in
|
|
|
+
|
|
|
+ self.stop()
|
|
|
+ if imageDataSampleBuffer != nil {
|
|
|
+ let imageData: Data = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer!)!
|
|
|
+ let scanImg: UIImage? = UIImage(data: imageData)
|
|
|
+
|
|
|
+ for idx in 0...self.arrayResult.count-1 {
|
|
|
+ self.arrayResult[idx].imgScanned = scanImg
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ self.successBlock(self.arrayResult)
|
|
|
+
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ open func connectionWithMediaType(mediaType: AVMediaType, connections: [AnyObject]) -> AVCaptureConnection? {
|
|
|
+ for connection: AnyObject in connections {
|
|
|
+ let connectionTmp: AVCaptureConnection = connection as! AVCaptureConnection
|
|
|
+
|
|
|
+ for port: Any in connectionTmp.inputPorts {
|
|
|
+ if (port as AnyObject).isKind(of: AVCaptureInput.Port.self) {
|
|
|
+ let portTmp: AVCaptureInput.Port = port as! AVCaptureInput.Port
|
|
|
+ if portTmp.mediaType == (mediaType) {
|
|
|
+ return connectionTmp
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ // MARK: 切换识别区域
|
|
|
+ open func changeScanRect(cropRect: CGRect) {
|
|
|
+ //待测试,不知道是否有效
|
|
|
+ stop()
|
|
|
+ output.rectOfInterest = cropRect
|
|
|
+ start()
|
|
|
+ }
|
|
|
+
|
|
|
+ // MARK: 切换识别码的类型
|
|
|
+ open func changeScanType(objType: [AVMetadataObject.ObjectType]) {
|
|
|
+ //待测试中途修改是否有效
|
|
|
+ output.metadataObjectTypes = objType
|
|
|
+ }
|
|
|
+
|
|
|
+ open func isGetFlash() -> Bool {
|
|
|
+ if (device.hasFlash && device.hasTorch) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ 打开或关闭闪关灯
|
|
|
+ - parameter torch: true:打开闪关灯 false:关闭闪光灯
|
|
|
+ */
|
|
|
+ open func setTorch(torch: Bool) {
|
|
|
+ if isGetFlash() {
|
|
|
+ do {
|
|
|
+ try input.device.lockForConfiguration()
|
|
|
+
|
|
|
+ input.device.torchMode = torch ? AVCaptureDevice.TorchMode.on : AVCaptureDevice.TorchMode.off
|
|
|
+
|
|
|
+ input.device.unlockForConfiguration()
|
|
|
+ } catch let error as NSError {
|
|
|
+ print("device.lockForConfiguration(): \(error)")
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ ------闪光灯打开或关闭
|
|
|
+ */
|
|
|
+ open func changeTorch() {
|
|
|
+ if isGetFlash() {
|
|
|
+ do {
|
|
|
+ try input.device.lockForConfiguration()
|
|
|
+
|
|
|
+ var torch = false
|
|
|
+
|
|
|
+ if input.device.torchMode == AVCaptureDevice.TorchMode.on {
|
|
|
+ torch = false
|
|
|
+ } else if input.device.torchMode == AVCaptureDevice.TorchMode.off {
|
|
|
+ torch = true
|
|
|
+ }
|
|
|
+
|
|
|
+ input.device.torchMode = torch ? AVCaptureDevice.TorchMode.on : AVCaptureDevice.TorchMode.off
|
|
|
+
|
|
|
+ input.device.unlockForConfiguration()
|
|
|
+ } catch let error as NSError {
|
|
|
+ print("device.lockForConfiguration(): \(error)")
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // MARK: - -----获取系统默认支持的码的类型
|
|
|
+ static func defaultMetaDataObjectTypes() ->[AVMetadataObject.ObjectType] {
|
|
|
+ var types: [AVMetadataObject.ObjectType] = [.qr, .upce, .code39, .code39Mod43, .ean13, .ean8, .code93, .code128, .pdf417, .aztec]
|
|
|
+
|
|
|
+ //if #available(iOS 8.0, *)
|
|
|
+ types += [.interleaved2of5, .itf14, .dataMatrix]
|
|
|
+ return types
|
|
|
+ }
|
|
|
+
|
|
|
+ static func isSysIos8Later() -> Bool {
|
|
|
+ // return floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_8_0
|
|
|
+
|
|
|
+ if #available(iOS 8, *) {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ 识别二维码码图像
|
|
|
+
|
|
|
+ - parameter image: 二维码图像
|
|
|
+
|
|
|
+ - returns: 返回识别结果
|
|
|
+ */
|
|
|
+ static public func recognizeQRImage(image: UIImage) -> [LBXScanResult] {
|
|
|
+ var returnResult: [LBXScanResult]=[]
|
|
|
+
|
|
|
+ if LBXScanWrapper.isSysIos8Later() {
|
|
|
+ //if #available(iOS 8.0, *)
|
|
|
+
|
|
|
+ let detector: CIDetector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy: CIDetectorAccuracyHigh])!
|
|
|
+
|
|
|
+ let img = CIImage(cgImage: (image.cgImage)!)
|
|
|
+
|
|
|
+ let features: [CIFeature]? = detector.features(in: img, options: [CIDetectorAccuracy: CIDetectorAccuracyHigh])
|
|
|
+
|
|
|
+ if( features != nil && (features?.count)! > 0) {
|
|
|
+ let feature = features![0]
|
|
|
+
|
|
|
+ if feature.isKind(of: CIQRCodeFeature.self) {
|
|
|
+ let featureTmp: CIQRCodeFeature = feature as! CIQRCodeFeature
|
|
|
+
|
|
|
+ let scanResult = featureTmp.messageString
|
|
|
+
|
|
|
+ let result = LBXScanResult(str: scanResult, img: image, barCodeType: AVMetadataObject.ObjectType.qr.rawValue, corner: nil)
|
|
|
+
|
|
|
+ returnResult.append(result)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return returnResult
|
|
|
+ }
|
|
|
+
|
|
|
+ // MARK: - - - 生成二维码,背景色及二维码颜色设置
|
|
|
+ static public func createCode( codeType: String, codeString: String, size: CGSize, qrColor: UIColor, bkColor: UIColor ) -> UIImage? {
|
|
|
+ //if #available(iOS 8.0, *)
|
|
|
+
|
|
|
+ let stringData = codeString.data(using: String.Encoding.utf8)
|
|
|
+
|
|
|
+ //系统自带能生成的码
|
|
|
+ // CIAztecCodeGenerator
|
|
|
+ // CICode128BarcodeGenerator
|
|
|
+ // CIPDF417BarcodeGenerator
|
|
|
+ // CIQRCodeGenerator
|
|
|
+ let qrFilter = CIFilter(name: "codeType")
|
|
|
+
|
|
|
+ qrFilter?.setValue(stringData, forKey: "inputMessage")
|
|
|
+
|
|
|
+ qrFilter?.setValue("H", forKey: "inputCorrectionLevel")
|
|
|
+
|
|
|
+ //上色
|
|
|
+ let colorFilter = CIFilter(name: "CIFalseColor", parameters: ["inputImage": qrFilter!.outputImage!, "inputColor0": CIColor(cgColor: qrColor.cgColor), "inputColor1": CIColor(cgColor: bkColor.cgColor)])
|
|
|
+
|
|
|
+ let qrImage = colorFilter!.outputImage!
|
|
|
+
|
|
|
+ //绘制
|
|
|
+ let cgImage = CIContext().createCGImage(qrImage, from: qrImage.extent)!
|
|
|
+
|
|
|
+ UIGraphicsBeginImageContext(size)
|
|
|
+ let context = UIGraphicsGetCurrentContext()!
|
|
|
+ context.interpolationQuality = CGInterpolationQuality.none
|
|
|
+ context.scaleBy(x: 1.0, y: -1.0)
|
|
|
+ context.draw(cgImage, in: context.boundingBoxOfClipPath)
|
|
|
+ let codeImage = UIGraphicsGetImageFromCurrentImageContext()
|
|
|
+ UIGraphicsEndImageContext()
|
|
|
+
|
|
|
+ return codeImage
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ static public func createCode128( codeString: String, size: CGSize, qrColor: UIColor, bkColor: UIColor ) -> UIImage? {
|
|
|
+ let stringData = codeString.data(using: String.Encoding.utf8)
|
|
|
+
|
|
|
+ //系统自带能生成的码
|
|
|
+ // CIAztecCodeGenerator 二维码
|
|
|
+ // CICode128BarcodeGenerator 条形码
|
|
|
+ // CIPDF417BarcodeGenerator
|
|
|
+ // CIQRCodeGenerator 二维码
|
|
|
+ let qrFilter = CIFilter(name: "CICode128BarcodeGenerator")
|
|
|
+ qrFilter?.setDefaults()
|
|
|
+ qrFilter?.setValue(stringData, forKey: "inputMessage")
|
|
|
+
|
|
|
+ let outputImage: CIImage? = qrFilter?.outputImage
|
|
|
+ let context = CIContext()
|
|
|
+ let cgImage = context.createCGImage(outputImage!, from: outputImage!.extent)
|
|
|
+
|
|
|
+ let image = UIImage(cgImage: cgImage!, scale: 1.0, orientation: UIImage.Orientation.up)
|
|
|
+
|
|
|
+ // Resize without interpolating
|
|
|
+ let scaleRate: CGFloat = 20.0
|
|
|
+ let resized = resizeImage(image: image, quality: CGInterpolationQuality.none, rate: scaleRate)
|
|
|
+
|
|
|
+ return resized
|
|
|
+ }
|
|
|
+
|
|
|
+ // MARK: 根据扫描结果,获取图像中得二维码区域图像(如果相机拍摄角度故意很倾斜,获取的图像效果很差)
|
|
|
+ static func getConcreteCodeImage(srcCodeImage: UIImage, codeResult: LBXScanResult) -> UIImage? {
|
|
|
+ let rect: CGRect = getConcreteCodeRectFromImage(srcCodeImage: srcCodeImage, codeResult: codeResult)
|
|
|
+
|
|
|
+ if rect.isEmpty {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ let img = imageByCroppingWithStyle(srcImg: srcCodeImage, rect: rect)
|
|
|
+
|
|
|
+ if img != nil {
|
|
|
+ let imgRotation = imageRotation(image: img!, orientation: UIImage.Orientation.right)
|
|
|
+ return imgRotation
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ //根据二维码的区域截取二维码区域图像
|
|
|
+ static public func getConcreteCodeImage(srcCodeImage: UIImage, rect: CGRect) -> UIImage? {
|
|
|
+ if rect.isEmpty {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ let img = imageByCroppingWithStyle(srcImg: srcCodeImage, rect: rect)
|
|
|
+
|
|
|
+ if img != nil {
|
|
|
+ let imgRotation = imageRotation(image: img!, orientation: UIImage.Orientation.right)
|
|
|
+ return imgRotation
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ //获取二维码的图像区域
|
|
|
+ static public func getConcreteCodeRectFromImage(srcCodeImage: UIImage, codeResult: LBXScanResult) -> CGRect {
|
|
|
+ if (codeResult.arrayCorner == nil || (codeResult.arrayCorner?.count)! < 4 ) {
|
|
|
+ return CGRect.zero
|
|
|
+ }
|
|
|
+
|
|
|
+ let corner: [[String: Float]] = codeResult.arrayCorner as! [[String: Float]]
|
|
|
+
|
|
|
+ let dicTopLeft = corner[0]
|
|
|
+ let dicTopRight = corner[1]
|
|
|
+ let dicBottomRight = corner[2]
|
|
|
+ let dicBottomLeft = corner[3]
|
|
|
+
|
|
|
+ let xLeftTopRatio: Float = dicTopLeft["X"]!
|
|
|
+ let yLeftTopRatio: Float = dicTopLeft["Y"]!
|
|
|
+
|
|
|
+ let xRightTopRatio: Float = dicTopRight["X"]!
|
|
|
+ let yRightTopRatio: Float = dicTopRight["Y"]!
|
|
|
+
|
|
|
+ let xBottomRightRatio: Float = dicBottomRight["X"]!
|
|
|
+ let yBottomRightRatio: Float = dicBottomRight["Y"]!
|
|
|
+
|
|
|
+ let xLeftBottomRatio: Float = dicBottomLeft["X"]!
|
|
|
+ let yLeftBottomRatio: Float = dicBottomLeft["Y"]!
|
|
|
+
|
|
|
+ //由于截图只能矩形,所以截图不规则四边形的最大外围
|
|
|
+ let xMinLeft = CGFloat( min(xLeftTopRatio, xLeftBottomRatio) )
|
|
|
+ let xMaxRight = CGFloat( max(xRightTopRatio, xBottomRightRatio) )
|
|
|
+
|
|
|
+ let yMinTop = CGFloat( min(yLeftTopRatio, yRightTopRatio) )
|
|
|
+ let yMaxBottom = CGFloat ( max(yLeftBottomRatio, yBottomRightRatio) )
|
|
|
+
|
|
|
+ let imgW = srcCodeImage.size.width
|
|
|
+ let imgH = srcCodeImage.size.height
|
|
|
+
|
|
|
+ //宽高反过来计算
|
|
|
+ let rect = CGRect(x: xMinLeft * imgH, y: yMinTop*imgW, width: (xMaxRight-xMinLeft)*imgH, height: (yMaxBottom-yMinTop)*imgW)
|
|
|
+ return rect
|
|
|
+ }
|
|
|
+
|
|
|
+ // MARK: - ---图像处理
|
|
|
+
|
|
|
+ /**
|
|
|
+ @brief 图像中间加logo图片
|
|
|
+ @param srcImg 原图像
|
|
|
+ @param LogoImage logo图像
|
|
|
+ @param logoSize logo图像尺寸
|
|
|
+ @return 加Logo的图像
|
|
|
+ */
|
|
|
+ static public func addImageLogo(srcImg: UIImage, logoImg: UIImage, logoSize: CGSize ) -> UIImage {
|
|
|
+ UIGraphicsBeginImageContext(srcImg.size)
|
|
|
+ srcImg.draw(in: CGRect(x: 0, y: 0, width: srcImg.size.width, height: srcImg.size.height))
|
|
|
+ let rect = CGRect(x: srcImg.size.width/2 - logoSize.width/2, y: srcImg.size.height/2-logoSize.height/2, width: logoSize.width, height: logoSize.height)
|
|
|
+ logoImg.draw(in: rect)
|
|
|
+ let resultingImage = UIGraphicsGetImageFromCurrentImageContext()
|
|
|
+ UIGraphicsEndImageContext()
|
|
|
+ return resultingImage!
|
|
|
+ }
|
|
|
+
|
|
|
+ //图像缩放
|
|
|
+ static func resizeImage(image: UIImage, quality: CGInterpolationQuality, rate: CGFloat) -> UIImage? {
|
|
|
+ var resized: UIImage?
|
|
|
+ let width = image.size.width * rate
|
|
|
+ let height = image.size.height * rate
|
|
|
+
|
|
|
+ UIGraphicsBeginImageContext(CGSize(width: width, height: height))
|
|
|
+ let context = UIGraphicsGetCurrentContext()
|
|
|
+ context!.interpolationQuality = quality
|
|
|
+ image.draw(in: CGRect(x: 0, y: 0, width: width, height: height))
|
|
|
+
|
|
|
+ resized = UIGraphicsGetImageFromCurrentImageContext()
|
|
|
+ UIGraphicsEndImageContext()
|
|
|
+
|
|
|
+ return resized
|
|
|
+ }
|
|
|
+
|
|
|
+ //图像裁剪
|
|
|
+ static func imageByCroppingWithStyle(srcImg: UIImage, rect: CGRect) -> UIImage? {
|
|
|
+ let imageRef = srcImg.cgImage
|
|
|
+ let imagePartRef = imageRef!.cropping(to: rect)
|
|
|
+ let cropImage = UIImage(cgImage: imagePartRef!)
|
|
|
+
|
|
|
+ return cropImage
|
|
|
+ }
|
|
|
+ //图像旋转
|
|
|
+ static func imageRotation(image: UIImage, orientation: UIImage.Orientation) -> UIImage {
|
|
|
+ var rotate: Double = 0.0
|
|
|
+ var rect: CGRect
|
|
|
+ var translateX: CGFloat = 0.0
|
|
|
+ var translateY: CGFloat = 0.0
|
|
|
+ var scaleX: CGFloat = 1.0
|
|
|
+ var scaleY: CGFloat = 1.0
|
|
|
+
|
|
|
+ switch (orientation) {
|
|
|
+ case UIImage.Orientation.left:
|
|
|
+ rotate = .pi/2
|
|
|
+ rect = CGRect(x: 0, y: 0, width: image.size.height, height: image.size.width)
|
|
|
+ translateX = 0
|
|
|
+ translateY = -rect.size.width
|
|
|
+ scaleY = rect.size.width/rect.size.height
|
|
|
+ scaleX = rect.size.height/rect.size.width
|
|
|
+ break
|
|
|
+ case UIImage.Orientation.right:
|
|
|
+ rotate = 3 * .pi/2
|
|
|
+ rect = CGRect(x: 0, y: 0, width: image.size.height, height: image.size.width)
|
|
|
+ translateX = -rect.size.height
|
|
|
+ translateY = 0
|
|
|
+ scaleY = rect.size.width/rect.size.height
|
|
|
+ scaleX = rect.size.height/rect.size.width
|
|
|
+ break
|
|
|
+ case UIImage.Orientation.down:
|
|
|
+ rotate = .pi
|
|
|
+ rect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)
|
|
|
+ translateX = -rect.size.width
|
|
|
+ translateY = -rect.size.height
|
|
|
+ break
|
|
|
+ default:
|
|
|
+ rotate = 0.0
|
|
|
+ rect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)
|
|
|
+ translateX = 0
|
|
|
+ translateY = 0
|
|
|
+ break
|
|
|
+ }
|
|
|
+
|
|
|
+ UIGraphicsBeginImageContext(rect.size)
|
|
|
+ let context = UIGraphicsGetCurrentContext()!
|
|
|
+ //做CTM变换
|
|
|
+ context.translateBy(x: 0.0, y: rect.size.height)
|
|
|
+ context.scaleBy(x: 1.0, y: -1.0)
|
|
|
+ context.rotate(by: CGFloat(rotate))
|
|
|
+ context.translateBy(x: translateX, y: translateY)
|
|
|
+
|
|
|
+ context.scaleBy(x: scaleX, y: scaleY)
|
|
|
+ //绘制图片
|
|
|
+ context.draw(image.cgImage!, in: CGRect(x: 0, y: 0, width: rect.size.width, height: rect.size.height))
|
|
|
+ let newPic = UIGraphicsGetImageFromCurrentImageContext()
|
|
|
+
|
|
|
+ return newPic!
|
|
|
+ }
|
|
|
+
|
|
|
+ deinit {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|