├── .gitignore
├── BBWebImage.podspec
├── BBWebImage.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── BBWebImage
├── BBWebImage.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── BBWebImageTests.xcscheme
├── BBWebImage
│ ├── BBWebImage.h
│ ├── Core
│ │ ├── BBAnimatedImage.swift
│ │ ├── BBAnimatedImageView.swift
│ │ ├── BBDiskCache.swift
│ │ ├── BBDiskStorage.swift
│ │ ├── BBDispatchQueuePool.swift
│ │ ├── BBImageCache.swift
│ │ ├── BBImageCoder.swift
│ │ ├── BBImageDownloadOperation.swift
│ │ ├── BBImageDownloadOperationQueue.swift
│ │ ├── BBImageDownloader.swift
│ │ ├── BBMemoryCache.swift
│ │ ├── BBWeakProxy.swift
│ │ ├── BBWebCache.swift
│ │ ├── BBWebCacheResource.swift
│ │ ├── BBWebImageEditor.swift
│ │ ├── BBWebImageGIFCoder.swift
│ │ ├── BBWebImageImageIOCoder.swift
│ │ └── BBWebImageManager.swift
│ ├── Extensions
│ │ ├── CALayer+BBWebCache.swift
│ │ ├── Data+ImageFormat.swift
│ │ ├── DispatchQueue+Safe.swift
│ │ ├── MKAnnotationView+BBWebCache.swift
│ │ ├── String+MD5.swift
│ │ ├── UIButton+BBWebCache.swift
│ │ ├── UIDevice+BBAdd.swift
│ │ ├── UIImage+ImageFormat.swift
│ │ └── UIImageView+BBWebCache.swift
│ ├── Filter
│ │ ├── BBCILookup.cikernel
│ │ └── BBCILookupFilter.swift
│ └── Info.plist
└── BBWebImageTests
│ ├── BBAnimatedImageTests.swift
│ ├── BBImageCoderManagerTests.swift
│ ├── BBLRUImageCacheTests.swift
│ ├── BBMergeRequestImageDownloaderTests.swift
│ ├── BBWebImageGIFCoderTests.swift
│ ├── BBWebImageManagerTests.swift
│ ├── Info.plist
│ ├── TestImageDownloadOperation.swift
│ ├── TestImageDownloadTask.swift
│ ├── mew_baseline.jpg
│ └── mew_baseline.png
├── BBWebImageDemo
├── BBWebImageDemo.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── BBWebImageDemo
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
│ ├── BBCILookupTestFilter.swift
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── GIFWallCell.swift
│ ├── GIFWallVC.swift
│ ├── ImageURLProvider.swift
│ ├── ImageWallCell.swift
│ ├── ImageWallVC.swift
│ ├── Info.plist
│ ├── MainMenuVC.swift
│ ├── Rotating_earth.gif
│ ├── TestFilterVC.swift
│ ├── TestGIFVC.swift
│ ├── TestVC.swift
│ ├── large_leaves_70mp.jpg
│ ├── placeholder.png
│ ├── sunflower.jpg
│ └── test_lookup.png
├── CompareImageLib
├── CompareImageLib.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── CompareImageLib.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── CompareImageLib
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── BBAnimatedImageWallCell.swift
│ ├── BBAnimatedImageWallVC.swift
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── ImageWallCell.swift
│ ├── ImageWallVC.swift
│ ├── Info.plist
│ ├── KiAnimatedImageWallCell.swift
│ ├── KiAnimatedImageWallVC.swift
│ ├── MainMenuVC.swift
│ ├── SDAnimatedImageWallCell.swift
│ ├── SDAnimatedImageWallVC.swift
│ ├── TestCacheVC.swift
│ ├── TestImages
│ │ ├── test_1.jpg
│ │ ├── test_10.jpg
│ │ ├── test_100.jpg
│ │ ├── test_100_size_64.jpg
│ │ ├── test_10_size_64.jpg
│ │ ├── test_11.jpg
│ │ ├── test_11_size_64.jpg
│ │ ├── test_12.jpg
│ │ ├── test_12_size_64.jpg
│ │ ├── test_13.jpg
│ │ ├── test_13_size_64.jpg
│ │ ├── test_14.jpg
│ │ ├── test_14_size_64.jpg
│ │ ├── test_15.jpg
│ │ ├── test_15_size_64.jpg
│ │ ├── test_16.jpg
│ │ ├── test_16_size_64.jpg
│ │ ├── test_17.jpg
│ │ ├── test_17_size_64.jpg
│ │ ├── test_18.jpg
│ │ ├── test_18_size_64.jpg
│ │ ├── test_19.jpg
│ │ ├── test_19_size_64.jpg
│ │ ├── test_1_size_64.jpg
│ │ ├── test_2.jpg
│ │ ├── test_20.jpg
│ │ ├── test_20_size_64.jpg
│ │ ├── test_21.jpg
│ │ ├── test_21_size_64.jpg
│ │ ├── test_22.jpg
│ │ ├── test_22_size_64.jpg
│ │ ├── test_23.jpg
│ │ ├── test_23_size_64.jpg
│ │ ├── test_24.jpg
│ │ ├── test_24_size_64.jpg
│ │ ├── test_25.jpg
│ │ ├── test_25_size_64.jpg
│ │ ├── test_26.jpg
│ │ ├── test_26_size_64.jpg
│ │ ├── test_27.jpg
│ │ ├── test_27_size_64.jpg
│ │ ├── test_28.jpg
│ │ ├── test_28_size_64.jpg
│ │ ├── test_29.jpg
│ │ ├── test_29_size_64.jpg
│ │ ├── test_2_size_64.jpg
│ │ ├── test_3.jpg
│ │ ├── test_30.jpg
│ │ ├── test_30_size_64.jpg
│ │ ├── test_31.jpg
│ │ ├── test_31_size_64.jpg
│ │ ├── test_32.jpg
│ │ ├── test_32_size_64.jpg
│ │ ├── test_33.jpg
│ │ ├── test_33_size_64.jpg
│ │ ├── test_34.jpg
│ │ ├── test_34_size_64.jpg
│ │ ├── test_35.jpg
│ │ ├── test_35_size_64.jpg
│ │ ├── test_36.jpg
│ │ ├── test_36_size_64.jpg
│ │ ├── test_37.jpg
│ │ ├── test_37_size_64.jpg
│ │ ├── test_38.jpg
│ │ ├── test_38_size_64.jpg
│ │ ├── test_39.jpg
│ │ ├── test_39_size_64.jpg
│ │ ├── test_3_size_64.jpg
│ │ ├── test_4.jpg
│ │ ├── test_40.jpg
│ │ ├── test_40_size_64.jpg
│ │ ├── test_41.jpg
│ │ ├── test_41_size_64.jpg
│ │ ├── test_42.jpg
│ │ ├── test_42_size_64.jpg
│ │ ├── test_43.jpg
│ │ ├── test_43_size_64.jpg
│ │ ├── test_44.jpg
│ │ ├── test_44_size_64.jpg
│ │ ├── test_45.jpg
│ │ ├── test_45_size_64.jpg
│ │ ├── test_46.jpg
│ │ ├── test_46_size_64.jpg
│ │ ├── test_47.jpg
│ │ ├── test_47_size_64.jpg
│ │ ├── test_48.jpg
│ │ ├── test_48_size_64.jpg
│ │ ├── test_49.jpg
│ │ ├── test_49_size_64.jpg
│ │ ├── test_4_size_64.jpg
│ │ ├── test_5.jpg
│ │ ├── test_50.jpg
│ │ ├── test_50_size_64.jpg
│ │ ├── test_51.jpg
│ │ ├── test_51_size_64.jpg
│ │ ├── test_52.jpg
│ │ ├── test_52_size_64.jpg
│ │ ├── test_53.jpg
│ │ ├── test_53_size_64.jpg
│ │ ├── test_54.jpg
│ │ ├── test_54_size_64.jpg
│ │ ├── test_55.jpg
│ │ ├── test_55_size_64.jpg
│ │ ├── test_56.jpg
│ │ ├── test_56_size_64.jpg
│ │ ├── test_57.jpg
│ │ ├── test_57_size_64.jpg
│ │ ├── test_58.jpg
│ │ ├── test_58_size_64.jpg
│ │ ├── test_59.jpg
│ │ ├── test_59_size_64.jpg
│ │ ├── test_5_size_64.jpg
│ │ ├── test_6.jpg
│ │ ├── test_60.jpg
│ │ ├── test_60_size_64.jpg
│ │ ├── test_61.jpg
│ │ ├── test_61_size_64.jpg
│ │ ├── test_62.jpg
│ │ ├── test_62_size_64.jpg
│ │ ├── test_63.jpg
│ │ ├── test_63_size_64.jpg
│ │ ├── test_64.jpg
│ │ ├── test_64_size_64.jpg
│ │ ├── test_65.jpg
│ │ ├── test_65_size_64.jpg
│ │ ├── test_66.jpg
│ │ ├── test_66_size_64.jpg
│ │ ├── test_67.jpg
│ │ ├── test_67_size_64.jpg
│ │ ├── test_68.jpg
│ │ ├── test_68_size_64.jpg
│ │ ├── test_69.jpg
│ │ ├── test_69_size_64.jpg
│ │ ├── test_6_size_64.jpg
│ │ ├── test_7.jpg
│ │ ├── test_70.jpg
│ │ ├── test_70_size_64.jpg
│ │ ├── test_71.jpg
│ │ ├── test_71_size_64.jpg
│ │ ├── test_72.jpg
│ │ ├── test_72_size_64.jpg
│ │ ├── test_73.jpg
│ │ ├── test_73_size_64.jpg
│ │ ├── test_74.jpg
│ │ ├── test_74_size_64.jpg
│ │ ├── test_75.jpg
│ │ ├── test_75_size_64.jpg
│ │ ├── test_76.jpg
│ │ ├── test_76_size_64.jpg
│ │ ├── test_77.jpg
│ │ ├── test_77_size_64.jpg
│ │ ├── test_78.jpg
│ │ ├── test_78_size_64.jpg
│ │ ├── test_79.jpg
│ │ ├── test_79_size_64.jpg
│ │ ├── test_7_size_64.jpg
│ │ ├── test_8.jpg
│ │ ├── test_80.jpg
│ │ ├── test_80_size_64.jpg
│ │ ├── test_81.jpg
│ │ ├── test_81_size_64.jpg
│ │ ├── test_82.jpg
│ │ ├── test_82_size_64.jpg
│ │ ├── test_83.jpg
│ │ ├── test_83_size_64.jpg
│ │ ├── test_84.jpg
│ │ ├── test_84_size_64.jpg
│ │ ├── test_85.jpg
│ │ ├── test_85_size_64.jpg
│ │ ├── test_86.jpg
│ │ ├── test_86_size_64.jpg
│ │ ├── test_87.jpg
│ │ ├── test_87_size_64.jpg
│ │ ├── test_88.jpg
│ │ ├── test_88_size_64.jpg
│ │ ├── test_89.jpg
│ │ ├── test_89_size_64.jpg
│ │ ├── test_8_size_64.jpg
│ │ ├── test_9.jpg
│ │ ├── test_90.jpg
│ │ ├── test_90_size_64.jpg
│ │ ├── test_91.jpg
│ │ ├── test_91_size_64.jpg
│ │ ├── test_92.jpg
│ │ ├── test_92_size_64.jpg
│ │ ├── test_93.jpg
│ │ ├── test_93_size_64.jpg
│ │ ├── test_94.jpg
│ │ ├── test_94_size_64.jpg
│ │ ├── test_95.jpg
│ │ ├── test_95_size_64.jpg
│ │ ├── test_96.jpg
│ │ ├── test_96_size_64.jpg
│ │ ├── test_97.jpg
│ │ ├── test_97_size_64.jpg
│ │ ├── test_98.jpg
│ │ ├── test_98_size_64.jpg
│ │ ├── test_99.jpg
│ │ ├── test_99_size_64.jpg
│ │ └── test_9_size_64.jpg
│ ├── YYAnimatedImageWallCell.swift
│ └── YYAnimatedImageWallVC.swift
├── Podfile
└── Podfile.lock
├── LICENSE
├── README.md
└── README_resources
├── CompareImageLib.key
├── CompareImageLib.numbers
├── architecture.png
├── compare_diskCache.png
├── compare_gif_CPU_memory.png
├── compare_memoryCache.png
├── edit_common.gif
├── edit_filter.gif
└── original_image.gif
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | ## Playgrounds
32 | timeline.xctimeline
33 | playground.xcworkspace
34 |
35 | # Swift Package Manager
36 | #
37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
38 | # Packages/
39 | # Package.pins
40 | # Package.resolved
41 | .build/
42 |
43 | # CocoaPods
44 |
45 | Pods/
46 |
47 | # Carthage
48 | #
49 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
50 | # Carthage/Checkouts
51 |
52 | Carthage/Build
53 |
54 | # fastlane
55 | #
56 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
57 | # screenshots whenever they are needed.
58 | # For more information about the recommended setup visit:
59 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
60 |
61 | fastlane/report.xml
62 | fastlane/Preview.html
63 | fastlane/screenshots/**/*.png
64 | fastlane/test_output
65 |
66 | # Code Injection
67 | #
68 | # After new code Injection tools there's a generated folder /iOSInjectionProject
69 | # https://github.com/johnno1962/injectionforxcode
70 |
71 | iOSInjectionProject/
72 |
73 | # macOS
74 |
75 | .DS_Store
76 |
--------------------------------------------------------------------------------
/BBWebImage.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'BBWebImage'
3 | s.version = '1.1.3'
4 | s.summary = 'A high performance Swift library for downloading, caching and editing web images asynchronously.'
5 |
6 | s.description = <<-DESC
7 | View extensions for `UIImageView`, `UIButton`, `MKAnnotationView` and `CALayer` to set image from URL.
8 | Asynchronous image downloader.
9 | Asynchronous memory + file + SQLite image cache with least recently used algorithm.
10 | Asynchronous image decompressing.
11 | Asynchronous image editing without modifying original image disk data.
12 | Animated image smart decoding, decompressing, editing and caching.
13 | Independent image cache, downloader, coder and editor for separate use.
14 | Customized image cache, downloader and coder.
15 | High performance.
16 | DESC
17 |
18 | s.homepage = 'https://github.com/Silence-GitHub/BBWebImage'
19 |
20 | s.license = { :type => 'MIT', :file => 'LICENSE' }
21 |
22 | s.author = { 'Kaibo Lu' => 'lukaibolkb@gmail.com' }
23 |
24 | s.platform = :ios, '8.0'
25 |
26 | s.swift_version = '5.0'
27 |
28 | s.source = { :git => 'https://github.com/Silence-GitHub/BBWebImage.git', :tag => s.version }
29 |
30 | s.requires_arc = true
31 |
32 | s.default_subspec = 'Core'
33 |
34 | s.subspec 'Core' do |core|
35 | core.source_files = 'BBWebImage/BBWebImage/BBWebImage.h', 'BBWebImage/BBWebImage/**/*.swift'
36 | core.exclude_files = 'BBWebImage/BBWebImage/Extensions/MKAnnotationView+BBWebCache.swift', 'BBWebImage/BBWebImage/Filter/*'
37 | end
38 |
39 | s.subspec 'MapKit' do |mk|
40 | mk.source_files = 'BBWebImage/BBWebImage/Extensions/MKAnnotationView+BBWebCache.swift'
41 | mk.dependency 'BBWebImage/Core'
42 | end
43 |
44 | s.subspec 'Filter' do |filter|
45 | filter.source_files = 'BBWebImage/BBWebImage/Filter'
46 | filter.resources = 'BBWebImage/BBWebImage/**/*.cikernel'
47 | filter.dependency 'BBWebImage/Core'
48 | end
49 |
50 | end
51 |
--------------------------------------------------------------------------------
/BBWebImage.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/BBWebImage.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage.xcodeproj/xcshareddata/xcschemes/BBWebImageTests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
14 |
15 |
17 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
39 |
40 |
41 |
42 |
48 |
49 |
51 |
52 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage/BBWebImage.h:
--------------------------------------------------------------------------------
1 | //
2 | // BBWebImage.h
3 | // BBWebImage
4 | //
5 | // Created by Kaibo Lu on 2018/10/3.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for BBWebImage.
12 | FOUNDATION_EXPORT double BBWebImageVersionNumber;
13 |
14 | //! Project version string for BBWebImage.
15 | FOUNDATION_EXPORT const unsigned char BBWebImageVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage/Core/BBDiskCache.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BBDiskCache.swift
3 | // BBWebImage
4 | //
5 | // Created by Kaibo Lu on 2018/10/29.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | /// BBDiskCache is a key-value disk cache using least recently used algorithm
12 | public class BBDiskCache {
13 | private let storage: BBDiskStorage
14 | private let sizeThreshold: Int
15 | private let queue: BBDispatchQueuePool
16 | private var costLimit: Int
17 | private var countLimit: Int
18 | private var ageLimit: TimeInterval
19 |
20 | /// Crreates a BBDiskCache object
21 | ///
22 | /// - Parameters:
23 | /// - path: directory storing image data
24 | /// - threshold: threshold specifying image data is store in sqlite (data.count <= threshold) or file (data.count > threshold)
25 | public init?(path: String, sizeThreshold threshold: Int) {
26 | if let currentStorage = BBDiskStorage(path: path) {
27 | storage = currentStorage
28 | } else {
29 | return nil
30 | }
31 | sizeThreshold = threshold
32 | queue = BBDispatchQueuePool.utility
33 | costLimit = .max
34 | countLimit = .max
35 | ageLimit = .greatestFiniteMagnitude
36 | trimRecursively()
37 | }
38 |
39 | /// Gets data with key synchronously
40 | ///
41 | /// - Parameter key: cache key
42 | /// - Returns: data in disk, or nil if no data found
43 | public func data(forKey key: String) -> Data? {
44 | return storage.data(forKey: key)
45 | }
46 |
47 | /// Gets data with key asynchronously
48 | ///
49 | /// - Parameters:
50 | /// - key: cache key
51 | /// - completion: a closure called when querying is finished
52 | public func data(forKey key: String, completion: @escaping (Data?) -> Void) {
53 | queue.async { [weak self] in
54 | guard let self = self else { return }
55 | completion(self.data(forKey: key))
56 | }
57 | }
58 |
59 | /// Checks whether data is in the disk cache.
60 | /// This method checks cache synchronously.
61 | ///
62 | /// - Parameters:
63 | /// - key: cache key
64 | /// - Returns: true if data is in the cache, or false if not
65 | public func dataExists(forKey key: String) -> Bool {
66 | return storage.dataExists(forKey: key)
67 | }
68 |
69 | /// Checks whether data is in the disk cache.
70 | /// This method checks cache asynchronously.
71 | ///
72 | /// - Parameters:
73 | /// - key: cache key
74 | /// - completion: a closure called when checking is finished
75 | public func dataExists(forKey key: String, completion: @escaping BBImageCacheCheckDiskCompletion) {
76 | queue.async { [weak self] in
77 | guard let self = self else { return }
78 | completion(self.dataExists(forKey: key))
79 | }
80 | }
81 |
82 | /// Stores data with key synchronously
83 | ///
84 | /// - Parameters:
85 | /// - data: data to store
86 | /// - key: cache key
87 | public func store(_ data: Data, forKey key: String) {
88 | storage.store(data, forKey: key, type: (data.count > sizeThreshold ? .file : .sqlite))
89 | }
90 |
91 | /// Stores data with key asynchronously
92 | ///
93 | /// - Parameters:
94 | /// - data: data to store
95 | /// - key: cache key
96 | /// - completion: a closure called when storing is finished
97 | public func store(_ data: Data, forKey key: String, completion: BBImageCacheStoreCompletion?) {
98 | queue.async { [weak self] in
99 | guard let self = self else { return }
100 | self.store(data, forKey: key)
101 | completion?()
102 | }
103 | }
104 |
105 | /// Stores data with data work closure and key asynchronously
106 | ///
107 | /// - Parameters:
108 | /// - dataWork: a closure called in a background thread, returning data
109 | /// - key: cache key
110 | /// - completion: a closure called when storing is finished
111 | public func store(_ dataWork: @escaping () -> Data?, forKey key: String, completion: BBImageCacheStoreCompletion?) {
112 | queue.async { [weak self] in
113 | guard let self = self else { return }
114 | if let data = dataWork() {
115 | self.store(data, forKey: key)
116 | }
117 | completion?()
118 | }
119 | }
120 |
121 | /// Removes data with key synchronously
122 | ///
123 | /// - Parameter key: cache key
124 | public func removeData(forKey key: String) {
125 | storage.removeData(forKey: key)
126 | }
127 |
128 | /// Removes data with key asynchronously
129 | ///
130 | /// - Parameters:
131 | /// - key: cache key
132 | /// - completion: a closure called when removing is finished
133 | public func removeData(forKey key: String, completion: BBImageCacheRemoveCompletion?) {
134 | queue.async { [weak self] in
135 | guard let self = self else { return }
136 | self.removeData(forKey: key)
137 | completion?()
138 | }
139 | }
140 |
141 | /// Removes all data synchronously
142 | public func clear() {
143 | storage.clear()
144 | }
145 |
146 | /// Removes all data asynchronously
147 | ///
148 | /// - Parameter completion: a closure called when clearing is finished
149 | public func clear(_ completion: BBImageCacheRemoveCompletion?) {
150 | queue.async { [weak self] in
151 | guard let self = self else { return }
152 | self.clear()
153 | completion?()
154 | }
155 | }
156 |
157 | private func trimRecursively() {
158 | DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 60) { [weak self] in
159 | guard let self = self else { return }
160 | self.storage.trim(toCost: self.costLimit)
161 | self.storage.trim(toCount: self.countLimit)
162 | self.storage.trim(toAge: self.ageLimit)
163 | self.trimRecursively()
164 | }
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage/Core/BBDispatchQueuePool.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BBDispatchQueuePool.swift
3 | // BBWebImage
4 | //
5 | // Created by Kaibo Lu on 2018/11/9.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | /// BBDispatchQueuePool holds mutiple serial queues.
12 | /// To prevent concurrent queue increasing thread count, use this class to control thread count.
13 | public class BBDispatchQueuePool {
14 | public static let userInteractive = BBDispatchQueuePool(label: "com.Kaibo.BBWebImage.QueuePool.userInteractive", qos: .userInteractive)
15 | public static let userInitiated = BBDispatchQueuePool(label: "com.Kaibo.BBWebImage.QueuePool.userInitiated", qos: .userInitiated)
16 | public static let utility = BBDispatchQueuePool(label: "com.Kaibo.BBWebImage.QueuePool.utility", qos: .utility)
17 | public static let `default` = BBDispatchQueuePool(label: "com.Kaibo.BBWebImage.QueuePool.default", qos: .default)
18 | public static let background = BBDispatchQueuePool(label: "com.Kaibo.BBWebImage.QueuePool.background", qos: .background)
19 |
20 | private let queues: [DispatchQueue]
21 | private var index: Int32
22 |
23 | /// Gets a dispatch queue from pool
24 | public var currentQueue: DispatchQueue {
25 | var currentIndex = OSAtomicIncrement32(&index)
26 | if currentIndex < 0 { currentIndex = -currentIndex }
27 | return queues[Int(currentIndex) % queues.count]
28 | }
29 |
30 | /// Creates a BBDispatchQueuePool object
31 | ///
32 | /// - Parameters:
33 | /// - label: dispatch queue label
34 | /// - qos: quality of service for dispatch queue
35 | /// - queueCount: dispatch queue count
36 | public init(label: String, qos: DispatchQoS, queueCount: Int = 0) {
37 | let count = queueCount > 0 ? queueCount : min(16, max(1, ProcessInfo.processInfo.activeProcessorCount))
38 | var pool: [DispatchQueue] = []
39 | for i in 0.. Void) {
51 | currentQueue.async(execute: work)
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage/Core/BBImageDownloadOperationQueue.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BBImageDownloadOperationQueue.swift
3 | // BBWebImage
4 | //
5 | // Created by Kaibo Lu on 2/1/19.
6 | // Copyright © 2019 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | private class BBImageDownloadLinkedMapNode {
12 | fileprivate weak var prev: BBImageDownloadLinkedMapNode?
13 | fileprivate weak var next: BBImageDownloadLinkedMapNode?
14 | fileprivate var key: URL
15 | fileprivate var value: BBImageDownloadOperation
16 |
17 | fileprivate init(key: URL, value: BBImageDownloadOperation) {
18 | self.key = key
19 | self.value = value
20 | }
21 | }
22 |
23 | private class BBImageDownloadLinkedMap {
24 | fileprivate var dic: [URL : BBImageDownloadLinkedMapNode]
25 | fileprivate var head: BBImageDownloadLinkedMapNode?
26 | fileprivate var tail: BBImageDownloadLinkedMapNode?
27 |
28 | init() { dic = [:] }
29 |
30 | fileprivate func enqueue(_ node: BBImageDownloadLinkedMapNode) {
31 | dic[node.key] = node
32 | if head == nil {
33 | head = node
34 | tail = node
35 | } else {
36 | tail?.next = node
37 | node.prev = tail
38 | tail = node
39 | }
40 | }
41 |
42 | fileprivate func dequeue() -> BBImageDownloadLinkedMapNode? {
43 | if let node = head {
44 | remove(node)
45 | return node
46 | }
47 | return nil
48 | }
49 |
50 | fileprivate func remove(_ node: BBImageDownloadLinkedMapNode) {
51 | dic[node.key] = nil
52 | node.prev?.next = node.next
53 | node.next?.prev = node.prev
54 | if head === node { head = node.next }
55 | if tail === node { tail = node.prev }
56 | }
57 | }
58 |
59 | class BBImageDownloadOperationQueue {
60 | private let waitingQueue: BBImageDownloadLinkedMap
61 | private let preloadWaitingQueue: BBImageDownloadLinkedMap
62 | var maxRunningCount: Int
63 | private(set) var currentRunningCount: Int
64 |
65 | init() {
66 | waitingQueue = BBImageDownloadLinkedMap()
67 | preloadWaitingQueue = BBImageDownloadLinkedMap()
68 | maxRunningCount = 1
69 | currentRunningCount = 0
70 | }
71 |
72 | func add(_ operation: BBImageDownloadOperation, preload: Bool) {
73 | if currentRunningCount < maxRunningCount {
74 | currentRunningCount += 1
75 | BBDispatchQueuePool.background.async { [weak self] in
76 | guard self != nil else { return }
77 | operation.start()
78 | }
79 | } else {
80 | let node = BBImageDownloadLinkedMapNode(key: operation.url, value: operation)
81 | if preload { preloadWaitingQueue.enqueue(node) }
82 | else { waitingQueue.enqueue(node) }
83 | }
84 | }
85 |
86 | func removeOperation(forKey key: URL) {
87 | if let node = waitingQueue.dic[key] {
88 | waitingQueue.remove(node)
89 | } else if let node = preloadWaitingQueue.dic[key] {
90 | preloadWaitingQueue.remove(node)
91 | } else if let next = waitingQueue.dequeue()?.value {
92 | BBDispatchQueuePool.background.async { [weak self] in
93 | guard self != nil else { return }
94 | next.start()
95 | }
96 | } else if let next = preloadWaitingQueue.dequeue()?.value {
97 | BBDispatchQueuePool.background.async { [weak self] in
98 | guard self != nil else { return }
99 | next.start()
100 | }
101 | } else {
102 | currentRunningCount -= 1
103 | assert(currentRunningCount >= 0, "currentRunningCount must >= 0")
104 | }
105 | }
106 |
107 | func upgradePreloadOperation(for key: URL) {
108 | if let node = preloadWaitingQueue.dic[key] {
109 | preloadWaitingQueue.remove(node)
110 | node.prev = nil
111 | node.next = nil
112 | waitingQueue.enqueue(node)
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage/Core/BBWeakProxy.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BBWeakProxy.swift
3 | // BBWebImage
4 | //
5 | // Created by Kaibo Lu on 2/6/19.
6 | // Copyright © 2019 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public class BBWeakProxy: NSObject {
12 | private weak var target: NSObjectProtocol?
13 |
14 | public init(target: NSObjectProtocol) {
15 | self.target = target
16 | }
17 |
18 | public override func responds(to aSelector: Selector!) -> Bool {
19 | return (target?.responds(to: aSelector) ?? false) || super.responds(to: aSelector)
20 | }
21 |
22 | public override func forwardingTarget(for aSelector: Selector!) -> Any? {
23 | return target
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage/Core/BBWebCacheResource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BBWebCacheResource.swift
3 | // BBWebImage
4 | //
5 | // Created by Kaibo Lu on 2018/12/8.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | /// BBWebCacheResource defines how to download and cache image
12 | public protocol BBWebCacheResource {
13 | var cacheKey: String { get }
14 | var downloadUrl: URL { get }
15 | }
16 |
17 | extension URL: BBWebCacheResource {
18 | public var cacheKey: String { return absoluteString }
19 | public var downloadUrl: URL { return self }
20 | }
21 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage/Core/BBWebImageGIFCoder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BBWebImageGIFCoder.swift
3 | // BBWebImage
4 | //
5 | // Created by Kaibo Lu on 2/6/19.
6 | // Copyright © 2019 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import MobileCoreServices
11 |
12 | public class BBWebImageGIFCoder: BBAnimatedImageCoder {
13 | private var imageSource: CGImageSource?
14 | private var imageOrientation: UIImage.Orientation
15 |
16 | public var imageData: Data? {
17 | didSet {
18 | if let data = imageData {
19 | imageSource = CGImageSourceCreateWithData(data as CFData, nil)
20 | if let source = imageSource,
21 | let properties = CGImageSourceCopyProperties(source, nil) as? [CFString : Any],
22 | let rawValue = properties[kCGImagePropertyOrientation] as? UInt32,
23 | let orientation = CGImagePropertyOrientation(rawValue: rawValue) {
24 | imageOrientation = orientation.bb_UIImageOrientation
25 | }
26 | } else {
27 | imageSource = nil
28 | }
29 | }
30 | }
31 |
32 | public var frameCount: Int? {
33 | if let source = imageSource {
34 | let count = CGImageSourceGetCount(source)
35 | if count > 0 { return count }
36 | }
37 | return nil
38 | }
39 |
40 | public var loopCount: Int? {
41 | if let source = imageSource,
42 | let properties = CGImageSourceCopyProperties(source, nil) as? [CFString : Any],
43 | let gifInfo = properties[kCGImagePropertyGIFDictionary] as? [CFString : Any],
44 | let count = gifInfo[kCGImagePropertyGIFLoopCount] as? Int {
45 | return count
46 | }
47 | return nil
48 | }
49 |
50 | public init() {
51 | imageOrientation = .up
52 | }
53 |
54 | public func imageFrame(at index: Int, decompress: Bool) -> UIImage? {
55 | if let source = imageSource,
56 | let sourceImage = CGImageSourceCreateImageAtIndex(source, index, [kCGImageSourceShouldCache : true] as CFDictionary) {
57 | if decompress {
58 | if let cgimage = BBWebImageImageIOCoder.decompressedImage(sourceImage) {
59 | return UIImage(cgImage: cgimage, scale: 1, orientation: imageOrientation)
60 | }
61 | } else {
62 | return UIImage(cgImage: sourceImage, scale: 1, orientation: imageOrientation)
63 | }
64 | }
65 | return nil
66 | }
67 |
68 | public func duration(at index: Int) -> TimeInterval? {
69 | if let source = imageSource,
70 | let properties = CGImageSourceCopyPropertiesAtIndex(source, index, nil) as? [CFString : Any],
71 | let gifInfo = properties[kCGImagePropertyGIFDictionary] as? [CFString : Any] {
72 | var currentDuration: TimeInterval = -1
73 | if let d = gifInfo[kCGImagePropertyGIFUnclampedDelayTime] as? TimeInterval {
74 | currentDuration = d
75 | } else if let d = gifInfo[kCGImagePropertyGIFDelayTime] as? TimeInterval {
76 | currentDuration = d
77 | }
78 | if currentDuration >= 0 {
79 | if currentDuration < 0.01 { currentDuration = 0.1 }
80 | return currentDuration
81 | }
82 | }
83 | return nil
84 | }
85 |
86 | public func imageFrameSize(at index: Int) -> CGSize? {
87 | if let source = imageSource,
88 | let properties = CGImageSourceCopyPropertiesAtIndex(source, index, nil) as? [CFString : Any],
89 | let width = properties[kCGImagePropertyPixelWidth] as? Int,
90 | width > 0,
91 | let height = properties[kCGImagePropertyPixelHeight] as? Int,
92 | height > 0 {
93 | return CGSize(width: width, height: height)
94 | }
95 | return nil
96 | }
97 | }
98 |
99 | extension BBWebImageGIFCoder: BBImageCoder {
100 | public func canDecode(_ data: Data) -> Bool {
101 | return data.bb_imageFormat == .GIF
102 | }
103 |
104 | public func decodedImage(with data: Data) -> UIImage? {
105 | let image = BBAnimatedImage(bb_data: data, decoder: copy() as? BBAnimatedImageCoder)
106 | image?.bb_imageFormat = data.bb_imageFormat
107 | return image
108 | }
109 |
110 | public func decompressedImage(with image: UIImage, data: Data) -> UIImage? {
111 | return nil
112 | }
113 |
114 | public func canEncode(_ format: BBImageFormat) -> Bool {
115 | return format == .GIF
116 | }
117 |
118 | public func encodedData(with image: UIImage, format: BBImageFormat) -> Data? {
119 | if format != .GIF { return nil }
120 | if let animatedImage = image as? BBAnimatedImage,
121 | animatedImage.bb_imageFormat == .GIF {
122 | return animatedImage.bb_originalImageData
123 | }
124 | var sourceImages: [CGImage] = []
125 | if let images = image.images {
126 | for frame in images {
127 | if let sourceImage = frame.cgImage {
128 | sourceImages.append(sourceImage)
129 | }
130 | }
131 | }
132 | if sourceImages.isEmpty,
133 | let sourceImage = image.cgImage {
134 | sourceImages.append(sourceImage)
135 | }
136 | guard !sourceImages.isEmpty,
137 | let data = CFDataCreateMutable(kCFAllocatorDefault, 0),
138 | let destination = CGImageDestinationCreateWithData(data, kUTTypeGIF, sourceImages.count, nil) else { return nil }
139 | if sourceImages.count == 1 {
140 | CGImageDestinationAddImage(destination, sourceImages.first!, nil)
141 | } else {
142 | let properties: [CFString : Any] = [kCGImagePropertyGIFDictionary : [kCGImagePropertyGIFLoopCount : 0]]
143 | CGImageDestinationSetProperties(destination, properties as CFDictionary)
144 |
145 | let frameDuration = image.duration / Double(image.images!.count)
146 | let frameProperties: [CFString : Any] = [kCGImagePropertyGIFDictionary : [kCGImagePropertyGIFUnclampedDelayTime : frameDuration]]
147 | for sourceImage in sourceImages {
148 | CGImageDestinationAddImage(destination, sourceImage, frameProperties as CFDictionary)
149 | }
150 | }
151 | if CGImageDestinationFinalize(destination) { return data as Data }
152 | return nil
153 | }
154 |
155 | public func copy() -> BBImageCoder { return BBWebImageGIFCoder() }
156 | }
157 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage/Core/BBWebImageImageIOCoder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BBWebImageImageIOCoder.swift
3 | // BBWebImage
4 | //
5 | // Created by Kaibo Lu on 2018/10/8.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public class BBWebImageImageIOCoder: BBImageCoder {
12 | private var imageSource: CGImageSource?
13 | private var imageWidth: Int
14 | private var imageHeight: Int
15 | private var imageOrientation: UIImage.Orientation
16 |
17 | public init() {
18 | imageWidth = 0
19 | imageHeight = 0
20 | imageOrientation = .up
21 | }
22 |
23 | public func canDecode(_ data: Data) -> Bool {
24 | switch data.bb_imageFormat {
25 | case .JPEG, .PNG:
26 | return true
27 | default:
28 | return false
29 | }
30 | }
31 |
32 | public func decodedImage(with data: Data) -> UIImage? {
33 | let image = UIImage(data: data)
34 | image?.bb_imageFormat = data.bb_imageFormat
35 | return image
36 | }
37 |
38 | public func decompressedImage(with image: UIImage, data: Data) -> UIImage? {
39 | guard let sourceImage = image.cgImage,
40 | let cgimage = BBWebImageImageIOCoder.decompressedImage(sourceImage) else { return image }
41 | let finalImage = UIImage(cgImage: cgimage, scale: image.scale, orientation: image.imageOrientation)
42 | finalImage.bb_imageFormat = image.bb_imageFormat
43 | return finalImage
44 | }
45 |
46 | public static func decompressedImage(_ sourceImage: CGImage) -> CGImage? {
47 | return autoreleasepool { () -> CGImage? in
48 | let width = sourceImage.width
49 | let height = sourceImage.height
50 | var bitmapInfo = sourceImage.bitmapInfo
51 | bitmapInfo.remove(.alphaInfoMask)
52 | if sourceImage.bb_containsAlpha {
53 | bitmapInfo = CGBitmapInfo(rawValue: bitmapInfo.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue)
54 | } else {
55 | bitmapInfo = CGBitmapInfo(rawValue: bitmapInfo.rawValue | CGImageAlphaInfo.noneSkipFirst.rawValue)
56 | }
57 | guard let context = CGContext(data: nil,
58 | width: width,
59 | height: height,
60 | bitsPerComponent: sourceImage.bitsPerComponent,
61 | bytesPerRow: 0,
62 | space: bb_shareColorSpace,
63 | bitmapInfo: bitmapInfo.rawValue) else { return nil }
64 | context.draw(sourceImage, in: CGRect(x: 0, y: 0, width: width, height: height))
65 | return context.makeImage()
66 | }
67 | }
68 |
69 | public func canEncode(_ format: BBImageFormat) -> Bool {
70 | return true
71 | }
72 |
73 | public func encodedData(with image: UIImage, format: BBImageFormat) -> Data? {
74 | guard let sourceImage = image.cgImage,
75 | let data = CFDataCreateMutable(kCFAllocatorDefault, 0) else { return nil }
76 | var imageFormat = format
77 | if format == .unknown { imageFormat = sourceImage.bb_containsAlpha ? .PNG : .JPEG }
78 | if let destination = CGImageDestinationCreateWithData(data, imageFormat.UTType, 1, nil) {
79 | let properties = [kCGImagePropertyOrientation : image.imageOrientation.bb_CGImageOrientation.rawValue]
80 | CGImageDestinationAddImage(destination, sourceImage, properties as CFDictionary)
81 | if CGImageDestinationFinalize(destination) { return data as Data }
82 | }
83 | return nil
84 | }
85 |
86 | public func copy() -> BBImageCoder { return BBWebImageImageIOCoder() }
87 | }
88 |
89 | extension BBWebImageImageIOCoder: BBImageProgressiveCoder {
90 | public func canIncrementallyDecode(_ data: Data) -> Bool {
91 | switch data.bb_imageFormat {
92 | case .JPEG, .PNG:
93 | return true
94 | default:
95 | return false
96 | }
97 | }
98 |
99 | public func incrementallyDecodedImage(with data: Data, finished: Bool) -> UIImage? {
100 | if imageSource == nil {
101 | imageSource = CGImageSourceCreateIncremental(nil)
102 | }
103 | guard let source = imageSource else { return nil }
104 | CGImageSourceUpdateData(source, data as CFData, finished)
105 | var image: UIImage?
106 | if imageWidth <= 0 || imageHeight <= 0,
107 | let properties = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) as? [CFString : AnyObject] {
108 | if let width = properties[kCGImagePropertyPixelWidth] as? Int {
109 | imageWidth = width
110 | }
111 | if let height = properties[kCGImagePropertyPixelHeight] as? Int {
112 | imageHeight = height
113 | }
114 | if let rawValue = properties[kCGImagePropertyOrientation] as? UInt32,
115 | let orientation = CGImagePropertyOrientation(rawValue: rawValue) {
116 | imageOrientation = orientation.bb_UIImageOrientation
117 | }
118 | }
119 | if imageWidth > 0 && imageHeight > 0,
120 | let cgimage = CGImageSourceCreateImageAtIndex(source, 0, nil) {
121 | image = UIImage(cgImage: cgimage, scale: 1, orientation: imageOrientation)
122 | image?.bb_imageFormat = data.bb_imageFormat
123 | }
124 | if finished {
125 | imageSource = nil
126 | imageWidth = 0
127 | imageHeight = 0
128 | imageOrientation = .up
129 | }
130 | return image
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage/Extensions/CALayer+BBWebCache.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CALayer+BBWebCache.swift
3 | // BBWebImage
4 | //
5 | // Created by Kaibo Lu on 2018/12/7.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension CALayer: BBWebCache {
12 | /// Sets image with resource, placeholder, custom opotions
13 | ///
14 | /// - Parameters:
15 | /// - resource: image resource specifying how to download and cache image
16 | /// - placeholder: placeholder image displayed when loading image
17 | /// - options: options for some behaviors
18 | /// - editor: editor specifying how to edit and cache image in memory
19 | /// - progress: a closure called while image is downloading
20 | /// - completion: a closure called when image loading is finished
21 | public func bb_setImage(with resource: BBWebCacheResource,
22 | placeholder: UIImage? = nil,
23 | options: BBWebImageOptions = .none,
24 | editor: BBWebImageEditor? = nil,
25 | progress: BBImageDownloaderProgress? = nil,
26 | completion: BBWebImageManagerCompletion? = nil) {
27 | let setImage: BBSetImage = { [weak self] (image) in
28 | if let self = self { self.contents = image?.cgImage }
29 | }
30 | bb_setImage(with: resource,
31 | placeholder: placeholder,
32 | options: options,
33 | editor: editor,
34 | taskKey: bb_imageLoadTaskKey,
35 | setImage: setImage,
36 | progress: progress,
37 | completion: completion)
38 | }
39 |
40 | /// Cancels image loading task
41 | public func bb_cancelImageLoadTask() {
42 | bb_webCacheOperation.task(forKey: bb_imageLoadTaskKey)?.cancel()
43 | }
44 |
45 | public var bb_imageLoadTaskKey: String { return classForCoder.description() }
46 | }
47 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage/Extensions/Data+ImageFormat.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Data+ImageFormat.swift
3 | // BBWebImage
4 | //
5 | // Created by Kaibo Lu on 2018/10/8.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import MobileCoreServices
11 |
12 | public enum BBImageFormat {
13 | case unknown
14 | case JPEG
15 | case PNG
16 | case GIF
17 |
18 | var UTType: CFString {
19 | switch self {
20 | case .JPEG:
21 | return kUTTypeJPEG
22 | case .PNG:
23 | return kUTTypePNG
24 | case .GIF:
25 | return kUTTypeGIF
26 | default:
27 | return kUTTypeImage
28 | }
29 | }
30 | }
31 |
32 | public extension Data {
33 | var bb_imageFormat: BBImageFormat {
34 | if let firstByte = self.first {
35 | switch firstByte {
36 | case 0xFF: return .JPEG // https://en.wikipedia.org/wiki/JPEG
37 | case 0x89: return .PNG // https://en.wikipedia.org/wiki/Portable_Network_Graphics
38 | case 0x47: return .GIF // https://en.wikipedia.org/wiki/GIF
39 | default: return .unknown
40 | }
41 | }
42 | return .unknown
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage/Extensions/DispatchQueue+Safe.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DispatchQueue+Safe.swift
3 | // BBWebImage
4 | //
5 | // Created by Kaibo Lu on 2018/10/8.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension DispatchQueue {
12 | func bb_safeAsync(_ work: @escaping () -> Void) {
13 | if label == String(cString: __dispatch_queue_get_label(nil), encoding: .utf8) {
14 | work()
15 | } else {
16 | async(execute: work)
17 | }
18 | }
19 |
20 | func bb_safeSync(_ work: @escaping () -> Void) {
21 | if label == String(cString: __dispatch_queue_get_label(nil), encoding: .utf8) {
22 | work()
23 | } else {
24 | sync(execute: work)
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage/Extensions/MKAnnotationView+BBWebCache.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MKAnnotationView+BBWebCache.swift
3 | // BBWebImage
4 | //
5 | // Created by Kaibo Lu on 2018/12/7.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import MapKit
11 |
12 | extension MKAnnotationView: BBWebCache {
13 | /// Sets image with resource, placeholder, custom opotions
14 | ///
15 | /// - Parameters:
16 | /// - resource: image resource specifying how to download and cache image
17 | /// - placeholder: placeholder image displayed when loading image
18 | /// - options: options for some behaviors
19 | /// - editor: editor specifying how to edit and cache image in memory
20 | /// - progress: a closure called while image is downloading
21 | /// - completion: a closure called when image loading is finished
22 | public func bb_setImage(with resource: BBWebCacheResource,
23 | placeholder: UIImage? = nil,
24 | options: BBWebImageOptions = .none,
25 | editor: BBWebImageEditor? = nil,
26 | progress: BBImageDownloaderProgress? = nil,
27 | completion: BBWebImageManagerCompletion? = nil) {
28 | let setImage: BBSetImage = { [weak self] (image) in
29 | if let self = self { self.image = image }
30 | }
31 | bb_setImage(with: resource,
32 | placeholder: placeholder,
33 | options: options,
34 | editor: editor,
35 | taskKey: bb_imageLoadTaskKey,
36 | setImage: setImage,
37 | progress: progress,
38 | completion: completion)
39 | }
40 |
41 | /// Cancels image loading task
42 | public func bb_cancelImageLoadTask() {
43 | bb_webCacheOperation.task(forKey: bb_imageLoadTaskKey)?.cancel()
44 | }
45 |
46 | public var bb_imageLoadTaskKey: String { return classForCoder.description() }
47 | }
48 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage/Extensions/String+MD5.swift:
--------------------------------------------------------------------------------
1 | //
2 | // String+MD5.swift
3 | // BBWebImage
4 | //
5 | // Created by Kaibo Lu on 2018/10/12.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import CommonCrypto
11 |
12 | public extension String {
13 | var bb_md5: String {
14 | guard let data = data(using: .utf8) else { return self }
15 | var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
16 | _ = data.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
17 | return CC_MD5(bytes.baseAddress, CC_LONG(data.count), &digest)
18 | }
19 | return digest.map { String(format: "%02x", $0) }.joined()
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage/Extensions/UIButton+BBWebCache.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIButton+BBWebCache.swift
3 | // BBWebImage
4 | //
5 | // Created by Kaibo Lu on 2018/10/9.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIButton: BBWebCache {
12 | /// Sets image with resource, placeholder, custom opotions
13 | ///
14 | /// - Parameters:
15 | /// - resource: image resource specifying how to download and cache image
16 | /// - state: button state to set image
17 | /// - placeholder: placeholder image displayed when loading image
18 | /// - options: options for some behaviors
19 | /// - editor: editor specifying how to edit and cache image in memory
20 | /// - progress: a closure called while image is downloading
21 | /// - completion: a closure called when image loading is finished
22 | public func bb_setImage(with resource: BBWebCacheResource,
23 | forState state: UIControl.State,
24 | placeholder: UIImage? = nil,
25 | options: BBWebImageOptions = .none,
26 | editor: BBWebImageEditor? = nil,
27 | progress: BBImageDownloaderProgress? = nil,
28 | completion: BBWebImageManagerCompletion? = nil) {
29 | let setImage: BBSetImage = { [weak self] (image) in
30 | if let self = self { self.setImage(image, for: state) }
31 | }
32 | bb_setImage(with: resource,
33 | placeholder: placeholder,
34 | options: options,
35 | editor: editor,
36 | taskKey: bb_imageLoadTaskKey(forState: state),
37 | setImage: setImage,
38 | progress: progress,
39 | completion: completion)
40 | }
41 |
42 | /// Cancels image loading task
43 | ///
44 | /// - Parameter state: button state to set image
45 | public func bb_cancelImageLoadTask(forState state: UIControl.State) {
46 | let key = bb_imageLoadTaskKey(forState: state)
47 | bb_webCacheOperation.task(forKey: key)?.cancel()
48 | }
49 |
50 | public func bb_imageLoadTaskKey(forState state: UIControl.State) -> String {
51 | return classForCoder.description() + "Image\(state.rawValue)"
52 | }
53 |
54 | /// Sets background image with resource, placeholder, custom opotions
55 | ///
56 | /// - Parameters:
57 | /// - resource: image resource specifying how to download and cache image
58 | /// - state: button state to set background image
59 | /// - placeholder: placeholder image displayed when loading image
60 | /// - options: options for some behaviors
61 | /// - editor: editor specifying how to edit and cache image in memory
62 | /// - progress: a closure called while image is downloading
63 | /// - completion: a closure called when image loading is finished
64 | public func bb_setBackgroundImage(with resource: BBWebCacheResource,
65 | forState state: UIControl.State,
66 | placeholder: UIImage? = nil,
67 | options: BBWebImageOptions = .none,
68 | editor: BBWebImageEditor? = nil,
69 | progress: BBImageDownloaderProgress? = nil,
70 | completion: BBWebImageManagerCompletion? = nil) {
71 | let setImage: BBSetImage = { [weak self] (image) in
72 | if let self = self { self.setBackgroundImage(image, for: state) }
73 | }
74 | bb_setImage(with: resource,
75 | placeholder: placeholder,
76 | options: options,
77 | editor: editor,
78 | taskKey: bb_backgroundImageLoadTaskKey(forState: state),
79 | setImage: setImage,
80 | progress: progress,
81 | completion: completion)
82 | }
83 |
84 | /// Cancels background image loading task
85 | ///
86 | /// - Parameter state: button state to set background image
87 | public func bb_cancelBackgroundImageLoadTask(forState state: UIControl.State) {
88 | let key = bb_backgroundImageLoadTaskKey(forState: state)
89 | bb_webCacheOperation.task(forKey: key)?.cancel()
90 | }
91 |
92 | public func bb_backgroundImageLoadTaskKey(forState state: UIControl.State) -> String {
93 | return classForCoder.description() + "BackgroundImage\(state.rawValue)"
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage/Extensions/UIDevice+BBAdd.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIDevice+BBAdd.swift
3 | // BBWebImage
4 | //
5 | // Created by Kaibo Lu on 2/11/19.
6 | // Copyright © 2019 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIDevice {
12 | static var bb_totalMemory: Int64 { return Int64(ProcessInfo().physicalMemory) }
13 |
14 | static var bb_freeMemory: Int64 {
15 | let host_port = mach_host_self()
16 | var page_size: vm_size_t = 0
17 | guard host_page_size(host_port, &page_size) == KERN_SUCCESS else { return -1 }
18 | var host_size = mach_msg_type_number_t(MemoryLayout.size / MemoryLayout.size)
19 | let hostInfo = vm_statistics_t.allocate(capacity: 1)
20 | let kern = hostInfo.withMemoryRebound(to: integer_t.self, capacity: Int(host_size)) {
21 | host_statistics(host_port, HOST_VM_INFO, $0, &host_size)
22 | }
23 | let vm_stat = hostInfo.move()
24 | hostInfo.deallocate()
25 | guard kern == KERN_SUCCESS else { return -1 }
26 | return Int64(page_size) * Int64(vm_stat.free_count)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage/Extensions/UIImage+ImageFormat.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+ImageFormat.swift
3 | // BBWebImage
4 | //
5 | // Created by Kaibo Lu on 2018/10/8.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | private var imageFormatKey: Void?
12 | private var imageDataKey: Void?
13 | private var imageEditKey: Void?
14 |
15 | public extension UIImage {
16 | var bb_imageFormat: BBImageFormat? {
17 | get { return objc_getAssociatedObject(self, &imageFormatKey) as? BBImageFormat }
18 | set { objc_setAssociatedObject(self, &imageFormatKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
19 | }
20 |
21 | var bb_imageEditKey: String? {
22 | get { return objc_getAssociatedObject(self, &imageEditKey) as? String }
23 | set { objc_setAssociatedObject(self, &imageEditKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
24 | }
25 |
26 | var bb_bytes: Int64 { return Int64(size.width * size.height * scale) }
27 | }
28 |
29 | public extension CGImage {
30 | var bb_containsAlpha: Bool { return !(alphaInfo == .none || alphaInfo == .noneSkipFirst || alphaInfo == .noneSkipLast) }
31 | var bb_bytes: Int { return max(1, height * bytesPerRow) }
32 | }
33 |
34 | extension CGImagePropertyOrientation {
35 | var bb_UIImageOrientation: UIImage.Orientation {
36 | switch self {
37 | case .up: return .up
38 | case .down: return .down
39 | case .left: return .left
40 | case .right: return .right
41 | case .upMirrored: return .upMirrored
42 | case .downMirrored: return .downMirrored
43 | case .leftMirrored: return .leftMirrored
44 | case .rightMirrored: return .downMirrored
45 | default: return .up
46 | }
47 | }
48 | }
49 |
50 | extension UIImage.Orientation {
51 | var bb_CGImageOrientation: CGImagePropertyOrientation {
52 | switch self {
53 | case .up: return .up
54 | case .down: return .down
55 | case .left: return .left
56 | case .right: return .right
57 | case .upMirrored: return .upMirrored
58 | case .downMirrored: return .downMirrored
59 | case .leftMirrored: return .leftMirrored
60 | case .rightMirrored: return .rightMirrored
61 | default: return .up
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage/Extensions/UIImageView+BBWebCache.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImageView+BBWebCache.swift
3 | // BBWebImage
4 | //
5 | // Created by Kaibo Lu on 2018/10/9.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIImageView: BBWebCache {
12 | /// Sets image with resource, placeholder, custom opotions
13 | ///
14 | /// - Parameters:
15 | /// - resource: image resource specifying how to download and cache image
16 | /// - placeholder: placeholder image displayed when loading image
17 | /// - options: options for some behaviors
18 | /// - editor: editor specifying how to edit and cache image in memory
19 | /// - progress: a closure called while image is downloading
20 | /// - completion: a closure called when image loading is finished
21 | public func bb_setImage(with resource: BBWebCacheResource,
22 | placeholder: UIImage? = nil,
23 | options: BBWebImageOptions = .none,
24 | editor: BBWebImageEditor? = nil,
25 | progress: BBImageDownloaderProgress? = nil,
26 | completion: BBWebImageManagerCompletion? = nil) {
27 | let setImage: BBSetImage = { [weak self] (image) in
28 | if let self = self { self.image = image }
29 | }
30 | bb_setImage(with: resource,
31 | placeholder: placeholder,
32 | options: options,
33 | editor: editor,
34 | taskKey: bb_imageLoadTaskKey,
35 | setImage: setImage,
36 | progress: progress,
37 | completion: completion)
38 | }
39 |
40 | /// Cancels image loading task
41 | public func bb_cancelImageLoadTask() {
42 | bb_webCacheOperation.task(forKey: bb_imageLoadTaskKey)?.cancel()
43 | }
44 |
45 | public var bb_imageLoadTaskKey: String { return classForCoder.description() }
46 |
47 | /// Sets highlighted image with resource, placeholder, custom opotions
48 | ///
49 | /// - Parameters:
50 | /// - resource: image resource specifying how to download and cache image
51 | /// - placeholder: placeholder image displayed when loading image
52 | /// - options: options for some behaviors
53 | /// - editor: editor specifying how to edit and cache image in memory
54 | /// - progress: a closure called while image is downloading
55 | /// - completion: a closure called when image loading is finished
56 | public func bb_setHighlightedImage(with resource: BBWebCacheResource,
57 | placeholder: UIImage? = nil,
58 | options: BBWebImageOptions = .none,
59 | editor: BBWebImageEditor? = nil,
60 | progress: BBImageDownloaderProgress? = nil,
61 | completion: BBWebImageManagerCompletion? = nil) {
62 | let setImage: BBSetImage = { [weak self] (image) in
63 | if let self = self { self.highlightedImage = image }
64 | }
65 | bb_setImage(with: resource,
66 | placeholder: placeholder,
67 | options: options,
68 | editor: editor,
69 | taskKey: bb_highlightedImageLoadTaskKey,
70 | setImage: setImage,
71 | progress: progress,
72 | completion: completion)
73 | }
74 |
75 | /// Cancels highlighted image loading task
76 | public func bb_cancelHighlightedImageLoadTask() {
77 | bb_webCacheOperation.task(forKey: bb_highlightedImageLoadTaskKey)?.cancel()
78 | }
79 |
80 | public var bb_highlightedImageLoadTaskKey: String { return classForCoder.description() + "Highlighted" }
81 | }
82 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage/Filter/BBCILookup.cikernel:
--------------------------------------------------------------------------------
1 | kernel vec4 filterKernel(sampler inputImage, sampler inputLUT, float intensity) {
2 | vec4 textureColor = sample(inputImage,samplerCoord(inputImage));
3 | textureColor = clamp(textureColor, vec4(0.0), vec4(1.0));
4 |
5 | float blueColor = textureColor.b * 63.0;
6 |
7 | vec2 quad1;
8 | quad1.y = floor(floor(blueColor) / 8.0);
9 | quad1.x = floor(blueColor) - (quad1.y * 8.0);
10 |
11 | vec2 quad2;
12 | quad2.y = floor(ceil(blueColor) / 8.0);
13 | quad2.x = ceil(blueColor) - (quad2.y * 8.0);
14 |
15 | vec2 texPos1;
16 | texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
17 | texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);
18 |
19 | vec2 texPos2;
20 | texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
21 | texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);
22 |
23 | texPos1.y = 1.0 - texPos1.y;
24 | texPos2.y = 1.0 - texPos2.y;
25 |
26 | vec4 inputLUTExtent = samplerExtent(inputLUT);
27 |
28 | vec4 newColor1 = sample(inputLUT, samplerTransform(inputLUT, texPos1 * vec2(512.0) + inputLUTExtent.xy));
29 | vec4 newColor2 = sample(inputLUT, samplerTransform(inputLUT, texPos2 * vec2(512.0) + inputLUTExtent.xy));
30 |
31 | vec4 newColor = mix(newColor1, newColor2, fract(blueColor));
32 | return mix(textureColor, vec4(newColor.rgb, textureColor.a), intensity);
33 | }
34 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage/Filter/BBCILookupFilter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BBCILookupFilter.swift
3 | // BBWebImage
4 | //
5 | // Created by Kaibo Lu on 2018/11/27.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | open class BBCILookupFilter: CIFilter {
12 | private static var _kernel: CIKernel?
13 |
14 | private static var kernel: CIKernel? {
15 | var localKernel = _kernel // Use local var to prevent multithreading problem
16 | if localKernel == nil {
17 | localKernel = CIKernel(source: kernelString)
18 | _kernel = localKernel
19 | }
20 | return localKernel
21 | }
22 |
23 | private static var kernelString: String {
24 | let path = Bundle(for: self).path(forResource: "BBCILookup", ofType: "cikernel")!
25 | return try! String(contentsOfFile: path, encoding: String.Encoding.utf8)
26 | }
27 |
28 | open class func clear() { _kernel = nil }
29 |
30 | public static func outputImage(withInputImage inputImage: CIImage, lookupTable: CIImage, intensity: CGFloat) -> CIImage? {
31 | return kernel?.apply(extent: inputImage.extent, roiCallback: { (index: Int32, destRect: CGRect) -> CGRect in
32 | if index == 0 { return destRect }
33 | return lookupTable.extent
34 | }, arguments: [inputImage, lookupTable, intensity])
35 | }
36 |
37 | @objc public var inputImage: CIImage? // Add `@objc` to make it key-value coding compliant. Or it will crash in iOS 8
38 |
39 | public var lookupTable: CIImage?
40 |
41 | private var _intensity: CGFloat
42 | public var intensity: CGFloat {
43 | get { return _intensity }
44 | set { _intensity = min(1, max(0, newValue)) }
45 | }
46 |
47 | open override var outputImage: CIImage? {
48 | if let inputImage = inputImage,
49 | let lookupTable = lookupTable {
50 | return BBCILookupFilter.outputImage(withInputImage: inputImage, lookupTable: lookupTable, intensity: _intensity)
51 | }
52 | return nil
53 | }
54 |
55 | public override init() {
56 | _intensity = 1
57 | super.init()
58 | }
59 |
60 | required public init?(coder aDecoder: NSCoder) {
61 | fatalError("init(coder:) has not been implemented")
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImage/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
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 |
22 |
23 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImageTests/BBImageCoderManagerTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BBImageCoderManagerTests.swift
3 | // BBWebImageTests
4 | //
5 | // Created by Kaibo Lu on 2018/12/4.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class BBImageCoderManagerTests: XCTestCase {
12 | var coder: BBImageCoderManager!
13 |
14 | var pngData: Data {
15 | let url = Bundle(for: classForCoder).url(forResource: "mew_baseline", withExtension: "png")!
16 | return try! Data(contentsOf: url)
17 | }
18 |
19 | var jpgData: Data {
20 | let url = Bundle(for: classForCoder).url(forResource: "mew_baseline", withExtension: "jpg")!
21 | return try! Data(contentsOf: url)
22 | }
23 |
24 | var gifData: Data {
25 | let url = Bundle(for: classForCoder).url(forResource: "Rotating_earth", withExtension: "gif")!
26 | return try! Data(contentsOf: url)
27 | }
28 |
29 | override func setUp() {
30 | coder = BBImageCoderManager()
31 | }
32 |
33 | override func tearDown() {}
34 |
35 | func testCanDecode() {
36 | XCTAssertFalse(coder.canDecode(Data()))
37 | XCTAssertTrue(coder.canDecode(pngData))
38 | XCTAssertTrue(coder.canDecode(jpgData))
39 | XCTAssertTrue(coder.canDecode(gifData))
40 | }
41 |
42 | func testDecode() {
43 | XCTAssertNil(coder.decodedImage(with: Data()))
44 |
45 | let pngImage = coder.decodedImage(with: pngData)
46 | XCTAssertNotNil(pngImage)
47 | XCTAssertEqual(pngImage?.bb_imageFormat, .PNG)
48 |
49 | let jpgImage = coder.decodedImage(with: jpgData)
50 | XCTAssertNotNil(jpgImage)
51 | XCTAssertEqual(jpgImage?.bb_imageFormat, .JPEG)
52 |
53 | let gifImage = coder.decodedImage(with: gifData)
54 | XCTAssertNotNil(gifImage)
55 | XCTAssertEqual(gifImage?.bb_imageFormat, .GIF)
56 | XCTAssertTrue(gifImage is BBAnimatedImage)
57 | }
58 |
59 | func testDecompress() {
60 | let pngData = self.pngData
61 | let pngImage = coder.decodedImage(with: pngData)!
62 | let pngDecompressedImage = coder.decompressedImage(with: pngImage, data: pngData)
63 | XCTAssertNotNil(pngDecompressedImage)
64 | XCTAssertNotEqual(pngImage, pngDecompressedImage)
65 | XCTAssertEqual(pngDecompressedImage?.bb_imageFormat, .PNG)
66 |
67 | let jpgData = self.jpgData
68 | let jpgImage = coder.decodedImage(with: jpgData)!
69 | let jpgDecompressedImage = coder.decompressedImage(with: jpgImage, data: jpgData)
70 | XCTAssertNotNil(jpgDecompressedImage)
71 | XCTAssertNotEqual(jpgImage, jpgDecompressedImage)
72 | XCTAssertEqual(jpgDecompressedImage?.bb_imageFormat, .JPEG)
73 |
74 | let gifData = self.gifData
75 | let gifImage = coder.decodedImage(with: gifData)!
76 | let gifDecompressedImage = coder.decompressedImage(with: gifImage, data: gifData)
77 | XCTAssertNil(gifDecompressedImage)
78 | }
79 |
80 | func testCanEncode() {
81 | XCTAssertTrue(coder.canEncode(.unknown))
82 | XCTAssertTrue(coder.canEncode(.PNG))
83 | XCTAssertTrue(coder.canEncode(.JPEG))
84 | XCTAssertTrue(coder.canEncode(.GIF))
85 | }
86 |
87 | func testEncode() {
88 | let images: [UIImage] = [coder.decodedImage(with: pngData)!,
89 | coder.decodedImage(with: jpgData)!,
90 | coder.decodedImage(with: gifData)!]
91 | for image in images {
92 | XCTAssertNotNil(coder.encodedData(with: image, format: .PNG))
93 | XCTAssertNotNil(coder.encodedData(with: image, format: .JPEG))
94 | XCTAssertNotNil(coder.encodedData(with: image, format: .GIF))
95 | XCTAssertNotNil(coder.encodedData(with: image, format: .unknown))
96 | }
97 | }
98 |
99 | func testCopy() {
100 | XCTAssertFalse(coder === coder.copy())
101 | }
102 |
103 | func testCanIncrementallyDecode() {
104 | XCTAssertTrue(coder.canIncrementallyDecode(pngData))
105 | XCTAssertTrue(coder.canIncrementallyDecode(jpgData))
106 | XCTAssertFalse(coder.canIncrementallyDecode(gifData))
107 | }
108 |
109 | func testIncrementallyDecodedImage() {
110 | let test = { (data: Data, total: Int, canDecode: Bool) -> Void in
111 | for i in 1...total {
112 | let finished = (i == total)
113 | let end = Int((Double(i) / Double(total)) * Double(data.count))
114 | let subdata = data.subdata(in: 0.. Void in
32 | XCTAssertNotNil(gifImage)
33 | XCTAssertEqual(gifImage?.bb_imageFormat, .GIF)
34 | XCTAssertTrue(gifImage is BBAnimatedImage)
35 | }
36 | test(coder.decodedImage(with: gifData))
37 | test(BBAnimatedImage(bb_data: gifData))
38 | test(BBAnimatedImage(bb_data: gifData, decoder: coder))
39 | }
40 |
41 | func testDecompress() {
42 | let gifData = self.gifData
43 | let gifImage = coder.decodedImage(with: gifData)!
44 | let gifDecompressedImage = coder.decompressedImage(with: gifImage, data: gifData)
45 | XCTAssertNil(gifDecompressedImage)
46 | }
47 |
48 | func testCanEncode() {
49 | XCTAssertFalse(coder.canEncode(.unknown))
50 | XCTAssertFalse(coder.canEncode(.PNG))
51 | XCTAssertFalse(coder.canEncode(.JPEG))
52 | XCTAssertTrue(coder.canEncode(.GIF))
53 | }
54 |
55 | func testEncode() {
56 | let test = { (image: UIImage) -> Void in
57 | XCTAssertNil(self.coder.encodedData(with: image, format: .unknown))
58 | XCTAssertNil(self.coder.encodedData(with: image, format: .PNG))
59 | XCTAssertNil(self.coder.encodedData(with: image, format: .JPEG))
60 | XCTAssertNotNil(self.coder.encodedData(with: image, format: .GIF))
61 | }
62 |
63 | let image = coder.decodedImage(with: gifData) as! BBAnimatedImage
64 | test(image)
65 |
66 | let jpgUrl = Bundle(for: classForCoder).url(forResource: "mew_baseline", withExtension: "jpg")!
67 | let jpgData = try! Data(contentsOf: jpgUrl)
68 | let jpgImage = UIImage(data: jpgData)!
69 | test(jpgImage)
70 |
71 | let pngUrl = Bundle(for: classForCoder).url(forResource: "mew_baseline", withExtension: "png")!
72 | let pngData = try! Data(contentsOf: pngUrl)
73 | let pngImage = UIImage(data: pngData)!
74 | test(pngImage)
75 |
76 | let images = UIImage.animatedImage(with: [jpgImage, pngImage], duration: 2)!
77 | test(images)
78 | }
79 |
80 | func testCopy() {
81 | XCTAssertFalse(coder === coder.copy())
82 | }
83 |
84 | func testImageData() {
85 | XCTAssertNil(coder.imageData)
86 | coder.imageData = gifData
87 | XCTAssertEqual(coder.imageData, gifData)
88 | }
89 |
90 | func testFrameCount() {
91 | coder.imageData = gifData
92 | XCTAssertEqual(coder.frameCount, 44)
93 | }
94 |
95 | func testLoopCount() {
96 | coder.imageData = gifData
97 | XCTAssertEqual(coder.loopCount, 65535)
98 | }
99 |
100 | func testImageFrame() {
101 | coder.imageData = gifData
102 | for i in 0..
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 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImageTests/TestImageDownloadTask.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestImageDownloadTask.swift
3 | // BBWebImageTests
4 | //
5 | // Created by Kaibo Lu on 1/28/19.
6 | // Copyright © 2019 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class TestImageDownloadTask: BBImageDownloadTask {
12 | private(set) var sentinel: Int32
13 | private(set) var url: URL
14 | private(set) var isCancelled: Bool
15 | private(set) var progress: BBImageDownloaderProgress?
16 | private(set) var completion: BBImageDownloaderCompletion
17 |
18 | init(sentinel: Int32, url: URL, progress: BBImageDownloaderProgress?, completion: @escaping BBImageDownloaderCompletion) {
19 | self.sentinel = sentinel
20 | self.url = url
21 | self.isCancelled = false
22 | self.progress = progress
23 | self.completion = { (_, _) in
24 | completion(nil, NSError(domain: "TestError", code: 0, userInfo: nil))
25 | }
26 | }
27 |
28 | func cancel() { isCancelled = true }
29 | }
30 |
--------------------------------------------------------------------------------
/BBWebImage/BBWebImageTests/mew_baseline.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/BBWebImage/BBWebImageTests/mew_baseline.jpg
--------------------------------------------------------------------------------
/BBWebImage/BBWebImageTests/mew_baseline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/BBWebImage/BBWebImageTests/mew_baseline.png
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // BBWebImageDemo
4 | //
5 | // Created by Kaibo Lu on 2018/10/3.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // 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.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // 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.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // 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.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo/BBCILookupTestFilter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BBCILookupTestFilter.swift
3 | // BBWebImageDemo
4 | //
5 | // Created by Kaibo Lu on 2018/11/29.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import BBWebImage
11 |
12 | class BBCILookupTestFilter: BBCILookupFilter {
13 | private static var _sharedLookupTable: CIImage?
14 | private static var sharedLookupTable: CIImage? {
15 | var localLookupTable = _sharedLookupTable
16 | if localLookupTable == nil {
17 | let url = Bundle.main.url(forResource: "test_lookup", withExtension: "png")!
18 | localLookupTable = CIImage(contentsOf: url)
19 | _sharedLookupTable = localLookupTable
20 | }
21 | return localLookupTable
22 | }
23 |
24 | override static func clear() {
25 | _sharedLookupTable = nil
26 | super.clear()
27 | }
28 |
29 | override init() {
30 | super.init()
31 | lookupTable = BBCILookupTestFilter.sharedLookupTable
32 | }
33 |
34 | required init?(coder aDecoder: NSCoder) {
35 | fatalError("init(coder:) has not been implemented")
36 | }
37 | }
38 |
39 |
40 | // The higher maxTileSize, the less memory cost, the longer processing time
41 | public func bb_imageEditorCILookupTestFilter(maxTileSize: Int = 0) -> BBWebImageEditor {
42 | let edit: BBWebImageEditMethod = { (image) in
43 | autoreleasepool { () -> UIImage? in
44 | var inputImage: CIImage?
45 | if let ciimage = image.ciImage {
46 | inputImage = ciimage
47 | } else if let cgimage = image.cgImage {
48 | inputImage = CIImage(cgImage: cgimage)
49 | } else {
50 | inputImage = CIImage(image: image)
51 | }
52 | guard let input = inputImage else { return image }
53 | let filter = BBCILookupTestFilter()
54 | if maxTileSize <= 0 {
55 | filter.inputImage = input
56 | if let output = filter.outputImage,
57 | let sourceImage = bb_shareCIContext.createCGImage(output, from: output.extent),
58 | let cgimage = BBWebImageImageIOCoder.decompressedImage(sourceImage) {
59 | // It costs more memory without decompressing
60 | return UIImage(cgImage: cgimage)
61 | }
62 | return image
63 | }
64 | // Split image into tiles, process tiles and combine
65 | let width = input.extent.width
66 | var height = max(1, floor(CGFloat(maxTileSize) / width))
67 | var y: CGFloat = 0
68 | var context: CGContext?
69 | while y < input.extent.height {
70 | if y + height > input.extent.height {
71 | height = input.extent.height - y
72 | }
73 | let success = autoreleasepool { () -> Bool in
74 | filter.inputImage = input.cropped(to: CGRect(x: 0, y: y, width: width, height: height))
75 | guard let output = filter.outputImage,
76 | let cgimage = bb_shareCIContext.createCGImage(output, from: output.extent) else { return false }
77 | if context == nil {
78 | var bitmapInfo = cgimage.bitmapInfo
79 | bitmapInfo.remove(.alphaInfoMask)
80 | if cgimage.bb_containsAlpha {
81 | bitmapInfo = CGBitmapInfo(rawValue: bitmapInfo.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue)
82 | } else {
83 | bitmapInfo = CGBitmapInfo(rawValue: bitmapInfo.rawValue | CGImageAlphaInfo.noneSkipFirst.rawValue)
84 | }
85 | context = CGContext(data: nil,
86 | width: Int(width),
87 | height: Int(input.extent.height),
88 | bitsPerComponent: cgimage.bitsPerComponent,
89 | bytesPerRow: 0,
90 | space: bb_shareColorSpace,
91 | bitmapInfo: bitmapInfo.rawValue)
92 | if (context == nil) { return false }
93 | }
94 | context?.draw(cgimage, in: CGRect(x: 0, y: y, width: width, height: height))
95 | return true
96 | }
97 | if !success { return image }
98 | y += height
99 | }
100 | return context?.makeImage().flatMap { UIImage(cgImage: $0) } ?? image
101 | }
102 | }
103 | return BBWebImageEditor(key: BBCILookupTestFilter.description(), edit: edit)
104 | }
105 |
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo/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 |
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo/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 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo/GIFWallCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GIFWallCell.swift
3 | // BBWebImageDemo
4 | //
5 | // Created by Kaibo Lu on 2/12/19.
6 | // Copyright © 2019 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import BBWebImage
11 |
12 | class GIFWallCell: UICollectionViewCell {
13 | private var imageView: UIImageView!
14 |
15 | override init(frame: CGRect) {
16 | super.init(frame: frame)
17 |
18 | imageView = BBAnimatedImageView(frame: CGRect(origin: .zero, size: frame.size))
19 | imageView.contentMode = .scaleAspectFill
20 | imageView.clipsToBounds = true
21 | contentView.addSubview(imageView)
22 | }
23 |
24 | required init?(coder aDecoder: NSCoder) {
25 | fatalError("init(coder:) has not been implemented")
26 | }
27 |
28 | func set(url: URL) {
29 | let editor = bb_imageEditorCommon(with: imageView.frame.size,
30 | corner: .allCorners,
31 | cornerRadius: 5,
32 | borderWidth: 1,
33 | borderColor: .yellow,
34 | backgroundColor: .gray)
35 | imageView.bb_setImage(with: url,
36 | placeholder: UIImage(named: "placeholder"),
37 | options: .none,
38 | editor: editor,
39 | progress: nil,
40 | completion: nil)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo/GIFWallVC.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GIFWallVC.swift
3 | // BBWebImageDemo
4 | //
5 | // Created by Kaibo Lu on 2/12/19.
6 | // Copyright © 2019 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class GIFWallVC: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 |
16 | let layout = UICollectionViewFlowLayout()
17 | layout.minimumLineSpacing = 0
18 | layout.minimumInteritemSpacing = 0
19 | let cellWidth = view.bounds.width / 4
20 | layout.itemSize = CGSize(width: cellWidth, height: cellWidth)
21 | let colletionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
22 | colletionView.register(GIFWallCell.self, forCellWithReuseIdentifier: GIFWallCell.description())
23 | colletionView.backgroundColor = .gray
24 | colletionView.dataSource = self
25 | view.addSubview(colletionView)
26 | }
27 | }
28 |
29 | extension GIFWallVC: UICollectionViewDataSource {
30 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
31 | return ImageURLProvider.gifUrlStrings.count
32 | }
33 |
34 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
35 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: GIFWallCell.description(), for: indexPath) as! GIFWallCell
36 | if let url = ImageURLProvider.gifURL(forIndex: indexPath.item) {
37 | cell.set(url: url)
38 | }
39 | return cell
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo/ImageWallCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageWallCell.swift
3 | // BBWebImageDemo
4 | //
5 | // Created by Kaibo Lu on 2018/11/7.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import BBWebImage
11 |
12 | class ImageWallCell: UICollectionViewCell {
13 | private var imageView: UIImageView!
14 |
15 | override init(frame: CGRect) {
16 | super.init(frame: frame)
17 |
18 | imageView = UIImageView(frame: CGRect(origin: .zero, size: frame.size))
19 | imageView.contentMode = .scaleAspectFill
20 | imageView.clipsToBounds = true
21 | contentView.addSubview(imageView)
22 | }
23 |
24 | required init?(coder aDecoder: NSCoder) {
25 | fatalError("init(coder:) has not been implemented")
26 | }
27 |
28 | func set(url: URL) {
29 | let editor = bb_imageEditorCommon(with: imageView.frame.size,
30 | corner: .allCorners,
31 | cornerRadius: 5,
32 | borderWidth: 1,
33 | borderColor: .yellow,
34 | backgroundColor: .gray)
35 | imageView.bb_setImage(with: url,
36 | placeholder: UIImage(named: "placeholder"),
37 | options: .progressiveDownload,
38 | editor: editor,
39 | progress: nil,
40 | completion: nil)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo/ImageWallVC.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageWallVC.swift
3 | // BBWebImageDemo
4 | //
5 | // Created by Kaibo Lu on 2018/11/7.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import BBWebImage
11 |
12 | class ImageWallVC: UIViewController {
13 |
14 | var preloadTasks: [Int : BBWebImageLoadTask]!
15 |
16 | override func viewDidLoad() {
17 | super.viewDidLoad()
18 |
19 | preloadTasks = [:]
20 |
21 | let layout = UICollectionViewFlowLayout()
22 | layout.minimumLineSpacing = 0
23 | layout.minimumInteritemSpacing = 0
24 | let cellWidth = view.bounds.width / 4
25 | layout.itemSize = CGSize(width: cellWidth, height: cellWidth)
26 | let colletionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
27 | colletionView.register(ImageWallCell.self, forCellWithReuseIdentifier: ImageWallCell.description())
28 | colletionView.backgroundColor = .gray
29 | colletionView.dataSource = self
30 | if #available(iOS 10.0, *) { colletionView.prefetchDataSource = self }
31 | view.addSubview(colletionView)
32 | }
33 | }
34 |
35 | extension ImageWallVC: UICollectionViewDataSource {
36 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
37 | return 4000
38 | }
39 |
40 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
41 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ImageWallCell.description(), for: indexPath) as! ImageWallCell
42 | if let url = ImageURLProvider.originURL(forIndex: indexPath.item + 1) {
43 | cell.set(url: url)
44 | }
45 | return cell
46 | }
47 | }
48 |
49 | extension ImageWallVC: UICollectionViewDataSourcePrefetching {
50 | func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) {
51 | var urls: [URL] = []
52 | for indexPath in indexPaths {
53 | if let url = ImageURLProvider.originURL(forIndex: indexPath.item + 1) {
54 | urls.append(url)
55 | }
56 | }
57 | let tasks = BBWebImageManager.shared.preload(urls, options: .none, progress: { (successCount, finishCount, total) in
58 | // print("Preload progress. success count = \(successCount), finish count = \(finishCount), total = \(total)")
59 | }) { (successCount, total) in
60 | // print("Preload completion. success count = \(successCount), total = \(total)")
61 | }
62 | for i in 0..
2 |
3 |
4 |
5 | NSAppTransportSecurity
6 |
7 | NSAllowsArbitraryLoads
8 |
9 |
10 | CFBundleDevelopmentRegion
11 | $(DEVELOPMENT_LANGUAGE)
12 | CFBundleExecutable
13 | $(EXECUTABLE_NAME)
14 | CFBundleIdentifier
15 | $(PRODUCT_BUNDLE_IDENTIFIER)
16 | CFBundleInfoDictionaryVersion
17 | 6.0
18 | CFBundleName
19 | $(PRODUCT_NAME)
20 | CFBundlePackageType
21 | APPL
22 | CFBundleShortVersionString
23 | 1.0
24 | CFBundleVersion
25 | 1
26 | LSRequiresIPhoneOS
27 |
28 | UILaunchStoryboardName
29 | LaunchScreen
30 | UIMainStoryboardFile
31 | Main
32 | UIRequiredDeviceCapabilities
33 |
34 | armv7
35 |
36 | UISupportedInterfaceOrientations
37 |
38 | UIInterfaceOrientationPortrait
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo/MainMenuVC.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainMenuVC.swift
3 | // BBWebImageDemo
4 | //
5 | // Created by Kaibo Lu on 2018/10/3.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import BBWebImage
11 |
12 | class MainMenuVC: UIViewController {
13 |
14 | @IBOutlet private weak var tableView: UITableView!
15 |
16 | private var list: [(String, () -> Void)]!
17 |
18 | override func viewDidLoad() {
19 | super.viewDidLoad()
20 |
21 | automaticallyAdjustsScrollViewInsets = false
22 |
23 | let test = { [weak self] in
24 | if let self = self { self.navigationController?.pushViewController(TestVC(), animated: true) }
25 | }
26 | let filter = { [weak self] in
27 | if let self = self { self.navigationController?.pushViewController(TestFilterVC(), animated: true) }
28 | }
29 | let gif = { [weak self] in
30 | if let self = self { self.navigationController?.pushViewController(TestGIFVC(), animated: true) }
31 | }
32 | let imageWall = { [weak self] in
33 | if let self = self { self.navigationController?.pushViewController(ImageWallVC(), animated: true) }
34 | }
35 | let gifWall = { [weak self] in
36 | if let self = self { self.navigationController?.pushViewController(GIFWallVC(), animated: true) }
37 | }
38 | let clearCache = { [weak self] in
39 | if self != nil { BBWebImageManager.shared.imageCache.clear(.all, completion: nil) }
40 | }
41 | list = [("Test", test),
42 | ("Test filter", filter),
43 | ("Test GIF", gif),
44 | ("Image wall", imageWall),
45 | ("GIF wall", gifWall),
46 | ("Clear cache", clearCache)]
47 |
48 | tableView.register(UITableViewCell.self, forCellReuseIdentifier: UITableViewCell.description())
49 | tableView.dataSource = self
50 | tableView.delegate = self
51 | }
52 | }
53 |
54 | extension MainMenuVC: UITableViewDataSource {
55 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
56 | return list.count
57 | }
58 |
59 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
60 | let cell = tableView.dequeueReusableCell(withIdentifier: UITableViewCell.description(), for: indexPath)
61 | cell.textLabel?.text = list[indexPath.row].0
62 | return cell
63 | }
64 | }
65 |
66 | extension MainMenuVC: UITableViewDelegate {
67 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
68 | tableView.deselectRow(at: indexPath, animated: true)
69 | list[indexPath.row].1()
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo/Rotating_earth.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/BBWebImageDemo/BBWebImageDemo/Rotating_earth.gif
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo/TestFilterVC.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestFilterVC.swift
3 | // BBWebImageDemo
4 | //
5 | // Created by Kaibo Lu on 2018/11/28.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import BBWebImage
11 |
12 | class TestFilterVC: UIViewController {
13 |
14 | private var imageView: UIImageView!
15 | private var button: UIButton!
16 | private var filtered: Bool = false
17 |
18 | override func viewDidLoad() {
19 | super.viewDidLoad()
20 |
21 | view.backgroundColor = .white
22 |
23 | imageView = UIImageView(frame: CGRect(x: 10, y: 100, width: view.bounds.width - 20, height: view.bounds.height - 200))
24 | imageView.contentMode = .scaleAspectFill
25 | imageView.clipsToBounds = true
26 | imageView.image = UIImage(named: "sunflower.jpg")
27 | view.addSubview(imageView)
28 |
29 | button = UIButton(frame: CGRect(x: 10, y: imageView.frame.maxY + 10, width: imageView.frame.width, height: 30))
30 | button.backgroundColor = .blue
31 | button.setTitle("Add filter", for: .normal)
32 | button.setTitle("Reset", for: .selected)
33 | button.addTarget(self, action: #selector(clickButton), for: .touchUpInside)
34 | view.addSubview(button)
35 | }
36 |
37 | @objc private func clickButton() {
38 | filtered = !filtered
39 | if filtered {
40 | let editor = bb_imageEditorCILookupTestFilter()
41 | imageView.image = editor.edit(imageView.image!)
42 | } else {
43 | imageView.image = UIImage(named: "sunflower.jpg")
44 | }
45 | button.isSelected = filtered
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo/TestGIFVC.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestGIFVC.swift
3 | // BBWebImageDemo
4 | //
5 | // Created by Kaibo Lu on 2/6/19.
6 | // Copyright © 2019 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import BBWebImage
11 |
12 | class TestGIFVC: UIViewController {
13 |
14 | private var imageView: BBAnimatedImageView!
15 | private var scaleLabel: UILabel!
16 |
17 | private var editor: BBWebImageEditor?
18 |
19 | override func viewDidLoad() {
20 | super.viewDidLoad()
21 |
22 | automaticallyAdjustsScrollViewInsets = false
23 | view.backgroundColor = .lightGray
24 |
25 | let x: CGFloat = 10
26 | let width = view.frame.width - 20
27 |
28 | let scrollView = UIScrollView(frame: CGRect(x: x, y: 100, width: width, height: 200))
29 | scrollView.contentSize = CGSize(width: width + 20, height: 200)
30 | view.addSubview(scrollView)
31 |
32 | imageView = BBAnimatedImageView(frame: scrollView.bounds)
33 | imageView.backgroundColor = .yellow
34 | imageView.contentMode = .scaleAspectFit
35 | let url = Bundle(for: self.classForCoder).url(forResource: "Rotating_earth", withExtension: "gif")!
36 | let data = try! Data(contentsOf: url)
37 | imageView.image = BBAnimatedImage(bb_data: data)
38 | scrollView.addSubview(imageView)
39 |
40 | var y = scrollView.frame.maxY + 10
41 | let height: CGFloat = 30
42 |
43 | scaleLabel = UILabel(frame: CGRect(x: x, y: y, width: width, height: height))
44 | scaleLabel.text = "Duration scale: 1.0"
45 | scaleLabel.textAlignment = .center
46 | view.addSubview(scaleLabel)
47 |
48 | y = scaleLabel.frame.maxY
49 |
50 | let scaleSilder = UISlider(frame: CGRect(x: x + 30, y: y, width: width - 60, height: height))
51 | scaleSilder.minimumValue = 0.2
52 | scaleSilder.maximumValue = 5
53 | scaleSilder.value = 1
54 | scaleSilder.addTarget(self, action: #selector(scaleSliderChanged(_:)), for: .valueChanged)
55 | view.addSubview(scaleSilder)
56 |
57 | y = scaleSilder.frame.maxY + 10
58 |
59 | var buttonIndex = 0
60 | let generateButton = { (title: String?, selectedTitle: String?) -> UIButton in
61 | let button = UIButton(frame: CGRect(x: x, y: y, width: self.imageView.frame.width, height: height))
62 | button.backgroundColor = (buttonIndex % 2 == 0 ? .blue : .red)
63 | button.setTitle(title, for: .normal)
64 | button.setTitle(selectedTitle, for: .selected)
65 | self.view.addSubview(button)
66 | y = button.frame.maxY
67 | buttonIndex += 1
68 | return button
69 | }
70 |
71 | let stopButton = generateButton("Stop", "Start")
72 | stopButton.addTarget(self, action: #selector(stopButtonClicked(_:)), for: .touchUpInside)
73 |
74 | let runLoopButton = generateButton("Change to default mode", "Change to common mode")
75 | runLoopButton.addTarget(self, action: #selector(runLoopButtonClicked(_:)), for: .touchUpInside)
76 |
77 | let filterButton = generateButton("Add filter", "Remove filter")
78 | filterButton.addTarget(self, action: #selector(filterButtonClicked(_:)), for: .touchUpInside)
79 |
80 | let frameIndexButton = generateButton("Set current frame index 0", nil)
81 | frameIndexButton.addTarget(self, action: #selector(frameIndexButtonClicked(_:)), for: .touchUpInside)
82 |
83 | let changeImageSegment = UISegmentedControl(frame: CGRect(x: x, y: y, width: width, height: height))
84 | changeImageSegment.insertSegment(withTitle: "GIF", at: 0, animated: false)
85 | changeImageSegment.insertSegment(withTitle: "Static", at: 1, animated: false)
86 | changeImageSegment.insertSegment(withTitle: "Images", at: 2, animated: false)
87 | changeImageSegment.selectedSegmentIndex = 0
88 | changeImageSegment.addTarget(self, action: #selector(changeImageSegmentChanged(_:)), for: .valueChanged)
89 | view.addSubview(changeImageSegment)
90 | }
91 |
92 | @objc private func scaleSliderChanged(_ slider: UISlider) {
93 | scaleLabel.text = String(format: "Duration scale: %.1f", slider.value)
94 | imageView.bb_animationDurationScale = Double(slider.value)
95 | }
96 |
97 | @objc private func stopButtonClicked(_ button: UIButton) {
98 | button.isSelected = !button.isSelected
99 | if button.isSelected {
100 | imageView.stopAnimating()
101 | } else {
102 | imageView.startAnimating()
103 | }
104 | }
105 |
106 | @objc private func runLoopButtonClicked(_ button: UIButton) {
107 | button.isSelected = !button.isSelected
108 | imageView.bb_runLoopMode = (button.isSelected ? .default : .common)
109 | }
110 |
111 | @objc private func filterButtonClicked(_ button: UIButton) {
112 | if editor == nil {
113 | let e = bb_imageEditorCILookupTestFilter()
114 | editor = e
115 | button.isSelected = true
116 | } else {
117 | editor = nil
118 | button.isSelected = false
119 | }
120 | if let animatedImage = imageView.image as? BBAnimatedImage {
121 | animatedImage.bb_editor = editor
122 | }
123 | }
124 |
125 | @objc private func frameIndexButtonClicked(_ button: UIButton) {
126 | imageView.bb_setCurrentFrameIndex(0, decodeIfNeeded: true)
127 | }
128 |
129 | @objc private func changeImageSegmentChanged(_ segment: UISegmentedControl) {
130 | switch segment.selectedSegmentIndex {
131 | case 0:
132 | let url = Bundle(for: self.classForCoder).url(forResource: "Rotating_earth", withExtension: "gif")!
133 | let data = try! Data(contentsOf: url)
134 | let animatedImage = BBAnimatedImage(bb_data: data)
135 | animatedImage?.bb_editor = editor
136 | imageView.image = animatedImage
137 | imageView.animationImages = nil
138 | case 1:
139 | imageView.image = UIImage(named: "placeholder")
140 | imageView.animationImages = nil
141 | case 2:
142 | imageView.animationImages = [UIImage(named: "sunflower.jpg")!, UIImage(named: "test_lookup")!]
143 | imageView.animationDuration = 1
144 | imageView.image = nil
145 | default:
146 | break
147 | }
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo/TestVC.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestVC.swift
3 | // BBWebImageDemo
4 | //
5 | // Created by Kaibo Lu on 2018/10/5.
6 | // Copyright © 2018年 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import BBWebImage
11 |
12 | class TestVC: UIViewController {
13 |
14 | private var donwloader: BBMergeRequestImageDownloader!
15 |
16 | override func viewDidLoad() {
17 | super.viewDidLoad()
18 |
19 | view.backgroundColor = UIColor.lightGray
20 |
21 | let imageView = UIImageView(frame: CGRect(x: 10, y: 100, width: view.frame.width - 20, height: view.frame.height - 200))
22 | imageView.contentMode = .scaleAspectFill
23 | imageView.clipsToBounds = true
24 | view.addSubview(imageView)
25 |
26 | let url = URL(string: "http://qzonestyle.gtimg.cn/qzone/app/weishi/client/testimage/origin/1.jpg")!
27 | let editor = bb_imageEditorCommon(with: imageView.frame.size,
28 | fillContentMode: .topLeft,
29 | maxResolution: 1024,
30 | corner: [.topLeft, .bottomRight],
31 | cornerRadius: 10,
32 | borderWidth: 2,
33 | borderColor: .yellow,
34 | backgroundColor: .blue)
35 | imageView.bb_setImage(with: url, placeholder: UIImage(named: "placeholder"), options: .none, editor: editor) { (image: UIImage?, data: Data?, error: Error?, cacheType: BBImageCacheType) in
36 | print("Completion")
37 | if let currentImage = image {
38 | print("Image: \(currentImage)")
39 | if let currentData = data {
40 | print("Data: \(currentData)")
41 | } else {
42 | print("No data")
43 | }
44 | print("Cache type: \(cacheType)")
45 | if let imageFormat = currentImage.bb_imageFormat {
46 | print("Image format: \(imageFormat)")
47 | } else {
48 | print("No image format")
49 | }
50 | } else if let currentError = error {
51 | print("Error: \(currentError)")
52 | }
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo/large_leaves_70mp.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/BBWebImageDemo/BBWebImageDemo/large_leaves_70mp.jpg
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo/placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/BBWebImageDemo/BBWebImageDemo/placeholder.png
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo/sunflower.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/BBWebImageDemo/BBWebImageDemo/sunflower.jpg
--------------------------------------------------------------------------------
/BBWebImageDemo/BBWebImageDemo/test_lookup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/BBWebImageDemo/BBWebImageDemo/test_lookup.png
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // CompareImageLib
4 | //
5 | // Created by Kaibo Lu on 3/4/19.
6 | // Copyright © 2019 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // 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.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // 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.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // 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.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/BBAnimatedImageWallCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BBAnimatedImageWallCell.swift
3 | // CompareImageLib
4 | //
5 | // Created by Kaibo Lu on 3/15/19.
6 | // Copyright © 2019 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import BBWebImage
11 |
12 | class BBAnimatedImageWallCell: UICollectionViewCell {
13 | private var imageView: UIImageView!
14 |
15 | override init(frame: CGRect) {
16 | super.init(frame: frame)
17 |
18 | imageView = BBAnimatedImageView(frame: CGRect(origin: .zero, size: frame.size))
19 | imageView.contentMode = .scaleAspectFill
20 | imageView.clipsToBounds = true
21 | contentView.addSubview(imageView)
22 | }
23 |
24 | required init?(coder aDecoder: NSCoder) {
25 | fatalError("init(coder:) has not been implemented")
26 | }
27 |
28 | func set(url: URL) {
29 | let placeholder = UIImage(named: "placeholder")
30 | imageView.bb_setImage(with: url, placeholder: placeholder)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/BBAnimatedImageWallVC.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BBAnimatedImageWallVC.swift
3 | // CompareImageLib
4 | //
5 | // Created by Kaibo Lu on 3/15/19.
6 | // Copyright © 2019 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class BBAnimatedImageWallVC: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 |
16 | let layout = UICollectionViewFlowLayout()
17 | layout.minimumLineSpacing = 0
18 | layout.minimumInteritemSpacing = 0
19 | let cellWidth = view.bounds.width / 4
20 | layout.itemSize = CGSize(width: cellWidth, height: cellWidth)
21 | let colletionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
22 | colletionView.register(BBAnimatedImageWallCell.self, forCellWithReuseIdentifier: BBAnimatedImageWallCell.description())
23 | colletionView.backgroundColor = .white
24 | colletionView.dataSource = self
25 | view.addSubview(colletionView)
26 | }
27 | }
28 |
29 | extension BBAnimatedImageWallVC: UICollectionViewDataSource {
30 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
31 | return ImageURLProvider.gifUrlStrings.count
32 | }
33 |
34 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
35 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: BBAnimatedImageWallCell.description(), for: indexPath) as! BBAnimatedImageWallCell
36 | if let url = ImageURLProvider.gifURL(forIndex: indexPath.item) {
37 | cell.set(url: url)
38 | }
39 | return cell
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/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 |
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/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 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/ImageWallCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageWallCell.swift
3 | // CompareImageLib
4 | //
5 | // Created by Kaibo Lu on 3/15/19.
6 | // Copyright © 2019 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import BBWebImage
11 | import SDWebImage
12 | import YYWebImage
13 | import Kingfisher
14 |
15 | class ImageWallCell: UICollectionViewCell {
16 | private var imageView: UIImageView!
17 |
18 | override init(frame: CGRect) {
19 | super.init(frame: frame)
20 |
21 | imageView = UIImageView(frame: CGRect(origin: .zero, size: frame.size))
22 | imageView.contentMode = .scaleAspectFill
23 | imageView.clipsToBounds = true
24 | contentView.addSubview(imageView)
25 | }
26 |
27 | required init?(coder aDecoder: NSCoder) {
28 | fatalError("init(coder:) has not been implemented")
29 | }
30 |
31 | func set(url: URL, type: TestType) {
32 | let placeholder = UIImage(named: "placeholder")
33 | switch type {
34 | case .BBWebImage:
35 | imageView.bb_setImage(with: url, placeholder: placeholder)
36 | case .SDWebImage:
37 | imageView.sd_setImage(with: url, placeholderImage: placeholder)
38 | case .YYWebImage:
39 | imageView.yy_setImage(with: url, placeholder: placeholder)
40 | case .Kingfisher:
41 | imageView.kf.setImage(with: url, placeholder: placeholder)
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/ImageWallVC.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageWallVC.swift
3 | // CompareImageLib
4 | //
5 | // Created by Kaibo Lu on 3/15/19.
6 | // Copyright © 2019 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | enum TestType {
12 | case BBWebImage
13 | case SDWebImage
14 | case YYWebImage
15 | case Kingfisher
16 | }
17 |
18 | class ImageWallVC: UIViewController {
19 |
20 | private let type: TestType
21 |
22 | init(type: TestType) {
23 | self.type = type
24 | super.init(nibName: nil, bundle: nil)
25 | }
26 |
27 | required init?(coder aDecoder: NSCoder) {
28 | fatalError("init(coder:) has not been implemented")
29 | }
30 |
31 | override func viewDidLoad() {
32 | super.viewDidLoad()
33 |
34 | let layout = UICollectionViewFlowLayout()
35 | layout.minimumLineSpacing = 0
36 | layout.minimumInteritemSpacing = 0
37 | let cellWidth = view.bounds.width / 4
38 | layout.itemSize = CGSize(width: cellWidth, height: cellWidth)
39 | let colletionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
40 | colletionView.register(ImageWallCell.self, forCellWithReuseIdentifier: ImageWallCell.description())
41 | colletionView.backgroundColor = .white
42 | colletionView.dataSource = self
43 | view.addSubview(colletionView)
44 | }
45 | }
46 |
47 | extension ImageWallVC: UICollectionViewDataSource {
48 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
49 | return 4000
50 | }
51 |
52 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
53 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ImageWallCell.description(), for: indexPath) as! ImageWallCell
54 | if let url = ImageURLProvider.originURL(forIndex: indexPath.item + 1) {
55 | cell.set(url: url, type: type)
56 | }
57 | return cell
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/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 | NSAppTransportSecurity
24 |
25 | NSAllowsArbitraryLoads
26 |
27 |
28 | UILaunchStoryboardName
29 | LaunchScreen
30 | UIMainStoryboardFile
31 | Main
32 | UIRequiredDeviceCapabilities
33 |
34 | armv7
35 |
36 | UISupportedInterfaceOrientations
37 |
38 | UIInterfaceOrientationPortrait
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/KiAnimatedImageWallCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KiAnimatedImageWallCell.swift
3 | // CompareImageLib
4 | //
5 | // Created by Kaibo Lu on 3/15/19.
6 | // Copyright © 2019 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Kingfisher
11 |
12 | class KiAnimatedImageWallCell: UICollectionViewCell {
13 | private var imageView: UIImageView!
14 |
15 | override init(frame: CGRect) {
16 | super.init(frame: frame)
17 |
18 | imageView = AnimatedImageView(frame: CGRect(origin: .zero, size: frame.size))
19 | imageView.contentMode = .scaleAspectFill
20 | imageView.clipsToBounds = true
21 | contentView.addSubview(imageView)
22 | }
23 |
24 | required init?(coder aDecoder: NSCoder) {
25 | fatalError("init(coder:) has not been implemented")
26 | }
27 |
28 | func set(url: URL) {
29 | let placeholder = UIImage(named: "placeholder")
30 | imageView.kf.setImage(with: url, placeholder: placeholder)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/KiAnimatedImageWallVC.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KiAnimatedImageWallVC.swift
3 | // CompareImageLib
4 | //
5 | // Created by Kaibo Lu on 3/15/19.
6 | // Copyright © 2019 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class KiAnimatedImageWallVC: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 |
16 | let layout = UICollectionViewFlowLayout()
17 | layout.minimumLineSpacing = 0
18 | layout.minimumInteritemSpacing = 0
19 | let cellWidth = view.bounds.width / 4
20 | layout.itemSize = CGSize(width: cellWidth, height: cellWidth)
21 | let colletionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
22 | colletionView.register(KiAnimatedImageWallCell.self, forCellWithReuseIdentifier: KiAnimatedImageWallCell.description())
23 | colletionView.backgroundColor = .white
24 | colletionView.dataSource = self
25 | view.addSubview(colletionView)
26 | }
27 | }
28 |
29 | extension KiAnimatedImageWallVC: UICollectionViewDataSource {
30 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
31 | return ImageURLProvider.gifUrlStrings.count
32 | }
33 |
34 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
35 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: KiAnimatedImageWallCell.description(), for: indexPath) as! KiAnimatedImageWallCell
36 | if let url = ImageURLProvider.gifURL(forIndex: indexPath.item) {
37 | cell.set(url: url)
38 | }
39 | return cell
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/MainMenuVC.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainMenuVC.swift
3 | // CompareImageLib
4 | //
5 | // Created by Kaibo Lu on 3/4/19.
6 | // Copyright © 2019 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import BBWebImage
11 | import SDWebImage
12 | import YYWebImage
13 | import Kingfisher
14 |
15 | typealias NoParamterBlock = () -> Void
16 |
17 | class MainMenuVC: UIViewController {
18 |
19 | @IBOutlet weak var tableView: UITableView!
20 |
21 | private var list: [(String, NoParamterBlock)]!
22 |
23 | override func viewDidLoad() {
24 | super.viewDidLoad()
25 |
26 | let testBB = { [weak self] in
27 | if let self = self { self.navigationController?.pushViewController(ImageWallVC(type: .BBWebImage), animated: true) }
28 | }
29 | let testSD = { [weak self] in
30 | if let self = self { self.navigationController?.pushViewController(ImageWallVC(type: .SDWebImage), animated: true) }
31 | }
32 | let testYY = { [weak self] in
33 | if let self = self { self.navigationController?.pushViewController(ImageWallVC(type: .YYWebImage), animated: true) }
34 | }
35 | let testKi = { [weak self] in
36 | if let self = self { self.navigationController?.pushViewController(ImageWallVC(type: .Kingfisher), animated: true) }
37 | }
38 | let testGifBB = { [weak self] in
39 | if let self = self { self.navigationController?.pushViewController(BBAnimatedImageWallVC(), animated: true) }
40 | }
41 | let testGifSD = { [weak self] in
42 | if let self = self { self.navigationController?.pushViewController(SDAnimatedImageWallVC(), animated: true) }
43 | }
44 | let testGifYY = { [weak self] in
45 | if let self = self { self.navigationController?.pushViewController(YYAnimatedImageWallVC(), animated: true) }
46 | }
47 | let testGifKi = { [weak self] in
48 | if let self = self { self.navigationController?.pushViewController(KiAnimatedImageWallVC(), animated: true) }
49 | }
50 | let testCache = { [weak self] in
51 | if let self = self { self.navigationController?.pushViewController(TestCacheVC(), animated: true) }
52 | }
53 | let clear = { [weak self] in
54 | guard self != nil else { return }
55 | BBWebImageManager.shared.imageCache.clear(.all, completion: nil)
56 |
57 | SDWebImageManager.shared().imageCache?.clearMemory()
58 | SDWebImageManager.shared().imageCache?.clearDisk(onCompletion: nil)
59 |
60 | YYWebImageManager.shared().cache?.memoryCache.removeAllObjects()
61 | YYWebImageManager.shared().cache?.diskCache.removeAllObjects()
62 |
63 | KingfisherManager.shared.cache.clearMemoryCache()
64 | KingfisherManager.shared.cache.clearDiskCache()
65 | }
66 | list = [("BBWebImage image wall", testBB),
67 | ("SDWebImage image wall", testSD),
68 | ("YYWebImage image wall", testYY),
69 | ("Kingfisher image wall", testKi),
70 | ("BBWebImage GIF wall", testGifBB),
71 | ("SDWebImage GIF wall", testGifSD),
72 | ("YYWebImage GIF wall", testGifYY),
73 | ("Kingfisher GIF wall", testGifKi),
74 | ("Test cache", testCache),
75 | ("Clear", clear)]
76 |
77 | tableView.register(UITableViewCell.self, forCellReuseIdentifier: UITableViewCell.description())
78 | tableView.dataSource = self
79 | tableView.delegate = self
80 | }
81 | }
82 |
83 | extension MainMenuVC: UITableViewDataSource {
84 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
85 | return list.count
86 | }
87 |
88 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
89 | let cell = tableView.dequeueReusableCell(withIdentifier: UITableViewCell.description(), for: indexPath)
90 | cell.textLabel?.text = list[indexPath.row].0
91 | return cell
92 | }
93 | }
94 |
95 | extension MainMenuVC: UITableViewDelegate {
96 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
97 | tableView.deselectRow(at: indexPath, animated: true)
98 | list[indexPath.row].1()
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/SDAnimatedImageWallCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SDAnimatedImageWallCell.swift
3 | // CompareImageLib
4 | //
5 | // Created by Kaibo Lu on 3/15/19.
6 | // Copyright © 2019 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SDWebImage
11 |
12 | class SDAnimatedImageWallCell: UICollectionViewCell {
13 | private var imageView: FLAnimatedImageView!
14 |
15 | override init(frame: CGRect) {
16 | super.init(frame: frame)
17 |
18 | imageView = FLAnimatedImageView(frame: CGRect(origin: .zero, size: frame.size))
19 | imageView.contentMode = .scaleAspectFill
20 | imageView.clipsToBounds = true
21 | contentView.addSubview(imageView)
22 | }
23 |
24 | required init?(coder aDecoder: NSCoder) {
25 | fatalError("init(coder:) has not been implemented")
26 | }
27 |
28 | func set(url: URL) {
29 | let placeholder = UIImage(named: "placeholder")
30 | imageView.sd_setImage(with: url, placeholderImage: placeholder, options: [], completed: nil)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/SDAnimatedImageWallVC.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SDAnimatedImageWallVC.swift
3 | // CompareImageLib
4 | //
5 | // Created by Kaibo Lu on 3/15/19.
6 | // Copyright © 2019 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SDAnimatedImageWallVC: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 |
16 | let layout = UICollectionViewFlowLayout()
17 | layout.minimumLineSpacing = 0
18 | layout.minimumInteritemSpacing = 0
19 | let cellWidth = view.bounds.width / 4
20 | layout.itemSize = CGSize(width: cellWidth, height: cellWidth)
21 | let colletionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
22 | colletionView.register(SDAnimatedImageWallCell.self, forCellWithReuseIdentifier: SDAnimatedImageWallCell.description())
23 | colletionView.backgroundColor = .white
24 | colletionView.dataSource = self
25 | view.addSubview(colletionView)
26 | }
27 | }
28 |
29 | extension SDAnimatedImageWallVC: UICollectionViewDataSource {
30 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
31 | return ImageURLProvider.gifUrlStrings.count
32 | }
33 |
34 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
35 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: SDAnimatedImageWallCell.description(), for: indexPath) as! SDAnimatedImageWallCell
36 | if let url = ImageURLProvider.gifURL(forIndex: indexPath.item) {
37 | cell.set(url: url)
38 | }
39 | return cell
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_1.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_10.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_100.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_100.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_100_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_100_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_10_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_10_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_11.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_11_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_11_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_12.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_12.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_12_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_12_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_13.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_13.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_13_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_13_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_14.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_14.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_14_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_14_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_15.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_15.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_15_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_15_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_16.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_16.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_16_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_16_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_17.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_17.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_17_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_17_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_18.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_18.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_18_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_18_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_19.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_19.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_19_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_19_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_1_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_1_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_2.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_20.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_20.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_20_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_20_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_21.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_21.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_21_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_21_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_22.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_22.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_22_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_22_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_23.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_23.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_23_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_23_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_24.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_24.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_24_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_24_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_25.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_25.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_25_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_25_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_26.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_26.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_26_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_26_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_27.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_27.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_27_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_27_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_28.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_28.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_28_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_28_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_29.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_29.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_29_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_29_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_2_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_2_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_3.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_30.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_30.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_30_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_30_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_31.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_31.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_31_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_31_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_32.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_32.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_32_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_32_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_33.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_33.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_33_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_33_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_34.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_34.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_34_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_34_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_35.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_35.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_35_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_35_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_36.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_36.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_36_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_36_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_37.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_37.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_37_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_37_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_38.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_38.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_38_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_38_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_39.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_39.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_39_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_39_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_3_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_3_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_4.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_40.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_40.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_40_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_40_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_41.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_41.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_41_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_41_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_42.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_42.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_42_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_42_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_43.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_43.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_43_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_43_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_44.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_44.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_44_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_44_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_45.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_45.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_45_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_45_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_46.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_46.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_46_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_46_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_47.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_47.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_47_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_47_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_48.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_48.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_48_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_48_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_49.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_49.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_49_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_49_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_4_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_4_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_5.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_50.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_50.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_50_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_50_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_51.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_51.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_51_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_51_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_52.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_52.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_52_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_52_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_53.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_53.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_53_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_53_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_54.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_54.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_54_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_54_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_55.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_55.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_55_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_55_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_56.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_56.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_56_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_56_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_57.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_57.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_57_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_57_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_58.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_58.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_58_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_58_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_59.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_59.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_59_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_59_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_5_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_5_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_6.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_60.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_60.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_60_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_60_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_61.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_61.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_61_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_61_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_62.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_62.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_62_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_62_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_63.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_63.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_63_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_63_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_64_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_64_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_65.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_65.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_65_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_65_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_66.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_66.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_66_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_66_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_67.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_67.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_67_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_67_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_68.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_68.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_68_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_68_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_69.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_69.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_69_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_69_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_6_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_6_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_7.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_70.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_70.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_70_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_70_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_71.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_71.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_71_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_71_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_72.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_72.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_72_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_72_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_73.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_73.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_73_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_73_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_74.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_74.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_74_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_74_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_75.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_75.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_75_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_75_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_76.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_76.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_76_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_76_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_77.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_77.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_77_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_77_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_78.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_78.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_78_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_78_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_79.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_79.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_79_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_79_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_7_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_7_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_8.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_80.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_80.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_80_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_80_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_81.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_81.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_81_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_81_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_82.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_82.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_82_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_82_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_83.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_83.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_83_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_83_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_84.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_84.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_84_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_84_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_85.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_85.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_85_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_85_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_86.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_86.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_86_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_86_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_87.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_87.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_87_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_87_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_88.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_88.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_88_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_88_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_89.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_89.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_89_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_89_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_8_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_8_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_9.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_90.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_90.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_90_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_90_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_91.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_91.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_91_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_91_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_92.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_92.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_92_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_92_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_93.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_93.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_93_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_93_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_94.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_94.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_94_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_94_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_95.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_95.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_95_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_95_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_96.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_96.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_96_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_96_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_97.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_97.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_97_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_97_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_98.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_98.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_98_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_98_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_99.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_99.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_99_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_99_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/TestImages/test_9_size_64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/CompareImageLib/CompareImageLib/TestImages/test_9_size_64.jpg
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/YYAnimatedImageWallCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // YYAnimatedImageWallCell.swift
3 | // CompareImageLib
4 | //
5 | // Created by Kaibo Lu on 3/15/19.
6 | // Copyright © 2019 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import YYWebImage
11 |
12 | class YYAnimatedImageWallCell: UICollectionViewCell {
13 | private var imageView: UIImageView!
14 |
15 | override init(frame: CGRect) {
16 | super.init(frame: frame)
17 |
18 | imageView = YYAnimatedImageView(frame: CGRect(origin: .zero, size: frame.size))
19 | imageView.contentMode = .scaleAspectFill
20 | imageView.clipsToBounds = true
21 | contentView.addSubview(imageView)
22 | }
23 |
24 | required init?(coder aDecoder: NSCoder) {
25 | fatalError("init(coder:) has not been implemented")
26 | }
27 |
28 | func set(url: URL) {
29 | let placeholder = UIImage(named: "placeholder")
30 | imageView.yy_setImage(with: url, placeholder: placeholder)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/CompareImageLib/CompareImageLib/YYAnimatedImageWallVC.swift:
--------------------------------------------------------------------------------
1 | //
2 | // YYAnimatedImageWallVC.swift
3 | // CompareImageLib
4 | //
5 | // Created by Kaibo Lu on 3/15/19.
6 | // Copyright © 2019 Kaibo Lu. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class YYAnimatedImageWallVC: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 |
16 | let layout = UICollectionViewFlowLayout()
17 | layout.minimumLineSpacing = 0
18 | layout.minimumInteritemSpacing = 0
19 | let cellWidth = view.bounds.width / 4
20 | layout.itemSize = CGSize(width: cellWidth, height: cellWidth)
21 | let colletionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
22 | colletionView.register(YYAnimatedImageWallCell.self, forCellWithReuseIdentifier: YYAnimatedImageWallCell.description())
23 | colletionView.backgroundColor = .white
24 | colletionView.dataSource = self
25 | view.addSubview(colletionView)
26 | }
27 | }
28 |
29 | extension YYAnimatedImageWallVC: UICollectionViewDataSource {
30 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
31 | return ImageURLProvider.gifUrlStrings.count
32 | }
33 |
34 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
35 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: YYAnimatedImageWallCell.description(), for: indexPath) as! YYAnimatedImageWallCell
36 | if let url = ImageURLProvider.gifURL(forIndex: indexPath.item) {
37 | cell.set(url: url)
38 | }
39 | return cell
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/CompareImageLib/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '8.0'
2 |
3 | target 'CompareImageLib' do
4 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
5 | use_frameworks!
6 |
7 | pod 'Kingfisher'
8 | pod 'SDWebImage/GIF'
9 | pod 'YYWebImage'
10 |
11 | end
12 |
--------------------------------------------------------------------------------
/CompareImageLib/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - FLAnimatedImage (1.0.12)
3 | - Kingfisher (4.10.1)
4 | - SDWebImage/Core (4.4.6)
5 | - SDWebImage/GIF (4.4.6):
6 | - FLAnimatedImage (~> 1.0)
7 | - SDWebImage/Core
8 | - YYCache (1.0.4)
9 | - YYImage (1.0.4):
10 | - YYImage/Core (= 1.0.4)
11 | - YYImage/Core (1.0.4)
12 | - YYWebImage (1.0.5):
13 | - YYCache
14 | - YYImage
15 |
16 | DEPENDENCIES:
17 | - Kingfisher
18 | - SDWebImage/GIF
19 | - YYWebImage
20 |
21 | SPEC REPOS:
22 | https://github.com/cocoapods/specs.git:
23 | - FLAnimatedImage
24 | - Kingfisher
25 | - SDWebImage
26 | - YYCache
27 | - YYImage
28 | - YYWebImage
29 |
30 | SPEC CHECKSUMS:
31 | FLAnimatedImage: 4a0b56255d9b05f18b6dd7ee06871be5d3b89e31
32 | Kingfisher: c148cd7b47ebde9989f6bc7c27dcaa79d81279a0
33 | SDWebImage: 3f3f0c02f09798048c47a5ed0a13f17b063572d8
34 | YYCache: 8105b6638f5e849296c71f331ff83891a4942952
35 | YYImage: 1e1b62a9997399593e4b9c4ecfbbabbf1d3f3b54
36 | YYWebImage: 5f7f36aee2ae293f016d418c7d6ba05c4863e928
37 |
38 | PODFILE CHECKSUM: 49900334799b07b34941a9a531723dc747bdc421
39 |
40 | COCOAPODS: 1.5.3
41 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Kaibo Lu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README_resources/CompareImageLib.key:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/README_resources/CompareImageLib.key
--------------------------------------------------------------------------------
/README_resources/CompareImageLib.numbers:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/README_resources/CompareImageLib.numbers
--------------------------------------------------------------------------------
/README_resources/architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/README_resources/architecture.png
--------------------------------------------------------------------------------
/README_resources/compare_diskCache.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/README_resources/compare_diskCache.png
--------------------------------------------------------------------------------
/README_resources/compare_gif_CPU_memory.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/README_resources/compare_gif_CPU_memory.png
--------------------------------------------------------------------------------
/README_resources/compare_memoryCache.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/README_resources/compare_memoryCache.png
--------------------------------------------------------------------------------
/README_resources/edit_common.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/README_resources/edit_common.gif
--------------------------------------------------------------------------------
/README_resources/edit_filter.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/README_resources/edit_filter.gif
--------------------------------------------------------------------------------
/README_resources/original_image.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Silence-GitHub/BBWebImage/66b6531a2b31bd313b4e0f313d97c189904e5f1c/README_resources/original_image.gif
--------------------------------------------------------------------------------