├── .gitignore ├── LICENSE ├── PPSnapshotKit.podspec ├── PPSnapshotKit.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── PPSnapshotKit ├── Base.lproj │ └── Main.storyboard ├── Others │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-20.png │ │ │ ├── Icon-20@2x-1.png │ │ │ ├── Icon-20@2x.png │ │ │ ├── Icon-20@3x.png │ │ │ ├── Icon-29.png │ │ │ ├── Icon-29@2x-1.png │ │ │ ├── Icon-29@2x.png │ │ │ ├── Icon-29@3x.png │ │ │ ├── Icon-40.png │ │ │ ├── Icon-40@2x-1.png │ │ │ ├── Icon-40@2x.png │ │ │ ├── Icon-40@3x.png │ │ │ ├── Icon-60@2x.png │ │ │ ├── Icon-60@3x.png │ │ │ ├── Icon-76.png │ │ │ ├── Icon-76@2x.png │ │ │ ├── Icon-83.5@2x.png │ │ │ └── Logo.png │ │ └── Contents.json │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── Info.plist │ └── main.m ├── PPImageViewController.h ├── PPImageViewController.m ├── PPMainViewController.h ├── PPMainViewController.m ├── PPSnapshotViewController.h ├── PPSnapshotViewController.m └── Source │ ├── PPSnapshotHandler.h │ └── PPSnapshotHandler.m └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | # Pods/ 38 | 39 | # Carthage 40 | # 41 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 42 | # Carthage/Checkouts 43 | 44 | Carthage/Build 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 52 | 53 | fastlane/report.xml 54 | fastlane/Preview.html 55 | fastlane/screenshots/**/*.png 56 | fastlane/test_output 57 | 58 | # Code Injection 59 | # 60 | # After new code Injection tools there's a generated folder /iOSInjectionProject 61 | # https://github.com/johnno1962/injectionforxcode 62 | 63 | iOSInjectionProject/ 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Vernon 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 | -------------------------------------------------------------------------------- /PPSnapshotKit.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "PPSnapshotKit" 3 | s.version = "0.0.1" 4 | s.summary = "iOS view screenshot, including UIScrollView, UIWebView and WKWebView" 5 | s.homepage = "https://github.com/VernonVan/PPSnapshotKit" 6 | s.license = "MIT" 7 | s.author = { "VernonVan" => "https://www.jianshu.com/u/0da7f56c0a41" } 8 | s.platform = :ios 9 | s.source = { :git => "https://github.com/VernonVan/PPSnapshotKit.git", :tag => "#{s.version}" } 10 | 11 | s.source_files = "PPSnapshotKit/Source/*.{h,m}" 12 | s.frameworks = "UIKit", "WebKit" 13 | 14 | end 15 | -------------------------------------------------------------------------------- /PPSnapshotKit.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | AD1A194D20C27930000270FB /* PPSnapshotHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = AD1A194120C27930000270FB /* PPSnapshotHandler.m */; }; 11 | AD1A194E20C27930000270FB /* PPSnapshotViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AD1A194220C27930000270FB /* PPSnapshotViewController.m */; }; 12 | AD1A194F20C27930000270FB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AD1A194520C27930000270FB /* Assets.xcassets */; }; 13 | AD1A195020C27930000270FB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AD1A194620C27930000270FB /* LaunchScreen.storyboard */; }; 14 | AD1A195120C27930000270FB /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = AD1A194820C27930000270FB /* main.m */; }; 15 | AD1A195220C27930000270FB /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = AD1A194920C27930000270FB /* AppDelegate.m */; }; 16 | AD1A195420C27930000270FB /* PPMainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AD1A194B20C27930000270FB /* PPMainViewController.m */; }; 17 | AD1A195520C27930000270FB /* PPImageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AD1A194C20C27930000270FB /* PPImageViewController.m */; }; 18 | AD1A195B20C27996000270FB /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AD1A195920C27996000270FB /* Main.storyboard */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | AD1A192320C27903000270FB /* PPSnapshotKit.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PPSnapshotKit.app; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | AD1A193C20C27930000270FB /* PPMainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPMainViewController.h; sourceTree = ""; }; 24 | AD1A193D20C27930000270FB /* PPSnapshotViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPSnapshotViewController.h; sourceTree = ""; }; 25 | AD1A193E20C27930000270FB /* PPImageViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPImageViewController.h; sourceTree = ""; }; 26 | AD1A194020C27930000270FB /* PPSnapshotHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PPSnapshotHandler.h; sourceTree = ""; }; 27 | AD1A194120C27930000270FB /* PPSnapshotHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPSnapshotHandler.m; sourceTree = ""; }; 28 | AD1A194220C27930000270FB /* PPSnapshotViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPSnapshotViewController.m; sourceTree = ""; }; 29 | AD1A194420C27930000270FB /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 30 | AD1A194520C27930000270FB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 31 | AD1A194720C27930000270FB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 32 | AD1A194820C27930000270FB /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 33 | AD1A194920C27930000270FB /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 34 | AD1A194A20C27930000270FB /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 35 | AD1A194B20C27930000270FB /* PPMainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPMainViewController.m; sourceTree = ""; }; 36 | AD1A194C20C27930000270FB /* PPImageViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PPImageViewController.m; sourceTree = ""; }; 37 | AD1A195A20C27996000270FB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 38 | /* End PBXFileReference section */ 39 | 40 | /* Begin PBXFrameworksBuildPhase section */ 41 | AD1A192020C27903000270FB /* Frameworks */ = { 42 | isa = PBXFrameworksBuildPhase; 43 | buildActionMask = 2147483647; 44 | files = ( 45 | ); 46 | runOnlyForDeploymentPostprocessing = 0; 47 | }; 48 | /* End PBXFrameworksBuildPhase section */ 49 | 50 | /* Begin PBXGroup section */ 51 | AD1A191A20C27903000270FB = { 52 | isa = PBXGroup; 53 | children = ( 54 | AD1A192520C27903000270FB /* PPSnapshotKit */, 55 | AD1A192420C27903000270FB /* Products */, 56 | ); 57 | sourceTree = ""; 58 | }; 59 | AD1A192420C27903000270FB /* Products */ = { 60 | isa = PBXGroup; 61 | children = ( 62 | AD1A192320C27903000270FB /* PPSnapshotKit.app */, 63 | ); 64 | name = Products; 65 | sourceTree = ""; 66 | }; 67 | AD1A192520C27903000270FB /* PPSnapshotKit */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | AD1A193F20C27930000270FB /* Source */, 71 | AD1A195920C27996000270FB /* Main.storyboard */, 72 | AD1A193C20C27930000270FB /* PPMainViewController.h */, 73 | AD1A194B20C27930000270FB /* PPMainViewController.m */, 74 | AD1A193D20C27930000270FB /* PPSnapshotViewController.h */, 75 | AD1A194220C27930000270FB /* PPSnapshotViewController.m */, 76 | AD1A193E20C27930000270FB /* PPImageViewController.h */, 77 | AD1A194C20C27930000270FB /* PPImageViewController.m */, 78 | AD1A194320C27930000270FB /* Others */, 79 | ); 80 | path = PPSnapshotKit; 81 | sourceTree = ""; 82 | }; 83 | AD1A193F20C27930000270FB /* Source */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | AD1A194020C27930000270FB /* PPSnapshotHandler.h */, 87 | AD1A194120C27930000270FB /* PPSnapshotHandler.m */, 88 | ); 89 | path = Source; 90 | sourceTree = ""; 91 | }; 92 | AD1A194320C27930000270FB /* Others */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | AD1A194420C27930000270FB /* AppDelegate.h */, 96 | AD1A194520C27930000270FB /* Assets.xcassets */, 97 | AD1A194620C27930000270FB /* LaunchScreen.storyboard */, 98 | AD1A194820C27930000270FB /* main.m */, 99 | AD1A194920C27930000270FB /* AppDelegate.m */, 100 | AD1A194A20C27930000270FB /* Info.plist */, 101 | ); 102 | path = Others; 103 | sourceTree = ""; 104 | }; 105 | /* End PBXGroup section */ 106 | 107 | /* Begin PBXNativeTarget section */ 108 | AD1A192220C27903000270FB /* PPSnapshotKit */ = { 109 | isa = PBXNativeTarget; 110 | buildConfigurationList = AD1A193920C27904000270FB /* Build configuration list for PBXNativeTarget "PPSnapshotKit" */; 111 | buildPhases = ( 112 | AD1A191F20C27903000270FB /* Sources */, 113 | AD1A192020C27903000270FB /* Frameworks */, 114 | AD1A192120C27903000270FB /* Resources */, 115 | ); 116 | buildRules = ( 117 | ); 118 | dependencies = ( 119 | ); 120 | name = PPSnapshotKit; 121 | productName = PPSnapshotKit; 122 | productReference = AD1A192320C27903000270FB /* PPSnapshotKit.app */; 123 | productType = "com.apple.product-type.application"; 124 | }; 125 | /* End PBXNativeTarget section */ 126 | 127 | /* Begin PBXProject section */ 128 | AD1A191B20C27903000270FB /* Project object */ = { 129 | isa = PBXProject; 130 | attributes = { 131 | LastUpgradeCheck = 0940; 132 | ORGANIZATIONNAME = Vernon; 133 | TargetAttributes = { 134 | AD1A192220C27903000270FB = { 135 | CreatedOnToolsVersion = 9.4; 136 | }; 137 | }; 138 | }; 139 | buildConfigurationList = AD1A191E20C27903000270FB /* Build configuration list for PBXProject "PPSnapshotKit" */; 140 | compatibilityVersion = "Xcode 9.3"; 141 | developmentRegion = en; 142 | hasScannedForEncodings = 0; 143 | knownRegions = ( 144 | en, 145 | Base, 146 | ); 147 | mainGroup = AD1A191A20C27903000270FB; 148 | productRefGroup = AD1A192420C27903000270FB /* Products */; 149 | projectDirPath = ""; 150 | projectRoot = ""; 151 | targets = ( 152 | AD1A192220C27903000270FB /* PPSnapshotKit */, 153 | ); 154 | }; 155 | /* End PBXProject section */ 156 | 157 | /* Begin PBXResourcesBuildPhase section */ 158 | AD1A192120C27903000270FB /* Resources */ = { 159 | isa = PBXResourcesBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | AD1A194F20C27930000270FB /* Assets.xcassets in Resources */, 163 | AD1A195020C27930000270FB /* LaunchScreen.storyboard in Resources */, 164 | AD1A195B20C27996000270FB /* Main.storyboard in Resources */, 165 | ); 166 | runOnlyForDeploymentPostprocessing = 0; 167 | }; 168 | /* End PBXResourcesBuildPhase section */ 169 | 170 | /* Begin PBXSourcesBuildPhase section */ 171 | AD1A191F20C27903000270FB /* Sources */ = { 172 | isa = PBXSourcesBuildPhase; 173 | buildActionMask = 2147483647; 174 | files = ( 175 | AD1A195220C27930000270FB /* AppDelegate.m in Sources */, 176 | AD1A194E20C27930000270FB /* PPSnapshotViewController.m in Sources */, 177 | AD1A195420C27930000270FB /* PPMainViewController.m in Sources */, 178 | AD1A195120C27930000270FB /* main.m in Sources */, 179 | AD1A195520C27930000270FB /* PPImageViewController.m in Sources */, 180 | AD1A194D20C27930000270FB /* PPSnapshotHandler.m in Sources */, 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | }; 184 | /* End PBXSourcesBuildPhase section */ 185 | 186 | /* Begin PBXVariantGroup section */ 187 | AD1A194620C27930000270FB /* LaunchScreen.storyboard */ = { 188 | isa = PBXVariantGroup; 189 | children = ( 190 | AD1A194720C27930000270FB /* Base */, 191 | ); 192 | name = LaunchScreen.storyboard; 193 | sourceTree = ""; 194 | }; 195 | AD1A195920C27996000270FB /* Main.storyboard */ = { 196 | isa = PBXVariantGroup; 197 | children = ( 198 | AD1A195A20C27996000270FB /* Base */, 199 | ); 200 | name = Main.storyboard; 201 | sourceTree = ""; 202 | }; 203 | /* End PBXVariantGroup section */ 204 | 205 | /* Begin XCBuildConfiguration section */ 206 | AD1A193720C27904000270FB /* Debug */ = { 207 | isa = XCBuildConfiguration; 208 | buildSettings = { 209 | ALWAYS_SEARCH_USER_PATHS = NO; 210 | CLANG_ANALYZER_NONNULL = YES; 211 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 212 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 213 | CLANG_CXX_LIBRARY = "libc++"; 214 | CLANG_ENABLE_MODULES = YES; 215 | CLANG_ENABLE_OBJC_ARC = YES; 216 | CLANG_ENABLE_OBJC_WEAK = YES; 217 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 218 | CLANG_WARN_BOOL_CONVERSION = YES; 219 | CLANG_WARN_COMMA = YES; 220 | CLANG_WARN_CONSTANT_CONVERSION = YES; 221 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 222 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 223 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 224 | CLANG_WARN_EMPTY_BODY = YES; 225 | CLANG_WARN_ENUM_CONVERSION = YES; 226 | CLANG_WARN_INFINITE_RECURSION = YES; 227 | CLANG_WARN_INT_CONVERSION = YES; 228 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 229 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 230 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 231 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 232 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 233 | CLANG_WARN_STRICT_PROTOTYPES = YES; 234 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 235 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 236 | CLANG_WARN_UNREACHABLE_CODE = YES; 237 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 238 | CODE_SIGN_IDENTITY = "iPhone Developer"; 239 | COPY_PHASE_STRIP = NO; 240 | DEBUG_INFORMATION_FORMAT = dwarf; 241 | ENABLE_STRICT_OBJC_MSGSEND = YES; 242 | ENABLE_TESTABILITY = YES; 243 | GCC_C_LANGUAGE_STANDARD = gnu11; 244 | GCC_DYNAMIC_NO_PIC = NO; 245 | GCC_NO_COMMON_BLOCKS = YES; 246 | GCC_OPTIMIZATION_LEVEL = 0; 247 | GCC_PREPROCESSOR_DEFINITIONS = ( 248 | "DEBUG=1", 249 | "$(inherited)", 250 | ); 251 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 252 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 253 | GCC_WARN_UNDECLARED_SELECTOR = YES; 254 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 255 | GCC_WARN_UNUSED_FUNCTION = YES; 256 | GCC_WARN_UNUSED_VARIABLE = YES; 257 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 258 | MTL_ENABLE_DEBUG_INFO = YES; 259 | ONLY_ACTIVE_ARCH = YES; 260 | SDKROOT = iphoneos; 261 | }; 262 | name = Debug; 263 | }; 264 | AD1A193820C27904000270FB /* Release */ = { 265 | isa = XCBuildConfiguration; 266 | buildSettings = { 267 | ALWAYS_SEARCH_USER_PATHS = NO; 268 | CLANG_ANALYZER_NONNULL = YES; 269 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 271 | CLANG_CXX_LIBRARY = "libc++"; 272 | CLANG_ENABLE_MODULES = YES; 273 | CLANG_ENABLE_OBJC_ARC = YES; 274 | CLANG_ENABLE_OBJC_WEAK = YES; 275 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 276 | CLANG_WARN_BOOL_CONVERSION = YES; 277 | CLANG_WARN_COMMA = YES; 278 | CLANG_WARN_CONSTANT_CONVERSION = YES; 279 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 280 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 281 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 282 | CLANG_WARN_EMPTY_BODY = YES; 283 | CLANG_WARN_ENUM_CONVERSION = YES; 284 | CLANG_WARN_INFINITE_RECURSION = YES; 285 | CLANG_WARN_INT_CONVERSION = YES; 286 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 287 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 288 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 289 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 290 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 291 | CLANG_WARN_STRICT_PROTOTYPES = YES; 292 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 293 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 294 | CLANG_WARN_UNREACHABLE_CODE = YES; 295 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 296 | CODE_SIGN_IDENTITY = "iPhone Developer"; 297 | COPY_PHASE_STRIP = NO; 298 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 299 | ENABLE_NS_ASSERTIONS = NO; 300 | ENABLE_STRICT_OBJC_MSGSEND = YES; 301 | GCC_C_LANGUAGE_STANDARD = gnu11; 302 | GCC_NO_COMMON_BLOCKS = YES; 303 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 304 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 305 | GCC_WARN_UNDECLARED_SELECTOR = YES; 306 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 307 | GCC_WARN_UNUSED_FUNCTION = YES; 308 | GCC_WARN_UNUSED_VARIABLE = YES; 309 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 310 | MTL_ENABLE_DEBUG_INFO = NO; 311 | SDKROOT = iphoneos; 312 | VALIDATE_PRODUCT = YES; 313 | }; 314 | name = Release; 315 | }; 316 | AD1A193A20C27904000270FB /* Debug */ = { 317 | isa = XCBuildConfiguration; 318 | buildSettings = { 319 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 320 | CODE_SIGN_STYLE = Automatic; 321 | DEVELOPMENT_TEAM = R6964LXMCM; 322 | INFOPLIST_FILE = "$(SRCROOT)/PPSnapshotKit/Others/Info.plist"; 323 | LD_RUNPATH_SEARCH_PATHS = ( 324 | "$(inherited)", 325 | "@executable_path/Frameworks", 326 | ); 327 | PRODUCT_BUNDLE_IDENTIFIER = cn.edu.scnu.PPSnapshotKit; 328 | PRODUCT_NAME = "$(TARGET_NAME)"; 329 | TARGETED_DEVICE_FAMILY = "1,2"; 330 | }; 331 | name = Debug; 332 | }; 333 | AD1A193B20C27904000270FB /* Release */ = { 334 | isa = XCBuildConfiguration; 335 | buildSettings = { 336 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 337 | CODE_SIGN_STYLE = Automatic; 338 | DEVELOPMENT_TEAM = R6964LXMCM; 339 | INFOPLIST_FILE = "$(SRCROOT)/PPSnapshotKit/Others/Info.plist"; 340 | LD_RUNPATH_SEARCH_PATHS = ( 341 | "$(inherited)", 342 | "@executable_path/Frameworks", 343 | ); 344 | PRODUCT_BUNDLE_IDENTIFIER = cn.edu.scnu.PPSnapshotKit; 345 | PRODUCT_NAME = "$(TARGET_NAME)"; 346 | TARGETED_DEVICE_FAMILY = "1,2"; 347 | }; 348 | name = Release; 349 | }; 350 | /* End XCBuildConfiguration section */ 351 | 352 | /* Begin XCConfigurationList section */ 353 | AD1A191E20C27903000270FB /* Build configuration list for PBXProject "PPSnapshotKit" */ = { 354 | isa = XCConfigurationList; 355 | buildConfigurations = ( 356 | AD1A193720C27904000270FB /* Debug */, 357 | AD1A193820C27904000270FB /* Release */, 358 | ); 359 | defaultConfigurationIsVisible = 0; 360 | defaultConfigurationName = Release; 361 | }; 362 | AD1A193920C27904000270FB /* Build configuration list for PBXNativeTarget "PPSnapshotKit" */ = { 363 | isa = XCConfigurationList; 364 | buildConfigurations = ( 365 | AD1A193A20C27904000270FB /* Debug */, 366 | AD1A193B20C27904000270FB /* Release */, 367 | ); 368 | defaultConfigurationIsVisible = 0; 369 | defaultConfigurationName = Release; 370 | }; 371 | /* End XCConfigurationList section */ 372 | }; 373 | rootObject = AD1A191B20C27903000270FB /* Project object */; 374 | } 375 | -------------------------------------------------------------------------------- /PPSnapshotKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PPSnapshotKit/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 | 28 | 35 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 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 | -------------------------------------------------------------------------------- /PPSnapshotKit/Others/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // PPWebCapture 4 | // 5 | // Created by Vernon on 2018/5/28. 6 | // Copyright © 2018年 Vernon. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /PPSnapshotKit/Others/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // PPWebCapture 4 | // 5 | // Created by Vernon on 2018/5/28. 6 | // Copyright © 2018年 Vernon. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-29@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-29@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-40@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-40@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-60@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-60@3x.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "size" : "20x20", 53 | "idiom" : "ipad", 54 | "filename" : "Icon-20.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-20@2x-1.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "29x29", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-29.png", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-29@2x-1.png", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "40x40", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-40.png", 79 | "scale" : "1x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-40@2x-1.png", 85 | "scale" : "2x" 86 | }, 87 | { 88 | "size" : "76x76", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-76.png", 91 | "scale" : "1x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-76@2x.png", 97 | "scale" : "2x" 98 | }, 99 | { 100 | "size" : "83.5x83.5", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-83.5@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "1024x1024", 107 | "idiom" : "ios-marketing", 108 | "filename" : "Logo.png", 109 | "scale" : "1x" 110 | } 111 | ], 112 | "info" : { 113 | "version" : 1, 114 | "author" : "xcode" 115 | } 116 | } -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VernonVan/PPSnapshotKit/f8cd58cebe8a35cd5dc153dfcf9ef319bf9eb97a/PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-20.png -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-20@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VernonVan/PPSnapshotKit/f8cd58cebe8a35cd5dc153dfcf9ef319bf9eb97a/PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-20@2x-1.png -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VernonVan/PPSnapshotKit/f8cd58cebe8a35cd5dc153dfcf9ef319bf9eb97a/PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-20@2x.png -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VernonVan/PPSnapshotKit/f8cd58cebe8a35cd5dc153dfcf9ef319bf9eb97a/PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-20@3x.png -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VernonVan/PPSnapshotKit/f8cd58cebe8a35cd5dc153dfcf9ef319bf9eb97a/PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-29.png -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-29@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VernonVan/PPSnapshotKit/f8cd58cebe8a35cd5dc153dfcf9ef319bf9eb97a/PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-29@2x-1.png -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VernonVan/PPSnapshotKit/f8cd58cebe8a35cd5dc153dfcf9ef319bf9eb97a/PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VernonVan/PPSnapshotKit/f8cd58cebe8a35cd5dc153dfcf9ef319bf9eb97a/PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VernonVan/PPSnapshotKit/f8cd58cebe8a35cd5dc153dfcf9ef319bf9eb97a/PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-40.png -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-40@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VernonVan/PPSnapshotKit/f8cd58cebe8a35cd5dc153dfcf9ef319bf9eb97a/PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-40@2x-1.png -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VernonVan/PPSnapshotKit/f8cd58cebe8a35cd5dc153dfcf9ef319bf9eb97a/PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VernonVan/PPSnapshotKit/f8cd58cebe8a35cd5dc153dfcf9ef319bf9eb97a/PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VernonVan/PPSnapshotKit/f8cd58cebe8a35cd5dc153dfcf9ef319bf9eb97a/PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VernonVan/PPSnapshotKit/f8cd58cebe8a35cd5dc153dfcf9ef319bf9eb97a/PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VernonVan/PPSnapshotKit/f8cd58cebe8a35cd5dc153dfcf9ef319bf9eb97a/PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VernonVan/PPSnapshotKit/f8cd58cebe8a35cd5dc153dfcf9ef319bf9eb97a/PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VernonVan/PPSnapshotKit/f8cd58cebe8a35cd5dc153dfcf9ef319bf9eb97a/PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VernonVan/PPSnapshotKit/f8cd58cebe8a35cd5dc153dfcf9ef319bf9eb97a/PPSnapshotKit/Others/Assets.xcassets/AppIcon.appiconset/Logo.png -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /PPSnapshotKit/Others/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 | -------------------------------------------------------------------------------- /PPSnapshotKit/Others/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /PPSnapshotKit/Others/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // PPWebCapture 4 | // 5 | // Created by Vernon on 2018/5/28. 6 | // Copyright © 2018年 Vernon. 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 | -------------------------------------------------------------------------------- /PPSnapshotKit/PPImageViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PPImageViewController.h 3 | // PPWebCapture 4 | // 5 | // Created by Vernon on 2018/6/1. 6 | // Copyright © 2018年 Vernon. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PPImageViewController : UIViewController 12 | 13 | @property (nonatomic, strong) UIImage *image; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /PPSnapshotKit/PPImageViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // PPImageViewController.m 3 | // PPWebCapture 4 | // 5 | // Created by Vernon on 2018/6/1. 6 | // Copyright © 2018年 Vernon. All rights reserved. 7 | // 8 | 9 | #import "PPImageViewController.h" 10 | 11 | @interface PPImageViewController () 12 | @property (nonatomic, strong) UIScrollView *scrollView; 13 | @property (nonatomic, strong) UIImageView *imageView; 14 | @end 15 | 16 | @implementation PPImageViewController 17 | 18 | - (void)viewDidLoad 19 | { 20 | [super viewDidLoad]; 21 | 22 | self.imageView = [[UIImageView alloc] init]; 23 | self.imageView.image = self.image; 24 | self.imageView.contentMode = UIViewContentModeScaleAspectFit; 25 | 26 | self.scrollView = [[UIScrollView alloc] init]; 27 | [self.scrollView addSubview:self.imageView]; 28 | [self.view addSubview:self.scrollView]; 29 | } 30 | 31 | - (void)viewDidAppear:(BOOL)animated 32 | { 33 | [super viewDidAppear:animated]; 34 | 35 | if (self.image.size.height == UIScreen.mainScreen.bounds.size.height) { 36 | self.scrollView.contentOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.frame.size.height); 37 | } 38 | } 39 | 40 | - (void)viewDidLayoutSubviews 41 | { 42 | [super viewDidLayoutSubviews]; 43 | 44 | CGFloat height = self.image.size.height; 45 | CGFloat width = self.image.size.width; 46 | 47 | self.scrollView.frame = self.view.bounds; 48 | self.scrollView.contentSize = CGSizeMake(width, height); 49 | 50 | self.imageView.frame = CGRectMake(0, 0, width, height); 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /PPSnapshotKit/PPMainViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PPMainViewController.h 3 | // PPWebCapture 4 | // 5 | // Created by Vernon on 2018/5/28. 6 | // Copyright © 2018年 Vernon. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PPMainViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /PPSnapshotKit/PPMainViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // PPMainViewController.m 3 | // PPWebCapture 4 | // 5 | // Created by Vernon on 2018/5/28. 6 | // Copyright © 2018年 Vernon. All rights reserved. 7 | // 8 | 9 | #import "PPMainViewController.h" 10 | #import "PPSnapshotViewController.h" 11 | 12 | @interface PPMainViewController () 13 | 14 | @end 15 | 16 | @implementation PPMainViewController 17 | 18 | - (void)viewDidLoad 19 | { 20 | [super viewDidLoad]; 21 | } 22 | 23 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 24 | { 25 | [super prepareForSegue:segue sender:sender]; 26 | 27 | PPSnapshotViewController *snapshotViewController = segue.destinationViewController; 28 | if ([segue.identifier isEqualToString:@"scrollView"]) { 29 | snapshotViewController.type = PPSnapshotViewControllerTypeScrollView; 30 | } else if ([segue.identifier isEqualToString:@"wkwebView"]) { 31 | snapshotViewController.type = PPSnapshotViewControllerTypeWKWebView; 32 | } else if ([segue.identifier isEqualToString:@"uiwebView"]) { 33 | snapshotViewController.type = PPSnapshotViewControllerTypeUIWebView; 34 | } 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /PPSnapshotKit/PPSnapshotViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PPSnapshotViewController.h 3 | // PPWebCapture 4 | // 5 | // Created by Vernon on 2018/6/1. 6 | // Copyright © 2018年 Vernon. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef NS_ENUM (NSUInteger, PPSnapshotViewControllerType) { 12 | PPSnapshotViewControllerTypeScrollView, 13 | PPSnapshotViewControllerTypeWKWebView, 14 | PPSnapshotViewControllerTypeUIWebView 15 | }; 16 | 17 | @interface PPSnapshotViewController : UIViewController 18 | 19 | @property (nonatomic, assign) PPSnapshotViewControllerType type; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /PPSnapshotKit/PPSnapshotViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // PPSnapshotViewController.m 3 | // PPWebCapture 4 | // 5 | // Created by Vernon on 2018/6/1. 6 | // Copyright © 2018年 Vernon. All rights reserved. 7 | // 8 | 9 | #import "PPSnapshotViewController.h" 10 | #import 11 | #import "PPImageViewController.h" 12 | #import "PPSnapshotHandler.h" 13 | 14 | @interface PPSnapshotViewController () { 15 | UIImage *_snapshotImage; 16 | } 17 | @property (nonatomic, strong) UITableView *tableView; 18 | @property (nonatomic, strong) UIWebView *uiWebView; 19 | @property (nonatomic, strong) WKWebView *wkWebView; 20 | @end 21 | 22 | @implementation PPSnapshotViewController 23 | 24 | - (void)viewDidLoad 25 | { 26 | [super viewDidLoad]; 27 | 28 | switch (self.type) { 29 | case PPSnapshotViewControllerTypeScrollView: 30 | [self.view addSubview:self.tableView]; 31 | break; 32 | case PPSnapshotViewControllerTypeWKWebView: 33 | [self.wkWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.jianshu.com/"]]]; 34 | break; 35 | case PPSnapshotViewControllerTypeUIWebView: 36 | [self.uiWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.jianshu.com/"]]]; 37 | break; 38 | default: 39 | break; 40 | } 41 | } 42 | 43 | - (UITableView *)tableView 44 | { 45 | if (!_tableView) { 46 | _tableView = [[UITableView alloc] initWithFrame:self.view.bounds]; 47 | _tableView.dataSource = self; 48 | [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"]; 49 | } 50 | return _tableView; 51 | } 52 | 53 | - (UIWebView *)uiWebView 54 | { 55 | if (!_uiWebView) { 56 | _uiWebView = [[UIWebView alloc] initWithFrame:self.view.bounds]; 57 | [self.view addSubview:_uiWebView]; 58 | } 59 | return _uiWebView; 60 | } 61 | 62 | - (WKWebView *)wkWebView 63 | { 64 | if (!_wkWebView) { 65 | _wkWebView = [[WKWebView alloc] initWithFrame:self.view.bounds]; 66 | [self.view addSubview:_wkWebView]; 67 | } 68 | return _wkWebView; 69 | } 70 | 71 | - (IBAction)captureAction:(id)sender 72 | { 73 | PPSnapshotHandler.defaultHandler.delegate = self; 74 | 75 | switch (self.type) { 76 | case PPSnapshotViewControllerTypeScrollView: 77 | [PPSnapshotHandler.defaultHandler snapshotForView:self.tableView]; 78 | break; 79 | case PPSnapshotViewControllerTypeWKWebView: 80 | [PPSnapshotHandler.defaultHandler snapshotForView:self.wkWebView]; 81 | break; 82 | case PPSnapshotViewControllerTypeUIWebView: 83 | [PPSnapshotHandler.defaultHandler snapshotForView:self.uiWebView]; 84 | break; 85 | default: 86 | break; 87 | } 88 | } 89 | 90 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 91 | { 92 | [super prepareForSegue:segue sender:sender]; 93 | 94 | PPImageViewController *imageViewController = segue.destinationViewController; 95 | imageViewController.image = _snapshotImage; 96 | } 97 | 98 | #pragma mark - PPSnapshotHandlerDelegate 99 | 100 | - (void)snapshotHandler:(PPSnapshotHandler *)snapshotHandler didFinish:(UIImage *)captureImage forView:(UIView *)view 101 | { 102 | PPSnapshotHandler.defaultHandler.delegate = nil; 103 | 104 | _snapshotImage = captureImage; 105 | [self performSegueWithIdentifier:@"showImage" sender:nil]; 106 | } 107 | 108 | #pragma mark - UITableView 109 | 110 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 111 | { 112 | return 40; 113 | } 114 | 115 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 116 | { 117 | UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath]; 118 | cell.textLabel.text = @"喵喵喵"; 119 | return cell; 120 | } 121 | 122 | @end 123 | -------------------------------------------------------------------------------- /PPSnapshotKit/Source/PPSnapshotHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // PPSnapshotHandler.h 3 | // PPWebCapture 4 | // 5 | // Created by Vernon on 2018/5/30. 6 | // Copyright © 2018年 Vernon. All rights reserved. 7 | // 8 | 9 | #import 10 | @class PPSnapshotHandler; 11 | 12 | @protocol PPSnapshotHandlerDelegate 13 | 14 | @optional 15 | 16 | - (void)snapshotHandler:(PPSnapshotHandler *)snapshotHandler didFinish:(UIImage *)captureImage forView:(UIView *)view; 17 | 18 | @end 19 | 20 | @interface PPSnapshotHandler : NSObject 21 | 22 | + (instancetype)defaultHandler; 23 | 24 | @property (nonatomic, weak) id delegate; 25 | 26 | - (void)snapshotForView:(__kindof UIView *)view; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /PPSnapshotKit/Source/PPSnapshotHandler.m: -------------------------------------------------------------------------------- 1 | // 2 | // PPSnapshotHandler.h 3 | // PPWebCapture 4 | // 5 | // Created by Vernon on 2018/5/30. 6 | // Copyright © 2018年 Vernon. All rights reserved. 7 | // 8 | 9 | #import "PPSnapshotHandler.h" 10 | #import 11 | 12 | #define DELAY_TIME_DRAW 0.1 13 | 14 | @interface PPSnapshotHandler () { 15 | BOOL _isCapturing; 16 | UIView *_captureView; 17 | } 18 | @end 19 | 20 | @implementation PPSnapshotHandler 21 | 22 | + (instancetype)defaultHandler 23 | { 24 | static dispatch_once_t onceToken; 25 | static PPSnapshotHandler *defaultHandler = nil; 26 | dispatch_once(&onceToken, ^{ 27 | defaultHandler = [[PPSnapshotHandler alloc] init]; 28 | }); 29 | return defaultHandler; 30 | } 31 | 32 | #pragma mark - public method 33 | 34 | - (void)snapshotForView:(__kindof UIView *)view 35 | { 36 | if (!view || _isCapturing) { 37 | return; 38 | } 39 | 40 | _captureView = view; 41 | 42 | if ([view isKindOfClass:[UIScrollView class]]) { 43 | [self snapshotForScrollView:(UIScrollView *)view]; 44 | } else if ([view isKindOfClass:[UIWebView class]]) { 45 | UIWebView *webView = (UIWebView *)view; 46 | [self snapshotForScrollView:webView.scrollView]; 47 | } else if ([view isKindOfClass:[WKWebView class]]) { 48 | [self snapshotForWKWebView:(WKWebView *)view]; 49 | } 50 | } 51 | 52 | #pragma mark - WKWebView 53 | 54 | - (void)snapshotForWKWebView:(WKWebView *)webView 55 | { 56 | UIView *snapshotView = [webView snapshotViewAfterScreenUpdates:YES]; 57 | snapshotView.frame = webView.frame; 58 | [webView.superview addSubview:snapshotView]; 59 | 60 | CGPoint currentOffset = webView.scrollView.contentOffset; 61 | CGRect currentFrame = webView.frame; 62 | UIView *currentSuperView = webView.superview; 63 | NSUInteger currentIndex = [webView.superview.subviews indexOfObject:webView]; 64 | 65 | UIView *containerView = [[UIView alloc] initWithFrame:webView.bounds]; 66 | [webView removeFromSuperview]; 67 | [containerView addSubview:webView]; 68 | 69 | CGSize totalSize = webView.scrollView.contentSize; 70 | NSInteger page = ceil(totalSize.height / containerView.bounds.size.height); 71 | 72 | webView.scrollView.contentOffset = CGPointZero; 73 | webView.frame = CGRectMake(0, 0, containerView.bounds.size.width, webView.scrollView.contentSize.height); 74 | 75 | UIGraphicsBeginImageContextWithOptions(totalSize, YES, UIScreen.mainScreen.scale); 76 | [self drawContentPage:containerView webView:webView index:0 maxIndex:page completion:^{ 77 | UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext(); 78 | UIGraphicsEndImageContext(); 79 | 80 | [webView removeFromSuperview]; 81 | [currentSuperView insertSubview:webView atIndex:currentIndex]; 82 | webView.frame = currentFrame; 83 | webView.scrollView.contentOffset = currentOffset; 84 | 85 | [snapshotView removeFromSuperview]; 86 | 87 | self->_isCapturing = NO; 88 | 89 | if (self.delegate && [self.delegate respondsToSelector:@selector(snapshotHandler:didFinish:forView:)]) { 90 | [self.delegate snapshotHandler:self didFinish:snapshotImage forView:self->_captureView]; 91 | } 92 | }]; 93 | } 94 | 95 | - (void)drawContentPage:(UIView *)targetView webView:(WKWebView *)webView index:(NSInteger)index maxIndex:(NSInteger)maxIndex completion:(dispatch_block_t)completion 96 | { 97 | CGRect splitFrame = CGRectMake(0, index * CGRectGetHeight(targetView.bounds), targetView.bounds.size.width, targetView.frame.size.height); 98 | CGRect myFrame = webView.frame; 99 | myFrame.origin.y = -(index * targetView.frame.size.height); 100 | webView.frame = myFrame; 101 | 102 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(DELAY_TIME_DRAW * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 103 | [targetView drawViewHierarchyInRect:splitFrame afterScreenUpdates:YES]; 104 | 105 | if (index < maxIndex) { 106 | [self drawContentPage:targetView webView:webView index:index + 1 maxIndex:maxIndex completion:completion]; 107 | } else { 108 | completion(); 109 | } 110 | }); 111 | } 112 | 113 | #pragma mark - UIScrollView 114 | 115 | - (void)snapshotForScrollView:(UIScrollView *)scrollView 116 | { 117 | CGPoint currentOffset = scrollView.contentOffset; 118 | CGRect currentFrame = scrollView.frame; 119 | 120 | scrollView.contentOffset = CGPointZero; 121 | scrollView.frame = CGRectMake(0, 0, scrollView.contentSize.width, scrollView.contentSize.height); 122 | 123 | UIGraphicsBeginImageContextWithOptions(scrollView.contentSize, YES, UIScreen.mainScreen.scale); 124 | [scrollView.layer renderInContext:UIGraphicsGetCurrentContext()]; 125 | UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext(); 126 | UIGraphicsEndImageContext(); 127 | 128 | scrollView.contentOffset = currentOffset; 129 | scrollView.frame = currentFrame; 130 | 131 | if (self.delegate && [self.delegate respondsToSelector:@selector(snapshotHandler:didFinish:forView:)]) { 132 | [self.delegate snapshotHandler:self didFinish:snapshotImage forView:_captureView]; 133 | } 134 | } 135 | 136 | @end 137 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PPSnapshotKit 2 | 对应的教程在这儿:[iOS 截图的那些事儿](https://www.jianshu.com/p/3327ffeb7fa5) 3 | 4 | ![演示](https://upload-images.jianshu.io/upload_images/698554-219189e2ec87b171.GIF?imageMogr2/auto-orient/strip) 5 | 6 | 7 | 8 | ### 安装 9 | 10 | 1. 手动导入: 11 | 12 | [下载](https://github.com/VernonVan/PPSnapshotKit/archive/master.zip) 最新的代码并解压,将 PPSnapshotKit->Source 中的文件拖入您的项目中即可 13 | 14 | 15 | 16 | 2. CocoaPods 安装: 17 | 18 | 修改你的 `PodFile` 并添加以下依赖项: 19 | 20 | ``` 21 | pod 'PPSnapshotKit' 22 | ``` 23 | 24 | 25 | 26 | ### 使用 27 | 28 | 直接在需要截图的 View 上调用: 29 | 30 | ```objective-c 31 | PPSnapshotHandler.defaultHandler.delegate = self; 32 | [PPSnapshotHandler.defaultHandler snapshotForView:viewToCapture]; 33 | ``` 34 | 35 | 截图完成得到回调可以获取到 `UIImage` 类型的截图: 36 | 37 | ``` 38 | snapshotHandler:didFinish:forView: 39 | ``` 40 | 41 | 42 | 43 | Enjoy it ~ --------------------------------------------------------------------------------