├── .gitattributes ├── .gitignore ├── .swift-version ├── LICENSE ├── Luban-iOSDemo ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Luban-iOS.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Luban-iOS │ ├── Controller │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Luban_iOS_Extension_h │ │ │ ├── UIImage+Luban_iOS_Extension_h.h │ │ │ └── UIImage+Luban_iOS_Extension_h.m │ │ ├── PhotoBrowserViewController.h │ │ ├── PhotoBrowserViewController.m │ │ ├── ViewController.h │ │ └── ViewController.m │ ├── Info.plist │ ├── LaunchScreen.storyboard │ ├── MacroFile.h │ ├── Main.storyboard │ ├── Resource │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ ├── ic_scqszj_sy.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── ic_scqszj_sy.png │ │ │ └── ic_wd_jyfk_tj.imageset │ │ │ │ ├── Contents.json │ │ │ │ ├── ic_wd_jyfk_tj@2x.png │ │ │ │ └── ic_wd_jyfk_tj@3x.png │ │ └── IMG_1998.JPG │ ├── Transition │ │ ├── ModalTransitionAnimator.h │ │ └── ModalTransitionAnimator.m │ └── main.m ├── Luban-iOSTests │ ├── Info.plist │ └── Luban_iOSTests.m ├── Luban-iOSUITests │ ├── Info.plist │ └── Luban_iOSUITests.m └── Luban_iOS_Extension_h │ ├── UIImage+Luban_iOS_Extension_h.h │ └── UIImage+Luban_iOS_Extension_h.m ├── Luban_iOS.podspec ├── Luban_iOS_Extension_h ├── UIImage+Luban_iOS_Extension_h.h └── UIImage+Luban_iOS_Extension_h.m └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj merge=union 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | ## Build generated 5 | build/ 6 | DerivedData/ 7 | ## Various settings 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata/ 17 | ## Other 18 | *.moved-aside 19 | *.xcuserstate 20 | .DS_Store 21 | ## Obj-C/Swift specific 22 | *.hmap 23 | *.ipa 24 | *.dSYM.zip 25 | *.dSYM 26 | # CocoaPods 27 | # 28 | # We recommend against adding the Pods directory to your .gitignore. However 29 | # you should judge for yourself, the pros and cons are mentioned at: 30 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 31 | # 32 | Pods/ 33 | # Carthage 34 | # 35 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 36 | # Carthage/Checkouts 37 | Carthage/Build 38 | # fastlane 39 | # 40 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 41 | # screenshots whenever they are needed. 42 | # For more information about the recommended setup visit: 43 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 44 | fastlane/report.xml 45 | fastlane/Preview.html 46 | fastlane/screenshots 47 | fastlane/test_output 48 | # Code Injection 49 | # 50 | # After new code Injection tools there's a generated folder /iOSInjectionProject 51 | # https://github.com/johnno1962/injectionforxcode 52 | iOSInjectionProject/ 53 | Luban-iOS/Luban-iOS.xcodeproj/project.pbxproj 54 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 2.3 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 cook 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 | -------------------------------------------------------------------------------- /Luban-iOSDemo/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 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Base.lproj/Main.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 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | BC6206311F1F3A3B00FCDC9E /* Luban_iOSTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BC6206301F1F3A3B00FCDC9E /* Luban_iOSTests.m */; }; 11 | BC62063C1F1F3A3B00FCDC9E /* Luban_iOSUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = BC62063B1F1F3A3B00FCDC9E /* Luban_iOSUITests.m */; }; 12 | BC6206731F25C78800FCDC9E /* PhotoBrowserViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BC62066B1F25C78800FCDC9E /* PhotoBrowserViewController.m */; }; 13 | BC6206741F25C78800FCDC9E /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BC62066D1F25C78800FCDC9E /* ViewController.m */; }; 14 | BC6206751F25C78800FCDC9E /* IMG_1998.JPG in Resources */ = {isa = PBXBuildFile; fileRef = BC62066F1F25C78800FCDC9E /* IMG_1998.JPG */; }; 15 | BC6206761F25C78800FCDC9E /* ModalTransitionAnimator.m in Sources */ = {isa = PBXBuildFile; fileRef = BC6206721F25C78800FCDC9E /* ModalTransitionAnimator.m */; }; 16 | BC62067A1F25C82900FCDC9E /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = BC6206771F25C82900FCDC9E /* Info.plist */; }; 17 | BC62067B1F25C82900FCDC9E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BC6206791F25C82900FCDC9E /* main.m */; }; 18 | BC62067D1F25C87D00FCDC9E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BC62067C1F25C87D00FCDC9E /* Assets.xcassets */; }; 19 | BC6206801F25C8A300FCDC9E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BC62067E1F25C8A300FCDC9E /* LaunchScreen.storyboard */; }; 20 | BC6206811F25C8A300FCDC9E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BC62067F1F25C8A300FCDC9E /* Main.storyboard */; }; 21 | BC6206841F25C8C000FCDC9E /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = BC6206831F25C8C000FCDC9E /* AppDelegate.m */; }; 22 | BC62068C1F25C95100FCDC9E /* UIImage+Luban_iOS_Extension_h.m in Sources */ = {isa = PBXBuildFile; fileRef = BC62068B1F25C95100FCDC9E /* UIImage+Luban_iOS_Extension_h.m */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXContainerItemProxy section */ 26 | BC62062D1F1F3A3B00FCDC9E /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = BC62060B1F1F3A3B00FCDC9E /* Project object */; 29 | proxyType = 1; 30 | remoteGlobalIDString = BC6206121F1F3A3B00FCDC9E; 31 | remoteInfo = "Luban-iOS"; 32 | }; 33 | BC6206381F1F3A3B00FCDC9E /* PBXContainerItemProxy */ = { 34 | isa = PBXContainerItemProxy; 35 | containerPortal = BC62060B1F1F3A3B00FCDC9E /* Project object */; 36 | proxyType = 1; 37 | remoteGlobalIDString = BC6206121F1F3A3B00FCDC9E; 38 | remoteInfo = "Luban-iOS"; 39 | }; 40 | /* End PBXContainerItemProxy section */ 41 | 42 | /* Begin PBXFileReference section */ 43 | BC6206131F1F3A3B00FCDC9E /* Luban-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Luban-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | BC62062C1F1F3A3B00FCDC9E /* Luban-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Luban-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | BC6206301F1F3A3B00FCDC9E /* Luban_iOSTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Luban_iOSTests.m; sourceTree = ""; }; 46 | BC6206321F1F3A3B00FCDC9E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 47 | BC6206371F1F3A3B00FCDC9E /* Luban-iOSUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Luban-iOSUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | BC62063B1F1F3A3B00FCDC9E /* Luban_iOSUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Luban_iOSUITests.m; sourceTree = ""; }; 49 | BC62063D1F1F3A3B00FCDC9E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50 | BC62066A1F25C78800FCDC9E /* PhotoBrowserViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PhotoBrowserViewController.h; sourceTree = ""; }; 51 | BC62066B1F25C78800FCDC9E /* PhotoBrowserViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PhotoBrowserViewController.m; sourceTree = ""; }; 52 | BC62066C1F25C78800FCDC9E /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 53 | BC62066D1F25C78800FCDC9E /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 54 | BC62066F1F25C78800FCDC9E /* IMG_1998.JPG */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = IMG_1998.JPG; sourceTree = ""; }; 55 | BC6206711F25C78800FCDC9E /* ModalTransitionAnimator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModalTransitionAnimator.h; sourceTree = ""; }; 56 | BC6206721F25C78800FCDC9E /* ModalTransitionAnimator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ModalTransitionAnimator.m; sourceTree = ""; }; 57 | BC6206771F25C82900FCDC9E /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | BC6206781F25C82900FCDC9E /* MacroFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroFile.h; sourceTree = ""; }; 59 | BC6206791F25C82900FCDC9E /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 60 | BC62067C1F25C87D00FCDC9E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 61 | BC62067E1F25C8A300FCDC9E /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 62 | BC62067F1F25C8A300FCDC9E /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 63 | BC6206821F25C8C000FCDC9E /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 64 | BC6206831F25C8C000FCDC9E /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 65 | BC62068A1F25C95100FCDC9E /* UIImage+Luban_iOS_Extension_h.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Luban_iOS_Extension_h.h"; sourceTree = ""; }; 66 | BC62068B1F25C95100FCDC9E /* UIImage+Luban_iOS_Extension_h.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Luban_iOS_Extension_h.m"; sourceTree = ""; }; 67 | /* End PBXFileReference section */ 68 | 69 | /* Begin PBXFrameworksBuildPhase section */ 70 | BC6206101F1F3A3B00FCDC9E /* Frameworks */ = { 71 | isa = PBXFrameworksBuildPhase; 72 | buildActionMask = 2147483647; 73 | files = ( 74 | ); 75 | runOnlyForDeploymentPostprocessing = 0; 76 | }; 77 | BC6206291F1F3A3B00FCDC9E /* Frameworks */ = { 78 | isa = PBXFrameworksBuildPhase; 79 | buildActionMask = 2147483647; 80 | files = ( 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | BC6206341F1F3A3B00FCDC9E /* Frameworks */ = { 85 | isa = PBXFrameworksBuildPhase; 86 | buildActionMask = 2147483647; 87 | files = ( 88 | ); 89 | runOnlyForDeploymentPostprocessing = 0; 90 | }; 91 | /* End PBXFrameworksBuildPhase section */ 92 | 93 | /* Begin PBXGroup section */ 94 | BC62060A1F1F3A3B00FCDC9E = { 95 | isa = PBXGroup; 96 | children = ( 97 | BC6206151F1F3A3B00FCDC9E /* Luban-iOS */, 98 | BC62062F1F1F3A3B00FCDC9E /* Luban-iOSTests */, 99 | BC62063A1F1F3A3B00FCDC9E /* Luban-iOSUITests */, 100 | BC6206141F1F3A3B00FCDC9E /* Products */, 101 | ); 102 | sourceTree = ""; 103 | }; 104 | BC6206141F1F3A3B00FCDC9E /* Products */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | BC6206131F1F3A3B00FCDC9E /* Luban-iOS.app */, 108 | BC62062C1F1F3A3B00FCDC9E /* Luban-iOSTests.xctest */, 109 | BC6206371F1F3A3B00FCDC9E /* Luban-iOSUITests.xctest */, 110 | ); 111 | name = Products; 112 | sourceTree = ""; 113 | }; 114 | BC6206151F1F3A3B00FCDC9E /* Luban-iOS */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | BC62067E1F25C8A300FCDC9E /* LaunchScreen.storyboard */, 118 | BC62067F1F25C8A300FCDC9E /* Main.storyboard */, 119 | BC6206691F25C78800FCDC9E /* Controller */, 120 | BC62066E1F25C78800FCDC9E /* Resource */, 121 | BC6206701F25C78800FCDC9E /* Transition */, 122 | BC6206161F1F3A3B00FCDC9E /* Supporting Files */, 123 | ); 124 | path = "Luban-iOS"; 125 | sourceTree = ""; 126 | }; 127 | BC6206161F1F3A3B00FCDC9E /* Supporting Files */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | BC6206771F25C82900FCDC9E /* Info.plist */, 131 | BC6206781F25C82900FCDC9E /* MacroFile.h */, 132 | BC6206791F25C82900FCDC9E /* main.m */, 133 | ); 134 | name = "Supporting Files"; 135 | sourceTree = ""; 136 | }; 137 | BC62062F1F1F3A3B00FCDC9E /* Luban-iOSTests */ = { 138 | isa = PBXGroup; 139 | children = ( 140 | BC6206301F1F3A3B00FCDC9E /* Luban_iOSTests.m */, 141 | BC6206321F1F3A3B00FCDC9E /* Info.plist */, 142 | ); 143 | path = "Luban-iOSTests"; 144 | sourceTree = ""; 145 | }; 146 | BC62063A1F1F3A3B00FCDC9E /* Luban-iOSUITests */ = { 147 | isa = PBXGroup; 148 | children = ( 149 | BC62063B1F1F3A3B00FCDC9E /* Luban_iOSUITests.m */, 150 | BC62063D1F1F3A3B00FCDC9E /* Info.plist */, 151 | ); 152 | path = "Luban-iOSUITests"; 153 | sourceTree = ""; 154 | }; 155 | BC6206691F25C78800FCDC9E /* Controller */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | BC6206891F25C95100FCDC9E /* Luban_iOS_Extension_h */, 159 | BC6206821F25C8C000FCDC9E /* AppDelegate.h */, 160 | BC6206831F25C8C000FCDC9E /* AppDelegate.m */, 161 | BC62066A1F25C78800FCDC9E /* PhotoBrowserViewController.h */, 162 | BC62066B1F25C78800FCDC9E /* PhotoBrowserViewController.m */, 163 | BC62066C1F25C78800FCDC9E /* ViewController.h */, 164 | BC62066D1F25C78800FCDC9E /* ViewController.m */, 165 | ); 166 | path = Controller; 167 | sourceTree = ""; 168 | }; 169 | BC62066E1F25C78800FCDC9E /* Resource */ = { 170 | isa = PBXGroup; 171 | children = ( 172 | BC62067C1F25C87D00FCDC9E /* Assets.xcassets */, 173 | BC62066F1F25C78800FCDC9E /* IMG_1998.JPG */, 174 | ); 175 | path = Resource; 176 | sourceTree = ""; 177 | }; 178 | BC6206701F25C78800FCDC9E /* Transition */ = { 179 | isa = PBXGroup; 180 | children = ( 181 | BC6206711F25C78800FCDC9E /* ModalTransitionAnimator.h */, 182 | BC6206721F25C78800FCDC9E /* ModalTransitionAnimator.m */, 183 | ); 184 | path = Transition; 185 | sourceTree = ""; 186 | }; 187 | BC6206891F25C95100FCDC9E /* Luban_iOS_Extension_h */ = { 188 | isa = PBXGroup; 189 | children = ( 190 | BC62068A1F25C95100FCDC9E /* UIImage+Luban_iOS_Extension_h.h */, 191 | BC62068B1F25C95100FCDC9E /* UIImage+Luban_iOS_Extension_h.m */, 192 | ); 193 | path = Luban_iOS_Extension_h; 194 | sourceTree = ""; 195 | }; 196 | /* End PBXGroup section */ 197 | 198 | /* Begin PBXNativeTarget section */ 199 | BC6206121F1F3A3B00FCDC9E /* Luban-iOS */ = { 200 | isa = PBXNativeTarget; 201 | buildConfigurationList = BC6206401F1F3A3B00FCDC9E /* Build configuration list for PBXNativeTarget "Luban-iOS" */; 202 | buildPhases = ( 203 | BC62060F1F1F3A3B00FCDC9E /* Sources */, 204 | BC6206101F1F3A3B00FCDC9E /* Frameworks */, 205 | BC6206111F1F3A3B00FCDC9E /* Resources */, 206 | ); 207 | buildRules = ( 208 | ); 209 | dependencies = ( 210 | ); 211 | name = "Luban-iOS"; 212 | productName = "Luban-iOS"; 213 | productReference = BC6206131F1F3A3B00FCDC9E /* Luban-iOS.app */; 214 | productType = "com.apple.product-type.application"; 215 | }; 216 | BC62062B1F1F3A3B00FCDC9E /* Luban-iOSTests */ = { 217 | isa = PBXNativeTarget; 218 | buildConfigurationList = BC6206431F1F3A3B00FCDC9E /* Build configuration list for PBXNativeTarget "Luban-iOSTests" */; 219 | buildPhases = ( 220 | BC6206281F1F3A3B00FCDC9E /* Sources */, 221 | BC6206291F1F3A3B00FCDC9E /* Frameworks */, 222 | BC62062A1F1F3A3B00FCDC9E /* Resources */, 223 | ); 224 | buildRules = ( 225 | ); 226 | dependencies = ( 227 | BC62062E1F1F3A3B00FCDC9E /* PBXTargetDependency */, 228 | ); 229 | name = "Luban-iOSTests"; 230 | productName = "Luban-iOSTests"; 231 | productReference = BC62062C1F1F3A3B00FCDC9E /* Luban-iOSTests.xctest */; 232 | productType = "com.apple.product-type.bundle.unit-test"; 233 | }; 234 | BC6206361F1F3A3B00FCDC9E /* Luban-iOSUITests */ = { 235 | isa = PBXNativeTarget; 236 | buildConfigurationList = BC6206461F1F3A3B00FCDC9E /* Build configuration list for PBXNativeTarget "Luban-iOSUITests" */; 237 | buildPhases = ( 238 | BC6206331F1F3A3B00FCDC9E /* Sources */, 239 | BC6206341F1F3A3B00FCDC9E /* Frameworks */, 240 | BC6206351F1F3A3B00FCDC9E /* Resources */, 241 | ); 242 | buildRules = ( 243 | ); 244 | dependencies = ( 245 | BC6206391F1F3A3B00FCDC9E /* PBXTargetDependency */, 246 | ); 247 | name = "Luban-iOSUITests"; 248 | productName = "Luban-iOSUITests"; 249 | productReference = BC6206371F1F3A3B00FCDC9E /* Luban-iOSUITests.xctest */; 250 | productType = "com.apple.product-type.bundle.ui-testing"; 251 | }; 252 | /* End PBXNativeTarget section */ 253 | 254 | /* Begin PBXProject section */ 255 | BC62060B1F1F3A3B00FCDC9E /* Project object */ = { 256 | isa = PBXProject; 257 | attributes = { 258 | LastUpgradeCheck = 0830; 259 | ORGANIZATIONNAME = guo; 260 | TargetAttributes = { 261 | BC6206121F1F3A3B00FCDC9E = { 262 | CreatedOnToolsVersion = 8.3.2; 263 | DevelopmentTeam = D95RMHATXP; 264 | ProvisioningStyle = Automatic; 265 | }; 266 | BC62062B1F1F3A3B00FCDC9E = { 267 | CreatedOnToolsVersion = 8.3.2; 268 | DevelopmentTeam = 8JAJ87K5LP; 269 | ProvisioningStyle = Automatic; 270 | TestTargetID = BC6206121F1F3A3B00FCDC9E; 271 | }; 272 | BC6206361F1F3A3B00FCDC9E = { 273 | CreatedOnToolsVersion = 8.3.2; 274 | DevelopmentTeam = 8JAJ87K5LP; 275 | ProvisioningStyle = Automatic; 276 | TestTargetID = BC6206121F1F3A3B00FCDC9E; 277 | }; 278 | }; 279 | }; 280 | buildConfigurationList = BC62060E1F1F3A3B00FCDC9E /* Build configuration list for PBXProject "Luban-iOS" */; 281 | compatibilityVersion = "Xcode 3.2"; 282 | developmentRegion = English; 283 | hasScannedForEncodings = 0; 284 | knownRegions = ( 285 | en, 286 | Base, 287 | ); 288 | mainGroup = BC62060A1F1F3A3B00FCDC9E; 289 | productRefGroup = BC6206141F1F3A3B00FCDC9E /* Products */; 290 | projectDirPath = ""; 291 | projectRoot = ""; 292 | targets = ( 293 | BC6206121F1F3A3B00FCDC9E /* Luban-iOS */, 294 | BC62062B1F1F3A3B00FCDC9E /* Luban-iOSTests */, 295 | BC6206361F1F3A3B00FCDC9E /* Luban-iOSUITests */, 296 | ); 297 | }; 298 | /* End PBXProject section */ 299 | 300 | /* Begin PBXResourcesBuildPhase section */ 301 | BC6206111F1F3A3B00FCDC9E /* Resources */ = { 302 | isa = PBXResourcesBuildPhase; 303 | buildActionMask = 2147483647; 304 | files = ( 305 | BC62067A1F25C82900FCDC9E /* Info.plist in Resources */, 306 | BC6206811F25C8A300FCDC9E /* Main.storyboard in Resources */, 307 | BC6206801F25C8A300FCDC9E /* LaunchScreen.storyboard in Resources */, 308 | BC62067D1F25C87D00FCDC9E /* Assets.xcassets in Resources */, 309 | BC6206751F25C78800FCDC9E /* IMG_1998.JPG in Resources */, 310 | ); 311 | runOnlyForDeploymentPostprocessing = 0; 312 | }; 313 | BC62062A1F1F3A3B00FCDC9E /* Resources */ = { 314 | isa = PBXResourcesBuildPhase; 315 | buildActionMask = 2147483647; 316 | files = ( 317 | ); 318 | runOnlyForDeploymentPostprocessing = 0; 319 | }; 320 | BC6206351F1F3A3B00FCDC9E /* Resources */ = { 321 | isa = PBXResourcesBuildPhase; 322 | buildActionMask = 2147483647; 323 | files = ( 324 | ); 325 | runOnlyForDeploymentPostprocessing = 0; 326 | }; 327 | /* End PBXResourcesBuildPhase section */ 328 | 329 | /* Begin PBXSourcesBuildPhase section */ 330 | BC62060F1F1F3A3B00FCDC9E /* Sources */ = { 331 | isa = PBXSourcesBuildPhase; 332 | buildActionMask = 2147483647; 333 | files = ( 334 | BC6206741F25C78800FCDC9E /* ViewController.m in Sources */, 335 | BC6206761F25C78800FCDC9E /* ModalTransitionAnimator.m in Sources */, 336 | BC62067B1F25C82900FCDC9E /* main.m in Sources */, 337 | BC62068C1F25C95100FCDC9E /* UIImage+Luban_iOS_Extension_h.m in Sources */, 338 | BC6206731F25C78800FCDC9E /* PhotoBrowserViewController.m in Sources */, 339 | BC6206841F25C8C000FCDC9E /* AppDelegate.m in Sources */, 340 | ); 341 | runOnlyForDeploymentPostprocessing = 0; 342 | }; 343 | BC6206281F1F3A3B00FCDC9E /* Sources */ = { 344 | isa = PBXSourcesBuildPhase; 345 | buildActionMask = 2147483647; 346 | files = ( 347 | BC6206311F1F3A3B00FCDC9E /* Luban_iOSTests.m in Sources */, 348 | ); 349 | runOnlyForDeploymentPostprocessing = 0; 350 | }; 351 | BC6206331F1F3A3B00FCDC9E /* Sources */ = { 352 | isa = PBXSourcesBuildPhase; 353 | buildActionMask = 2147483647; 354 | files = ( 355 | BC62063C1F1F3A3B00FCDC9E /* Luban_iOSUITests.m in Sources */, 356 | ); 357 | runOnlyForDeploymentPostprocessing = 0; 358 | }; 359 | /* End PBXSourcesBuildPhase section */ 360 | 361 | /* Begin PBXTargetDependency section */ 362 | BC62062E1F1F3A3B00FCDC9E /* PBXTargetDependency */ = { 363 | isa = PBXTargetDependency; 364 | target = BC6206121F1F3A3B00FCDC9E /* Luban-iOS */; 365 | targetProxy = BC62062D1F1F3A3B00FCDC9E /* PBXContainerItemProxy */; 366 | }; 367 | BC6206391F1F3A3B00FCDC9E /* PBXTargetDependency */ = { 368 | isa = PBXTargetDependency; 369 | target = BC6206121F1F3A3B00FCDC9E /* Luban-iOS */; 370 | targetProxy = BC6206381F1F3A3B00FCDC9E /* PBXContainerItemProxy */; 371 | }; 372 | /* End PBXTargetDependency section */ 373 | 374 | /* Begin XCBuildConfiguration section */ 375 | BC62063E1F1F3A3B00FCDC9E /* Debug */ = { 376 | isa = XCBuildConfiguration; 377 | buildSettings = { 378 | ALWAYS_SEARCH_USER_PATHS = NO; 379 | CLANG_ANALYZER_NONNULL = YES; 380 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 381 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 382 | CLANG_CXX_LIBRARY = "libc++"; 383 | CLANG_ENABLE_MODULES = YES; 384 | CLANG_ENABLE_OBJC_ARC = YES; 385 | CLANG_WARN_BOOL_CONVERSION = YES; 386 | CLANG_WARN_CONSTANT_CONVERSION = YES; 387 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 388 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 389 | CLANG_WARN_EMPTY_BODY = YES; 390 | CLANG_WARN_ENUM_CONVERSION = YES; 391 | CLANG_WARN_INFINITE_RECURSION = YES; 392 | CLANG_WARN_INT_CONVERSION = YES; 393 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 394 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 395 | CLANG_WARN_UNREACHABLE_CODE = YES; 396 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 397 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 398 | COPY_PHASE_STRIP = NO; 399 | DEBUG_INFORMATION_FORMAT = dwarf; 400 | ENABLE_STRICT_OBJC_MSGSEND = YES; 401 | ENABLE_TESTABILITY = YES; 402 | GCC_C_LANGUAGE_STANDARD = gnu99; 403 | GCC_DYNAMIC_NO_PIC = NO; 404 | GCC_NO_COMMON_BLOCKS = YES; 405 | GCC_OPTIMIZATION_LEVEL = 0; 406 | GCC_PREPROCESSOR_DEFINITIONS = ( 407 | "DEBUG=1", 408 | "$(inherited)", 409 | ); 410 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 411 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 412 | GCC_WARN_UNDECLARED_SELECTOR = YES; 413 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 414 | GCC_WARN_UNUSED_FUNCTION = YES; 415 | GCC_WARN_UNUSED_VARIABLE = YES; 416 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 417 | MTL_ENABLE_DEBUG_INFO = YES; 418 | ONLY_ACTIVE_ARCH = YES; 419 | SDKROOT = iphoneos; 420 | TARGETED_DEVICE_FAMILY = "1,2"; 421 | }; 422 | name = Debug; 423 | }; 424 | BC62063F1F1F3A3B00FCDC9E /* Release */ = { 425 | isa = XCBuildConfiguration; 426 | buildSettings = { 427 | ALWAYS_SEARCH_USER_PATHS = NO; 428 | CLANG_ANALYZER_NONNULL = YES; 429 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 430 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 431 | CLANG_CXX_LIBRARY = "libc++"; 432 | CLANG_ENABLE_MODULES = YES; 433 | CLANG_ENABLE_OBJC_ARC = YES; 434 | CLANG_WARN_BOOL_CONVERSION = YES; 435 | CLANG_WARN_CONSTANT_CONVERSION = YES; 436 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 437 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 438 | CLANG_WARN_EMPTY_BODY = YES; 439 | CLANG_WARN_ENUM_CONVERSION = YES; 440 | CLANG_WARN_INFINITE_RECURSION = YES; 441 | CLANG_WARN_INT_CONVERSION = YES; 442 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 443 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 444 | CLANG_WARN_UNREACHABLE_CODE = YES; 445 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 446 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 447 | COPY_PHASE_STRIP = NO; 448 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 449 | ENABLE_NS_ASSERTIONS = NO; 450 | ENABLE_STRICT_OBJC_MSGSEND = YES; 451 | GCC_C_LANGUAGE_STANDARD = gnu99; 452 | GCC_NO_COMMON_BLOCKS = YES; 453 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 454 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 455 | GCC_WARN_UNDECLARED_SELECTOR = YES; 456 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 457 | GCC_WARN_UNUSED_FUNCTION = YES; 458 | GCC_WARN_UNUSED_VARIABLE = YES; 459 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 460 | MTL_ENABLE_DEBUG_INFO = NO; 461 | SDKROOT = iphoneos; 462 | TARGETED_DEVICE_FAMILY = "1,2"; 463 | VALIDATE_PRODUCT = YES; 464 | }; 465 | name = Release; 466 | }; 467 | BC6206411F1F3A3B00FCDC9E /* Debug */ = { 468 | isa = XCBuildConfiguration; 469 | buildSettings = { 470 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 471 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 472 | DEVELOPMENT_TEAM = D95RMHATXP; 473 | INFOPLIST_FILE = "Luban-iOS/Info.plist"; 474 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 475 | PRODUCT_BUNDLE_IDENTIFIER = "lianjia.Luban-iOS"; 476 | PRODUCT_NAME = "$(TARGET_NAME)"; 477 | PROVISIONING_PROFILE_SPECIFIER = ""; 478 | }; 479 | name = Debug; 480 | }; 481 | BC6206421F1F3A3B00FCDC9E /* Release */ = { 482 | isa = XCBuildConfiguration; 483 | buildSettings = { 484 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 485 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 486 | DEVELOPMENT_TEAM = D95RMHATXP; 487 | INFOPLIST_FILE = "Luban-iOS/Info.plist"; 488 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 489 | PRODUCT_BUNDLE_IDENTIFIER = "lianjia.Luban-iOS"; 490 | PRODUCT_NAME = "$(TARGET_NAME)"; 491 | PROVISIONING_PROFILE_SPECIFIER = ""; 492 | }; 493 | name = Release; 494 | }; 495 | BC6206441F1F3A3B00FCDC9E /* Debug */ = { 496 | isa = XCBuildConfiguration; 497 | buildSettings = { 498 | BUNDLE_LOADER = "$(TEST_HOST)"; 499 | DEVELOPMENT_TEAM = 8JAJ87K5LP; 500 | INFOPLIST_FILE = "Luban-iOSTests/Info.plist"; 501 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 502 | PRODUCT_BUNDLE_IDENTIFIER = "lianjia.Luban-iOSTests"; 503 | PRODUCT_NAME = "$(TARGET_NAME)"; 504 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Luban-iOS.app/Luban-iOS"; 505 | }; 506 | name = Debug; 507 | }; 508 | BC6206451F1F3A3B00FCDC9E /* Release */ = { 509 | isa = XCBuildConfiguration; 510 | buildSettings = { 511 | BUNDLE_LOADER = "$(TEST_HOST)"; 512 | DEVELOPMENT_TEAM = 8JAJ87K5LP; 513 | INFOPLIST_FILE = "Luban-iOSTests/Info.plist"; 514 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 515 | PRODUCT_BUNDLE_IDENTIFIER = "lianjia.Luban-iOSTests"; 516 | PRODUCT_NAME = "$(TARGET_NAME)"; 517 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Luban-iOS.app/Luban-iOS"; 518 | }; 519 | name = Release; 520 | }; 521 | BC6206471F1F3A3B00FCDC9E /* Debug */ = { 522 | isa = XCBuildConfiguration; 523 | buildSettings = { 524 | DEVELOPMENT_TEAM = 8JAJ87K5LP; 525 | INFOPLIST_FILE = "Luban-iOSUITests/Info.plist"; 526 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 527 | PRODUCT_BUNDLE_IDENTIFIER = "lianjia.Luban-iOSUITests"; 528 | PRODUCT_NAME = "$(TARGET_NAME)"; 529 | TEST_TARGET_NAME = "Luban-iOS"; 530 | }; 531 | name = Debug; 532 | }; 533 | BC6206481F1F3A3B00FCDC9E /* Release */ = { 534 | isa = XCBuildConfiguration; 535 | buildSettings = { 536 | DEVELOPMENT_TEAM = 8JAJ87K5LP; 537 | INFOPLIST_FILE = "Luban-iOSUITests/Info.plist"; 538 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 539 | PRODUCT_BUNDLE_IDENTIFIER = "lianjia.Luban-iOSUITests"; 540 | PRODUCT_NAME = "$(TARGET_NAME)"; 541 | TEST_TARGET_NAME = "Luban-iOS"; 542 | }; 543 | name = Release; 544 | }; 545 | /* End XCBuildConfiguration section */ 546 | 547 | /* Begin XCConfigurationList section */ 548 | BC62060E1F1F3A3B00FCDC9E /* Build configuration list for PBXProject "Luban-iOS" */ = { 549 | isa = XCConfigurationList; 550 | buildConfigurations = ( 551 | BC62063E1F1F3A3B00FCDC9E /* Debug */, 552 | BC62063F1F1F3A3B00FCDC9E /* Release */, 553 | ); 554 | defaultConfigurationIsVisible = 0; 555 | defaultConfigurationName = Release; 556 | }; 557 | BC6206401F1F3A3B00FCDC9E /* Build configuration list for PBXNativeTarget "Luban-iOS" */ = { 558 | isa = XCConfigurationList; 559 | buildConfigurations = ( 560 | BC6206411F1F3A3B00FCDC9E /* Debug */, 561 | BC6206421F1F3A3B00FCDC9E /* Release */, 562 | ); 563 | defaultConfigurationIsVisible = 0; 564 | defaultConfigurationName = Release; 565 | }; 566 | BC6206431F1F3A3B00FCDC9E /* Build configuration list for PBXNativeTarget "Luban-iOSTests" */ = { 567 | isa = XCConfigurationList; 568 | buildConfigurations = ( 569 | BC6206441F1F3A3B00FCDC9E /* Debug */, 570 | BC6206451F1F3A3B00FCDC9E /* Release */, 571 | ); 572 | defaultConfigurationIsVisible = 0; 573 | defaultConfigurationName = Release; 574 | }; 575 | BC6206461F1F3A3B00FCDC9E /* Build configuration list for PBXNativeTarget "Luban-iOSUITests" */ = { 576 | isa = XCConfigurationList; 577 | buildConfigurations = ( 578 | BC6206471F1F3A3B00FCDC9E /* Debug */, 579 | BC6206481F1F3A3B00FCDC9E /* Release */, 580 | ); 581 | defaultConfigurationIsVisible = 0; 582 | defaultConfigurationName = Release; 583 | }; 584 | /* End XCConfigurationList section */ 585 | }; 586 | rootObject = BC62060B1F1F3A3B00FCDC9E /* Project object */; 587 | } 588 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/Controller/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // Luban-iOS 4 | // 5 | // Created by guo on 2017/7/19. 6 | // Copyright © 2017年 guo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/Controller/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // Luban-iOS 4 | // 5 | // Created by guo on 2017/7/19. 6 | // Copyright © 2017年 guo. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // 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. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // 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. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // 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. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // 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. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/Controller/Luban_iOS_Extension_h/UIImage+Luban_iOS_Extension_h.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Luban_iOS_Extension_h.h 3 | // Luban-iOS 4 | // 5 | // Created by guo on 2017/7/20. 6 | // Copyright © 2017年 guo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIImage (Luban_iOS_Extension_h) 12 | 13 | + (NSData *)lubanCompressImage:(UIImage *)image; 14 | + (NSData *)lubanCompressImage:(UIImage *)image withMask:(NSString *)maskName; 15 | + (NSData *)lubanCompressImage:(UIImage *)image withCustomImage:(NSString *)imageName; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/Controller/Luban_iOS_Extension_h/UIImage+Luban_iOS_Extension_h.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Luban_iOS_Extension_h.m 3 | // Luban-iOS 4 | // 5 | // Created by guo on 2017/7/20. 6 | // Copyright © 2017年 guo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "UIImage+Luban_iOS_Extension_h.h" 11 | 12 | @implementation UIImage (Luban_iOS_Extension_h) 13 | 14 | static char isCustomImage; 15 | static char customImageName; 16 | 17 | + (NSData *)lubanCompressImage:(UIImage *)image { 18 | return [self lubanCompressImage:image withMask:nil]; 19 | } 20 | + (NSData *)lubanCompressImage:(UIImage *)image withMask:(NSString *)maskName { 21 | 22 | double size; 23 | NSData *imageData = UIImageJPEGRepresentation(image, 1); 24 | 25 | NSLog(@"Luban-iOS image data size before compressed == %f Kb",imageData.length/1024.0); 26 | 27 | int fixelW = (int)image.size.width; 28 | int fixelH = (int)image.size.height; 29 | int thumbW = fixelW % 2 == 1 ? fixelW + 1 : fixelW; 30 | int thumbH = fixelH % 2 == 1 ? fixelH + 1 : fixelH; 31 | 32 | double scale = ((double)fixelW/(double)fixelH); 33 | 34 | if (scale <= 1 && scale > 0.5625) { 35 | 36 | if (fixelH < 1664) { 37 | if (imageData.length/1024.0 < 150) { 38 | return imageData; 39 | } 40 | size = (fixelW * fixelH) / pow(1664, 2) * 150; 41 | size = size < 60 ? 60 : size; 42 | } 43 | else if (fixelH >= 1664 && fixelH < 4990) { 44 | thumbW = fixelW / 2; 45 | thumbH = fixelH / 2; 46 | size = (thumbH * thumbW) / pow(2495, 2) * 300; 47 | size = size < 60 ? 60 : size; 48 | } 49 | else if (fixelH >= 4990 && fixelH < 10240) { 50 | thumbW = fixelW / 4; 51 | thumbH = fixelH / 4; 52 | size = (thumbW * thumbH) / pow(2560, 2) * 300; 53 | size = size < 100 ? 100 : size; 54 | } 55 | else { 56 | int multiple = fixelH / 1280 == 0 ? 1 : fixelH / 1280; 57 | thumbW = fixelW / multiple; 58 | thumbH = fixelH / multiple; 59 | size = (thumbW * thumbH) / pow(2560, 2) * 300; 60 | size = size < 100 ? 100 : size; 61 | } 62 | } 63 | else if (scale <= 0.5625 && scale > 0.5) { 64 | 65 | if (fixelH < 1280 && imageData.length/1024 < 200) { 66 | 67 | return imageData; 68 | } 69 | int multiple = fixelH / 1280 == 0 ? 1 : fixelH / 1280; 70 | thumbW = fixelW / multiple; 71 | thumbH = fixelH / multiple; 72 | size = (thumbW * thumbH) / (1440.0 * 2560.0) * 400; 73 | size = size < 100 ? 100 : size; 74 | } 75 | else { 76 | int multiple = (int)ceil(fixelH / (1280.0 / scale)); 77 | thumbW = fixelW / multiple; 78 | thumbH = fixelH / multiple; 79 | size = ((thumbW * thumbH) / (1280.0 * (1280 / scale))) * 500; 80 | size = size < 100 ? 100 : size; 81 | } 82 | return [self compressWithImage:image thumbW:thumbW thumbH:thumbH size:size withMask:maskName]; 83 | } 84 | 85 | + (NSData *)lubanCompressImage:(UIImage *)image withCustomImage:(NSString *)imageName { 86 | 87 | if (imageName) { 88 | objc_setAssociatedObject(self, &isCustomImage, @(1), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 89 | objc_setAssociatedObject(self, &customImageName, imageName, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 90 | } 91 | return [self lubanCompressImage:image withMask:nil]; 92 | } 93 | 94 | + (NSData *)compressWithImage:(UIImage *)image thumbW:(int)width thumbH:(int)height size:(double)size withMask:(NSString *)maskName { 95 | 96 | UIImage *thumbImage = [image fixOrientation]; 97 | thumbImage = [thumbImage resizeImage:image thumbWidth:width thumbHeight:height withMask:maskName]; 98 | 99 | float qualityCompress = 0.0; 100 | NSData *imageData = UIImageJPEGRepresentation(thumbImage, qualityCompress); 101 | 102 | NSUInteger lenght = imageData.length; 103 | while (lenght / 1024 > size && qualityCompress <= (1-0.06)) { 104 | 105 | qualityCompress += 0.06 ; 106 | int intCommpress = (int)(qualityCompress*100); 107 | qualityCompress = intCommpress/100.0; 108 | imageData = UIImageJPEGRepresentation(thumbImage, qualityCompress); 109 | lenght = imageData.length; 110 | thumbImage = [UIImage imageWithData:imageData]; 111 | } 112 | NSLog(@"Luban-iOS image data size after compressed ==%f kb",imageData.length/1024.0); 113 | return imageData; 114 | } 115 | 116 | // specify the size 117 | - (UIImage *)resizeImage:(UIImage *)image thumbWidth:(int)width thumbHeight:(int)height withMask:(NSString *)maskName { 118 | 119 | int outW = (int)image.size.width; 120 | int outH = (int)image.size.height; 121 | 122 | int inSampleSize = 1; 123 | 124 | if (outW > width || outH > height) { 125 | int halfW = outW / 2; 126 | int halfH = outH / 2; 127 | 128 | while ((halfH / inSampleSize) > height && (halfW / inSampleSize) > width) { 129 | inSampleSize *= 2; 130 | } 131 | } 132 | 133 | // keep one decimal 134 | int outWith = (int)((outW / (float) width)*10); 135 | int outHeiht = (int)((outH / (float) height)*10); 136 | float heightRatio = outHeiht/10.0; 137 | float widthRatio = outWith/10.0; 138 | 139 | if (heightRatio > 1 || widthRatio > 1) { 140 | 141 | inSampleSize = heightRatio > widthRatio ? heightRatio : widthRatio; 142 | } 143 | CGSize thumbSize = CGSizeMake((NSUInteger)((CGFloat)(outW/inSampleSize)), (NSUInteger)((CGFloat)(outH/inSampleSize))); 144 | 145 | UIGraphicsBeginImageContext(thumbSize); 146 | 147 | CGContextRef context = UIGraphicsGetCurrentContext(); 148 | 149 | [image drawInRect:CGRectMake(0, 0, thumbSize.width, thumbSize.height)]; 150 | if (maskName) { 151 | 152 | CGContextTranslateCTM (context, thumbSize.width / 2, thumbSize.height / 2); 153 | CGContextScaleCTM (context, 1, -1); 154 | 155 | [self drawMaskWithString:maskName context:context radius:0 angle:0 colour:[UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.5] font:[UIFont systemFontOfSize:38.0] slantAngle:(CGFloat)(M_PI/6) size:thumbSize]; 156 | } 157 | else { 158 | NSNumber *iscustom = objc_getAssociatedObject(self, &isCustomImage); 159 | BOOL isCustom = [iscustom boolValue]; 160 | if (isCustom) { 161 | NSString *imageName = objc_getAssociatedObject(self, &customImageName); 162 | UIImage *imageMask = [UIImage imageNamed:imageName]; 163 | if (imageMask) { 164 | [imageMask drawInRect:CGRectMake(0, 0, thumbSize.width, thumbSize.height)]; 165 | } 166 | } 167 | } 168 | UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext(); 169 | UIGraphicsEndImageContext(); 170 | 171 | objc_setAssociatedObject(self, &isCustomImage, @(NO), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 172 | 173 | return resultImage; 174 | } 175 | 176 | - (UIImage *)fixOrientation { 177 | 178 | // No-op if the orientation is already correct 179 | if (self.imageOrientation == UIImageOrientationUp) return self; 180 | 181 | // We need to calculate the proper transformation to make the image upright. 182 | // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored. 183 | CGAffineTransform transform = CGAffineTransformIdentity; 184 | 185 | switch (self.imageOrientation) { 186 | case UIImageOrientationDown: 187 | case UIImageOrientationDownMirrored: 188 | transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height); 189 | transform = CGAffineTransformRotate(transform, M_PI); 190 | break; 191 | 192 | case UIImageOrientationLeft: 193 | case UIImageOrientationLeftMirrored: 194 | transform = CGAffineTransformTranslate(transform, self.size.width, 0); 195 | transform = CGAffineTransformRotate(transform, M_PI_2); 196 | break; 197 | 198 | case UIImageOrientationRight: 199 | case UIImageOrientationRightMirrored: 200 | transform = CGAffineTransformTranslate(transform, 0, self.size.height); 201 | transform = CGAffineTransformRotate(transform, -M_PI_2); 202 | break; 203 | case UIImageOrientationUp: 204 | case UIImageOrientationUpMirrored: 205 | break; 206 | } 207 | 208 | switch (self.imageOrientation) { 209 | case UIImageOrientationUpMirrored: 210 | case UIImageOrientationDownMirrored: 211 | transform = CGAffineTransformTranslate(transform, self.size.width, 0); 212 | transform = CGAffineTransformScale(transform, -1, 1); 213 | break; 214 | 215 | case UIImageOrientationLeftMirrored: 216 | case UIImageOrientationRightMirrored: 217 | transform = CGAffineTransformTranslate(transform, self.size.height, 0); 218 | transform = CGAffineTransformScale(transform, -1, 1); 219 | break; 220 | case UIImageOrientationUp: 221 | case UIImageOrientationDown: 222 | case UIImageOrientationLeft: 223 | case UIImageOrientationRight: 224 | break; 225 | } 226 | 227 | // Now we draw the underlying CGImage into a new context, applying the transform 228 | // calculated above. 229 | CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height, 230 | CGImageGetBitsPerComponent(self.CGImage), 0, 231 | CGImageGetColorSpace(self.CGImage), 232 | CGImageGetBitmapInfo(self.CGImage)); 233 | CGContextConcatCTM(ctx, transform); 234 | switch (self.imageOrientation) { 235 | case UIImageOrientationLeft: 236 | case UIImageOrientationLeftMirrored: 237 | case UIImageOrientationRight: 238 | case UIImageOrientationRightMirrored: 239 | // Grr... 240 | CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage); 241 | break; 242 | 243 | default: 244 | CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage); 245 | break; 246 | } 247 | 248 | // And now we just create a new UIImage from the drawing context 249 | CGImageRef cgimg = CGBitmapContextCreateImage(ctx); 250 | UIImage *img = [UIImage imageWithCGImage:cgimg]; 251 | CGContextRelease(ctx); 252 | CGImageRelease(cgimg); 253 | return img; 254 | } 255 | 256 | - (void) drawMaskWithString:(NSString *)str context:(CGContextRef)context radius:(CGFloat)radius angle:(CGFloat)angle colour:(UIColor *)colour font:(UIFont *)font slantAngle:(CGFloat)slantAngle size:(CGSize)size{ 257 | // ******************************************************* 258 | // This draws the String str centred at the position 259 | // specified by the polar coordinates (r, theta) 260 | // i.e. the x= r * cos(theta) y= r * sin(theta) 261 | // and rotated by the angle slantAngle 262 | // ******************************************************* 263 | 264 | // Set the text attributes 265 | NSDictionary *attributes = @{NSForegroundColorAttributeName:colour, 266 | NSFontAttributeName:font}; 267 | // Save the context 268 | CGContextSaveGState(context); 269 | // Undo the inversion of the Y-axis (or the text goes backwards!) 270 | CGContextScaleCTM(context, 1, -1); 271 | // Move the origin to the centre of the text (negating the y-axis manually) 272 | CGContextTranslateCTM(context, radius * cos(angle), -(radius * sin(angle))); 273 | // Rotate the coordinate system 274 | CGContextRotateCTM(context, -slantAngle); 275 | // Calculate the width of the text 276 | CGSize offset = [str sizeWithAttributes:attributes]; 277 | // Move the origin by half the size of the text 278 | CGContextTranslateCTM (context, -offset.width / 2, -offset.height / 2); // Move the origin to the centre of the text (negating the y-axis manually) 279 | // Draw the text 280 | 281 | NSInteger width = ceil(cos(slantAngle)*offset.width); 282 | NSInteger height = ceil(sin(slantAngle)*offset.width); 283 | 284 | NSInteger row = size.height/(height+100.0); 285 | NSInteger coloum = size.width/(width+100.0)>6?:6; 286 | CGFloat xPoint = 0; 287 | CGFloat yPoint = 0; 288 | for (NSInteger index = 0; index < row*coloum; index++) { 289 | 290 | xPoint = (index%coloum) *(width+100.0)-[UIScreen mainScreen].bounds.size.width; 291 | yPoint = (index/coloum) *(height+100.0); 292 | [str drawAtPoint:CGPointMake(xPoint, yPoint) withAttributes:attributes]; 293 | xPoint += -[UIScreen mainScreen].bounds.size.width; 294 | yPoint += -[UIScreen mainScreen].bounds.size.height; 295 | [str drawAtPoint:CGPointMake(xPoint, yPoint) withAttributes:attributes]; 296 | } 297 | 298 | // Restore the context 299 | CGContextRestoreGState(context); 300 | } 301 | 302 | @end 303 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/Controller/PhotoBrowserViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PhotoBrowserViewController.h 3 | // Luban-iOS 4 | // 5 | // Created by guo on 2017/7/20. 6 | // Copyright © 2017年 guo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PhotoBrowserViewController : UIViewController 12 | 13 | @property (nonatomic, strong) UIImage *imgBrowse; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/Controller/PhotoBrowserViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // PhotoBrowserViewController.m 3 | // Luban-iOS 4 | // 5 | // Created by guo on 2017/7/20. 6 | // Copyright © 2017年 guo. All rights reserved. 7 | // 8 | 9 | #import "PhotoBrowserViewController.h" 10 | 11 | @interface PhotoBrowserViewController () 12 | 13 | @property (weak, nonatomic) IBOutlet UIImageView *imgView; 14 | 15 | @end 16 | 17 | @implementation PhotoBrowserViewController 18 | 19 | - (void)viewDidLoad { 20 | [super viewDidLoad]; 21 | 22 | [self initSubViews]; 23 | } 24 | 25 | - (void)initSubViews { 26 | 27 | [self.imgView setImage:self.imgBrowse]; 28 | } 29 | 30 | - (IBAction)tapView:(UITapGestureRecognizer *)sender { 31 | 32 | [self dismissViewControllerAnimated:YES completion:nil]; 33 | } 34 | 35 | - (void)setImgBrowse:(UIImage *)imgBrowse { 36 | 37 | _imgBrowse = imgBrowse; 38 | 39 | if (imgBrowse) { 40 | self.view.backgroundColor = [UIColor blackColor]; 41 | } 42 | else { 43 | self.view.backgroundColor = [UIColor colorWithRed:128.0/255.0 green:216.0/255.0 blue:255.0/255.0 alpha:1.0]; 44 | } 45 | } 46 | 47 | - (void)didReceiveMemoryWarning { 48 | [super didReceiveMemoryWarning]; 49 | // Dispose of any resources that can be recreated. 50 | } 51 | 52 | /* 53 | #pragma mark - Navigation 54 | 55 | // In a storyboard-based application, you will often want to do a little preparation before navigation 56 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 57 | // Get the new view controller using [segue destinationViewController]. 58 | // Pass the selected object to the new view controller. 59 | } 60 | */ 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/Controller/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // Luban-iOS 4 | // 5 | // Created by guo on 2017/7/19. 6 | // Copyright © 2017年 guo. All rights reserved. 7 | // 8 | #import "MacroFile.h" 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/Controller/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // Luban-iOS 4 | // 5 | // Created by guo on 2017/7/19. 6 | // Copyright © 2017年 guo. All rights reserved. 7 | // 8 | #import "ViewController.h" 9 | #import "ModalTransitionAnimator.h" 10 | #import 11 | #import "PhotoBrowserViewController.h" 12 | #import "UIImage+Luban_iOS_Extension_h.h" 13 | 14 | @interface ViewController () 15 | 16 | 17 | @property (nonatomic, strong) UIImage *imgCompressed; 18 | @property (nonatomic, strong) UIImagePickerController *cameraController; 19 | @property (nonatomic, strong) IBOutlet UIImageView *img_brower; 20 | 21 | @end 22 | 23 | @implementation ViewController 24 | 25 | - (void)viewDidLoad { 26 | [super viewDidLoad]; 27 | [self initDataSource]; 28 | #if TARGET_IPHONE_SIMULATOR 29 | #define SIMULATOR 1 30 | #elif TARGET_OS_IPHONE 31 | #define SIMULATOR 0 32 | #endif 33 | } 34 | 35 | - (void)initDataSource { 36 | NSData *imgData = [UIImage lubanCompressImage:[UIImage imageNamed:@"IMG_1998.JPG"] withMask:@"Luban_iOS"]; 37 | self.imgCompressed = [UIImage imageWithData:imgData]; 38 | self.img_brower.image = _imgCompressed; 39 | } 40 | 41 | - (IBAction)btnClick:(UIButton *)sender { 42 | 43 | if (SIMULATOR) { 44 | UIAlertController *alertView = [UIAlertController alertControllerWithTitle:@"提示" message:SIMULATOR_WARING preferredStyle:UIAlertControllerStyleAlert]; 45 | UIAlertAction *doneAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]; 46 | [alertView addAction:doneAction]; 47 | [self presentViewController:alertView animated:YES completion:nil]; 48 | return; 49 | } 50 | 51 | AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; 52 | if (status == AVAuthorizationStatusDenied) { 53 | UIAlertController *alertView = [UIAlertController alertControllerWithTitle:@"提示" message:SETTING_ALERT preferredStyle:UIAlertControllerStyleAlert]; 54 | UIAlertAction *doneAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]; 55 | [alertView addAction:doneAction]; 56 | [self presentViewController:alertView animated:YES completion:nil]; 57 | } 58 | else { 59 | 60 | [self presentViewController:self.cameraController animated:YES completion:nil]; 61 | } 62 | } 63 | - (IBAction)tapView:(UITapGestureRecognizer *)sender { 64 | 65 | PhotoBrowserViewController *photoBrowseVC = [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"PhotoBrowserViewController"]; 66 | photoBrowseVC.imgBrowse = self.imgCompressed; 67 | photoBrowseVC.transitioningDelegate = self; 68 | [self presentViewController:photoBrowseVC animated:YES completion:nil]; 69 | } 70 | 71 | #pragma mark - UIImagePickerControllerDelegate 72 | 73 | - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(nullable NSDictionary *)editingInfo { 74 | 75 | NSData *imgData = [UIImage lubanCompressImage:image]; 76 | self.imgCompressed = [UIImage imageWithData:imgData]; 77 | self.img_brower.image = _imgCompressed; 78 | [picker dismissViewControllerAnimated:YES completion:nil]; 79 | } 80 | - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { 81 | [picker dismissViewControllerAnimated:YES completion:nil]; 82 | } 83 | 84 | #pragma mark - UIViewControllerTransitioningDelegate 85 | 86 | - (nullable id )animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source { 87 | return [self transitionAnimatorWithPresentProperty:YES]; 88 | } 89 | 90 | - (nullable id )animationControllerForDismissedController:(UIViewController *)dismissed { 91 | return [self transitionAnimatorWithPresentProperty:NO]; 92 | } 93 | 94 | #pragma mark - Private 95 | 96 | - (ModalTransitionAnimator *)transitionAnimatorWithPresentProperty:(BOOL)isPresented { 97 | 98 | ModalTransitionAnimator *transitionAnimator = [ModalTransitionAnimator new]; 99 | transitionAnimator.m_isPresented = isPresented; 100 | transitionAnimator.m_originRect = [self.view convertRect:self.img_brower.frame toView:nil]; 101 | return transitionAnimator; 102 | } 103 | 104 | #pragma mark - Getter & Setter 105 | 106 | - (UIImagePickerController *)cameraController { 107 | 108 | if (!_cameraController) { 109 | _cameraController = [[UIImagePickerController alloc] init]; 110 | _cameraController.sourceType = UIImagePickerControllerSourceTypeCamera; 111 | _cameraController.delegate = self; 112 | _cameraController.modalPresentationStyle = UIModalPresentationFullScreen; 113 | } 114 | return _cameraController; 115 | } 116 | 117 | - (void)setImgCompressed:(UIImage *)imgCompressed { 118 | 119 | _imgCompressed = imgCompressed; 120 | 121 | if (imgCompressed) { 122 | _img_brower.backgroundColor = [UIColor blackColor]; 123 | } 124 | else { 125 | _img_brower.backgroundColor = [UIColor colorWithRed:128.0/255.0 green:216.0/255.0 blue:255.0/255.0 alpha:1.0]; 126 | } 127 | } 128 | 129 | - (void)didReceiveMemoryWarning { 130 | [super didReceiveMemoryWarning]; 131 | // Dispose of any resources that can be recreated. 132 | } 133 | 134 | 135 | @end 136 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSCameraUsageDescription 6 | 使用相机拍摄照片 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/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 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/MacroFile.h: -------------------------------------------------------------------------------- 1 | // 2 | // MacroFile.h 3 | // Luban-iOS 4 | // 5 | // Created by guo on 2017/7/21. 6 | // Copyright © 2017年 guo. All rights reserved. 7 | // 8 | 9 | #ifndef MacroFile_h 10 | #define MacroFile_h 11 | 12 | #define SIMULATOR_WARING @"模拟器不支持拍照,想测试拍照,请在真机上运行,项目里已经内置了一张名字为 IMG_1998.JPG 的图片,所展示的也是此图的压缩图,点击可以查看压缩后的大图,控制台输出了压缩前后图片的大小" 13 | #define SETTING_ALERT @"请前往手机 设置->找到Luban-iOS->打开相机权限" 14 | 15 | 16 | #endif /* MacroFile_h */ 17 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/Main.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 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/Resource/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 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/Resource/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/Resource/Assets.xcassets/ic_scqszj_sy.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "ic_scqszj_sy.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/Resource/Assets.xcassets/ic_scqszj_sy.imageset/ic_scqszj_sy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GuoZhiQiang/Luban_iOS/4554b92c20af3d87be7f6bd237adf6ce86c89a4f/Luban-iOSDemo/Luban-iOS/Resource/Assets.xcassets/ic_scqszj_sy.imageset/ic_scqszj_sy.png -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/Resource/Assets.xcassets/ic_wd_jyfk_tj.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "ic_wd_jyfk_tj@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "ic_wd_jyfk_tj@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/Resource/Assets.xcassets/ic_wd_jyfk_tj.imageset/ic_wd_jyfk_tj@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GuoZhiQiang/Luban_iOS/4554b92c20af3d87be7f6bd237adf6ce86c89a4f/Luban-iOSDemo/Luban-iOS/Resource/Assets.xcassets/ic_wd_jyfk_tj.imageset/ic_wd_jyfk_tj@2x.png -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/Resource/Assets.xcassets/ic_wd_jyfk_tj.imageset/ic_wd_jyfk_tj@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GuoZhiQiang/Luban_iOS/4554b92c20af3d87be7f6bd237adf6ce86c89a4f/Luban-iOSDemo/Luban-iOS/Resource/Assets.xcassets/ic_wd_jyfk_tj.imageset/ic_wd_jyfk_tj@3x.png -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/Resource/IMG_1998.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GuoZhiQiang/Luban_iOS/4554b92c20af3d87be7f6bd237adf6ce86c89a4f/Luban-iOSDemo/Luban-iOS/Resource/IMG_1998.JPG -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/Transition/ModalTransitionAnimator.h: -------------------------------------------------------------------------------- 1 | // 2 | // ModalTransitionAnimator.h 3 | // Luban-iOS 4 | // 5 | // Created by guo on 2017/7/21. 6 | // Copyright © 2017年 guo. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | #import 11 | 12 | @interface ModalTransitionAnimator : NSObject 13 | 14 | // default value is 0.3s 15 | @property (nonatomic, assign) CGFloat m_duration; 16 | // default value is CGRectZero 17 | @property (nonatomic, assign) CGRect m_originRect; 18 | // default value is YES 19 | @property (nonatomic, assign) BOOL m_isPresented; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/Transition/ModalTransitionAnimator.m: -------------------------------------------------------------------------------- 1 | // 2 | // ModalTransitionAnimator.m 3 | // Luban-iOS 4 | // 5 | // Created by guo on 2017/7/21. 6 | // Copyright © 2017年 guo. All rights reserved. 7 | // 8 | #import 9 | #import "ModalTransitionAnimator.h" 10 | 11 | @implementation ModalTransitionAnimator 12 | 13 | - (instancetype)init { 14 | self = [super init]; 15 | return self; 16 | } 17 | 18 | - (NSTimeInterval)transitionDuration:(id)transitionContext { 19 | return self.m_duration; 20 | } 21 | 22 | - (void)animateTransition:(id)transitionContext { 23 | 24 | UIView *transToView ; 25 | UIView *transFromView ; 26 | CGPoint endAnimationCenter ; 27 | CGPoint startAnimationCenter ; 28 | CGAffineTransform transformEnd ; 29 | CGAffineTransform transformStart ; 30 | 31 | if ([transitionContext respondsToSelector:@selector(viewForKey:)]) { 32 | transToView = [transitionContext viewForKey:UITransitionContextToViewKey]; 33 | transFromView = [transitionContext viewForKey:UITransitionContextFromViewKey]; 34 | } 35 | else { 36 | // lower ios7 37 | transToView = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey].view; 38 | transFromView = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey].view; 39 | } 40 | UIView *animationView = self.m_isPresented ? transToView : transFromView; 41 | 42 | CGFloat scaleX = CGRectGetWidth(animationView.frame) ? CGRectGetWidth(self.m_originRect) / CGRectGetWidth(animationView.frame) : 0.0; 43 | CGFloat scaleY = CGRectGetHeight(animationView.frame) ? CGRectGetHeight(self.m_originRect) / CGRectGetHeight(animationView.frame) : 0.0; 44 | 45 | CGAffineTransform transform = CGAffineTransformMakeScale(scaleX, scaleY); 46 | 47 | CGPoint originCenter = CGPointMake(CGRectGetMidX(self.m_originRect), CGRectGetMidY(self.m_originRect)); 48 | CGPoint animationCenter = CGPointMake(CGRectGetMidX(animationView.frame), CGRectGetMidY(animationView.frame)); 49 | 50 | if (self.m_isPresented) { 51 | transformEnd = CGAffineTransformIdentity; 52 | transformStart = transform; 53 | endAnimationCenter = animationCenter; 54 | startAnimationCenter = originCenter; 55 | } 56 | else { 57 | transformEnd = transform; 58 | transformStart = CGAffineTransformIdentity; 59 | endAnimationCenter = originCenter; 60 | startAnimationCenter = animationCenter; 61 | } 62 | UIView *contrainer = [transitionContext containerView]; 63 | [contrainer addSubview:transToView]; 64 | [contrainer bringSubviewToFront:animationView]; 65 | 66 | animationView.transform = transformStart; 67 | animationView.center = startAnimationCenter; 68 | 69 | [UIView animateWithDuration:self.m_duration animations:^{ 70 | 71 | animationView.transform = transformEnd; 72 | animationView.center = endAnimationCenter; 73 | } completion:^(BOOL finished) { 74 | BOOL transitionWasCancelled = [transitionContext transitionWasCancelled]; 75 | [transitionContext completeTransition:!transitionWasCancelled]; 76 | }]; 77 | } 78 | 79 | - (CGFloat)m_duration { 80 | 81 | NSNumber *duration = objc_getAssociatedObject(self, _cmd); 82 | if (duration) { 83 | return [duration floatValue]; 84 | } 85 | self.m_duration = 0.3; 86 | return 0.3; 87 | } 88 | 89 | - (void)setM_duration:(CGFloat)m_duration { 90 | 91 | SEL key = @selector(m_duration); 92 | objc_setAssociatedObject(self, key, @(m_duration), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 93 | } 94 | 95 | - (CGRect)m_originRect { 96 | NSValue *rect = objc_getAssociatedObject(self, _cmd); 97 | if (rect) { 98 | return [rect CGRectValue]; 99 | } 100 | self.m_originRect = CGRectZero; 101 | return CGRectZero; 102 | } 103 | 104 | - (void)setM_originRect:(CGRect)m_originRect { 105 | 106 | SEL key = @selector(m_originRect); 107 | objc_setAssociatedObject(self, key, [NSValue valueWithCGRect:m_originRect], OBJC_ASSOCIATION_RETAIN_NONATOMIC); 108 | } 109 | 110 | - (BOOL)m_isPresented { 111 | 112 | NSNumber *present = objc_getAssociatedObject(self, _cmd); 113 | if (present) { 114 | return [present boolValue]; 115 | } 116 | self.m_isPresented = YES; 117 | return YES; 118 | } 119 | 120 | - (void)setM_isPresented:(BOOL)m_isPresented { 121 | 122 | SEL key = @selector(m_isPresented); 123 | objc_setAssociatedObject(self, key, @(m_isPresented), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 124 | } 125 | 126 | @end 127 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOS/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Luban-iOS 4 | // 5 | // Created by guo on 2017/7/19. 6 | // Copyright © 2017年 guo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOSTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOSTests/Luban_iOSTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // Luban_iOSTests.m 3 | // Luban-iOSTests 4 | // 5 | // Created by guo on 2017/7/19. 6 | // Copyright © 2017年 guo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface Luban_iOSTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation Luban_iOSTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOSUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban-iOSUITests/Luban_iOSUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // Luban_iOSUITests.m 3 | // Luban-iOSUITests 4 | // 5 | // Created by guo on 2017/7/19. 6 | // Copyright © 2017年 guo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface Luban_iOSUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation Luban_iOSUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // 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. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban_iOS_Extension_h/UIImage+Luban_iOS_Extension_h.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Luban_iOS_Extension_h.h 3 | // Luban-iOS 4 | // 5 | // Created by guo on 2017/7/20. 6 | // Copyright © 2017年 guo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIImage (Luban_iOS_Extension_h) 12 | 13 | + (NSData *)lubanCompressImage:(UIImage *)image; 14 | + (NSData *)lubanCompressImage:(UIImage *)image withMask:(NSString *)maskName; 15 | + (NSData *)lubanCompressImage:(UIImage *)image withCustomImage:(NSString *)imageName; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Luban-iOSDemo/Luban_iOS_Extension_h/UIImage+Luban_iOS_Extension_h.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Luban_iOS_Extension_h.m 3 | // Luban-iOS 4 | // 5 | // Created by guo on 2017/7/20. 6 | // Copyright © 2017年 guo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "UIImage+Luban_iOS_Extension_h.h" 11 | 12 | @implementation UIImage (Luban_iOS_Extension_h) 13 | 14 | static char isCustomImage; 15 | static char customImageName; 16 | 17 | + (NSData *)lubanCompressImage:(UIImage *)image { 18 | return [self lubanCompressImage:image withMask:nil]; 19 | } 20 | + (NSData *)lubanCompressImage:(UIImage *)image withMask:(NSString *)maskName { 21 | 22 | double size; 23 | NSData *imageData = UIImageJPEGRepresentation(image, 1); 24 | 25 | NSLog(@"Luban-iOS image data size before compressed == %f Kb",imageData.length/1024.0); 26 | 27 | int fixelW = (int)image.size.width; 28 | int fixelH = (int)image.size.height; 29 | int thumbW = fixelW % 2 == 1 ? fixelW + 1 : fixelW; 30 | int thumbH = fixelH % 2 == 1 ? fixelH + 1 : fixelH; 31 | 32 | double scale = ((double)fixelW/fixelH); 33 | 34 | if (scale <= 1 && scale > 0.5625) { 35 | 36 | if (fixelH < 1664) { 37 | if (imageData.length/1024.0 < 150) { 38 | return imageData; 39 | } 40 | size = (fixelW * fixelH) / pow(1664, 2) * 150; 41 | size = size < 60 ? 60 : size; 42 | } 43 | else if (fixelH >= 1664 && fixelH < 4990) { 44 | thumbW = fixelW / 2; 45 | thumbH = fixelH / 2; 46 | size = (thumbH * thumbW) / pow(2495, 2) * 300; 47 | size = size < 60 ? 60 : size; 48 | } 49 | else if (fixelH >= 4990 && fixelH < 10240) { 50 | thumbW = fixelW / 4; 51 | thumbH = fixelH / 4; 52 | size = (thumbW * thumbH) / pow(2560, 2) * 300; 53 | size = size < 100 ? 100 : size; 54 | } 55 | else { 56 | int multiple = fixelH / 1280 == 0 ? 1 : fixelH / 1280; 57 | thumbW = fixelW / multiple; 58 | thumbH = fixelH / multiple; 59 | size = (thumbW * thumbH) / pow(2560, 2) * 300; 60 | size = size < 100 ? 100 : size; 61 | } 62 | } 63 | else if (scale <= 0.5625 && scale > 0.5) { 64 | 65 | if (fixelH < 1280 && imageData.length/1024 < 200) { 66 | 67 | return imageData; 68 | } 69 | int multiple = fixelH / 1280 == 0 ? 1 : fixelH / 1280; 70 | thumbW = fixelW / multiple; 71 | thumbH = fixelH / multiple; 72 | size = (thumbW * thumbH) / (1440.0 * 2560.0) * 400; 73 | size = size < 100 ? 100 : size; 74 | } 75 | else { 76 | int multiple = (int)ceil(fixelH / (1280.0 / scale)); 77 | thumbW = fixelW / multiple; 78 | thumbH = fixelH / multiple; 79 | size = ((thumbW * thumbH) / (1280.0 * (1280 / scale))) * 500; 80 | size = size < 100 ? 100 : size; 81 | } 82 | return [self compressWithImage:image thumbW:thumbW thumbH:thumbH size:size withMask:maskName]; 83 | } 84 | 85 | + (NSData *)lubanCompressImage:(UIImage *)image withCustomImage:(NSString *)imageName { 86 | 87 | if (imageName) { 88 | objc_setAssociatedObject(self, &isCustomImage, @(1), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 89 | objc_setAssociatedObject(self, &customImageName, imageName, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 90 | } 91 | return [self lubanCompressImage:image withMask:nil]; 92 | } 93 | 94 | + (NSData *)compressWithImage:(UIImage *)image thumbW:(int)width thumbH:(int)height size:(double)size withMask:(NSString *)maskName { 95 | 96 | UIImage *thumbImage = [image fixOrientation]; 97 | thumbImage = [thumbImage resizeImage:image thumbWidth:width thumbHeight:height withMask:maskName]; 98 | 99 | float qualityCompress = 0.0; 100 | NSData *imageData = UIImageJPEGRepresentation(thumbImage, qualityCompress); 101 | 102 | NSUInteger lenght = imageData.length; 103 | while (lenght / 1024 > size && qualityCompress <= (1-0.06)) { 104 | 105 | qualityCompress += 0.06 ; 106 | int intCommpress = (int)(qualityCompress*100); 107 | qualityCompress = intCommpress/100.0; 108 | imageData = UIImageJPEGRepresentation(thumbImage, qualityCompress); 109 | lenght = imageData.length; 110 | thumbImage = [UIImage imageWithData:imageData]; 111 | } 112 | NSLog(@"Luban-iOS image data size after compressed ==%f kb",imageData.length/1024.0); 113 | return imageData; 114 | } 115 | 116 | // specify the size 117 | - (UIImage *)resizeImage:(UIImage *)image thumbWidth:(int)width thumbHeight:(int)height withMask:(NSString *)maskName { 118 | 119 | int outW = (int)image.size.width; 120 | int outH = (int)image.size.height; 121 | 122 | int inSampleSize = 1; 123 | 124 | if (outW > width || outH > height) { 125 | int halfW = outW / 2; 126 | int halfH = outH / 2; 127 | 128 | while ((halfH / inSampleSize) > height && (halfW / inSampleSize) > width) { 129 | inSampleSize *= 2; 130 | } 131 | } 132 | // keep one decimal 133 | int outWith = (int)((outW / (float) width)*10); 134 | int outHeiht = (int)((outH / (float) height)*10); 135 | float heightRatio = outHeiht/10.0; 136 | float widthRatio = outWith/10.0; 137 | 138 | if (heightRatio > 1 || widthRatio > 1) { 139 | 140 | inSampleSize = heightRatio > widthRatio ? heightRatio : widthRatio; 141 | } 142 | CGSize thumbSize = CGSizeMake((NSUInteger)((CGFloat)(outW/inSampleSize)), (NSUInteger)((CGFloat)(outH/inSampleSize))); 143 | 144 | UIGraphicsBeginImageContext(thumbSize); 145 | 146 | CGContextRef context = UIGraphicsGetCurrentContext(); 147 | 148 | [image drawInRect:CGRectMake(0, 0, thumbSize.width, thumbSize.height)]; 149 | if (maskName) { 150 | 151 | CGContextTranslateCTM (context, thumbSize.width / 2, thumbSize.height / 2); 152 | CGContextScaleCTM (context, 1, -1); 153 | 154 | [self drawMaskWithString:maskName context:context radius:0 angle:0 colour:[UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.5] font:[UIFont systemFontOfSize:38.0] slantAngle:(CGFloat)(M_PI/6) size:thumbSize]; 155 | } 156 | else { 157 | NSNumber *iscustom = objc_getAssociatedObject(self, &isCustomImage); 158 | BOOL isCustom = [iscustom boolValue]; 159 | if (isCustom) { 160 | NSString *imageName = objc_getAssociatedObject(self, &customImageName); 161 | UIImage *imageMask = [UIImage imageNamed:imageName]; 162 | if (imageMask) { 163 | [imageMask drawInRect:CGRectMake(0, 0, thumbSize.width, thumbSize.height)]; 164 | } 165 | } 166 | } 167 | UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext(); 168 | UIGraphicsEndImageContext(); 169 | 170 | objc_setAssociatedObject(self, &isCustomImage, @(NO), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 171 | 172 | return resultImage; 173 | } 174 | 175 | - (UIImage *)fixOrientation { 176 | 177 | // No-op if the orientation is already correct 178 | if (self.imageOrientation == UIImageOrientationUp) return self; 179 | 180 | // We need to calculate the proper transformation to make the image upright. 181 | // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored. 182 | CGAffineTransform transform = CGAffineTransformIdentity; 183 | 184 | switch (self.imageOrientation) { 185 | case UIImageOrientationDown: 186 | case UIImageOrientationDownMirrored: 187 | transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height); 188 | transform = CGAffineTransformRotate(transform, M_PI); 189 | break; 190 | 191 | case UIImageOrientationLeft: 192 | case UIImageOrientationLeftMirrored: 193 | transform = CGAffineTransformTranslate(transform, self.size.width, 0); 194 | transform = CGAffineTransformRotate(transform, M_PI_2); 195 | break; 196 | 197 | case UIImageOrientationRight: 198 | case UIImageOrientationRightMirrored: 199 | transform = CGAffineTransformTranslate(transform, 0, self.size.height); 200 | transform = CGAffineTransformRotate(transform, -M_PI_2); 201 | break; 202 | case UIImageOrientationUp: 203 | case UIImageOrientationUpMirrored: 204 | break; 205 | } 206 | 207 | switch (self.imageOrientation) { 208 | case UIImageOrientationUpMirrored: 209 | case UIImageOrientationDownMirrored: 210 | transform = CGAffineTransformTranslate(transform, self.size.width, 0); 211 | transform = CGAffineTransformScale(transform, -1, 1); 212 | break; 213 | 214 | case UIImageOrientationLeftMirrored: 215 | case UIImageOrientationRightMirrored: 216 | transform = CGAffineTransformTranslate(transform, self.size.height, 0); 217 | transform = CGAffineTransformScale(transform, -1, 1); 218 | break; 219 | case UIImageOrientationUp: 220 | case UIImageOrientationDown: 221 | case UIImageOrientationLeft: 222 | case UIImageOrientationRight: 223 | break; 224 | } 225 | 226 | // Now we draw the underlying CGImage into a new context, applying the transform 227 | // calculated above. 228 | CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height, 229 | CGImageGetBitsPerComponent(self.CGImage), 0, 230 | CGImageGetColorSpace(self.CGImage), 231 | CGImageGetBitmapInfo(self.CGImage)); 232 | CGContextConcatCTM(ctx, transform); 233 | switch (self.imageOrientation) { 234 | case UIImageOrientationLeft: 235 | case UIImageOrientationLeftMirrored: 236 | case UIImageOrientationRight: 237 | case UIImageOrientationRightMirrored: 238 | // Grr... 239 | CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage); 240 | break; 241 | 242 | default: 243 | CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage); 244 | break; 245 | } 246 | 247 | // And now we just create a new UIImage from the drawing context 248 | CGImageRef cgimg = CGBitmapContextCreateImage(ctx); 249 | UIImage *img = [UIImage imageWithCGImage:cgimg]; 250 | CGContextRelease(ctx); 251 | CGImageRelease(cgimg); 252 | return img; 253 | } 254 | 255 | - (void) drawMaskWithString:(NSString *)str context:(CGContextRef)context radius:(CGFloat)radius angle:(CGFloat)angle colour:(UIColor *)colour font:(UIFont *)font slantAngle:(CGFloat)slantAngle size:(CGSize)size{ 256 | // ******************************************************* 257 | // This draws the String str centred at the position 258 | // specified by the polar coordinates (r, theta) 259 | // i.e. the x= r * cos(theta) y= r * sin(theta) 260 | // and rotated by the angle slantAngle 261 | // ******************************************************* 262 | 263 | // Set the text attributes 264 | NSDictionary *attributes = @{NSForegroundColorAttributeName:colour, 265 | NSFontAttributeName:font}; 266 | // Save the context 267 | CGContextSaveGState(context); 268 | // Undo the inversion of the Y-axis (or the text goes backwards!) 269 | CGContextScaleCTM(context, 1, -1); 270 | // Move the origin to the centre of the text (negating the y-axis manually) 271 | CGContextTranslateCTM(context, radius * cos(angle), -(radius * sin(angle))); 272 | // Rotate the coordinate system 273 | CGContextRotateCTM(context, -slantAngle); 274 | // Calculate the width of the text 275 | CGSize offset = [str sizeWithAttributes:attributes]; 276 | // Move the origin by half the size of the text 277 | CGContextTranslateCTM (context, -offset.width / 2, -offset.height / 2); // Move the origin to the centre of the text (negating the y-axis manually) 278 | // Draw the text 279 | 280 | NSInteger width = ceil(cos(slantAngle)*offset.width); 281 | NSInteger height = ceil(sin(slantAngle)*offset.width); 282 | 283 | NSInteger row = size.height/(height+100.0); 284 | NSInteger coloum = size.width/(width+100.0)>6?:6; 285 | CGFloat xPoint = 0; 286 | CGFloat yPoint = 0; 287 | for (NSInteger index = 0; index < row*coloum; index++) { 288 | 289 | xPoint = (index%coloum) *(width+100.0)-[UIScreen mainScreen].bounds.size.width; 290 | yPoint = (index/coloum) *(height+100.0); 291 | [str drawAtPoint:CGPointMake(xPoint, yPoint) withAttributes:attributes]; 292 | xPoint += -[UIScreen mainScreen].bounds.size.width; 293 | yPoint += -[UIScreen mainScreen].bounds.size.height; 294 | [str drawAtPoint:CGPointMake(xPoint, yPoint) withAttributes:attributes]; 295 | } 296 | 297 | // Restore the context 298 | CGContextRestoreGState(context); 299 | } 300 | 301 | @end 302 | -------------------------------------------------------------------------------- /Luban_iOS.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint Luban_iOS.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | 11 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 12 | s.name = "Luban_iOS" 13 | s.version = "1.0.6" 14 | s.summary = "An UIImage's category to compress data almost without distortion ,Thanks to Android LuBan library" 15 | s.description = <<-DESC 16 | An UIImage's category to compress data almost without distortion ,Thanks to Android LuBan library. Just pod in 2 files and no need for any setups 17 | DESC 18 | s.homepage = "https://github.com/GuoZhiQiang/Luban_iOS" 19 | 20 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 21 | 22 | s.license = { :type => "MIT", :file => "LICENSE" } 23 | 24 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 25 | 26 | s.author = { "cook" => "http://www.jianshu.com/p/eb786aefdlle" } 27 | s.social_media_url = "http://weibo.com/2639447231/profile" 28 | 29 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 30 | 31 | s.platform = :ios, "8.0" 32 | 33 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 34 | 35 | s.source = { :git => "https://github.com/GuoZhiQiang/Luban_iOS.git", :tag => "1.0.6" } 36 | 37 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 38 | 39 | s.source_files = "Luban_iOS_Extension_h/*.{h,m}" 40 | 41 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 42 | 43 | s.requires_arc = true 44 | 45 | end 46 | -------------------------------------------------------------------------------- /Luban_iOS_Extension_h/UIImage+Luban_iOS_Extension_h.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Luban_iOS_Extension_h.h 3 | // Luban-iOS 4 | // 5 | // Created by guo on 2017/7/20. 6 | // Copyright © 2017年 guo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIImage (Luban_iOS_Extension_h) 12 | 13 | + (NSData *)lubanCompressImage:(UIImage *)image; 14 | + (NSData *)lubanCompressImage:(UIImage *)image withMask:(NSString *)maskName; 15 | + (NSData *)lubanCompressImage:(UIImage *)image withCustomImage:(NSString *)imageName; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Luban_iOS_Extension_h/UIImage+Luban_iOS_Extension_h.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Luban_iOS_Extension_h.m 3 | // Luban-iOS 4 | // 5 | // Created by guo on 2017/7/20. 6 | // Copyright © 2017年 guo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "UIImage+Luban_iOS_Extension_h.h" 11 | 12 | @implementation UIImage (Luban_iOS_Extension_h) 13 | 14 | static char isCustomImage; 15 | static char customImageName; 16 | 17 | + (NSData *)lubanCompressImage:(UIImage *)image { 18 | return [self lubanCompressImage:image withMask:nil]; 19 | } 20 | + (NSData *)lubanCompressImage:(UIImage *)image withMask:(NSString *)maskName { 21 | 22 | double size; 23 | NSData *imageData = UIImageJPEGRepresentation(image, 1); 24 | 25 | NSLog(@"Luban-iOS image data size before compressed == %f Kb",imageData.length/1024.0); 26 | 27 | int fixelW = (int)image.size.width; 28 | int fixelH = (int)image.size.height; 29 | int thumbW = fixelW % 2 == 1 ? fixelW + 1 : fixelW; 30 | int thumbH = fixelH % 2 == 1 ? fixelH + 1 : fixelH; 31 | 32 | double scale = ((double)fixelW/fixelH); 33 | 34 | if (scale <= 1 && scale > 0.5625) { 35 | 36 | if (fixelH < 1664) { 37 | if (imageData.length/1024.0 < 150) { 38 | return imageData; 39 | } 40 | size = (fixelW * fixelH) / pow(1664, 2) * 150; 41 | size = size < 60 ? 60 : size; 42 | } 43 | else if (fixelH >= 1664 && fixelH < 4990) { 44 | thumbW = fixelW / 2; 45 | thumbH = fixelH / 2; 46 | size = (thumbH * thumbW) / pow(2495, 2) * 300; 47 | size = size < 60 ? 60 : size; 48 | } 49 | else if (fixelH >= 4990 && fixelH < 10240) { 50 | thumbW = fixelW / 4; 51 | thumbH = fixelH / 4; 52 | size = (thumbW * thumbH) / pow(2560, 2) * 300; 53 | size = size < 100 ? 100 : size; 54 | } 55 | else { 56 | int multiple = fixelH / 1280 == 0 ? 1 : fixelH / 1280; 57 | thumbW = fixelW / multiple; 58 | thumbH = fixelH / multiple; 59 | size = (thumbW * thumbH) / pow(2560, 2) * 300; 60 | size = size < 100 ? 100 : size; 61 | } 62 | } 63 | else if (scale <= 0.5625 && scale > 0.5) { 64 | 65 | if (fixelH < 1280 && imageData.length/1024 < 200) { 66 | 67 | return imageData; 68 | } 69 | int multiple = fixelH / 1280 == 0 ? 1 : fixelH / 1280; 70 | thumbW = fixelW / multiple; 71 | thumbH = fixelH / multiple; 72 | size = (thumbW * thumbH) / (1440.0 * 2560.0) * 400; 73 | size = size < 100 ? 100 : size; 74 | } 75 | else { 76 | int multiple = (int)ceil(fixelH / (1280.0 / scale)); 77 | thumbW = fixelW / multiple; 78 | thumbH = fixelH / multiple; 79 | size = ((thumbW * thumbH) / (1280.0 * (1280 / scale))) * 500; 80 | size = size < 100 ? 100 : size; 81 | } 82 | return [self compressWithImage:image thumbW:thumbW thumbH:thumbH size:size withMask:maskName]; 83 | } 84 | 85 | + (NSData *)lubanCompressImage:(UIImage *)image withCustomImage:(NSString *)imageName { 86 | 87 | if (imageName) { 88 | objc_setAssociatedObject(self, &isCustomImage, @(1), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 89 | objc_setAssociatedObject(self, &customImageName, imageName, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 90 | } 91 | return [self lubanCompressImage:image withMask:nil]; 92 | } 93 | 94 | + (NSData *)compressWithImage:(UIImage *)image thumbW:(int)width thumbH:(int)height size:(double)size withMask:(NSString *)maskName { 95 | 96 | UIImage *thumbImage = [image fixOrientation]; 97 | thumbImage = [thumbImage resizeImage:image thumbWidth:width thumbHeight:height withMask:maskName]; 98 | 99 | float qualityCompress = 0.0; 100 | NSData *imageData = UIImageJPEGRepresentation(thumbImage, qualityCompress); 101 | 102 | NSUInteger lenght = imageData.length; 103 | while (lenght / 1024 > size && qualityCompress <= (1-0.06)) { 104 | 105 | qualityCompress += 0.06 ; 106 | int intCommpress = (int)(qualityCompress*100); 107 | qualityCompress = intCommpress/100.0; 108 | imageData = UIImageJPEGRepresentation(thumbImage, qualityCompress); 109 | lenght = imageData.length; 110 | thumbImage = [UIImage imageWithData:imageData]; 111 | } 112 | NSLog(@"Luban-iOS image data size after compressed ==%f kb",imageData.length/1024.0); 113 | return imageData; 114 | } 115 | 116 | // specify the size 117 | - (UIImage *)resizeImage:(UIImage *)image thumbWidth:(int)width thumbHeight:(int)height withMask:(NSString *)maskName { 118 | 119 | int outW = (int)image.size.width; 120 | int outH = (int)image.size.height; 121 | 122 | int inSampleSize = 1; 123 | 124 | if (outW > width || outH > height) { 125 | int halfW = outW / 2; 126 | int halfH = outH / 2; 127 | 128 | while ((halfH / inSampleSize) > height && (halfW / inSampleSize) > width) { 129 | inSampleSize *= 2; 130 | } 131 | } 132 | // keep one decimal 133 | int outWith = (int)((outW / (float) width)*10); 134 | int outHeiht = (int)((outH / (float) height)*10); 135 | float heightRatio = outHeiht/10.0; 136 | float widthRatio = outWith/10.0; 137 | 138 | if (heightRatio > 1 || widthRatio > 1) { 139 | 140 | inSampleSize = heightRatio > widthRatio ? heightRatio : widthRatio; 141 | } 142 | CGSize thumbSize = CGSizeMake((NSUInteger)((CGFloat)(outW/inSampleSize)), (NSUInteger)((CGFloat)(outH/inSampleSize))); 143 | 144 | UIGraphicsBeginImageContext(thumbSize); 145 | 146 | CGContextRef context = UIGraphicsGetCurrentContext(); 147 | 148 | [image drawInRect:CGRectMake(0, 0, thumbSize.width, thumbSize.height)]; 149 | if (maskName) { 150 | 151 | CGContextTranslateCTM (context, thumbSize.width / 2, thumbSize.height / 2); 152 | CGContextScaleCTM (context, 1, -1); 153 | 154 | [self drawMaskWithString:maskName context:context radius:0 angle:0 colour:[UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.5] font:[UIFont systemFontOfSize:38.0] slantAngle:(CGFloat)(M_PI/6) size:thumbSize]; 155 | } 156 | else { 157 | NSNumber *iscustom = objc_getAssociatedObject(self, &isCustomImage); 158 | BOOL isCustom = [iscustom boolValue]; 159 | if (isCustom) { 160 | NSString *imageName = objc_getAssociatedObject(self, &customImageName); 161 | UIImage *imageMask = [UIImage imageNamed:imageName]; 162 | if (imageMask) { 163 | [imageMask drawInRect:CGRectMake(0, 0, thumbSize.width, thumbSize.height)]; 164 | } 165 | } 166 | } 167 | UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext(); 168 | UIGraphicsEndImageContext(); 169 | 170 | objc_setAssociatedObject(self, &isCustomImage, @(NO), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 171 | 172 | return resultImage; 173 | } 174 | 175 | - (UIImage *)fixOrientation { 176 | 177 | // No-op if the orientation is already correct 178 | if (self.imageOrientation == UIImageOrientationUp) return self; 179 | 180 | // We need to calculate the proper transformation to make the image upright. 181 | // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored. 182 | CGAffineTransform transform = CGAffineTransformIdentity; 183 | 184 | switch (self.imageOrientation) { 185 | case UIImageOrientationDown: 186 | case UIImageOrientationDownMirrored: 187 | transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height); 188 | transform = CGAffineTransformRotate(transform, M_PI); 189 | break; 190 | 191 | case UIImageOrientationLeft: 192 | case UIImageOrientationLeftMirrored: 193 | transform = CGAffineTransformTranslate(transform, self.size.width, 0); 194 | transform = CGAffineTransformRotate(transform, M_PI_2); 195 | break; 196 | 197 | case UIImageOrientationRight: 198 | case UIImageOrientationRightMirrored: 199 | transform = CGAffineTransformTranslate(transform, 0, self.size.height); 200 | transform = CGAffineTransformRotate(transform, -M_PI_2); 201 | break; 202 | case UIImageOrientationUp: 203 | case UIImageOrientationUpMirrored: 204 | break; 205 | } 206 | 207 | switch (self.imageOrientation) { 208 | case UIImageOrientationUpMirrored: 209 | case UIImageOrientationDownMirrored: 210 | transform = CGAffineTransformTranslate(transform, self.size.width, 0); 211 | transform = CGAffineTransformScale(transform, -1, 1); 212 | break; 213 | 214 | case UIImageOrientationLeftMirrored: 215 | case UIImageOrientationRightMirrored: 216 | transform = CGAffineTransformTranslate(transform, self.size.height, 0); 217 | transform = CGAffineTransformScale(transform, -1, 1); 218 | break; 219 | case UIImageOrientationUp: 220 | case UIImageOrientationDown: 221 | case UIImageOrientationLeft: 222 | case UIImageOrientationRight: 223 | break; 224 | } 225 | 226 | // Now we draw the underlying CGImage into a new context, applying the transform 227 | // calculated above. 228 | CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height, 229 | CGImageGetBitsPerComponent(self.CGImage), 0, 230 | CGImageGetColorSpace(self.CGImage), 231 | CGImageGetBitmapInfo(self.CGImage)); 232 | CGContextConcatCTM(ctx, transform); 233 | switch (self.imageOrientation) { 234 | case UIImageOrientationLeft: 235 | case UIImageOrientationLeftMirrored: 236 | case UIImageOrientationRight: 237 | case UIImageOrientationRightMirrored: 238 | // Grr... 239 | CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage); 240 | break; 241 | 242 | default: 243 | CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage); 244 | break; 245 | } 246 | 247 | // And now we just create a new UIImage from the drawing context 248 | CGImageRef cgimg = CGBitmapContextCreateImage(ctx); 249 | UIImage *img = [UIImage imageWithCGImage:cgimg]; 250 | CGContextRelease(ctx); 251 | CGImageRelease(cgimg); 252 | return img; 253 | } 254 | 255 | - (void) drawMaskWithString:(NSString *)str context:(CGContextRef)context radius:(CGFloat)radius angle:(CGFloat)angle colour:(UIColor *)colour font:(UIFont *)font slantAngle:(CGFloat)slantAngle size:(CGSize)size{ 256 | // ******************************************************* 257 | // This draws the String str centred at the position 258 | // specified by the polar coordinates (r, theta) 259 | // i.e. the x= r * cos(theta) y= r * sin(theta) 260 | // and rotated by the angle slantAngle 261 | // ******************************************************* 262 | 263 | // Set the text attributes 264 | NSDictionary *attributes = @{NSForegroundColorAttributeName:colour, 265 | NSFontAttributeName:font}; 266 | // Save the context 267 | CGContextSaveGState(context); 268 | // Undo the inversion of the Y-axis (or the text goes backwards!) 269 | CGContextScaleCTM(context, 1, -1); 270 | // Move the origin to the centre of the text (negating the y-axis manually) 271 | CGContextTranslateCTM(context, radius * cos(angle), -(radius * sin(angle))); 272 | // Rotate the coordinate system 273 | CGContextRotateCTM(context, -slantAngle); 274 | // Calculate the width of the text 275 | CGSize offset = [str sizeWithAttributes:attributes]; 276 | // Move the origin by half the size of the text 277 | CGContextTranslateCTM (context, -offset.width / 2, -offset.height / 2); // Move the origin to the centre of the text (negating the y-axis manually) 278 | // Draw the text 279 | 280 | NSInteger width = ceil(cos(slantAngle)*offset.width); 281 | NSInteger height = ceil(sin(slantAngle)*offset.width); 282 | 283 | NSInteger row = size.height/(height+100.0); 284 | NSInteger coloum = size.width/(width+100.0)>6?:6; 285 | CGFloat xPoint = 0; 286 | CGFloat yPoint = 0; 287 | for (NSInteger index = 0; index < row*coloum; index++) { 288 | 289 | xPoint = (index%coloum) *(width+100.0)-[UIScreen mainScreen].bounds.size.width; 290 | yPoint = (index/coloum) *(height+100.0); 291 | [str drawAtPoint:CGPointMake(xPoint, yPoint) withAttributes:attributes]; 292 | xPoint += -[UIScreen mainScreen].bounds.size.width; 293 | yPoint += -[UIScreen mainScreen].bounds.size.height; 294 | [str drawAtPoint:CGPointMake(xPoint, yPoint) withAttributes:attributes]; 295 | } 296 | 297 | // Restore the context 298 | CGContextRestoreGState(context); 299 | } 300 | 301 | @end 302 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # [Wiki](https://github.com/GuoZhiQiang/Luban_iOS/wiki) 3 | - 带有演示效果图 `gif`,请查看 [图文并茂](http://www.jianshu.com/p/7bb78eed7826) 4 | 5 | # 更新.Update 6 | - 现在可以添加自定义文字 **水印** 了 | Add custom text as an watermark to your image 7 | - 对应的调用方法:`[UIImage lubanCompressImage:image withMask:maskName]` 8 | 9 | # Luban-iOS 10 | - 借鉴 [Android 鲁班](https://github.com/Curzibn/Luban)压缩库,生成的 iOS 版 压缩代码 11 | 12 | ## 压缩比如下表.Compare: 13 | 14 | | 机型 | 照片获取途径 | 原图大小.before | 压缩后大小.after | 15 | |:------------- |:--------------- | :-------------| :------------- | 16 | | 6s | 拍照(竖屏) | 5.19 Mb | 86.8 Kb 17 | | 6s | 拍照(横屏) | 5.26 Mb | 29.2 Kb 18 | | 7plus | 拍照(竖屏) | 8.05 Mb | 229.1 Kb 19 | | 7plus | 拍照(横屏) | 6.34 Mb | 39.6 Kb 20 | | 6s | 截屏 | 1.05 Mb | 53.56 Kb 21 | | 7plus | 截屏 |234.7 Kb | 37.5 Kb 22 | 23 | ## 安装.Install 24 | 25 | ### Via CocoaPods 26 | - 在 `Podfile` 文件里添加`pod 'Luban_iOS'` 27 | 28 | 然后在终端运行 `pod install` 29 | 30 | >注意:如果使用 `pod search Luban_iOS` or `pod search Luban-iOS` 搜不到,那么,你需要 31 | ``` 32 | pod setup 33 | rm -rf ~/Library/Caches/Cocoapods 34 | ``` 35 | 36 | ### 使用.Usage 37 | - 下载 Demo 试玩一下,看一下输出,点一下图片看压缩后的效果大图 38 | - 导入 Category 头文件: 39 | 40 | `#import ` 41 | 42 | - 方法调用 43 | 44 | `[UIImage lubanCompressImage:image]` **or** 45 | 46 | `[UIImage lubanCompressImage:image withMask:maskName]` **or** 47 | 48 | `[UIImage lubanCompressImage:image withCustomImage:imageName]` 49 | 50 | - 参数说明 51 | 52 | ``` 53 | /* 54 | image: UIImage 对象 55 | withMask: 添加水印名字 (NSString) 56 |  withCustomImage: 水印图片名称 57 | */ 58 | ``` 59 | - 注意: 60 | 想使用自定义文字水印的请使用方法:`[UIImage lubanCompressImage:image withMask:maskName]` 61 | 添加水印时,想使用自定义图片水印的请使用方法:`[UIImage lubanCompressImage:image withCustomImage:imageName]` 62 | 63 | ### 后续添加的功能.Further 64 | - 可以自定义水印旋转角度 65 | - 可以根据一个本地路径,进行压缩并存储 66 | --------------------------------------------------------------------------------