Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
galaxy-iOS
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
mobile-group
galaxy-iOS
Commits
69a1a665
Commit
69a1a665
authored
Sep 18, 2025
by
Alex朱枝文
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
增加扫码逻辑
parent
c0755736
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
1718 additions
and
6 deletions
+1718
-6
project.pbxproj
galaxy/galaxy.xcodeproj/project.pbxproj
+40
-0
YHHomeHoldViewPageViewController.swift
...Modules/Home(首页)/C/YHHomeHoldViewPageViewController.swift
+4
-0
YHHomeSearchView.swift
.../galaxy/Classes/Modules/Home(首页)/V/YHHomeSearchView.swift
+22
-1
YHMyNewViewController.swift
...xy/Classes/Modules/Mine(我的)/C/YHMyNewViewController.swift
+21
-5
YHScanViewController.swift
...axy/Classes/Modules/Mine(我的)/C/YHScanViewController.swift
+60
-0
LBXPermissions.swift
galaxy/galaxy/Classes/Tools/SwiftScan/LBXPermissions.swift
+70
-0
LBXScanLineAnimation.swift
...galaxy/Classes/Tools/SwiftScan/LBXScanLineAnimation.swift
+79
-0
LBXScanNetAnimation.swift
.../galaxy/Classes/Tools/SwiftScan/LBXScanNetAnimation.swift
+76
-0
LBXScanView.swift
galaxy/galaxy/Classes/Tools/SwiftScan/LBXScanView.swift
+409
-0
LBXScanViewController.swift
...alaxy/Classes/Tools/SwiftScan/LBXScanViewController.swift
+202
-0
LBXScanViewStyle.swift
galaxy/galaxy/Classes/Tools/SwiftScan/LBXScanViewStyle.swift
+88
-0
LBXScanWrapper.swift
galaxy/galaxy/Classes/Tools/SwiftScan/LBXScanWrapper.swift
+603
-0
Contents.json
.../Assets.xcassets/Mine/qr_scan_icon.imageset/Contents.json
+22
-0
qr_scan_icon@2x.png
...s.xcassets/Mine/qr_scan_icon.imageset/qr_scan_icon@2x.png
+0
-0
qr_scan_icon@3x.png
...s.xcassets/Mine/qr_scan_icon.imageset/qr_scan_icon@3x.png
+0
-0
Contents.json
...ssets.xcassets/Mine/scan_move_line.imageset/Contents.json
+22
-0
scan_move_line@2x.png
...assets/Mine/scan_move_line.imageset/scan_move_line@2x.png
+0
-0
scan_move_line@3x.png
...assets/Mine/scan_move_line.imageset/scan_move_line@3x.png
+0
-0
No files found.
galaxy/galaxy.xcodeproj/project.pbxproj
View file @
69a1a665
...
...
@@ -1253,6 +1253,14 @@
04B00FC72D9A420F00F640C5
/* YHMakePlanPriceAlertView.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04B00FB82D9A420F00F640C5
/* YHMakePlanPriceAlertView.swift */
;
};
04B00FC82D9A420F00F640C5
/* YHMakePlanCusttomHeadView.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04B00FB62D9A420F00F640C5
/* YHMakePlanCusttomHeadView.swift */
;
};
04B00FCA2D9AAD6100F640C5
/* YHMakePlanTopView.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04B00FC92D9AAD6100F640C5
/* YHMakePlanTopView.swift */
;
};
04C0ED6A2E7BAC2D00B0D182
/* LBXScanView.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04C0ED652E7BAC2D00B0D182
/* LBXScanView.swift */
;
};
04C0ED6B2E7BAC2D00B0D182
/* LBXScanViewController.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04C0ED662E7BAC2D00B0D182
/* LBXScanViewController.swift */
;
};
04C0ED6C2E7BAC2D00B0D182
/* LBXScanWrapper.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04C0ED682E7BAC2D00B0D182
/* LBXScanWrapper.swift */
;
};
04C0ED6D2E7BAC2D00B0D182
/* LBXScanViewStyle.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04C0ED672E7BAC2D00B0D182
/* LBXScanViewStyle.swift */
;
};
04C0ED6E2E7BAC2D00B0D182
/* LBXPermissions.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04C0ED622E7BAC2D00B0D182
/* LBXPermissions.swift */
;
};
04C0ED6F2E7BAC2D00B0D182
/* LBXScanNetAnimation.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04C0ED642E7BAC2D00B0D182
/* LBXScanNetAnimation.swift */
;
};
04C0ED702E7BAC2D00B0D182
/* LBXScanLineAnimation.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04C0ED632E7BAC2D00B0D182
/* LBXScanLineAnimation.swift */
;
};
04C0ED7C2E7BEF7800B0D182
/* YHScanViewController.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04C0ED7B2E7BEF7800B0D182
/* YHScanViewController.swift */
;
};
04D8FF552D9258AA00703C75
/* YHPlanScoreView.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04D8FF542D9258AA00703C75
/* YHPlanScoreView.swift */
;
};
04D8FF572D925A0800703C75
/* YHPlanScoreChart.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04D8FF562D925A0800703C75
/* YHPlanScoreChart.swift */
;
};
04D8FF592D925E6700703C75
/* YHPlanModel.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
04D8FF582D925E6700703C75
/* YHPlanModel.swift */
;
};
...
...
@@ -2593,6 +2601,14 @@
04B00FBA2D9A420F00F640C5
/* YHMakePlanShareAlertView.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
YHMakePlanShareAlertView.swift
;
sourceTree
=
"<group>"
;
};
04B00FBB2D9A420F00F640C5
/* YHMakePlanStateHeadView.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
YHMakePlanStateHeadView.swift
;
sourceTree
=
"<group>"
;
};
04B00FC92D9AAD6100F640C5
/* YHMakePlanTopView.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
YHMakePlanTopView.swift
;
sourceTree
=
"<group>"
;
};
04C0ED622E7BAC2D00B0D182
/* LBXPermissions.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
LBXPermissions.swift
;
sourceTree
=
"<group>"
;
};
04C0ED632E7BAC2D00B0D182
/* LBXScanLineAnimation.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
LBXScanLineAnimation.swift
;
sourceTree
=
"<group>"
;
};
04C0ED642E7BAC2D00B0D182
/* LBXScanNetAnimation.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
LBXScanNetAnimation.swift
;
sourceTree
=
"<group>"
;
};
04C0ED652E7BAC2D00B0D182
/* LBXScanView.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
LBXScanView.swift
;
sourceTree
=
"<group>"
;
};
04C0ED662E7BAC2D00B0D182
/* LBXScanViewController.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
LBXScanViewController.swift
;
sourceTree
=
"<group>"
;
};
04C0ED672E7BAC2D00B0D182
/* LBXScanViewStyle.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
LBXScanViewStyle.swift
;
sourceTree
=
"<group>"
;
};
04C0ED682E7BAC2D00B0D182
/* LBXScanWrapper.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
LBXScanWrapper.swift
;
sourceTree
=
"<group>"
;
};
04C0ED7B2E7BEF7800B0D182
/* YHScanViewController.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
YHScanViewController.swift
;
sourceTree
=
"<group>"
;
};
04D8FF542D9258AA00703C75
/* YHPlanScoreView.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
YHPlanScoreView.swift
;
sourceTree
=
"<group>"
;
};
04D8FF562D925A0800703C75
/* YHPlanScoreChart.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
YHPlanScoreChart.swift
;
sourceTree
=
"<group>"
;
};
04D8FF582D925E6700703C75
/* YHPlanModel.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
YHPlanModel.swift
;
sourceTree
=
"<group>"
;
};
...
...
@@ -5947,6 +5963,7 @@
045C0EE02D12CA5E00BD2DC0
/* YHVideoPlaySettingVC.swift */
,
048D6ADA2D5E00DE00BC6F4C
/* YHMemberCenterViewController.swift */
,
04AFEF562D6C78AA0007A011
/* YHVipLevelRightViewController.swift */
,
04C0ED7B2E7BEF7800B0D182
/* YHScanViewController.swift */
,
);
path
=
C
;
sourceTree
=
"<group>"
;
...
...
@@ -6264,6 +6281,7 @@
045C0F472D12CA5E00BD2DC0
/* Tools */
=
{
isa
=
PBXGroup
;
children
=
(
04C0ED692E7BAC2D00B0D182
/* SwiftScan */
,
045C0F0E2D12CA5E00BD2DC0
/* Analytics */
,
045C0F112D12CA5E00BD2DC0
/* CustomRefreshHeader */
,
045C0F232D12CA5E00BD2DC0
/* Extention */
,
...
...
@@ -6854,6 +6872,20 @@
path
=
MakePlan
;
sourceTree
=
"<group>"
;
};
04C0ED692E7BAC2D00B0D182
/* SwiftScan */
=
{
isa
=
PBXGroup
;
children
=
(
04C0ED622E7BAC2D00B0D182
/* LBXPermissions.swift */
,
04C0ED632E7BAC2D00B0D182
/* LBXScanLineAnimation.swift */
,
04C0ED642E7BAC2D00B0D182
/* LBXScanNetAnimation.swift */
,
04C0ED652E7BAC2D00B0D182
/* LBXScanView.swift */
,
04C0ED662E7BAC2D00B0D182
/* LBXScanViewController.swift */
,
04C0ED672E7BAC2D00B0D182
/* LBXScanViewStyle.swift */
,
04C0ED682E7BAC2D00B0D182
/* LBXScanWrapper.swift */
,
);
path
=
SwiftScan
;
sourceTree
=
"<group>"
;
};
04D8FF4F2D9257F700703C75
/* Plan(方案) */
=
{
isa
=
PBXGroup
;
children
=
(
...
...
@@ -7421,6 +7453,13 @@
045C0FE52D12CA5F00BD2DC0
/* YHStatusAdvantageBottomView.swift in Sources */
,
045C0FE62D12CA5F00BD2DC0
/* YHLifeItemTableViewCell.swift in Sources */
,
045C0FE72D12CA5F00BD2DC0
/* YHIndustryLocationCell.swift in Sources */
,
04C0ED6A2E7BAC2D00B0D182
/* LBXScanView.swift in Sources */
,
04C0ED6B2E7BAC2D00B0D182
/* LBXScanViewController.swift in Sources */
,
04C0ED6C2E7BAC2D00B0D182
/* LBXScanWrapper.swift in Sources */
,
04C0ED6D2E7BAC2D00B0D182
/* LBXScanViewStyle.swift in Sources */
,
04C0ED6E2E7BAC2D00B0D182
/* LBXPermissions.swift in Sources */
,
04C0ED6F2E7BAC2D00B0D182
/* LBXScanNetAnimation.swift in Sources */
,
04C0ED702E7BAC2D00B0D182
/* LBXScanLineAnimation.swift in Sources */
,
045C0FE82D12CA5F00BD2DC0
/* YHActivityApplyInfoItemView.swift in Sources */
,
045C0FE92D12CA5F00BD2DC0
/* YHVisaRenewalItemDetailType.swift in Sources */
,
045C0FEA2D12CA5F00BD2DC0
/* YHPrivacyAlertView.swift in Sources */
,
...
...
@@ -8214,6 +8253,7 @@
045C12822D12CA5F00BD2DC0
/* YHServiceCenterStepThreeTableHeadView.swift in Sources */
,
045C12832D12CA5F00BD2DC0
/* YHResignRiskWarningAlertView.swift in Sources */
,
045C12842D12CA5F00BD2DC0
/* YHDashLineView.swift in Sources */
,
04C0ED7C2E7BEF7800B0D182
/* YHScanViewController.swift in Sources */
,
045C12852D12CA5F00BD2DC0
/* YHPreviewInfoCertificateInformationItemsView.swift in Sources */
,
045C12862D12CA5F00BD2DC0
/* YHOfficialApprovalResultVC.swift in Sources */
,
045C12872D12CA5F00BD2DC0
/* YHStatusAdvantageVC.swift in Sources */
,
...
...
galaxy/galaxy/Classes/Modules/Home(首页)/C/YHHomeHoldViewPageViewController.swift
View file @
69a1a665
...
...
@@ -270,6 +270,10 @@ class YHHomeHoldViewPageViewController: YHBaseViewController, WKUIDelegate, WKNa
let
view
=
YHHomeSearchView
()
let
tap
=
UITapGestureRecognizer
(
target
:
self
,
action
:
#selector(
didSearchBarClicked
)
)
view
.
addGestureRecognizer
(
tap
)
view
.
didClickScanBtnEvent
=
{
[
weak
self
]
in
let
vc
=
YHScanViewController
()
self
?
.
navigationController
?
.
pushViewController
(
vc
)
}
return
view
}()
...
...
galaxy/galaxy/Classes/Modules/Home(首页)/V/YHHomeSearchView.swift
View file @
69a1a665
...
...
@@ -17,12 +17,22 @@ class YHHomeSearchView: UIView {
return
lable
}()
private
lazy
var
scanBtn
:
UIButton
=
{
let
btn
=
UIButton
()
btn
.
setImage
(
UIImage
(
named
:
"qr_scan_icon"
),
for
:
.
normal
)
btn
.
YH_clickEdgeInsets
=
UIEdgeInsets
(
top
:
20
,
left
:
20
,
bottom
:
20
,
right
:
20
)
btn
.
addTarget
(
self
,
action
:
#selector(
didClickScanBtn(btn:)
)
,
for
:
.
touchUpInside
)
return
btn
}()
var
placeHolder
:
String
=
""
{
didSet
{
self
.
placeHolderLabel
.
text
=
placeHolder
}
}
var
didClickScanBtnEvent
:
(()
->
Void
)?
override
init
(
frame
:
CGRect
)
{
super
.
init
(
frame
:
frame
)
initView
()
...
...
@@ -47,12 +57,23 @@ private extension YHHomeSearchView {
make
.
width
.
height
.
equalTo
(
16
)
}
addSubview
(
scanBtn
)
scanBtn
.
snp
.
makeConstraints
{
make
in
make
.
width
.
height
.
equalTo
(
24.0
)
make
.
right
.
equalToSuperview
()
.
offset
(
-
12
)
make
.
centerY
.
equalToSuperview
()
}
addSubview
(
placeHolderLabel
)
placeHolderLabel
.
snp
.
makeConstraints
{
make
in
make
.
centerY
.
equalToSuperview
()
make
.
left
.
equalTo
(
imageV
.
snp
.
right
)
.
offset
(
8
)
make
.
height
.
equalTo
(
18
)
make
.
right
.
equalTo
Superview
(
)
.
offset
(
-
12
)
make
.
right
.
equalTo
(
scanBtn
.
snp
.
left
)
.
offset
(
-
12
)
}
}
@objc
func
didClickScanBtn
(
btn
:
UIButton
)
{
didClickScanBtnEvent
?()
}
}
galaxy/galaxy/Classes/Modules/Mine(我的)/C/YHMyNewViewController.swift
View file @
69a1a665
...
...
@@ -130,6 +130,14 @@ class YHMyNewViewController: YHBaseViewController {
return
btn
}()
private
lazy
var
scanBtn
:
UIButton
=
{
let
btn
=
UIButton
()
btn
.
setImage
(
UIImage
(
named
:
"qr_scan_icon"
),
for
:
.
normal
)
btn
.
YH_clickEdgeInsets
=
UIEdgeInsets
(
top
:
20
,
left
:
20
,
bottom
:
20
,
right
:
20
)
btn
.
addTarget
(
self
,
action
:
#selector(
didClickScanBtn(btn:)
)
,
for
:
.
touchUpInside
)
return
btn
}()
private
lazy
var
settingRedPointView
:
UIView
=
{
let
view
=
UIView
()
view
.
layer
.
cornerRadius
=
kCornerRadius3
...
...
@@ -150,6 +158,7 @@ class YHMyNewViewController: YHBaseViewController {
view
.
addSubview
(
bgImgView
)
view
.
addSubview
(
tableView
)
view
.
addSubview
(
settingBtn
)
view
.
addSubview
(
scanBtn
)
view
.
addSubview
(
settingRedPointView
)
bgImgView
.
snp
.
makeConstraints
{
make
in
...
...
@@ -176,6 +185,12 @@ class YHMyNewViewController: YHBaseViewController {
make
.
bottom
.
equalTo
(
settingBtn
.
snp
.
top
)
.
offset
(
3
)
}
scanBtn
.
snp
.
makeConstraints
{
make
in
make
.
width
.
height
.
equalTo
(
24.0
)
make
.
right
.
equalTo
(
settingBtn
.
snp
.
left
)
.
offset
(
-
17
)
make
.
top
.
equalTo
(
k_Height_StatusBar
+
10
)
}
updateUserUI
()
NotificationCenter
.
default
.
addObserver
(
self
,
selector
:
#selector(
loginSuccess
)
,
name
:
YhConstant
.
YhNotification
.
didLoginSuccessNotifiction
,
object
:
nil
)
...
...
@@ -303,12 +318,13 @@ class YHMyNewViewController: YHBaseViewController {
if
!
checkLogin
()
{
return
}
let
vc
=
YHMySettingViewController
()
self
.
navigationController
?
.
pushViewController
(
vc
)
// let vc = YHH5WebViewVC()
// vc.isFullScreenFlag = false
// vc.url = "http://192.168.34.113:10301/superAppBridge.html#/order/antom-pay?id=1864¶m=eyJhbGbolyFeciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NTc0NzI5MzAsImkiOjQyMzgxNzEzODcwNzAyMSwidSI6IumTtuays-mbhuWboiIsInIiOiJzdXBlcl9hcHAifQ.Phsg13OfN5XJ0cLe759U2W0hH1iTZeneimgTlnouPcg"
// self.navigationController?.pushViewController(vc)
}
@objc
func
didClickScanBtn
(
btn
:
UIButton
)
{
let
vc
=
YHScanViewController
()
self
.
navigationController
?
.
pushViewController
(
vc
)
}
}
extension
YHMyNewViewController
:
UITableViewDelegate
,
UITableViewDataSource
{
...
...
galaxy/galaxy/Classes/Modules/Mine(我的)/C/YHScanViewController.swift
0 → 100644
View file @
69a1a665
//
// YHScanViewController.swift
// galaxy
//
// Created by alexzzw on 2025/9/18.
// Copyright © 2025 https://www.galaxy-immi.com. All rights reserved.
//
import
UIKit
class
YHScanViewController
:
LBXScanViewController
{
private
let
topOffset
=
44.0
private
let
leftOffset
=
48.0
override
var
preferredStatusBarStyle
:
UIStatusBarStyle
{
return
.
lightContent
}
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
gk_navTitleColor
=
.
white
gk_navTitle
=
"扫码"
gk_navBarAlpha
=
0.0
gk_navBackgroundColor
=
.
clear
gk_backImage
=
UIImage
(
named
:
"back_icon_white"
)
setupScanStyle
()
}
override
func
handleCodeResult
(
arrayResult
:
[
LBXScanResult
])
{
//
}
deinit
{
//
}
}
extension
YHScanViewController
{
private
func
setupScanStyle
()
{
var
style
=
LBXScanViewStyle
()
style
.
centerUpOffset
=
topOffset
style
.
xScanRetangleOffset
=
leftOffset
style
.
photoframeAngleStyle
=
LBXScanViewPhotoframeAngleStyle
.
Inner
style
.
photoframeLineW
=
3
style
.
photoframeAngleW
=
18
style
.
photoframeAngleH
=
18
style
.
isNeedShowRetangle
=
false
style
.
anmiationStyle
=
LBXScanViewAnimationStyle
.
LineMove
// 扫描横线图片
style
.
animationImage
=
UIImage
(
named
:
"scan_move_line"
)
// 4个角的颜色
style
.
colorAngle
=
UIColor
.
white
// 非矩形框区域颜色
style
.
color_NotRecoginitonArea
=
UIColor
.
black
.
withAlphaComponent
(
0.3
)
scanStyle
=
style
}
}
galaxy/galaxy/Classes/Tools/SwiftScan/LBXPermissions.swift
0 → 100755
View file @
69a1a665
//
// 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
)
}
})
case
.
limited
:
comletion
(
false
)
@unknown
default
:
comletion
(
false
)
}
}
// MARK: - --相机权限
static
func
authorizeCameraWith
(
comletion
:
@escaping
(
Bool
)
->
Void
)
{
let
granted
=
AVCaptureDevice
.
authorizationStatus
(
for
:
AVMediaType
.
video
)
switch
granted
{
case
.
authorized
:
comletion
(
true
)
case
.
denied
:
comletion
(
false
)
case
.
restricted
:
comletion
(
false
)
case
.
notDetermined
:
AVCaptureDevice
.
requestAccess
(
for
:
AVMediaType
.
video
,
completionHandler
:
{
(
granted
:
Bool
)
in
DispatchQueue
.
main
.
async
{
comletion
(
granted
)
}
})
@unknown
default
:
comletion
(
false
)
}
}
// MARK: 跳转到APP系统设置权限界面
static
func
jumpToSystemPrivacySetting
()
{
if
let
appSetting
=
URL
(
string
:
UIApplication
.
openSettingsURLString
)
{
if
#available(iOS 10, *)
{
UIApplication
.
shared
.
open
(
appSetting
,
options
:
[:],
completionHandler
:
nil
)
}
else
{
UIApplication
.
shared
.
openURL
(
appSetting
)
}
}
}
}
galaxy/galaxy/Classes/Tools/SwiftScan/LBXScanLineAnimation.swift
0 → 100755
View file @
69a1a665
//
// 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
}
guard
let
image
=
self
.
image
else
{
return
}
var
frame
:
CGRect
=
animationRect
let
hImg
=
image
.
size
.
height
*
animationRect
.
size
.
width
/
image
.
size
.
width
frame
.
origin
.
y
-=
hImg
frame
.
size
.
height
=
hImg
self
.
frame
=
frame
self
.
alpha
=
0.0
UIView
.
animate
(
withDuration
:
1.4
,
animations
:
{
()
in
self
.
alpha
=
1.0
var
frame
=
self
.
animationRect
let
hImg
=
image
.
size
.
height
*
self
.
animationRect
.
size
.
width
/
image
.
size
.
width
frame
.
origin
.
y
+=
(
frame
.
size
.
height
-
hImg
)
frame
.
size
.
height
=
hImg
self
.
frame
=
frame
},
completion
:
{
(
_
:
Bool
)
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
()
}
}
galaxy/galaxy/Classes/Tools/SwiftScan/LBXScanNetAnimation.swift
0 → 100755
View file @
69a1a665
//
// 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
}
guard
let
image
=
self
.
image
else
{
return
}
var
frame
=
animationRect
let
hImg
=
image
.
size
.
height
*
animationRect
.
size
.
width
/
image
.
size
.
width
frame
.
origin
.
y
-=
hImg
frame
.
size
.
height
=
hImg
self
.
frame
=
frame
self
.
alpha
=
0.0
UIView
.
animate
(
withDuration
:
1.2
,
animations
:
{
()
in
self
.
alpha
=
1.0
var
frame
=
self
.
animationRect
let
hImg
=
image
.
size
.
height
*
self
.
animationRect
.
size
.
width
/
image
.
size
.
width
frame
.
origin
.
y
+=
(
frame
.
size
.
height
-
hImg
)
frame
.
size
.
height
=
hImg
self
.
frame
=
frame
},
completion
:
{
(
_
:
Bool
)
in
self
.
perform
(
#selector(
LBXScanNetAnimation.stepAnimation
)
,
with
:
nil
,
afterDelay
:
0.3
)
})
}
func
stopStepAnimating
()
{
self
.
isHidden
=
true
isAnimationing
=
false
}
}
galaxy/galaxy/Classes/Tools/SwiftScan/LBXScanView.swift
0 → 100755
View file @
69a1a665
//
// 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
.
LineMove
:
scanLineAnimation
=
LBXScanLineAnimation
.
instance
()
case
.
NetGrid
:
scanNetAnimation
=
LBXScanNetAnimation
.
instance
()
case
.
LineStill
:
scanLineStill
=
UIImageView
()
scanLineStill
?
.
image
=
viewStyle
.
animationImage
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
()
}
}
/**
* 开始扫描动画
*/
func
startScanAnimation
()
{
if
isAnimationing
{
return
}
isAnimationing
=
true
let
cropRect
:
CGRect
=
getScanRectForAnimation
()
switch
viewStyle
.
anmiationStyle
{
case
.
LineMove
:
scanLineAnimation
?
.
startAnimatingWithRect
(
animationRect
:
cropRect
,
parentView
:
self
,
image
:
viewStyle
.
animationImage
)
case
.
NetGrid
:
scanNetAnimation
?
.
startAnimatingWithRect
(
animationRect
:
cropRect
,
parentView
:
self
,
image
:
viewStyle
.
animationImage
)
case
.
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
if
let
scanLineStill
=
scanLineStill
{
self
.
addSubview
(
scanLineStill
)
}
self
.
scanLineStill
?
.
isHidden
=
false
default
:
break
}
}
/**
* 开始扫描动画
*/
func
stopScanAnimation
()
{
isAnimationing
=
false
switch
viewStyle
.
anmiationStyle
{
case
.
LineMove
:
scanLineAnimation
?
.
stopStepAnimating
()
case
.
NetGrid
:
scanNetAnimation
?
.
stopStepAnimating
()
case
.
LineStill
:
self
.
scanLineStill
?
.
isHidden
=
true
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
.
Outer
:
diffAngle
=
linewidthAngle
/
3
// 框外面4个角,与框紧密联系在一起
case
.
On
:
diffAngle
=
0
case
.
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
{
let
activityView
=
UIActivityIndicatorView
(
frame
:
CGRect
(
x
:
0
,
y
:
0
,
width
:
30
,
height
:
30
))
self
.
activityView
=
activityView
activityView
.
center
=
CGPoint
(
x
:
XRetangleLeft
+
sizeRetangle
.
width
/
2
-
50
,
y
:
YMinRetangle
+
sizeRetangle
.
height
/
2
)
// activityView = 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))
let
labelReadying
=
UILabel
(
frame
:
labelReadyRect
)
self
.
labelReadying
=
labelReadying
labelReadying
.
text
=
readyStr
labelReadying
.
backgroundColor
=
UIColor
.
clear
labelReadying
.
textColor
=
UIColor
.
white
labelReadying
.
font
=
UIFont
.
systemFont
(
ofSize
:
18.0
)
addSubview
(
labelReadying
)
}
activityView
?
.
startAnimating
()
}
func
deviceStopReadying
()
{
if
activityView
!=
nil
{
activityView
?
.
stopAnimating
()
activityView
?
.
removeFromSuperview
()
labelReadying
?
.
removeFromSuperview
()
activityView
=
nil
labelReadying
=
nil
}
}
}
galaxy/galaxy/Classes/Tools/SwiftScan/LBXScanViewController.swift
0 → 100755
View file @
69a1a665
//
// LBXScanViewController.swift
// swiftScan
//
// Created by lbxia on 15/12/8.
// Copyright © 2015年 xialibing. All rights reserved.
//
import
UIKit
import
Foundation
import
AVFoundation
protocol
LBXScanViewControllerDelegate
:
AnyObject
{
func
scanFinished
(
scanResult
:
LBXScanResult
,
error
:
String
?)
}
protocol
QRRectDelegate
:
AnyObject
{
func
drawwed
()
}
class
LBXScanViewController
:
YHBaseViewController
,
UIImagePickerControllerDelegate
,
UINavigationControllerDelegate
{
// 返回扫码结果,也可以通过继承本控制器,改写该handleCodeResult方法即可
open
weak
var
scanResultDelegate
:
LBXScanViewControllerDelegate
?
open
var
delegate
:
QRRectDelegate
?
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
drawScanView
()
// self.edgesForExtendedLayout = UIRectEdge(rawValue: 0)
}
open
func
setNeedCodeImage
(
needCodeImg
:
Bool
)
{
isNeedCodeImage
=
needCodeImg
}
// 设置框内识别
open
func
setOpenInterestRect
(
isOpen
:
Bool
)
{
isOpenInterestRect
=
isOpen
}
override
open
func
viewDidAppear
(
_
animated
:
Bool
)
{
super
.
viewDidAppear
(
animated
)
LBXPermissions
.
authorizeCameraWith
{
[
weak
self
]
granted
in
if
granted
{
self
?
.
perform
(
#selector(
LBXScanViewController.startScan
)
,
with
:
nil
,
afterDelay
:
0.3
)
}
else
{
// 跳转到系统设置
YHCommonAlertView
.
show
(
""
,
"没有相机权限,是否跳转设置页面开启?"
,
"取消"
,
"确定"
,
fullGuestureEnable
:
false
)
{
}
callBack
:
{
let
localUrl
=
URL
(
string
:
UIApplication
.
openSettingsURLString
)
if
let
url
=
localUrl
{
if
UIApplication
.
shared
.
canOpenURL
(
url
)
{
UIApplication
.
shared
.
open
(
url
,
options
:
[:],
completionHandler
:
nil
)
}
}
}
}
}
}
@objc
open
func
startScan
()
{
if
scanObj
==
nil
{
var
cropRect
=
CGRect
.
zero
if
isOpenInterestRect
{
guard
let
style
=
scanStyle
else
{
return
}
cropRect
=
LBXScanView
.
getScanRectWithPreView
(
preView
:
self
.
view
,
style
:
style
)
}
// 指定识别几种码
if
arrayCodeType
==
nil
{
arrayCodeType
=
[
.
qr
,
.
ean13
,
.
code39
,
.
code128
]
}
guard
let
codeTypes
=
arrayCodeType
else
{
return
}
scanObj
=
LBXScanWrapper
(
videoPreView
:
self
.
view
,
objType
:
codeTypes
,
isCaptureImg
:
isNeedCodeImage
,
cropRect
:
cropRect
,
success
:
{
[
weak
self
]
arrayResult
in
if
let
strongSelf
=
self
{
// 停止扫描动画
strongSelf
.
qRScanView
?
.
stopScanAnimation
()
strongSelf
.
handleCodeResult
(
arrayResult
:
arrayResult
)
}
})
}
// 结束相机等待提示
qRScanView
?
.
deviceStopReadying
()
// 开始扫描动画
qRScanView
?
.
startScanAnimation
()
// 相机运行
scanObj
?
.
start
()
}
open
func
stopScan
()
{
qRScanView
?
.
stopScanAnimation
()
scanObj
?
.
stop
()
}
open
func
drawScanView
()
{
if
qRScanView
==
nil
{
guard
let
style
=
scanStyle
else
{
return
}
let
qRScanView
=
LBXScanView
(
frame
:
self
.
view
.
frame
,
vstyle
:
style
)
self
.
qRScanView
=
qRScanView
self
.
view
.
addSubview
(
qRScanView
)
delegate
?
.
drawwed
()
}
qRScanView
?
.
deviceStartReadying
(
readyStr
:
readyString
)
}
// 处理扫码结果,如果是继承本控制器的,可以重写该方法,作出相应地处理,或者设置delegate作出相应处理
open
func
handleCodeResult
(
arrayResult
:
[
LBXScanResult
])
{
if
let
delegate
=
scanResultDelegate
{
self
.
navigationController
?
.
popViewController
(
animated
:
true
)
let
result
:
LBXScanResult
=
arrayResult
[
0
]
delegate
.
scanFinished
(
scanResult
:
result
,
error
:
nil
)
}
else
{
for
result
:
LBXScanResult
in
arrayResult
{
debugPrint
(
"%@"
,
result
.
strScanned
??
""
)
}
let
result
:
LBXScanResult
=
arrayResult
[
0
]
YHCommonAlertView
.
show
(
result
.
strBarCodeType
,
result
.
strScanned
,
""
,
"确定"
,
fullGuestureEnable
:
false
)
{
}
callBack
:
{
}
}
}
override
open
func
viewWillDisappear
(
_
animated
:
Bool
)
{
NSObject
.
cancelPreviousPerformRequests
(
withTarget
:
self
)
stopScan
()
}
open
func
openPhotoAlbum
()
{
LBXPermissions
.
authorizePhotoWith
{
[
weak
self
]
granted
in
if
granted
{
let
picker
=
UIImagePickerController
()
picker
.
sourceType
=
.
photoLibrary
picker
.
delegate
=
self
picker
.
allowsEditing
=
true
self
?
.
present
(
picker
,
animated
:
true
,
completion
:
nil
)
}
else
{
YHCommonAlertView
.
show
(
""
,
"没有相册权限,是否跳转设置页面开启?"
,
"取消"
,
"确定"
,
fullGuestureEnable
:
false
)
{
}
callBack
:
{
let
localUrl
=
URL
(
string
:
UIApplication
.
openSettingsURLString
)
if
let
url
=
localUrl
{
if
UIApplication
.
shared
.
canOpenURL
(
url
)
{
UIApplication
.
shared
.
open
(
url
,
options
:
[:],
completionHandler
:
nil
)
}
}
}
}
}
}
// MARK: - 相册选择图片识别二维码 (条形码没有找到系统方法)
public
func
imagePickerController
(
_
picker
:
UIImagePickerController
,
didFinishPickingMediaWithInfo
info
:
[
UIImagePickerController
.
InfoKey
:
Any
])
{
picker
.
dismiss
(
animated
:
true
,
completion
:
nil
)
var
image
:
UIImage
?
=
info
[
.
editedImage
]
as?
UIImage
if
image
==
nil
{
image
=
info
[
.
originalImage
]
as?
UIImage
}
if
let
validImage
=
image
{
let
arrayResult
=
LBXScanWrapper
.
recognizeQRImage
(
image
:
validImage
)
if
arrayResult
.
count
>
0
{
handleCodeResult
(
arrayResult
:
arrayResult
)
return
}
}
YHCommonAlertView
.
show
(
""
,
"暂无法识别图片中二维码"
,
""
,
"确定"
,
fullGuestureEnable
:
false
)
{
}
callBack
:
{
}
}
deinit
{
}
}
galaxy/galaxy/Classes/Tools/SwiftScan/LBXScanViewStyle.swift
0 → 100755
View file @
69a1a665
//
// 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
()
{
}
}
galaxy/galaxy/Classes/Tools/SwiftScan/LBXScanWrapper.swift
0 → 100755
View file @
69a1a665
//
// LBXScanWrapper.swift
// swiftScan
//
// Created by lbxia on 15/12/10.
// Copyright © 2015年 xialibing. All rights reserved.
//
import
AVFoundation
import
UIKit
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
]?)
{
strScanned
=
str
imgScanned
=
img
strBarCodeType
=
barCodeType
arrayCorner
=
corner
}
}
open
class
LBXScanWrapper
:
NSObject
,
AVCaptureMetadataOutputObjectsDelegate
{
let
device
=
AVCaptureDevice
.
default
(
for
:
AVMediaType
.
video
)
var
input
:
AVCaptureDeviceInput
?
var
output
:
AVCaptureMetadataOutput
let
session
=
AVCaptureSession
()
var
previewLayer
:
AVCaptureVideoPreviewLayer
?
var
stillImageOutput
:
AVCaptureStillImageOutput
?
// 存储返回结果
var
arrayResult
:
[
LBXScanResult
]
=
[]
// 扫码结果返回block
var
successBlock
:
([
LBXScanResult
])
->
Void
// 是否需要拍照
var
isNeedCaptureImage
:
Bool
// 当前扫码结果是否处理
var
isNeedScanResult
:
Bool
=
true
private
let
sessionQueue
=
DispatchQueue
(
label
:
"com.lbxscan.session"
,
qos
:
.
userInitiated
)
init
(
videoPreView
:
UIView
,
objType
:
[
AVMetadataObject
.
ObjectType
]
=
[
.
qr
],
isCaptureImg
:
Bool
,
cropRect
:
CGRect
=
CGRect
.
zero
,
success
:
@escaping
(([
LBXScanResult
])
->
Void
))
{
successBlock
=
success
output
=
AVCaptureMetadataOutput
()
isNeedCaptureImage
=
isCaptureImg
stillImageOutput
=
AVCaptureStillImageOutput
()
super
.
init
()
guard
let
device
=
device
else
{
return
}
do
{
input
=
try
AVCaptureDeviceInput
(
device
:
device
)
}
catch
let
error
as
NSError
{
print
(
"AVCaptureDeviceInput():
\(
error
)
"
)
return
}
guard
let
validInput
=
input
else
{
return
}
if
session
.
canAddInput
(
validInput
)
{
session
.
addInput
(
validInput
)
}
if
session
.
canAddOutput
(
output
)
{
session
.
addOutput
(
output
)
}
if
let
stillOutput
=
stillImageOutput
,
session
.
canAddOutput
(
stillOutput
)
{
session
.
addOutput
(
stillOutput
)
}
let
outputSettings
:
[
String
:
Any
]
=
[
AVVideoCodecKey
:
AVVideoCodecType
.
jpeg
]
stillImageOutput
?
.
outputSettings
=
outputSettings
session
.
sessionPreset
=
AVCaptureSession
.
Preset
.
high
// 参数设置
output
.
setMetadataObjectsDelegate
(
self
,
queue
:
DispatchQueue
.
main
)
output
.
metadataObjectTypes
=
objType
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
if
let
layer
=
previewLayer
{
videoPreView
.
layer
.
insertSublayer
(
layer
,
at
:
0
)
}
if
device
.
isFocusPointOfInterestSupported
&&
device
.
isFocusModeSupported
(
AVCaptureDevice
.
FocusMode
.
continuousAutoFocus
)
{
do
{
try
device
.
lockForConfiguration
()
device
.
focusMode
=
AVCaptureDevice
.
FocusMode
.
continuousAutoFocus
device
.
unlockForConfiguration
()
}
catch
let
error
as
NSError
{
print
(
"device.lockForConfiguration():
\(
error
)
"
)
}
}
}
public
func
metadataOutput
(
_
output
:
AVCaptureMetadataOutput
,
didOutput
metadataObjects
:
[
AVMetadataObject
],
from
connection
:
AVCaptureConnection
)
{
if
!
isNeedScanResult
{
// 上一帧处理中
return
}
isNeedScanResult
=
false
arrayResult
.
removeAll
()
// 识别扫码类型
for
current
in
metadataObjects
{
if
let
code
=
current
as?
AVMetadataMachineReadableCodeObject
{
// 码类型
let
codeType
=
code
.
type
// 码内容
let
codeContent
=
code
.
stringValue
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
}
}
func
start
()
{
sessionQueue
.
async
{
if
!
self
.
session
.
isRunning
{
self
.
isNeedScanResult
=
true
self
.
session
.
startRunning
()
}
}
}
func
stop
()
{
sessionQueue
.
async
{
if
self
.
session
.
isRunning
{
self
.
isNeedScanResult
=
false
self
.
session
.
stopRunning
()
}
}
}
// MARK: - ---拍照
open
func
captureImage
()
{
guard
let
stillOutput
=
stillImageOutput
else
{
stop
()
successBlock
(
arrayResult
)
return
}
let
stillImageConnection
:
AVCaptureConnection
?
=
connectionWithMediaType
(
mediaType
:
AVMediaType
.
video
as
AVMediaType
,
connections
:
stillOutput
.
connections
as
[
AnyObject
])
guard
let
connection
=
stillImageConnection
else
{
stop
()
successBlock
(
arrayResult
)
return
}
stillOutput
.
captureStillImageAsynchronously
(
from
:
connection
,
completionHandler
:
{
imageDataSampleBuffer
,
_
in
self
.
stop
()
if
let
sampleBuffer
=
imageDataSampleBuffer
,
let
imageData
:
Data
=
AVCaptureStillImageOutput
.
jpegStillImageNSDataRepresentation
(
sampleBuffer
)
{
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
in
connections
{
guard
let
connectionTmp
=
connection
as?
AVCaptureConnection
else
{
continue
}
for
port
in
connectionTmp
.
inputPorts
{
if
port
.
mediaType
==
mediaType
{
return
connectionTmp
}
}
}
return
nil
}
// MARK: 切换识别区域
open
func
changeScanRect
(
cropRect
:
CGRect
)
{
sessionQueue
.
async
{
if
self
.
session
.
isRunning
{
self
.
session
.
stopRunning
()
}
DispatchQueue
.
main
.
async
{
self
.
output
.
rectOfInterest
=
cropRect
self
.
sessionQueue
.
async
{
self
.
session
.
startRunning
()
}
}
}
}
// MARK: 切换识别码的类型
open
func
changeScanType
(
objType
:
[
AVMetadataObject
.
ObjectType
])
{
// 待测试中途修改是否有效
output
.
metadataObjectTypes
=
objType
}
open
func
isGetFlash
()
->
Bool
{
guard
let
device
=
device
else
{
return
false
}
return
device
.
hasFlash
&&
device
.
hasTorch
}
/**
打开或关闭闪关灯
- parameter torch: true:打开闪关灯 false:关闭闪光灯
*/
open
func
setTorch
(
torch
:
Bool
)
{
if
isGetFlash
()
{
guard
let
device
=
input
?
.
device
else
{
return
}
do
{
try
device
.
lockForConfiguration
()
device
.
torchMode
=
torch
?
AVCaptureDevice
.
TorchMode
.
on
:
AVCaptureDevice
.
TorchMode
.
off
device
.
unlockForConfiguration
()
}
catch
let
error
as
NSError
{
print
(
"device.lockForConfiguration():
\(
error
)
"
)
}
}
}
/**
------闪光灯打开或关闭
*/
open
func
changeTorch
()
{
if
isGetFlash
()
{
guard
let
device
=
input
?
.
device
else
{
return
}
do
{
try
device
.
lockForConfiguration
()
var
torch
=
false
if
device
.
torchMode
==
AVCaptureDevice
.
TorchMode
.
on
{
torch
=
false
}
else
if
device
.
torchMode
==
AVCaptureDevice
.
TorchMode
.
off
{
torch
=
true
}
device
.
torchMode
=
torch
?
AVCaptureDevice
.
TorchMode
.
on
:
AVCaptureDevice
.
TorchMode
.
off
device
.
unlockForConfiguration
()
}
catch
let
error
as
NSError
{
print
(
"device.lockForConfiguration():
\(
error
)
"
)
}
}
}
// MARK: - -----获取系统默认支持的码的类型
static
func
defaultMetaDataObjectTypes
()
->
[
AVMetadataObject
.
ObjectType
]
{
var
types
=
[
AVMetadataObject
.
ObjectType
.
qr
,
AVMetadataObject
.
ObjectType
.
upce
,
AVMetadataObject
.
ObjectType
.
code39
,
AVMetadataObject
.
ObjectType
.
code39Mod43
,
AVMetadataObject
.
ObjectType
.
ean13
,
AVMetadataObject
.
ObjectType
.
ean8
,
AVMetadataObject
.
ObjectType
.
code93
,
AVMetadataObject
.
ObjectType
.
code128
,
AVMetadataObject
.
ObjectType
.
pdf417
,
AVMetadataObject
.
ObjectType
.
aztec
]
types
.
append
(
AVMetadataObject
.
ObjectType
.
interleaved2of5
)
types
.
append
(
AVMetadataObject
.
ObjectType
.
itf14
)
types
.
append
(
AVMetadataObject
.
ObjectType
.
dataMatrix
)
return
types
as
[
AVMetadataObject
.
ObjectType
]
}
static
func
isSysIos8Later
()
->
Bool
{
if
#available(iOS 8, *)
{
return
true
}
return
false
}
/**
识别二维码码图像
- parameter image: 二维码图像
- returns: 返回识别结果
*/
public
static
func
recognizeQRImage
(
image
:
UIImage
)
->
[
LBXScanResult
]
{
var
returnResult
:
[
LBXScanResult
]
=
[]
if
LBXScanWrapper
.
isSysIos8Later
()
{
guard
let
detector
=
CIDetector
(
ofType
:
CIDetectorTypeQRCode
,
context
:
nil
,
options
:
[
CIDetectorAccuracy
:
CIDetectorAccuracyHigh
]),
let
cgImage
=
image
.
cgImage
else
{
return
returnResult
}
let
img
=
CIImage
(
cgImage
:
cgImage
)
let
features
:
[
CIFeature
]?
=
detector
.
features
(
in
:
img
,
options
:
[
CIDetectorAccuracy
:
CIDetectorAccuracyHigh
])
if
let
validFeatures
=
features
,
validFeatures
.
count
>
0
{
let
feature
=
validFeatures
[
0
]
if
let
featureTmp
=
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: - - - 生成二维码,背景色及二维码颜色设置
public
static
func
createCode
(
codeType
:
String
,
codeString
:
String
,
size
:
CGSize
,
qrColor
:
UIColor
,
bkColor
:
UIColor
)
->
UIImage
?
{
guard
let
stringData
=
codeString
.
data
(
using
:
String
.
Encoding
.
utf8
),
let
qrFilter
=
CIFilter
(
name
:
codeType
)
else
{
return
nil
}
qrFilter
.
setValue
(
stringData
,
forKey
:
"inputMessage"
)
qrFilter
.
setValue
(
"M"
,
forKey
:
"inputCorrectionLevel"
)
guard
let
outputImage
=
qrFilter
.
outputImage
,
let
colorFilter
=
CIFilter
(
name
:
"CIFalseColor"
,
parameters
:
[
"inputImage"
:
outputImage
,
"inputColor0"
:
CIColor
(
cgColor
:
qrColor
.
cgColor
),
"inputColor1"
:
CIColor
(
cgColor
:
bkColor
.
cgColor
)]),
let
qrImage
=
colorFilter
.
outputImage
,
let
cgImage
=
CIContext
()
.
createCGImage
(
qrImage
,
from
:
qrImage
.
extent
)
else
{
return
nil
}
UIGraphicsBeginImageContext
(
size
)
guard
let
context
=
UIGraphicsGetCurrentContext
()
else
{
UIGraphicsEndImageContext
()
return
nil
}
context
.
interpolationQuality
=
CGInterpolationQuality
.
none
context
.
scaleBy
(
x
:
1.0
,
y
:
-
1.0
)
context
.
draw
(
cgImage
,
in
:
context
.
boundingBoxOfClipPath
)
let
codeImage
=
UIGraphicsGetImageFromCurrentImageContext
()
UIGraphicsEndImageContext
()
return
codeImage
}
public
static
func
createCode128
(
codeString
:
String
,
size
:
CGSize
,
qrColor
:
UIColor
,
bkColor
:
UIColor
)
->
UIImage
?
{
guard
let
stringData
=
codeString
.
data
(
using
:
String
.
Encoding
.
utf8
),
let
qrFilter
=
CIFilter
(
name
:
"CICode39BarcodeGenerator"
)
else
{
return
nil
}
qrFilter
.
setDefaults
()
qrFilter
.
setValue
(
stringData
,
forKey
:
"inputMessage"
)
guard
let
outputImage
=
qrFilter
.
outputImage
else
{
return
nil
}
let
context
=
CIContext
()
guard
let
cgImage
=
context
.
createCGImage
(
outputImage
,
from
:
outputImage
.
extent
)
else
{
return
nil
}
let
image
=
UIImage
(
cgImage
:
cgImage
,
scale
:
1.0
,
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
let
validImg
=
img
{
let
imgRotation
=
imageRotation
(
image
:
validImg
,
orientation
:
.
right
)
return
imgRotation
}
return
nil
}
// 根据二维码的区域截取二维码区域图像
public
static
func
getConcreteCodeImage
(
srcCodeImage
:
UIImage
,
rect
:
CGRect
)
->
UIImage
?
{
if
rect
.
isEmpty
{
return
nil
}
let
img
=
imageByCroppingWithStyle
(
srcImg
:
srcCodeImage
,
rect
:
rect
)
if
let
validImg
=
img
{
let
imgRotation
=
imageRotation
(
image
:
validImg
,
orientation
:
.
right
)
return
imgRotation
}
return
nil
}
// 获取二维码的图像区域
public
static
func
getConcreteCodeRectFromImage
(
srcCodeImage
:
UIImage
,
codeResult
:
LBXScanResult
)
->
CGRect
{
guard
let
corners
=
codeResult
.
arrayCorner
,
corners
.
count
>=
4
else
{
return
CGRect
.
zero
}
guard
let
corner
=
corners
as?
[[
String
:
Float
]]
else
{
return
CGRect
.
zero
}
let
dicTopLeft
=
corner
[
0
]
let
dicTopRight
=
corner
[
1
]
let
dicBottomRight
=
corner
[
2
]
let
dicBottomLeft
=
corner
[
3
]
guard
let
xLeftTopRatio
=
dicTopLeft
[
"X"
],
let
yLeftTopRatio
=
dicTopLeft
[
"Y"
],
let
xRightTopRatio
=
dicTopRight
[
"X"
],
let
yRightTopRatio
=
dicTopRight
[
"Y"
],
let
xBottomRightRatio
=
dicBottomRight
[
"X"
],
let
yBottomRightRatio
=
dicBottomRight
[
"Y"
],
let
xLeftBottomRatio
=
dicBottomLeft
[
"X"
],
let
yLeftBottomRatio
=
dicBottomLeft
[
"Y"
]
else
{
return
CGRect
.
zero
}
// 由于截图只能矩形,所以截图不规则四边形的最大外围
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的图像
*/
public
static
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
))
guard
let
context
=
UIGraphicsGetCurrentContext
()
else
{
UIGraphicsEndImageContext
()
return
nil
}
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
?
{
guard
let
imageRef
=
srcImg
.
cgImage
,
let
imagePartRef
=
imageRef
.
cropping
(
to
:
rect
)
else
{
return
nil
}
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
.
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
case
.
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
case
.
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
default
:
rotate
=
0.0
rect
=
CGRect
(
x
:
0
,
y
:
0
,
width
:
image
.
size
.
width
,
height
:
image
.
size
.
height
)
translateX
=
0
translateY
=
0
}
UIGraphicsBeginImageContext
(
rect
.
size
)
guard
let
context
=
UIGraphicsGetCurrentContext
(),
let
cgImage
=
image
.
cgImage
else
{
UIGraphicsEndImageContext
()
return
image
}
// 做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
(
cgImage
,
in
:
CGRect
(
x
:
0
,
y
:
0
,
width
:
rect
.
size
.
width
,
height
:
rect
.
size
.
height
))
let
newPic
=
UIGraphicsGetImageFromCurrentImageContext
()
UIGraphicsEndImageContext
()
return
newPic
??
image
}
deinit
{
// print("LBXScanWrapper deinit")
}
}
galaxy/galaxy/Res/Assets.xcassets/Mine/qr_scan_icon.imageset/Contents.json
0 → 100644
View file @
69a1a665
{
"images"
:
[
{
"idiom"
:
"universal"
,
"scale"
:
"1x"
},
{
"filename"
:
"qr_scan_icon@2x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"2x"
},
{
"filename"
:
"qr_scan_icon@3x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"3x"
}
],
"info"
:
{
"author"
:
"xcode"
,
"version"
:
1
}
}
galaxy/galaxy/Res/Assets.xcassets/Mine/qr_scan_icon.imageset/qr_scan_icon@2x.png
0 → 100644
View file @
69a1a665
345 Bytes
galaxy/galaxy/Res/Assets.xcassets/Mine/qr_scan_icon.imageset/qr_scan_icon@3x.png
0 → 100644
View file @
69a1a665
437 Bytes
galaxy/galaxy/Res/Assets.xcassets/Mine/scan_move_line.imageset/Contents.json
0 → 100644
View file @
69a1a665
{
"images"
:
[
{
"idiom"
:
"universal"
,
"scale"
:
"1x"
},
{
"filename"
:
"scan_move_line@2x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"2x"
},
{
"filename"
:
"scan_move_line@3x.png"
,
"idiom"
:
"universal"
,
"scale"
:
"3x"
}
],
"info"
:
{
"author"
:
"xcode"
,
"version"
:
1
}
}
galaxy/galaxy/Res/Assets.xcassets/Mine/scan_move_line.imageset/scan_move_line@2x.png
0 → 100644
View file @
69a1a665
30 KB
galaxy/galaxy/Res/Assets.xcassets/Mine/scan_move_line.imageset/scan_move_line@3x.png
0 → 100644
View file @
69a1a665
61.4 KB
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment