LBXScanWrapper.swift 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. //
  2. // LBXScanWrapper.swift
  3. // swiftScan
  4. //
  5. // Created by lbxia on 15/12/10.
  6. // Copyright © 2015年 xialibing. All rights reserved.
  7. //
  8. import UIKit
  9. import AVFoundation
  10. public struct LBXScanResult {
  11. //码内容
  12. public var strScanned:String? = ""
  13. //扫描图像
  14. public var imgScanned:UIImage?
  15. //码的类型
  16. public var strBarCodeType:String? = ""
  17. //码在图像中的位置
  18. public var arrayCorner:[AnyObject]?
  19. public init(str:String?,img:UIImage?,barCodeType:String?,corner:[AnyObject]?)
  20. {
  21. self.strScanned = str
  22. self.imgScanned = img
  23. self.strBarCodeType = barCodeType
  24. self.arrayCorner = corner
  25. }
  26. }
  27. open class LBXScanWrapper: NSObject,AVCaptureMetadataOutputObjectsDelegate {
  28. let device = AVCaptureDevice.default(for: AVMediaType.video)
  29. var input:AVCaptureDeviceInput?
  30. var output:AVCaptureMetadataOutput
  31. let session = AVCaptureSession()
  32. var previewLayer:AVCaptureVideoPreviewLayer?
  33. var stillImageOutput:AVCaptureStillImageOutput?
  34. //存储返回结果
  35. var arrayResult:[LBXScanResult] = [];
  36. //扫码结果返回block
  37. var successBlock:([LBXScanResult]) -> Void
  38. //是否需要拍照
  39. var isNeedCaptureImage:Bool
  40. //当前扫码结果是否处理
  41. var isNeedScanResult:Bool = true
  42. /**
  43. 初始化设备
  44. - parameter videoPreView: 视频显示UIView
  45. - parameter objType: 识别码的类型,缺省值 QR二维码
  46. - parameter isCaptureImg: 识别后是否采集当前照片
  47. - parameter cropRect: 识别区域
  48. - parameter success: 返回识别信息
  49. - returns:
  50. */
  51. init( videoPreView:UIView,objType:[AVMetadataObject.ObjectType] = [(AVMetadataObject.ObjectType.qr as NSString) as AVMetadataObject.ObjectType],isCaptureImg:Bool,cropRect:CGRect=CGRect.zero,success:@escaping ( ([LBXScanResult]) -> Void) )
  52. {
  53. do{
  54. input = try AVCaptureDeviceInput(device: device!)
  55. }
  56. catch let error as NSError {
  57. print("AVCaptureDeviceInput(): \(error)")
  58. }
  59. successBlock = success
  60. // Output
  61. output = AVCaptureMetadataOutput()
  62. isNeedCaptureImage = isCaptureImg
  63. stillImageOutput = AVCaptureStillImageOutput();
  64. super.init()
  65. if device == nil || input == nil {
  66. return
  67. }
  68. if session.canAddInput(input!) {
  69. session.addInput(input!)
  70. }
  71. if session.canAddOutput(output) {
  72. session.addOutput(output)
  73. }
  74. if session.canAddOutput(stillImageOutput!) {
  75. session.addOutput(stillImageOutput!)
  76. }
  77. let outputSettings:Dictionary = [AVVideoCodecJPEG:AVVideoCodecKey]
  78. stillImageOutput?.outputSettings = outputSettings
  79. session.sessionPreset = AVCaptureSession.Preset.high
  80. //参数设置
  81. output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
  82. output.metadataObjectTypes = objType
  83. // output.metadataObjectTypes = [AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code]
  84. if !cropRect.equalTo(CGRect.zero)
  85. {
  86. //启动相机后,直接修改该参数无效
  87. output.rectOfInterest = cropRect
  88. }
  89. previewLayer = AVCaptureVideoPreviewLayer(session: session)
  90. previewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
  91. var frame:CGRect = videoPreView.frame
  92. frame.origin = CGPoint.zero
  93. previewLayer?.frame = frame
  94. videoPreView.layer .insertSublayer(previewLayer!, at: 0)
  95. if ( device!.isFocusPointOfInterestSupported && device!.isFocusModeSupported(AVCaptureDevice.FocusMode.continuousAutoFocus) )
  96. {
  97. do
  98. {
  99. try input?.device.lockForConfiguration()
  100. input?.device.focusMode = AVCaptureDevice.FocusMode.continuousAutoFocus
  101. input?.device.unlockForConfiguration()
  102. }
  103. catch let error as NSError {
  104. print("device.lockForConfiguration(): \(error)")
  105. }
  106. }
  107. }
  108. public func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
  109. captureOutput(output, didOutputMetadataObjects: metadataObjects, from: connection)
  110. }
  111. func start()
  112. {
  113. if !session.isRunning
  114. {
  115. isNeedScanResult = true
  116. session.startRunning()
  117. }
  118. }
  119. func stop()
  120. {
  121. if session.isRunning
  122. {
  123. isNeedScanResult = false
  124. session.stopRunning()
  125. }
  126. }
  127. open func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
  128. if !isNeedScanResult
  129. {
  130. //上一帧处理中
  131. return
  132. }
  133. isNeedScanResult = false
  134. arrayResult.removeAll()
  135. //识别扫码类型
  136. for current:Any in metadataObjects
  137. {
  138. if (current as AnyObject).isKind(of: AVMetadataMachineReadableCodeObject.self)
  139. {
  140. let code = current as! AVMetadataMachineReadableCodeObject
  141. //码类型
  142. let codeType = code.type
  143. // print("code type:%@",codeType)
  144. //码内容
  145. let codeContent = code.stringValue
  146. // print("code string:%@",codeContent)
  147. //4个字典,分别 左上角-右上角-右下角-左下角的 坐标百分百,可以使用这个比例抠出码的图像
  148. // let arrayRatio = code.corners
  149. arrayResult.append(LBXScanResult(str: codeContent, img: UIImage(), barCodeType: codeType.rawValue, corner: code.corners as [AnyObject]?))
  150. }
  151. }
  152. if arrayResult.count > 0
  153. {
  154. if isNeedCaptureImage
  155. {
  156. captureImage()
  157. }
  158. else
  159. {
  160. stop()
  161. successBlock(arrayResult)
  162. }
  163. }
  164. else
  165. {
  166. isNeedScanResult = true
  167. }
  168. }
  169. //MARK: ----拍照
  170. open func captureImage()
  171. {
  172. let stillImageConnection:AVCaptureConnection? = connectionWithMediaType(mediaType: AVMediaType.video as AVMediaType, connections: (stillImageOutput?.connections)! as [AnyObject])
  173. stillImageOutput?.captureStillImageAsynchronously(from: stillImageConnection!, completionHandler: { (imageDataSampleBuffer, error) -> Void in
  174. self.stop()
  175. if imageDataSampleBuffer != nil
  176. {
  177. let imageData: Data = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer!)!
  178. let scanImg:UIImage? = UIImage(data: imageData)
  179. for idx in 0...self.arrayResult.count-1
  180. {
  181. self.arrayResult[idx].imgScanned = scanImg
  182. }
  183. }
  184. self.successBlock(self.arrayResult)
  185. })
  186. }
  187. open func connectionWithMediaType(mediaType:AVMediaType, connections:[AnyObject]) -> AVCaptureConnection?
  188. {
  189. for connection:AnyObject in connections
  190. {
  191. let connectionTmp:AVCaptureConnection = connection as! AVCaptureConnection
  192. for port:Any in connectionTmp.inputPorts
  193. {
  194. if (port as AnyObject).isKind(of: AVCaptureInput.Port.self)
  195. {
  196. let portTmp:AVCaptureInput.Port = port as! AVCaptureInput.Port
  197. if portTmp.mediaType == mediaType
  198. {
  199. return connectionTmp
  200. }
  201. }
  202. }
  203. }
  204. return nil
  205. }
  206. //MARK:切换识别区域
  207. open func changeScanRect(cropRect:CGRect)
  208. {
  209. //待测试,不知道是否有效
  210. stop()
  211. output.rectOfInterest = cropRect
  212. start()
  213. }
  214. //MARK: 切换识别码的类型
  215. open func changeScanType(objType:[AVMetadataObject.ObjectType])
  216. {
  217. //待测试中途修改是否有效
  218. output.metadataObjectTypes = objType
  219. }
  220. open func isGetFlash()->Bool
  221. {
  222. if (device != nil && device!.hasFlash && device!.hasTorch)
  223. {
  224. return true
  225. }
  226. return false
  227. }
  228. /**
  229. 打开或关闭闪关灯
  230. - parameter torch: true:打开闪关灯 false:关闭闪光灯
  231. */
  232. open func setTorch(torch:Bool)
  233. {
  234. if isGetFlash()
  235. {
  236. do
  237. {
  238. try input?.device.lockForConfiguration()
  239. input?.device.torchMode = torch ? AVCaptureDevice.TorchMode.on : AVCaptureDevice.TorchMode.off
  240. input?.device.unlockForConfiguration()
  241. }
  242. catch let error as NSError {
  243. print("device.lockForConfiguration(): \(error)")
  244. }
  245. }
  246. }
  247. /**
  248. ------闪光灯打开或关闭
  249. */
  250. open func changeTorch()
  251. {
  252. if isGetFlash()
  253. {
  254. do
  255. {
  256. try input?.device.lockForConfiguration()
  257. var torch = false
  258. if input?.device.torchMode == AVCaptureDevice.TorchMode.on
  259. {
  260. torch = false
  261. }
  262. else if input?.device.torchMode == AVCaptureDevice.TorchMode.off
  263. {
  264. torch = true
  265. }
  266. input?.device.torchMode = torch ? AVCaptureDevice.TorchMode.on : AVCaptureDevice.TorchMode.off
  267. input?.device.unlockForConfiguration()
  268. }
  269. catch let error as NSError {
  270. print("device.lockForConfiguration(): \(error)")
  271. }
  272. }
  273. }
  274. //MARK: ------获取系统默认支持的码的类型
  275. static func defaultMetaDataObjectTypes() ->[AVMetadataObject.ObjectType]
  276. {
  277. var types =
  278. [AVMetadataObject.ObjectType.qr,
  279. AVMetadataObject.ObjectType.upce,
  280. AVMetadataObject.ObjectType.code39,
  281. AVMetadataObject.ObjectType.code39Mod43,
  282. AVMetadataObject.ObjectType.ean13,
  283. AVMetadataObject.ObjectType.ean8,
  284. AVMetadataObject.ObjectType.code93,
  285. AVMetadataObject.ObjectType.code128,
  286. AVMetadataObject.ObjectType.pdf417,
  287. AVMetadataObject.ObjectType.aztec
  288. ]
  289. //if #available(iOS 8.0, *)
  290. types.append(AVMetadataObject.ObjectType.interleaved2of5)
  291. types.append(AVMetadataObject.ObjectType.itf14)
  292. types.append(AVMetadataObject.ObjectType.dataMatrix)
  293. return types as [AVMetadataObject.ObjectType]
  294. }
  295. static func isSysIos8Later()->Bool
  296. {
  297. // return floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_8_0
  298. if #available(iOS 8, *) {
  299. return true;
  300. }
  301. return false
  302. }
  303. /**
  304. 识别二维码码图像
  305. - parameter image: 二维码图像
  306. - returns: 返回识别结果
  307. */
  308. static public func recognizeQRImage(image:UIImage) ->[LBXScanResult]
  309. {
  310. var returnResult:[LBXScanResult]=[]
  311. if LBXScanWrapper.isSysIos8Later()
  312. {
  313. //if #available(iOS 8.0, *)
  314. let detector:CIDetector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh])!
  315. let img = CIImage(cgImage: (image.cgImage)!)
  316. let features:[CIFeature]? = detector.features(in: img, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh])
  317. if( features != nil && (features?.count)! > 0)
  318. {
  319. let feature = features![0]
  320. if feature.isKind(of: CIQRCodeFeature.self)
  321. {
  322. let featureTmp:CIQRCodeFeature = feature as! CIQRCodeFeature
  323. let scanResult = featureTmp.messageString
  324. let result = LBXScanResult(str: scanResult, img: image, barCodeType: AVMetadataObject.ObjectType.qr.rawValue,corner: nil)
  325. returnResult.append(result)
  326. }
  327. }
  328. }
  329. return returnResult
  330. }
  331. //MARK: -- - 生成二维码,背景色及二维码颜色设置
  332. static public func createCode( codeType:String, codeString:String, size:CGSize,qrColor:UIColor,bkColor:UIColor )->UIImage?
  333. {
  334. //if #available(iOS 8.0, *)
  335. let stringData = codeString.data(using: String.Encoding.utf8)
  336. //系统自带能生成的码
  337. // CIAztecCodeGenerator
  338. // CICode128BarcodeGenerator
  339. // CIPDF417BarcodeGenerator
  340. // CIQRCodeGenerator
  341. let qrFilter = CIFilter(name: codeType)
  342. qrFilter?.setValue(stringData, forKey: "inputMessage")
  343. qrFilter?.setValue("H", forKey: "inputCorrectionLevel")
  344. //上色
  345. let colorFilter = CIFilter(name: "CIFalseColor", parameters: ["inputImage":qrFilter!.outputImage!,"inputColor0":CIColor(cgColor: qrColor.cgColor),"inputColor1":CIColor(cgColor: bkColor.cgColor)])
  346. let qrImage = colorFilter!.outputImage!;
  347. //绘制
  348. let cgImage = CIContext().createCGImage(qrImage, from: qrImage.extent)!
  349. UIGraphicsBeginImageContext(size);
  350. let context = UIGraphicsGetCurrentContext()!;
  351. context.interpolationQuality = CGInterpolationQuality.none;
  352. context.scaleBy(x: 1.0, y: -1.0);
  353. context.draw(cgImage, in: context.boundingBoxOfClipPath)
  354. let codeImage = UIGraphicsGetImageFromCurrentImageContext();
  355. UIGraphicsEndImageContext();
  356. return codeImage
  357. }
  358. static public func createCode128( codeString:String, size:CGSize,qrColor:UIColor,bkColor:UIColor )->UIImage?
  359. {
  360. let stringData = codeString.data(using: String.Encoding.utf8)
  361. //系统自带能生成的码
  362. // CIAztecCodeGenerator 二维码
  363. // CICode128BarcodeGenerator 条形码
  364. // CIPDF417BarcodeGenerator
  365. // CIQRCodeGenerator 二维码
  366. let qrFilter = CIFilter(name: "CICode128BarcodeGenerator")
  367. qrFilter?.setDefaults()
  368. qrFilter?.setValue(stringData, forKey: "inputMessage")
  369. let outputImage:CIImage? = qrFilter?.outputImage
  370. let context = CIContext()
  371. let cgImage = context.createCGImage(outputImage!, from: outputImage!.extent)
  372. let image = UIImage(cgImage: cgImage!, scale: 1.0, orientation: UIImage.Orientation.up)
  373. // Resize without interpolating
  374. let scaleRate:CGFloat = 20.0
  375. let resized = resizeImage(image: image, quality: CGInterpolationQuality.none, rate: scaleRate)
  376. return resized;
  377. }
  378. //MARK:根据扫描结果,获取图像中得二维码区域图像(如果相机拍摄角度故意很倾斜,获取的图像效果很差)
  379. static func getConcreteCodeImage(srcCodeImage:UIImage,codeResult:LBXScanResult)->UIImage?
  380. {
  381. let rect:CGRect = getConcreteCodeRectFromImage(srcCodeImage: srcCodeImage, codeResult: codeResult)
  382. if rect.isEmpty
  383. {
  384. return nil
  385. }
  386. let img = imageByCroppingWithStyle(srcImg: srcCodeImage, rect: rect)
  387. if img != nil
  388. {
  389. let imgRotation = imageRotation(image: img!, orientation: UIImage.Orientation.right)
  390. return imgRotation
  391. }
  392. return nil
  393. }
  394. //根据二维码的区域截取二维码区域图像
  395. static public func getConcreteCodeImage(srcCodeImage:UIImage,rect:CGRect)->UIImage?
  396. {
  397. if rect.isEmpty
  398. {
  399. return nil
  400. }
  401. let img = imageByCroppingWithStyle(srcImg: srcCodeImage, rect: rect)
  402. if img != nil
  403. {
  404. let imgRotation = imageRotation(image: img!, orientation: UIImage.Orientation.right)
  405. return imgRotation
  406. }
  407. return nil
  408. }
  409. //获取二维码的图像区域
  410. static public func getConcreteCodeRectFromImage(srcCodeImage:UIImage,codeResult:LBXScanResult)->CGRect
  411. {
  412. if (codeResult.arrayCorner == nil || (codeResult.arrayCorner?.count)! < 4 )
  413. {
  414. return CGRect.zero
  415. }
  416. let corner:[[String:Float]] = codeResult.arrayCorner as! [[String:Float]]
  417. let dicTopLeft = corner[0]
  418. let dicTopRight = corner[1]
  419. let dicBottomRight = corner[2]
  420. let dicBottomLeft = corner[3]
  421. let xLeftTopRatio:Float = dicTopLeft["X"]!
  422. let yLeftTopRatio:Float = dicTopLeft["Y"]!
  423. let xRightTopRatio:Float = dicTopRight["X"]!
  424. let yRightTopRatio:Float = dicTopRight["Y"]!
  425. let xBottomRightRatio:Float = dicBottomRight["X"]!
  426. let yBottomRightRatio:Float = dicBottomRight["Y"]!
  427. let xLeftBottomRatio:Float = dicBottomLeft["X"]!
  428. let yLeftBottomRatio:Float = dicBottomLeft["Y"]!
  429. //由于截图只能矩形,所以截图不规则四边形的最大外围
  430. let xMinLeft = CGFloat( min(xLeftTopRatio, xLeftBottomRatio) )
  431. let xMaxRight = CGFloat( max(xRightTopRatio, xBottomRightRatio) )
  432. let yMinTop = CGFloat( min(yLeftTopRatio, yRightTopRatio) )
  433. let yMaxBottom = CGFloat ( max(yLeftBottomRatio, yBottomRightRatio) )
  434. let imgW = srcCodeImage.size.width
  435. let imgH = srcCodeImage.size.height
  436. //宽高反过来计算
  437. let rect = CGRect(x: xMinLeft * imgH, y: yMinTop*imgW, width: (xMaxRight-xMinLeft)*imgH, height: (yMaxBottom-yMinTop)*imgW)
  438. return rect
  439. }
  440. //MARK: ----图像处理
  441. /**
  442. @brief 图像中间加logo图片
  443. @param srcImg 原图像
  444. @param LogoImage logo图像
  445. @param logoSize logo图像尺寸
  446. @return 加Logo的图像
  447. */
  448. static public func addImageLogo(srcImg:UIImage,logoImg:UIImage,logoSize:CGSize )->UIImage
  449. {
  450. UIGraphicsBeginImageContext(srcImg.size);
  451. srcImg.draw(in: CGRect(x: 0, y: 0, width: srcImg.size.width, height: srcImg.size.height))
  452. 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);
  453. logoImg.draw(in: rect)
  454. let resultingImage = UIGraphicsGetImageFromCurrentImageContext();
  455. UIGraphicsEndImageContext();
  456. return resultingImage!;
  457. }
  458. //图像缩放
  459. static func resizeImage(image:UIImage,quality:CGInterpolationQuality,rate:CGFloat)->UIImage?
  460. {
  461. var resized:UIImage?;
  462. let width = image.size.width * rate;
  463. let height = image.size.height * rate;
  464. UIGraphicsBeginImageContext(CGSize(width: width, height: height));
  465. let context = UIGraphicsGetCurrentContext();
  466. context!.interpolationQuality = quality;
  467. image.draw(in: CGRect(x: 0, y: 0, width: width, height: height))
  468. resized = UIGraphicsGetImageFromCurrentImageContext();
  469. UIGraphicsEndImageContext();
  470. return resized;
  471. }
  472. //图像裁剪
  473. static func imageByCroppingWithStyle(srcImg:UIImage,rect:CGRect)->UIImage?
  474. {
  475. let imageRef = srcImg.cgImage
  476. let imagePartRef = imageRef!.cropping(to: rect)
  477. let cropImage = UIImage(cgImage: imagePartRef!)
  478. return cropImage
  479. }
  480. //图像旋转
  481. static func imageRotation(image:UIImage,orientation:UIImage.Orientation)->UIImage
  482. {
  483. var rotate:Double = 0.0;
  484. var rect:CGRect;
  485. var translateX:CGFloat = 0.0;
  486. var translateY:CGFloat = 0.0;
  487. var scaleX:CGFloat = 1.0;
  488. var scaleY:CGFloat = 1.0;
  489. switch (orientation) {
  490. case UIImage.Orientation.left:
  491. rotate = .pi/2;
  492. rect = CGRect(x: 0, y: 0, width: image.size.height, height: image.size.width);
  493. translateX = 0;
  494. translateY = -rect.size.width;
  495. scaleY = rect.size.width/rect.size.height;
  496. scaleX = rect.size.height/rect.size.width;
  497. break;
  498. case UIImage.Orientation.right:
  499. rotate = 3 * .pi/2;
  500. rect = CGRect(x: 0, y: 0, width: image.size.height, height: image.size.width);
  501. translateX = -rect.size.height;
  502. translateY = 0;
  503. scaleY = rect.size.width/rect.size.height;
  504. scaleX = rect.size.height/rect.size.width;
  505. break;
  506. case UIImage.Orientation.down:
  507. rotate = .pi;
  508. rect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height);
  509. translateX = -rect.size.width;
  510. translateY = -rect.size.height;
  511. break;
  512. default:
  513. rotate = 0.0;
  514. rect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height);
  515. translateX = 0;
  516. translateY = 0;
  517. break;
  518. }
  519. UIGraphicsBeginImageContext(rect.size);
  520. let context = UIGraphicsGetCurrentContext()!;
  521. //做CTM变换
  522. context.translateBy(x: 0.0, y: rect.size.height);
  523. context.scaleBy(x: 1.0, y: -1.0);
  524. context.rotate(by: CGFloat(rotate));
  525. context.translateBy(x: translateX, y: translateY);
  526. context.scaleBy(x: scaleX, y: scaleY);
  527. //绘制图片
  528. context.draw(image.cgImage!, in: CGRect(x: 0, y: 0, width: rect.size.width, height: rect.size.height))
  529. let newPic = UIGraphicsGetImageFromCurrentImageContext();
  530. return newPic!;
  531. }
  532. deinit
  533. {
  534. // print("LBXScanWrapper deinit")
  535. }
  536. }