南鑫林 vor 6 Jahren
Ursprung
Commit
44bf012530

+ 48 - 0
RainbowPlanet/RainbowPlanet.xcodeproj/project.pbxproj

@@ -71,6 +71,14 @@
 		A71AF0BC226F099B001730FE /* ProductHBigTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A71AF0BB226F099B001730FE /* ProductHBigTableViewCell.swift */; };
 		A71AF0BE226F1792001730FE /* ShoppingMallModule.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A71AF0BD226F1792001730FE /* ShoppingMallModule.xcassets */; };
 		A71D2A602265673A00A55D16 /* RegisterLoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A71D2A5F2265673A00A55D16 /* RegisterLoginView.swift */; };
+		A7274C50228EE5F0000E3A07 /* PhotoAndCameraManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7274C4F228EE5EF000E3A07 /* PhotoAndCameraManager.swift */; };
+		A7274C59228EE636000E3A07 /* LBXScanNetAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7274C52228EE635000E3A07 /* LBXScanNetAnimation.swift */; };
+		A7274C5A228EE636000E3A07 /* LBXScanView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7274C53228EE635000E3A07 /* LBXScanView.swift */; };
+		A7274C5B228EE636000E3A07 /* LBXScanViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7274C54228EE635000E3A07 /* LBXScanViewController.swift */; };
+		A7274C5C228EE636000E3A07 /* LBXScanLineAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7274C55228EE635000E3A07 /* LBXScanLineAnimation.swift */; };
+		A7274C5D228EE636000E3A07 /* LBXScanViewStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7274C56228EE635000E3A07 /* LBXScanViewStyle.swift */; };
+		A7274C5E228EE636000E3A07 /* LBXPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7274C57228EE635000E3A07 /* LBXPermissions.swift */; };
+		A7274C5F228EE636000E3A07 /* LBXScanWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7274C58228EE635000E3A07 /* LBXScanWrapper.swift */; };
 		A72843FC224DB6B800F82F30 /* SwiftMoyaServiceUserApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = A72843FB224DB6B800F82F30 /* SwiftMoyaServiceUserApi.swift */; };
 		A7284401224DBB7700F82F30 /* SwiftMoyaNetWorkServiceUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7284400224DBB7700F82F30 /* SwiftMoyaNetWorkServiceUser.swift */; };
 		A7284404224DBFBD00F82F30 /* UserModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7284403224DBFBD00F82F30 /* UserModel.swift */; };
@@ -435,6 +443,14 @@
 		A71AF0BB226F099B001730FE /* ProductHBigTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductHBigTableViewCell.swift; sourceTree = "<group>"; };
 		A71AF0BD226F1792001730FE /* ShoppingMallModule.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = ShoppingMallModule.xcassets; sourceTree = "<group>"; };
 		A71D2A5F2265673A00A55D16 /* RegisterLoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterLoginView.swift; sourceTree = "<group>"; };
+		A7274C4F228EE5EF000E3A07 /* PhotoAndCameraManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoAndCameraManager.swift; sourceTree = "<group>"; };
+		A7274C52228EE635000E3A07 /* LBXScanNetAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LBXScanNetAnimation.swift; sourceTree = "<group>"; };
+		A7274C53228EE635000E3A07 /* LBXScanView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LBXScanView.swift; sourceTree = "<group>"; };
+		A7274C54228EE635000E3A07 /* LBXScanViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LBXScanViewController.swift; sourceTree = "<group>"; };
+		A7274C55228EE635000E3A07 /* LBXScanLineAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LBXScanLineAnimation.swift; sourceTree = "<group>"; };
+		A7274C56228EE635000E3A07 /* LBXScanViewStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LBXScanViewStyle.swift; sourceTree = "<group>"; };
+		A7274C57228EE635000E3A07 /* LBXPermissions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LBXPermissions.swift; sourceTree = "<group>"; };
+		A7274C58228EE635000E3A07 /* LBXScanWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LBXScanWrapper.swift; sourceTree = "<group>"; };
 		A72843FB224DB6B800F82F30 /* SwiftMoyaServiceUserApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftMoyaServiceUserApi.swift; sourceTree = "<group>"; };
 		A7284400224DBB7700F82F30 /* SwiftMoyaNetWorkServiceUser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftMoyaNetWorkServiceUser.swift; sourceTree = "<group>"; };
 		A7284403224DBFBD00F82F30 /* UserModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserModel.swift; sourceTree = "<group>"; };
@@ -1257,6 +1273,28 @@
 			path = SwiftMoyaServiceApi;
 			sourceTree = "<group>";
 		};
+		A7274C4E228EE5EF000E3A07 /* PhotoAndCameraManager */ = {
+			isa = PBXGroup;
+			children = (
+				A7274C4F228EE5EF000E3A07 /* PhotoAndCameraManager.swift */,
+			);
+			path = PhotoAndCameraManager;
+			sourceTree = "<group>";
+		};
+		A7274C51228EE635000E3A07 /* SwiftScan */ = {
+			isa = PBXGroup;
+			children = (
+				A7274C52228EE635000E3A07 /* LBXScanNetAnimation.swift */,
+				A7274C53228EE635000E3A07 /* LBXScanView.swift */,
+				A7274C54228EE635000E3A07 /* LBXScanViewController.swift */,
+				A7274C55228EE635000E3A07 /* LBXScanLineAnimation.swift */,
+				A7274C56228EE635000E3A07 /* LBXScanViewStyle.swift */,
+				A7274C57228EE635000E3A07 /* LBXPermissions.swift */,
+				A7274C58228EE635000E3A07 /* LBXScanWrapper.swift */,
+			);
+			path = SwiftScan;
+			sourceTree = "<group>";
+		};
 		A72843FD224DB79400F82F30 /* SwiftMoyaServiceUser */ = {
 			isa = PBXGroup;
 			children = (
@@ -2072,6 +2110,8 @@
 		A77F2CBC2232022A001BD3F6 /* Tools */ = {
 			isa = PBXGroup;
 			children = (
+				A7274C51228EE635000E3A07 /* SwiftScan */,
+				A7274C4E228EE5EF000E3A07 /* PhotoAndCameraManager */,
 				A70B2C232286C03800B2449F /* NXLPageControl */,
 				A7D4608C227616E600A5A54E /* FMDB */,
 				A71901712275F56C00104A50 /* BaiduToCityFactory */,
@@ -3241,6 +3281,7 @@
 				A77F2C9E2231FDDC001BD3F6 /* BaseViewController.swift in Sources */,
 				A7284A75225465DD000BAEC4 /* SwiftMoyaNetWorkServicePay.swift in Sources */,
 				A77F2CC722320627001BD3F6 /* WRNavigationBar.swift in Sources */,
+				A7274C5E228EE636000E3A07 /* LBXPermissions.swift in Sources */,
 				A7D46092227619CD00A5A54E /* BaiduToCityFactory.swift in Sources */,
 				A71AA51C227219EF008FF1A5 /* EditExpressAddressView.swift in Sources */,
 				BDAA40FB228E9CC300CF841D /* OrderApplyRefundNoteInfoCell.swift in Sources */,
@@ -3343,6 +3384,7 @@
 				A7A98E0B227EBD04005306E9 /* CategorySearchView.swift in Sources */,
 				A72A73142232475E00B21995 /* AlipayManager.swift in Sources */,
 				A7824B042271F10300ABA381 /* EditSelfMentionContactsView.swift in Sources */,
+				A7274C5B228EE636000E3A07 /* LBXScanViewController.swift in Sources */,
 				A7FF1566228C6DF200A85748 /* OrderShopAndStatusTableViewCell.swift in Sources */,
 				A7A98E332280272A005306E9 /* ShoppingMallBannerTableViewCell.swift in Sources */,
 				BDF862AA228E43A4000DEF84 /* OrderCommentTableViewCell.swift in Sources */,
@@ -3418,6 +3460,7 @@
 				A7A98E17227EED76005306E9 /* SpecialViewController.swift in Sources */,
 				A7778CB32244D73400C7C47A /* RegisterLoginViewController.swift in Sources */,
 				BD7AB8432284390B0030646A /* OrderPaySelfPickInfoCell.swift in Sources */,
+				A7274C5F228EE636000E3A07 /* LBXScanWrapper.swift in Sources */,
 				A7CC752F2271A1F2003C4F38 /* SetPasswordView.swift in Sources */,
 				A7A98E09227EB8DD005306E9 /* CategoryView.swift in Sources */,
 				A7CC75362271AC14003C4F38 /* AddressManagerView.swift in Sources */,
@@ -3427,6 +3470,7 @@
 				A7BB685922696B9200AB07A2 /* SelfRecommendationCollectionViewCell.swift in Sources */,
 				A7636AC822682BAF00374F9E /* LocationView.swift in Sources */,
 				A738D205225AF90D00EEE860 /* WeChatpayOrderModel.swift in Sources */,
+				A7274C5C228EE636000E3A07 /* LBXScanLineAnimation.swift in Sources */,
 				A7CC7524227190FB003C4F38 /* AccountSecurityView.swift in Sources */,
 				BD1DC6CB228D157000B89C57 /* OrderCreateBackModel.swift in Sources */,
 				A72A72BD22321DE000B21995 /* Extension+UIColor.swift in Sources */,
@@ -3474,6 +3518,7 @@
 				BD1DC6C9228D005000B89C57 /* OrderCreateParameterModel.swift in Sources */,
 				A71AA52622732068008FF1A5 /* SwiftMoyaServiceConfigApi.swift in Sources */,
 				A77F2C982231FD25001BD3F6 /* BaseNavigationViewController.swift in Sources */,
+				A7274C5D228EE636000E3A07 /* LBXScanViewStyle.swift in Sources */,
 				A7A98E1B227EEE49005306E9 /* SpecialView.swift in Sources */,
 				BDF47D7A228271F600941AB9 /* ShoppingCartView.swift in Sources */,
 				A7824AFB2271EA2600ABA381 /* SelfMentionContactsListView.swift in Sources */,
@@ -3490,11 +3535,13 @@
 				BDF862AE228E57E1000DEF84 /* OrderCommentDefaultCollectionCell.swift in Sources */,
 				A70B2C3E228825B100B2449F /* ProductDetailEvaluationTableViewCell.swift in Sources */,
 				A79057022276C9770037F823 /* SetPasswordModel.swift in Sources */,
+				A7274C5A228EE636000E3A07 /* LBXScanView.swift in Sources */,
 				A7FF1560228C693D00A85748 /* OrderViewController.swift in Sources */,
 				A729B5B42267254B004AE098 /* PasswordLoginViewController.swift in Sources */,
 				A7B4E7582282897B0012914A /* ProductFloorLeftHeaderCollectionReusableView.swift in Sources */,
 				A7D4608E227616F800A5A54E /* SQLiteManager.swift in Sources */,
 				A70B2C6B2288815300B2449F /* PickHeaderView.swift in Sources */,
+				A7274C50228EE5F0000E3A07 /* PhotoAndCameraManager.swift in Sources */,
 				A77F2C612231FB49001BD3F6 /* AppDelegate.swift in Sources */,
 				A729B5A82266F2E0004AE098 /* AlertSheetView.swift in Sources */,
 				A7CC75382271ADD6003C4F38 /* AddressManagerSelfMentionExpressHeaderView.swift in Sources */,
@@ -3522,6 +3569,7 @@
 				A7B4E756228281620012914A /* ShoppingMallSlidingLeftRightBgCollectionViewCell.swift in Sources */,
 				A757C92E22744ACE00226355 /* AddressManagerListModel.swift in Sources */,
 				BDAA40F9228E9ADA00CF841D /* OrderApplyRefundReasonCell.swift in Sources */,
+				A7274C59228EE636000E3A07 /* LBXScanNetAnimation.swift in Sources */,
 				A7541502224C5ECB002480B5 /* BaiduMapManager.swift in Sources */,
 				A757C9342274882E00226355 /* UIScrollView+MJRefreshEX.m in Sources */,
 				A77F2C9C2231FDCF001BD3F6 /* BaseView.swift in Sources */,

+ 92 - 0
RainbowPlanet/RainbowPlanet/Tools/PhotoAndCameraManager/PhotoAndCameraManager.swift

@@ -0,0 +1,92 @@
+//
+//  PhotoManager.swift
+//  CreaditPayment
+//
+//  Created by 南鑫林 on 2018/12/19.
+//  Copyright © 2018 南鑫林. All rights reserved.
+//
+
+import UIKit
+
+class PhotoAndCameraManager: NSObject {
+    private static let _sharedInstance = PhotoAndCameraManager()
+
+    private override init() {} // 私有化init方法
+
+    class func shared() -> PhotoAndCameraManager {
+        return _sharedInstance
+    }
+
+    typealias PhotoAndCameraManagerImageBlock = (_ image: UIImage) -> Void
+
+    var photoAndCameraManagerImageBlock : PhotoAndCameraManagerImageBlock?
+
+    var isEditedImage : Bool = true
+
+
+    /// 相册
+    func authorizePhoto() {
+
+        LBXPermissions.authorizePhotoWith {
+            [weak self] (granted) in
+            guard let strongSelf = self else { return }
+
+            if granted {
+                let picker = UIImagePickerController()
+                picker.sourceType = UIImagePickerController.SourceType.photoLibrary
+                picker.delegate = strongSelf
+                picker.allowsEditing = strongSelf.isEditedImage
+                getCurrentVC().present(picker, animated: true, completion: nil)
+            } else {
+                LBXPermissions.jumpToSystemPrivacySetting()
+            }
+        }
+    }
+
+
+    /// 相机
+    func authorizeCamera() {
+        LBXPermissions.authorizeCameraWith {
+            [weak self] (granted) in
+            guard let strongSelf = self else { return }
+            if granted {
+                let picker = UIImagePickerController()
+                picker.sourceType = UIImagePickerController.SourceType.camera
+                picker.delegate = strongSelf;
+                picker.allowsEditing = strongSelf.isEditedImage
+                getCurrentVC().present(picker, animated: true, completion: nil)
+            } else {
+                LBXPermissions.jumpToSystemPrivacySetting()
+            }
+        }
+    }
+}
+
+extension PhotoAndCameraManager : UIImagePickerControllerDelegate,UINavigationControllerDelegate {
+    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
+        //查看info对象
+        //显示的图片
+        var image : UIImage? = info[.editedImage] as? UIImage
+
+        if (image == nil ) {
+            image = info[.originalImage] as? UIImage
+            return
+        }
+
+        if self.isEditedImage {
+            //获取编辑后的图片
+            image = info[.editedImage] as? UIImage
+        }else{
+            //获取选择的原图
+            image = info[.originalImage] as? UIImage
+        }
+
+        //图片控制器退出
+        picker.dismiss(animated: true, completion: {
+            () -> Void in
+            if self.photoAndCameraManagerImageBlock != nil {
+                self.photoAndCameraManagerImageBlock!(image!)
+            }
+        })
+    }
+}

+ 73 - 0
RainbowPlanet/RainbowPlanet/Tools/SwiftScan/LBXPermissions.swift

@@ -0,0 +1,73 @@
+//
+//  LBXPermissions.swift
+//  swiftScan
+//
+//  Created by xialibing on 15/12/15.
+//  Copyright © 2015年 xialibing. All rights reserved.
+//
+
+import UIKit
+import AVFoundation
+import Photos
+import AssetsLibrary
+
+class LBXPermissions: NSObject {
+
+    // MARK: - ---获取相册权限
+    static func authorizePhotoWith(comletion:@escaping (Bool) -> Void) {
+        let granted = PHPhotoLibrary.authorizationStatus()
+        switch granted {
+        case PHAuthorizationStatus.authorized:
+            comletion(true)
+        case PHAuthorizationStatus.denied, PHAuthorizationStatus.restricted:
+            comletion(false)
+        case PHAuthorizationStatus.notDetermined:
+            PHPhotoLibrary.requestAuthorization({ (status) in
+                DispatchQueue.main.async {
+                    comletion(status == PHAuthorizationStatus.authorized ? true:false)
+                }
+            })
+        default:
+            break
+        }
+    }
+
+    // MARK: - --相机权限
+    static func authorizeCameraWith(comletion:@escaping (Bool) -> Void ) {
+        let granted = AVCaptureDevice.authorizationStatus(for: AVMediaType.video)
+
+        switch granted {
+        case .authorized:
+            comletion(true)
+            break
+        case .denied:
+            comletion(false)
+            break
+        case .restricted:
+            comletion(false)
+            break
+        case .notDetermined:
+            AVCaptureDevice.requestAccess(for: AVMediaType.video, completionHandler: { (granted: Bool) in
+                DispatchQueue.main.async {
+                    comletion(granted)
+                }
+            })
+        default:
+            break
+        }
+    }
+
+    // MARK: 跳转到APP系统设置权限界面
+    static func jumpToSystemPrivacySetting() {
+        let appSetting = URL(string: UIApplication.openSettingsURLString)
+
+        if appSetting != nil {
+            if #available(iOS 10, *) {
+                UIApplication.shared.open(appSetting!, options: [:], completionHandler: nil)
+            } else {
+                UIApplication.shared.openURL(appSetting!)
+            }
+        }
+    }
+
+}

+ 77 - 0
RainbowPlanet/RainbowPlanet/Tools/SwiftScan/LBXScanLineAnimation.swift

@@ -0,0 +1,77 @@
+//
+//  LBXScanLineAnimation.swift
+//  swiftScan
+//
+//  Created by lbxia on 15/12/9.
+//  Copyright © 2015年 xialibing. All rights reserved.
+//
+
+import UIKit
+
+class LBXScanLineAnimation: UIImageView {
+
+    var isAnimationing = false
+    var animationRect: CGRect = CGRect.zero
+
+    func startAnimatingWithRect(animationRect: CGRect, parentView: UIView, image: UIImage?) {
+        self.image = image
+        self.animationRect = animationRect
+        parentView.addSubview(self)
+
+        self.isHidden = false
+
+        isAnimationing = true
+
+        if image != nil {
+            stepAnimation()
+        }
+
+    }
+
+    @objc func stepAnimation() {
+        if (!isAnimationing) {
+            return
+        }
+
+        var frame: CGRect = animationRect
+
+        let hImg = self.image!.size.height * animationRect.size.width / self.image!.size.width
+
+        frame.origin.y -= hImg
+        frame.size.height = hImg
+        self.frame = frame
+        self.alpha = 0.0
+
+        UIView.animate(withDuration: 1.4, animations: { () -> Void in
+
+            self.alpha = 1.0
+
+            var frame = self.animationRect
+            let hImg = self.image!.size.height * self.animationRect.size.width / self.image!.size.width
+
+            frame.origin.y += (frame.size.height -  hImg)
+            frame.size.height = hImg
+
+            self.frame = frame
+
+        }, completion: { (value: Bool) -> Void in
+
+            self.perform(#selector(LBXScanLineAnimation.stepAnimation), with: nil, afterDelay: 0.3)
+        })
+
+    }
+
+    func stopStepAnimating() {
+        self.isHidden = true
+        isAnimationing = false
+    }
+
+    static public func instance() -> LBXScanLineAnimation {
+        return LBXScanLineAnimation()
+    }
+
+    deinit {
+        stopStepAnimating()
+    }
+
+}

+ 72 - 0
RainbowPlanet/RainbowPlanet/Tools/SwiftScan/LBXScanNetAnimation.swift

@@ -0,0 +1,72 @@
+//
+//  LBXScanNetAnimation.swift
+//  swiftScan
+//
+//  Created by lbxia on 15/12/9.
+//  Copyright © 2015年 xialibing. All rights reserved.
+//
+
+import UIKit
+
+class LBXScanNetAnimation: UIImageView {
+
+    var isAnimationing = false
+    var animationRect: CGRect = CGRect.zero
+
+    static public func instance() -> LBXScanNetAnimation {
+        return LBXScanNetAnimation()
+    }
+
+    func startAnimatingWithRect(animationRect: CGRect, parentView: UIView, image: UIImage?) {
+        self.image = image
+        self.animationRect = animationRect
+        parentView.addSubview(self)
+
+        self.isHidden = false
+
+        isAnimationing = true
+
+        if (image != nil) {
+            stepAnimation()
+        }
+
+    }
+
+    @objc func stepAnimation() {
+        if (!isAnimationing) {
+            return
+        }
+        var frame = animationRect
+        let hImg = self.image!.size.height * animationRect.size.width / self.image!.size.width
+
+        frame.origin.y -= hImg
+        frame.size.height = hImg
+        self.frame = frame
+
+        self.alpha = 0.0
+
+        UIView.animate(withDuration: 1.2, animations: { () -> Void in
+
+            self.alpha = 1.0
+
+            var frame = self.animationRect
+            let hImg = self.image!.size.height * self.animationRect.size.width / self.image!.size.width
+
+            frame.origin.y += (frame.size.height -  hImg)
+            frame.size.height = hImg
+
+            self.frame = frame
+
+        }, completion: { (value: Bool) -> Void in
+
+            self.perform(#selector(LBXScanNetAnimation.stepAnimation), with: nil, afterDelay: 0.3)
+
+        })
+    }
+
+    func stopStepAnimating() {
+        self.isHidden = true
+        isAnimationing = false
+    }
+
+}

+ 431 - 0
RainbowPlanet/RainbowPlanet/Tools/SwiftScan/LBXScanView.swift

@@ -0,0 +1,431 @@
+//
+//  LBXScanView.swift
+//  swiftScan
+//
+//  Created by xialibing on 15/12/8.
+//  Copyright © 2015年 xialibing. All rights reserved.
+//
+
+import UIKit
+
+open class LBXScanView: UIView {
+    //扫码区域各种参数
+    var viewStyle: LBXScanViewStyle = LBXScanViewStyle()
+
+    //扫码区域
+    var scanRetangleRect: CGRect = CGRect.zero
+
+    //线条扫码动画封装
+    var scanLineAnimation: LBXScanLineAnimation?
+
+    //网格扫码动画封装
+    var scanNetAnimation: LBXScanNetAnimation?
+
+    //线条在中间位置,不移动
+    var scanLineStill: UIImageView?
+
+    //启动相机时 菊花等待
+    var activityView: UIActivityIndicatorView?
+
+    //启动相机中的提示文字
+    var labelReadying: UILabel?
+
+    //记录动画状态
+    var isAnimationing: Bool = false
+
+    /**
+     初始化扫描界面
+     - parameter frame:  界面大小,一般为视频显示区域
+     - parameter vstyle: 界面效果参数
+     
+     - returns: instancetype
+     */
+    public init(frame: CGRect, vstyle: LBXScanViewStyle ) {
+        viewStyle = vstyle
+
+        switch (viewStyle.anmiationStyle) {
+        case LBXScanViewAnimationStyle.LineMove:
+            scanLineAnimation = LBXScanLineAnimation.instance()
+            break
+        case LBXScanViewAnimationStyle.NetGrid:
+            scanNetAnimation = LBXScanNetAnimation.instance()
+            break
+        case LBXScanViewAnimationStyle.LineStill:
+            scanLineStill = UIImageView()
+            scanLineStill?.image = viewStyle.animationImage
+            break
+
+        default:
+            break
+        }
+
+        var frameTmp = frame
+        frameTmp.origin = CGPoint.zero
+
+        super.init(frame: frameTmp)
+
+        backgroundColor = UIColor.clear
+    }
+
+    override init(frame: CGRect) {
+
+        var frameTmp = frame
+        frameTmp.origin = CGPoint.zero
+
+        super.init(frame: frameTmp)
+
+        backgroundColor = UIColor.clear
+    }
+
+    required public init?(coder aDecoder: NSCoder) {
+        self.init()
+
+    }
+
+    deinit {
+        if (scanLineAnimation != nil) {
+            scanLineAnimation!.stopStepAnimating()
+        }
+        if (scanNetAnimation != nil) {
+            scanNetAnimation!.stopStepAnimating()
+        }
+
+        //        print("LBXScanView deinit")
+    }
+
+    /**
+     *  开始扫描动画
+     */
+    func startScanAnimation() {
+        if isAnimationing {
+            return
+        }
+
+        isAnimationing = true
+
+        let cropRect: CGRect = getScanRectForAnimation()
+
+        switch viewStyle.anmiationStyle {
+        case LBXScanViewAnimationStyle.LineMove:
+
+            //            print(NSStringFromCGRect(cropRect))
+
+            scanLineAnimation!.startAnimatingWithRect(animationRect: cropRect, parentView: self, image: viewStyle.animationImage )
+            break
+        case LBXScanViewAnimationStyle.NetGrid:
+
+            scanNetAnimation!.startAnimatingWithRect(animationRect: cropRect, parentView: self, image: viewStyle.animationImage )
+            break
+        case LBXScanViewAnimationStyle.LineStill:
+
+            let stillRect = CGRect(x: cropRect.origin.x+20,
+                                   y: cropRect.origin.y + cropRect.size.height/2,
+                                   width: cropRect.size.width-40,
+                                   height: 2)
+            self.scanLineStill?.frame = stillRect
+
+            self.addSubview(scanLineStill!)
+            self.scanLineStill?.isHidden = false
+
+            break
+
+        default: break
+
+        }
+    }
+
+    /**
+     *  开始扫描动画
+     */
+    func stopScanAnimation() {
+        isAnimationing = false
+
+        switch viewStyle.anmiationStyle {
+        case LBXScanViewAnimationStyle.LineMove:
+
+            scanLineAnimation?.stopStepAnimating()
+            break
+        case LBXScanViewAnimationStyle.NetGrid:
+
+            scanNetAnimation?.stopStepAnimating()
+            break
+        case LBXScanViewAnimationStyle.LineStill:
+            self.scanLineStill?.isHidden = true
+
+            break
+
+        default: break
+
+        }
+    }
+
+    // Only override drawRect: if you perform custom drawing.
+    // An empty implementation adversely affects performance during animation.
+    override open func draw(_ rect: CGRect) {
+        // Drawing code
+        drawScanRect()
+    }
+
+    // MARK: - ---- 绘制扫码效果-----
+    func drawScanRect() {
+        let XRetangleLeft = viewStyle.xScanRetangleOffset
+        var sizeRetangle = CGSize(width: self.frame.size.width - XRetangleLeft*2.0, height: self.frame.size.width - XRetangleLeft*2.0)
+        if viewStyle.whRatio != 1.0 {
+            let w = sizeRetangle.width
+            var h: CGFloat = w / viewStyle.whRatio
+
+            let hInt: Int = Int(h)
+            h = CGFloat(hInt)
+
+            sizeRetangle = CGSize(width: w, height: h)
+        }
+
+        //扫码区域Y轴最小坐标
+        let YMinRetangle = self.frame.size.height / 2.0 - sizeRetangle.height/2.0 - viewStyle.centerUpOffset
+        let YMaxRetangle = YMinRetangle + sizeRetangle.height
+        let XRetangleRight = self.frame.size.width - XRetangleLeft
+
+        //        print("frame:%@",NSStringFromCGRect(self.frame))
+
+        let context = UIGraphicsGetCurrentContext()!
+
+        //非扫码区域半透明
+        //设置非识别区域颜色
+        context.setFillColor(viewStyle.color_NotRecoginitonArea.cgColor)
+        //填充矩形
+        //扫码区域上面填充
+        var rect = CGRect(x: 0, y: 0, width: self.frame.size.width, height: YMinRetangle)
+        context.fill(rect)
+
+        //扫码区域左边填充
+        rect = CGRect(x: 0, y: YMinRetangle, width: XRetangleLeft, height: sizeRetangle.height)
+        context.fill(rect)
+
+        //扫码区域右边填充
+        rect = CGRect(x: XRetangleRight, y: YMinRetangle, width: XRetangleLeft, height: sizeRetangle.height)
+        context.fill(rect)
+
+        //扫码区域下面填充
+        rect = CGRect(x: 0, y: YMaxRetangle, width: self.frame.size.width, height: self.frame.size.height - YMaxRetangle)
+        context.fill(rect)
+        //执行绘画
+        context.strokePath()
+
+        if viewStyle.isNeedShowRetangle {
+            //中间画矩形(正方形)
+            context.setStrokeColor(viewStyle.colorRetangleLine.cgColor)
+            context.setLineWidth(1)
+
+            context.addRect(CGRect(x: XRetangleLeft, y: YMinRetangle, width: sizeRetangle.width, height: sizeRetangle.height))
+
+            //CGContextMoveToPoint(context, XRetangleLeft, YMinRetangle);
+            //CGContextAddLineToPoint(context, XRetangleLeft+sizeRetangle.width, YMinRetangle);
+
+            context.strokePath()
+
+        }
+        scanRetangleRect = CGRect(x: XRetangleLeft, y: YMinRetangle, width: sizeRetangle.width, height: sizeRetangle.height)
+
+        //画矩形框4格外围相框角
+
+        //相框角的宽度和高度
+        let wAngle = viewStyle.photoframeAngleW
+        let hAngle = viewStyle.photoframeAngleH
+
+        //4个角的 线的宽度
+        let linewidthAngle = viewStyle.photoframeLineW;// 经验参数:6和4
+
+        //画扫码矩形以及周边半透明黑色坐标参数
+        var diffAngle = linewidthAngle/3
+        diffAngle = linewidthAngle / 2; //框外面4个角,与框有缝隙
+        diffAngle = linewidthAngle/2;  //框4个角 在线上加4个角效果
+        diffAngle = 0;//与矩形框重合
+
+        switch viewStyle.photoframeAngleStyle {
+        case LBXScanViewPhotoframeAngleStyle.Outer:
+            diffAngle = linewidthAngle/3//框外面4个角,与框紧密联系在一起
+
+        case LBXScanViewPhotoframeAngleStyle.On:
+            diffAngle = 0
+
+        case LBXScanViewPhotoframeAngleStyle.Inner:
+            diffAngle = -viewStyle.photoframeLineW/2
+        }
+
+        context.setStrokeColor(viewStyle.colorAngle.cgColor)
+        context.setFillColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
+
+        // Draw them with a 2.0 stroke width so they are a bit more visible.
+        context.setLineWidth(linewidthAngle)
+
+        //
+        let leftX = XRetangleLeft - diffAngle
+        let topY = YMinRetangle - diffAngle
+        let rightX = XRetangleRight + diffAngle
+        let bottomY = YMaxRetangle + diffAngle
+
+        //左上角水平线
+        context.move(to: CGPoint(x: leftX-linewidthAngle/2, y: topY))
+        context.addLine(to: CGPoint(x: leftX + wAngle, y: topY))
+
+        //左上角垂直线
+        context.move(to: CGPoint(x: leftX, y: topY-linewidthAngle/2))
+        context.addLine(to: CGPoint(x: leftX, y: topY+hAngle))
+
+        //左下角水平线
+        context.move(to: CGPoint(x: leftX-linewidthAngle/2, y: bottomY))
+        context.addLine(to: CGPoint(x: leftX + wAngle, y: bottomY))
+
+        //左下角垂直线
+        context.move(to: CGPoint(x: leftX, y: bottomY+linewidthAngle/2))
+        context.addLine(to: CGPoint(x: leftX, y: bottomY - hAngle))
+
+        //右上角水平线
+        context.move(to: CGPoint(x: rightX+linewidthAngle/2, y: topY))
+        context.addLine(to: CGPoint(x: rightX - wAngle, y: topY))
+
+        //右上角垂直线
+        context.move(to: CGPoint(x: rightX, y: topY-linewidthAngle/2))
+        context.addLine(to: CGPoint(x: rightX, y: topY + hAngle))
+
+        //右下角水平线
+        context.move(to: CGPoint(x: rightX+linewidthAngle/2, y: bottomY))
+        context.addLine(to: CGPoint(x: rightX - wAngle, y: bottomY))
+
+        //右下角垂直线
+        context.move(to: CGPoint(x: rightX, y: bottomY+linewidthAngle/2))
+        context.addLine(to: CGPoint(x: rightX, y: bottomY - hAngle))
+
+        context.strokePath()
+    }
+
+    func getScanRectForAnimation() -> CGRect {
+        let XRetangleLeft = viewStyle.xScanRetangleOffset
+        var sizeRetangle = CGSize(width: self.frame.size.width - XRetangleLeft*2, height: self.frame.size.width - XRetangleLeft*2)
+
+        if viewStyle.whRatio != 1 {
+            let w = sizeRetangle.width
+            var h = w / viewStyle.whRatio
+
+            let hInt: Int = Int(h)
+            h = CGFloat(hInt)
+
+            sizeRetangle = CGSize(width: w, height: h)
+        }
+
+        //扫码区域Y轴最小坐标
+        let YMinRetangle = self.frame.size.height / 2.0 - sizeRetangle.height/2.0 - viewStyle.centerUpOffset
+        //扫码区域坐标
+        let cropRect =  CGRect(x: XRetangleLeft, y: YMinRetangle, width: sizeRetangle.width, height: sizeRetangle.height)
+
+        return cropRect
+    }
+
+    //根据矩形区域,获取识别区域
+    static func getScanRectWithPreView(preView: UIView, style: LBXScanViewStyle) -> CGRect {
+        let XRetangleLeft = style.xScanRetangleOffset
+        var sizeRetangle = CGSize(width: preView.frame.size.width - XRetangleLeft*2, height: preView.frame.size.width - XRetangleLeft*2)
+
+        if style.whRatio != 1 {
+            let w = sizeRetangle.width
+            var h = w / style.whRatio
+
+            let hInt: Int = Int(h)
+            h = CGFloat(hInt)
+
+            sizeRetangle = CGSize(width: w, height: h)
+        }
+
+        //扫码区域Y轴最小坐标
+        let YMinRetangle = preView.frame.size.height / 2.0 - sizeRetangle.height/2.0 - style.centerUpOffset
+        //扫码区域坐标
+        let cropRect =  CGRect(x: XRetangleLeft, y: YMinRetangle, width: sizeRetangle.width, height: sizeRetangle.height)
+
+        //计算兴趣区域
+        var rectOfInterest: CGRect
+
+        //ref:http://www.cocoachina.com/ios/20141225/10763.html
+        let size = preView.bounds.size
+        let p1 = size.height/size.width
+
+        let p2: CGFloat = 1920.0/1080.0 //使用了1080p的图像输出
+        if p1 < p2 {
+            let fixHeight = size.width * 1920.0 / 1080.0
+            let fixPadding = (fixHeight - size.height)/2
+            rectOfInterest = CGRect(x: (cropRect.origin.y + fixPadding)/fixHeight,
+                                    y: cropRect.origin.x/size.width,
+                                    width: cropRect.size.height/fixHeight,
+                                    height: cropRect.size.width/size.width)
+
+        } else {
+            let fixWidth = size.height * 1080.0 / 1920.0
+            let fixPadding = (fixWidth - size.width)/2
+            rectOfInterest = CGRect(x: cropRect.origin.y/size.height,
+                                    y: (cropRect.origin.x + fixPadding)/fixWidth,
+                                    width: cropRect.size.height/size.height,
+                                    height: cropRect.size.width/fixWidth)
+        }
+        return rectOfInterest
+    }
+
+    func getRetangeSize() -> CGSize {
+        let XRetangleLeft = viewStyle.xScanRetangleOffset
+
+        var sizeRetangle = CGSize(width: self.frame.size.width - XRetangleLeft*2, height: self.frame.size.width - XRetangleLeft*2)
+
+        let w = sizeRetangle.width
+        var h = w / viewStyle.whRatio
+
+        let hInt: Int = Int(h)
+        h = CGFloat(hInt)
+
+        sizeRetangle = CGSize(width: w, height: h)
+
+        return sizeRetangle
+    }
+
+    func deviceStartReadying(readyStr: String) {
+        let XRetangleLeft = viewStyle.xScanRetangleOffset
+
+        let sizeRetangle = getRetangeSize()
+
+        //扫码区域Y轴最小坐标
+        let YMinRetangle = self.frame.size.height / 2.0 - sizeRetangle.height/2.0 - viewStyle.centerUpOffset
+
+        //设备启动状态提示
+        if (activityView == nil) {
+            self.activityView = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
+
+            activityView?.center = CGPoint(x: XRetangleLeft +  sizeRetangle.width/2 - 50, y: YMinRetangle + sizeRetangle.height/2)
+            activityView?.style = UIActivityIndicatorView.Style.whiteLarge
+
+            addSubview(activityView!)
+
+            let labelReadyRect = CGRect(x: activityView!.frame.origin.x + activityView!.frame.size.width + 10, y: activityView!.frame.origin.y, width: 100, height: 30)
+            //print("%@",NSStringFromCGRect(labelReadyRect))
+            self.labelReadying = UILabel(frame: labelReadyRect)
+            labelReadying?.text = readyStr
+            labelReadying?.backgroundColor = UIColor.clear
+            labelReadying?.textColor = UIColor.white
+            labelReadying?.font = UIFont.systemFont(ofSize: 18.0)
+            addSubview(labelReadying!)
+        }
+
+        addSubview(labelReadying!)
+        activityView?.startAnimating()
+
+    }
+
+    func deviceStopReadying() {
+        if activityView != nil {
+            activityView?.stopAnimating()
+            activityView?.removeFromSuperview()
+            labelReadying?.removeFromSuperview()
+
+            activityView = nil
+            labelReadying = nil
+
+        }
+    }
+
+}

+ 207 - 0
RainbowPlanet/RainbowPlanet/Tools/SwiftScan/LBXScanViewController.swift

@@ -0,0 +1,207 @@
+//
+//  LBXScanViewController.swift
+//  swiftScan
+//
+//  Created by lbxia on 15/12/8.
+//  Copyright © 2015年 xialibing. All rights reserved.
+//
+
+import UIKit
+import Foundation
+import AVFoundation
+
+public protocol LBXScanViewControllerDelegate: class {
+    func scanFinished(scanResult: LBXScanResult, error: String?)
+    func brightnessValueChange(brightnessValue: Float)
+}
+
+
+
+open class LBXScanViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
+
+    //返回扫码结果,也可以通过继承本控制器,改写该handleCodeResult方法即可
+    open weak var scanResultDelegate: LBXScanViewControllerDelegate?
+
+    open var scanObj: LBXScanWrapper?
+
+    open var scanStyle: LBXScanViewStyle? = LBXScanViewStyle()
+
+    open var qRScanView: LBXScanView?
+
+    //启动区域识别功能
+    open var isOpenInterestRect = false
+
+    //识别码的类型
+    public var arrayCodeType: [AVMetadataObject.ObjectType]?
+
+    //是否需要识别后的当前图像
+    public  var isNeedCodeImage = false
+
+    //相机启动提示文字
+    public var readyString: String = "loading"
+
+    override open func viewDidLoad() {
+        super.viewDidLoad()
+        self.view.backgroundColor = UIColor.black
+        self.edgesForExtendedLayout = UIRectEdge(rawValue: 0)
+    }
+
+    open func setNeedCodeImage(needCodeImg: Bool) {
+        isNeedCodeImage = needCodeImg
+    }
+    //设置框内识别
+    open func setOpenInterestRect(isOpen: Bool) {
+        isOpenInterestRect = isOpen
+    }
+
+    override open func viewWillAppear(_ animated: Bool) {
+        super.viewWillAppear(animated)
+    }
+
+    override open func viewDidAppear(_ animated: Bool) {
+
+        super.viewDidAppear(animated)
+
+        drawScanView()
+
+        perform(#selector(LBXScanViewController.startScan), with: nil, afterDelay: 0.3)
+
+    }
+
+    @objc open func startScan() {
+
+        if (scanObj == nil) {
+            var cropRect = CGRect.zero
+            if isOpenInterestRect {
+                cropRect = LBXScanView.getScanRectWithPreView(preView: self.view, style: scanStyle! )
+            }
+
+            //指定识别几种码
+            if arrayCodeType == nil {
+                arrayCodeType = [AVMetadataObject.ObjectType.qr, AVMetadataObject.ObjectType.ean13, AVMetadataObject.ObjectType.code128]
+            }
+
+            scanObj = try? LBXScanWrapper(videoPreView: self.view, objType: arrayCodeType!, isCaptureImg: isNeedCodeImage, cropRect: cropRect, success: { [weak self] (arrayResult) -> Void in
+
+                if let strongSelf = self {
+                    //停止扫描动画
+                    strongSelf.qRScanView?.stopScanAnimation()
+
+                    strongSelf.handleCodeResult(arrayResult: arrayResult)
+                }
+            })
+        }
+
+        self.scanObj!.brightnessValueBlock = {
+            [weak self] brightnessValue in
+            guard let strongSelf = self else { return }
+            if strongSelf.scanResultDelegate != nil {
+                strongSelf.scanResultDelegate?.brightnessValueChange(brightnessValue: brightnessValue)
+            }
+
+        }
+
+        //结束相机等待提示
+        qRScanView?.deviceStopReadying()
+
+        //开始扫描动画
+        qRScanView?.startScanAnimation()
+
+        //相机运行
+        scanObj?.start()
+    }
+
+    open func drawScanView() {
+        if qRScanView == nil {
+            qRScanView = LBXScanView(frame: self.view.frame, vstyle: scanStyle! )
+            self.view.addSubview(qRScanView!)
+        }
+        qRScanView?.deviceStartReadying(readyStr: readyString)
+
+    }
+
+    /**
+     处理扫码结果,如果是继承本控制器的,可以重写该方法,作出相应地处理,或者设置delegate作出相应处理
+     */
+    open func handleCodeResult(arrayResult: [LBXScanResult]) {
+        if let delegate = scanResultDelegate {
+
+            let result: LBXScanResult = arrayResult[0]
+
+            delegate.scanFinished(scanResult: result, error: nil)
+
+        } else {
+
+            for result: LBXScanResult in arrayResult {
+                print("%@", result.strScanned ?? "")
+            }
+
+            let result: LBXScanResult = arrayResult[0]
+
+            showMsg(title: result.strBarCodeType, message: result.strScanned)
+        }
+    }
+
+    override open func viewWillDisappear(_ animated: Bool) {
+
+        NSObject.cancelPreviousPerformRequests(withTarget: self)
+
+        qRScanView?.stopScanAnimation()
+
+        scanObj?.stop()
+    }
+
+    open func openPhotoAlbum() {
+        LBXPermissions.authorizePhotoWith { [weak self] (granted) in
+
+            let picker = UIImagePickerController()
+
+            picker.sourceType = UIImagePickerController.SourceType.photoLibrary
+
+            picker.delegate = self
+
+            picker.allowsEditing = true
+
+            self?.present(picker, animated: true, completion: nil)
+        }
+    }
+
+    // MARK: - ----相册选择图片识别二维码 (条形码没有找到系统方法)
+    public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
+
+        var image: UIImage? = info[UIImagePickerController.InfoKey.editedImage] as? UIImage
+
+        if (image == nil ) {
+            image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage
+        }
+
+        if(image != nil) {
+            let arrayResult = LBXScanWrapper.recognizeQRImage(image: image!)
+            if arrayResult.count > 0 {
+                handleCodeResult(arrayResult: arrayResult)
+                return
+            }
+        }
+
+        showMsg(title: nil, message: NSLocalizedString("Identify failed", comment: "Identify failed"))
+    }
+
+    func showMsg(title: String?, message: String?) {
+
+        let alertController = UIAlertController(title: nil, message: message, preferredStyle: UIAlertController.Style.alert)
+        let alertAction = UIAlertAction(title: NSLocalizedString("OK", comment: "OK"), style: UIAlertAction.Style.default) { (alertAction) in
+
+            //                if let strongSelf = self
+            //                {
+            //                    strongSelf.startScan()
+            //                }
+        }
+
+        alertController.addAction(alertAction)
+        present(alertController, animated: true, completion: nil)
+    }
+    deinit {
+        //        print("LBXScanViewController deinit")
+    }
+
+}

+ 90 - 0
RainbowPlanet/RainbowPlanet/Tools/SwiftScan/LBXScanViewStyle.swift

@@ -0,0 +1,90 @@
+//
+//  LBXScanViewStyle.swift
+//  swiftScan
+//
+//  Created by xialibing on 15/12/8.
+//  Copyright © 2015年 xialibing. All rights reserved.
+//
+
+import UIKit
+
+///扫码区域动画效果
+public enum LBXScanViewAnimationStyle {
+    case LineMove   //线条上下移动
+    case NetGrid    //网格
+    case LineStill  //线条停止在扫码区域中央
+    case None       //无动画
+}
+
+///扫码区域4个角位置类型
+public enum LBXScanViewPhotoframeAngleStyle {
+    case Inner//内嵌,一般不显示矩形框情况下
+    case Outer//外嵌,包围在矩形框的4个角
+    case On   //在矩形框的4个角上,覆盖
+}
+
+public struct LBXScanViewStyle {
+
+    // MARK: - -中心位置矩形框
+
+    /// 是否需要绘制扫码矩形框,默认YES
+    public var isNeedShowRetangle: Bool = true
+
+    /**
+     *  默认扫码区域为正方形,如果扫码区域不是正方形,设置宽高比
+     */
+    public var whRatio: CGFloat = 1.0
+
+    /**
+     @brief  矩形框(视频显示透明区)域向上移动偏移量,0表示扫码透明区域在当前视图中心位置,如果负值表示扫码区域下移
+     */
+    public var centerUpOffset: CGFloat = 44
+
+    /**
+     *  矩形框(视频显示透明区)域离界面左边及右边距离,默认60
+     */
+    public var xScanRetangleOffset: CGFloat = 60
+
+    /**
+     @brief  矩形框线条颜色,默认白色
+     */
+    public var colorRetangleLine = UIColor.white
+
+    // MARK: -矩形框(扫码区域)周围4个角
+
+    /**
+     @brief  扫码区域的4个角类型
+     */
+    public var photoframeAngleStyle = LBXScanViewPhotoframeAngleStyle.Outer
+
+    //4个角的颜色
+    public var colorAngle = UIColor(red: 0.0, green: 167.0/255.0, blue: 231.0/255.0, alpha: 1.0)
+
+    //扫码区域4个角的宽度和高度
+    public var photoframeAngleW: CGFloat = 24.0
+    public var photoframeAngleH: CGFloat = 24.0
+    /**
+     @brief  扫码区域4个角的线条宽度,默认6,建议8到4之间
+     */
+    public var photoframeLineW: CGFloat = 6
+
+    // MARK: - ---动画效果
+
+    /**
+     @brief  扫码动画效果:线条或网格
+     */
+    public var anmiationStyle = LBXScanViewAnimationStyle.LineMove
+
+    /**
+     *  动画效果的图像,如线条或网格的图像
+     */
+    public var animationImage: UIImage?
+
+    // MARK: - 非识别区域颜色,默认 RGBA (0,0,0,0.5),范围(0--1)
+    public var color_NotRecoginitonArea: UIColor = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.5)
+
+    public init() {
+
+    }
+
+}

+ 634 - 0
RainbowPlanet/RainbowPlanet/Tools/SwiftScan/LBXScanWrapper.swift

@@ -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 {
+
+    }
+
+}
+