├── .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 | [](https://raw.githubusercontent.com/ibireme/YYImage/master/LICENSE)
4 | [](https://github.com/Carthage/Carthage)
5 | [](http://cocoapods.org/pods/YYImage)
6 | [](http://cocoadocs.org/docsets/YYImage)
7 | [](https://www.apple.com/nl/ios/)
8 | [](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 | 
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 | 
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 | Path | Scale |
22 | "icon.png" | 1 |
23 | "icon@2x.png" | 2 |
24 | "icon@2.5x.png" | 2.5 |
25 | "icon@2x" | 1 |
26 | "icon@2x..png" | 1 |
27 | "icon@2x.png/" | 1 |
28 |
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 | Before | After(scale:2) |
41 | "icon" | "icon@2x" |
42 | "icon " | "icon @2x" |
43 | "icon.top" | "icon.top@2x" |
44 | "/p/name" | "/p/name@2x" |
45 | "/path/" | "/path/" |
46 |
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 | Path | Scale |
63 | "icon.png" | 1 |
64 | "icon@2x.png" | 2 |
65 | "icon@2.5x.png" | 2.5 |
66 | "icon@2x" | 1 |
67 | "icon@2x..png" | 1 |
68 | "icon@2x.png/" | 1 |
69 |
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 |
--------------------------------------------------------------------------------