├── .gitignore
├── LICENSE
├── README.md
├── ptDrag
├── pointsDrag.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── pointsDrag
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ ├── single_lhs_rotate.imageset
│ │ ├── Contents.json
│ │ ├── icon_zuozhuan@2x.png
│ │ └── icon_zuozhuan@3x.png
│ └── single_rhs_rotate.imageset
│ │ ├── Contents.json
│ │ ├── icon_youzhuan@2x.png
│ │ └── icon_youzhuan@3x.png
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ ├── MagnifierView.swift
│ ├── SceneDelegate.swift
│ ├── SketchController.swift
│ ├── SketchModel.swift
│ ├── SketchView.swift
│ ├── Util
│ ├── FontAdd.swift
│ ├── ImgAdd.swift
│ ├── PointAdd.swift
│ └── sizeAdd.swift
│ ├── View
│ └── DirectionRotateB.swift
│ └── ViewController.swift
├── ptDragEasy
├── pointsDrag.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── pointsDrag
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ ├── single_lhs_rotate.imageset
│ │ ├── Contents.json
│ │ ├── icon_zuozhuan@2x.png
│ │ └── icon_zuozhuan@3x.png
│ └── single_rhs_rotate.imageset
│ │ ├── Contents.json
│ │ ├── icon_youzhuan@2x.png
│ │ └── icon_youzhuan@3x.png
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ ├── MagnifierView.swift
│ ├── SceneDelegate.swift
│ ├── SketchController.swift
│ ├── SketchModel.swift
│ ├── SketchView.swift
│ ├── Util
│ ├── FontAdd.swift
│ ├── ImgAdd.swift
│ ├── PointAdd.swift
│ └── sizeAdd.swift
│ ├── View
│ └── DirectionRotateB.swift
│ └── ViewController.swift
├── secondCrop
├── README.md
├── raw
│ ├── Example
│ │ ├── Example.xcodeproj
│ │ │ ├── project.pbxproj
│ │ │ └── project.xcworkspace
│ │ │ │ ├── contents.xcworkspacedata
│ │ │ │ └── xcshareddata
│ │ │ │ └── IDEWorkspaceChecks.plist
│ │ └── Example
│ │ │ ├── AppDelegate.swift
│ │ │ ├── Assets.xcassets
│ │ │ └── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ │ ├── Base.lproj
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ │ ├── Classes
│ │ │ ├── Array+shift.swift
│ │ │ ├── CGPoint+geometry.swift
│ │ │ ├── SEAreaView.swift
│ │ │ ├── SECornerView.swift
│ │ │ ├── SECropError.swift
│ │ │ ├── SECropView.swift
│ │ │ ├── SEQuadrangleHelper.swift
│ │ │ └── UIView+globalCoordinates.swift
│ │ │ ├── ImageViewController.swift
│ │ │ ├── Info.plist
│ │ │ ├── Resources
│ │ │ └── paper.jpg
│ │ │ └── ViewController.swift
│ ├── Pod
│ │ └── Classes
│ │ │ ├── Array+shift.swift
│ │ │ ├── CGPoint+geometry.swift
│ │ │ ├── SEAreaView.swift
│ │ │ ├── SECornerView.swift
│ │ │ ├── SECropError.swift
│ │ │ ├── SECropView.swift
│ │ │ ├── SEQuadrangleHelper.swift
│ │ │ └── UIView+globalCoordinates.swift
│ └── README.md
├── secondCrop.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── secondCrop
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── ImageViewController.swift
│ ├── Info.plist
│ ├── Resources
│ └── paper.jpg
│ ├── SceneDelegate.swift
│ ├── ViewController.swift
│ └── crop
│ ├── Array+shift.swift
│ ├── CGPoint+geometry.swift
│ ├── SEAreaView.swift
│ ├── SECornerView.swift
│ ├── SECropError.swift
│ ├── SECropView.swift
│ ├── SEQuadrangleHelper.swift
│ └── UIView+globalCoordinates.swift
├── src
├── 0.PNG
├── 1.PNG
├── 2.PNG
├── 3.PNG
└── second.png
└── thirdCapture
├── README.md
├── captureAndFilter.xcodeproj
├── project.pbxproj
└── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── captureAndFilter
├── AppDelegate.swift
├── Assets.xcassets
│ ├── 4
│ │ ├── 4_tag_mask_plus.imageset
│ │ │ ├── Contents.json
│ │ │ ├── 编组@2x.png
│ │ │ └── 编组@3x.png
│ │ ├── 4_zhi_zhang_jump.imageset
│ │ │ ├── Contents.json
│ │ │ ├── 编组 8@2x.png
│ │ │ └── 编组 8@3x.png
│ │ ├── Contents.json
│ │ ├── album_4_kiWa.imageset
│ │ │ ├── Contents.json
│ │ │ ├── 编组 2@2x.png
│ │ │ └── 编组 2@3x.png
│ │ ├── audio_4_3.imageset
│ │ │ ├── Contents.json
│ │ │ ├── 内容区/icon/120*120/创建音频@2x.png
│ │ │ └── 内容区/icon/120*120/创建音频@3x.png
│ │ ├── camera_4.imageset
│ │ │ ├── Contents.json
│ │ │ ├── 内容区/icon/历史记录@2x.png
│ │ │ └── 内容区/icon/历史记录@3x.png
│ │ ├── camera_4_highWox.imageset
│ │ │ ├── Contents.json
│ │ │ ├── 拍摄键@2x.png
│ │ │ └── 拍摄键@3x.png
│ │ ├── camera_4_tip.imageset
│ │ │ ├── Contents.json
│ │ │ ├── 弹窗提示@2x.png
│ │ │ └── 弹窗提示@3x.png
│ │ ├── fluorescence_4_1.imageset
│ │ │ ├── Contents.json
│ │ │ ├── 内容区/icon/120*120/荧光笔取词@2x.png
│ │ │ └── 内容区/icon/120*120/荧光笔取词@3x.png
│ │ ├── fork_4_kWa.imageset
│ │ │ ├── Contents.json
│ │ │ ├── 编组@2x.png
│ │ │ └── 编组@3x.png
│ │ ├── mine_4.imageset
│ │ │ ├── Contents.json
│ │ │ ├── 矩形备份 2@2x.png
│ │ │ └── 矩形备份 2@3x.png
│ │ ├── mine_4_arrow_item.imageset
│ │ │ ├── Contents.json
│ │ │ ├── 路径 8@2x.png
│ │ │ └── 路径 8@3x.png
│ │ ├── mine_4_selected.imageset
│ │ │ ├── Contents.json
│ │ │ ├── tab栏/icon/我的/选中@2x.png
│ │ │ └── tab栏/icon/我的/选中@3x.png
│ │ ├── mine_woX_header_4_arrow.imageset
│ │ │ ├── Contents.json
│ │ │ ├── 内容区/icon/历史记录@2x.png
│ │ │ └── 内容区/icon/历史记录@3x.png
│ │ ├── mine_woX_header_4_bg.imageset
│ │ │ ├── Contents.json
│ │ │ ├── 矩形@2x.png
│ │ │ └── 矩形@3x.png
│ │ ├── plus_4.imageset
│ │ │ ├── Contents.json
│ │ │ ├── tab栏/icon/加号@2x.png
│ │ │ └── tab栏/icon/加号@3x.png
│ │ ├── pop_fork_4.imageset
│ │ │ ├── Contents.json
│ │ │ ├── 内容区/icon/历史记录@2x.png
│ │ │ └── 内容区/icon/历史记录@3x.png
│ │ ├── rotate_4_X.imageset
│ │ │ ├── Contents.json
│ │ │ ├── 内容区/icon/历史记录@2x.png
│ │ │ └── 内容区/icon/历史记录@3x.png
│ │ ├── takenImg_4_tick.imageset
│ │ │ ├── Contents.json
│ │ │ ├── 拍摄键@2x.png
│ │ │ └── 拍摄键@3x.png
│ │ ├── textBook_4.imageset
│ │ │ ├── Contents.json
│ │ │ ├── 矩形备份 2@2x.png
│ │ │ └── 矩形备份 2@3x.png
│ │ ├── textBook_4_selected.imageset
│ │ │ ├── Contents.json
│ │ │ ├── tab栏/icon/课本/选中@2x.png
│ │ │ └── tab栏/icon/课本/选中@3x.png
│ │ └── text_4_2.imageset
│ │ │ ├── Contents.json
│ │ │ ├── 内容区/icon/120*120/创建文本@2x.png
│ │ │ └── 内容区/icon/120*120/创建文本@3x.png
│ ├── 5
│ │ ├── Contents.json
│ │ └── not_a_net.imageset
│ │ │ ├── Contents.json
│ │ │ ├── 编组 2@2x.png
│ │ │ └── 编组 2@3x.png
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── CusCamera.swift
├── Info.plist
├── SceneDelegate.swift
├── SnapKit.framework
│ ├── Headers
│ │ └── SnapKit-Swift.h
│ ├── Info.plist
│ ├── Modules
│ │ ├── SnapKit.swiftmodule
│ │ │ ├── Project
│ │ │ │ ├── arm64-apple-ios.swiftsourceinfo
│ │ │ │ └── arm64.swiftsourceinfo
│ │ │ ├── arm64-apple-ios.swiftdoc
│ │ │ ├── arm64-apple-ios.swiftmodule
│ │ │ ├── arm64.swiftdoc
│ │ │ └── arm64.swiftmodule
│ │ └── module.modulemap
│ └── SnapKit
├── ViewController.swift
├── crop
│ ├── Array+shift.swift
│ ├── CGPoint+geometry.swift
│ ├── SEAreaView.swift
│ ├── SECornerView.swift
│ ├── SECropError.swift
│ ├── SECropView.swift
│ ├── SEQuadrangleHelper.swift
│ └── UIView+globalCoordinates.swift
├── two
│ ├── ButtomViewFinal.swift
│ ├── ButtomViewP.swift
│ └── LinedTipView.swift
└── util
│ ├── DebugLayer.swift
│ ├── FontAdd.swift
│ ├── RectAdd.swift
│ ├── UIImageAdd.swift
│ ├── ZLCustomCamera.swift
│ ├── ZLGeneralDefine.swift
│ └── ZLPhotoConfiguration.swift
├── captureAndFilterTests
├── Info.plist
└── captureAndFilterTests.swift
└── captureAndFilterUITests
├── Info.plist
└── captureAndFilterUITests.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xcuserstate
23 |
24 | ## Obj-C/Swift specific
25 | *.hmap
26 | *.ipa
27 | *.dSYM.zip
28 | *.dSYM
29 | *.DS_store
30 | # CocoaPods
31 | #
32 | # We recommend against adding the Pods directory to your .gitignore. However
33 | # you should judge for yourself, the pros and cons are mentioned at:
34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
35 | #
36 | # Pods/
37 |
38 | # Carthage
39 | #
40 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
41 | # Carthage/Checkouts
42 |
43 | Carthage/Build
44 |
45 | # fastlane
46 | #
47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
48 | # screenshots whenever they are needed.
49 | # For more information about the recommended setup visit:
50 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
51 |
52 | fastlane/report.xml
53 | fastlane/Preview.html
54 | fastlane/screenshots
55 | fastlane/test_output
56 |
57 | # Code Injection
58 | #
59 | # After new code Injection tools there's a generated folder /iOSInjectionProject
60 | # https://github.com/johnno1962/injectionforxcode
61 |
62 | iOSInjectionProject/
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 邓江洲
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SmartCropTry
2 | Smart Crop Try, 努力仿照 “全能扫描王”
3 |
4 |
5 | ## [juejin blog: 仿扫描全能王的选择区域功能:拍照,旋转](https://juejin.im/post/6882950524786704398)
6 |
7 |
8 | ## [juejin blog: 低仿扫描全能王的选择区域功能](https://juejin.im/post/6875134095232335880)
9 |
10 |
11 | ### 添加选择区域,是否 OK 的交互
12 |
13 | > 有参考 rzmn/CropView
14 |
15 |
16 | 
17 |
18 |
19 | ### 端点拖动, 和放大镜
20 |
21 | 
22 |
23 |
24 | ### 凸四边形判定
25 |
26 |
27 | 
28 |
29 |
30 | ### 交叉边,重新连线
31 |
32 |
33 | 
34 |
35 |
36 | 
37 |
--------------------------------------------------------------------------------
/ptDrag/pointsDrag.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ptDrag/pointsDrag.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ptDrag/pointsDrag/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // pointsDrag
4 | //
5 | // Created by Jz D on 2020/9/16.
6 | // Copyright © 2020 Jz D. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 |
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
17 | // Override point for customization after application launch.
18 | return true
19 | }
20 |
21 | // MARK: UISceneSession Lifecycle
22 |
23 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
24 | // Called when a new scene session is being created.
25 | // Use this method to select a configuration to create the new scene with.
26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
27 | }
28 |
29 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
30 | // Called when the user discards a scene session.
31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
33 | }
34 |
35 |
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/ptDrag/pointsDrag/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/ptDrag/pointsDrag/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/ptDrag/pointsDrag/Assets.xcassets/single_lhs_rotate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "icon_zuozhuan@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "icon_zuozhuan@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/ptDrag/pointsDrag/Assets.xcassets/single_lhs_rotate.imageset/icon_zuozhuan@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/ptDrag/pointsDrag/Assets.xcassets/single_lhs_rotate.imageset/icon_zuozhuan@2x.png
--------------------------------------------------------------------------------
/ptDrag/pointsDrag/Assets.xcassets/single_lhs_rotate.imageset/icon_zuozhuan@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/ptDrag/pointsDrag/Assets.xcassets/single_lhs_rotate.imageset/icon_zuozhuan@3x.png
--------------------------------------------------------------------------------
/ptDrag/pointsDrag/Assets.xcassets/single_rhs_rotate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "icon_youzhuan@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "icon_youzhuan@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/ptDrag/pointsDrag/Assets.xcassets/single_rhs_rotate.imageset/icon_youzhuan@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/ptDrag/pointsDrag/Assets.xcassets/single_rhs_rotate.imageset/icon_youzhuan@2x.png
--------------------------------------------------------------------------------
/ptDrag/pointsDrag/Assets.xcassets/single_rhs_rotate.imageset/icon_youzhuan@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/ptDrag/pointsDrag/Assets.xcassets/single_rhs_rotate.imageset/icon_youzhuan@3x.png
--------------------------------------------------------------------------------
/ptDrag/pointsDrag/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/ptDrag/pointsDrag/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/ptDrag/pointsDrag/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | NSCameraUsageDescription
14 | 需要
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UIApplicationSceneManifest
26 |
27 | UIApplicationSupportsMultipleScenes
28 |
29 | UISceneConfigurations
30 |
31 | UIWindowSceneSessionRoleApplication
32 |
33 |
34 | UISceneConfigurationName
35 | Default Configuration
36 | UISceneDelegateClassName
37 | $(PRODUCT_MODULE_NAME).SceneDelegate
38 | UISceneStoryboardFile
39 | Main
40 |
41 |
42 |
43 |
44 | UILaunchStoryboardName
45 | LaunchScreen
46 | UIMainStoryboardFile
47 | Main
48 | UIRequiredDeviceCapabilities
49 |
50 | armv7
51 |
52 | UISupportedInterfaceOrientations
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationLandscapeLeft
56 | UIInterfaceOrientationLandscapeRight
57 |
58 | UISupportedInterfaceOrientations~ipad
59 |
60 | UIInterfaceOrientationPortrait
61 | UIInterfaceOrientationPortraitUpsideDown
62 | UIInterfaceOrientationLandscapeLeft
63 | UIInterfaceOrientationLandscapeRight
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/ptDrag/pointsDrag/MagnifierView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MagnifierView.swift
3 | // MagnifierView_demo
4 | //
5 | // Created by lidongxi on 2018/3/23.
6 | // Copyright © 2018年 lidongxi. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class MagnifierView: UIView {
12 |
13 |
14 | public var renderView: UIView?
15 |
16 | public var renderPoint : CGPoint = CGPoint.zero {
17 | didSet{
18 | self.layer.setNeedsDisplay()
19 | }
20 | }
21 |
22 | override var isHidden: Bool {
23 | didSet{
24 | layer.borderColor = isHidden ? UIColor.clear.cgColor : UIColor.lightGray.cgColor
25 | }
26 | }
27 |
28 |
29 |
30 | override init(frame: CGRect) {
31 | super.init(frame: frame)
32 |
33 | layer.borderWidth = 1
34 | layer.borderColor = UIColor.lightGray.cgColor
35 | isHidden = true
36 | layer.delegate = self
37 | // 保证和屏幕读取像素的比例一致
38 | layer.contentsScale = UIScreen.main.scale
39 | }
40 |
41 | required init?(coder aDecoder: NSCoder) {
42 | fatalError("init(coder:) has not been implemented")
43 | }
44 |
45 | override func draw(_ layer: CALayer, in ctx: CGContext) {
46 | super.draw(layer, in: ctx)
47 | guard let renderer = renderView else {
48 | return
49 | }
50 | // 提前位移半个长宽的坑
51 | ctx.translateBy(x: frame.size.width * 0.5, y: frame.size.height * 0.5)
52 | /// 缩放比例
53 | let scale : CGFloat = 3
54 | ctx.scaleBy(x: scale, y: scale)
55 | // 再次位移后就可以把触摸点移至self.center的位置
56 | ctx.translateBy(x: -renderPoint.x, y: -renderPoint.y)
57 |
58 | renderer.layer.render(in: ctx)
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/ptDrag/pointsDrag/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // pointsDrag
4 | //
5 | // Created by Jz D on 2020/9/16.
6 | // Copyright © 2020 Jz D. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
12 |
13 | var window: UIWindow?
14 |
15 |
16 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
17 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
18 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
19 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
20 | guard let _ = (scene as? UIWindowScene) else { return }
21 | }
22 |
23 | func sceneDidDisconnect(_ scene: UIScene) {
24 | // Called as the scene is being released by the system.
25 | // This occurs shortly after the scene enters the background, or when its session is discarded.
26 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
27 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
28 | }
29 |
30 | func sceneDidBecomeActive(_ scene: UIScene) {
31 | // Called when the scene has moved from an inactive state to an active state.
32 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
33 | }
34 |
35 | func sceneWillResignActive(_ scene: UIScene) {
36 | // Called when the scene will move from an active state to an inactive state.
37 | // This may occur due to temporary interruptions (ex. an incoming phone call).
38 | }
39 |
40 | func sceneWillEnterForeground(_ scene: UIScene) {
41 | // Called as the scene transitions from the background to the foreground.
42 | // Use this method to undo the changes made on entering the background.
43 | }
44 |
45 | func sceneDidEnterBackground(_ scene: UIScene) {
46 | // Called as the scene transitions from the foreground to the background.
47 | // Use this method to save data, release shared resources, and store enough scene-specific state information
48 | // to restore the scene back to its current state.
49 | }
50 |
51 |
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/ptDrag/pointsDrag/Util/FontAdd.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FontAdd.swift
3 | //
4 | //
5 | // Created by Jz D on 2019/8/23.
6 | //
7 |
8 | import UIKit
9 |
10 |
11 |
12 | enum FontWeight: String {
13 | case light = "Light"
14 | case regular = "Regular"
15 | case medium = "Medium"
16 |
17 | case semibold = "Semibold"
18 | case bold = "Bold"
19 | case heavy = "Heavy"
20 | }
21 |
22 | enum FontType: String {
23 | case PingFangSC = "PingFangSC"
24 | case SFProText = "SFProText"
25 | }
26 |
27 | extension UIFont {
28 |
29 | static func heavy(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {
30 | return customFont(type, weight: .heavy, fontSize: fontSize)
31 | }
32 |
33 | static func regular(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {
34 | return customFont(type, weight: .regular, fontSize: fontSize)
35 | }
36 |
37 | static func bold(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {
38 | return customFont(type, weight: .bold, fontSize: fontSize)
39 | }
40 |
41 | static func light(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {
42 | return customFont(type, weight: .light, fontSize: fontSize)
43 | }
44 |
45 | static func medium(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {
46 | return customFont(type, weight: .medium, fontSize: fontSize)
47 | }
48 |
49 | static func semibold(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {
50 | return customFont(type, weight: .semibold, fontSize: fontSize)
51 | }
52 |
53 | /// 自定义字体
54 | static func customFont(_ type: FontType, weight: FontWeight, fontSize: CGFloat) -> UIFont {
55 | let realFontSize = fontSize
56 |
57 | if let customFont = UIFont(name: "\(type.rawValue)-\(weight.rawValue)", size: realFontSize) {
58 | return customFont
59 | }
60 |
61 | var systemWeight = UIFont.Weight.regular
62 | switch weight {
63 | case .light:
64 | systemWeight = UIFont.Weight.light
65 | case .regular:
66 | systemWeight = UIFont.Weight.regular
67 | case .medium:
68 | systemWeight = UIFont.Weight.medium
69 | case .semibold:
70 | systemWeight = UIFont.Weight.semibold
71 | case .bold:
72 | systemWeight = UIFont.Weight.bold
73 | case .heavy:
74 | systemWeight = UIFont.Weight.heavy
75 | }
76 | return UIFont.systemFont(ofSize: realFontSize, weight: systemWeight)
77 | }
78 | }
79 |
80 |
81 |
82 |
83 |
84 | extension UIFont {
85 |
86 | static let scoreName = UIFont.medium(ofSize: 16)
87 | static let headerFirstThree = UIFont.medium(ofSize: 22)
88 | static let accountListTitle = UIFont.regular(ofSize: 16)
89 |
90 |
91 |
92 | static let myStudyTitle = UIFont.medium(ofSize: 18)
93 | static let myStudyListScoreName = UIFont.medium(ofSize: 14)
94 | static let loginHeaderName = UIFont.medium(ofSize: 16)
95 |
96 |
97 | }
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/ptDrag/pointsDrag/Util/ImgAdd.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImgAdd.swift
3 | // pointsDrag
4 | //
5 | // Created by Jz D on 2020/10/10.
6 | // Copyright © 2020 Jz D. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 |
12 |
13 |
14 | extension UIImage{
15 |
16 |
17 | func image(rotated time: Int) -> UIImage{
18 | guard time != 0 else {
19 | return self
20 | }
21 |
22 | let radian = CGFloat(time) * CGFloat.pi / 2
23 | let rotatedSize = CGRect(origin: .zero, size: size)
24 | .applying(CGAffineTransform(rotationAngle: radian))
25 | .integral.size
26 | UIGraphicsBeginImageContext(rotatedSize)
27 | if let context = UIGraphicsGetCurrentContext() {
28 | let origin = CGPoint(x: rotatedSize.width / 2.0,
29 | y: rotatedSize.height / 2.0)
30 | context.translateBy(x: origin.x, y: origin.y)
31 | context.rotate(by: radian)
32 | draw(in: CGRect(x: -origin.y, y: -origin.x,
33 | width: size.width, height: size.height))
34 | let rotatedImage = UIGraphicsGetImageFromCurrentImageContext()
35 | UIGraphicsEndImageContext()
36 |
37 | return rotatedImage ?? self
38 | }
39 |
40 | return self
41 |
42 | }
43 |
44 |
45 |
46 | }
47 |
48 |
49 |
50 | extension UIImage {
51 | var leftTurn: UIImage{
52 | image(rotated: 1)
53 | }
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/ptDrag/pointsDrag/Util/PointAdd.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PointAdd.swift
3 | // pointsDrag
4 | //
5 | // Created by Jz D on 2020/10/12.
6 | // Copyright © 2020 Jz D. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 |
12 |
13 |
14 |
15 | func -(lhs: CGPoint, rhs: CGPoint) -> CGPoint {
16 | return CGPoint(x: lhs.x - rhs.x, y: lhs.y - rhs.y)
17 | }
18 |
19 |
20 |
21 | // 用于坐标系变换
22 |
23 | extension CGPoint{
24 | mutating
25 | func scale(by rate: CGFloat, forS size: CGSize){
26 | let newX = size.width * 0.5 + (x - size.width * 0.5) * rate
27 | let newY = size.height * 0.5 + (y - size.height * 0.5) * rate
28 | self = CGPoint(x: newX, y: newY)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/ptDrag/pointsDrag/Util/sizeAdd.swift:
--------------------------------------------------------------------------------
1 | //
2 | // sizeAdd.swift
3 | // pointsDrag
4 | //
5 | // Created by Jz D on 2020/10/12.
6 | // Copyright © 2020 Jz D. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 |
12 |
13 | extension CGSize{
14 |
15 |
16 |
17 |
18 | func size(in std: CGSize) -> CGSize{
19 |
20 | let hRatio = height / std.height
21 | let wRatio = width / std.width
22 |
23 | let reSolution = height / width
24 |
25 |
26 | print(width, height)
27 |
28 | let s: CGSize
29 | if hRatio > wRatio{
30 | s = CGSize(width: std.height / reSolution, height: std.height)
31 | }
32 | else{
33 | s = CGSize(width: std.width, height: std.width * reSolution)
34 | }
35 | return s
36 |
37 | }
38 |
39 |
40 | func size(by horizontal: CGFloat) -> CGSize{
41 |
42 |
43 |
44 | let reSolution = height / width
45 |
46 |
47 | print(width, height)
48 |
49 | return CGSize(width: horizontal, height: horizontal / reSolution)
50 |
51 |
52 | }
53 |
54 |
55 | func ratio(by rate: CGFloat) -> CGSize{
56 | return CGSize(width: width * rate, height: height * rate)
57 | }
58 |
59 |
60 |
61 | var reverted: CGSize{
62 | CGSize(width: height, height: width)
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/ptDrag/pointsDrag/View/DirectionRotateB.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DirectionRotateB.swift
3 | // pointsDrag
4 | //
5 | // Created by Jz D on 2020/10/12.
6 | // Copyright © 2020 Jz D. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 |
12 |
13 |
14 | enum RotateOpt{
15 | case lhs, rhs
16 | }
17 |
18 |
19 |
20 |
21 | class DirectionRotateB: UIButton {
22 |
23 |
24 | let imgSize = CGSize(width: 32, height: 32)
25 | let titleW: CGFloat = 36
26 |
27 | let spacing: CGFloat = 6
28 |
29 |
30 | init(opt kind: RotateOpt){
31 |
32 | super.init(frame: .zero)
33 | let img: UIImage?
34 | let title: String
35 | switch kind {
36 | case .lhs:
37 | title = "左转"
38 |
39 | img = UIImage(named: "single_lhs_rotate")
40 | case .rhs:
41 | title = "右转"
42 |
43 | img = UIImage(named: "single_rhs_rotate")
44 | }
45 | setImage(img, for: .normal)
46 | setTitle(title, for: .normal)
47 | setTitleColor(UIColor(rgb: 0x666666), for: .normal)
48 | backgroundColor = UIColor.white
49 |
50 | titleLabel?.font = UIFont.regular(ofSize: 18)
51 | }
52 |
53 | required init?(coder: NSCoder) {
54 | fatalError("init(coder:) has not been implemented")
55 | }
56 |
57 |
58 |
59 |
60 |
61 |
62 | override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
63 |
64 |
65 | let x = contentRect.origin.x
66 | let y = (contentRect.size.height - imgSize.height)/2
67 | return CGRect(x: x, y: y, width: imgSize.width, height: imgSize.height)
68 | }
69 |
70 |
71 |
72 | override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
73 | let titleH: CGFloat = 24
74 | let x = contentRect.origin.x + imgSize.width + spacing
75 | let y = (contentRect.size.height - titleH)/2
76 | return CGRect(x: x, y: y, width: titleW, height: titleH)
77 |
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/ptDrag/pointsDrag/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // pointsDrag
4 | //
5 | // Created by Jz D on 2020/10/10.
6 | // Copyright © 2020 Jz D. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ViewController: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 |
16 | // Do any additional setup after loading the view.
17 | }
18 |
19 |
20 |
21 |
22 | @IBAction func photoIt(_ sender: Any) {
23 |
24 | let picker = UIImagePickerController()
25 | picker.delegate = self
26 | picker.sourceType = UIImagePickerController.SourceType.camera
27 | present(picker, animated: true)
28 |
29 | }
30 |
31 |
32 | }
33 |
34 |
35 |
36 |
37 | extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate{
38 |
39 |
40 | func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
41 |
42 | picker.dismiss(animated: true)
43 |
44 |
45 | if let image = info[.originalImage] as? UIImage{
46 | var midImg = image
47 | let s = image.size
48 | if s.width > s.height{
49 | midImg = image.leftTurn
50 | }
51 |
52 |
53 | let sketchC = SketchController()
54 | sketchC.image = midImg
55 | sketchC.modalPresentationStyle = .fullScreen
56 | present(sketchC, animated: true) {}
57 |
58 |
59 |
60 | }
61 |
62 |
63 | }
64 |
65 |
66 |
67 | }
68 |
69 |
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // pointsDrag
4 | //
5 | // Created by Jz D on 2020/9/16.
6 | // Copyright © 2020 Jz D. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 |
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
17 | // Override point for customization after application launch.
18 | return true
19 | }
20 |
21 | // MARK: UISceneSession Lifecycle
22 |
23 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
24 | // Called when a new scene session is being created.
25 | // Use this method to select a configuration to create the new scene with.
26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
27 | }
28 |
29 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
30 | // Called when the user discards a scene session.
31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
33 | }
34 |
35 |
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/Assets.xcassets/single_lhs_rotate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "icon_zuozhuan@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "icon_zuozhuan@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/Assets.xcassets/single_lhs_rotate.imageset/icon_zuozhuan@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/ptDragEasy/pointsDrag/Assets.xcassets/single_lhs_rotate.imageset/icon_zuozhuan@2x.png
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/Assets.xcassets/single_lhs_rotate.imageset/icon_zuozhuan@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/ptDragEasy/pointsDrag/Assets.xcassets/single_lhs_rotate.imageset/icon_zuozhuan@3x.png
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/Assets.xcassets/single_rhs_rotate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "icon_youzhuan@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "icon_youzhuan@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/Assets.xcassets/single_rhs_rotate.imageset/icon_youzhuan@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/ptDragEasy/pointsDrag/Assets.xcassets/single_rhs_rotate.imageset/icon_youzhuan@2x.png
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/Assets.xcassets/single_rhs_rotate.imageset/icon_youzhuan@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/ptDragEasy/pointsDrag/Assets.xcassets/single_rhs_rotate.imageset/icon_youzhuan@3x.png
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | NSCameraUsageDescription
24 | 需要
25 | UIApplicationSceneManifest
26 |
27 | UIApplicationSupportsMultipleScenes
28 |
29 | UISceneConfigurations
30 |
31 | UIWindowSceneSessionRoleApplication
32 |
33 |
34 | UISceneConfigurationName
35 | Default Configuration
36 | UISceneDelegateClassName
37 | $(PRODUCT_MODULE_NAME).SceneDelegate
38 | UISceneStoryboardFile
39 | Main
40 |
41 |
42 |
43 |
44 | UILaunchStoryboardName
45 | LaunchScreen
46 | UIMainStoryboardFile
47 | Main
48 | UIRequiredDeviceCapabilities
49 |
50 | armv7
51 |
52 | UISupportedInterfaceOrientations
53 |
54 | UIInterfaceOrientationPortrait
55 |
56 | UISupportedInterfaceOrientations~ipad
57 |
58 | UIInterfaceOrientationPortrait
59 | UIInterfaceOrientationPortraitUpsideDown
60 | UIInterfaceOrientationLandscapeLeft
61 | UIInterfaceOrientationLandscapeRight
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/MagnifierView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MagnifierView.swift
3 | // MagnifierView_demo
4 | //
5 | // Created by lidongxi on 2018/3/23.
6 | // Copyright © 2018年 lidongxi. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class MagnifierView: UIView {
12 |
13 |
14 | public var renderView: UIView?
15 |
16 | public var renderPoint : CGPoint = CGPoint.zero {
17 | didSet{
18 | self.layer.setNeedsDisplay()
19 | }
20 | }
21 |
22 | override var isHidden: Bool {
23 | didSet{
24 | layer.borderColor = isHidden ? UIColor.clear.cgColor : UIColor.lightGray.cgColor
25 | }
26 | }
27 |
28 |
29 |
30 | override init(frame: CGRect) {
31 | super.init(frame: frame)
32 |
33 | layer.borderWidth = 1
34 | layer.borderColor = UIColor.lightGray.cgColor
35 | isHidden = true
36 | layer.delegate = self
37 | // 保证和屏幕读取像素的比例一致
38 | layer.contentsScale = UIScreen.main.scale
39 | }
40 |
41 | required init?(coder aDecoder: NSCoder) {
42 | fatalError("init(coder:) has not been implemented")
43 | }
44 |
45 | override func draw(_ layer: CALayer, in ctx: CGContext) {
46 | super.draw(layer, in: ctx)
47 | guard let renderer = renderView else {
48 | return
49 | }
50 | // 提前位移半个长宽的坑
51 | ctx.translateBy(x: frame.size.width * 0.5, y: frame.size.height * 0.5)
52 | /// 缩放比例
53 | let scale : CGFloat = 3
54 | ctx.scaleBy(x: scale, y: scale)
55 | // 再次位移后就可以把触摸点移至self.center的位置
56 | ctx.translateBy(x: -renderPoint.x, y: -renderPoint.y)
57 |
58 | renderer.layer.render(in: ctx)
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // pointsDrag
4 | //
5 | // Created by Jz D on 2020/9/16.
6 | // Copyright © 2020 Jz D. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
12 |
13 | var window: UIWindow?
14 |
15 |
16 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
17 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
18 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
19 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
20 | guard let _ = (scene as? UIWindowScene) else { return }
21 | }
22 |
23 | func sceneDidDisconnect(_ scene: UIScene) {
24 | // Called as the scene is being released by the system.
25 | // This occurs shortly after the scene enters the background, or when its session is discarded.
26 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
27 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
28 | }
29 |
30 | func sceneDidBecomeActive(_ scene: UIScene) {
31 | // Called when the scene has moved from an inactive state to an active state.
32 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
33 | }
34 |
35 | func sceneWillResignActive(_ scene: UIScene) {
36 | // Called when the scene will move from an active state to an inactive state.
37 | // This may occur due to temporary interruptions (ex. an incoming phone call).
38 | }
39 |
40 | func sceneWillEnterForeground(_ scene: UIScene) {
41 | // Called as the scene transitions from the background to the foreground.
42 | // Use this method to undo the changes made on entering the background.
43 | }
44 |
45 | func sceneDidEnterBackground(_ scene: UIScene) {
46 | // Called as the scene transitions from the foreground to the background.
47 | // Use this method to save data, release shared resources, and store enough scene-specific state information
48 | // to restore the scene back to its current state.
49 | }
50 |
51 |
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/SketchController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // pointsDrag
4 | //
5 | // Created by Jz D on 2020/9/16.
6 | // Copyright © 2020 Jz D. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 |
12 |
13 | struct ImgLayout {
14 |
15 | static let std = ImgLayout()
16 |
17 | let w: CGFloat
18 |
19 | let h: CGFloat
20 |
21 | let center: CGPoint
22 |
23 | let s: CGSize
24 |
25 |
26 | let screenH: CGFloat
27 |
28 | let screenW: CGFloat
29 |
30 |
31 |
32 | init() {
33 |
34 | screenH = UIScreen.main.bounds.height
35 | screenW = UIScreen.main.bounds.width
36 |
37 | h = screenH - 160
38 |
39 |
40 | w = min(screenW - 80, h - 40)
41 | let edge = min(h, w)
42 | center = CGPoint(x: screenW * 0.5, y: screenH * 0.5 + 40)
43 |
44 | s = CGSize(width: edge, height: edge)
45 |
46 |
47 | }
48 |
49 |
50 |
51 |
52 | }
53 |
54 |
55 |
56 |
57 | class SketchController: UIViewController {
58 |
59 | var image: UIImage?
60 |
61 | lazy var imgView = UIImageView(image: image)
62 |
63 | lazy var sketch: SketchView = {
64 | let sk = SketchView()
65 | sk.delegate = self
66 | // sk.layer.borderColor = UIColor.green.cgColor
67 | // sk.layer.borderWidth = 2
68 | return sk
69 | }()
70 |
71 | let magnifieViewWH : CGFloat = 150
72 |
73 | lazy var magnifierV = MagnifierView(frame: CGRect(x: 20, y: 20, width: magnifieViewWH, height: magnifieViewWH))
74 |
75 |
76 | lazy var measure = ImgLayout()
77 |
78 |
79 | lazy var lhsRotateB = DirectionRotateB(opt: .lhs)
80 |
81 | lazy var rhsRotateB = DirectionRotateB(opt: .rhs)
82 |
83 |
84 | var angle: CGFloat = 0
85 |
86 | override func viewDidLoad() {
87 | super.viewDidLoad()
88 | // Do any additional setup after loading the view.
89 | view.backgroundColor = UIColor.white
90 |
91 |
92 | if let img = image{
93 | let s = img.size.size(in: measure.s)
94 |
95 | imgView.frame.size = s
96 | imgView.center = measure.center
97 | sketch.frame = imgView.frame
98 | view.addSubview(imgView)
99 | view.addSubview(sketch)
100 | sketch.reloadData()
101 |
102 |
103 | magnifierV.renderView = imgView
104 | view.addSubview(magnifierV)
105 | }
106 |
107 |
108 | view.addSubview(lhsRotateB)
109 | view.addSubview(rhsRotateB)
110 | let sizeB = CGSize(width: 74, height: 32)
111 | lhsRotateB.frame.size = sizeB
112 | rhsRotateB.frame.size = sizeB
113 |
114 | lhsRotateB.center = CGPoint(x: 50, y: measure.screenH - sizeB.height - 20)
115 | rhsRotateB.center = CGPoint(x: measure.screenW - sizeB.width - 50, y: measure.screenH - sizeB.height - 20)
116 |
117 | lhsRotateB.addTarget(self, action: #selector(leftTurn), for: .touchUpInside)
118 | rhsRotateB.addTarget(self, action: #selector(rightTurn), for: .touchUpInside)
119 | }
120 |
121 |
122 | @objc func leftTurn(){
123 | rotate(with: .lhs)
124 | }
125 |
126 |
127 |
128 | @objc func rightTurn(){
129 | rotate(with: .rhs)
130 | }
131 |
132 |
133 |
134 | func rotate(with direction: RotateOpt) {
135 |
136 | let sizeOld = sketch.frame.size
137 | let originOld = sketch.frame.origin
138 | let center = sketch.center
139 |
140 | switch direction {
141 | case .lhs:
142 |
143 | // 逆时针
144 |
145 | angle -= 1
146 |
147 |
148 | sketch.defaultPoints.update(clockwize: false, by: sizeOld)
149 | case .rhs:
150 |
151 | // 顺时针
152 |
153 | angle += 1
154 |
155 | sketch.defaultPoints.update(clockwize: true, by: sizeOld)
156 | // 下一步,对 UI 的修改,影响上一步
157 |
158 | }
159 |
160 |
161 |
162 | imgView.transform = CGAffineTransform(rotationAngle: ImgSingleAngle.time * angle)
163 |
164 | sketch.frame.size = CGSize(width: sizeOld.height, height: sizeOld.width)
165 |
166 |
167 | sketch.center = center
168 | let originNew = sketch.frame.origin
169 |
170 | sketch.defaultPoints.patch(vector: originNew - originOld)
171 |
172 |
173 |
174 | sketch.reloadData()
175 |
176 | }
177 |
178 | }
179 |
180 |
181 |
182 |
183 | extension SketchController: SketchViewProxy{
184 |
185 |
186 | func sketch(status isStart: Bool) {
187 | magnifierV.isHidden = (isStart == false)
188 | }
189 |
190 | func sketch(moving pt: CGPoint) {
191 | // 设置渲染的中心点
192 | magnifierV.renderPoint = pt
193 | }
194 |
195 | }
196 |
197 |
198 |
199 | struct ImgSingleAngle {
200 | static let time = CGFloat.pi * 0.5
201 | }
202 |
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/Util/FontAdd.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FontAdd.swift
3 | //
4 | //
5 | // Created by Jz D on 2019/8/23.
6 | //
7 |
8 | import UIKit
9 |
10 |
11 |
12 | enum FontWeight: String {
13 | case light = "Light"
14 | case regular = "Regular"
15 | case medium = "Medium"
16 |
17 | case semibold = "Semibold"
18 | case bold = "Bold"
19 | case heavy = "Heavy"
20 | }
21 |
22 | enum FontType: String {
23 | case PingFangSC = "PingFangSC"
24 | case SFProText = "SFProText"
25 | }
26 |
27 | extension UIFont {
28 |
29 | static func heavy(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {
30 | return customFont(type, weight: .heavy, fontSize: fontSize)
31 | }
32 |
33 | static func regular(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {
34 | return customFont(type, weight: .regular, fontSize: fontSize)
35 | }
36 |
37 | static func bold(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {
38 | return customFont(type, weight: .bold, fontSize: fontSize)
39 | }
40 |
41 | static func light(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {
42 | return customFont(type, weight: .light, fontSize: fontSize)
43 | }
44 |
45 | static func medium(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {
46 | return customFont(type, weight: .medium, fontSize: fontSize)
47 | }
48 |
49 | static func semibold(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {
50 | return customFont(type, weight: .semibold, fontSize: fontSize)
51 | }
52 |
53 | /// 自定义字体
54 | static func customFont(_ type: FontType, weight: FontWeight, fontSize: CGFloat) -> UIFont {
55 | let realFontSize = fontSize
56 |
57 | if let customFont = UIFont(name: "\(type.rawValue)-\(weight.rawValue)", size: realFontSize) {
58 | return customFont
59 | }
60 |
61 | var systemWeight = UIFont.Weight.regular
62 | switch weight {
63 | case .light:
64 | systemWeight = UIFont.Weight.light
65 | case .regular:
66 | systemWeight = UIFont.Weight.regular
67 | case .medium:
68 | systemWeight = UIFont.Weight.medium
69 | case .semibold:
70 | systemWeight = UIFont.Weight.semibold
71 | case .bold:
72 | systemWeight = UIFont.Weight.bold
73 | case .heavy:
74 | systemWeight = UIFont.Weight.heavy
75 | }
76 | return UIFont.systemFont(ofSize: realFontSize, weight: systemWeight)
77 | }
78 | }
79 |
80 |
81 |
82 |
83 |
84 | extension UIFont {
85 |
86 | static let scoreName = UIFont.medium(ofSize: 16)
87 | static let headerFirstThree = UIFont.medium(ofSize: 22)
88 | static let accountListTitle = UIFont.regular(ofSize: 16)
89 |
90 |
91 |
92 | static let myStudyTitle = UIFont.medium(ofSize: 18)
93 | static let myStudyListScoreName = UIFont.medium(ofSize: 14)
94 | static let loginHeaderName = UIFont.medium(ofSize: 16)
95 |
96 |
97 | }
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/Util/ImgAdd.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImgAdd.swift
3 | // pointsDrag
4 | //
5 | // Created by Jz D on 2020/10/10.
6 | // Copyright © 2020 Jz D. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 |
12 |
13 |
14 | extension UIImage{
15 |
16 |
17 | func image(rotated time: Int) -> UIImage{
18 | guard time != 0 else {
19 | return self
20 | }
21 |
22 | let radian = CGFloat(time) * CGFloat.pi / 2
23 | let rotatedSize = CGRect(origin: .zero, size: size)
24 | .applying(CGAffineTransform(rotationAngle: radian))
25 | .integral.size
26 | UIGraphicsBeginImageContext(rotatedSize)
27 | if let context = UIGraphicsGetCurrentContext() {
28 | let origin = CGPoint(x: rotatedSize.width / 2.0,
29 | y: rotatedSize.height / 2.0)
30 | context.translateBy(x: origin.x, y: origin.y)
31 | context.rotate(by: radian)
32 | draw(in: CGRect(x: -origin.y, y: -origin.x,
33 | width: size.width, height: size.height))
34 | let rotatedImage = UIGraphicsGetImageFromCurrentImageContext()
35 | UIGraphicsEndImageContext()
36 |
37 | return rotatedImage ?? self
38 | }
39 |
40 | return self
41 |
42 | }
43 |
44 |
45 |
46 | }
47 |
48 |
49 |
50 | extension UIImage {
51 | var leftTurn: UIImage{
52 | image(rotated: 1)
53 | }
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/Util/PointAdd.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PointAdd.swift
3 | // pointsDrag
4 | //
5 | // Created by Jz D on 2020/10/12.
6 | // Copyright © 2020 Jz D. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 |
12 |
13 |
14 |
15 | func -(lhs: CGPoint, rhs: CGPoint) -> CGPoint {
16 | return CGPoint(x: lhs.x - rhs.x, y: lhs.y - rhs.y)
17 | }
18 |
19 |
20 |
21 | extension CGPoint{
22 | mutating
23 | func scale(by rate: CGFloat, forS size: CGSize){
24 | let newX = size.width * 0.5 * rate + (x - size.width * 0.5) * rate * 0.5
25 | let newY = size.height * 0.5 * rate + (y - size.height * 0.5) * rate * 0.5
26 | self = CGPoint(x: newX, y: newY)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/Util/sizeAdd.swift:
--------------------------------------------------------------------------------
1 | //
2 | // sizeAdd.swift
3 | // pointsDrag
4 | //
5 | // Created by Jz D on 2020/10/12.
6 | // Copyright © 2020 Jz D. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 |
12 |
13 | extension CGSize{
14 |
15 |
16 |
17 |
18 | func size(in std: CGSize) -> CGSize{
19 |
20 | let hRatio = height / std.height
21 | let wRatio = width / std.width
22 |
23 | let reSolution = height / width
24 |
25 |
26 | print(width, height)
27 |
28 | let s: CGSize
29 | if hRatio > wRatio{
30 | s = CGSize(width: std.height / reSolution, height: std.height)
31 | }
32 | else{
33 | s = CGSize(width: std.width, height: std.width * reSolution)
34 | }
35 | return s
36 |
37 | }
38 |
39 |
40 | func size(by horizontal: CGFloat) -> CGSize{
41 |
42 |
43 |
44 | let reSolution = height / width
45 |
46 |
47 | print(width, height)
48 |
49 | return CGSize(width: horizontal, height: horizontal / reSolution)
50 |
51 |
52 | }
53 |
54 |
55 | func ratio(by rate: CGFloat) -> CGSize{
56 | return CGSize(width: width * rate, height: height * rate)
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/View/DirectionRotateB.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DirectionRotateB.swift
3 | // pointsDrag
4 | //
5 | // Created by Jz D on 2020/10/12.
6 | // Copyright © 2020 Jz D. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 |
12 |
13 |
14 | enum RotateOpt{
15 | case lhs, rhs
16 | }
17 |
18 |
19 |
20 |
21 | class DirectionRotateB: UIButton {
22 |
23 |
24 | let imgSize = CGSize(width: 32, height: 32)
25 | let titleW: CGFloat = 36
26 |
27 | let spacing: CGFloat = 6
28 |
29 |
30 | init(opt kind: RotateOpt){
31 |
32 | super.init(frame: .zero)
33 | let img: UIImage?
34 | let title: String
35 | switch kind {
36 | case .lhs:
37 | title = "左转"
38 |
39 | img = UIImage(named: "single_lhs_rotate")
40 | case .rhs:
41 | title = "右转"
42 |
43 | img = UIImage(named: "single_rhs_rotate")
44 | }
45 | setImage(img, for: .normal)
46 | setTitle(title, for: .normal)
47 | setTitleColor(UIColor(rgb: 0x666666), for: .normal)
48 | backgroundColor = UIColor.white
49 |
50 | titleLabel?.font = UIFont.regular(ofSize: 18)
51 | }
52 |
53 | required init?(coder: NSCoder) {
54 | fatalError("init(coder:) has not been implemented")
55 | }
56 |
57 |
58 |
59 |
60 |
61 |
62 | override func imageRect(forContentRect contentRect: CGRect) -> CGRect {
63 |
64 |
65 | let x = contentRect.origin.x
66 | let y = (contentRect.size.height - imgSize.height)/2
67 | return CGRect(x: x, y: y, width: imgSize.width, height: imgSize.height)
68 | }
69 |
70 |
71 |
72 | override func titleRect(forContentRect contentRect: CGRect) -> CGRect {
73 | let titleH: CGFloat = 24
74 | let x = contentRect.origin.x + imgSize.width + spacing
75 | let y = (contentRect.size.height - titleH)/2
76 | return CGRect(x: x, y: y, width: titleW, height: titleH)
77 |
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/ptDragEasy/pointsDrag/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // pointsDrag
4 | //
5 | // Created by Jz D on 2020/10/10.
6 | // Copyright © 2020 Jz D. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ViewController: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 |
16 | // Do any additional setup after loading the view.
17 | }
18 |
19 |
20 |
21 |
22 | @IBAction func photoIt(_ sender: Any) {
23 |
24 | let picker = UIImagePickerController()
25 | picker.delegate = self
26 | picker.sourceType = UIImagePickerController.SourceType.camera
27 | present(picker, animated: true)
28 |
29 | }
30 |
31 |
32 | }
33 |
34 |
35 |
36 |
37 | extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate{
38 |
39 |
40 | func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
41 |
42 | picker.dismiss(animated: true)
43 |
44 |
45 | if let image = info[.originalImage] as? UIImage{
46 | var midImg = image
47 | let s = image.size
48 | if s.width > s.height{
49 | midImg = image.leftTurn
50 | }
51 |
52 |
53 | let sketchC = SketchController()
54 | sketchC.image = midImg
55 | sketchC.modalPresentationStyle = .fullScreen
56 | present(sketchC, animated: true) {}
57 |
58 |
59 |
60 | }
61 |
62 |
63 | }
64 |
65 |
66 |
67 | }
68 |
69 |
--------------------------------------------------------------------------------
/secondCrop/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## [juejin blog: 照片选择区域功能的另一实现: 加动效](https://juejin.cn/post/6929917715813662727)
3 |
4 | ## [juejin blog: 仿扫描全能王的选择区域功能:拍照,旋转](https://juejin.im/post/6882950524786704398)
5 |
6 |
7 | ## [juejin blog: 低仿扫描全能王的选择区域功能](https://juejin.im/post/6875134095232335880)
8 |
9 |
10 | ### 添加选择区域,是否 OK 的交互
11 |
12 | > 有参考 rzmn/CropView
13 |
14 |
15 | 
16 |
17 |
18 | ### 端点拖动, 和放大镜
19 |
20 | 
21 |
22 |
23 | ### 凸四边形判定
24 |
25 |
26 | 
27 |
28 |
29 | ### 交叉边,重新连线
30 |
31 |
32 | 
33 |
34 |
35 | 
36 |
--------------------------------------------------------------------------------
/secondCrop/raw/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/secondCrop/raw/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/secondCrop/raw/Example/Example/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Example
4 | //
5 | // Created by Никита Разумный on 11/6/17.
6 | // Copyright © 2017 example. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
18 | return true
19 | }
20 |
21 | func applicationWillResignActive(_ application: UIApplication) {
22 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
23 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
24 | }
25 |
26 | func applicationDidEnterBackground(_ application: UIApplication) {
27 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
29 | }
30 |
31 | func applicationWillEnterForeground(_ application: UIApplication) {
32 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
33 | }
34 |
35 | func applicationDidBecomeActive(_ application: UIApplication) {
36 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
37 | }
38 |
39 | func applicationWillTerminate(_ application: UIApplication) {
40 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
41 | }
42 |
43 |
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/secondCrop/raw/Example/Example/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/secondCrop/raw/Example/Example/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/secondCrop/raw/Example/Example/Classes/Array+shift.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Array+shift.swift
3 | // CropView
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Array {
11 | func shifted(by shiftAmount: Int) -> Array {
12 | guard self.count > 0, (shiftAmount % self.count) != 0 else { return self }
13 | let moduloShiftAmount = shiftAmount % self.count
14 |
15 | let negativeShift = shiftAmount < 0
16 | let effectiveShiftAmount = negativeShift ? moduloShiftAmount + self.count : moduloShiftAmount
17 | let shift: (Int) -> Int = { return $0 + effectiveShiftAmount >= self.count ? $0 + effectiveShiftAmount - self.count : $0 + effectiveShiftAmount }
18 |
19 | return self.enumerated().sorted(by: { shift($0.offset) < shift($1.offset) }).map { $0.element }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/secondCrop/raw/Example/Example/Classes/CGPoint+geometry.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGPoint+geometry.swift
3 | // CropView
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | //
7 |
8 | import UIKit
9 |
10 | extension CGPoint {
11 | func cartesian(for size: CGSize) -> CGPoint {
12 | return CGPoint(x: x, y: size.height - y)
13 | }
14 | static func cross(a: CGPoint, b: CGPoint) -> CGFloat {
15 | return a.x * b.y - a.y * b.x
16 | }
17 | func normalized(size: CGSize) -> CGPoint {
18 | return CGPoint(x: max(min(x, size.width), 0), y: max(min(y, size.height), 0))
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/secondCrop/raw/Example/Example/Classes/SEAreaView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AreaView.swift
3 | // CropViewController
4 | //
5 | // Created by Никита Разумный on 11/5/17.
6 | // Copyright © 2017 resquare. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SEAreaView: UIView {
12 |
13 | var cropView : SECropView?
14 | var isPathValid = true
15 |
16 | override init(frame: CGRect) {
17 | super.init(frame: frame)
18 | contentMode = .redraw
19 |
20 | CATransaction.begin()
21 | CATransaction.setDisableActions(true)
22 | CATransaction.commit()
23 | }
24 |
25 | required init?(coder aDecoder: NSCoder) {
26 | super.init(coder: aDecoder)
27 | contentMode = .redraw
28 |
29 | CATransaction.begin()
30 | CATransaction.setDisableActions(true)
31 | CATransaction.commit()
32 | }
33 |
34 | override func draw(_ rect: CGRect) {
35 | super.draw(rect)
36 |
37 | guard let path = cropView?.path else { return }
38 |
39 | let context = UIGraphicsGetCurrentContext()
40 | context?.setAllowsAntialiasing(true)
41 | context?.clip(to: rect)
42 |
43 | context?.addPath(path)
44 | context?.setLineWidth(1)
45 | context?.setLineCap(.round)
46 | context?.setLineJoin(.round)
47 |
48 |
49 | context?.setStrokeColor((isPathValid ? SECropView.goodAreaColor : SECropView.badAreaColor).cgColor)
50 | context?.strokePath()
51 |
52 | context?.saveGState()
53 | context?.addRect(bounds)
54 | context?.addPath(path)
55 |
56 | context?.setFillColor(UIColor(white: 0.3, alpha: 0.2).cgColor)
57 | context?.drawPath(using: .eoFill)
58 |
59 | context?.restoreGState()
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/secondCrop/raw/Example/Example/Classes/SECornerView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CornerView.swift
3 | // CropViewController
4 | //
5 | // Created by Никита Разумный on 11/5/17.
6 | // Copyright © 2017 resquare. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SECornerView: UIView {
12 |
13 | override init(frame: CGRect) {
14 | super.init(frame: frame)
15 | layer.cornerRadius = frame.size.width / 2.0
16 | layer.borderWidth = 1.0
17 | layer.masksToBounds = true
18 | backgroundColor = UIColor.clear
19 | }
20 |
21 | required init?(coder aDecoder: NSCoder) {
22 | super.init(coder: aDecoder)
23 | }
24 |
25 | override func draw(_ rect: CGRect) {
26 | super.draw(rect)
27 | let position = superview!.convert(self.frame, to: nil)
28 | let touchPoint = position.origin
29 |
30 | let context = UIGraphicsGetCurrentContext()!
31 |
32 | context.translateBy(x: -(position.size.width / 2 - SECropView.cornerSize / 2),
33 | y: -(position.size.width / 2 - SECropView.cornerSize / 2))
34 |
35 | context.translateBy(x: -touchPoint.x,
36 | y: -touchPoint.y)
37 |
38 | /* TODO: faster rendering
39 | isHidden = true
40 | (superview as! SECropView).areaQuadrangle.isHidden = true
41 | self.superview?.superview?.superview?.layer.render(in: context)
42 | (superview as! SECropView).areaQuadrangle.isHidden = false
43 | isHidden = false
44 | */
45 | }
46 |
47 | func scaleUp() {
48 | UIView.animate(withDuration: 0.15, animations: {
49 | self.layer.borderWidth = 0.5
50 | self.transform = CGAffineTransform.identity.scaledBy(x: 2, y: 2)
51 | }) { (_) in
52 | self.setNeedsDisplay()
53 | }
54 | }
55 |
56 | func scaleDown() {
57 | UIView.animate(withDuration: 0.15, animations: {
58 | self.layer.borderWidth = 1
59 | self.transform = CGAffineTransform.identity
60 | }) { (_) in
61 | self.setNeedsDisplay()
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/secondCrop/raw/Example/Example/Classes/SECropError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SECropError.swift
3 | // CropView
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | //
7 |
8 | import UIKit
9 |
10 | public enum SECropError: Error {
11 | case missingSuperview
12 | case missingImageOnImageView
13 | case invalidNumberOfCorners
14 | case nonConvexRect
15 | case missingImageWhileCropping
16 | case unknown
17 | }
18 |
--------------------------------------------------------------------------------
/secondCrop/raw/Example/Example/Classes/SEQuadrangleHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SEQuadrangleHelper.swift
3 | // CropView
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | //
7 |
8 | import UIKit
9 | import Foundation
10 | import AVFoundation
11 |
12 | public class SEQuadrangleHelper {
13 |
14 | static internal func orderPointsInQuadrangle(quad: [CGPoint]) throws -> [CGPoint] {
15 | func orderArrayClockwise(quad: [CGPoint]) -> [CGPoint] {
16 | // oriented area of quadrangle: cloclwise if it > 0
17 | var square : CGFloat = 0.0
18 | for i in 0 ..< quad.count - 1 {
19 | square += CGPoint.cross(a: CGPoint(x: quad[i].x - quad[0].x, y: quad[i].y - quad[0].y),
20 | b: CGPoint(x: quad[i + 1].x - quad[0].x, y: quad[i + 1].y - quad[0].y))
21 | }
22 | return square > 0 ? quad : quad.reversed()
23 | }
24 |
25 | func findTopLeftPointIndex(quad: [CGPoint]) throws -> Int {
26 | var topLeftPointIdx : Int = -1
27 | var topLeftShiftValue : CGFloat = 1000.0 * 1000.0 * 1000.0
28 |
29 | for i in 0 ..< quad.count {
30 | let shiftValue = quad[i].y + quad[i].x
31 | if shiftValue < topLeftShiftValue {
32 | topLeftPointIdx = i
33 | topLeftShiftValue = shiftValue
34 | }
35 | }
36 | guard topLeftPointIdx != -1 else { throw SECropError.unknown }
37 | return topLeftPointIdx
38 | }
39 |
40 | guard quad.count == 4 else { throw SECropError.invalidNumberOfCorners }
41 | guard checkConvex(corners: quad) else { throw SECropError.nonConvexRect }
42 |
43 | let orderedQuad = orderArrayClockwise(quad: quad)
44 | let topLeftIdx = try findTopLeftPointIndex(quad: orderedQuad)
45 | return orderedQuad.shifted(by: orderedQuad.count - topLeftIdx)
46 | }
47 |
48 | static public func cropImage(with image: UIImage, quad: [CGPoint]) throws -> UIImage {
49 |
50 | let ciImage = CIImage(image: image)
51 |
52 | let perspectiveCorrection = CIFilter(name: "CIPerspectiveCorrection")
53 | let imgSize = CGSize(width: image.size.width * image.scale,
54 | height: image.size.height * image.scale)
55 |
56 | let orderedQuad = try orderPointsInQuadrangle(quad: quad)
57 | let context = CIContext(options: nil)
58 | print("ordered quad: ", orderedQuad)
59 |
60 | guard let transform = perspectiveCorrection else { throw SECropError.unknown }
61 | transform.setValue(CIVector(cgPoint: orderedQuad[0].cartesian(for: imgSize)),
62 | forKey: "inputTopLeft")
63 | transform.setValue(CIVector(cgPoint: orderedQuad[1].cartesian(for: imgSize)),
64 | forKey: "inputTopRight")
65 | transform.setValue(CIVector(cgPoint: orderedQuad[2].cartesian(for: imgSize)),
66 | forKey: "inputBottomRight")
67 | transform.setValue(CIVector(cgPoint: orderedQuad[3].cartesian(for: imgSize)),
68 | forKey: "inputBottomLeft")
69 | transform.setValue(ciImage, forKey: kCIInputImageKey)
70 |
71 | guard let perspectiveCorrectedImg = transform.outputImage, let cgImage = context.createCGImage(perspectiveCorrectedImg, from: perspectiveCorrectedImg.extent) else { throw SECropError.unknown }
72 |
73 | return UIImage(cgImage: cgImage)
74 | }
75 |
76 | static internal func checkConvex(corners: [CGPoint]) -> Bool {
77 | guard corners.count > 2 else {
78 | return false
79 | }
80 | var positiveCount = 0
81 | var negativeCount = 0
82 | for i in 0 ..< corners.count {
83 | let p0 = corners[i]
84 | let p1 = corners[(i + 1) % corners.count]
85 | let p2 = corners[(i + 2) % corners.count]
86 |
87 | let cross = (p1.x - p0.x) * (p2.y - p1.y) - (p1.y - p0.y) * (p2.x - p1.x);
88 | if cross > 0 {
89 | positiveCount += 1
90 | } else if cross < 0 {
91 | negativeCount += 1
92 | }
93 | }
94 | return positiveCount == corners.count || negativeCount == corners.count
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/secondCrop/raw/Example/Example/Classes/UIView+globalCoordinates.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+globalCoordinates.swift
3 | // CropView
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIView {
11 | var globalPoint :CGPoint? {
12 | return self.superview?.convert(self.frame.origin, to: nil)
13 | }
14 | var globalFrame :CGRect? {
15 | return self.superview?.convert(self.frame, to: nil)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/secondCrop/raw/Example/Example/ImageViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageViewController.swift
3 | // Example
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | // Copyright © 2018 example. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ImageViewController: UIViewController {
12 | @IBOutlet weak var imageView: UIImageView!
13 | var image : UIImage?
14 |
15 | override func viewDidLoad() {
16 | super.viewDidLoad()
17 | imageView.image = image
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/secondCrop/raw/Example/Example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeRight
35 | UIInterfaceOrientationLandscapeLeft
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/secondCrop/raw/Example/Example/Resources/paper.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/secondCrop/raw/Example/Example/Resources/paper.jpg
--------------------------------------------------------------------------------
/secondCrop/raw/Example/Example/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // Example
4 | //
5 | // Created by Никита Разумный on 11/6/17.
6 | // Copyright © 2017 example. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | import AVFoundation
12 |
13 | class ViewController: UIViewController {
14 |
15 | let cropView = SECropView()
16 | @IBOutlet weak var imageView: UIImageView!
17 |
18 | override func viewDidLoad() {
19 | super.viewDidLoad()
20 | // points are defined in the coordinate system of the image
21 | cropView.configureWithCorners(corners: [CGPoint(x: 120, y: 100),
22 | CGPoint(x: 270, y: 170),
23 | CGPoint(x: 280, y: 450),
24 | CGPoint(x: 120, y: 400)], on: imageView)
25 | }
26 |
27 | override func viewDidAppear(_ animated: Bool) {
28 | super.viewDidAppear(animated)
29 | /*
30 | if you want to re-set cropView coordinates
31 | cropView.setCorners(newCorners: [CGPoint(x: 240, y: 200),
32 | CGPoint(x: 540, y: 340),
33 | CGPoint(x: 560, y: 900),
34 | CGPoint(x: 240, y: 800)])
35 | */
36 | }
37 |
38 | @IBAction func saveImg(_ sender: Any) {
39 | do {
40 | guard let corners = cropView.cornerLocations else { return }
41 | guard let image = imageView.image else { return }
42 |
43 | let croppedImage = try SEQuadrangleHelper.cropImage(with: image, quad: corners)
44 |
45 | performSegue(withIdentifier: "doCrop", sender: croppedImage)
46 | } catch let error as SECropError {
47 | print(error)
48 | } catch {
49 | print("Something went wrong, are you feeling OK?")
50 | }
51 | }
52 |
53 | override func prepare(for segue: UIStoryboardSegue, sender: Any?){
54 | guard let vc = segue.destination as? ImageViewController else { return }
55 | guard let img = sender as? UIImage else { return }
56 | vc.image = img
57 | }
58 | }
59 |
60 |
--------------------------------------------------------------------------------
/secondCrop/raw/Pod/Classes/Array+shift.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Array+shift.swift
3 | // CropView
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Array {
11 | func shifted(by shiftAmount: Int) -> Array {
12 | guard self.count > 0, (shiftAmount % self.count) != 0 else { return self }
13 | let moduloShiftAmount = shiftAmount % self.count
14 |
15 | let negativeShift = shiftAmount < 0
16 | let effectiveShiftAmount = negativeShift ? moduloShiftAmount + self.count : moduloShiftAmount
17 | let shift: (Int) -> Int = { return $0 + effectiveShiftAmount >= self.count ? $0 + effectiveShiftAmount - self.count : $0 + effectiveShiftAmount }
18 |
19 | return self.enumerated().sorted(by: { shift($0.offset) < shift($1.offset) }).map { $0.element }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/secondCrop/raw/Pod/Classes/CGPoint+geometry.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGPoint+geometry.swift
3 | // CropView
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | //
7 |
8 | import UIKit
9 |
10 | extension CGPoint {
11 | func cartesian(for size: CGSize) -> CGPoint {
12 | return CGPoint(x: x, y: size.height - y)
13 | }
14 | static func cross(a: CGPoint, b: CGPoint) -> CGFloat {
15 | return a.x * b.y - a.y * b.x
16 | }
17 | func normalized(size: CGSize) -> CGPoint {
18 | return CGPoint(x: max(min(x, size.width), 0), y: max(min(y, size.height), 0))
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/secondCrop/raw/Pod/Classes/SEAreaView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AreaView.swift
3 | // CropViewController
4 | //
5 | // Created by Никита Разумный on 11/5/17.
6 | // Copyright © 2017 resquare. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SEAreaView: UIView {
12 |
13 | var cropView : SECropView?
14 | var isPathValid = true
15 |
16 | override init(frame: CGRect) {
17 | super.init(frame: frame)
18 | contentMode = .redraw
19 |
20 | CATransaction.begin()
21 | CATransaction.setDisableActions(true)
22 | CATransaction.commit()
23 | }
24 |
25 | required init?(coder aDecoder: NSCoder) {
26 | super.init(coder: aDecoder)
27 | contentMode = .redraw
28 |
29 | CATransaction.begin()
30 | CATransaction.setDisableActions(true)
31 | CATransaction.commit()
32 | }
33 |
34 | override func draw(_ rect: CGRect) {
35 | super.draw(rect)
36 |
37 | guard let path = cropView?.path else { return }
38 |
39 | let context = UIGraphicsGetCurrentContext()
40 | context?.setAllowsAntialiasing(true)
41 | context?.clip(to: rect)
42 |
43 | context?.addPath(path)
44 | context?.setLineWidth(1)
45 | context?.setLineCap(.round)
46 | context?.setLineJoin(.round)
47 |
48 |
49 | context?.setStrokeColor((isPathValid ? SECropView.goodAreaColor : SECropView.badAreaColor).cgColor)
50 | context?.strokePath()
51 |
52 | context?.saveGState()
53 | context?.addRect(bounds)
54 | context?.addPath(path)
55 |
56 | context?.setFillColor(UIColor(white: 0.3, alpha: 0.2).cgColor)
57 | context?.drawPath(using: .eoFill)
58 |
59 | context?.restoreGState()
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/secondCrop/raw/Pod/Classes/SECornerView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CornerView.swift
3 | // CropViewController
4 | //
5 | // Created by Никита Разумный on 11/5/17.
6 | // Copyright © 2017 resquare. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SECornerView: UIView {
12 |
13 | override init(frame: CGRect) {
14 | super.init(frame: frame)
15 | layer.cornerRadius = frame.size.width / 2.0
16 | layer.borderWidth = 1.0
17 | layer.masksToBounds = true
18 | backgroundColor = UIColor.clear
19 | }
20 |
21 | required init?(coder aDecoder: NSCoder) {
22 | super.init(coder: aDecoder)
23 | }
24 |
25 | override func draw(_ rect: CGRect) {
26 | super.draw(rect)
27 | let position = superview!.convert(self.frame, to: nil)
28 | let touchPoint = position.origin
29 |
30 | let context = UIGraphicsGetCurrentContext()!
31 |
32 | context.translateBy(x: -(position.size.width / 2 - SECropView.cornerSize / 2),
33 | y: -(position.size.width / 2 - SECropView.cornerSize / 2))
34 |
35 | context.translateBy(x: -touchPoint.x,
36 | y: -touchPoint.y)
37 |
38 | /* TODO: faster rendering
39 | isHidden = true
40 | (superview as! SECropView).areaQuadrangle.isHidden = true
41 | self.superview?.superview?.superview?.layer.render(in: context)
42 | (superview as! SECropView).areaQuadrangle.isHidden = false
43 | isHidden = false
44 | */
45 | }
46 |
47 | func scaleUp() {
48 | UIView.animate(withDuration: 0.15, animations: {
49 | self.layer.borderWidth = 0.5
50 | self.transform = CGAffineTransform.identity.scaledBy(x: 2, y: 2)
51 | }) { (_) in
52 | self.setNeedsDisplay()
53 | }
54 | }
55 |
56 | func scaleDown() {
57 | UIView.animate(withDuration: 0.15, animations: {
58 | self.layer.borderWidth = 1
59 | self.transform = CGAffineTransform.identity
60 | }) { (_) in
61 | self.setNeedsDisplay()
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/secondCrop/raw/Pod/Classes/SECropError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SECropError.swift
3 | // CropView
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | //
7 |
8 | import UIKit
9 |
10 | public enum SECropError: Error {
11 | case missingSuperview
12 | case missingImageOnImageView
13 | case invalidNumberOfCorners
14 | case nonConvexRect
15 | case missingImageWhileCropping
16 | case unknown
17 | }
18 |
--------------------------------------------------------------------------------
/secondCrop/raw/Pod/Classes/SEQuadrangleHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SEQuadrangleHelper.swift
3 | // CropView
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | //
7 |
8 | import UIKit
9 | import Foundation
10 | import AVFoundation
11 |
12 | public class SEQuadrangleHelper {
13 |
14 | static internal func orderPointsInQuadrangle(quad: [CGPoint]) throws -> [CGPoint] {
15 | func orderArrayClockwise(quad: [CGPoint]) -> [CGPoint] {
16 | // oriented area of quadrangle: cloclwise if it > 0
17 | var square : CGFloat = 0.0
18 | for i in 0 ..< quad.count - 1 {
19 | square += CGPoint.cross(a: CGPoint(x: quad[i].x - quad[0].x, y: quad[i].y - quad[0].y),
20 | b: CGPoint(x: quad[i + 1].x - quad[0].x, y: quad[i + 1].y - quad[0].y))
21 | }
22 | return square > 0 ? quad : quad.reversed()
23 | }
24 |
25 | func findTopLeftPointIndex(quad: [CGPoint]) throws -> Int {
26 | var topLeftPointIdx : Int = -1
27 | var topLeftShiftValue : CGFloat = 1000.0 * 1000.0 * 1000.0
28 |
29 | for i in 0 ..< quad.count {
30 | let shiftValue = quad[i].y + quad[i].x
31 | if shiftValue < topLeftShiftValue {
32 | topLeftPointIdx = i
33 | topLeftShiftValue = shiftValue
34 | }
35 | }
36 | guard topLeftPointIdx != -1 else { throw SECropError.unknown }
37 | return topLeftPointIdx
38 | }
39 |
40 | guard quad.count == 4 else { throw SECropError.invalidNumberOfCorners }
41 | guard checkConvex(corners: quad) else { throw SECropError.nonConvexRect }
42 |
43 | let orderedQuad = orderArrayClockwise(quad: quad)
44 | let topLeftIdx = try findTopLeftPointIndex(quad: orderedQuad)
45 | return orderedQuad.shifted(by: orderedQuad.count - topLeftIdx)
46 | }
47 |
48 | static public func cropImage(with image: UIImage, quad: [CGPoint]) throws -> UIImage {
49 |
50 | let ciImage = CIImage(image: image)
51 |
52 | let perspectiveCorrection = CIFilter(name: "CIPerspectiveCorrection")
53 | let imgSize = CGSize(width: image.size.width * image.scale,
54 | height: image.size.height * image.scale)
55 |
56 | let orderedQuad = try orderPointsInQuadrangle(quad: quad)
57 | let context = CIContext(options: nil)
58 | print("ordered quad: ", orderedQuad)
59 |
60 | guard let transform = perspectiveCorrection else { throw SECropError.unknown }
61 | transform.setValue(CIVector(cgPoint: orderedQuad[0].cartesian(for: imgSize)),
62 | forKey: "inputTopLeft")
63 | transform.setValue(CIVector(cgPoint: orderedQuad[1].cartesian(for: imgSize)),
64 | forKey: "inputTopRight")
65 | transform.setValue(CIVector(cgPoint: orderedQuad[2].cartesian(for: imgSize)),
66 | forKey: "inputBottomRight")
67 | transform.setValue(CIVector(cgPoint: orderedQuad[3].cartesian(for: imgSize)),
68 | forKey: "inputBottomLeft")
69 | transform.setValue(ciImage, forKey: kCIInputImageKey)
70 |
71 | guard let perspectiveCorrectedImg = transform.outputImage, let cgImage = context.createCGImage(perspectiveCorrectedImg, from: perspectiveCorrectedImg.extent) else { throw SECropError.unknown }
72 |
73 | return UIImage(cgImage: cgImage)
74 | }
75 |
76 | static internal func checkConvex(corners: [CGPoint]) -> Bool {
77 | guard corners.count > 2 else {
78 | return false
79 | }
80 | var positiveCount = 0
81 | var negativeCount = 0
82 | for i in 0 ..< corners.count {
83 | let p0 = corners[i]
84 | let p1 = corners[(i + 1) % corners.count]
85 | let p2 = corners[(i + 2) % corners.count]
86 |
87 | let cross = (p1.x - p0.x) * (p2.y - p1.y) - (p1.y - p0.y) * (p2.x - p1.x);
88 | if cross > 0 {
89 | positiveCount += 1
90 | } else if cross < 0 {
91 | negativeCount += 1
92 | }
93 | }
94 | return positiveCount == corners.count || negativeCount == corners.count
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/secondCrop/raw/Pod/Classes/UIView+globalCoordinates.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+globalCoordinates.swift
3 | // CropView
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIView {
11 | var globalPoint :CGPoint? {
12 | return self.superview?.convert(self.frame.origin, to: nil)
13 | }
14 | var globalFrame :CGRect? {
15 | return self.superview?.convert(self.frame, to: nil)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/secondCrop/raw/README.md:
--------------------------------------------------------------------------------
1 | # CropView
2 | Quadrangle view and image cropper like a Notes App
3 |
4 |
5 |
6 | # Demo
7 | 
8 |
9 | # Usage
10 | ### Initialization
11 | Set initial coordinates in points
12 | ``` swift
13 | cropView.configureWithCorners(corners: [CGPoint(x: 120, y: 100),
14 | CGPoint(x: 270, y: 170),
15 | CGPoint(x: 280, y: 450),
16 | CGPoint(x: 120, y: 400)], on: imageView)
17 | ```
18 | ### Customisation
19 | Customize color of your corners/contour and corners size
20 | ``` swift
21 | // SECornerView.swift
22 | static var cornerSize : CGFloat = 50.0
23 | ```
24 | ``` swift
25 | // SECropView.swift
26 | static var goodAreaColor = #colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1)
27 | static var badAreaColor = #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1)
28 | ```
29 | ### Geometry
30 | ``` swift
31 | // SEQuadrangleHelper.swift
32 |
33 | // Crop image by quadrangle points in pixels
34 | static public func cropImage(with image: UIImage, quad: [CGPoint]) throws -> UIImage
35 | // get image frame in UIImageView and convert quadrangle coordinates into image pixels
36 | static public func getCoordinatesOnImageWithoutScale(on imageView: UIImageView, with cropView: SECropView) throws -> Array
37 | // get quadrangle coordinates, related by UIImageView frame in pixels
38 | static public func getCoordinatesOnImageView(on imageView: UIImageView, with cropView: SECropView) throws -> Array
39 | ```
40 |
41 |
--------------------------------------------------------------------------------
/secondCrop/secondCrop.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/secondCrop/secondCrop.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/secondCrop/secondCrop/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // secondCrop
4 | //
5 | // Created by Jz D on 2021/2/2.
6 | //
7 |
8 | import UIKit
9 |
10 | @main
11 | class AppDelegate: UIResponder, UIApplicationDelegate {
12 |
13 |
14 |
15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
16 | // Override point for customization after application launch.
17 | return true
18 | }
19 |
20 | // MARK: UISceneSession Lifecycle
21 |
22 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
23 | // Called when a new scene session is being created.
24 | // Use this method to select a configuration to create the new scene with.
25 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
26 | }
27 |
28 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
29 | // Called when the user discards a scene session.
30 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
31 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
32 | }
33 |
34 |
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/secondCrop/secondCrop/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/secondCrop/secondCrop/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/secondCrop/secondCrop/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/secondCrop/secondCrop/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/secondCrop/secondCrop/ImageViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageViewController.swift
3 | // Example
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | // Copyright © 2018 example. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ImageViewController: UIViewController {
12 | @IBOutlet weak var imageView: UIImageView!
13 | var image : UIImage?
14 |
15 | override func viewDidLoad() {
16 | super.viewDidLoad()
17 | imageView.image = image
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/secondCrop/secondCrop/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 | UISceneStoryboardFile
37 | Main
38 |
39 |
40 |
41 |
42 | UIApplicationSupportsIndirectInputEvents
43 |
44 | UILaunchStoryboardName
45 | LaunchScreen
46 | UIMainStoryboardFile
47 | Main
48 | UIRequiredDeviceCapabilities
49 |
50 | armv7
51 |
52 | UISupportedInterfaceOrientations
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationLandscapeLeft
56 | UIInterfaceOrientationLandscapeRight
57 |
58 | UISupportedInterfaceOrientations~ipad
59 |
60 | UIInterfaceOrientationPortrait
61 | UIInterfaceOrientationPortraitUpsideDown
62 | UIInterfaceOrientationLandscapeLeft
63 | UIInterfaceOrientationLandscapeRight
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/secondCrop/secondCrop/Resources/paper.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/secondCrop/secondCrop/Resources/paper.jpg
--------------------------------------------------------------------------------
/secondCrop/secondCrop/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // secondCrop
4 | //
5 | // Created by Jz D on 2021/2/2.
6 | //
7 |
8 | import UIKit
9 |
10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
11 |
12 | var window: UIWindow?
13 |
14 |
15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
16 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
17 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
18 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
19 | guard let _ = (scene as? UIWindowScene) else { return }
20 | }
21 |
22 | func sceneDidDisconnect(_ scene: UIScene) {
23 | // Called as the scene is being released by the system.
24 | // This occurs shortly after the scene enters the background, or when its session is discarded.
25 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
26 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
27 | }
28 |
29 | func sceneDidBecomeActive(_ scene: UIScene) {
30 | // Called when the scene has moved from an inactive state to an active state.
31 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
32 | }
33 |
34 | func sceneWillResignActive(_ scene: UIScene) {
35 | // Called when the scene will move from an active state to an inactive state.
36 | // This may occur due to temporary interruptions (ex. an incoming phone call).
37 | }
38 |
39 | func sceneWillEnterForeground(_ scene: UIScene) {
40 | // Called as the scene transitions from the background to the foreground.
41 | // Use this method to undo the changes made on entering the background.
42 | }
43 |
44 | func sceneDidEnterBackground(_ scene: UIScene) {
45 | // Called as the scene transitions from the foreground to the background.
46 | // Use this method to save data, release shared resources, and store enough scene-specific state information
47 | // to restore the scene back to its current state.
48 | }
49 |
50 |
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/secondCrop/secondCrop/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // secondCrop
4 | //
5 | // Created by Jz D on 2021/2/2.
6 | //
7 |
8 | import UIKit
9 |
10 | class ViewController: UIViewController {
11 |
12 | let cropView = SECropView()
13 | @IBOutlet weak var imageView: UIImageView!
14 |
15 | override func viewDidLoad() {
16 | super.viewDidLoad()
17 | // Do any additional setup after loading the view.
18 | cropView.configure(corners: imageView)
19 | }
20 |
21 |
22 |
23 | @IBAction func saveImg(_ sender: Any) {
24 | do {
25 | guard let corners = cropView.cornerLocations else{
26 | return
27 | }
28 | let croppedImage = try SEQuadrangleHelper.cropImage(in: imageView, quad: corners)
29 | performSegue(withIdentifier: "doCrop", sender: croppedImage)
30 | } catch let error as SECropError {
31 | print(error)
32 | } catch {
33 | print(error)
34 | }
35 | }
36 |
37 | override func prepare(for segue: UIStoryboardSegue, sender: Any?){
38 | guard let vc = segue.destination as? ImageViewController else { return }
39 | guard let img = sender as? UIImage else { return }
40 | vc.image = img
41 | }
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/secondCrop/secondCrop/crop/Array+shift.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Array+shift.swift
3 | // CropView
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Array {
11 | func shifted(by shiftAmount: Int) -> [Element]{
12 | guard count > 0, (shiftAmount % count) != 0 else { return self }
13 | let moduloShiftAmount = shiftAmount % count
14 | let effectiveShiftAmount: Int
15 | if shiftAmount < 0{
16 | effectiveShiftAmount = moduloShiftAmount + count
17 | }
18 | else{
19 | effectiveShiftAmount = moduloShiftAmount
20 | }
21 | let shift: (Int) -> Int = {
22 | if $0 + effectiveShiftAmount >= count{
23 | return $0 + effectiveShiftAmount - count
24 | }
25 | else{
26 | return $0 + effectiveShiftAmount
27 | }
28 | }
29 | return enumerated().sorted(by: { shift($0.offset) < shift($1.offset) }).map { $0.element }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/secondCrop/secondCrop/crop/CGPoint+geometry.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGPoint+geometry.swift
3 | // CropView
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | //
7 |
8 | import UIKit
9 |
10 | extension CGPoint {
11 | func cartesian(for size: CGSize) -> CGPoint {
12 | return CGPoint(x: x, y: size.height - y)
13 | }
14 | static func cross(a: CGPoint, b: CGPoint) -> CGFloat {
15 | return a.x * b.y - a.y * b.x
16 | }
17 | func normalized(size: CGSize) -> CGPoint {
18 | return CGPoint(x: max(min(x, size.width), 0), y: max(min(y, size.height), 0))
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/secondCrop/secondCrop/crop/SEAreaView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AreaView.swift
3 | // CropViewController
4 | //
5 | // Created by Никита Разумный on 11/5/17.
6 | // Copyright © 2017 resquare. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SEAreaView: UIView {
12 |
13 | var path: CGMutablePath?
14 | var isPathValid = true
15 |
16 |
17 | override func draw(_ rect: CGRect) {
18 | super.draw(rect)
19 |
20 | guard let p = path else { return }
21 |
22 | let context = UIGraphicsGetCurrentContext()
23 | context?.setAllowsAntialiasing(true)
24 | context?.clip(to: rect)
25 |
26 | context?.addPath(p)
27 | context?.setLineWidth(1)
28 | context?.setLineCap(.round)
29 | context?.setLineJoin(.round)
30 |
31 |
32 | context?.setStrokeColor((isPathValid ? Setting.std.goodAreaColor : Setting.std.badAreaColor).cgColor)
33 | context?.strokePath()
34 | context?.addRect(bounds)
35 | context?.addPath(p)
36 |
37 | context?.setFillColor(UIColor(white: 0.3, alpha: 0.2).cgColor)
38 | context?.drawPath(using: .eoFill)
39 | }
40 |
41 |
42 | func fill(path p: CGMutablePath){
43 | path = p
44 | setNeedsDisplay()
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/secondCrop/secondCrop/crop/SECornerView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CornerView.swift
3 | // CropViewController
4 | //
5 | // Created by Никита Разумный on 11/5/17.
6 | // Copyright © 2017 resquare. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SECornerView: UIView {
12 |
13 | override init(frame: CGRect) {
14 | super.init(frame: frame)
15 | layer.cornerRadius = frame.size.width / 2.0
16 | layer.borderWidth = 1.0
17 | layer.masksToBounds = true
18 | backgroundColor = UIColor.clear
19 | }
20 |
21 | required init?(coder aDecoder: NSCoder) {
22 | super.init(coder: aDecoder)
23 | }
24 |
25 | func scaleUp() {
26 | UIView.animate(withDuration: 0.15, animations: {
27 | self.layer.borderWidth = 0.5
28 | self.transform = CGAffineTransform.identity.scaledBy(x: 2, y: 2)
29 | })
30 | }
31 |
32 | func scaleDown() {
33 | UIView.animate(withDuration: 0.15, animations: {
34 | self.layer.borderWidth = 1
35 | self.transform = CGAffineTransform.identity
36 | })
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/secondCrop/secondCrop/crop/SECropError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SECropError.swift
3 | // CropView
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | //
7 |
8 | import UIKit
9 |
10 | public enum SECropError: Error {
11 | case missingSuperview
12 | case missingImageOnImageView
13 | case invalidNumberOfCorners
14 | case nonConvexRect
15 | case missingImageWhileCropping
16 | case unknown
17 | case noImage
18 | }
19 |
--------------------------------------------------------------------------------
/secondCrop/secondCrop/crop/SEQuadrangleHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SEQuadrangleHelper.swift
3 | // CropView
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | //
7 |
8 | import UIKit
9 | import Foundation
10 | import AVFoundation
11 |
12 | public class SEQuadrangleHelper {
13 |
14 | static internal func orderPointsInQuadrangle(quad: [CGPoint]) throws -> [CGPoint] {
15 | func orderArrayClockwise(quad: [CGPoint]) -> [CGPoint] {
16 | // oriented area of quadrangle: cloclwise if it > 0
17 | var square: CGFloat = 0.0
18 | for i in 0 ..< quad.count - 1 {
19 | square += CGPoint.cross(a: CGPoint(x: quad[i].x - quad[0].x, y: quad[i].y - quad[0].y),
20 | b: CGPoint(x: quad[i + 1].x - quad[0].x, y: quad[i + 1].y - quad[0].y))
21 | }
22 | return square > 0 ? quad : quad.reversed()
23 | }
24 |
25 | func findTopLeftPointIndex(quad: [CGPoint]) throws -> Int {
26 | var topLeftPointIdx : Int = -1
27 | var topLeftShiftValue : CGFloat = 1000.0 * 1000.0 * 1000.0
28 |
29 | for i in 0 ..< quad.count {
30 | let shiftValue = quad[i].y + quad[i].x
31 | if shiftValue < topLeftShiftValue {
32 | topLeftPointIdx = i
33 | topLeftShiftValue = shiftValue
34 | }
35 | }
36 | guard topLeftPointIdx != -1 else { throw SECropError.unknown }
37 | return topLeftPointIdx
38 | }
39 |
40 | guard quad.count == 4 else { throw SECropError.invalidNumberOfCorners }
41 | guard checkConvex(corners: quad) else { throw SECropError.nonConvexRect }
42 |
43 | let orderedQuad = orderArrayClockwise(quad: quad)
44 | let topLeftIdx = try findTopLeftPointIndex(quad: orderedQuad)
45 | return orderedQuad.shifted(by: orderedQuad.count - topLeftIdx)
46 | }
47 |
48 | static public func cropImage(in imageView: UIImageView, quad corners: [CGPoint]) throws -> UIImage {
49 | guard let image = imageView.image else {
50 | throw SECropError.noImage
51 | }
52 | let imgSize = image.size
53 | let f = AVMakeRect(aspectRatio: imgSize, insideRect: imageView.bounds)
54 | let quad = corners.map { (pt) -> CGPoint in
55 | return pt.inner(img: imgSize, relative: f.size)
56 | }
57 | let ciImage = CIImage(image: image)
58 |
59 | let perspectiveCorrection = CIFilter(name: "CIPerspectiveCorrection")
60 |
61 | let orderedQuad = try orderPointsInQuadrangle(quad: quad)
62 | let context = CIContext(options: nil)
63 | let pt = orderedQuad[2]
64 | print("ordered quad: ", orderedQuad, pt.y / pt.x, "imgSize: ", imgSize, imgSize.height/imgSize.width)
65 |
66 | guard let transform = perspectiveCorrection else { throw SECropError.unknown }
67 | transform.setValue(CIVector(cgPoint: orderedQuad[0].cartesian(for: imgSize)),
68 | forKey: "inputTopLeft")
69 | transform.setValue(CIVector(cgPoint: orderedQuad[1].cartesian(for: imgSize)),
70 | forKey: "inputTopRight")
71 | transform.setValue(CIVector(cgPoint: orderedQuad[2].cartesian(for: imgSize)),
72 | forKey: "inputBottomRight")
73 | transform.setValue(CIVector(cgPoint: orderedQuad[3].cartesian(for: imgSize)),
74 | forKey: "inputBottomLeft")
75 | transform.setValue(ciImage, forKey: kCIInputImageKey)
76 |
77 | guard let perspectiveCorrectedImg = transform.outputImage, let cgImage = context.createCGImage(perspectiveCorrectedImg, from: perspectiveCorrectedImg.extent) else { throw SECropError.unknown }
78 |
79 | return UIImage(cgImage: cgImage)
80 | }
81 |
82 | static internal func checkConvex(corners: [CGPoint]) -> Bool {
83 | guard corners.count > 2 else {
84 | return false
85 | }
86 | var positiveCount = 0
87 | var negativeCount = 0
88 | for i in 0 ..< corners.count {
89 | let p0 = corners[i]
90 | let p1 = corners[(i + 1) % corners.count]
91 | let p2 = corners[(i + 2) % corners.count]
92 |
93 | let cross = (p1.x - p0.x) * (p2.y - p1.y) - (p1.y - p0.y) * (p2.x - p1.x);
94 | if cross > 0 {
95 | positiveCount += 1
96 | } else if cross < 0 {
97 | negativeCount += 1
98 | }
99 | }
100 | return positiveCount == corners.count || negativeCount == corners.count
101 | }
102 | }
103 |
104 |
105 |
106 |
107 | extension CGPoint{
108 | func inner(img s: CGSize, relative dot: CGSize) -> CGPoint{
109 | let xx = x * s.width/dot.width
110 | let yy = y * s.height/dot.height
111 | return CGPoint(x: xx, y: yy)
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/secondCrop/secondCrop/crop/UIView+globalCoordinates.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+globalCoordinates.swift
3 | // CropView
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIView {
11 | var globalPoint :CGPoint? {
12 | superview?.convert(frame.origin, to: nil)
13 | }
14 | var globalFrame :CGRect? {
15 | superview?.convert(frame, to: nil)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/0.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/src/0.PNG
--------------------------------------------------------------------------------
/src/1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/src/1.PNG
--------------------------------------------------------------------------------
/src/2.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/src/2.PNG
--------------------------------------------------------------------------------
/src/3.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/src/3.PNG
--------------------------------------------------------------------------------
/src/second.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/src/second.png
--------------------------------------------------------------------------------
/thirdCapture/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## [juejin blog: 图片朝向,与滤镜(透视校正)](https://juejin.cn/post/6932496153556549646)
3 |
4 |
5 |
6 |
7 | ## [juejin blog: 照片选择区域功能的另一实现: 加动效](https://juejin.cn/post/6929917715813662727)
8 |
9 | ## [juejin blog: 仿扫描全能王的选择区域功能:拍照,旋转](https://juejin.im/post/6882950524786704398)
10 |
11 |
12 | ## [juejin blog: 低仿扫描全能王的选择区域功能](https://juejin.im/post/6875134095232335880)
13 |
14 |
15 | ### 添加选择区域,是否 OK 的交互
16 |
17 | > 有参考 rzmn/CropView
18 |
19 |
20 | 
21 |
22 |
23 | ### 端点拖动, 和放大镜
24 |
25 | 
26 |
27 |
28 | ### 凸四边形判定
29 |
30 |
31 | 
32 |
33 |
34 | ### 交叉边,重新连线
35 |
36 |
37 | 
38 |
39 |
40 | 
41 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // captureAndFilter
4 | //
5 | // Created by Jz D on 2021/2/23.
6 | //
7 |
8 | import UIKit
9 |
10 | @main
11 | class AppDelegate: UIResponder, UIApplicationDelegate {
12 |
13 |
14 |
15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
16 | // Override point for customization after application launch.
17 | return true
18 | }
19 |
20 | // MARK: UISceneSession Lifecycle
21 |
22 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
23 | // Called when a new scene session is being created.
24 | // Use this method to select a configuration to create the new scene with.
25 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
26 | }
27 |
28 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
29 | // Called when the user discards a scene session.
30 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
31 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
32 | }
33 |
34 |
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/4_tag_mask_plus.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "编组@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "编组@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/4_tag_mask_plus.imageset/编组@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/4_tag_mask_plus.imageset/编组@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/4_tag_mask_plus.imageset/编组@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/4_tag_mask_plus.imageset/编组@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/4_zhi_zhang_jump.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "编组 8@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "编组 8@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/4_zhi_zhang_jump.imageset/编组 8@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/4_zhi_zhang_jump.imageset/编组 8@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/4_zhi_zhang_jump.imageset/编组 8@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/4_zhi_zhang_jump.imageset/编组 8@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/album_4_kiWa.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "编组 2@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "编组 2@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/album_4_kiWa.imageset/编组 2@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/album_4_kiWa.imageset/编组 2@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/album_4_kiWa.imageset/编组 2@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/album_4_kiWa.imageset/编组 2@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/audio_4_3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "内容区/icon/120*120/创建音频@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "内容区/icon/120*120/创建音频@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/audio_4_3.imageset/内容区/icon/120*120/创建音频@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/audio_4_3.imageset/内容区/icon/120*120/创建音频@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/audio_4_3.imageset/内容区/icon/120*120/创建音频@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/audio_4_3.imageset/内容区/icon/120*120/创建音频@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/camera_4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "内容区/icon/历史记录@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "内容区/icon/历史记录@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/camera_4.imageset/内容区/icon/历史记录@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/camera_4.imageset/内容区/icon/历史记录@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/camera_4.imageset/内容区/icon/历史记录@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/camera_4.imageset/内容区/icon/历史记录@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/camera_4_highWox.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "拍摄键@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "拍摄键@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/camera_4_highWox.imageset/拍摄键@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/camera_4_highWox.imageset/拍摄键@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/camera_4_highWox.imageset/拍摄键@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/camera_4_highWox.imageset/拍摄键@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/camera_4_tip.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "弹窗提示@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "弹窗提示@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/camera_4_tip.imageset/弹窗提示@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/camera_4_tip.imageset/弹窗提示@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/camera_4_tip.imageset/弹窗提示@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/camera_4_tip.imageset/弹窗提示@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/fluorescence_4_1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "内容区/icon/120*120/荧光笔取词@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "内容区/icon/120*120/荧光笔取词@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/fluorescence_4_1.imageset/内容区/icon/120*120/荧光笔取词@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/fluorescence_4_1.imageset/内容区/icon/120*120/荧光笔取词@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/fluorescence_4_1.imageset/内容区/icon/120*120/荧光笔取词@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/fluorescence_4_1.imageset/内容区/icon/120*120/荧光笔取词@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/fork_4_kWa.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "编组@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "编组@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/fork_4_kWa.imageset/编组@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/fork_4_kWa.imageset/编组@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/fork_4_kWa.imageset/编组@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/fork_4_kWa.imageset/编组@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "矩形备份 2@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "矩形备份 2@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_4.imageset/矩形备份 2@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_4.imageset/矩形备份 2@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_4.imageset/矩形备份 2@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_4.imageset/矩形备份 2@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_4_arrow_item.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "路径 8@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "路径 8@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_4_arrow_item.imageset/路径 8@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_4_arrow_item.imageset/路径 8@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_4_arrow_item.imageset/路径 8@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_4_arrow_item.imageset/路径 8@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_4_selected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "tab栏/icon/我的/选中@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "tab栏/icon/我的/选中@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_4_selected.imageset/tab栏/icon/我的/选中@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_4_selected.imageset/tab栏/icon/我的/选中@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_4_selected.imageset/tab栏/icon/我的/选中@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_4_selected.imageset/tab栏/icon/我的/选中@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_woX_header_4_arrow.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "内容区/icon/历史记录@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "内容区/icon/历史记录@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_woX_header_4_arrow.imageset/内容区/icon/历史记录@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_woX_header_4_arrow.imageset/内容区/icon/历史记录@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_woX_header_4_arrow.imageset/内容区/icon/历史记录@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_woX_header_4_arrow.imageset/内容区/icon/历史记录@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_woX_header_4_bg.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "矩形@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "矩形@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_woX_header_4_bg.imageset/矩形@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_woX_header_4_bg.imageset/矩形@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_woX_header_4_bg.imageset/矩形@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/mine_woX_header_4_bg.imageset/矩形@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/plus_4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "tab栏/icon/加号@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "tab栏/icon/加号@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/plus_4.imageset/tab栏/icon/加号@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/plus_4.imageset/tab栏/icon/加号@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/plus_4.imageset/tab栏/icon/加号@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/plus_4.imageset/tab栏/icon/加号@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/pop_fork_4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "内容区/icon/历史记录@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "内容区/icon/历史记录@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/pop_fork_4.imageset/内容区/icon/历史记录@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/pop_fork_4.imageset/内容区/icon/历史记录@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/pop_fork_4.imageset/内容区/icon/历史记录@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/pop_fork_4.imageset/内容区/icon/历史记录@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/rotate_4_X.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "内容区/icon/历史记录@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "内容区/icon/历史记录@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/rotate_4_X.imageset/内容区/icon/历史记录@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/rotate_4_X.imageset/内容区/icon/历史记录@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/rotate_4_X.imageset/内容区/icon/历史记录@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/rotate_4_X.imageset/内容区/icon/历史记录@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/takenImg_4_tick.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "拍摄键@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "拍摄键@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/takenImg_4_tick.imageset/拍摄键@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/takenImg_4_tick.imageset/拍摄键@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/takenImg_4_tick.imageset/拍摄键@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/takenImg_4_tick.imageset/拍摄键@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/textBook_4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "矩形备份 2@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "矩形备份 2@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/textBook_4.imageset/矩形备份 2@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/textBook_4.imageset/矩形备份 2@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/textBook_4.imageset/矩形备份 2@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/textBook_4.imageset/矩形备份 2@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/textBook_4_selected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "tab栏/icon/课本/选中@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "tab栏/icon/课本/选中@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/textBook_4_selected.imageset/tab栏/icon/课本/选中@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/textBook_4_selected.imageset/tab栏/icon/课本/选中@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/textBook_4_selected.imageset/tab栏/icon/课本/选中@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/textBook_4_selected.imageset/tab栏/icon/课本/选中@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/text_4_2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "内容区/icon/120*120/创建文本@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "内容区/icon/120*120/创建文本@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/text_4_2.imageset/内容区/icon/120*120/创建文本@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/text_4_2.imageset/内容区/icon/120*120/创建文本@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/4/text_4_2.imageset/内容区/icon/120*120/创建文本@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/4/text_4_2.imageset/内容区/icon/120*120/创建文本@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/5/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/5/not_a_net.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "编组 2@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "编组 2@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/5/not_a_net.imageset/编组 2@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/5/not_a_net.imageset/编组 2@2x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/5/not_a_net.imageset/编组 2@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/Assets.xcassets/5/not_a_net.imageset/编组 2@3x.png
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | NSCameraUsageDescription
24 | 请点击"允许",
25 | NSMicrophoneUsageDescription
26 | 请点击"允许",
27 | UIApplicationSceneManifest
28 |
29 | UIApplicationSupportsMultipleScenes
30 |
31 | UISceneConfigurations
32 |
33 | UIWindowSceneSessionRoleApplication
34 |
35 |
36 | UISceneConfigurationName
37 | Default Configuration
38 | UISceneDelegateClassName
39 | $(PRODUCT_MODULE_NAME).SceneDelegate
40 | UISceneStoryboardFile
41 | Main
42 |
43 |
44 |
45 |
46 | UIApplicationSupportsIndirectInputEvents
47 |
48 | UILaunchStoryboardName
49 | LaunchScreen
50 | UIMainStoryboardFile
51 | Main
52 | UIRequiredDeviceCapabilities
53 |
54 | armv7
55 |
56 | UISupportedInterfaceOrientations
57 |
58 | UIInterfaceOrientationPortrait
59 |
60 | UISupportedInterfaceOrientations~ipad
61 |
62 | UIInterfaceOrientationPortrait
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // captureAndFilter
4 | //
5 | // Created by Jz D on 2021/2/23.
6 | //
7 |
8 | import UIKit
9 |
10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
11 |
12 | var window: UIWindow?
13 |
14 |
15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
16 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
17 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
18 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
19 | guard let _ = (scene as? UIWindowScene) else { return }
20 | }
21 |
22 | func sceneDidDisconnect(_ scene: UIScene) {
23 | // Called as the scene is being released by the system.
24 | // This occurs shortly after the scene enters the background, or when its session is discarded.
25 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
26 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
27 | }
28 |
29 | func sceneDidBecomeActive(_ scene: UIScene) {
30 | // Called when the scene has moved from an inactive state to an active state.
31 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
32 | }
33 |
34 | func sceneWillResignActive(_ scene: UIScene) {
35 | // Called when the scene will move from an active state to an inactive state.
36 | // This may occur due to temporary interruptions (ex. an incoming phone call).
37 | }
38 |
39 | func sceneWillEnterForeground(_ scene: UIScene) {
40 | // Called as the scene transitions from the background to the foreground.
41 | // Use this method to undo the changes made on entering the background.
42 | }
43 |
44 | func sceneDidEnterBackground(_ scene: UIScene) {
45 | // Called as the scene transitions from the foreground to the background.
46 | // Use this method to save data, release shared resources, and store enough scene-specific state information
47 | // to restore the scene back to its current state.
48 | }
49 |
50 |
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/SnapKit.framework/Info.plist:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/SnapKit.framework/Info.plist
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/SnapKit.framework/Modules/SnapKit.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/SnapKit.framework/Modules/SnapKit.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/SnapKit.framework/Modules/SnapKit.swiftmodule/Project/arm64.swiftsourceinfo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/SnapKit.framework/Modules/SnapKit.swiftmodule/Project/arm64.swiftsourceinfo
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/SnapKit.framework/Modules/SnapKit.swiftmodule/arm64-apple-ios.swiftdoc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/SnapKit.framework/Modules/SnapKit.swiftmodule/arm64-apple-ios.swiftdoc
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/SnapKit.framework/Modules/SnapKit.swiftmodule/arm64-apple-ios.swiftmodule:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/SnapKit.framework/Modules/SnapKit.swiftmodule/arm64-apple-ios.swiftmodule
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/SnapKit.framework/Modules/SnapKit.swiftmodule/arm64.swiftdoc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/SnapKit.framework/Modules/SnapKit.swiftmodule/arm64.swiftdoc
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/SnapKit.framework/Modules/SnapKit.swiftmodule/arm64.swiftmodule:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/SnapKit.framework/Modules/SnapKit.swiftmodule/arm64.swiftmodule
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/SnapKit.framework/Modules/module.modulemap:
--------------------------------------------------------------------------------
1 | framework module SnapKit {
2 | header "SnapKit-Swift.h"
3 | requires objc
4 | }
5 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/SnapKit.framework/SnapKit:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BoxDengJZ/SmartCropTry/bf7ab1c6a30694d241b08cdc0ef6bea02f359533/thirdCapture/captureAndFilter/SnapKit.framework/SnapKit
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // captureAndFilter
4 | //
5 | // Created by Jz D on 2021/2/23.
6 | //
7 |
8 | import UIKit
9 |
10 | class ViewController: UIViewController {
11 |
12 | override func viewDidLoad() {
13 | super.viewDidLoad()
14 | // Do any additional setup after loading the view.
15 |
16 |
17 | }
18 |
19 | @IBAction func open(_ sender: Any) {
20 |
21 | let camera = CusCamera()
22 | camera.takeDoneBlockX = { (info) in
23 | print(info)
24 | }
25 | showDetailViewController(camera, sender: nil)
26 | }
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/crop/Array+shift.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Array+shift.swift
3 | // CropView
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Array {
11 | func shifted(by shiftAmount: Int) -> [Element]{
12 | guard count > 0, (shiftAmount % count) != 0 else { return self }
13 | let moduloShiftAmount = shiftAmount % count
14 | let effectiveShiftAmount: Int
15 | if shiftAmount < 0{
16 | effectiveShiftAmount = moduloShiftAmount + count
17 | }
18 | else{
19 | effectiveShiftAmount = moduloShiftAmount
20 | }
21 | let shift: (Int) -> Int = {
22 | if $0 + effectiveShiftAmount >= count{
23 | return $0 + effectiveShiftAmount - count
24 | }
25 | else{
26 | return $0 + effectiveShiftAmount
27 | }
28 | }
29 | return enumerated().sorted(by: { shift($0.offset) < shift($1.offset) }).map { $0.element }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/crop/CGPoint+geometry.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGPoint+geometry.swift
3 | // CropView
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | //
7 |
8 | import UIKit
9 |
10 | extension CGPoint {
11 | func cartesian(for size: CGSize) -> CGPoint {
12 | return CGPoint(x: x, y: size.height - y)
13 | }
14 | static func cross(a: CGPoint, b: CGPoint) -> CGFloat {
15 | return a.x * b.y - a.y * b.x
16 | }
17 | func normalized(size: CGSize) -> CGPoint {
18 | return CGPoint(x: max(min(x, size.width), 0), y: max(min(y, size.height), 0))
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/crop/SEAreaView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AreaView.swift
3 | // CropViewController
4 | //
5 | // Created by Никита Разумный on 11/5/17.
6 | // Copyright © 2017 resquare. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SEAreaView: UIView {
12 |
13 | var path: CGMutablePath?
14 | var isPathValid = true
15 |
16 |
17 | override func draw(_ rect: CGRect) {
18 | super.draw(rect)
19 |
20 | guard let p = path else { return }
21 |
22 | let context = UIGraphicsGetCurrentContext()
23 | context?.setAllowsAntialiasing(true)
24 | context?.clip(to: rect)
25 |
26 | context?.addPath(p)
27 | context?.setLineWidth(1)
28 | context?.setLineCap(.round)
29 | context?.setLineJoin(.round)
30 |
31 |
32 | context?.setStrokeColor((isPathValid ? Setting.std.goodAreaColor : Setting.std.badAreaColor).cgColor)
33 | context?.strokePath()
34 | context?.addRect(bounds)
35 | context?.addPath(p)
36 |
37 | context?.setFillColor(UIColor(white: 0.3, alpha: 0.2).cgColor)
38 | context?.drawPath(using: .eoFill)
39 | }
40 |
41 |
42 | func fill(path p: CGMutablePath){
43 | path = p
44 | setNeedsDisplay()
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/crop/SECornerView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CornerView.swift
3 | // CropViewController
4 | //
5 | // Created by Никита Разумный on 11/5/17.
6 | // Copyright © 2017 resquare. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SECornerView: UIView {
12 |
13 | override init(frame: CGRect) {
14 | super.init(frame: frame)
15 | layer.cornerRadius = frame.size.width / 2.0
16 | layer.borderWidth = 1.0
17 | layer.masksToBounds = true
18 | backgroundColor = UIColor.clear
19 | }
20 |
21 | required init?(coder aDecoder: NSCoder) {
22 | super.init(coder: aDecoder)
23 | }
24 |
25 | func scaleUp() {
26 | UIView.animate(withDuration: 0.15, animations: {
27 | self.layer.borderWidth = 0.5
28 | self.transform = CGAffineTransform.identity.scaledBy(x: 2, y: 2)
29 | })
30 | }
31 |
32 | func scaleDown() {
33 | UIView.animate(withDuration: 0.15, animations: {
34 | self.layer.borderWidth = 1
35 | self.transform = CGAffineTransform.identity
36 | })
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/crop/SECropError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SECropError.swift
3 | // CropView
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | //
7 |
8 | import UIKit
9 |
10 | public enum SECropError: Error {
11 | case missingSuperview
12 | case missingImageOnImageView
13 | case invalidNumberOfCorners
14 | case nonConvexRect
15 | case missingImageWhileCropping
16 | case unknown
17 | case noImage
18 | }
19 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/crop/SEQuadrangleHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SEQuadrangleHelper.swift
3 | // CropView
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | //
7 |
8 | import UIKit
9 | import Foundation
10 | import AVFoundation
11 |
12 | public class SEQuadrangleHelper {
13 |
14 | static internal func orderPointsInQuadrangle(quad: [CGPoint]) throws -> [CGPoint] {
15 | func orderArrayClockwise(quad: [CGPoint]) -> [CGPoint] {
16 | // oriented area of quadrangle: cloclwise if it > 0
17 | var square: CGFloat = 0.0
18 | for i in 0 ..< quad.count - 1 {
19 | square += CGPoint.cross(a: CGPoint(x: quad[i].x - quad[0].x, y: quad[i].y - quad[0].y),
20 | b: CGPoint(x: quad[i + 1].x - quad[0].x, y: quad[i + 1].y - quad[0].y))
21 | }
22 | return square > 0 ? quad : quad.reversed()
23 | }
24 |
25 | func findTopLeftPointIndex(quad: [CGPoint]) throws -> Int {
26 | var topLeftPointIdx : Int = -1
27 | var topLeftShiftValue : CGFloat = 1000.0 * 1000.0 * 1000.0
28 |
29 | for i in 0 ..< quad.count {
30 | let shiftValue = quad[i].y + quad[i].x
31 | if shiftValue < topLeftShiftValue {
32 | topLeftPointIdx = i
33 | topLeftShiftValue = shiftValue
34 | }
35 | }
36 | guard topLeftPointIdx != -1 else { throw SECropError.unknown }
37 | return topLeftPointIdx
38 | }
39 |
40 | guard quad.count == 4 else { throw SECropError.invalidNumberOfCorners }
41 | guard checkConvex(corners: quad) else { throw SECropError.nonConvexRect }
42 |
43 | let orderedQuad = orderArrayClockwise(quad: quad)
44 | let topLeftIdx = try findTopLeftPointIndex(quad: orderedQuad)
45 | return orderedQuad.shifted(by: orderedQuad.count - topLeftIdx)
46 | }
47 |
48 | static public func cropImage(in rect: CGRect,with img: UIImage, quad corners: [CGPoint]) throws -> UIImage {
49 | let imgSize = img.size
50 | let f = AVMakeRect(aspectRatio: imgSize, insideRect: rect)
51 | let quad = corners.map { (pt) -> CGPoint in
52 | return pt.inner(img: imgSize, relative: f.size)
53 | }
54 | let ciImage = CIImage(image: img)
55 | // print("rect: ", rect, "corners: ",corners)
56 | let perspectiveCorrection = CIFilter(name: "CIPerspectiveCorrection")
57 |
58 | let orderedQuad = try orderPointsInQuadrangle(quad: quad)
59 | let context = CIContext(options: nil)
60 | // print("ordered quad: ", orderedQuad, "imgSize: ", imgSize)
61 |
62 | guard let transform = perspectiveCorrection else {
63 | throw SECropError.unknown
64 | }
65 | transform.setValue(CIVector(cgPoint: orderedQuad[0].cartesian(for: imgSize)),
66 | forKey: "inputTopLeft")
67 | transform.setValue(CIVector(cgPoint: orderedQuad[1].cartesian(for: imgSize)),
68 | forKey: "inputTopRight")
69 | transform.setValue(CIVector(cgPoint: orderedQuad[2].cartesian(for: imgSize)),
70 | forKey: "inputBottomRight")
71 | transform.setValue(CIVector(cgPoint: orderedQuad[3].cartesian(for: imgSize)),
72 | forKey: "inputBottomLeft")
73 | transform.setValue(ciImage, forKey: kCIInputImageKey)
74 |
75 | guard let perspectiveCorrectedImg = transform.outputImage, let cgImage = context.createCGImage(perspectiveCorrectedImg, from: perspectiveCorrectedImg.extent) else {
76 | throw SECropError.unknown
77 | }
78 |
79 | return UIImage(cgImage: cgImage, scale: img.scale, orientation: img.imageOrientation)
80 | }
81 |
82 | static internal func checkConvex(corners: [CGPoint]) -> Bool {
83 | guard corners.count > 2 else {
84 | return false
85 | }
86 | var positiveCount = 0
87 | var negativeCount = 0
88 | for i in 0 ..< corners.count {
89 | let p0 = corners[i]
90 | let p1 = corners[(i + 1) % corners.count]
91 | let p2 = corners[(i + 2) % corners.count]
92 |
93 | let cross = (p1.x - p0.x) * (p2.y - p1.y) - (p1.y - p0.y) * (p2.x - p1.x);
94 | if cross > 0 {
95 | positiveCount += 1
96 | } else if cross < 0 {
97 | negativeCount += 1
98 | }
99 | }
100 | return positiveCount == corners.count || negativeCount == corners.count
101 | }
102 | }
103 |
104 |
105 |
106 |
107 | extension CGPoint{
108 | func inner(img s: CGSize, relative dot: CGSize) -> CGPoint{
109 | let xx = x * s.width/dot.width
110 | let yy = y * s.height/dot.height
111 | return CGPoint(x: xx, y: yy)
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/crop/UIView+globalCoordinates.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+globalCoordinates.swift
3 | // CropView
4 | //
5 | // Created by Никита Разумный on 2/3/18.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIView {
11 | var globalPoint :CGPoint? {
12 | superview?.convert(frame.origin, to: nil)
13 | }
14 | var globalFrame :CGRect? {
15 | superview?.convert(frame, to: nil)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/two/ButtomViewFinal.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ButtomViewFinal.swift
3 | // petit
4 | //
5 | // Created by Jz D on 2021/2/3.
6 | // Copyright © 2021 swift. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ButtomViewFinal: UIView{
12 |
13 | lazy var bottomBeach: UIView = {
14 | let v = UIView()
15 | v.backgroundColor = UIColor.black
16 | return v
17 | }()
18 |
19 |
20 | lazy var retakeBtn: UIButton = {
21 | let keBtn = UIButton()
22 | keBtn.setTitle("重拍", for: .normal)
23 | keBtn.setTitleColor(UIColor.white, for: .normal)
24 | keBtn.titleLabel?.font = UIFont.regular(ofSize: 16)
25 | keBtn.adjustsImageWhenHighlighted = false
26 | return keBtn
27 | }()
28 |
29 | lazy var rotateBtn: UIButton = {
30 | let neBtn = UIButton()
31 | neBtn.setImage(UIImage(named: "rotate_4_X"), for: .normal)
32 | return neBtn
33 | }()
34 |
35 | lazy var doneBtn: UIButton = {
36 | let neBtn = UIButton()
37 | neBtn.setImage(UIImage(named: "takenImg_4_tick"), for: .normal)
38 | return neBtn
39 | }()
40 |
41 |
42 | override init(frame: CGRect) {
43 | super.init(frame: frame)
44 | isHidden = true
45 | addSubs([bottomBeach, retakeBtn, doneBtn,
46 | rotateBtn])
47 | bottomBeach.snp.makeConstraints { (m) in
48 | m.edges.equalToSuperview()
49 | }
50 |
51 | retakeBtn.snp.makeConstraints { (m) in
52 | m.leading.equalToSuperview().offset(40)
53 | m.centerY.equalTo(rotateBtn)
54 | }
55 |
56 | doneBtn.snp.makeConstraints { (m) in
57 | m.centerX.equalToSuperview()
58 | m.top.equalToSuperview().offset(48)
59 | m.size.equalTo(CGSize(width: 60, height: 60))
60 | }
61 |
62 | rotateBtn.snp.makeConstraints { (m) in
63 | m.trailing.equalToSuperview().offset(-40)
64 | m.top.equalTo(bottomBeach).offset(63)
65 | m.size.equalTo(CGSize(width: 25, height: 25))
66 | }
67 | }
68 |
69 |
70 |
71 |
72 | required init?(coder: NSCoder) {
73 | fatalError()
74 | }
75 |
76 | }
77 |
78 |
79 |
80 | extension UIView{
81 |
82 | func addSubs(_ views: [UIView]){
83 | views.forEach(addSubview(_:))
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/two/ButtomViewP.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ButtomVIewP.swift
3 | // petit
4 | //
5 | // Created by Jz D on 2021/2/3.
6 | // Copyright © 2021 swift. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ButtomViewP: UIView{
12 |
13 |
14 | lazy var dismissBtn: UIButton = {
15 | let edge: CGFloat = 45
16 | let b = UIButton(frame: CGRect(x: 40, y: 58, width: edge, height: edge))
17 | b.setImage(UIImage(named: "fork_4_kWa"), for: .normal)
18 | b.adjustsImageWhenHighlighted = false
19 | return b
20 | }()
21 |
22 |
23 | lazy var albumBu: UIButton = {
24 | let edge: CGFloat = 45
25 | let x = UI.std.width - 40 - edge
26 | let b = UIButton(frame: CGRect(x: x, y: 58, width: edge, height: edge))
27 | b.setImage(UIImage(named: "album_4_kiWa"), for: .normal)
28 |
29 | b.adjustsImageWhenHighlighted = false
30 | return b
31 | }()
32 |
33 |
34 |
35 | lazy var largeCircleB: UIImageView = {
36 | let img = UIImageView(image: UIImage(named: "camera_4_highWox"))
37 | img.isUserInteractionEnabled = true
38 | return img
39 | }()
40 |
41 |
42 |
43 | override init(frame: CGRect){
44 | super.init(frame: frame)
45 | backgroundColor = UIColor.black
46 | addSubs([largeCircleB,
47 | dismissBtn, albumBu])
48 |
49 | }
50 |
51 |
52 | override func layoutSubviews() {
53 | super.layoutSubviews()
54 |
55 | let largeCircleH: CGFloat = 60
56 | largeCircleB.frame = CGRect(x: (bounds.width-largeCircleH)/2, y: 48, width: largeCircleH, height: largeCircleH)
57 | }
58 |
59 |
60 | required init?(coder: NSCoder) {
61 | fatalError()
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/two/LinedTipView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LinedTipView.swift
3 | // petit
4 | //
5 | // Created by Jz D on 2021/2/3.
6 | // Copyright © 2021 swift. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class LinedTipView: UIView {
12 |
13 |
14 | lazy var tipIcon: UIImageView = {
15 | let frm = CGRect(x: 0, y: 0, width: 160, height: 160)
16 | let bel = UIImageView(frame: frm)
17 | bel.image = UIImage(named: "camera_4_tip")
18 |
19 | return bel
20 | }()
21 |
22 |
23 | override init(frame: CGRect) {
24 | super.init(frame: frame)
25 | backgroundColor = .clear
26 | addSubs([ tipIcon ])
27 | // layer.debug()
28 | }
29 |
30 |
31 | required init?(coder: NSCoder) {
32 | fatalError()
33 | }
34 |
35 |
36 | override func layoutSubviews() {
37 | super.layoutSubviews()
38 | tipIcon.center = CGPoint(x: bounds.width / 2, y: bounds.height / 2)
39 | }
40 |
41 |
42 | // Only override draw() if you perform custom drawing.
43 | // An empty implementation adversely affects performance during animation.
44 | override func draw(_ rect: CGRect) {
45 | let b = UIBezierPath()
46 | b.lineWidth = 1
47 | let pieceX = rect.width * 0.33
48 | let pieceY = rect.height * 0.33
49 | // 两竖
50 | b.move(to: CGPoint(x: pieceX, y: 0))
51 | b.addLine(to: CGPoint(x: pieceX, y: rect.height))
52 |
53 | b.move(to: CGPoint(x: pieceX * 2, y: 0))
54 | b.addLine(to: CGPoint(x: pieceX * 2, y: rect.height))
55 |
56 | // 两横
57 | b.move(to: CGPoint(x: 0, y: pieceY))
58 | b.addLine(to: CGPoint(x: rect.width, y: pieceY))
59 |
60 | b.move(to: CGPoint(x: 0, y: pieceY * 2))
61 | b.addLine(to: CGPoint(x: rect.width, y: pieceY * 2))
62 |
63 | UIColor(rgb: 0xFFFFFF, alpha: 0.6).setStroke()
64 | b.stroke()
65 | }
66 |
67 |
68 | }
69 |
70 |
71 |
72 |
73 |
74 |
75 | extension UIColor {
76 |
77 |
78 | convenience init(red: Int, green: Int, blue: Int, alpha: CGFloat) {
79 | assert(red >= 0 && red <= 255, "Invalid red component")
80 | assert(green >= 0 && green <= 255, "Invalid green component")
81 | assert(blue >= 0 && blue <= 255, "Invalid blue component")
82 |
83 | self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: alpha)
84 | }
85 |
86 |
87 |
88 | convenience init(rgb: Int, alpha: CGFloat = 1) {
89 | self.init(
90 | red: (rgb >> 16) & 0xFF,
91 | green: (rgb >> 8) & 0xFF,
92 | blue: rgb & 0xFF,
93 | alpha: alpha
94 | )
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/util/DebugLayer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File.swift
3 | // musicSheet
4 | //
5 | // Created by Jz D on 2019/8/22.
6 | // Copyright © 2019 上海莫小臣有限公司. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension CALayer{
12 |
13 | func debug(){
14 | borderColor = UIColor.blue.cgColor
15 | borderWidth = 1
16 | }
17 | }
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | protocol UI_debug {
27 | func debug( _ event: @escaping (UITapGestureRecognizer) -> Void)
28 | }
29 |
30 |
31 |
32 | extension UIView: UI_debug{
33 | // debugV
34 | func debug( _ event: @escaping (UITapGestureRecognizer) -> Void){
35 | // isUserInteractionEnabled = true
36 | let tap = UITapGestureRecognizer()
37 | tap.numberOfTapsRequired = 2
38 | // addGestureRecognizer(tap)
39 | // tap.rx.event.bind(onNext: event).disposed(by: rx.disposeBag)
40 | }
41 |
42 | }
43 |
44 |
45 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/util/FontAdd.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FontAdd.swift
3 | //
4 | //
5 | // Created by Jz D on 2019/8/23.
6 | //
7 |
8 | import UIKit
9 |
10 |
11 |
12 | enum FontWeight: String {
13 | case light = "Light"
14 | case regular = "Regular"
15 | case medium = "Medium"
16 |
17 | case semibold = "Semibold"
18 | case bold = "Bold"
19 | case heavy = "Heavy"
20 | }
21 |
22 | enum FontType: String {
23 | case PingFangSC = "PingFangSC"
24 | case SFProText = "SFProText"
25 | }
26 |
27 | extension UIFont {
28 |
29 | static func heavy(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {
30 | return customFont(type, weight: .heavy, fontSize: fontSize)
31 | }
32 |
33 | static func regular(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {
34 | return customFont(type, weight: .regular, fontSize: fontSize)
35 | }
36 |
37 | static func bold(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {
38 | return customFont(type, weight: .bold, fontSize: fontSize)
39 | }
40 |
41 | static func light(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {
42 | return customFont(type, weight: .light, fontSize: fontSize)
43 | }
44 |
45 | static func medium(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {
46 | return customFont(type, weight: .medium, fontSize: fontSize)
47 | }
48 |
49 | static func semibold(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {
50 | return customFont(type, weight: .semibold, fontSize: fontSize)
51 | }
52 |
53 | /// 自定义字体
54 | static func customFont(_ type: FontType, weight: FontWeight, fontSize: CGFloat) -> UIFont {
55 | let realFontSize = fontSize
56 |
57 | if let customFont = UIFont(name: "\(type.rawValue)-\(weight.rawValue)", size: realFontSize) {
58 | return customFont
59 | }
60 |
61 | var systemWeight = UIFont.Weight.regular
62 | switch weight {
63 | case .light:
64 | systemWeight = UIFont.Weight.light
65 | case .regular:
66 | systemWeight = UIFont.Weight.regular
67 | case .medium:
68 | systemWeight = UIFont.Weight.medium
69 | case .semibold:
70 | systemWeight = UIFont.Weight.semibold
71 | case .bold:
72 | systemWeight = UIFont.Weight.bold
73 | case .heavy:
74 | systemWeight = UIFont.Weight.heavy
75 | }
76 | return UIFont.systemFont(ofSize: realFontSize, weight: systemWeight)
77 | }
78 | }
79 |
80 |
81 |
82 |
83 |
84 | extension UIFont {
85 |
86 | static let scoreName = UIFont.medium(ofSize: 16)
87 | static let headerFirstThree = UIFont.medium(ofSize: 22)
88 | static let accountListTitle = UIFont.regular(ofSize: 16)
89 |
90 |
91 |
92 | static let myStudyTitle = UIFont.medium(ofSize: 18)
93 | static let myStudyListScoreName = UIFont.medium(ofSize: 14)
94 | static let loginHeaderName = UIFont.medium(ofSize: 16)
95 |
96 |
97 | }
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/util/RectAdd.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RectAdd.swift
3 | // musicSheet
4 | //
5 | // Created by Jz D on 2019/8/26.
6 | // Copyright © 2019 上海莫小臣有限公司. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 |
12 | extension CGRect{
13 |
14 | var end: CGPoint{
15 | return CGPoint(x: maxX, y: maxY)
16 | }
17 |
18 | var leftBottom: CGPoint{
19 | return CGPoint(x: minX, y: maxY)
20 | }
21 |
22 | var rightUp: CGPoint{
23 | return CGPoint(x: maxX, y: minY)
24 | }
25 | }
26 |
27 |
28 |
29 | struct UI {
30 |
31 | static let std = UI()
32 |
33 | var height: CGFloat{
34 | UIScreen.main.bounds.height
35 | }
36 |
37 |
38 | var layout: CGRect{
39 | UIScreen.main.bounds
40 | }
41 |
42 |
43 | var width: CGFloat{
44 | UIScreen.main.bounds.width
45 | }
46 |
47 | var bigS: Bool{
48 | UIScreen.main.bounds.height >= 812 || special
49 | }
50 |
51 |
52 |
53 | var center: CGPoint{
54 | CGPoint(x: width * 0.5, y: height * 0.5)
55 | }
56 |
57 |
58 | var origineY: CGFloat{
59 | return 20
60 | }
61 |
62 | var safeY: CGFloat{
63 | if bigS{
64 | return 44
65 | }
66 | else{
67 | return 0
68 | }
69 | }
70 |
71 | var bottomOffsetY: CGFloat{
72 | if bigS{
73 | return 34
74 | }
75 | else{
76 | return 0
77 | }
78 | }
79 |
80 |
81 | var contentY: CGFloat{
82 | origineY + 64
83 | }
84 |
85 |
86 | var special: Bool{
87 | UIScreen.main.bounds.width <= 320
88 | }
89 | }
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | public func * (left: CGFloat, right: Int) -> CGFloat {
100 | return left * CGFloat(right)
101 | }
102 |
103 |
104 | public func * (left: Int, right: CGFloat) -> CGFloat {
105 | return CGFloat(left) * right
106 | }
107 |
108 |
109 |
110 | extension CGFloat{
111 | var scalar: CGFloat{
112 | CGFloat(Int(self))
113 | }
114 | }
115 |
116 |
117 |
118 | extension CGRect{
119 | func right(x offset: CGFloat) -> CGRect{
120 | CGRect(origin: CGPoint(x: origin.x + offset, y: origin.y), size: size)
121 | }
122 |
123 |
124 | }
125 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/util/ZLCustomCamera.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ZLCustomCamera.swift
3 | // ZLPhotoBrowser
4 | //
5 | // Created by long on 2020/8/11.
6 | //
7 | // Copyright (c) 2020 Long Zhang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import UIKit
28 | import AVFoundation
29 | import CoreMotion
30 |
31 |
32 |
33 | enum CustomCameraOpt{
34 | case dft
35 | case result
36 | }
37 | class ZLCustomCamera{}
38 | extension ZLCustomCamera {
39 |
40 | @objc public enum CaptureSessionPreset: Int {
41 |
42 | var avSessionPreset: AVCaptureSession.Preset {
43 | switch self {
44 | case .cif352x288:
45 | return .cif352x288
46 | case .vga640x480:
47 | return .vga640x480
48 | case .hd1280x720:
49 | return .hd1280x720
50 | case .hd1920x1080:
51 | return .hd1920x1080
52 | case .hd4K3840x2160:
53 | return .hd4K3840x2160
54 | }
55 | }
56 |
57 | case cif352x288
58 | case vga640x480
59 | case hd1280x720
60 | case hd1920x1080
61 | case hd4K3840x2160
62 | }
63 |
64 | @objc public enum CameraFlashMode: Int {
65 |
66 | // 转自定义相机
67 | var avFlashMode: AVCaptureDevice.FlashMode {
68 | switch self {
69 | case .auto:
70 | return .auto
71 | case .on:
72 | return .on
73 | case .off:
74 | return .off
75 | }
76 | }
77 |
78 | // 转系统相机
79 | var imagePickerFlashMode: UIImagePickerController.CameraFlashMode {
80 | switch self {
81 | case .auto:
82 | return .auto
83 | case .on:
84 | return .on
85 | case .off:
86 | return .off
87 | }
88 | }
89 |
90 | case auto
91 | case on
92 | case off
93 | }
94 |
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilter/util/ZLGeneralDefine.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ZLGeneralDefine.swift
3 | // ZLPhotoBrowser
4 | //
5 | // Created by long on 2020/8/11.
6 | //
7 | // Copyright (c) 2020 Long Zhang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import UIKit
28 |
29 | let ZLMaxImageWidth: CGFloat = 600
30 |
31 | struct ZLLayout {
32 |
33 | static let navTitleFont = getFont(17)
34 |
35 | static let bottomToolViewH: CGFloat = 55
36 |
37 | static let bottomToolBtnH: CGFloat = 34
38 |
39 | static let bottomToolTitleFont = getFont(17)
40 |
41 | static let bottomToolBtnCornerRadius: CGFloat = 5
42 |
43 | static let thumbCollectionViewItemSpacing: CGFloat = 2
44 |
45 | static let thumbCollectionViewLineSpacing: CGFloat = 2
46 |
47 | }
48 |
49 | func zlRGB(_ red: CGFloat, _ green: CGFloat, _ blue: CGFloat) -> UIColor {
50 | return UIColor(red: red / 255, green: green / 255, blue: blue / 255, alpha: 1)
51 | }
52 |
53 |
54 | func getFont(_ size: CGFloat) -> UIFont {
55 | guard let name = ZLCustomFontDeploy.fontName else {
56 | return UIFont.systemFont(ofSize: size)
57 | }
58 |
59 | return UIFont(name: name, size: size) ?? UIFont.systemFont(ofSize: size)
60 | }
61 |
62 | func getAppName() -> String {
63 | if let name = Bundle.main.localizedInfoDictionary?["CFBundleDisplayName"] as? String {
64 | return name
65 | }
66 | if let name = Bundle.main.infoDictionary?["CFBundleDisplayName"] as? String {
67 | return name
68 | }
69 | if let name = Bundle.main.infoDictionary?["CFBundleName"] as? String {
70 | return name
71 | }
72 | return "App"
73 | }
74 |
75 |
76 |
77 | func getSpringAnimation() -> CAKeyframeAnimation {
78 | let animate = CAKeyframeAnimation(keyPath: "transform")
79 | animate.duration = 0.3
80 | animate.isRemovedOnCompletion = true
81 | animate.fillMode = .forwards
82 |
83 | animate.values = [CATransform3DMakeScale(0.7, 0.7, 1),
84 | CATransform3DMakeScale(1.2, 1.2, 1),
85 | CATransform3DMakeScale(0.8, 0.8, 1),
86 | CATransform3DMakeScale(1, 1, 1)]
87 | return animate
88 | }
89 |
90 |
91 | func zl_debugPrint(_ message: Any) {
92 | // debugPrint(message)
93 | }
94 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilterTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilterTests/captureAndFilterTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // captureAndFilterTests.swift
3 | // captureAndFilterTests
4 | //
5 | // Created by Jz D on 2021/2/23.
6 | //
7 |
8 | import XCTest
9 | @testable import captureAndFilter
10 |
11 | class captureAndFilterTests: XCTestCase {
12 |
13 | override func setUpWithError() throws {
14 | // Put setup code here. This method is called before the invocation of each test method in the class.
15 | }
16 |
17 | override func tearDownWithError() throws {
18 | // Put teardown code here. This method is called after the invocation of each test method in the class.
19 | }
20 |
21 | func testExample() throws {
22 | // This is an example of a functional test case.
23 | // Use XCTAssert and related functions to verify your tests produce the correct results.
24 | }
25 |
26 | func testPerformanceExample() throws {
27 | // This is an example of a performance test case.
28 | self.measure {
29 | // Put the code you want to measure the time of here.
30 | }
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilterUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/thirdCapture/captureAndFilterUITests/captureAndFilterUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // captureAndFilterUITests.swift
3 | // captureAndFilterUITests
4 | //
5 | // Created by Jz D on 2021/2/23.
6 | //
7 |
8 | import XCTest
9 |
10 | class captureAndFilterUITests: XCTestCase {
11 |
12 | override func setUpWithError() throws {
13 | // Put setup code here. This method is called before the invocation of each test method in the class.
14 |
15 | // In UI tests it is usually best to stop immediately when a failure occurs.
16 | continueAfterFailure = false
17 |
18 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
19 | }
20 |
21 | override func tearDownWithError() throws {
22 | // Put teardown code here. This method is called after the invocation of each test method in the class.
23 | }
24 |
25 | func testExample() throws {
26 | // UI tests must launch the application that they test.
27 | let app = XCUIApplication()
28 | app.launch()
29 |
30 | // Use recording to get started writing UI tests.
31 | // Use XCTAssert and related functions to verify your tests produce the correct results.
32 | }
33 |
34 | func testLaunchPerformance() throws {
35 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) {
36 | // This measures how long it takes to launch your application.
37 | measure(metrics: [XCTApplicationLaunchMetric()]) {
38 | XCUIApplication().launch()
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------