├── .gitignore ├── .travis.yml ├── Demo ├── YYImageDemo.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata └── YYImageDemo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── EmoticonWeibo.bundle │ └── com.sina.default │ │ ├── d_aini@2x.png │ │ ├── d_aini@3x.png │ │ ├── d_baibai@2x.png │ │ ├── d_baibai@3x.png │ │ ├── d_beishang@2x.png │ │ ├── d_beishang@3x.png │ │ ├── d_bishi@2x.png │ │ ├── d_bishi@3x.png │ │ ├── d_bizui@2x.png │ │ ├── d_bizui@3x.png │ │ ├── d_chanzui@2x.png │ │ ├── d_chanzui@3x.png │ │ ├── d_chijing@2x.png │ │ ├── d_chijing@3x.png │ │ ├── d_dahaqi@2x.png │ │ ├── d_dahaqi@3x.png │ │ ├── d_dalian@2x.png │ │ ├── d_dalian@3x.png │ │ ├── d_ganmao@2x.png │ │ ├── d_ganmao@3x.png │ │ ├── d_guzhang@2x.png │ │ ├── d_guzhang@3x.png │ │ ├── d_haha@2x.png │ │ ├── d_haha@3x.png │ │ ├── d_haixiu@2x.png │ │ └── d_haixiu@3x.png │ ├── Info.plist │ ├── ResourceTwitter.bundle │ ├── fav02l-sheet.png │ └── fav02l-sheet@2x.png │ ├── UIControl+YYAdd.h │ ├── UIControl+YYAdd.m │ ├── UIGestureRecognizer+YYAdd.h │ ├── UIGestureRecognizer+YYAdd.m │ ├── UIView+YYAdd.h │ ├── UIView+YYAdd.m │ ├── ViewController.h │ ├── ViewController.m │ ├── YYBPGCoder.h │ ├── YYBPGCoder.m │ ├── YYImageBenchmark.h │ ├── YYImageBenchmark.m │ ├── YYImageDisplayExample.h │ ├── YYImageDisplayExample.m │ ├── YYImageExample.h │ ├── YYImageExample.m │ ├── YYImageExampleHelper.h │ ├── YYImageExampleHelper.m │ ├── YYImageProgressiveExample.h │ ├── YYImageProgressiveExample.m │ ├── YYWebImageExample.h │ ├── YYWebImageExample.m │ ├── cube@2x.png │ ├── google@2x.webp │ ├── main.m │ ├── mew_baseline.gif │ ├── mew_baseline.jpg │ ├── mew_baseline.png │ ├── mew_interlaced.gif │ ├── mew_interlaced.png │ ├── mew_progressive.jpg │ ├── niconiconi@2x.gif │ ├── nyancat@2x.webp │ ├── pia@2x.png │ └── wall-e@2x.webp ├── Framework ├── Info.plist └── YYImage.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ └── contents.xcworkspacedata │ └── xcshareddata │ └── xcschemes │ └── YYImage.xcscheme ├── LICENSE ├── README.md ├── Vendor ├── WebP.framework │ ├── Headers │ │ ├── config.h │ │ ├── decode.h │ │ ├── demux.h │ │ ├── encode.h │ │ ├── format_constants.h │ │ ├── mux.h │ │ ├── mux_types.h │ │ └── types.h │ └── WebP └── WebP.sh ├── YYImage.podspec └── YYImage ├── YYAnimatedImageView.h ├── YYAnimatedImageView.m ├── YYFrameImage.h ├── YYFrameImage.m ├── YYImage.h ├── YYImage.m ├── YYImageCoder.h ├── YYImageCoder.m ├── YYSpriteSheetImage.h └── YYSpriteSheetImage.m /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | # 6 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 7 | 8 | ## Build generated 9 | build/ 10 | DerivedData/ 11 | 12 | ## Various settings 13 | *.pbxuser 14 | !default.pbxuser 15 | *.mode1v3 16 | !default.mode1v3 17 | *.mode2v3 18 | !default.mode2v3 19 | *.perspectivev3 20 | !default.perspectivev3 21 | xcuserdata/ 22 | 23 | ## Other 24 | *.moved-aside 25 | *.xccheckout 26 | *.xcuserstate 27 | *.xcscmblueprint 28 | 29 | ## Obj-C/Swift specific 30 | *.hmap 31 | *.ipa 32 | *.dSYM.zip 33 | *.dSYM 34 | 35 | # CocoaPods 36 | # 37 | # We recommend against adding the Pods directory to your .gitignore. However 38 | # you should judge for yourself, the pros and cons are mentioned at: 39 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 40 | # 41 | # Pods/ 42 | 43 | # Carthage 44 | # 45 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 46 | # Carthage/Checkouts 47 | 48 | Carthage/Build 49 | 50 | # fastlane 51 | # 52 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 53 | # screenshots whenever they are needed. 54 | # For more information about the recommended setup visit: 55 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 56 | 57 | fastlane/report.xml 58 | fastlane/Preview.html 59 | fastlane/screenshots 60 | fastlane/test_output 61 | 62 | # Code Injection 63 | # 64 | # After new code Injection tools there's a generated folder /iOSInjectionProject 65 | # https://github.com/johnno1962/injectionforxcode 66 | 67 | iOSInjectionProject/ 68 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode8 3 | xcode_project: Framework/YYImage.xcodeproj 4 | xcode_scheme: YYImage 5 | 6 | before_install: 7 | - env 8 | - xcodebuild -version 9 | - xcodebuild -showsdks 10 | - xcpretty --version 11 | 12 | script: 13 | - set -o pipefail 14 | - xcodebuild clean build -project "$TRAVIS_XCODE_PROJECT" -scheme "$TRAVIS_XCODE_SCHEME" | xcpretty 15 | -------------------------------------------------------------------------------- /Demo/YYImageDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // YYImageDemo 4 | // 5 | // Created by ibireme on 15/10/16. 6 | // Copyright © 2015年 ibireme. 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 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // YYImageDemo 4 | // 5 | // Created by ibireme on 15/10/16. 6 | // Copyright © 2015年 ibireme. 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 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // 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. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/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 | } -------------------------------------------------------------------------------- /Demo/YYImageDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/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 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_aini@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_aini@2x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_aini@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_aini@3x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_baibai@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_baibai@2x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_baibai@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_baibai@3x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_beishang@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_beishang@2x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_beishang@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_beishang@3x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_bishi@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_bishi@2x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_bishi@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_bishi@3x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_bizui@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_bizui@2x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_bizui@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_bizui@3x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_chanzui@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_chanzui@2x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_chanzui@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_chanzui@3x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_chijing@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_chijing@2x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_chijing@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_chijing@3x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_dahaqi@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_dahaqi@2x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_dahaqi@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_dahaqi@3x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_dalian@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_dalian@2x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_dalian@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_dalian@3x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_ganmao@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_ganmao@2x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_ganmao@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_ganmao@3x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_guzhang@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_guzhang@2x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_guzhang@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_guzhang@3x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_haha@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_haha@2x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_haha@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_haha@3x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_haixiu@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_haixiu@2x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_haixiu@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/EmoticonWeibo.bundle/com.sina.default/d_haixiu@3x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/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 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/ResourceTwitter.bundle/fav02l-sheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/ResourceTwitter.bundle/fav02l-sheet.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/ResourceTwitter.bundle/fav02l-sheet@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/ResourceTwitter.bundle/fav02l-sheet@2x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/UIControl+YYAdd.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIControl+YYAdd.h 3 | // YYKit 4 | // 5 | // Created by ibireme on 13/4/5. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | /** 15 | Provides extensions for `UIControl`. 16 | */ 17 | @interface UIControl (YYAdd) 18 | 19 | /** 20 | Removes all targets and actions for a particular event (or events) 21 | from an internal dispatch table. 22 | */ 23 | - (void)removeAllTargets; 24 | 25 | /** 26 | Adds or replaces a target and action for a particular event (or events) 27 | to an internal dispatch table. 28 | 29 | @param target The target object—that is, the object to which the 30 | action message is sent. If this is nil, the responder 31 | chain is searched for an object willing to respond to the 32 | action message. 33 | 34 | @param action A selector identifying an action message. It cannot be NULL. 35 | 36 | @param controlEvents A bitmask specifying the control events for which the 37 | action message is sent. 38 | */ 39 | - (void)setTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents; 40 | 41 | /** 42 | Adds a block for a particular event (or events) to an internal dispatch table. 43 | It will cause a strong reference to @a block. 44 | 45 | @param block The block which is invoked then the action message is 46 | sent (cannot be nil). The block is retained. 47 | 48 | @param controlEvents A bitmask specifying the control events for which the 49 | action message is sent. 50 | */ 51 | - (void)addBlockForControlEvents:(UIControlEvents)controlEvents block:(void (^)(id sender))block; 52 | 53 | /** 54 | Adds or replaces a block for a particular event (or events) to an internal 55 | dispatch table. It will cause a strong reference to @a block. 56 | 57 | @param block The block which is invoked then the action message is 58 | sent (cannot be nil). The block is retained. 59 | 60 | @param controlEvents A bitmask specifying the control events for which the 61 | action message is sent. 62 | */ 63 | - (void)setBlockForControlEvents:(UIControlEvents)controlEvents block:(void (^)(id sender))block; 64 | 65 | /** 66 | Removes all blocks for a particular event (or events) from an internal 67 | dispatch table. 68 | 69 | @param controlEvents A bitmask specifying the control events for which the 70 | action message is sent. 71 | */ 72 | - (void)removeAllBlocksForControlEvents:(UIControlEvents)controlEvents; 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/UIControl+YYAdd.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIControl+YYAdd.m 3 | // YYKit 4 | // 5 | // Created by ibireme on 13/4/5. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "UIControl+YYAdd.h" 13 | #import 14 | 15 | 16 | static const int block_key; 17 | 18 | @interface _YYUIControlBlockTarget : NSObject 19 | 20 | @property (nonatomic, copy) void (^block)(id sender); 21 | @property (nonatomic, assign) UIControlEvents events; 22 | 23 | - (id)initWithBlock:(void (^)(id sender))block events:(UIControlEvents)events; 24 | - (void)invoke:(id)sender; 25 | 26 | @end 27 | 28 | @implementation _YYUIControlBlockTarget 29 | 30 | - (id)initWithBlock:(void (^)(id sender))block events:(UIControlEvents)events { 31 | self = [super init]; 32 | if (self) { 33 | _block = [block copy]; 34 | _events = events; 35 | } 36 | return self; 37 | } 38 | 39 | - (void)invoke:(id)sender { 40 | if (_block) _block(sender); 41 | } 42 | 43 | @end 44 | 45 | 46 | 47 | @implementation UIControl (YYAdd) 48 | 49 | - (void)removeAllTargets { 50 | [[self allTargets] enumerateObjectsUsingBlock: ^(id object, BOOL *stop) { 51 | [self removeTarget:object 52 | action:NULL 53 | forControlEvents:UIControlEventAllEvents]; 54 | }]; 55 | } 56 | 57 | - (void)setTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents { 58 | NSSet *targets = [self allTargets]; 59 | for (id currentTarget in targets) { 60 | NSArray *actions = [self actionsForTarget:currentTarget forControlEvent:controlEvents]; 61 | for (NSString *currentAction in actions) { 62 | [self removeTarget:currentTarget action:NSSelectorFromString(currentAction) 63 | forControlEvents:controlEvents]; 64 | } 65 | } 66 | [self addTarget:target action:action forControlEvents:controlEvents]; 67 | } 68 | 69 | - (void)addBlockForControlEvents:(UIControlEvents)controlEvents 70 | block:(void (^)(id sender))block { 71 | _YYUIControlBlockTarget *target = [[_YYUIControlBlockTarget alloc] 72 | initWithBlock:block events:controlEvents]; 73 | [self addTarget:target action:@selector(invoke:) forControlEvents:controlEvents]; 74 | NSMutableArray *targets = [self _yy_allUIControlBlockTargets]; 75 | [targets addObject:target]; 76 | } 77 | 78 | - (void)setBlockForControlEvents:(UIControlEvents)controlEvents 79 | block:(void (^)(id sender))block { 80 | [self removeAllBlocksForControlEvents:controlEvents]; 81 | [self addBlockForControlEvents:controlEvents block:block]; 82 | } 83 | 84 | - (void)removeAllBlocksForControlEvents:(UIControlEvents)controlEvents { 85 | NSMutableArray *targets = [self _yy_allUIControlBlockTargets]; 86 | NSMutableArray *removes = [NSMutableArray array]; 87 | [targets enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) { 88 | _YYUIControlBlockTarget *target = (_YYUIControlBlockTarget *)obj; 89 | if (target.events == controlEvents) { 90 | [removes addObject:target]; 91 | [self removeTarget:target 92 | action:@selector(invoke:) 93 | forControlEvents:controlEvents]; 94 | } 95 | }]; 96 | [targets removeObjectsInArray:removes]; 97 | } 98 | 99 | - (NSMutableArray *)_yy_allUIControlBlockTargets { 100 | NSMutableArray *targets = objc_getAssociatedObject(self, &block_key); 101 | if (!targets) { 102 | targets = [NSMutableArray array]; 103 | objc_setAssociatedObject(self, &block_key, targets, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 104 | } 105 | return targets; 106 | } 107 | 108 | @end 109 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/UIGestureRecognizer+YYAdd.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIGestureRecognizer+YYAdd.h 3 | // YYKit 4 | // 5 | // Created by ibireme on 13/10/13. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | /** 15 | Provides extensions for `UIGestureRecognizer`. 16 | */ 17 | @interface UIGestureRecognizer (YYAdd) 18 | 19 | /** 20 | Initializes an allocated gesture-recognizer object with a action block. 21 | 22 | @param block An action block that to handle the gesture recognized by the 23 | receiver. nil is invalid. It is retained by the gesture. 24 | 25 | @return An initialized instance of a concrete UIGestureRecognizer subclass or 26 | nil if an error occurred in the attempt to initialize the object. 27 | */ 28 | - (instancetype)initWithActionBlock:(void (^)(id sender))block; 29 | 30 | /** 31 | Adds an action block to a gesture-recognizer object. It is retained by the 32 | gesture. 33 | 34 | @param block A block invoked by the action message. nil is not a valid value. 35 | */ 36 | - (void)addActionBlock:(void (^)(id sender))block; 37 | 38 | /** 39 | Remove all action blocks. 40 | */ 41 | - (void)removeAllActionBlocks; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/UIGestureRecognizer+YYAdd.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIGestureRecognizer+YYAdd.m 3 | // YYKit 4 | // 5 | // Created by ibireme on 13/10/13. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "UIGestureRecognizer+YYAdd.h" 13 | #import 14 | 15 | static const int block_key; 16 | 17 | @interface _YYUIGestureRecognizerBlockTarget : NSObject 18 | 19 | @property (nonatomic, copy) void (^block)(id sender); 20 | 21 | - (id)initWithBlock:(void (^)(id sender))block; 22 | - (void)invoke:(id)sender; 23 | 24 | @end 25 | 26 | @implementation _YYUIGestureRecognizerBlockTarget 27 | 28 | - (id)initWithBlock:(void (^)(id sender))block{ 29 | self = [super init]; 30 | if (self) { 31 | _block = [block copy]; 32 | } 33 | return self; 34 | } 35 | 36 | - (void)invoke:(id)sender { 37 | if (_block) _block(sender); 38 | } 39 | 40 | @end 41 | 42 | 43 | 44 | 45 | @implementation UIGestureRecognizer (YYAdd) 46 | 47 | - (instancetype)initWithActionBlock:(void (^)(id sender))block { 48 | self = [self init]; 49 | [self addActionBlock:block]; 50 | return self; 51 | } 52 | 53 | - (void)addActionBlock:(void (^)(id sender))block { 54 | _YYUIGestureRecognizerBlockTarget *target = [[_YYUIGestureRecognizerBlockTarget alloc] initWithBlock:block]; 55 | [self addTarget:target action:@selector(invoke:)]; 56 | NSMutableArray *targets = [self _yy_allUIGestureRecognizerBlockTargets]; 57 | [targets addObject:target]; 58 | } 59 | 60 | - (void)removeAllActionBlocks{ 61 | NSMutableArray *targets = [self _yy_allUIGestureRecognizerBlockTargets]; 62 | [targets enumerateObjectsUsingBlock:^(id target, NSUInteger idx, BOOL *stop) { 63 | [self removeTarget:target action:@selector(invoke:)]; 64 | }]; 65 | [targets removeAllObjects]; 66 | } 67 | 68 | - (NSMutableArray *)_yy_allUIGestureRecognizerBlockTargets { 69 | NSMutableArray *targets = objc_getAssociatedObject(self, &block_key); 70 | if (!targets) { 71 | targets = [NSMutableArray array]; 72 | objc_setAssociatedObject(self, &block_key, targets, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 73 | } 74 | return targets; 75 | } 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/UIView+YYAdd.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+YYAdd.h 3 | // YYCategories 4 | // 5 | // Created by ibireme on 13/4/3. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | /** 15 | Provides extensions for `UIView`. 16 | */ 17 | @interface UIView (YYAdd) 18 | 19 | /** 20 | Shortcut to set the view.layer's shadow 21 | 22 | @param color Shadow Color 23 | @param offset Shadow offset 24 | @param radius Shadow radius 25 | */ 26 | - (void)setLayerShadow:(UIColor*)color offset:(CGSize)offset radius:(CGFloat)radius; 27 | 28 | /** 29 | Remove all subviews. 30 | 31 | @warning Never call this method inside your view's drawRect: method. 32 | */ 33 | - (void)removeAllSubviews; 34 | 35 | /** 36 | Returns the view's view controller (may be nil). 37 | */ 38 | @property (nonatomic, readonly) UIViewController *viewController; 39 | 40 | @property (nonatomic) CGFloat left; ///< Shortcut for frame.origin.x. 41 | @property (nonatomic) CGFloat top; ///< Shortcut for frame.origin.y 42 | @property (nonatomic) CGFloat right; ///< Shortcut for frame.origin.x + frame.size.width 43 | @property (nonatomic) CGFloat bottom; ///< Shortcut for frame.origin.y + frame.size.height 44 | @property (nonatomic) CGFloat width; ///< Shortcut for frame.size.width. 45 | @property (nonatomic) CGFloat height; ///< Shortcut for frame.size.height. 46 | @property (nonatomic) CGFloat centerX; ///< Shortcut for center.x 47 | @property (nonatomic) CGFloat centerY; ///< Shortcut for center.y 48 | @property (nonatomic) CGPoint origin; ///< Shortcut for frame.origin. 49 | @property (nonatomic) CGSize size; ///< Shortcut for frame.size. 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/UIView+YYAdd.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+YYAdd.m 3 | // YYCategories 4 | // 5 | // Created by ibireme on 13/4/3. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "UIView+YYAdd.h" 13 | #import 14 | 15 | @implementation UIView (YYAdd) 16 | 17 | - (void)setLayerShadow:(UIColor*)color offset:(CGSize)offset radius:(CGFloat)radius { 18 | self.layer.shadowColor = color.CGColor; 19 | self.layer.shadowOffset = offset; 20 | self.layer.shadowRadius = radius; 21 | self.layer.shadowOpacity = 1; 22 | self.layer.shouldRasterize = YES; 23 | self.layer.rasterizationScale = [UIScreen mainScreen].scale; 24 | } 25 | 26 | - (void)removeAllSubviews { 27 | //[self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; 28 | while (self.subviews.count) { 29 | [self.subviews.lastObject removeFromSuperview]; 30 | } 31 | } 32 | 33 | - (UIViewController *)viewController { 34 | for (UIView *view = self; view; view = view.superview) { 35 | UIResponder *nextResponder = [view nextResponder]; 36 | if ([nextResponder isKindOfClass:[UIViewController class]]) { 37 | return (UIViewController *)nextResponder; 38 | } 39 | } 40 | return nil; 41 | } 42 | 43 | - (CGFloat)left { 44 | return self.frame.origin.x; 45 | } 46 | 47 | - (void)setLeft:(CGFloat)x { 48 | CGRect frame = self.frame; 49 | frame.origin.x = x; 50 | self.frame = frame; 51 | } 52 | 53 | - (CGFloat)top { 54 | return self.frame.origin.y; 55 | } 56 | 57 | - (void)setTop:(CGFloat)y { 58 | CGRect frame = self.frame; 59 | frame.origin.y = y; 60 | self.frame = frame; 61 | } 62 | 63 | - (CGFloat)right { 64 | return self.frame.origin.x + self.frame.size.width; 65 | } 66 | 67 | - (void)setRight:(CGFloat)right { 68 | CGRect frame = self.frame; 69 | frame.origin.x = right - frame.size.width; 70 | self.frame = frame; 71 | } 72 | 73 | - (CGFloat)bottom { 74 | return self.frame.origin.y + self.frame.size.height; 75 | } 76 | 77 | - (void)setBottom:(CGFloat)bottom { 78 | CGRect frame = self.frame; 79 | frame.origin.y = bottom - frame.size.height; 80 | self.frame = frame; 81 | } 82 | 83 | - (CGFloat)width { 84 | return self.frame.size.width; 85 | } 86 | 87 | - (void)setWidth:(CGFloat)width { 88 | CGRect frame = self.frame; 89 | frame.size.width = width; 90 | self.frame = frame; 91 | } 92 | 93 | - (CGFloat)height { 94 | return self.frame.size.height; 95 | } 96 | 97 | - (void)setHeight:(CGFloat)height { 98 | CGRect frame = self.frame; 99 | frame.size.height = height; 100 | self.frame = frame; 101 | } 102 | 103 | - (CGFloat)centerX { 104 | return self.center.x; 105 | } 106 | 107 | - (void)setCenterX:(CGFloat)centerX { 108 | self.center = CGPointMake(centerX, self.center.y); 109 | } 110 | 111 | - (CGFloat)centerY { 112 | return self.center.y; 113 | } 114 | 115 | - (void)setCenterY:(CGFloat)centerY { 116 | self.center = CGPointMake(self.center.x, centerY); 117 | } 118 | 119 | - (CGPoint)origin { 120 | return self.frame.origin; 121 | } 122 | 123 | - (void)setOrigin:(CGPoint)origin { 124 | CGRect frame = self.frame; 125 | frame.origin = origin; 126 | self.frame = frame; 127 | } 128 | 129 | - (CGSize)size { 130 | return self.frame.size; 131 | } 132 | 133 | - (void)setSize:(CGSize)size { 134 | CGRect frame = self.frame; 135 | frame.size = size; 136 | self.frame = frame; 137 | } 138 | 139 | @end 140 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // YYImageDemo 4 | // 5 | // Created by ibireme on 15/10/16. 6 | // Copyright © 2015年 ibireme. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UINavigationController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // YYImageDemo 4 | // 5 | // Created by ibireme on 15/10/16. 6 | // Copyright © 2015年 ibireme. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "YYImageExample.h" 11 | 12 | @interface ViewController () 13 | 14 | @end 15 | 16 | @implementation ViewController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | YYImageExample *vc = [YYImageExample new]; 21 | [self pushViewController:vc animated:NO]; 22 | } 23 | 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/YYBPGCoder.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYBPGCoder.h 3 | // YYKitExample 4 | // 5 | // Created by ibireme on 15/8/13. 6 | // Copyright (c) 2015 ibireme. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YYImage.h" 11 | 12 | /* 13 | BPG image format: 14 | http://bellard.org/bpg/ 15 | */ 16 | 17 | /** 18 | Decode BPG data 19 | @param bpgData BPG image data. 20 | @param decodeForDisplay YES: returns a premultiply BRGA format image, NO: returns an ARGB format image. 21 | @return A new image, or NULL if an error occurs. 22 | */ 23 | CG_EXTERN CGImageRef YYCGImageCreateWithBPGData(CFDataRef bpgData, BOOL decodeForDisplay); 24 | 25 | /** 26 | Decode a frame from BPG image data, returns NULL if an error occurs. 27 | @warning This method should only be used for benchmark. 28 | */ 29 | CG_EXTERN CGImageRef YYCGImageCreateFrameWithBPGData(CFDataRef bpgData, NSUInteger frameIndex, BOOL decodeForDisplay); 30 | 31 | /** 32 | Decode all frames in BPG image data, returns NULL if an error occurs. 33 | @warning This method should only be used for benchmark. 34 | */ 35 | CG_EXTERN void YYCGImageDecodeAllFrameInBPGData(CFDataRef bpgData, BOOL decodeForDisplay); 36 | 37 | /** 38 | Whether data is bpg. 39 | */ 40 | CG_EXTERN BOOL YYImageIsBPGData(CFDataRef data); 41 | 42 | 43 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/YYBPGCoder.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYBPGCoder.m 3 | // YYKitExample 4 | // 5 | // Created by ibireme on 15/8/13. 6 | // Copyright (c) 2015 ibireme. All rights reserved. 7 | // 8 | 9 | #import "YYBPGCoder.h" 10 | #import 11 | #import 12 | #import 13 | 14 | #define YY_FOUR_CC(c1,c2,c3,c4) ((uint32_t)(((c4) << 24) | ((c3) << 16) | ((c2) << 8) | (c1))) 15 | 16 | /// Returns byte-aligned size. 17 | static inline size_t _YYImageByteAlign(size_t size, size_t alignment) { 18 | return ((size + (alignment - 1)) / alignment) * alignment; 19 | } 20 | 21 | /** 22 | A callback used in CGDataProviderCreateWithData() to release data. 23 | 24 | Example: 25 | 26 | void *data = malloc(size); 27 | CGDataProviderRef provider = CGDataProviderCreateWithData(data, data, size, YYCGDataProviderReleaseDataCallback); 28 | */ 29 | static void _YYCGDataProviderReleaseDataCallback(void *info, const void *data, size_t size) { 30 | free(info); 31 | } 32 | 33 | CGImageRef YYCGImageCreateWithBPGData(CFDataRef bpgData, BOOL decodeForDisplay) { 34 | BPGDecoderContext *decoderContext = NULL; 35 | BPGImageInfo imageInfo = {0}; 36 | size_t width, height, lineSize, stride, size; 37 | uint8_t *rgbaLine = NULL, *rgbaBuffer = NULL; 38 | CGDataProviderRef dataProvider = NULL; 39 | CGImageRef cgImage = NULL; 40 | CGBitmapInfo bitmapInfo; 41 | 42 | if (!bpgData || CFDataGetLength(bpgData) == 0) return NULL; 43 | decoderContext = bpg_decoder_open(); 44 | if (!decoderContext) return NULL; 45 | if (bpg_decoder_decode(decoderContext, CFDataGetBytePtr(bpgData), (int)CFDataGetLength(bpgData)) < 0) goto fail; 46 | if (bpg_decoder_get_info(decoderContext, &imageInfo) < 0) goto fail; 47 | 48 | width = imageInfo.width; 49 | height = imageInfo.height; 50 | lineSize = 4 * width; 51 | stride = _YYImageByteAlign(lineSize, 32); 52 | size = stride * height; 53 | 54 | if (width == 0 || height == 0) goto fail; 55 | rgbaLine = malloc(lineSize); 56 | if (!rgbaLine) goto fail; 57 | rgbaBuffer = malloc(size); 58 | if (!rgbaBuffer) goto fail; 59 | if (bpg_decoder_start(decoderContext, BPG_OUTPUT_FORMAT_RGBA32) < 0) goto fail; 60 | 61 | for (int y = 0; y < height; y++) { 62 | if (bpg_decoder_get_line(decoderContext, rgbaLine) < 0) goto fail; 63 | memcpy(rgbaBuffer + (y * stride), rgbaLine, lineSize); 64 | } 65 | free(rgbaLine); 66 | rgbaLine = NULL; 67 | bpg_decoder_close(decoderContext); 68 | decoderContext = NULL; 69 | 70 | if (decodeForDisplay) { 71 | vImage_Buffer src; 72 | src.data = rgbaBuffer; 73 | src.width = width; 74 | src.height = height; 75 | src.rowBytes = stride; 76 | vImage_Error error; 77 | 78 | // premultiply RGBA 79 | error = vImagePremultiplyData_RGBA8888(&src, &src, kvImageNoFlags); 80 | if (error != kvImageNoError) goto fail; 81 | 82 | // convert to bgrA 83 | uint8_t map[4] = {2,1,0,3}; 84 | error = vImagePermuteChannels_ARGB8888(&src, &src, map, kvImageNoFlags); 85 | if (error != kvImageNoError) goto fail; 86 | bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; 87 | } else { 88 | bitmapInfo = kCGImageAlphaLast | kCGBitmapByteOrderDefault; 89 | } 90 | 91 | dataProvider = CGDataProviderCreateWithData(rgbaBuffer, rgbaBuffer, size, _YYCGDataProviderReleaseDataCallback); 92 | if (!dataProvider) goto fail; 93 | rgbaBuffer = NULL; // hold by provider 94 | cgImage = CGImageCreate(width, height, 8, 32, stride, YYCGColorSpaceGetDeviceRGB(), 95 | bitmapInfo, dataProvider, NULL, NO, 96 | kCGRenderingIntentDefault); 97 | 98 | CGDataProviderRelease(dataProvider); 99 | return cgImage; 100 | 101 | fail: 102 | if (decoderContext) bpg_decoder_close(decoderContext); 103 | if (rgbaLine) free(rgbaLine); 104 | if (rgbaBuffer) free(rgbaBuffer); 105 | return NULL; 106 | } 107 | 108 | 109 | CGImageRef YYCGImageCreateFrameWithBPGData(CFDataRef bpgData, NSUInteger frameIndex, BOOL decodeForDisplay) { 110 | BPGDecoderContext *decoderContext = NULL; 111 | BPGImageInfo imageInfo = {0}; 112 | size_t width, height, lineSize, stride, size; 113 | uint8_t *rgbaLine = NULL, *rgbaBuffer = NULL; 114 | CGDataProviderRef dataProvider = NULL; 115 | CGImageRef cgImage = NULL; 116 | CGBitmapInfo bitmapInfo; 117 | 118 | if (!bpgData || CFDataGetLength(bpgData) == 0) return NULL; 119 | decoderContext = bpg_decoder_open(); 120 | if (!decoderContext) return NULL; 121 | if (bpg_decoder_decode(decoderContext, CFDataGetBytePtr(bpgData), (int)CFDataGetLength(bpgData)) < 0) goto fail; 122 | if (bpg_decoder_get_info(decoderContext, &imageInfo) < 0) goto fail; 123 | 124 | width = imageInfo.width; 125 | height = imageInfo.height; 126 | lineSize = 4 * width; 127 | stride = _YYImageByteAlign(lineSize, 32); 128 | size = stride * height; 129 | 130 | if (width == 0 || height == 0) goto fail; 131 | rgbaLine = malloc(lineSize); 132 | if (!rgbaLine) goto fail; 133 | rgbaBuffer = malloc(size); 134 | if (!rgbaBuffer) goto fail; 135 | 136 | for (NSUInteger i = 0; i <= frameIndex; i++) { 137 | if (bpg_decoder_start(decoderContext, BPG_OUTPUT_FORMAT_RGBA32) < 0) goto fail; 138 | } 139 | 140 | for (int y = 0; y < height; y++) { 141 | if (bpg_decoder_get_line(decoderContext, rgbaLine) < 0) goto fail; 142 | memcpy(rgbaBuffer + (y * stride), rgbaLine, lineSize); 143 | } 144 | free(rgbaLine); 145 | rgbaLine = NULL; 146 | bpg_decoder_close(decoderContext); 147 | decoderContext = NULL; 148 | 149 | if (decodeForDisplay) { 150 | vImage_Buffer src; 151 | src.data = rgbaBuffer; 152 | src.width = width; 153 | src.height = height; 154 | src.rowBytes = stride; 155 | vImage_Error error; 156 | 157 | // premultiply RGBA 158 | error = vImagePremultiplyData_RGBA8888(&src, &src, kvImageNoFlags); 159 | if (error != kvImageNoError) goto fail; 160 | 161 | // convert to BGRA 162 | uint8_t map[4] = {2,1,0,3}; 163 | error = vImagePermuteChannels_ARGB8888(&src, &src, map, kvImageNoFlags); 164 | if (error != kvImageNoError) goto fail; 165 | bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; 166 | } else { 167 | bitmapInfo = kCGImageAlphaLast | kCGBitmapByteOrderDefault; 168 | } 169 | 170 | dataProvider = CGDataProviderCreateWithData(rgbaBuffer, rgbaBuffer, size, _YYCGDataProviderReleaseDataCallback); 171 | if (!dataProvider) goto fail; 172 | rgbaBuffer = NULL; // hold by provider 173 | cgImage = CGImageCreate(width, height, 8, 32, stride, YYCGColorSpaceGetDeviceRGB(), 174 | bitmapInfo, dataProvider, NULL, NO, 175 | kCGRenderingIntentDefault); 176 | 177 | CGDataProviderRelease(dataProvider); 178 | return cgImage; 179 | 180 | fail: 181 | if (decoderContext) bpg_decoder_close(decoderContext); 182 | if (rgbaLine) free(rgbaLine); 183 | if (rgbaBuffer) free(rgbaBuffer); 184 | return NULL; 185 | } 186 | 187 | 188 | void YYCGImageDecodeAllFrameInBPGData(CFDataRef bpgData, BOOL decodeForDisplay) { 189 | BPGDecoderContext *decoderContext = NULL; 190 | BPGImageInfo imageInfo = {0}; 191 | size_t width, height, lineSize, stride, size; 192 | uint8_t *rgbaLine = NULL, *rgbaBuffer = NULL; 193 | CGDataProviderRef dataProvider = NULL; 194 | CGImageRef cgImage = NULL; 195 | CGBitmapInfo bitmapInfo; 196 | 197 | if (!bpgData || CFDataGetLength(bpgData) == 0) return; 198 | decoderContext = bpg_decoder_open(); 199 | if (!decoderContext) return; 200 | if (bpg_decoder_decode(decoderContext, CFDataGetBytePtr(bpgData), (int)CFDataGetLength(bpgData)) < 0) goto end; 201 | if (bpg_decoder_get_info(decoderContext, &imageInfo) < 0) goto end; 202 | 203 | width = imageInfo.width; 204 | height = imageInfo.height; 205 | lineSize = 4 * width; 206 | stride = _YYImageByteAlign(lineSize, 32); 207 | size = stride * height; 208 | 209 | 210 | for (;;) { 211 | if (bpg_decoder_start(decoderContext, BPG_OUTPUT_FORMAT_RGBA32) < 0) goto end; 212 | 213 | if (width == 0 || height == 0) goto end; 214 | rgbaLine = malloc(lineSize); 215 | if (!rgbaLine) goto end; 216 | rgbaBuffer = malloc(size); 217 | if (!rgbaBuffer) goto end; 218 | 219 | for (int y = 0; y < height; y++) { 220 | if (bpg_decoder_get_line(decoderContext, rgbaLine) < 0) goto end; 221 | memcpy(rgbaBuffer + (y * stride), rgbaLine, lineSize); 222 | } 223 | free(rgbaLine); 224 | rgbaLine = NULL; 225 | 226 | if (decodeForDisplay) { 227 | vImage_Buffer src; 228 | src.data = rgbaBuffer; 229 | src.width = width; 230 | src.height = height; 231 | src.rowBytes = stride; 232 | vImage_Error error; 233 | 234 | // premultiply RGBA 235 | error = vImagePremultiplyData_RGBA8888(&src, &src, kvImageNoFlags); 236 | if (error != kvImageNoError) goto end; 237 | 238 | // convert to BGRA 239 | uint8_t map[4] = {2,1,0,3}; 240 | error = vImagePermuteChannels_ARGB8888(&src, &src, map, kvImageNoFlags); 241 | if (error != kvImageNoError) goto end; 242 | bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; 243 | } else { 244 | bitmapInfo = kCGImageAlphaLast | kCGBitmapByteOrderDefault; 245 | } 246 | 247 | dataProvider = CGDataProviderCreateWithData(rgbaBuffer, rgbaBuffer, size, _YYCGDataProviderReleaseDataCallback); 248 | if (!dataProvider) goto end; 249 | rgbaBuffer = NULL; // hold by provider 250 | cgImage = CGImageCreate(width, height, 8, 32, stride, YYCGColorSpaceGetDeviceRGB(), 251 | bitmapInfo, dataProvider, NULL, NO, 252 | kCGRenderingIntentDefault); 253 | 254 | CGDataProviderRelease(dataProvider); 255 | if (cgImage) CFRelease(cgImage); 256 | } 257 | return; 258 | 259 | end: 260 | if (decoderContext) bpg_decoder_close(decoderContext); 261 | if (rgbaLine) free(rgbaLine); 262 | if (rgbaBuffer) free(rgbaBuffer); 263 | return; 264 | } 265 | 266 | 267 | BOOL YYImageIsBPGData(CFDataRef data) { 268 | if (!data || CFDataGetLength(data) < 8) return NO; 269 | const uint8_t *bytes = CFDataGetBytePtr(data); 270 | uint32_t magic = *((uint32_t *)bytes); 271 | return magic == YY_FOUR_CC('B', 'P', 'G', 0xFB); 272 | } 273 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/YYImageBenchmark.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYImageProfileExample.h 3 | // YYKitExample 4 | // 5 | // Created by ibireme on 15/8/10. 6 | // Copyright (c) 2015 ibireme. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface YYImageBenchmark : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/YYImageDisplayExample.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYImageDisplayExample.h 3 | // YYKitExample 4 | // 5 | // Created by ibireme on 15/8/9. 6 | // Copyright (c) 2015 ibireme. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface YYImageDisplayExample : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/YYImageDisplayExample.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYImageDisplayExample.m 3 | // YYKitExample 4 | // 5 | // Created by ibireme on 15/8/9. 6 | // Copyright (c) 2015 ibireme. All rights reserved. 7 | // 8 | 9 | #import "YYImageDisplayExample.h" 10 | #import "YYImage.h" 11 | #import "UIView+YYAdd.h" 12 | #import "YYImageExampleHelper.h" 13 | #import 14 | 15 | @interface YYImageDisplayExample() 16 | 17 | @end 18 | @implementation YYImageDisplayExample { 19 | UIScrollView *_scrollView; 20 | } 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | self.view.backgroundColor = [UIColor colorWithWhite:0.863 alpha:1.000]; 25 | 26 | _scrollView = [UIScrollView new]; 27 | _scrollView.frame = self.view.bounds; 28 | [self.view addSubview:_scrollView]; 29 | 30 | UILabel *label = [UILabel new]; 31 | label.backgroundColor = [UIColor clearColor]; 32 | label.size = CGSizeMake(self.view.width, 60); 33 | label.top = 20; 34 | label.textAlignment = NSTextAlignmentCenter; 35 | label.numberOfLines = 0; 36 | label.text = @"Tap the image to pause/play\n Slide on the image to forward/rewind"; 37 | 38 | if ([self isSimulator]) { 39 | label.text = [@"Please run this app in device\nto get better performance.\n\n" stringByAppendingString:label.text]; 40 | label.height = 120; 41 | } 42 | 43 | [_scrollView addSubview:label]; 44 | 45 | [self addImageWithName:@"niconiconi" text:@"Animated GIF"]; 46 | [self addImageWithName:@"wall-e" text:@"Animated WebP"]; 47 | [self addImageWithName:@"pia" text:@"Animated PNG (APNG)"]; 48 | [self addFrameImageWithText:@"Frame Animation"]; 49 | [self addSpriteSheetImageWithText:@"Sprite Sheet Animation"]; 50 | 51 | _scrollView.panGestureRecognizer.cancelsTouchesInView = YES; 52 | } 53 | 54 | - (void)addImageWithName:(NSString *)name text:(NSString *)text { 55 | YYImage *image = [YYImage imageNamed:name]; 56 | [self addImage:image size:CGSizeZero text:text]; 57 | } 58 | 59 | - (void)addFrameImageWithText:(NSString *)text { 60 | 61 | NSString *basePath = [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"EmoticonWeibo.bundle/com.sina.default"]; 62 | NSMutableArray *paths = [NSMutableArray new]; 63 | [paths addObject:[basePath stringByAppendingPathComponent:@"d_aini@3x.png"]]; 64 | [paths addObject:[basePath stringByAppendingPathComponent:@"d_baibai@3x.png"]]; 65 | [paths addObject:[basePath stringByAppendingPathComponent:@"d_chanzui@3x.png"]]; 66 | [paths addObject:[basePath stringByAppendingPathComponent:@"d_chijing@3x.png"]]; 67 | [paths addObject:[basePath stringByAppendingPathComponent:@"d_dahaqi@3x.png"]]; 68 | [paths addObject:[basePath stringByAppendingPathComponent:@"d_guzhang@3x.png"]]; 69 | [paths addObject:[basePath stringByAppendingPathComponent:@"d_haha@2x.png"]]; 70 | [paths addObject:[basePath stringByAppendingPathComponent:@"d_haixiu@3x.png"]]; 71 | 72 | UIImage *image = [[YYFrameImage alloc] initWithImagePaths:paths oneFrameDuration:0.1 loopCount:0]; 73 | [self addImage:image size:CGSizeZero text:text]; 74 | } 75 | 76 | - (void)addSpriteSheetImageWithText:(NSString *)text { 77 | NSString *path = [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"ResourceTwitter.bundle/fav02l-sheet@2x.png"]; 78 | UIImage *sheet = [[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:path] scale:2]; 79 | NSMutableArray *contentRects = [NSMutableArray new]; 80 | NSMutableArray *durations = [NSMutableArray new]; 81 | 82 | 83 | // 8 * 12 sprites in a single sheet image 84 | CGSize size = CGSizeMake(sheet.size.width / 8, sheet.size.height / 12); 85 | for (int j = 0; j < 12; j++) { 86 | for (int i = 0; i < 8; i++) { 87 | CGRect rect; 88 | rect.size = size; 89 | rect.origin.x = sheet.size.width / 8 * i; 90 | rect.origin.y = sheet.size.height / 12 * j; 91 | [contentRects addObject:[NSValue valueWithCGRect:rect]]; 92 | [durations addObject:@(1 / 60.0)]; 93 | } 94 | } 95 | YYSpriteSheetImage *sprite; 96 | sprite = [[YYSpriteSheetImage alloc] initWithSpriteSheetImage:sheet 97 | contentRects:contentRects 98 | frameDurations:durations 99 | loopCount:0]; 100 | [self addImage:sprite size:size text:text]; 101 | } 102 | 103 | - (void)addImage:(UIImage *)image size:(CGSize)size text:(NSString *)text { 104 | YYAnimatedImageView *imageView = [[YYAnimatedImageView alloc] initWithImage:image]; 105 | 106 | if (size.width > 0 && size.height > 0) imageView.size = size; 107 | imageView.centerX = self.view.width / 2; 108 | imageView.top = [(UIView *)[_scrollView.subviews lastObject] bottom] + 30; 109 | [_scrollView addSubview:imageView]; 110 | [YYImageExampleHelper addTapControlToAnimatedImageView:imageView]; 111 | [YYImageExampleHelper addPanControlToAnimatedImageView:imageView]; 112 | for (UIGestureRecognizer *g in imageView.gestureRecognizers) { 113 | g.delegate = self; 114 | } 115 | 116 | UILabel *imageLabel = [UILabel new]; 117 | imageLabel.backgroundColor = [UIColor clearColor]; 118 | imageLabel.frame = CGRectMake(0, 0, self.view.width, 20); 119 | imageLabel.top = imageView.bottom + 10; 120 | imageLabel.textAlignment = NSTextAlignmentCenter; 121 | imageLabel.text = text; 122 | [_scrollView addSubview:imageLabel]; 123 | 124 | _scrollView.contentSize = CGSizeMake(self.view.width, imageLabel.bottom + 20); 125 | } 126 | 127 | - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ 128 | return YES; 129 | } 130 | 131 | 132 | 133 | - (BOOL)isSimulator { 134 | size_t size; 135 | sysctlbyname("hw.machine", NULL, &size, NULL, 0); 136 | char *machine = malloc(size); 137 | sysctlbyname("hw.machine", machine, &size, NULL, 0); 138 | NSString *model = [NSString stringWithUTF8String:machine]; 139 | free(machine); 140 | return [model isEqualToString:@"x86_64"] || [model isEqualToString:@"i386"]; 141 | } 142 | 143 | @end 144 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/YYImageExample.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYImageExample.h 3 | // YYKitExample 4 | // 5 | // Created by ibireme on 15/7/18. 6 | // Copyright (c) 2015 ibireme. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface YYImageExample : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/YYImageExample.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYImageExample.m 3 | // YYKitExample 4 | // 5 | // Created by ibireme on 15/7/18. 6 | // Copyright (c) 2015 ibireme. All rights reserved. 7 | // 8 | 9 | #import "YYImageExample.h" 10 | #import "YYImage.h" 11 | #import "UIView+YYAdd.h" 12 | #import 13 | #import 14 | 15 | @interface YYImageExample() 16 | @property (nonatomic, strong) NSMutableArray *titles; 17 | @property (nonatomic, strong) NSMutableArray *classNames; 18 | @end 19 | 20 | @implementation YYImageExample 21 | 22 | - (void)viewDidLoad { 23 | self.title = @"YYImage Demo"; 24 | [super viewDidLoad]; 25 | self.titles = @[].mutableCopy; 26 | self.classNames = @[].mutableCopy; 27 | [self addCell:@"Animated Image" class:@"YYImageDisplayExample"]; 28 | [self addCell:@"Progressive Image" class:@"YYImageProgressiveExample"]; 29 | //[self addCell:@"Web Image" class:@"YYWebImageExample"]; 30 | //[self addCell:@"Benchmark" class:@"YYImageBenchmark"]; 31 | [self.tableView reloadData]; 32 | } 33 | 34 | - (void)addCell:(NSString *)title class:(NSString *)className { 35 | [self.titles addObject:title]; 36 | [self.classNames addObject:className]; 37 | } 38 | 39 | #pragma mark - Table view data source 40 | 41 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 42 | return _titles.count; 43 | } 44 | 45 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 46 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"YY"]; 47 | if (!cell) { 48 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"YY"]; 49 | } 50 | cell.textLabel.text = _titles[indexPath.row]; 51 | return cell; 52 | } 53 | 54 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 55 | NSString *className = self.classNames[indexPath.row]; 56 | Class class = NSClassFromString(className); 57 | if (class) { 58 | UIViewController *ctrl = class.new; 59 | ctrl.title = _titles[indexPath.row]; 60 | [self.navigationController pushViewController:ctrl animated:YES]; 61 | } 62 | [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; 63 | } 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/YYImageExampleHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYImageExampleUtils.h 3 | // YYKitExample 4 | // 5 | // Created by ibireme on 15/7/20. 6 | // Copyright (c) 2015 ibireme. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YYImage.h" 11 | 12 | @interface YYImageExampleHelper : NSObject 13 | 14 | /// Tap to play/pause 15 | + (void)addTapControlToAnimatedImageView:(YYAnimatedImageView *)view; 16 | 17 | /// Slide to forward/rewind 18 | + (void)addPanControlToAnimatedImageView:(YYAnimatedImageView *)view; 19 | 20 | @end 21 | 22 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/YYImageExampleHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYImageExampleUtils.m 3 | // YYKitExample 4 | // 5 | // Created by ibireme on 15/7/20. 6 | // Copyright (c) 2015 ibireme. All rights reserved. 7 | // 8 | 9 | #import "YYImageExampleHelper.h" 10 | #import "YYImage.h" 11 | #import "UIView+YYAdd.h" 12 | #import "UIGestureRecognizer+YYAdd.h" 13 | #import 14 | #import 15 | //#import 16 | 17 | @implementation YYImageExampleHelper 18 | 19 | + (void)addTapControlToAnimatedImageView:(YYAnimatedImageView *)view { 20 | if (!view) return; 21 | view.userInteractionEnabled = YES; 22 | __weak typeof(view) _view = view; 23 | 24 | UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithActionBlock:^(id sender) { 25 | if ([_view isAnimating]) [_view stopAnimating]; 26 | else [_view startAnimating]; 27 | 28 | // add a "bounce" animation 29 | UIViewAnimationOptions op = UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowAnimatedContent | UIViewAnimationOptionBeginFromCurrentState; 30 | [UIView animateWithDuration:0.1 delay:0 options:op animations:^{ 31 | [_view.layer setValue:@(0.97) forKeyPath:@"transform.scale"]; 32 | } completion:^(BOOL finished) { 33 | [UIView animateWithDuration:0.1 delay:0 options:op animations:^{ 34 | [_view.layer setValue:@(1.008) forKeyPath:@"transform.scale"]; 35 | } completion:^(BOOL finished) { 36 | [UIView animateWithDuration:0.1 delay:0 options:op animations:^{ 37 | [_view.layer setValue:@(1) forKeyPath:@"transform.scale"]; 38 | } completion:NULL]; 39 | }]; 40 | }]; 41 | }]; 42 | [view addGestureRecognizer:tap]; 43 | } 44 | 45 | + (void)addPanControlToAnimatedImageView:(YYAnimatedImageView *)view { 46 | if (!view) return; 47 | view.userInteractionEnabled = YES; 48 | __weak typeof(view) _view = view; 49 | __block BOOL previousIsPlaying; 50 | 51 | UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithActionBlock:^(id sender) { 52 | UIImage *image = (id)_view.image; 53 | if (![image conformsToProtocol:@protocol(YYAnimatedImage)]) return; 54 | UIPanGestureRecognizer *gesture = sender; 55 | CGPoint p = [gesture locationInView:gesture.view]; 56 | CGFloat progress = p.x / gesture.view.width; 57 | if (gesture.state == UIGestureRecognizerStateBegan) { 58 | previousIsPlaying = [_view isAnimating]; 59 | [_view stopAnimating]; 60 | _view.currentAnimatedImageIndex = image.animatedImageFrameCount * progress; 61 | } else if (gesture.state == UIGestureRecognizerStateEnded || 62 | gesture.state == UIGestureRecognizerStateCancelled) { 63 | if (previousIsPlaying) [_view startAnimating]; 64 | } else { 65 | _view.currentAnimatedImageIndex = image.animatedImageFrameCount * progress; 66 | } 67 | }]; 68 | [view addGestureRecognizer:pan]; 69 | } 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/YYImageProgressiveExample.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYImageProgressiveExample.h 3 | // YYKitExample 4 | // 5 | // Created by ibireme on 15/8/24. 6 | // Copyright (c) 2015 ibireme. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface YYImageProgressiveExample : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/YYImageProgressiveExample.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYImageProgressiveExample.m 3 | // YYKitExample 4 | // 5 | // Created by ibireme on 15/8/24. 6 | // Copyright (c) 2015 ibireme. All rights reserved. 7 | // 8 | 9 | #import "YYImageProgressiveExample.h" 10 | #import "YYImage.h" 11 | #import "UIView+YYAdd.h" 12 | #import "UIControl+YYAdd.h" 13 | 14 | @interface NSData(YYAdd) 15 | @end 16 | @implementation NSData(YYAdd) 17 | + (NSData *)dataNamed:(NSString *)name { 18 | NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@""]; 19 | if (!path) return nil; 20 | NSData *data = [NSData dataWithContentsOfFile:path]; 21 | return data; 22 | } 23 | @end 24 | 25 | 26 | @interface YYImageProgressiveExample () { 27 | UIImageView *_imageView; 28 | UISegmentedControl *_seg0; 29 | UISegmentedControl *_seg1; 30 | UISlider *_slider0; 31 | } 32 | 33 | @end 34 | 35 | @implementation YYImageProgressiveExample 36 | 37 | - (void)viewDidLoad { 38 | [super viewDidLoad]; 39 | self.view.backgroundColor = [UIColor whiteColor]; 40 | 41 | _imageView = [UIImageView new]; 42 | _imageView.size = CGSizeMake(300, 300); 43 | _imageView.backgroundColor = [UIColor colorWithWhite:0.790 alpha:1.000]; 44 | _imageView.centerX = self.view.width / 2; 45 | 46 | _seg0 = [[UISegmentedControl alloc] initWithItems:@[@"baseline",@"progressive/interlaced"]]; 47 | _seg0.selectedSegmentIndex = 0; 48 | _seg0.size = CGSizeMake(_imageView.width, 30); 49 | _seg0.centerX = self.view.width / 2; 50 | 51 | _seg1 = [[UISegmentedControl alloc] initWithItems:@[@"JPEG", @"PNG", @"GIF"]]; 52 | _seg1.frame = _seg0.frame; 53 | _seg1.selectedSegmentIndex = 0; 54 | 55 | _slider0 = [UISlider new]; 56 | _slider0.width = _seg0.width; 57 | [_slider0 sizeToFit]; 58 | _slider0.minimumValue = 0; 59 | _slider0.maximumValue = 1.05; 60 | _slider0.value = 0; 61 | _slider0.centerX = self.view.width / 2; 62 | 63 | _imageView.top = 64 + 10; 64 | _seg0.top = _imageView.bottom + 10; 65 | _seg1.top = _seg0.bottom + 10; 66 | _slider0.top = _seg1.bottom + 10; 67 | 68 | [self.view addSubview:_imageView]; 69 | [self.view addSubview:_seg0]; 70 | [self.view addSubview:_seg1]; 71 | [self.view addSubview:_slider0]; 72 | 73 | __weak typeof(self) _self = self; 74 | [_seg0 addBlockForControlEvents:UIControlEventValueChanged block:^(id sender) { 75 | [_self changed]; 76 | }]; 77 | [_seg1 addBlockForControlEvents:UIControlEventValueChanged block:^(id sender) { 78 | [_self changed]; 79 | }]; 80 | [_slider0 addBlockForControlEvents:UIControlEventValueChanged block:^(id sender) { 81 | [_self changed]; 82 | }]; 83 | } 84 | 85 | - (void)changed { 86 | NSString *name = nil; 87 | if (_seg0.selectedSegmentIndex == 0) { 88 | if (_seg1.selectedSegmentIndex == 0) { 89 | name = @"mew_baseline.jpg"; 90 | } else if (_seg1.selectedSegmentIndex == 1) { 91 | name = @"mew_baseline.png"; 92 | } else { 93 | name = @"mew_baseline.gif"; 94 | } 95 | } else { 96 | if (_seg1.selectedSegmentIndex == 0) { 97 | name = @"mew_progressive.jpg"; 98 | } else if (_seg1.selectedSegmentIndex == 1) { 99 | name = @"mew_interlaced.png"; 100 | } else { 101 | name = @"mew_interlaced.gif"; 102 | } 103 | } 104 | 105 | NSData *data = [NSData dataNamed:name]; 106 | float progress = _slider0.value; 107 | if (progress > 1) progress = 1; 108 | NSData *subData = [data subdataWithRange:NSMakeRange(0, data.length * progress)]; 109 | 110 | YYImageDecoder *decoder = [[YYImageDecoder alloc] initWithScale:[UIScreen mainScreen].scale]; 111 | [decoder updateData:subData final:NO]; 112 | YYImageFrame *frame = [decoder frameAtIndex:0 decodeForDisplay:YES]; 113 | 114 | _imageView.image = frame.image; 115 | } 116 | 117 | @end 118 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/YYWebImageExample.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYWebImageExample.h 3 | // YYKitExample 4 | // 5 | // Created by ibireme on 15/7/19. 6 | // Copyright (c) 2015 ibireme. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface YYWebImageExample : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/YYWebImageExample.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYWebImageExample.m 3 | // YYKitExample 4 | // 5 | // Created by ibireme on 15/7/19. 6 | // Copyright (c) 2015 ibireme. All rights reserved. 7 | // 8 | 9 | #import "YYWebImageExample.h" 10 | #import 11 | 12 | #define kCellHeight ceil((kScreenWidth) * 3.0 / 4.0) 13 | 14 | @interface YYWebImageExampleCell : UITableViewCell 15 | @property (nonatomic, strong) YYAnimatedImageView *webImageView; 16 | @property (nonatomic, strong) UIActivityIndicatorView *indicator; 17 | @property (nonatomic, strong) CAShapeLayer *progressLayer; 18 | @property (nonatomic, strong) UILabel *label; 19 | @end 20 | 21 | @implementation YYWebImageExampleCell 22 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 23 | self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 24 | self.backgroundColor = [UIColor clearColor]; 25 | self.contentView.backgroundColor = [UIColor clearColor]; 26 | self.size = CGSizeMake(kScreenWidth, kCellHeight); 27 | self.contentView.size = self.size; 28 | _webImageView = [YYAnimatedImageView new]; 29 | _webImageView.size = self.size; 30 | _webImageView.clipsToBounds = YES; 31 | _webImageView.contentMode = UIViewContentModeScaleAspectFill; 32 | _webImageView.backgroundColor = [UIColor whiteColor]; 33 | [self.contentView addSubview:_webImageView]; 34 | 35 | _indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; 36 | _indicator.center = CGPointMake(self.width / 2, self.height / 2); 37 | _indicator.hidden = YES; 38 | //[self.contentView addSubview:_indicator]; //use progress bar instead.. 39 | 40 | _label = [UILabel new]; 41 | _label.size = self.size; 42 | _label.textAlignment = NSTextAlignmentCenter; 43 | _label.text = @"Load fail, tap to reload."; 44 | _label.textColor = [UIColor colorWithWhite:0.7 alpha:1.0]; 45 | _label.hidden = YES; 46 | _label.userInteractionEnabled = YES; 47 | [self.contentView addSubview:_label]; 48 | 49 | CGFloat lineHeight = 4; 50 | _progressLayer = [CAShapeLayer layer]; 51 | _progressLayer.size = CGSizeMake(_webImageView.width, lineHeight); 52 | UIBezierPath *path = [UIBezierPath bezierPath]; 53 | [path moveToPoint:CGPointMake(0, _progressLayer.height / 2)]; 54 | [path addLineToPoint:CGPointMake(_webImageView.width, _progressLayer.height / 2)]; 55 | _progressLayer.lineWidth = lineHeight; 56 | _progressLayer.path = path.CGPath; 57 | _progressLayer.strokeColor = [UIColor colorWithRed:0.000 green:0.640 blue:1.000 alpha:0.720].CGColor; 58 | _progressLayer.lineCap = kCALineCapButt; 59 | _progressLayer.strokeStart = 0; 60 | _progressLayer.strokeEnd = 0; 61 | [_webImageView.layer addSublayer:_progressLayer]; 62 | 63 | __weak typeof(self) _self = self; 64 | UITapGestureRecognizer *g = [[UITapGestureRecognizer alloc] initWithActionBlock:^(id sender) { 65 | [_self setImageURL:_self.webImageView.imageURL]; 66 | }]; 67 | [_label addGestureRecognizer:g]; 68 | 69 | return self; 70 | } 71 | 72 | - (void)setImageURL:(NSURL *)url { 73 | _label.hidden = YES; 74 | _indicator.hidden = NO; 75 | [_indicator startAnimating]; 76 | __weak typeof(self) _self = self; 77 | 78 | [CATransaction begin]; 79 | [CATransaction setDisableActions: YES]; 80 | self.progressLayer.hidden = YES; 81 | self.progressLayer.strokeEnd = 0; 82 | [CATransaction commit]; 83 | 84 | [_webImageView setImageWithURL:url 85 | placeholder:nil 86 | options:YYWebImageOptionProgressiveBlur | YYWebImageOptionShowNetworkActivity | YYWebImageOptionSetImageWithFadeAnimation 87 | progress:^(NSInteger receivedSize, NSInteger expectedSize) { 88 | if (expectedSize > 0 && receivedSize > 0) { 89 | CGFloat progress = (CGFloat)receivedSize / expectedSize; 90 | progress = progress < 0 ? 0 : progress > 1 ? 1 : progress; 91 | if (_self.progressLayer.hidden) _self.progressLayer.hidden = NO; 92 | _self.progressLayer.strokeEnd = progress; 93 | } 94 | } transform:nil 95 | completion:^(UIImage *image, NSURL *url, YYWebImageFromType from, YYWebImageStage stage, NSError *error) { 96 | if (stage == YYWebImageStageFinished) { 97 | _self.progressLayer.hidden = YES; 98 | [_self.indicator stopAnimating]; 99 | _self.indicator.hidden = YES; 100 | if (!image) _self.label.hidden = NO; 101 | } 102 | }]; 103 | } 104 | 105 | - (void)prepareForReuse { 106 | //nothing 107 | } 108 | 109 | @end 110 | 111 | 112 | @implementation YYWebImageExample { 113 | NSArray *_imageLinks; 114 | } 115 | 116 | - (void)viewDidLoad { 117 | [super viewDidLoad]; 118 | self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 119 | self.view.backgroundColor = [UIColor whiteColor]; 120 | 121 | UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:@"Reload" style:UIBarButtonItemStylePlain target:self action:@selector(reload)]; 122 | self.navigationItem.rightBarButtonItem = button; 123 | self.view.backgroundColor = [UIColor colorWithWhite:0.217 alpha:1.000]; 124 | 125 | NSArray *links = @[ 126 | /* 127 | You can add your image url here. 128 | */ 129 | 130 | // progressive jpeg 131 | @"https://s-media-cache-ak0.pinimg.com/1200x/2e/0c/c5/2e0cc5d86e7b7cd42af225c29f21c37f.jpg", 132 | 133 | // animated gif: http://cinemagraphs.com/ 134 | @"http://i.imgur.com/uoBwCLj.gif", 135 | @"http://i.imgur.com/8KHKhxI.gif", 136 | @"http://i.imgur.com/WXJaqof.gif", 137 | 138 | // animated gif: https://dribbble.com/markpear 139 | @"https://d13yacurqjgara.cloudfront.net/users/345826/screenshots/1780193/dots18.gif", 140 | @"https://d13yacurqjgara.cloudfront.net/users/345826/screenshots/1809343/dots17.1.gif", 141 | @"https://d13yacurqjgara.cloudfront.net/users/345826/screenshots/1845612/dots22.gif", 142 | @"https://d13yacurqjgara.cloudfront.net/users/345826/screenshots/1820014/big-hero-6.gif", 143 | @"https://d13yacurqjgara.cloudfront.net/users/345826/screenshots/1819006/dots11.0.gif", 144 | @"https://d13yacurqjgara.cloudfront.net/users/345826/screenshots/1799885/dots21.gif", 145 | 146 | // animaged gif: https://dribbble.com/jonadinges 147 | @"https://d13yacurqjgara.cloudfront.net/users/288987/screenshots/2025999/batman-beyond-the-rain.gif", 148 | @"https://d13yacurqjgara.cloudfront.net/users/288987/screenshots/1855350/r_nin.gif", 149 | @"https://d13yacurqjgara.cloudfront.net/users/288987/screenshots/1963497/way-back-home.gif", 150 | @"https://d13yacurqjgara.cloudfront.net/users/288987/screenshots/1913272/depressed-slurp-cycle.gif", 151 | 152 | // jpg: https://dribbble.com/snootyfox 153 | @"https://d13yacurqjgara.cloudfront.net/users/26059/screenshots/2047158/beerhenge.jpg", 154 | @"https://d13yacurqjgara.cloudfront.net/users/26059/screenshots/2016158/avalanche.jpg", 155 | @"https://d13yacurqjgara.cloudfront.net/users/26059/screenshots/1839353/pilsner.jpg", 156 | @"https://d13yacurqjgara.cloudfront.net/users/26059/screenshots/1833469/porter.jpg", 157 | @"https://d13yacurqjgara.cloudfront.net/users/26059/screenshots/1521183/farmers.jpg", 158 | @"https://d13yacurqjgara.cloudfront.net/users/26059/screenshots/1391053/tents.jpg", 159 | @"https://d13yacurqjgara.cloudfront.net/users/26059/screenshots/1399501/imperial_beer.jpg", 160 | @"https://d13yacurqjgara.cloudfront.net/users/26059/screenshots/1488711/fishin.jpg", 161 | @"https://d13yacurqjgara.cloudfront.net/users/26059/screenshots/1466318/getaway.jpg", 162 | 163 | // animated webp and apng: http://littlesvr.ca/apng/gif_apng_webp.html 164 | @"http://littlesvr.ca/apng/images/BladeRunner.png", 165 | @"http://littlesvr.ca/apng/images/Contact.webp", 166 | ]; 167 | 168 | _imageLinks = links; 169 | [self.tableView reloadData]; 170 | [self scrollViewDidScroll:self.tableView]; 171 | } 172 | 173 | - (void)viewDidAppear:(BOOL)animated { 174 | [super viewDidAppear:animated]; 175 | if (kiOS7Later) { 176 | self.navigationController.navigationBar.barStyle = UIBarStyleBlack; 177 | self.navigationController.navigationBar.tintColor = [UIColor whiteColor]; 178 | } 179 | [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent; 180 | } 181 | 182 | - (void)viewWillDisappear:(BOOL)animated { 183 | [super viewWillDisappear:animated]; 184 | if (kiOS7Later) { 185 | self.navigationController.navigationBar.barStyle = UIBarStyleDefault; 186 | self.navigationController.navigationBar.tintColor = nil; 187 | } 188 | [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDefault; 189 | } 190 | 191 | - (void)reload { 192 | [[YYImageCache sharedCache].memoryCache removeAllObjects]; 193 | [[YYImageCache sharedCache].diskCache removeAllObjectsWithBlock:nil]; 194 | [self.tableView performSelector:@selector(reloadData) afterDelay:0.1]; 195 | } 196 | 197 | - (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { 198 | return NO; 199 | } 200 | 201 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 202 | return _imageLinks.count * 4; 203 | } 204 | 205 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 206 | return kCellHeight; 207 | } 208 | 209 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 210 | YYWebImageExampleCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; 211 | if (!cell) cell = [[YYWebImageExampleCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"]; 212 | [cell setImageURL:[NSURL URLWithString:_imageLinks[indexPath.row % _imageLinks.count]]]; 213 | return cell; 214 | } 215 | 216 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView { 217 | CGFloat viewHeight = scrollView.height + scrollView.contentInset.top; 218 | for (YYWebImageExampleCell *cell in [self.tableView visibleCells]) { 219 | CGFloat y = cell.centerY - scrollView.contentOffset.y; 220 | CGFloat p = y - viewHeight / 2; 221 | CGFloat scale = cos(p / viewHeight * 0.8) * 0.95; 222 | if (kiOS8Later) { 223 | [UIView animateWithDuration:0.15 delay:0 options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState animations:^{ 224 | cell.webImageView.transform = CGAffineTransformMakeScale(scale, scale); 225 | } completion:NULL]; 226 | } else { 227 | cell.webImageView.transform = CGAffineTransformMakeScale(scale, scale); 228 | } 229 | } 230 | } 231 | 232 | @end 233 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/cube@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/cube@2x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/google@2x.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/google@2x.webp -------------------------------------------------------------------------------- /Demo/YYImageDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // YYImageDemo 4 | // 5 | // Created by ibireme on 15/10/16. 6 | // Copyright © 2015年 ibireme. 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 | -------------------------------------------------------------------------------- /Demo/YYImageDemo/mew_baseline.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/mew_baseline.gif -------------------------------------------------------------------------------- /Demo/YYImageDemo/mew_baseline.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/mew_baseline.jpg -------------------------------------------------------------------------------- /Demo/YYImageDemo/mew_baseline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/mew_baseline.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/mew_interlaced.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/mew_interlaced.gif -------------------------------------------------------------------------------- /Demo/YYImageDemo/mew_interlaced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/mew_interlaced.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/mew_progressive.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/mew_progressive.jpg -------------------------------------------------------------------------------- /Demo/YYImageDemo/niconiconi@2x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/niconiconi@2x.gif -------------------------------------------------------------------------------- /Demo/YYImageDemo/nyancat@2x.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/nyancat@2x.webp -------------------------------------------------------------------------------- /Demo/YYImageDemo/pia@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/pia@2x.png -------------------------------------------------------------------------------- /Demo/YYImageDemo/wall-e@2x.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Demo/YYImageDemo/wall-e@2x.webp -------------------------------------------------------------------------------- /Framework/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 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.4 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Framework/YYImage.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D9A995351F05644B0062698B /* YYAnimatedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = D9A9952B1F05644A0062698B /* YYAnimatedImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | D9A995361F05644B0062698B /* YYAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = D9A9952C1F05644A0062698B /* YYAnimatedImageView.m */; }; 12 | D9A995371F05644B0062698B /* YYFrameImage.h in Headers */ = {isa = PBXBuildFile; fileRef = D9A9952D1F05644A0062698B /* YYFrameImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; 13 | D9A995381F05644B0062698B /* YYFrameImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9A9952E1F05644A0062698B /* YYFrameImage.m */; }; 14 | D9A995391F05644B0062698B /* YYImage.h in Headers */ = {isa = PBXBuildFile; fileRef = D9A9952F1F05644A0062698B /* YYImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; 15 | D9A9953A1F05644B0062698B /* YYImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9A995301F05644A0062698B /* YYImage.m */; }; 16 | D9A9953B1F05644B0062698B /* YYImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = D9A995311F05644A0062698B /* YYImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 17 | D9A9953C1F05644B0062698B /* YYImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = D9A995321F05644A0062698B /* YYImageCoder.m */; }; 18 | D9A9953D1F05644B0062698B /* YYSpriteSheetImage.h in Headers */ = {isa = PBXBuildFile; fileRef = D9A995331F05644A0062698B /* YYSpriteSheetImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; 19 | D9A9953E1F05644B0062698B /* YYSpriteSheetImage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9A995341F05644A0062698B /* YYSpriteSheetImage.m */; }; 20 | D9A995481F0564D40062698B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9A995471F0564C40062698B /* UIKit.framework */; }; 21 | D9A995491F0564D40062698B /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9A995461F0564BF0062698B /* CoreFoundation.framework */; }; 22 | D9A9954A1F0564D40062698B /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9A995451F0564BB0062698B /* QuartzCore.framework */; }; 23 | D9A9954B1F0564D40062698B /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9A995441F0564B70062698B /* Accelerate.framework */; }; 24 | D9A9954C1F0564D40062698B /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9A995431F0564B20062698B /* ImageIO.framework */; }; 25 | D9A9954D1F0564D40062698B /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9A995421F0564AF0062698B /* MobileCoreServices.framework */; }; 26 | D9A9954E1F0564D40062698B /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9A995411F0564A70062698B /* AssetsLibrary.framework */; }; 27 | D9A9954F1F0564D40062698B /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D9A995401F05649B0062698B /* libz.tbd */; }; 28 | /* End PBXBuildFile section */ 29 | 30 | /* Begin PBXFileReference section */ 31 | D9A9951F1F0564180062698B /* YYImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = YYImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 32 | D9A995231F0564180062698B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 33 | D9A9952B1F05644A0062698B /* YYAnimatedImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYAnimatedImageView.h; sourceTree = ""; }; 34 | D9A9952C1F05644A0062698B /* YYAnimatedImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYAnimatedImageView.m; sourceTree = ""; }; 35 | D9A9952D1F05644A0062698B /* YYFrameImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYFrameImage.h; sourceTree = ""; }; 36 | D9A9952E1F05644A0062698B /* YYFrameImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYFrameImage.m; sourceTree = ""; }; 37 | D9A9952F1F05644A0062698B /* YYImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYImage.h; sourceTree = ""; }; 38 | D9A995301F05644A0062698B /* YYImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYImage.m; sourceTree = ""; }; 39 | D9A995311F05644A0062698B /* YYImageCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYImageCoder.h; sourceTree = ""; }; 40 | D9A995321F05644A0062698B /* YYImageCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYImageCoder.m; sourceTree = ""; }; 41 | D9A995331F05644A0062698B /* YYSpriteSheetImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYSpriteSheetImage.h; sourceTree = ""; }; 42 | D9A995341F05644A0062698B /* YYSpriteSheetImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYSpriteSheetImage.m; sourceTree = ""; }; 43 | D9A995401F05649B0062698B /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; 44 | D9A995411F0564A70062698B /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; }; 45 | D9A995421F0564AF0062698B /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; 46 | D9A995431F0564B20062698B /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; }; 47 | D9A995441F0564B70062698B /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; 48 | D9A995451F0564BB0062698B /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 49 | D9A995461F0564BF0062698B /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; 50 | D9A995471F0564C40062698B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 51 | /* End PBXFileReference section */ 52 | 53 | /* Begin PBXFrameworksBuildPhase section */ 54 | D9A9951B1F0564180062698B /* Frameworks */ = { 55 | isa = PBXFrameworksBuildPhase; 56 | buildActionMask = 2147483647; 57 | files = ( 58 | D9A995481F0564D40062698B /* UIKit.framework in Frameworks */, 59 | D9A995491F0564D40062698B /* CoreFoundation.framework in Frameworks */, 60 | D9A9954A1F0564D40062698B /* QuartzCore.framework in Frameworks */, 61 | D9A9954B1F0564D40062698B /* Accelerate.framework in Frameworks */, 62 | D9A9954C1F0564D40062698B /* ImageIO.framework in Frameworks */, 63 | D9A9954D1F0564D40062698B /* MobileCoreServices.framework in Frameworks */, 64 | D9A9954E1F0564D40062698B /* AssetsLibrary.framework in Frameworks */, 65 | D9A9954F1F0564D40062698B /* libz.tbd in Frameworks */, 66 | ); 67 | runOnlyForDeploymentPostprocessing = 0; 68 | }; 69 | /* End PBXFrameworksBuildPhase section */ 70 | 71 | /* Begin PBXGroup section */ 72 | D9A995151F0564180062698B = { 73 | isa = PBXGroup; 74 | children = ( 75 | D9A9952A1F05644A0062698B /* YYImage */, 76 | D9A9953F1F05649B0062698B /* Frameworks */, 77 | D9A995201F0564180062698B /* Products */, 78 | ); 79 | sourceTree = ""; 80 | }; 81 | D9A995201F0564180062698B /* Products */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | D9A9951F1F0564180062698B /* YYImage.framework */, 85 | ); 86 | name = Products; 87 | sourceTree = ""; 88 | }; 89 | D9A9952A1F05644A0062698B /* YYImage */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | D9A9952F1F05644A0062698B /* YYImage.h */, 93 | D9A995301F05644A0062698B /* YYImage.m */, 94 | D9A995331F05644A0062698B /* YYSpriteSheetImage.h */, 95 | D9A995341F05644A0062698B /* YYSpriteSheetImage.m */, 96 | D9A9952D1F05644A0062698B /* YYFrameImage.h */, 97 | D9A9952E1F05644A0062698B /* YYFrameImage.m */, 98 | D9A9952B1F05644A0062698B /* YYAnimatedImageView.h */, 99 | D9A9952C1F05644A0062698B /* YYAnimatedImageView.m */, 100 | D9A995311F05644A0062698B /* YYImageCoder.h */, 101 | D9A995321F05644A0062698B /* YYImageCoder.m */, 102 | ); 103 | name = YYImage; 104 | path = ../YYImage; 105 | sourceTree = ""; 106 | }; 107 | D9A9953F1F05649B0062698B /* Frameworks */ = { 108 | isa = PBXGroup; 109 | children = ( 110 | D9A995471F0564C40062698B /* UIKit.framework */, 111 | D9A995461F0564BF0062698B /* CoreFoundation.framework */, 112 | D9A995451F0564BB0062698B /* QuartzCore.framework */, 113 | D9A995441F0564B70062698B /* Accelerate.framework */, 114 | D9A995431F0564B20062698B /* ImageIO.framework */, 115 | D9A995421F0564AF0062698B /* MobileCoreServices.framework */, 116 | D9A995411F0564A70062698B /* AssetsLibrary.framework */, 117 | D9A995401F05649B0062698B /* libz.tbd */, 118 | D9A995231F0564180062698B /* Info.plist */, 119 | ); 120 | name = Frameworks; 121 | sourceTree = ""; 122 | }; 123 | /* End PBXGroup section */ 124 | 125 | /* Begin PBXHeadersBuildPhase section */ 126 | D9A9951C1F0564180062698B /* Headers */ = { 127 | isa = PBXHeadersBuildPhase; 128 | buildActionMask = 2147483647; 129 | files = ( 130 | D9A995371F05644B0062698B /* YYFrameImage.h in Headers */, 131 | D9A995351F05644B0062698B /* YYAnimatedImageView.h in Headers */, 132 | D9A9953B1F05644B0062698B /* YYImageCoder.h in Headers */, 133 | D9A995391F05644B0062698B /* YYImage.h in Headers */, 134 | D9A9953D1F05644B0062698B /* YYSpriteSheetImage.h in Headers */, 135 | ); 136 | runOnlyForDeploymentPostprocessing = 0; 137 | }; 138 | /* End PBXHeadersBuildPhase section */ 139 | 140 | /* Begin PBXNativeTarget section */ 141 | D9A9951E1F0564180062698B /* YYImage */ = { 142 | isa = PBXNativeTarget; 143 | buildConfigurationList = D9A995271F0564180062698B /* Build configuration list for PBXNativeTarget "YYImage" */; 144 | buildPhases = ( 145 | D9A9951A1F0564180062698B /* Sources */, 146 | D9A9951B1F0564180062698B /* Frameworks */, 147 | D9A9951C1F0564180062698B /* Headers */, 148 | D9A9951D1F0564180062698B /* Resources */, 149 | ); 150 | buildRules = ( 151 | ); 152 | dependencies = ( 153 | ); 154 | name = YYImage; 155 | productName = YYImage; 156 | productReference = D9A9951F1F0564180062698B /* YYImage.framework */; 157 | productType = "com.apple.product-type.framework"; 158 | }; 159 | /* End PBXNativeTarget section */ 160 | 161 | /* Begin PBXProject section */ 162 | D9A995161F0564180062698B /* Project object */ = { 163 | isa = PBXProject; 164 | attributes = { 165 | LastUpgradeCheck = 0900; 166 | ORGANIZATIONNAME = ibireme; 167 | TargetAttributes = { 168 | D9A9951E1F0564180062698B = { 169 | CreatedOnToolsVersion = 9.0; 170 | }; 171 | }; 172 | }; 173 | buildConfigurationList = D9A995191F0564180062698B /* Build configuration list for PBXProject "YYImage" */; 174 | compatibilityVersion = "Xcode 8.0"; 175 | developmentRegion = en; 176 | hasScannedForEncodings = 0; 177 | knownRegions = ( 178 | en, 179 | ); 180 | mainGroup = D9A995151F0564180062698B; 181 | productRefGroup = D9A995201F0564180062698B /* Products */; 182 | projectDirPath = ""; 183 | projectRoot = ""; 184 | targets = ( 185 | D9A9951E1F0564180062698B /* YYImage */, 186 | ); 187 | }; 188 | /* End PBXProject section */ 189 | 190 | /* Begin PBXResourcesBuildPhase section */ 191 | D9A9951D1F0564180062698B /* Resources */ = { 192 | isa = PBXResourcesBuildPhase; 193 | buildActionMask = 2147483647; 194 | files = ( 195 | ); 196 | runOnlyForDeploymentPostprocessing = 0; 197 | }; 198 | /* End PBXResourcesBuildPhase section */ 199 | 200 | /* Begin PBXSourcesBuildPhase section */ 201 | D9A9951A1F0564180062698B /* Sources */ = { 202 | isa = PBXSourcesBuildPhase; 203 | buildActionMask = 2147483647; 204 | files = ( 205 | D9A995361F05644B0062698B /* YYAnimatedImageView.m in Sources */, 206 | D9A995381F05644B0062698B /* YYFrameImage.m in Sources */, 207 | D9A9953A1F05644B0062698B /* YYImage.m in Sources */, 208 | D9A9953C1F05644B0062698B /* YYImageCoder.m in Sources */, 209 | D9A9953E1F05644B0062698B /* YYSpriteSheetImage.m in Sources */, 210 | ); 211 | runOnlyForDeploymentPostprocessing = 0; 212 | }; 213 | /* End PBXSourcesBuildPhase section */ 214 | 215 | /* Begin XCBuildConfiguration section */ 216 | D9A995251F0564180062698B /* Debug */ = { 217 | isa = XCBuildConfiguration; 218 | buildSettings = { 219 | ALWAYS_SEARCH_USER_PATHS = NO; 220 | CLANG_ANALYZER_NONNULL = YES; 221 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 222 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 223 | CLANG_CXX_LIBRARY = "libc++"; 224 | CLANG_ENABLE_MODULES = YES; 225 | CLANG_ENABLE_OBJC_ARC = YES; 226 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 227 | CLANG_WARN_BOOL_CONVERSION = YES; 228 | CLANG_WARN_COMMA = YES; 229 | CLANG_WARN_CONSTANT_CONVERSION = YES; 230 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 231 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 232 | CLANG_WARN_EMPTY_BODY = YES; 233 | CLANG_WARN_ENUM_CONVERSION = YES; 234 | CLANG_WARN_INFINITE_RECURSION = YES; 235 | CLANG_WARN_INT_CONVERSION = YES; 236 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 237 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 238 | CLANG_WARN_STRICT_PROTOTYPES = YES; 239 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 240 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 241 | CLANG_WARN_UNREACHABLE_CODE = YES; 242 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 243 | CODE_SIGN_IDENTITY = "iPhone Developer"; 244 | COPY_PHASE_STRIP = NO; 245 | CURRENT_PROJECT_VERSION = 1; 246 | DEBUG_INFORMATION_FORMAT = dwarf; 247 | ENABLE_STRICT_OBJC_MSGSEND = YES; 248 | ENABLE_TESTABILITY = YES; 249 | GCC_C_LANGUAGE_STANDARD = gnu11; 250 | GCC_DYNAMIC_NO_PIC = NO; 251 | GCC_NO_COMMON_BLOCKS = YES; 252 | GCC_OPTIMIZATION_LEVEL = 0; 253 | GCC_PREPROCESSOR_DEFINITIONS = ( 254 | "DEBUG=1", 255 | "$(inherited)", 256 | ); 257 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 258 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 259 | GCC_WARN_UNDECLARED_SELECTOR = YES; 260 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 261 | GCC_WARN_UNUSED_FUNCTION = YES; 262 | GCC_WARN_UNUSED_VARIABLE = YES; 263 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 264 | MTL_ENABLE_DEBUG_INFO = YES; 265 | ONLY_ACTIVE_ARCH = YES; 266 | SDKROOT = iphoneos; 267 | VERSIONING_SYSTEM = "apple-generic"; 268 | VERSION_INFO_PREFIX = ""; 269 | }; 270 | name = Debug; 271 | }; 272 | D9A995261F0564180062698B /* Release */ = { 273 | isa = XCBuildConfiguration; 274 | buildSettings = { 275 | ALWAYS_SEARCH_USER_PATHS = NO; 276 | CLANG_ANALYZER_NONNULL = YES; 277 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 278 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 279 | CLANG_CXX_LIBRARY = "libc++"; 280 | CLANG_ENABLE_MODULES = YES; 281 | CLANG_ENABLE_OBJC_ARC = YES; 282 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 283 | CLANG_WARN_BOOL_CONVERSION = YES; 284 | CLANG_WARN_COMMA = YES; 285 | CLANG_WARN_CONSTANT_CONVERSION = YES; 286 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 287 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 288 | CLANG_WARN_EMPTY_BODY = YES; 289 | CLANG_WARN_ENUM_CONVERSION = YES; 290 | CLANG_WARN_INFINITE_RECURSION = YES; 291 | CLANG_WARN_INT_CONVERSION = YES; 292 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 293 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 294 | CLANG_WARN_STRICT_PROTOTYPES = YES; 295 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 296 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 297 | CLANG_WARN_UNREACHABLE_CODE = YES; 298 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 299 | CODE_SIGN_IDENTITY = "iPhone Developer"; 300 | COPY_PHASE_STRIP = NO; 301 | CURRENT_PROJECT_VERSION = 1; 302 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 303 | ENABLE_NS_ASSERTIONS = NO; 304 | ENABLE_STRICT_OBJC_MSGSEND = YES; 305 | GCC_C_LANGUAGE_STANDARD = gnu11; 306 | GCC_NO_COMMON_BLOCKS = YES; 307 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 308 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 309 | GCC_WARN_UNDECLARED_SELECTOR = YES; 310 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 311 | GCC_WARN_UNUSED_FUNCTION = YES; 312 | GCC_WARN_UNUSED_VARIABLE = YES; 313 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 314 | MTL_ENABLE_DEBUG_INFO = NO; 315 | SDKROOT = iphoneos; 316 | VALIDATE_PRODUCT = YES; 317 | VERSIONING_SYSTEM = "apple-generic"; 318 | VERSION_INFO_PREFIX = ""; 319 | }; 320 | name = Release; 321 | }; 322 | D9A995281F0564180062698B /* Debug */ = { 323 | isa = XCBuildConfiguration; 324 | buildSettings = { 325 | APPLICATION_EXTENSION_API_ONLY = YES; 326 | CODE_SIGN_IDENTITY = ""; 327 | DEFINES_MODULE = YES; 328 | DYLIB_COMPATIBILITY_VERSION = 1; 329 | DYLIB_CURRENT_VERSION = 1; 330 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 331 | INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; 332 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 333 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 334 | PRODUCT_BUNDLE_IDENTIFIER = com.ibireme.YYImage; 335 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 336 | SKIP_INSTALL = YES; 337 | TARGETED_DEVICE_FAMILY = "1,2"; 338 | }; 339 | name = Debug; 340 | }; 341 | D9A995291F0564180062698B /* Release */ = { 342 | isa = XCBuildConfiguration; 343 | buildSettings = { 344 | APPLICATION_EXTENSION_API_ONLY = YES; 345 | CODE_SIGN_IDENTITY = ""; 346 | DEFINES_MODULE = YES; 347 | DYLIB_COMPATIBILITY_VERSION = 1; 348 | DYLIB_CURRENT_VERSION = 1; 349 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 350 | INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; 351 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 352 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 353 | PRODUCT_BUNDLE_IDENTIFIER = com.ibireme.YYImage; 354 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 355 | SKIP_INSTALL = YES; 356 | TARGETED_DEVICE_FAMILY = "1,2"; 357 | }; 358 | name = Release; 359 | }; 360 | /* End XCBuildConfiguration section */ 361 | 362 | /* Begin XCConfigurationList section */ 363 | D9A995191F0564180062698B /* Build configuration list for PBXProject "YYImage" */ = { 364 | isa = XCConfigurationList; 365 | buildConfigurations = ( 366 | D9A995251F0564180062698B /* Debug */, 367 | D9A995261F0564180062698B /* Release */, 368 | ); 369 | defaultConfigurationIsVisible = 0; 370 | defaultConfigurationName = Release; 371 | }; 372 | D9A995271F0564180062698B /* Build configuration list for PBXNativeTarget "YYImage" */ = { 373 | isa = XCConfigurationList; 374 | buildConfigurations = ( 375 | D9A995281F0564180062698B /* Debug */, 376 | D9A995291F0564180062698B /* Release */, 377 | ); 378 | defaultConfigurationIsVisible = 0; 379 | defaultConfigurationName = Release; 380 | }; 381 | /* End XCConfigurationList section */ 382 | }; 383 | rootObject = D9A995161F0564180062698B /* Project object */; 384 | } 385 | -------------------------------------------------------------------------------- /Framework/YYImage.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Framework/YYImage.xcodeproj/xcshareddata/xcschemes/YYImage.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 46 | 47 | 53 | 54 | 55 | 56 | 57 | 58 | 64 | 65 | 71 | 72 | 73 | 74 | 76 | 77 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 ibireme 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 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | YYImage 2 | ============== 3 | [![License MIT](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://raw.githubusercontent.com/ibireme/YYImage/master/LICENSE)  4 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)  5 | [![CocoaPods](http://img.shields.io/cocoapods/v/YYImage.svg?style=flat)](http://cocoapods.org/pods/YYImage)  6 | [![CocoaPods](http://img.shields.io/cocoapods/p/YYImage.svg?style=flat)](http://cocoadocs.org/docsets/YYImage)  7 | [![Support](https://img.shields.io/badge/support-iOS%206%2B%20-blue.svg?style=flat)](https://www.apple.com/nl/ios/)  8 | [![Build Status](https://travis-ci.org/ibireme/YYImage.svg?branch=master)](https://travis-ci.org/ibireme/YYImage) 9 | 10 | Image framework for iOS to display/encode/decode animated WebP, APNG, GIF, and more.
11 | (It's a component of [YYKit](https://github.com/ibireme/YYKit)) 12 | 13 | ![niconiconi~](https://raw.github.com/ibireme/YYImage/master/Demo/YYImageDemo/niconiconi@2x.gif 14 | ) 15 | 16 | Features 17 | ============== 18 | - Display/encode/decode animated image with these types:
    WebP, APNG, GIF. 19 | - Display/encode/decode still image with these types:
    WebP, PNG, GIF, JPEG, JP2, TIFF, BMP, ICO, ICNS. 20 | - Baseline/progressive/interlaced image decode with these types:
    PNG, GIF, JPEG, BMP. 21 | - Display frame based image animation and sprite sheet animation. 22 | - Dynamic memory buffer for lower memory usage. 23 | - Fully compatible with UIImage and UIImageView class. 24 | - Extendable protocol for custom image animation. 25 | - Fully documented. 26 | 27 | Usage 28 | ============== 29 | 30 | ### Display animated image 31 | ```objc 32 | // File: ani@3x.gif 33 | UIImage *image = [YYImage imageNamed:@"ani.gif"]; 34 | UIImageView *imageView = [[YYAnimatedImageView alloc] initWithImage:image]; 35 | [self.view addSubview:imageView]; 36 | ``` 37 | 38 | ### Display frame animation 39 | ```objc 40 | // Files: frame1.png, frame2.png, frame3.png 41 | NSArray *paths = @[@"/ani/frame1.png", @"/ani/frame2.png", @"/ani/frame3.png"]; 42 | NSArray *times = @[@0.1, @0.2, @0.1]; 43 | UIImage *image = [YYFrameImage alloc] initWithImagePaths:paths frameDurations:times repeats:YES]; 44 | UIImageView *imageView = [YYAnimatedImageView alloc] initWithImage:image]; 45 | [self.view addSubview:imageView]; 46 | ``` 47 | 48 | ### Display sprite sheet animation 49 | ```objc 50 | // 8 * 12 sprites in a single sheet image 51 | UIImage *spriteSheet = [UIImage imageNamed:@"sprite-sheet"]; 52 | NSMutableArray *contentRects = [NSMutableArray new]; 53 | NSMutableArray *durations = [NSMutableArray new]; 54 | for (int j = 0; j < 12; j++) { 55 | for (int i = 0; i < 8; i++) { 56 | CGRect rect; 57 | rect.size = CGSizeMake(img.size.width / 8, img.size.height / 12); 58 | rect.origin.x = img.size.width / 8 * i; 59 | rect.origin.y = img.size.height / 12 * j; 60 | [contentRects addObject:[NSValue valueWithCGRect:rect]]; 61 | [durations addObject:@(1 / 60.0)]; 62 | } 63 | } 64 | YYSpriteSheetImage *sprite; 65 | sprite = [[YYSpriteSheetImage alloc] initWithSpriteSheetImage:img 66 | contentRects:contentRects 67 | frameDurations:durations 68 | loopCount:0]; 69 | YYAnimatedImageView *imageView = [YYAnimatedImageView new]; 70 | imageView.size = CGSizeMake(img.size.width / 8, img.size.height / 12); 71 | imageView.image = sprite; 72 | [self.view addSubview:imageView]; 73 | ``` 74 | 75 | ### Animation control 76 | ```objc 77 | YYAnimatedImageView *imageView = ...; 78 | // pause: 79 | [imageView stopAnimating]; 80 | // play: 81 | [imageView startAnimating]; 82 | // set frame index: 83 | imageView.currentAnimatedImageIndex = 12; 84 | // get current status 85 | image.currentIsPlayingAnimation; 86 | ``` 87 | 88 | ### Image decoder 89 | ```objc 90 | // Decode single frame: 91 | NSData *data = [NSData dataWithContentsOfFile:@"/tmp/image.webp"]; 92 | YYImageDecoder *decoder = [YYImageDecoder decoderWithData:data scale:2.0]; 93 | UIImage image = [decoder frameAtIndex:0 decodeForDisplay:YES].image; 94 | 95 | // Progressive: 96 | NSMutableData *data = [NSMutableData new]; 97 | YYImageDecoder *decoder = [[YYImageDecoder alloc] initWithScale:2.0]; 98 | while(newDataArrived) { 99 | [data appendData:newData]; 100 | [decoder updateData:data final:NO]; 101 | if (decoder.frameCount > 0) { 102 | UIImage image = [decoder frameAtIndex:0 decodeForDisplay:YES].image; 103 | // progressive display... 104 | } 105 | } 106 | [decoder updateData:data final:YES]; 107 | UIImage image = [decoder frameAtIndex:0 decodeForDisplay:YES].image; 108 | // final display... 109 | ``` 110 | 111 | ### Image encoder 112 | ```objc 113 | // Encode still image: 114 | YYImageEncoder *jpegEncoder = [[YYImageEncoder alloc] initWithType:YYImageTypeJPEG]; 115 | jpegEncoder.quality = 0.9; 116 | [jpegEncoder addImage:image duration:0]; 117 | NSData jpegData = [jpegEncoder encode]; 118 | 119 | // Encode animated image: 120 | YYImageEncoder *webpEncoder = [[YYImageEncoder alloc] initWithType:YYImageTypeWebP]; 121 | webpEncoder.loopCount = 5; 122 | [webpEncoder addImage:image0 duration:0.1]; 123 | [webpEncoder addImage:image1 duration:0.15]; 124 | [webpEncoder addImage:image2 duration:0.2]; 125 | NSData webpData = [webpEncoder encode]; 126 | ``` 127 | 128 | ### Image type detection 129 | ```objc 130 | // Get image type from image data 131 | YYImageType type = YYImageDetectType(data); 132 | if (type == YYImageTypePNG) ... 133 | ``` 134 | 135 | Installation 136 | ============== 137 | 138 | ### CocoaPods 139 | 140 | 1. Update cocoapods to the latest version. 141 | 2. Add `pod 'YYImage'` to your Podfile. 142 | 3. Run `pod install` or `pod update`. 143 | 4. Import \. 144 | 5. Notice: it doesn't include WebP subspec by default, if you want to support WebP format, you may add `pod 'YYImage/WebP'` to your Podfile. 145 | 146 | ### Carthage 147 | 148 | 1. Add `github "ibireme/YYImage"` to your Cartfile. 149 | 2. Run `carthage update --platform ios` and add the framework to your project. 150 | 3. Import \. 151 | 4. Notice: carthage framework doesn't include WebP component, if you want to support WebP format, use CocoaPods or install manually. 152 | 153 | ### Manually 154 | 155 | 1. Download all the files in the YYImage subdirectory. 156 | 2. Add the source files to your Xcode project. 157 | 3. Link with required frameworks: 158 | * UIKit 159 | * CoreFoundation 160 | * QuartzCore 161 | * AssetsLibrary 162 | * ImageIO 163 | * Accelerate 164 | * MobileCoreServices 165 | * libz 166 | 4. Import `YYImage.h`. 167 | 5. Notice: if you want to support WebP format, you may add `Vendor/WebP.framework`(static library) to your Xcode project. 168 | 169 | FAQ 170 | ============== 171 | _Q: Why I can't display WebP image?_ 172 | 173 | A: Make sure you added the `WebP.framework` in your project. You may call `YYImageWebPAvailable()` to check whether the WebP subspec is installed correctly. 174 | 175 | _Q: Why I can't play APNG animation?_ 176 | 177 | A: You should disable the `Compress PNG Files` and `Remove Text Metadata From PNG Files` in your project's build settings. Or you can rename your APNG file's extension name with `apng`. 178 | 179 | Documentation 180 | ============== 181 | Full API documentation is available on [CocoaDocs](http://cocoadocs.org/docsets/YYImage/).
182 | You can also install documentation locally using [appledoc](https://github.com/tomaz/appledoc). 183 | 184 | 185 | 186 | Requirements 187 | ============== 188 | This library requires `iOS 6.0+` and `Xcode 8.0+`. 189 | 190 | 191 | License 192 | ============== 193 | YYImage is provided under the MIT license. See LICENSE file for details. 194 | 195 | 196 |

197 | --- 198 | 中文介绍 199 | ============== 200 | YYImage: 功能强大的 iOS 图像框架。
201 | (该项目是 [YYKit](https://github.com/ibireme/YYKit) 组件之一) 202 | 203 | ![niconiconi~](https://raw.github.com/ibireme/YYImage/master/Demo/YYImageDemo/niconiconi@2x.gif 204 | ) 205 | 206 | 特性 207 | ============== 208 | - 支持以下类型动画图像的播放/编码/解码:
209 |     WebP, APNG, GIF。 210 | - 支持以下类型静态图像的显示/编码/解码:
211 |     WebP, PNG, GIF, JPEG, JP2, TIFF, BMP, ICO, ICNS。 212 | - 支持以下类型图片的渐进式/逐行扫描/隔行扫描解码:
213 |     PNG, GIF, JPEG, BMP。 214 | - 支持多张图片构成的帧动画播放,支持单张图片的 sprite sheet 动画。 215 | - 高效的动态内存缓存管理,以保证高性能低内存的动画播放。 216 | - 完全兼容 UIImage 和 UIImageView,使用方便。 217 | - 保留可扩展的接口,以支持自定义动画。 218 | - 每个类和方法都有完善的文档注释。 219 | 220 | 221 | 用法 222 | ============== 223 | 224 | ### 显示动画类型的图片 225 | ```objc 226 | // 文件: ani@3x.gif 227 | UIImage *image = [YYImage imageNamed:@"ani.gif"]; 228 | UIImageView *imageView = [[YYAnimatedImageView alloc] initWithImage:image]; 229 | [self.view addSubview:imageView]; 230 | ``` 231 | 232 | ### 播放帧动画 233 | ```objc 234 | // 文件: frame1.png, frame2.png, frame3.png 235 | NSArray *paths = @[@"/ani/frame1.png", @"/ani/frame2.png", @"/ani/frame3.png"]; 236 | NSArray *times = @[@0.1, @0.2, @0.1]; 237 | UIImage *image = [YYFrameImage alloc] initWithImagePaths:paths frameDurations:times repeats:YES]; 238 | UIImageView *imageView = [YYAnimatedImageView alloc] initWithImage:image]; 239 | [self.view addSubview:imageView]; 240 | ``` 241 | 242 | ### 播放 sprite sheet 动画 243 | ```objc 244 | // 8 * 12 sprites in a single sheet image 245 | UIImage *spriteSheet = [UIImage imageNamed:@"sprite-sheet"]; 246 | NSMutableArray *contentRects = [NSMutableArray new]; 247 | NSMutableArray *durations = [NSMutableArray new]; 248 | for (int j = 0; j < 12; j++) { 249 | for (int i = 0; i < 8; i++) { 250 | CGRect rect; 251 | rect.size = CGSizeMake(img.size.width / 8, img.size.height / 12); 252 | rect.origin.x = img.size.width / 8 * i; 253 | rect.origin.y = img.size.height / 12 * j; 254 | [contentRects addObject:[NSValue valueWithCGRect:rect]]; 255 | [durations addObject:@(1 / 60.0)]; 256 | } 257 | } 258 | YYSpriteSheetImage *sprite; 259 | sprite = [[YYSpriteSheetImage alloc] initWithSpriteSheetImage:img 260 | contentRects:contentRects 261 | frameDurations:durations 262 | loopCount:0]; 263 | YYAnimatedImageView *imageView = [YYAnimatedImageView new]; 264 | imageView.size = CGSizeMake(img.size.width / 8, img.size.height / 12); 265 | imageView.image = sprite; 266 | [self.view addSubview:imageView]; 267 | ``` 268 | 269 | ### 动画播放控制 270 | ```objc 271 | YYAnimatedImageView *imageView = ...; 272 | // 暂停: 273 | [imageView stopAnimating]; 274 | // 播放: 275 | [imageView startAnimating]; 276 | // 设置播放进度: 277 | imageView.currentAnimatedImageIndex = 12; 278 | // 获取播放状态: 279 | image.currentIsPlayingAnimation; 280 | //上面两个属性都支持 KVO。 281 | ``` 282 | 283 | ### 图片解码 284 | ```objc 285 | // 解码单帧图片: 286 | NSData *data = [NSData dataWithContentsOfFile:@"/tmp/image.webp"]; 287 | YYImageDecoder *decoder = [YYImageDecoder decoderWithData:data scale:2.0]; 288 | UIImage image = [decoder frameAtIndex:0 decodeForDisplay:YES].image; 289 | 290 | // 渐进式图片解码 (可用于图片下载显示): 291 | NSMutableData *data = [NSMutableData new]; 292 | YYImageDecoder *decoder = [[YYImageDecoder alloc] initWithScale:2.0]; 293 | while(newDataArrived) { 294 | [data appendData:newData]; 295 | [decoder updateData:data final:NO]; 296 | if (decoder.frameCount > 0) { 297 | UIImage image = [decoder frameAtIndex:0 decodeForDisplay:YES].image; 298 | // progressive display... 299 | } 300 | } 301 | [decoder updateData:data final:YES]; 302 | UIImage image = [decoder frameAtIndex:0 decodeForDisplay:YES].image; 303 | // final display... 304 | ``` 305 | 306 | ### 图片编码 307 | ```objc 308 | // 编码静态图 (支持各种常见图片格式): 309 | YYImageEncoder *jpegEncoder = [[YYImageEncoder alloc] initWithType:YYImageTypeJPEG]; 310 | jpegEncoder.quality = 0.9; 311 | [jpegEncoder addImage:image duration:0]; 312 | NSData jpegData = [jpegEncoder encode]; 313 | 314 | // 编码动态图 (支持 GIF/APNG/WebP): 315 | YYImageEncoder *webpEncoder = [[YYImageEncoder alloc] initWithType:YYImageTypeWebP]; 316 | webpEncoder.loopCount = 5; 317 | [webpEncoder addImage:image0 duration:0.1]; 318 | [webpEncoder addImage:image1 duration:0.15]; 319 | [webpEncoder addImage:image2 duration:0.2]; 320 | NSData webpData = [webpEncoder encode]; 321 | ``` 322 | 323 | ### 图片类型探测 324 | ```objc 325 | // 获取图片类型 326 | YYImageType type = YYImageDetectType(data); 327 | if (type == YYImageTypePNG) ... 328 | ``` 329 | 330 | 安装 331 | ============== 332 | 333 | ### CocoaPods 334 | 335 | 1. 将 cocoapods 更新至最新版本. 336 | 2. 在 Podfile 中添加 `pod 'YYImage'`。 337 | 3. 执行 `pod install` 或 `pod update`。 338 | 4. 导入 \。 339 | 5. 注意:pod 配置并没有包含 WebP 组件, 如果你需要支持 WebP,可以在 Podfile 中添加 `pod 'YYImage/WebP'`。 340 | 341 | ### Carthage 342 | 343 | 1. 在 Cartfile 中添加 `github "ibireme/YYImage"`。 344 | 2. 执行 `carthage update --platform ios` 并将生成的 framework 添加到你的工程。 345 | 3. 导入 \。 346 | 4. 注意:carthage framework 并没有包含 WebP 组件。如果你需要支持 WebP,可以用 CocoaPods 安装,或者手动安装。 347 | 348 | ### 手动安装 349 | 350 | 1. 下载 YYImage 文件夹内的所有内容。 351 | 2. 将 YYImage 内的源文件添加(拖放)到你的工程。 352 | 3. 链接以下 frameworks: 353 | * UIKit 354 | * CoreFoundation 355 | * QuartzCore 356 | * AssetsLibrary 357 | * ImageIO 358 | * Accelerate 359 | * MobileCoreServices 360 | * libz 361 | 4. 导入 `YYImage.h`。 362 | 5. 注意:如果你需要支持 WebP,可以将 `Vendor/WebP.framework`(静态库) 加入你的工程。 363 | 364 | 常见问题 365 | ============== 366 | _Q: 为什么我不能显示 WebP 图片?_ 367 | 368 | A: 确保 `WebP.framework` 已经被添加到你的工程内了。你可以调用 `YYImageWebPAvailable()` 来检查一下 WebP 组件是否被正确安装。 369 | 370 | _Q: 为什么我不能播放 APNG 动画?_ 371 | 372 | A: 你应该禁用 Build Settings 中的 `Compress PNG Files` 和 `Remove Text Metadata From PNG Files`. 或者你也可以把 APNG 文件的扩展名改为`apng`. 373 | 374 | 文档 375 | ============== 376 | 你可以在 [CocoaDocs](http://cocoadocs.org/docsets/YYImage/) 查看在线 API 文档,也可以用 [appledoc](https://github.com/tomaz/appledoc) 本地生成文档。 377 | 378 | 379 | 系统要求 380 | ============== 381 | 该项目最低支持 `iOS 6.0` 和 `Xcode 8.0`。 382 | 383 | 384 | 许可证 385 | ============== 386 | YYImage 使用 MIT 许可证,详情见 LICENSE 文件。 387 | 388 | 389 | 相关链接 390 | ============== 391 | [移动端图片格式调研](https://blog.ibireme.com/2015/11/02/mobile_image_benchmark/)
392 | 393 | [iOS 处理图片的一些小 Tip](https://blog.ibireme.com/2015/11/02/ios_image_tips/) 394 | 395 | -------------------------------------------------------------------------------- /Vendor/WebP.framework/Headers/config.h: -------------------------------------------------------------------------------- 1 | /* src/webp/config.h. Generated from config.h.in by configure. */ 2 | /* src/webp/config.h.in. Generated from configure.ac by autoheader. */ 3 | 4 | /* Define if building universal (internal helper macro) */ 5 | /* #undef AC_APPLE_UNIVERSAL_BUILD */ 6 | 7 | /* Set to 1 if __builtin_bswap16 is available */ 8 | #define HAVE_BUILTIN_BSWAP16 1 9 | 10 | /* Set to 1 if __builtin_bswap32 is available */ 11 | #define HAVE_BUILTIN_BSWAP32 1 12 | 13 | /* Set to 1 if __builtin_bswap64 is available */ 14 | #define HAVE_BUILTIN_BSWAP64 1 15 | 16 | /* Define to 1 if you have the header file. */ 17 | #define HAVE_DLFCN_H 1 18 | 19 | /* Define to 1 if you have the header file. */ 20 | /* #undef HAVE_GLUT_GLUT_H */ 21 | 22 | /* Define to 1 if you have the header file. */ 23 | /* #undef HAVE_GL_GLUT_H */ 24 | 25 | /* Define to 1 if you have the header file. */ 26 | #define HAVE_INTTYPES_H 1 27 | 28 | /* Define to 1 if you have the header file. */ 29 | #define HAVE_MEMORY_H 1 30 | 31 | /* Define to 1 if you have the header file. */ 32 | /* #undef HAVE_OPENGL_GLUT_H */ 33 | 34 | /* Have PTHREAD_PRIO_INHERIT. */ 35 | #define HAVE_PTHREAD_PRIO_INHERIT 1 36 | 37 | /* Define to 1 if you have the header file. */ 38 | /* #undef HAVE_SHLWAPI_H */ 39 | 40 | /* Define to 1 if you have the header file. */ 41 | #define HAVE_STDINT_H 1 42 | 43 | /* Define to 1 if you have the header file. */ 44 | #define HAVE_STDLIB_H 1 45 | 46 | /* Define to 1 if you have the header file. */ 47 | #define HAVE_STRINGS_H 1 48 | 49 | /* Define to 1 if you have the header file. */ 50 | #define HAVE_STRING_H 1 51 | 52 | /* Define to 1 if you have the header file. */ 53 | #define HAVE_SYS_STAT_H 1 54 | 55 | /* Define to 1 if you have the header file. */ 56 | #define HAVE_SYS_TYPES_H 1 57 | 58 | /* Define to 1 if you have the header file. */ 59 | #define HAVE_UNISTD_H 1 60 | 61 | /* Define to 1 if you have the header file. */ 62 | /* #undef HAVE_WINCODEC_H */ 63 | 64 | /* Define to 1 if you have the header file. */ 65 | /* #undef HAVE_WINDOWS_H */ 66 | 67 | /* Define to the sub-directory in which libtool stores uninstalled libraries. 68 | */ 69 | #define LT_OBJDIR ".libs/" 70 | 71 | /* Name of package */ 72 | #define PACKAGE "libwebp" 73 | 74 | /* Define to the address where bug reports for this package should be sent. */ 75 | #define PACKAGE_BUGREPORT "https://bugs.chromium.org/p/webp" 76 | 77 | /* Define to the full name of this package. */ 78 | #define PACKAGE_NAME "libwebp" 79 | 80 | /* Define to the full name and version of this package. */ 81 | #define PACKAGE_STRING "libwebp 0.6.0" 82 | 83 | /* Define to the one symbol short name of this package. */ 84 | #define PACKAGE_TARNAME "libwebp" 85 | 86 | /* Define to the home page for this package. */ 87 | #define PACKAGE_URL "http://developers.google.com/speed/webp" 88 | 89 | /* Define to the version of this package. */ 90 | #define PACKAGE_VERSION "0.6.0" 91 | 92 | /* Define to necessary symbol if this constant uses a non-standard name on 93 | your system. */ 94 | /* #undef PTHREAD_CREATE_JOINABLE */ 95 | 96 | /* Define to 1 if you have the ANSI C header files. */ 97 | #define STDC_HEADERS 1 98 | 99 | /* Version number of package */ 100 | #define VERSION "0.6.0" 101 | 102 | /* Enable experimental code */ 103 | /* #undef WEBP_EXPERIMENTAL_FEATURES */ 104 | 105 | /* Set to 1 if AVX2 is supported */ 106 | /* #undef WEBP_HAVE_AVX2 */ 107 | 108 | /* Set to 1 if GIF library is installed */ 109 | /* #undef WEBP_HAVE_GIF */ 110 | 111 | /* Set to 1 if OpenGL is supported */ 112 | /* #undef WEBP_HAVE_GL */ 113 | 114 | /* Set to 1 if JPEG library is installed */ 115 | /* #undef WEBP_HAVE_JPEG */ 116 | 117 | /* Set to 1 if NEON is supported */ 118 | /* #undef WEBP_HAVE_NEON */ 119 | 120 | /* Set to 1 if runtime detection of NEON is enabled */ 121 | /* #undef WEBP_HAVE_NEON_RTCD */ 122 | 123 | /* Set to 1 if PNG library is installed */ 124 | /* #undef WEBP_HAVE_PNG */ 125 | 126 | /* Set to 1 if SSE2 is supported */ 127 | /* #undef WEBP_HAVE_SSE2 */ 128 | 129 | /* Set to 1 if SSE4.1 is supported */ 130 | /* #undef WEBP_HAVE_SSE41 */ 131 | 132 | /* Set to 1 if TIFF library is installed */ 133 | /* #undef WEBP_HAVE_TIFF */ 134 | 135 | /* Undefine this to disable thread support. */ 136 | #define WEBP_USE_THREAD 1 137 | 138 | /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most 139 | significant byte first (like Motorola and SPARC, unlike Intel). */ 140 | #if defined AC_APPLE_UNIVERSAL_BUILD 141 | # if defined __BIG_ENDIAN__ 142 | # define WORDS_BIGENDIAN 1 143 | # endif 144 | #else 145 | # ifndef WORDS_BIGENDIAN 146 | /* # undef WORDS_BIGENDIAN */ 147 | # endif 148 | #endif 149 | -------------------------------------------------------------------------------- /Vendor/WebP.framework/Headers/demux.h: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Google Inc. All Rights Reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style license 4 | // that can be found in the COPYING file in the root of the source 5 | // tree. An additional intellectual property rights grant can be found 6 | // in the file PATENTS. All contributing project authors may 7 | // be found in the AUTHORS file in the root of the source tree. 8 | // ----------------------------------------------------------------------------- 9 | // 10 | // Demux API. 11 | // Enables extraction of image and extended format data from WebP files. 12 | 13 | // Code Example: Demuxing WebP data to extract all the frames, ICC profile 14 | // and EXIF/XMP metadata. 15 | /* 16 | WebPDemuxer* demux = WebPDemux(&webp_data); 17 | 18 | uint32_t width = WebPDemuxGetI(demux, WEBP_FF_CANVAS_WIDTH); 19 | uint32_t height = WebPDemuxGetI(demux, WEBP_FF_CANVAS_HEIGHT); 20 | // ... (Get information about the features present in the WebP file). 21 | uint32_t flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS); 22 | 23 | // ... (Iterate over all frames). 24 | WebPIterator iter; 25 | if (WebPDemuxGetFrame(demux, 1, &iter)) { 26 | do { 27 | // ... (Consume 'iter'; e.g. Decode 'iter.fragment' with WebPDecode(), 28 | // ... and get other frame properties like width, height, offsets etc. 29 | // ... see 'struct WebPIterator' below for more info). 30 | } while (WebPDemuxNextFrame(&iter)); 31 | WebPDemuxReleaseIterator(&iter); 32 | } 33 | 34 | // ... (Extract metadata). 35 | WebPChunkIterator chunk_iter; 36 | if (flags & ICCP_FLAG) WebPDemuxGetChunk(demux, "ICCP", 1, &chunk_iter); 37 | // ... (Consume the ICC profile in 'chunk_iter.chunk'). 38 | WebPDemuxReleaseChunkIterator(&chunk_iter); 39 | if (flags & EXIF_FLAG) WebPDemuxGetChunk(demux, "EXIF", 1, &chunk_iter); 40 | // ... (Consume the EXIF metadata in 'chunk_iter.chunk'). 41 | WebPDemuxReleaseChunkIterator(&chunk_iter); 42 | if (flags & XMP_FLAG) WebPDemuxGetChunk(demux, "XMP ", 1, &chunk_iter); 43 | // ... (Consume the XMP metadata in 'chunk_iter.chunk'). 44 | WebPDemuxReleaseChunkIterator(&chunk_iter); 45 | WebPDemuxDelete(demux); 46 | */ 47 | 48 | #ifndef WEBP_WEBP_DEMUX_H_ 49 | #define WEBP_WEBP_DEMUX_H_ 50 | 51 | #include "./decode.h" // for WEBP_CSP_MODE 52 | #include "./mux_types.h" 53 | 54 | #ifdef __cplusplus 55 | extern "C" { 56 | #endif 57 | 58 | #define WEBP_DEMUX_ABI_VERSION 0x0107 // MAJOR(8b) + MINOR(8b) 59 | 60 | // Note: forward declaring enumerations is not allowed in (strict) C and C++, 61 | // the types are left here for reference. 62 | // typedef enum WebPDemuxState WebPDemuxState; 63 | // typedef enum WebPFormatFeature WebPFormatFeature; 64 | typedef struct WebPDemuxer WebPDemuxer; 65 | typedef struct WebPIterator WebPIterator; 66 | typedef struct WebPChunkIterator WebPChunkIterator; 67 | typedef struct WebPAnimInfo WebPAnimInfo; 68 | typedef struct WebPAnimDecoderOptions WebPAnimDecoderOptions; 69 | 70 | //------------------------------------------------------------------------------ 71 | 72 | // Returns the version number of the demux library, packed in hexadecimal using 73 | // 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507. 74 | WEBP_EXTERN(int) WebPGetDemuxVersion(void); 75 | 76 | //------------------------------------------------------------------------------ 77 | // Life of a Demux object 78 | 79 | typedef enum WebPDemuxState { 80 | WEBP_DEMUX_PARSE_ERROR = -1, // An error occurred while parsing. 81 | WEBP_DEMUX_PARSING_HEADER = 0, // Not enough data to parse full header. 82 | WEBP_DEMUX_PARSED_HEADER = 1, // Header parsing complete, 83 | // data may be available. 84 | WEBP_DEMUX_DONE = 2 // Entire file has been parsed. 85 | } WebPDemuxState; 86 | 87 | // Internal, version-checked, entry point 88 | WEBP_EXTERN(WebPDemuxer*) WebPDemuxInternal( 89 | const WebPData*, int, WebPDemuxState*, int); 90 | 91 | // Parses the full WebP file given by 'data'. For single images the WebP file 92 | // header alone or the file header and the chunk header may be absent. 93 | // Returns a WebPDemuxer object on successful parse, NULL otherwise. 94 | static WEBP_INLINE WebPDemuxer* WebPDemux(const WebPData* data) { 95 | return WebPDemuxInternal(data, 0, NULL, WEBP_DEMUX_ABI_VERSION); 96 | } 97 | 98 | // Parses the possibly incomplete WebP file given by 'data'. 99 | // If 'state' is non-NULL it will be set to indicate the status of the demuxer. 100 | // Returns NULL in case of error or if there isn't enough data to start parsing; 101 | // and a WebPDemuxer object on successful parse. 102 | // Note that WebPDemuxer keeps internal pointers to 'data' memory segment. 103 | // If this data is volatile, the demuxer object should be deleted (by calling 104 | // WebPDemuxDelete()) and WebPDemuxPartial() called again on the new data. 105 | // This is usually an inexpensive operation. 106 | static WEBP_INLINE WebPDemuxer* WebPDemuxPartial( 107 | const WebPData* data, WebPDemuxState* state) { 108 | return WebPDemuxInternal(data, 1, state, WEBP_DEMUX_ABI_VERSION); 109 | } 110 | 111 | // Frees memory associated with 'dmux'. 112 | WEBP_EXTERN(void) WebPDemuxDelete(WebPDemuxer* dmux); 113 | 114 | //------------------------------------------------------------------------------ 115 | // Data/information extraction. 116 | 117 | typedef enum WebPFormatFeature { 118 | WEBP_FF_FORMAT_FLAGS, // Extended format flags present in the 'VP8X' chunk. 119 | WEBP_FF_CANVAS_WIDTH, 120 | WEBP_FF_CANVAS_HEIGHT, 121 | WEBP_FF_LOOP_COUNT, 122 | WEBP_FF_BACKGROUND_COLOR, 123 | WEBP_FF_FRAME_COUNT // Number of frames present in the demux object. 124 | // In case of a partial demux, this is the number of 125 | // frames seen so far, with the last frame possibly 126 | // being partial. 127 | } WebPFormatFeature; 128 | 129 | // Get the 'feature' value from the 'dmux'. 130 | // NOTE: values are only valid if WebPDemux() was used or WebPDemuxPartial() 131 | // returned a state > WEBP_DEMUX_PARSING_HEADER. 132 | WEBP_EXTERN(uint32_t) WebPDemuxGetI( 133 | const WebPDemuxer* dmux, WebPFormatFeature feature); 134 | 135 | //------------------------------------------------------------------------------ 136 | // Frame iteration. 137 | 138 | struct WebPIterator { 139 | int frame_num; 140 | int num_frames; // equivalent to WEBP_FF_FRAME_COUNT. 141 | int x_offset, y_offset; // offset relative to the canvas. 142 | int width, height; // dimensions of this frame. 143 | int duration; // display duration in milliseconds. 144 | WebPMuxAnimDispose dispose_method; // dispose method for the frame. 145 | int complete; // true if 'fragment' contains a full frame. partial images 146 | // may still be decoded with the WebP incremental decoder. 147 | WebPData fragment; // The frame given by 'frame_num'. Note for historical 148 | // reasons this is called a fragment. 149 | int has_alpha; // True if the frame contains transparency. 150 | WebPMuxAnimBlend blend_method; // Blend operation for the frame. 151 | 152 | uint32_t pad[2]; // padding for later use. 153 | void* private_; // for internal use only. 154 | }; 155 | 156 | // Retrieves frame 'frame_number' from 'dmux'. 157 | // 'iter->fragment' points to the frame on return from this function. 158 | // Setting 'frame_number' equal to 0 will return the last frame of the image. 159 | // Returns false if 'dmux' is NULL or frame 'frame_number' is not present. 160 | // Call WebPDemuxReleaseIterator() when use of the iterator is complete. 161 | // NOTE: 'dmux' must persist for the lifetime of 'iter'. 162 | WEBP_EXTERN(int) WebPDemuxGetFrame( 163 | const WebPDemuxer* dmux, int frame_number, WebPIterator* iter); 164 | 165 | // Sets 'iter->fragment' to point to the next ('iter->frame_num' + 1) or 166 | // previous ('iter->frame_num' - 1) frame. These functions do not loop. 167 | // Returns true on success, false otherwise. 168 | WEBP_EXTERN(int) WebPDemuxNextFrame(WebPIterator* iter); 169 | WEBP_EXTERN(int) WebPDemuxPrevFrame(WebPIterator* iter); 170 | 171 | // Releases any memory associated with 'iter'. 172 | // Must be called before any subsequent calls to WebPDemuxGetChunk() on the same 173 | // iter. Also, must be called before destroying the associated WebPDemuxer with 174 | // WebPDemuxDelete(). 175 | WEBP_EXTERN(void) WebPDemuxReleaseIterator(WebPIterator* iter); 176 | 177 | //------------------------------------------------------------------------------ 178 | // Chunk iteration. 179 | 180 | struct WebPChunkIterator { 181 | // The current and total number of chunks with the fourcc given to 182 | // WebPDemuxGetChunk(). 183 | int chunk_num; 184 | int num_chunks; 185 | WebPData chunk; // The payload of the chunk. 186 | 187 | uint32_t pad[6]; // padding for later use 188 | void* private_; 189 | }; 190 | 191 | // Retrieves the 'chunk_number' instance of the chunk with id 'fourcc' from 192 | // 'dmux'. 193 | // 'fourcc' is a character array containing the fourcc of the chunk to return, 194 | // e.g., "ICCP", "XMP ", "EXIF", etc. 195 | // Setting 'chunk_number' equal to 0 will return the last chunk in a set. 196 | // Returns true if the chunk is found, false otherwise. Image related chunk 197 | // payloads are accessed through WebPDemuxGetFrame() and related functions. 198 | // Call WebPDemuxReleaseChunkIterator() when use of the iterator is complete. 199 | // NOTE: 'dmux' must persist for the lifetime of the iterator. 200 | WEBP_EXTERN(int) WebPDemuxGetChunk(const WebPDemuxer* dmux, 201 | const char fourcc[4], int chunk_number, 202 | WebPChunkIterator* iter); 203 | 204 | // Sets 'iter->chunk' to point to the next ('iter->chunk_num' + 1) or previous 205 | // ('iter->chunk_num' - 1) chunk. These functions do not loop. 206 | // Returns true on success, false otherwise. 207 | WEBP_EXTERN(int) WebPDemuxNextChunk(WebPChunkIterator* iter); 208 | WEBP_EXTERN(int) WebPDemuxPrevChunk(WebPChunkIterator* iter); 209 | 210 | // Releases any memory associated with 'iter'. 211 | // Must be called before destroying the associated WebPDemuxer with 212 | // WebPDemuxDelete(). 213 | WEBP_EXTERN(void) WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter); 214 | 215 | //------------------------------------------------------------------------------ 216 | // WebPAnimDecoder API 217 | // 218 | // This API allows decoding (possibly) animated WebP images. 219 | // 220 | // Code Example: 221 | /* 222 | WebPAnimDecoderOptions dec_options; 223 | WebPAnimDecoderOptionsInit(&dec_options); 224 | // Tune 'dec_options' as needed. 225 | WebPAnimDecoder* dec = WebPAnimDecoderNew(webp_data, &dec_options); 226 | WebPAnimInfo anim_info; 227 | WebPAnimDecoderGetInfo(dec, &anim_info); 228 | for (uint32_t i = 0; i < anim_info.loop_count; ++i) { 229 | while (WebPAnimDecoderHasMoreFrames(dec)) { 230 | uint8_t* buf; 231 | int timestamp; 232 | WebPAnimDecoderGetNext(dec, &buf, ×tamp); 233 | // ... (Render 'buf' based on 'timestamp'). 234 | // ... (Do NOT free 'buf', as it is owned by 'dec'). 235 | } 236 | WebPAnimDecoderReset(dec); 237 | } 238 | const WebPDemuxer* demuxer = WebPAnimDecoderGetDemuxer(dec); 239 | // ... (Do something using 'demuxer'; e.g. get EXIF/XMP/ICC data). 240 | WebPAnimDecoderDelete(dec); 241 | */ 242 | 243 | typedef struct WebPAnimDecoder WebPAnimDecoder; // Main opaque object. 244 | 245 | // Global options. 246 | struct WebPAnimDecoderOptions { 247 | // Output colorspace. Only the following modes are supported: 248 | // MODE_RGBA, MODE_BGRA, MODE_rgbA and MODE_bgrA. 249 | WEBP_CSP_MODE color_mode; 250 | int use_threads; // If true, use multi-threaded decoding. 251 | uint32_t padding[7]; // Padding for later use. 252 | }; 253 | 254 | // Internal, version-checked, entry point. 255 | WEBP_EXTERN(int) WebPAnimDecoderOptionsInitInternal( 256 | WebPAnimDecoderOptions*, int); 257 | 258 | // Should always be called, to initialize a fresh WebPAnimDecoderOptions 259 | // structure before modification. Returns false in case of version mismatch. 260 | // WebPAnimDecoderOptionsInit() must have succeeded before using the 261 | // 'dec_options' object. 262 | static WEBP_INLINE int WebPAnimDecoderOptionsInit( 263 | WebPAnimDecoderOptions* dec_options) { 264 | return WebPAnimDecoderOptionsInitInternal(dec_options, 265 | WEBP_DEMUX_ABI_VERSION); 266 | } 267 | 268 | // Internal, version-checked, entry point. 269 | WEBP_EXTERN(WebPAnimDecoder*) WebPAnimDecoderNewInternal( 270 | const WebPData*, const WebPAnimDecoderOptions*, int); 271 | 272 | // Creates and initializes a WebPAnimDecoder object. 273 | // Parameters: 274 | // webp_data - (in) WebP bitstream. This should remain unchanged during the 275 | // lifetime of the output WebPAnimDecoder object. 276 | // dec_options - (in) decoding options. Can be passed NULL to choose 277 | // reasonable defaults (in particular, color mode MODE_RGBA 278 | // will be picked). 279 | // Returns: 280 | // A pointer to the newly created WebPAnimDecoder object, or NULL in case of 281 | // parsing error, invalid option or memory error. 282 | static WEBP_INLINE WebPAnimDecoder* WebPAnimDecoderNew( 283 | const WebPData* webp_data, const WebPAnimDecoderOptions* dec_options) { 284 | return WebPAnimDecoderNewInternal(webp_data, dec_options, 285 | WEBP_DEMUX_ABI_VERSION); 286 | } 287 | 288 | // Global information about the animation.. 289 | struct WebPAnimInfo { 290 | uint32_t canvas_width; 291 | uint32_t canvas_height; 292 | uint32_t loop_count; 293 | uint32_t bgcolor; 294 | uint32_t frame_count; 295 | uint32_t pad[4]; // padding for later use 296 | }; 297 | 298 | // Get global information about the animation. 299 | // Parameters: 300 | // dec - (in) decoder instance to get information from. 301 | // info - (out) global information fetched from the animation. 302 | // Returns: 303 | // True on success. 304 | WEBP_EXTERN(int) WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec, 305 | WebPAnimInfo* info); 306 | 307 | // Fetch the next frame from 'dec' based on options supplied to 308 | // WebPAnimDecoderNew(). This will be a fully reconstructed canvas of size 309 | // 'canvas_width * 4 * canvas_height', and not just the frame sub-rectangle. The 310 | // returned buffer 'buf' is valid only until the next call to 311 | // WebPAnimDecoderGetNext(), WebPAnimDecoderReset() or WebPAnimDecoderDelete(). 312 | // Parameters: 313 | // dec - (in/out) decoder instance from which the next frame is to be fetched. 314 | // buf - (out) decoded frame. 315 | // timestamp - (out) timestamp of the frame in milliseconds. 316 | // Returns: 317 | // False if any of the arguments are NULL, or if there is a parsing or 318 | // decoding error, or if there are no more frames. Otherwise, returns true. 319 | WEBP_EXTERN(int) WebPAnimDecoderGetNext(WebPAnimDecoder* dec, 320 | uint8_t** buf, int* timestamp); 321 | 322 | // Check if there are more frames left to decode. 323 | // Parameters: 324 | // dec - (in) decoder instance to be checked. 325 | // Returns: 326 | // True if 'dec' is not NULL and some frames are yet to be decoded. 327 | // Otherwise, returns false. 328 | WEBP_EXTERN(int) WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec); 329 | 330 | // Resets the WebPAnimDecoder object, so that next call to 331 | // WebPAnimDecoderGetNext() will restart decoding from 1st frame. This would be 332 | // helpful when all frames need to be decoded multiple times (e.g. 333 | // info.loop_count times) without destroying and recreating the 'dec' object. 334 | // Parameters: 335 | // dec - (in/out) decoder instance to be reset 336 | WEBP_EXTERN(void) WebPAnimDecoderReset(WebPAnimDecoder* dec); 337 | 338 | // Grab the internal demuxer object. 339 | // Getting the demuxer object can be useful if one wants to use operations only 340 | // available through demuxer; e.g. to get XMP/EXIF/ICC metadata. The returned 341 | // demuxer object is owned by 'dec' and is valid only until the next call to 342 | // WebPAnimDecoderDelete(). 343 | // 344 | // Parameters: 345 | // dec - (in) decoder instance from which the demuxer object is to be fetched. 346 | WEBP_EXTERN(const WebPDemuxer*) WebPAnimDecoderGetDemuxer( 347 | const WebPAnimDecoder* dec); 348 | 349 | // Deletes the WebPAnimDecoder object. 350 | // Parameters: 351 | // dec - (in/out) decoder instance to be deleted 352 | WEBP_EXTERN(void) WebPAnimDecoderDelete(WebPAnimDecoder* dec); 353 | 354 | #ifdef __cplusplus 355 | } // extern "C" 356 | #endif 357 | 358 | #endif /* WEBP_WEBP_DEMUX_H_ */ 359 | -------------------------------------------------------------------------------- /Vendor/WebP.framework/Headers/format_constants.h: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Google Inc. All Rights Reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style license 4 | // that can be found in the COPYING file in the root of the source 5 | // tree. An additional intellectual property rights grant can be found 6 | // in the file PATENTS. All contributing project authors may 7 | // be found in the AUTHORS file in the root of the source tree. 8 | // ----------------------------------------------------------------------------- 9 | // 10 | // Internal header for constants related to WebP file format. 11 | // 12 | // Author: Urvang (urvang@google.com) 13 | 14 | #ifndef WEBP_WEBP_FORMAT_CONSTANTS_H_ 15 | #define WEBP_WEBP_FORMAT_CONSTANTS_H_ 16 | 17 | // Create fourcc of the chunk from the chunk tag characters. 18 | #define MKFOURCC(a, b, c, d) ((a) | (b) << 8 | (c) << 16 | (uint32_t)(d) << 24) 19 | 20 | // VP8 related constants. 21 | #define VP8_SIGNATURE 0x9d012a // Signature in VP8 data. 22 | #define VP8_MAX_PARTITION0_SIZE (1 << 19) // max size of mode partition 23 | #define VP8_MAX_PARTITION_SIZE (1 << 24) // max size for token partition 24 | #define VP8_FRAME_HEADER_SIZE 10 // Size of the frame header within VP8 data. 25 | 26 | // VP8L related constants. 27 | #define VP8L_SIGNATURE_SIZE 1 // VP8L signature size. 28 | #define VP8L_MAGIC_BYTE 0x2f // VP8L signature byte. 29 | #define VP8L_IMAGE_SIZE_BITS 14 // Number of bits used to store 30 | // width and height. 31 | #define VP8L_VERSION_BITS 3 // 3 bits reserved for version. 32 | #define VP8L_VERSION 0 // version 0 33 | #define VP8L_FRAME_HEADER_SIZE 5 // Size of the VP8L frame header. 34 | 35 | #define MAX_PALETTE_SIZE 256 36 | #define MAX_CACHE_BITS 11 37 | #define HUFFMAN_CODES_PER_META_CODE 5 38 | #define ARGB_BLACK 0xff000000 39 | 40 | #define DEFAULT_CODE_LENGTH 8 41 | #define MAX_ALLOWED_CODE_LENGTH 15 42 | 43 | #define NUM_LITERAL_CODES 256 44 | #define NUM_LENGTH_CODES 24 45 | #define NUM_DISTANCE_CODES 40 46 | #define CODE_LENGTH_CODES 19 47 | 48 | #define MIN_HUFFMAN_BITS 2 // min number of Huffman bits 49 | #define MAX_HUFFMAN_BITS 9 // max number of Huffman bits 50 | 51 | #define TRANSFORM_PRESENT 1 // The bit to be written when next data 52 | // to be read is a transform. 53 | #define NUM_TRANSFORMS 4 // Maximum number of allowed transform 54 | // in a bitstream. 55 | typedef enum { 56 | PREDICTOR_TRANSFORM = 0, 57 | CROSS_COLOR_TRANSFORM = 1, 58 | SUBTRACT_GREEN = 2, 59 | COLOR_INDEXING_TRANSFORM = 3 60 | } VP8LImageTransformType; 61 | 62 | // Alpha related constants. 63 | #define ALPHA_HEADER_LEN 1 64 | #define ALPHA_NO_COMPRESSION 0 65 | #define ALPHA_LOSSLESS_COMPRESSION 1 66 | #define ALPHA_PREPROCESSED_LEVELS 1 67 | 68 | // Mux related constants. 69 | #define TAG_SIZE 4 // Size of a chunk tag (e.g. "VP8L"). 70 | #define CHUNK_SIZE_BYTES 4 // Size needed to store chunk's size. 71 | #define CHUNK_HEADER_SIZE 8 // Size of a chunk header. 72 | #define RIFF_HEADER_SIZE 12 // Size of the RIFF header ("RIFFnnnnWEBP"). 73 | #define ANMF_CHUNK_SIZE 16 // Size of an ANMF chunk. 74 | #define ANIM_CHUNK_SIZE 6 // Size of an ANIM chunk. 75 | #define VP8X_CHUNK_SIZE 10 // Size of a VP8X chunk. 76 | 77 | #define MAX_CANVAS_SIZE (1 << 24) // 24-bit max for VP8X width/height. 78 | #define MAX_IMAGE_AREA (1ULL << 32) // 32-bit max for width x height. 79 | #define MAX_LOOP_COUNT (1 << 16) // maximum value for loop-count 80 | #define MAX_DURATION (1 << 24) // maximum duration 81 | #define MAX_POSITION_OFFSET (1 << 24) // maximum frame x/y offset 82 | 83 | // Maximum chunk payload is such that adding the header and padding won't 84 | // overflow a uint32_t. 85 | #define MAX_CHUNK_PAYLOAD (~0U - CHUNK_HEADER_SIZE - 1) 86 | 87 | #endif /* WEBP_WEBP_FORMAT_CONSTANTS_H_ */ 88 | -------------------------------------------------------------------------------- /Vendor/WebP.framework/Headers/mux_types.h: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Google Inc. All Rights Reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style license 4 | // that can be found in the COPYING file in the root of the source 5 | // tree. An additional intellectual property rights grant can be found 6 | // in the file PATENTS. All contributing project authors may 7 | // be found in the AUTHORS file in the root of the source tree. 8 | // ----------------------------------------------------------------------------- 9 | // 10 | // Data-types common to the mux and demux libraries. 11 | // 12 | // Author: Urvang (urvang@google.com) 13 | 14 | #ifndef WEBP_WEBP_MUX_TYPES_H_ 15 | #define WEBP_WEBP_MUX_TYPES_H_ 16 | 17 | #include // free() 18 | #include // memset() 19 | #include "./types.h" 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | // Note: forward declaring enumerations is not allowed in (strict) C and C++, 26 | // the types are left here for reference. 27 | // typedef enum WebPFeatureFlags WebPFeatureFlags; 28 | // typedef enum WebPMuxAnimDispose WebPMuxAnimDispose; 29 | // typedef enum WebPMuxAnimBlend WebPMuxAnimBlend; 30 | typedef struct WebPData WebPData; 31 | 32 | // VP8X Feature Flags. 33 | typedef enum WebPFeatureFlags { 34 | ANIMATION_FLAG = 0x00000002, 35 | XMP_FLAG = 0x00000004, 36 | EXIF_FLAG = 0x00000008, 37 | ALPHA_FLAG = 0x00000010, 38 | ICCP_FLAG = 0x00000020, 39 | 40 | ALL_VALID_FLAGS = 0x0000003e 41 | } WebPFeatureFlags; 42 | 43 | // Dispose method (animation only). Indicates how the area used by the current 44 | // frame is to be treated before rendering the next frame on the canvas. 45 | typedef enum WebPMuxAnimDispose { 46 | WEBP_MUX_DISPOSE_NONE, // Do not dispose. 47 | WEBP_MUX_DISPOSE_BACKGROUND // Dispose to background color. 48 | } WebPMuxAnimDispose; 49 | 50 | // Blend operation (animation only). Indicates how transparent pixels of the 51 | // current frame are blended with those of the previous canvas. 52 | typedef enum WebPMuxAnimBlend { 53 | WEBP_MUX_BLEND, // Blend. 54 | WEBP_MUX_NO_BLEND // Do not blend. 55 | } WebPMuxAnimBlend; 56 | 57 | // Data type used to describe 'raw' data, e.g., chunk data 58 | // (ICC profile, metadata) and WebP compressed image data. 59 | struct WebPData { 60 | const uint8_t* bytes; 61 | size_t size; 62 | }; 63 | 64 | // Initializes the contents of the 'webp_data' object with default values. 65 | static WEBP_INLINE void WebPDataInit(WebPData* webp_data) { 66 | if (webp_data != NULL) { 67 | memset(webp_data, 0, sizeof(*webp_data)); 68 | } 69 | } 70 | 71 | // Clears the contents of the 'webp_data' object by calling free(). Does not 72 | // deallocate the object itself. 73 | static WEBP_INLINE void WebPDataClear(WebPData* webp_data) { 74 | if (webp_data != NULL) { 75 | free((void*)webp_data->bytes); 76 | WebPDataInit(webp_data); 77 | } 78 | } 79 | 80 | // Allocates necessary storage for 'dst' and copies the contents of 'src'. 81 | // Returns true on success. 82 | static WEBP_INLINE int WebPDataCopy(const WebPData* src, WebPData* dst) { 83 | if (src == NULL || dst == NULL) return 0; 84 | WebPDataInit(dst); 85 | if (src->bytes != NULL && src->size != 0) { 86 | dst->bytes = (uint8_t*)malloc(src->size); 87 | if (dst->bytes == NULL) return 0; 88 | memcpy((void*)dst->bytes, src->bytes, src->size); 89 | dst->size = src->size; 90 | } 91 | return 1; 92 | } 93 | 94 | #ifdef __cplusplus 95 | } // extern "C" 96 | #endif 97 | 98 | #endif /* WEBP_WEBP_MUX_TYPES_H_ */ 99 | -------------------------------------------------------------------------------- /Vendor/WebP.framework/Headers/types.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Google Inc. All Rights Reserved. 2 | // 3 | // Use of this source code is governed by a BSD-style license 4 | // that can be found in the COPYING file in the root of the source 5 | // tree. An additional intellectual property rights grant can be found 6 | // in the file PATENTS. All contributing project authors may 7 | // be found in the AUTHORS file in the root of the source tree. 8 | // ----------------------------------------------------------------------------- 9 | // 10 | // Common types 11 | // 12 | // Author: Skal (pascal.massimino@gmail.com) 13 | 14 | #ifndef WEBP_WEBP_TYPES_H_ 15 | #define WEBP_WEBP_TYPES_H_ 16 | 17 | #include // for size_t 18 | 19 | #ifndef _MSC_VER 20 | #include 21 | #if defined(__cplusplus) || !defined(__STRICT_ANSI__) || \ 22 | (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) 23 | #define WEBP_INLINE inline 24 | #else 25 | #define WEBP_INLINE 26 | #endif 27 | #else 28 | typedef signed char int8_t; 29 | typedef unsigned char uint8_t; 30 | typedef signed short int16_t; 31 | typedef unsigned short uint16_t; 32 | typedef signed int int32_t; 33 | typedef unsigned int uint32_t; 34 | typedef unsigned long long int uint64_t; 35 | typedef long long int int64_t; 36 | #define WEBP_INLINE __forceinline 37 | #endif /* _MSC_VER */ 38 | 39 | #ifndef WEBP_EXTERN 40 | // This explicitly marks library functions and allows for changing the 41 | // signature for e.g., Windows DLL builds. 42 | # if defined(__GNUC__) && __GNUC__ >= 4 43 | # define WEBP_EXTERN(type) extern __attribute__ ((visibility ("default"))) type 44 | # else 45 | # define WEBP_EXTERN(type) extern type 46 | # endif /* __GNUC__ >= 4 */ 47 | #endif /* WEBP_EXTERN */ 48 | 49 | // Macro to check ABI compatibility (same major revision number) 50 | #define WEBP_ABI_IS_INCOMPATIBLE(a, b) (((a) >> 8) != ((b) >> 8)) 51 | 52 | #endif /* WEBP_WEBP_TYPES_H_ */ 53 | -------------------------------------------------------------------------------- /Vendor/WebP.framework/WebP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYImage/42ba209608cb332887a33ebcae1bde50c52b151d/Vendor/WebP.framework/WebP -------------------------------------------------------------------------------- /Vendor/WebP.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This script generates 'WebP.framework' (static library). 4 | # An iOS app can decode WebP images by including 'WebP.framework'. 5 | # 6 | # 1. Download the latest libwebp source code from 7 | # http://downloads.webmproject.org/releases/webp/index.html 8 | # 2. Use this script instead of the original 'iosbuild.sh' to build the WebP.framework. 9 | # It will build all modules, include mux, demux, coder and decoder. 10 | # 11 | # Notice: You should use Xcode 7 (or above) to support bitcode. 12 | 13 | set -e 14 | 15 | # Extract the latest SDK version from the final field of the form: iphoneosX.Y 16 | readonly SDK=$(xcodebuild -showsdks \ 17 | | grep iphoneos | sort | tail -n 1 | awk '{print substr($NF, 9)}' 18 | ) 19 | # Extract Xcode version. 20 | readonly XCODE=$(xcodebuild -version | grep Xcode | cut -d " " -f2) 21 | if [[ -z "${XCODE}" ]]; then 22 | echo "Xcode not available" 23 | exit 1 24 | fi 25 | 26 | readonly OLDPATH=${PATH} 27 | 28 | # Add iPhoneOS-V6 to the list of platforms below if you need armv6 support. 29 | # Note that iPhoneOS-V6 support is not available with the iOS6 SDK. 30 | PLATFORMS="iPhoneSimulator iPhoneSimulator64" 31 | PLATFORMS+=" iPhoneOS-V7 iPhoneOS-V7s iPhoneOS-V7-arm64" 32 | readonly PLATFORMS 33 | readonly SRCDIR=$(dirname $0) 34 | readonly TOPDIR=$(pwd) 35 | readonly BUILDDIR="${TOPDIR}/iosbuild" 36 | readonly TARGETDIR="${TOPDIR}/WebP.framework" 37 | readonly DEVELOPER=$(xcode-select --print-path) 38 | readonly PLATFORMSROOT="${DEVELOPER}/Platforms" 39 | readonly LIPO=$(xcrun -sdk iphoneos${SDK} -find lipo) 40 | LIBLIST='' 41 | 42 | if [[ -z "${SDK}" ]]; then 43 | echo "iOS SDK not available" 44 | exit 1 45 | else 46 | echo "iOS SDK Version ${SDK}" 47 | fi 48 | 49 | rm -rf ${BUILDDIR} 50 | rm -rf ${TARGETDIR} 51 | mkdir -p ${BUILDDIR} 52 | mkdir -p ${TARGETDIR}/Headers/ 53 | 54 | if [[ ! -e ${SRCDIR}/configure ]]; then 55 | if ! (cd ${SRCDIR} && sh autogen.sh); then 56 | cat < 'MIT', :file => 'LICENSE' } 6 | s.authors = { 'ibireme' => 'ibireme@gmail.com' } 7 | s.social_media_url = 'http://blog.ibireme.com' 8 | s.homepage = 'https://github.com/ibireme/YYImage' 9 | s.platform = :ios, '6.0' 10 | s.ios.deployment_target = '6.0' 11 | s.source = { :git => 'https://github.com/ibireme/YYImage.git', :tag => s.version.to_s } 12 | 13 | s.requires_arc = true 14 | s.default_subspec = 'Core' 15 | 16 | s.subspec 'Core' do |core| 17 | core.source_files = 'YYImage/*.{h,m}' 18 | core.public_header_files = 'YYImage/*.{h}' 19 | core.libraries = 'z' 20 | core.frameworks = 'UIKit', 'CoreFoundation', 'QuartzCore', 'AssetsLibrary', 'ImageIO', 'Accelerate', 'MobileCoreServices' 21 | end 22 | 23 | s.subspec 'WebP' do |webp| 24 | webp.dependency 'YYImage/Core' 25 | webp.ios.vendored_frameworks = 'Vendor/WebP.framework' 26 | end 27 | 28 | s.subspec 'libwebp' do |libwebp| 29 | libwebp.dependency 'YYImage/Core' 30 | libwebp.dependency 'libwebp' 31 | libwebp.xcconfig = { 32 | 'USER_HEADER_SEARCH_PATHS' => '$(inherited) $(SRCROOT)/libwebp/src' 33 | } 34 | end 35 | 36 | end 37 | -------------------------------------------------------------------------------- /YYImage/YYAnimatedImageView.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYAnimatedImageView.h 3 | // YYImage 4 | // 5 | // Created by ibireme on 14/10/19. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /** 17 | An image view for displaying animated image. 18 | 19 | @discussion It is a fully compatible `UIImageView` subclass. 20 | If the `image` or `highlightedImage` property adopt to the `YYAnimatedImage` protocol, 21 | then it can be used to play the multi-frame animation. The animation can also be 22 | controlled with the UIImageView methods `-startAnimating`, `-stopAnimating` and `-isAnimating`. 23 | 24 | This view request the frame data just in time. When the device has enough free memory, 25 | this view may cache some or all future frames in an inner buffer for lower CPU cost. 26 | Buffer size is dynamically adjusted based on the current state of the device memory. 27 | 28 | Sample Code: 29 | 30 | // ani@3x.gif 31 | YYImage *image = [YYImage imageNamed:@"ani"]; 32 | YYAnimatedImageView *imageView = [YYAnimatedImageView alloc] initWithImage:image]; 33 | [view addSubView:imageView]; 34 | */ 35 | @interface YYAnimatedImageView : UIImageView 36 | 37 | /** 38 | If the image has more than one frame, set this value to `YES` will automatically 39 | play/stop the animation when the view become visible/invisible. 40 | 41 | The default value is `YES`. 42 | */ 43 | @property (nonatomic) BOOL autoPlayAnimatedImage; 44 | 45 | /** 46 | Index of the currently displayed frame (index from 0). 47 | 48 | Set a new value to this property will cause to display the new frame immediately. 49 | If the new value is invalid, this method has no effect. 50 | 51 | You can add an observer to this property to observe the playing status. 52 | */ 53 | @property (nonatomic) NSUInteger currentAnimatedImageIndex; 54 | 55 | /** 56 | Whether the image view is playing animation currently. 57 | 58 | You can add an observer to this property to observe the playing status. 59 | */ 60 | @property (nonatomic, readonly) BOOL currentIsPlayingAnimation; 61 | 62 | /** 63 | The animation timer's runloop mode, default is `NSRunLoopCommonModes`. 64 | 65 | Set this property to `NSDefaultRunLoopMode` will make the animation pause during 66 | UIScrollView scrolling. 67 | */ 68 | @property (nonatomic, copy) NSString *runloopMode; 69 | 70 | /** 71 | The max size (in bytes) for inner frame buffer size, default is 0 (dynamically). 72 | 73 | When the device has enough free memory, this view will request and decode some or 74 | all future frame image into an inner buffer. If this property's value is 0, then 75 | the max buffer size will be dynamically adjusted based on the current state of 76 | the device free memory. Otherwise, the buffer size will be limited by this value. 77 | 78 | When receive memory warning or app enter background, the buffer will be released 79 | immediately, and may grow back at the right time. 80 | */ 81 | @property (nonatomic) NSUInteger maxBufferSize; 82 | 83 | @end 84 | 85 | 86 | 87 | /** 88 | The YYAnimatedImage protocol declares the required methods for animated image 89 | display with YYAnimatedImageView. 90 | 91 | Subclass a UIImage and implement this protocol, so that instances of that class 92 | can be set to YYAnimatedImageView.image or YYAnimatedImageView.highlightedImage 93 | to display animation. 94 | 95 | See `YYImage` and `YYFrameImage` for example. 96 | */ 97 | @protocol YYAnimatedImage 98 | @required 99 | /// Total animated frame count. 100 | /// It the frame count is less than 1, then the methods below will be ignored. 101 | - (NSUInteger)animatedImageFrameCount; 102 | 103 | /// Animation loop count, 0 means infinite looping. 104 | - (NSUInteger)animatedImageLoopCount; 105 | 106 | /// Bytes per frame (in memory). It may used to optimize memory buffer size. 107 | - (NSUInteger)animatedImageBytesPerFrame; 108 | 109 | /// Returns the frame image from a specified index. 110 | /// This method may be called on background thread. 111 | /// @param index Frame index (zero based). 112 | - (nullable UIImage *)animatedImageFrameAtIndex:(NSUInteger)index; 113 | 114 | /// Returns the frames's duration from a specified index. 115 | /// @param index Frame index (zero based). 116 | - (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index; 117 | 118 | @optional 119 | /// A rectangle in image coordinates defining the subrectangle of the image that 120 | /// will be displayed. The rectangle should not outside the image's bounds. 121 | /// It may used to display sprite animation with a single image (sprite sheet). 122 | - (CGRect)animatedImageContentsRectAtIndex:(NSUInteger)index; 123 | @end 124 | 125 | NS_ASSUME_NONNULL_END 126 | -------------------------------------------------------------------------------- /YYImage/YYFrameImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYFrameImage.h 3 | // YYImage 4 | // 5 | // Created by ibireme on 14/12/9. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | #import 16 | #elif __has_include() 17 | #import 18 | #else 19 | #import "YYAnimatedImageView.h" 20 | #endif 21 | 22 | NS_ASSUME_NONNULL_BEGIN 23 | 24 | /** 25 | An image to display frame-based animation. 26 | 27 | @discussion It is a fully compatible `UIImage` subclass. 28 | It only support system image format such as png and jpeg. 29 | The animation can be played by YYAnimatedImageView. 30 | 31 | Sample Code: 32 | 33 | NSArray *paths = @[@"/ani/frame1.png", @"/ani/frame2.png", @"/ani/frame3.png"]; 34 | NSArray *times = @[@0.1, @0.2, @0.1]; 35 | YYFrameImage *image = [YYFrameImage alloc] initWithImagePaths:paths frameDurations:times repeats:YES]; 36 | YYAnimatedImageView *imageView = [YYAnimatedImageView alloc] initWithImage:image]; 37 | [view addSubView:imageView]; 38 | */ 39 | @interface YYFrameImage : UIImage 40 | 41 | /** 42 | Create a frame animated image from files. 43 | 44 | @param paths An array of NSString objects, contains the full or 45 | partial path to each image file. 46 | e.g. @[@"/ani/1.png",@"/ani/2.png",@"/ani/3.png"] 47 | 48 | @param oneFrameDuration The duration (in seconds) per frame. 49 | 50 | @param loopCount The animation loop count, 0 means infinite. 51 | 52 | @return An initialized YYFrameImage object, or nil when an error occurs. 53 | */ 54 | - (nullable instancetype)initWithImagePaths:(NSArray *)paths 55 | oneFrameDuration:(NSTimeInterval)oneFrameDuration 56 | loopCount:(NSUInteger)loopCount; 57 | 58 | /** 59 | Create a frame animated image from files. 60 | 61 | @param paths An array of NSString objects, contains the full or 62 | partial path to each image file. 63 | e.g. @[@"/ani/frame1.png",@"/ani/frame2.png",@"/ani/frame3.png"] 64 | 65 | @param frameDurations An array of NSNumber objects, contains the duration (in seconds) per frame. 66 | e.g. @[@0.1, @0.2, @0.3]; 67 | 68 | @param loopCount The animation loop count, 0 means infinite. 69 | 70 | @return An initialized YYFrameImage object, or nil when an error occurs. 71 | */ 72 | - (nullable instancetype)initWithImagePaths:(NSArray *)paths 73 | frameDurations:(NSArray *)frameDurations 74 | loopCount:(NSUInteger)loopCount; 75 | 76 | /** 77 | Create a frame animated image from an array of data. 78 | 79 | @param dataArray An array of NSData objects. 80 | 81 | @param oneFrameDuration The duration (in seconds) per frame. 82 | 83 | @param loopCount The animation loop count, 0 means infinite. 84 | 85 | @return An initialized YYFrameImage object, or nil when an error occurs. 86 | */ 87 | - (nullable instancetype)initWithImageDataArray:(NSArray *)dataArray 88 | oneFrameDuration:(NSTimeInterval)oneFrameDuration 89 | loopCount:(NSUInteger)loopCount; 90 | 91 | /** 92 | Create a frame animated image from an array of data. 93 | 94 | @param dataArray An array of NSData objects. 95 | 96 | @param frameDurations An array of NSNumber objects, contains the duration (in seconds) per frame. 97 | e.g. @[@0.1, @0.2, @0.3]; 98 | 99 | @param loopCount The animation loop count, 0 means infinite. 100 | 101 | @return An initialized YYFrameImage object, or nil when an error occurs. 102 | */ 103 | - (nullable instancetype)initWithImageDataArray:(NSArray *)dataArray 104 | frameDurations:(NSArray *)frameDurations 105 | loopCount:(NSUInteger)loopCount; 106 | 107 | @end 108 | 109 | NS_ASSUME_NONNULL_END 110 | -------------------------------------------------------------------------------- /YYImage/YYFrameImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYFrameImage.m 3 | // YYImage 4 | // 5 | // Created by ibireme on 14/12/9. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYFrameImage.h" 13 | #import "YYImageCoder.h" 14 | 15 | 16 | /** 17 | Return the path scale. 18 | 19 | e.g. 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
Path Scale
"icon.png" 1
"icon@2x.png" 2
"icon@2.5x.png" 2.5
"icon@2x" 1
"icon@2x..png" 1
"icon@2x.png/" 1
29 | */ 30 | static CGFloat _NSStringPathScale(NSString *string) { 31 | if (string.length == 0 || [string hasSuffix:@"/"]) return 1; 32 | NSString *name = string.stringByDeletingPathExtension; 33 | __block CGFloat scale = 1; 34 | 35 | NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:@"@[0-9]+\\.?[0-9]*x$" options:NSRegularExpressionAnchorsMatchLines error:nil]; 36 | [pattern enumerateMatchesInString:name options:kNilOptions range:NSMakeRange(0, name.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { 37 | if (result.range.location >= 3) { 38 | scale = [string substringWithRange:NSMakeRange(result.range.location + 1, result.range.length - 2)].doubleValue; 39 | } 40 | }]; 41 | 42 | return scale; 43 | } 44 | 45 | 46 | 47 | @implementation YYFrameImage { 48 | NSUInteger _loopCount; 49 | NSUInteger _oneFrameBytes; 50 | NSArray *_imagePaths; 51 | NSArray *_imageDatas; 52 | NSArray *_frameDurations; 53 | } 54 | 55 | - (instancetype)initWithImagePaths:(NSArray *)paths oneFrameDuration:(NSTimeInterval)oneFrameDuration loopCount:(NSUInteger)loopCount { 56 | NSMutableArray *durations = [NSMutableArray new]; 57 | for (int i = 0, max = (int)paths.count; i < max; i++) { 58 | [durations addObject:@(oneFrameDuration)]; 59 | } 60 | return [self initWithImagePaths:paths frameDurations:durations loopCount:loopCount]; 61 | } 62 | 63 | - (instancetype)initWithImagePaths:(NSArray *)paths frameDurations:(NSArray *)frameDurations loopCount:(NSUInteger)loopCount { 64 | if (paths.count == 0) return nil; 65 | if (paths.count != frameDurations.count) return nil; 66 | 67 | NSString *firstPath = paths[0]; 68 | NSData *firstData = [NSData dataWithContentsOfFile:firstPath]; 69 | CGFloat scale = _NSStringPathScale(firstPath); 70 | UIImage *firstCG = [[[UIImage alloc] initWithData:firstData] yy_imageByDecoded]; 71 | self = [self initWithCGImage:firstCG.CGImage scale:scale orientation:UIImageOrientationUp]; 72 | if (!self) return nil; 73 | long frameByte = CGImageGetBytesPerRow(firstCG.CGImage) * CGImageGetHeight(firstCG.CGImage); 74 | _oneFrameBytes = (NSUInteger)frameByte; 75 | _imagePaths = paths.copy; 76 | _frameDurations = frameDurations.copy; 77 | _loopCount = loopCount; 78 | 79 | return self; 80 | } 81 | 82 | - (instancetype)initWithImageDataArray:(NSArray *)dataArray oneFrameDuration:(NSTimeInterval)oneFrameDuration loopCount:(NSUInteger)loopCount { 83 | NSMutableArray *durations = [NSMutableArray new]; 84 | for (int i = 0, max = (int)dataArray.count; i < max; i++) { 85 | [durations addObject:@(oneFrameDuration)]; 86 | } 87 | return [self initWithImageDataArray:dataArray frameDurations:durations loopCount:loopCount]; 88 | } 89 | 90 | - (instancetype)initWithImageDataArray:(NSArray *)dataArray frameDurations:(NSArray *)frameDurations loopCount:(NSUInteger)loopCount { 91 | if (dataArray.count == 0) return nil; 92 | if (dataArray.count != frameDurations.count) return nil; 93 | 94 | NSData *firstData = dataArray[0]; 95 | CGFloat scale = [UIScreen mainScreen].scale; 96 | UIImage *firstCG = [[[UIImage alloc] initWithData:firstData] yy_imageByDecoded]; 97 | self = [self initWithCGImage:firstCG.CGImage scale:scale orientation:UIImageOrientationUp]; 98 | if (!self) return nil; 99 | long frameByte = CGImageGetBytesPerRow(firstCG.CGImage) * CGImageGetHeight(firstCG.CGImage); 100 | _oneFrameBytes = (NSUInteger)frameByte; 101 | _imageDatas = dataArray.copy; 102 | _frameDurations = frameDurations.copy; 103 | _loopCount = loopCount; 104 | 105 | return self; 106 | } 107 | 108 | #pragma mark - YYAnimtedImage 109 | 110 | - (NSUInteger)animatedImageFrameCount { 111 | if (_imagePaths) { 112 | return _imagePaths.count; 113 | } else if (_imageDatas) { 114 | return _imageDatas.count; 115 | } else { 116 | return 1; 117 | } 118 | } 119 | 120 | - (NSUInteger)animatedImageLoopCount { 121 | return _loopCount; 122 | } 123 | 124 | - (NSUInteger)animatedImageBytesPerFrame { 125 | return _oneFrameBytes; 126 | } 127 | 128 | - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index { 129 | if (_imagePaths) { 130 | if (index >= _imagePaths.count) return nil; 131 | NSString *path = _imagePaths[index]; 132 | CGFloat scale = _NSStringPathScale(path); 133 | NSData *data = [NSData dataWithContentsOfFile:path]; 134 | return [[UIImage imageWithData:data scale:scale] yy_imageByDecoded]; 135 | } else if (_imageDatas) { 136 | if (index >= _imageDatas.count) return nil; 137 | NSData *data = _imageDatas[index]; 138 | return [[UIImage imageWithData:data scale:[UIScreen mainScreen].scale] yy_imageByDecoded]; 139 | } else { 140 | return index == 0 ? self : nil; 141 | } 142 | } 143 | 144 | - (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index { 145 | if (index >= _frameDurations.count) return 0; 146 | NSNumber *num = _frameDurations[index]; 147 | return [num doubleValue]; 148 | } 149 | 150 | @end 151 | -------------------------------------------------------------------------------- /YYImage/YYImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYImage.h 3 | // YYImage 4 | // 5 | // Created by ibireme on 14/10/20. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | FOUNDATION_EXPORT double YYImageVersionNumber; 16 | FOUNDATION_EXPORT const unsigned char YYImageVersionString[]; 17 | #import 18 | #import 19 | #import 20 | #import 21 | #elif __has_include() 22 | #import 23 | #import 24 | #import 25 | #import 26 | #else 27 | #import "YYFrameImage.h" 28 | #import "YYSpriteSheetImage.h" 29 | #import "YYImageCoder.h" 30 | #import "YYAnimatedImageView.h" 31 | #endif 32 | 33 | NS_ASSUME_NONNULL_BEGIN 34 | 35 | 36 | /** 37 | A YYImage object is a high-level way to display animated image data. 38 | 39 | @discussion It is a fully compatible `UIImage` subclass. It extends the UIImage 40 | to support animated WebP, APNG and GIF format image data decoding. It also 41 | support NSCoding protocol to archive and unarchive multi-frame image data. 42 | 43 | If the image is created from multi-frame image data, and you want to play the 44 | animation, try replace UIImageView with `YYAnimatedImageView`. 45 | 46 | Sample Code: 47 | 48 | // animation@3x.webp 49 | YYImage *image = [YYImage imageNamed:@"animation.webp"]; 50 | YYAnimatedImageView *imageView = [YYAnimatedImageView alloc] initWithImage:image]; 51 | [view addSubView:imageView]; 52 | 53 | */ 54 | @interface YYImage : UIImage 55 | 56 | + (nullable YYImage *)imageNamed:(NSString *)name; // no cache! 57 | + (nullable YYImage *)imageWithContentsOfFile:(NSString *)path; 58 | + (nullable YYImage *)imageWithData:(NSData *)data; 59 | + (nullable YYImage *)imageWithData:(NSData *)data scale:(CGFloat)scale; 60 | 61 | /** 62 | If the image is created from data or file, then the value indicates the data type. 63 | */ 64 | @property (nonatomic, readonly) YYImageType animatedImageType; 65 | 66 | /** 67 | If the image is created from animated image data (multi-frame GIF/APNG/WebP), 68 | this property stores the original image data. 69 | */ 70 | @property (nullable, nonatomic, readonly) NSData *animatedImageData; 71 | 72 | /** 73 | The total memory usage (in bytes) if all frame images was loaded into memory. 74 | The value is 0 if the image is not created from a multi-frame image data. 75 | */ 76 | @property (nonatomic, readonly) NSUInteger animatedImageMemorySize; 77 | 78 | /** 79 | Preload all frame image to memory. 80 | 81 | @discussion Set this property to `YES` will block the calling thread to decode 82 | all animation frame image to memory, set to `NO` will release the preloaded frames. 83 | If the image is shared by lots of image views (such as emoticon), preload all 84 | frames will reduce the CPU cost. 85 | 86 | See `animatedImageMemorySize` for memory cost. 87 | */ 88 | @property (nonatomic) BOOL preloadAllAnimatedImageFrames; 89 | 90 | @end 91 | 92 | NS_ASSUME_NONNULL_END 93 | -------------------------------------------------------------------------------- /YYImage/YYImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYImage.m 3 | // YYImage 4 | // 5 | // Created by ibireme on 14/10/20. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYImage.h" 13 | 14 | /** 15 | An array of NSNumber objects, shows the best order for path scale search. 16 | e.g. iPhone3GS:@[@1,@2,@3] iPhone5:@[@2,@3,@1] iPhone6 Plus:@[@3,@2,@1] 17 | */ 18 | static NSArray *_NSBundlePreferredScales() { 19 | static NSArray *scales; 20 | static dispatch_once_t onceToken; 21 | dispatch_once(&onceToken, ^{ 22 | CGFloat screenScale = [UIScreen mainScreen].scale; 23 | if (screenScale <= 1) { 24 | scales = @[@1,@2,@3]; 25 | } else if (screenScale <= 2) { 26 | scales = @[@2,@3,@1]; 27 | } else { 28 | scales = @[@3,@2,@1]; 29 | } 30 | }); 31 | return scales; 32 | } 33 | 34 | /** 35 | Add scale modifier to the file name (without path extension), 36 | From @"name" to @"name@2x". 37 | 38 | e.g. 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
Before After(scale:2)
"icon" "icon@2x"
"icon " "icon @2x"
"icon.top" "icon.top@2x"
"/p/name" "/p/name@2x"
"/path/" "/path/"
47 | 48 | @param scale Resource scale. 49 | @return String by add scale modifier, or just return if it's not end with file name. 50 | */ 51 | static NSString *_NSStringByAppendingNameScale(NSString *string, CGFloat scale) { 52 | if (!string) return nil; 53 | if (fabs(scale - 1) <= __FLT_EPSILON__ || string.length == 0 || [string hasSuffix:@"/"]) return string.copy; 54 | return [string stringByAppendingFormat:@"@%@x", @(scale)]; 55 | } 56 | 57 | /** 58 | Return the path scale. 59 | 60 | e.g. 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
Path Scale
"icon.png" 1
"icon@2x.png" 2
"icon@2.5x.png" 2.5
"icon@2x" 1
"icon@2x..png" 1
"icon@2x.png/" 1
70 | */ 71 | static CGFloat _NSStringPathScale(NSString *string) { 72 | if (string.length == 0 || [string hasSuffix:@"/"]) return 1; 73 | NSString *name = string.stringByDeletingPathExtension; 74 | __block CGFloat scale = 1; 75 | 76 | NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:@"@[0-9]+\\.?[0-9]*x$" options:NSRegularExpressionAnchorsMatchLines error:nil]; 77 | [pattern enumerateMatchesInString:name options:kNilOptions range:NSMakeRange(0, name.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { 78 | if (result.range.location >= 3) { 79 | scale = [string substringWithRange:NSMakeRange(result.range.location + 1, result.range.length - 2)].doubleValue; 80 | } 81 | }]; 82 | 83 | return scale; 84 | } 85 | 86 | 87 | @implementation YYImage { 88 | YYImageDecoder *_decoder; 89 | NSArray *_preloadedFrames; 90 | dispatch_semaphore_t _preloadedLock; 91 | NSUInteger _bytesPerFrame; 92 | } 93 | 94 | + (YYImage *)imageNamed:(NSString *)name { 95 | if (name.length == 0) return nil; 96 | if ([name hasSuffix:@"/"]) return nil; 97 | 98 | NSString *res = name.stringByDeletingPathExtension; 99 | NSString *ext = name.pathExtension; 100 | NSString *path = nil; 101 | CGFloat scale = 1; 102 | 103 | // If no extension, guess by system supported (same as UIImage). 104 | NSArray *exts = ext.length > 0 ? @[ext] : @[@"", @"png", @"jpeg", @"jpg", @"gif", @"webp", @"apng"]; 105 | NSArray *scales = _NSBundlePreferredScales(); 106 | for (int s = 0; s < scales.count; s++) { 107 | scale = ((NSNumber *)scales[s]).floatValue; 108 | NSString *scaledName = _NSStringByAppendingNameScale(res, scale); 109 | for (NSString *e in exts) { 110 | path = [[NSBundle mainBundle] pathForResource:scaledName ofType:e]; 111 | if (path) break; 112 | } 113 | if (path) break; 114 | } 115 | if (path.length == 0) return nil; 116 | 117 | NSData *data = [NSData dataWithContentsOfFile:path]; 118 | if (data.length == 0) return nil; 119 | 120 | return [[self alloc] initWithData:data scale:scale]; 121 | } 122 | 123 | + (YYImage *)imageWithContentsOfFile:(NSString *)path { 124 | return [[self alloc] initWithContentsOfFile:path]; 125 | } 126 | 127 | + (YYImage *)imageWithData:(NSData *)data { 128 | return [[self alloc] initWithData:data]; 129 | } 130 | 131 | + (YYImage *)imageWithData:(NSData *)data scale:(CGFloat)scale { 132 | return [[self alloc] initWithData:data scale:scale]; 133 | } 134 | 135 | - (instancetype)initWithContentsOfFile:(NSString *)path { 136 | NSData *data = [NSData dataWithContentsOfFile:path]; 137 | return [self initWithData:data scale:_NSStringPathScale(path)]; 138 | } 139 | 140 | - (instancetype)initWithData:(NSData *)data { 141 | return [self initWithData:data scale:1]; 142 | } 143 | 144 | - (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale { 145 | if (data.length == 0) return nil; 146 | if (scale <= 0) scale = [UIScreen mainScreen].scale; 147 | _preloadedLock = dispatch_semaphore_create(1); 148 | @autoreleasepool { 149 | YYImageDecoder *decoder = [YYImageDecoder decoderWithData:data scale:scale]; 150 | YYImageFrame *frame = [decoder frameAtIndex:0 decodeForDisplay:YES]; 151 | UIImage *image = frame.image; 152 | if (!image) return nil; 153 | self = [self initWithCGImage:image.CGImage scale:decoder.scale orientation:image.imageOrientation]; 154 | if (!self) return nil; 155 | _animatedImageType = decoder.type; 156 | if (decoder.frameCount > 1) { 157 | _decoder = decoder; 158 | _bytesPerFrame = CGImageGetBytesPerRow(image.CGImage) * CGImageGetHeight(image.CGImage); 159 | _animatedImageMemorySize = _bytesPerFrame * decoder.frameCount; 160 | } 161 | self.yy_isDecodedForDisplay = YES; 162 | } 163 | return self; 164 | } 165 | 166 | - (NSData *)animatedImageData { 167 | return _decoder.data; 168 | } 169 | 170 | - (void)setPreloadAllAnimatedImageFrames:(BOOL)preloadAllAnimatedImageFrames { 171 | if (_preloadAllAnimatedImageFrames != preloadAllAnimatedImageFrames) { 172 | if (preloadAllAnimatedImageFrames && _decoder.frameCount > 0) { 173 | NSMutableArray *frames = [NSMutableArray new]; 174 | for (NSUInteger i = 0, max = _decoder.frameCount; i < max; i++) { 175 | UIImage *img = [self animatedImageFrameAtIndex:i]; 176 | if (img) { 177 | [frames addObject:img]; 178 | } else { 179 | [frames addObject:[NSNull null]]; 180 | } 181 | } 182 | dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER); 183 | _preloadedFrames = frames; 184 | dispatch_semaphore_signal(_preloadedLock); 185 | } else { 186 | dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER); 187 | _preloadedFrames = nil; 188 | dispatch_semaphore_signal(_preloadedLock); 189 | } 190 | } 191 | } 192 | 193 | #pragma mark - protocol NSCoding 194 | 195 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 196 | NSNumber *scale = [aDecoder decodeObjectForKey:@"YYImageScale"]; 197 | NSData *data = [aDecoder decodeObjectForKey:@"YYImageData"]; 198 | if (data.length) { 199 | self = [self initWithData:data scale:scale.doubleValue]; 200 | } else { 201 | self = [super initWithCoder:aDecoder]; 202 | } 203 | return self; 204 | } 205 | 206 | - (void)encodeWithCoder:(NSCoder *)aCoder { 207 | if (_decoder.data.length) { 208 | [aCoder encodeObject:@(self.scale) forKey:@"YYImageScale"]; 209 | [aCoder encodeObject:_decoder.data forKey:@"YYImageData"]; 210 | } else { 211 | [super encodeWithCoder:aCoder]; // Apple use UIImagePNGRepresentation() to encode UIImage. 212 | } 213 | } 214 | 215 | + (BOOL)supportsSecureCoding { 216 | return YES; 217 | } 218 | 219 | #pragma mark - protocol YYAnimatedImage 220 | 221 | - (NSUInteger)animatedImageFrameCount { 222 | return _decoder.frameCount; 223 | } 224 | 225 | - (NSUInteger)animatedImageLoopCount { 226 | return _decoder.loopCount; 227 | } 228 | 229 | - (NSUInteger)animatedImageBytesPerFrame { 230 | return _bytesPerFrame; 231 | } 232 | 233 | - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index { 234 | if (index >= _decoder.frameCount) return nil; 235 | dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER); 236 | UIImage *image = _preloadedFrames[index]; 237 | dispatch_semaphore_signal(_preloadedLock); 238 | if (image) return image == (id)[NSNull null] ? nil : image; 239 | return [_decoder frameAtIndex:index decodeForDisplay:YES].image; 240 | } 241 | 242 | - (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index { 243 | NSTimeInterval duration = [_decoder frameDurationAtIndex:index]; 244 | 245 | /* 246 | http://opensource.apple.com/source/WebCore/WebCore-7600.1.25/platform/graphics/cg/ImageSourceCG.cpp 247 | Many annoying ads specify a 0 duration to make an image flash as quickly as 248 | possible. We follow Safari and Firefox's behavior and use a duration of 100 ms 249 | for any frames that specify a duration of <= 10 ms. 250 | See and for more information. 251 | 252 | See also: http://nullsleep.tumblr.com/post/16524517190/animated-gif-minimum-frame-delay-browser. 253 | */ 254 | if (duration < 0.011f) return 0.100f; 255 | return duration; 256 | } 257 | 258 | @end 259 | -------------------------------------------------------------------------------- /YYImage/YYImageCoder.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYImageCoder.h 3 | // YYImage 4 | // 5 | // Created by ibireme on 15/5/13. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /** 17 | Image file type. 18 | */ 19 | typedef NS_ENUM(NSUInteger, YYImageType) { 20 | YYImageTypeUnknown = 0, ///< unknown 21 | YYImageTypeJPEG, ///< jpeg, jpg 22 | YYImageTypeJPEG2000, ///< jp2 23 | YYImageTypeTIFF, ///< tiff, tif 24 | YYImageTypeBMP, ///< bmp 25 | YYImageTypeICO, ///< ico 26 | YYImageTypeICNS, ///< icns 27 | YYImageTypeGIF, ///< gif 28 | YYImageTypePNG, ///< png 29 | YYImageTypeWebP, ///< webp 30 | YYImageTypeOther, ///< other image format 31 | }; 32 | 33 | 34 | /** 35 | Dispose method specifies how the area used by the current frame is to be treated 36 | before rendering the next frame on the canvas. 37 | */ 38 | typedef NS_ENUM(NSUInteger, YYImageDisposeMethod) { 39 | 40 | /** 41 | No disposal is done on this frame before rendering the next; the contents 42 | of the canvas are left as is. 43 | */ 44 | YYImageDisposeNone = 0, 45 | 46 | /** 47 | The frame's region of the canvas is to be cleared to fully transparent black 48 | before rendering the next frame. 49 | */ 50 | YYImageDisposeBackground, 51 | 52 | /** 53 | The frame's region of the canvas is to be reverted to the previous contents 54 | before rendering the next frame. 55 | */ 56 | YYImageDisposePrevious, 57 | }; 58 | 59 | /** 60 | Blend operation specifies how transparent pixels of the current frame are 61 | blended with those of the previous canvas. 62 | */ 63 | typedef NS_ENUM(NSUInteger, YYImageBlendOperation) { 64 | 65 | /** 66 | All color components of the frame, including alpha, overwrite the current 67 | contents of the frame's canvas region. 68 | */ 69 | YYImageBlendNone = 0, 70 | 71 | /** 72 | The frame should be composited onto the output buffer based on its alpha. 73 | */ 74 | YYImageBlendOver, 75 | }; 76 | 77 | /** 78 | An image frame object. 79 | */ 80 | @interface YYImageFrame : NSObject 81 | @property (nonatomic) NSUInteger index; ///< Frame index (zero based) 82 | @property (nonatomic) NSUInteger width; ///< Frame width 83 | @property (nonatomic) NSUInteger height; ///< Frame height 84 | @property (nonatomic) NSUInteger offsetX; ///< Frame origin.x in canvas (left-bottom based) 85 | @property (nonatomic) NSUInteger offsetY; ///< Frame origin.y in canvas (left-bottom based) 86 | @property (nonatomic) NSTimeInterval duration; ///< Frame duration in seconds 87 | @property (nonatomic) YYImageDisposeMethod dispose; ///< Frame dispose method. 88 | @property (nonatomic) YYImageBlendOperation blend; ///< Frame blend operation. 89 | @property (nullable, nonatomic, strong) UIImage *image; ///< The image. 90 | + (instancetype)frameWithImage:(UIImage *)image; 91 | @end 92 | 93 | 94 | #pragma mark - Decoder 95 | 96 | /** 97 | An image decoder to decode image data. 98 | 99 | @discussion This class supports decoding animated WebP, APNG, GIF and system 100 | image format such as PNG, JPG, JP2, BMP, TIFF, PIC, ICNS and ICO. It can be used 101 | to decode complete image data, or to decode incremental image data during image 102 | download. This class is thread-safe. 103 | 104 | Example: 105 | 106 | // Decode single image: 107 | NSData *data = [NSData dataWithContentOfFile:@"/tmp/image.webp"]; 108 | YYImageDecoder *decoder = [YYImageDecoder decoderWithData:data scale:2.0]; 109 | UIImage image = [decoder frameAtIndex:0 decodeForDisplay:YES].image; 110 | 111 | // Decode image during download: 112 | NSMutableData *data = [NSMutableData new]; 113 | YYImageDecoder *decoder = [[YYImageDecoder alloc] initWithScale:2.0]; 114 | while(newDataArrived) { 115 | [data appendData:newData]; 116 | [decoder updateData:data final:NO]; 117 | if (decoder.frameCount > 0) { 118 | UIImage image = [decoder frameAtIndex:0 decodeForDisplay:YES].image; 119 | // progressive display... 120 | } 121 | } 122 | [decoder updateData:data final:YES]; 123 | UIImage image = [decoder frameAtIndex:0 decodeForDisplay:YES].image; 124 | // final display... 125 | 126 | */ 127 | @interface YYImageDecoder : NSObject 128 | 129 | @property (nullable, nonatomic, readonly) NSData *data; ///< Image data. 130 | @property (nonatomic, readonly) YYImageType type; ///< Image data type. 131 | @property (nonatomic, readonly) CGFloat scale; ///< Image scale. 132 | @property (nonatomic, readonly) NSUInteger frameCount; ///< Image frame count. 133 | @property (nonatomic, readonly) NSUInteger loopCount; ///< Image loop count, 0 means infinite. 134 | @property (nonatomic, readonly) NSUInteger width; ///< Image canvas width. 135 | @property (nonatomic, readonly) NSUInteger height; ///< Image canvas height. 136 | @property (nonatomic, readonly, getter=isFinalized) BOOL finalized; 137 | 138 | /** 139 | Creates an image decoder. 140 | 141 | @param scale Image's scale. 142 | @return An image decoder. 143 | */ 144 | - (instancetype)initWithScale:(CGFloat)scale NS_DESIGNATED_INITIALIZER; 145 | 146 | /** 147 | Updates the incremental image with new data. 148 | 149 | @discussion You can use this method to decode progressive/interlaced/baseline 150 | image when you do not have the complete image data. The `data` was retained by 151 | decoder, you should not modify the data in other thread during decoding. 152 | 153 | @param data The data to add to the image decoder. Each time you call this 154 | function, the 'data' parameter must contain all of the image file data 155 | accumulated so far. 156 | 157 | @param final A value that specifies whether the data is the final set. 158 | Pass YES if it is, NO otherwise. When the data is already finalized, you can 159 | not update the data anymore. 160 | 161 | @return Whether succeed. 162 | */ 163 | - (BOOL)updateData:(nullable NSData *)data final:(BOOL)final; 164 | 165 | /** 166 | Convenience method to create a decoder with specified data. 167 | @param data Image data. 168 | @param scale Image's scale. 169 | @return A new decoder, or nil if an error occurs. 170 | */ 171 | + (nullable instancetype)decoderWithData:(NSData *)data scale:(CGFloat)scale; 172 | 173 | /** 174 | Decodes and returns a frame from a specified index. 175 | @param index Frame image index (zero-based). 176 | @param decodeForDisplay Whether decode the image to memory bitmap for display. 177 | If NO, it will try to returns the original frame data without blend. 178 | @return A new frame with image, or nil if an error occurs. 179 | */ 180 | - (nullable YYImageFrame *)frameAtIndex:(NSUInteger)index decodeForDisplay:(BOOL)decodeForDisplay; 181 | 182 | /** 183 | Returns the frame duration from a specified index. 184 | @param index Frame image (zero-based). 185 | @return Duration in seconds. 186 | */ 187 | - (NSTimeInterval)frameDurationAtIndex:(NSUInteger)index; 188 | 189 | /** 190 | Returns the frame's properties. See "CGImageProperties.h" in ImageIO.framework 191 | for more information. 192 | 193 | @param index Frame image index (zero-based). 194 | @return The ImageIO frame property. 195 | */ 196 | - (nullable NSDictionary *)framePropertiesAtIndex:(NSUInteger)index; 197 | 198 | /** 199 | Returns the image's properties. See "CGImageProperties.h" in ImageIO.framework 200 | for more information. 201 | */ 202 | - (nullable NSDictionary *)imageProperties; 203 | 204 | @end 205 | 206 | 207 | 208 | #pragma mark - Encoder 209 | 210 | /** 211 | An image encoder to encode image to data. 212 | 213 | @discussion It supports encoding single frame image with the type defined in YYImageType. 214 | It also supports encoding multi-frame image with GIF, APNG and WebP. 215 | 216 | Example: 217 | 218 | YYImageEncoder *jpegEncoder = [[YYImageEncoder alloc] initWithType:YYImageTypeJPEG]; 219 | jpegEncoder.quality = 0.9; 220 | [jpegEncoder addImage:image duration:0]; 221 | NSData jpegData = [jpegEncoder encode]; 222 | 223 | YYImageEncoder *gifEncoder = [[YYImageEncoder alloc] initWithType:YYImageTypeGIF]; 224 | gifEncoder.loopCount = 5; 225 | [gifEncoder addImage:image0 duration:0.1]; 226 | [gifEncoder addImage:image1 duration:0.15]; 227 | [gifEncoder addImage:image2 duration:0.2]; 228 | NSData gifData = [gifEncoder encode]; 229 | 230 | @warning It just pack the images together when encoding multi-frame image. If you 231 | want to reduce the image file size, try imagemagick/ffmpeg for GIF and WebP, 232 | and apngasm for APNG. 233 | */ 234 | @interface YYImageEncoder : NSObject 235 | 236 | @property (nonatomic, readonly) YYImageType type; ///< Image type. 237 | @property (nonatomic) NSUInteger loopCount; ///< Loop count, 0 means infinit, only available for GIF/APNG/WebP. 238 | @property (nonatomic) BOOL lossless; ///< Lossless, only available for WebP. 239 | @property (nonatomic) CGFloat quality; ///< Compress quality, 0.0~1.0, only available for JPG/JP2/WebP. 240 | 241 | - (instancetype)init UNAVAILABLE_ATTRIBUTE; 242 | + (instancetype)new UNAVAILABLE_ATTRIBUTE; 243 | 244 | /** 245 | Create an image encoder with a specified type. 246 | @param type Image type. 247 | @return A new encoder, or nil if an error occurs. 248 | */ 249 | - (nullable instancetype)initWithType:(YYImageType)type NS_DESIGNATED_INITIALIZER; 250 | 251 | /** 252 | Add an image to encoder. 253 | @param image Image. 254 | @param duration Image duration for animation. Pass 0 to ignore this parameter. 255 | */ 256 | - (void)addImage:(UIImage *)image duration:(NSTimeInterval)duration; 257 | 258 | /** 259 | Add an image with image data to encoder. 260 | @param data Image data. 261 | @param duration Image duration for animation. Pass 0 to ignore this parameter. 262 | */ 263 | - (void)addImageWithData:(NSData *)data duration:(NSTimeInterval)duration; 264 | 265 | /** 266 | Add an image from a file path to encoder. 267 | @param path Image file path. 268 | @param duration Image duration for animation. Pass 0 to ignore this parameter. 269 | */ 270 | - (void)addImageWithFile:(NSString *)path duration:(NSTimeInterval)duration; 271 | 272 | /** 273 | Encodes the image and returns the image data. 274 | @return The image data, or nil if an error occurs. 275 | */ 276 | - (nullable NSData *)encode; 277 | 278 | /** 279 | Encodes the image to a file. 280 | @param path The file path (overwrite if exist). 281 | @return Whether succeed. 282 | */ 283 | - (BOOL)encodeToFile:(NSString *)path; 284 | 285 | /** 286 | Convenience method to encode single frame image. 287 | @param image The image. 288 | @param type The destination image type. 289 | @param quality Image quality, 0.0~1.0. 290 | @return The image data, or nil if an error occurs. 291 | */ 292 | + (nullable NSData *)encodeImage:(UIImage *)image type:(YYImageType)type quality:(CGFloat)quality; 293 | 294 | /** 295 | Convenience method to encode image from a decoder. 296 | @param decoder The image decoder. 297 | @param type The destination image type; 298 | @param quality Image quality, 0.0~1.0. 299 | @return The image data, or nil if an error occurs. 300 | */ 301 | + (nullable NSData *)encodeImageWithDecoder:(YYImageDecoder *)decoder type:(YYImageType)type quality:(CGFloat)quality; 302 | 303 | @end 304 | 305 | 306 | #pragma mark - UIImage 307 | 308 | @interface UIImage (YYImageCoder) 309 | 310 | /** 311 | Decompress this image to bitmap, so when the image is displayed on screen, 312 | the main thread won't be blocked by additional decode. If the image has already 313 | been decoded or unable to decode, it just returns itself. 314 | 315 | @return an image decoded, or just return itself if no needed. 316 | @see yy_isDecodedForDisplay 317 | */ 318 | - (instancetype)yy_imageByDecoded; 319 | 320 | /** 321 | Wherher the image can be display on screen without additional decoding. 322 | @warning It just a hint for your code, change it has no other effect. 323 | */ 324 | @property (nonatomic) BOOL yy_isDecodedForDisplay; 325 | 326 | /** 327 | Saves this image to iOS Photos Album. 328 | 329 | @discussion This method attempts to save the original data to album if the 330 | image is created from an animated GIF/APNG, otherwise, it will save the image 331 | as JPEG or PNG (based on the alpha information). 332 | 333 | @param completionBlock The block invoked (in main thread) after the save operation completes. 334 | assetURL: An URL that identifies the saved image file. If the image is not saved, assetURL is nil. 335 | error: If the image is not saved, an error object that describes the reason for failure, otherwise nil. 336 | */ 337 | - (void)yy_saveToAlbumWithCompletionBlock:(nullable void(^)(NSURL * _Nullable assetURL, NSError * _Nullable error))completionBlock; 338 | 339 | /** 340 | Return a 'best' data representation for this image. 341 | 342 | @discussion The convertion based on these rule: 343 | 1. If the image is created from an animated GIF/APNG/WebP, it returns the original data. 344 | 2. It returns PNG or JPEG(0.9) representation based on the alpha information. 345 | 346 | @return Image data, or nil if an error occurs. 347 | */ 348 | - (nullable NSData *)yy_imageDataRepresentation; 349 | 350 | @end 351 | 352 | 353 | 354 | #pragma mark - Helper 355 | 356 | /// Detect a data's image type by reading the data's header 16 bytes (very fast). 357 | CG_EXTERN YYImageType YYImageDetectType(CFDataRef data); 358 | 359 | /// Convert YYImageType to UTI (such as kUTTypeJPEG). 360 | CG_EXTERN CFStringRef _Nullable YYImageTypeToUTType(YYImageType type); 361 | 362 | /// Convert UTI (such as kUTTypeJPEG) to YYImageType. 363 | CG_EXTERN YYImageType YYImageTypeFromUTType(CFStringRef uti); 364 | 365 | /// Get image type's file extension (such as @"jpg"). 366 | CG_EXTERN NSString *_Nullable YYImageTypeGetExtension(YYImageType type); 367 | 368 | 369 | 370 | /// Returns the shared DeviceRGB color space. 371 | CG_EXTERN CGColorSpaceRef YYCGColorSpaceGetDeviceRGB(); 372 | 373 | /// Returns the shared DeviceGray color space. 374 | CG_EXTERN CGColorSpaceRef YYCGColorSpaceGetDeviceGray(); 375 | 376 | /// Returns whether a color space is DeviceRGB. 377 | CG_EXTERN BOOL YYCGColorSpaceIsDeviceRGB(CGColorSpaceRef space); 378 | 379 | /// Returns whether a color space is DeviceGray. 380 | CG_EXTERN BOOL YYCGColorSpaceIsDeviceGray(CGColorSpaceRef space); 381 | 382 | 383 | 384 | /// Convert EXIF orientation value to UIImageOrientation. 385 | CG_EXTERN UIImageOrientation YYUIImageOrientationFromEXIFValue(NSInteger value); 386 | 387 | /// Convert UIImageOrientation to EXIF orientation value. 388 | CG_EXTERN NSInteger YYUIImageOrientationToEXIFValue(UIImageOrientation orientation); 389 | 390 | 391 | 392 | /** 393 | Create a decoded image. 394 | 395 | @discussion If the source image is created from a compressed image data (such as 396 | PNG or JPEG), you can use this method to decode the image. After decoded, you can 397 | access the decoded bytes with CGImageGetDataProvider() and CGDataProviderCopyData() 398 | without additional decode process. If the image has already decoded, this method 399 | just copy the decoded bytes to the new image. 400 | 401 | @param imageRef The source image. 402 | @param decodeForDisplay If YES, this method will decode the image and convert 403 | it to BGRA8888 (premultiplied) or BGRX8888 format for CALayer display. 404 | 405 | @return A decoded image, or NULL if an error occurs. 406 | */ 407 | CG_EXTERN CGImageRef _Nullable YYCGImageCreateDecodedCopy(CGImageRef imageRef, BOOL decodeForDisplay); 408 | 409 | /** 410 | Create an image copy with an orientation. 411 | 412 | @param imageRef Source image 413 | @param orientation Image orientation which will applied to the image. 414 | @param destBitmapInfo Destimation image bitmap, only support 32bit format (such as ARGB8888). 415 | @return A new image, or NULL if an error occurs. 416 | */ 417 | CG_EXTERN CGImageRef _Nullable YYCGImageCreateCopyWithOrientation(CGImageRef imageRef, 418 | UIImageOrientation orientation, 419 | CGBitmapInfo destBitmapInfo); 420 | 421 | /** 422 | Create an image copy with CGAffineTransform. 423 | 424 | @param imageRef Source image. 425 | @param transform Transform applied to image (left-bottom based coordinate system). 426 | @param destSize Destination image size 427 | @param destBitmapInfo Destimation image bitmap, only support 32bit format (such as ARGB8888). 428 | @return A new image, or NULL if an error occurs. 429 | */ 430 | CG_EXTERN CGImageRef _Nullable YYCGImageCreateAffineTransformCopy(CGImageRef imageRef, 431 | CGAffineTransform transform, 432 | CGSize destSize, 433 | CGBitmapInfo destBitmapInfo); 434 | 435 | /** 436 | Encode an image to data with CGImageDestination. 437 | 438 | @param imageRef The image. 439 | @param type The image destination data type. 440 | @param quality The quality (0.0~1.0) 441 | @return A new image data, or nil if an error occurs. 442 | */ 443 | CG_EXTERN CFDataRef _Nullable YYCGImageCreateEncodedData(CGImageRef imageRef, YYImageType type, CGFloat quality); 444 | 445 | 446 | /** 447 | Whether WebP is available in YYImage. 448 | */ 449 | CG_EXTERN BOOL YYImageWebPAvailable(); 450 | 451 | /** 452 | Get a webp image frame count; 453 | 454 | @param webpData WebP data. 455 | @return Image frame count, or 0 if an error occurs. 456 | */ 457 | CG_EXTERN NSUInteger YYImageGetWebPFrameCount(CFDataRef webpData); 458 | 459 | /** 460 | Decode an image from WebP data, returns NULL if an error occurs. 461 | 462 | @param webpData The WebP data. 463 | @param decodeForDisplay If YES, this method will decode the image and convert it 464 | to BGRA8888 (premultiplied) format for CALayer display. 465 | @param useThreads YES to enable multi-thread decode. 466 | (speed up, but cost more CPU) 467 | @param bypassFiltering YES to skip the in-loop filtering. 468 | (speed up, but may lose some smooth) 469 | @param noFancyUpsampling YES to use faster pointwise upsampler. 470 | (speed down, and may lose some details). 471 | @return The decoded image, or NULL if an error occurs. 472 | */ 473 | CG_EXTERN CGImageRef _Nullable YYCGImageCreateWithWebPData(CFDataRef webpData, 474 | BOOL decodeForDisplay, 475 | BOOL useThreads, 476 | BOOL bypassFiltering, 477 | BOOL noFancyUpsampling); 478 | 479 | typedef NS_ENUM(NSUInteger, YYImagePreset) { 480 | YYImagePresetDefault = 0, ///< default preset. 481 | YYImagePresetPicture, ///< digital picture, like portrait, inner shot 482 | YYImagePresetPhoto, ///< outdoor photograph, with natural lighting 483 | YYImagePresetDrawing, ///< hand or line drawing, with high-contrast details 484 | YYImagePresetIcon, ///< small-sized colorful images 485 | YYImagePresetText ///< text-like 486 | }; 487 | 488 | /** 489 | Encode a CGImage to WebP data 490 | 491 | @param imageRef image 492 | @param lossless YES=lossless (similar to PNG), NO=lossy (similar to JPEG) 493 | @param quality 0.0~1.0 (0=smallest file, 1.0=biggest file) 494 | For lossless image, try the value near 1.0; for lossy, try the value near 0.8. 495 | @param compressLevel 0~6 (0=fast, 6=slower-better). Default is 4. 496 | @param preset Preset for different image type, default is YYImagePresetDefault. 497 | @return WebP data, or nil if an error occurs. 498 | */ 499 | CG_EXTERN CFDataRef _Nullable YYCGImageCreateEncodedWebPData(CGImageRef imageRef, 500 | BOOL lossless, 501 | CGFloat quality, 502 | int compressLevel, 503 | YYImagePreset preset); 504 | 505 | NS_ASSUME_NONNULL_END 506 | -------------------------------------------------------------------------------- /YYImage/YYSpriteSheetImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYSpriteImage.h 3 | // YYImage 4 | // 5 | // Created by ibireme on 15/4/21. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | #import 16 | #elif __has_include() 17 | #import 18 | #else 19 | #import "YYAnimatedImageView.h" 20 | #endif 21 | 22 | NS_ASSUME_NONNULL_BEGIN 23 | 24 | /** 25 | An image to display sprite sheet animation. 26 | 27 | @discussion It is a fully compatible `UIImage` subclass. 28 | The animation can be played by YYAnimatedImageView. 29 | 30 | Sample Code: 31 | 32 | // 8 * 12 sprites in a single sheet image 33 | UIImage *spriteSheet = [UIImage imageNamed:@"sprite-sheet"]; 34 | NSMutableArray *contentRects = [NSMutableArray new]; 35 | NSMutableArray *durations = [NSMutableArray new]; 36 | for (int j = 0; j < 12; j++) { 37 | for (int i = 0; i < 8; i++) { 38 | CGRect rect; 39 | rect.size = CGSizeMake(img.size.width / 8, img.size.height / 12); 40 | rect.origin.x = img.size.width / 8 * i; 41 | rect.origin.y = img.size.height / 12 * j; 42 | [contentRects addObject:[NSValue valueWithCGRect:rect]]; 43 | [durations addObject:@(1 / 60.0)]; 44 | } 45 | } 46 | YYSpriteSheetImage *sprite; 47 | sprite = [[YYSpriteSheetImage alloc] initWithSpriteSheetImage:img 48 | contentRects:contentRects 49 | frameDurations:durations 50 | loopCount:0]; 51 | YYAnimatedImageView *imgView = [YYAnimatedImageView new]; 52 | imgView.size = CGSizeMake(img.size.width / 8, img.size.height / 12); 53 | imgView.image = sprite; 54 | 55 | 56 | 57 | @discussion It can also be used to display single frame in sprite sheet image. 58 | Sample Code: 59 | 60 | YYSpriteSheetImage *sheet = ...; 61 | UIImageView *imageView = ...; 62 | imageView.image = sheet; 63 | imageView.layer.contentsRect = [sheet contentsRectForCALayerAtIndex:6]; 64 | 65 | */ 66 | @interface YYSpriteSheetImage : UIImage 67 | 68 | /** 69 | Creates and returns an image object. 70 | 71 | @param image The sprite sheet image (contains all frames). 72 | 73 | @param contentRects The sprite sheet image frame rects in the image coordinates. 74 | The rectangle should not outside the image's bounds. The objects in this array 75 | should be created with [NSValue valueWithCGRect:]. 76 | 77 | @param frameDurations The sprite sheet image frame's durations in seconds. 78 | The objects in this array should be NSNumber. 79 | 80 | @param loopCount Animation loop count, 0 means infinite looping. 81 | 82 | @return An image object, or nil if an error occurs. 83 | */ 84 | - (nullable instancetype)initWithSpriteSheetImage:(UIImage *)image 85 | contentRects:(NSArray *)contentRects 86 | frameDurations:(NSArray *)frameDurations 87 | loopCount:(NSUInteger)loopCount; 88 | 89 | @property (nonatomic, readonly) NSArray *contentRects; 90 | @property (nonatomic, readonly) NSArray *frameDurations; 91 | @property (nonatomic, readonly) NSUInteger loopCount; 92 | 93 | /** 94 | Get the contents rect for CALayer. 95 | See "contentsRect" property in CALayer for more information. 96 | 97 | @param index Index of frame. 98 | @return Contents Rect. 99 | */ 100 | - (CGRect)contentsRectForCALayerAtIndex:(NSUInteger)index; 101 | 102 | @end 103 | 104 | NS_ASSUME_NONNULL_END 105 | -------------------------------------------------------------------------------- /YYImage/YYSpriteSheetImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYSpriteImage.m 3 | // YYImage 4 | // 5 | // Created by ibireme on 15/4/21. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYSpriteSheetImage.h" 13 | 14 | @implementation YYSpriteSheetImage 15 | 16 | - (instancetype)initWithSpriteSheetImage:(UIImage *)image 17 | contentRects:(NSArray *)contentRects 18 | frameDurations:(NSArray *)frameDurations 19 | loopCount:(NSUInteger)loopCount { 20 | if (!image.CGImage) return nil; 21 | if (contentRects.count < 1 || frameDurations.count < 1) return nil; 22 | if (contentRects.count != frameDurations.count) return nil; 23 | 24 | self = [super initWithCGImage:image.CGImage scale:image.scale orientation:image.imageOrientation]; 25 | if (!self) return nil; 26 | 27 | _contentRects = contentRects.copy; 28 | _frameDurations = frameDurations.copy; 29 | _loopCount = loopCount; 30 | return self; 31 | } 32 | 33 | - (CGRect)contentsRectForCALayerAtIndex:(NSUInteger)index { 34 | CGRect layerRect = CGRectMake(0, 0, 1, 1); 35 | if (index >= _contentRects.count) return layerRect; 36 | 37 | CGSize imageSize = self.size; 38 | CGRect rect = [self animatedImageContentsRectAtIndex:index]; 39 | if (imageSize.width > 0.01 && imageSize.height > 0.01) { 40 | layerRect.origin.x = rect.origin.x / imageSize.width; 41 | layerRect.origin.y = rect.origin.y / imageSize.height; 42 | layerRect.size.width = rect.size.width / imageSize.width; 43 | layerRect.size.height = rect.size.height / imageSize.height; 44 | layerRect = CGRectIntersection(layerRect, CGRectMake(0, 0, 1, 1)); 45 | if (CGRectIsNull(layerRect) || CGRectIsEmpty(layerRect)) { 46 | layerRect = CGRectMake(0, 0, 1, 1); 47 | } 48 | } 49 | return layerRect; 50 | } 51 | 52 | #pragma mark @protocol YYAnimatedImage 53 | 54 | - (NSUInteger)animatedImageFrameCount { 55 | return _contentRects.count; 56 | } 57 | 58 | - (NSUInteger)animatedImageLoopCount { 59 | return _loopCount; 60 | } 61 | 62 | - (NSUInteger)animatedImageBytesPerFrame { 63 | return 0; 64 | } 65 | 66 | - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index { 67 | return self; 68 | } 69 | 70 | - (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index { 71 | if (index >= _frameDurations.count) return 0; 72 | return ((NSNumber *)_frameDurations[index]).doubleValue; 73 | } 74 | 75 | - (CGRect)animatedImageContentsRectAtIndex:(NSUInteger)index { 76 | if (index >= _contentRects.count) return CGRectZero; 77 | return ((NSValue *)_contentRects[index]).CGRectValue; 78 | } 79 | 80 | @end 81 | --------------------------------------------------------------------------------