Commit 07fd87d3 by SunARcTech2

changes

parent 3c37240a
No preview for this file type
......@@ -141,13 +141,13 @@
B0F5F58F2140E6C60071443A /* Certificates.p12 in Resources */ = {isa = PBXBuildFile; fileRef = B0F5F5862140E6C50071443A /* Certificates.p12 */; };
B14F485320C6B1C400C95FB0 /* CardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14F484A20C6B1C400C95FB0 /* CardView.swift */; };
B1A3E6BE20E0E9E8003194B1 /* DrawButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1A3E6B520E0E9E8003194B1 /* DrawButton.swift */; };
C70B7A172174962B0022781B /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = C70B7A162174962B0022781B /* GoogleService-Info.plist */; };
C725BD1221525FFD00D65D41 /* OrderDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = C725BD1121525FFD00D65D41 /* OrderDetails.swift */; };
C725BD1C2152600D00D65D41 /* OrderDetailsExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = C725BD1B2152600D00D65D41 /* OrderDetailsExt.swift */; };
C725BD2021526CF700D65D41 /* FAQDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C725BD1F21526CF700D65D41 /* FAQDetailsViewController.swift */; };
C7330EB8216DCE4000DF238B /* FormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7330EB7216DCE4000DF238B /* FormViewController.swift */; };
C7C33EC0215A2C69001D5B25 /* PostInFullScreenView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C7C33EBF215A2C69001D5B25 /* PostInFullScreenView.xib */; };
C7C33EC2215A2C75001D5B25 /* PostInFullScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C33EC1215A2C75001D5B25 /* PostInFullScreenView.swift */; };
C7E21D80216F6F79004606E8 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = C7E21D7E216F6F78004606E8 /* GoogleService-Info.plist */; };
C7E21D81216F6F79004606E8 /* GoogleService-Info2.plist in Resources */ = {isa = PBXBuildFile; fileRef = C7E21D7F216F6F79004606E8 /* GoogleService-Info2.plist */; };
EC04CD3D2052CC0100B425BB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EC04CD3C2052CC0100B425BB /* Assets.xcassets */; };
EC04CD492052CC3B00B425BB /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = EC04CD4B2052CC3B00B425BB /* Localizable.strings */; };
......@@ -688,13 +688,13 @@
B0F5F5862140E6C50071443A /* Certificates.p12 */ = {isa = PBXFileReference; lastKnownFileType = file; path = Certificates.p12; sourceTree = "<group>"; };
B14F484A20C6B1C400C95FB0 /* CardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardView.swift; sourceTree = "<group>"; };
B1A3E6B520E0E9E8003194B1 /* DrawButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DrawButton.swift; sourceTree = "<group>"; };
C70B7A162174962B0022781B /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
C725BD1121525FFD00D65D41 /* OrderDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderDetails.swift; sourceTree = "<group>"; };
C725BD1B2152600D00D65D41 /* OrderDetailsExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrderDetailsExt.swift; sourceTree = "<group>"; };
C725BD1F21526CF700D65D41 /* FAQDetailsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAQDetailsViewController.swift; sourceTree = "<group>"; };
C7330EB7216DCE4000DF238B /* FormViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormViewController.swift; sourceTree = "<group>"; };
C7C33EBF215A2C69001D5B25 /* PostInFullScreenView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PostInFullScreenView.xib; sourceTree = "<group>"; };
C7C33EC1215A2C75001D5B25 /* PostInFullScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostInFullScreenView.swift; sourceTree = "<group>"; };
C7E21D7E216F6F78004606E8 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
C7E21D7F216F6F79004606E8 /* GoogleService-Info2.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info2.plist"; sourceTree = "<group>"; };
EC04CD322052CC0100B425BB /* Bhagyashree.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Bhagyashree.app; sourceTree = BUILT_PRODUCTS_DIR; };
EC04CD3C2052CC0100B425BB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
......@@ -1488,8 +1488,8 @@
B0B468F320B52A9C0076B7BE /* Sunarc */,
EC04CD3C2052CC0100B425BB /* Assets.xcassets */,
B024385020B52EF5007D12AE /* Fengshui.xcassets */,
C7E21D7E216F6F78004606E8 /* GoogleService-Info.plist */,
C7E21D7F216F6F79004606E8 /* GoogleService-Info2.plist */,
C70B7A162174962B0022781B /* GoogleService-Info.plist */,
EC04CD412052CC0100B425BB /* Info.plist */,
);
path = Bhagyashree;
......@@ -2234,7 +2234,6 @@
buildActionMask = 2147483647;
files = (
C7C33EC0215A2C69001D5B25 /* PostInFullScreenView.xib in Resources */,
C7E21D80216F6F79004606E8 /* GoogleService-Info.plist in Resources */,
EC04CFE32052CF3900B425BB /* Main.storyboard in Resources */,
EC04CEC02052CE4A00B425BB /* CartTableViewCell.xib in Resources */,
EC04CF4D2052CF0B00B425BB /* TopCategoryTableViewCell.xib in Resources */,
......@@ -2321,6 +2320,7 @@
EC04CEF82052CE9400B425BB /* AddreessViewCell2.xib in Resources */,
EC04CF542052CF0B00B425BB /* HotdealsTableViewCell.xib in Resources */,
EC04D0322052D2F400B425BB /* ContinueToBillTableViewCell.xib in Resources */,
C70B7A172174962B0022781B /* GoogleService-Info.plist in Resources */,
B024385120B52EF5007D12AE /* Fengshui.xcassets in Resources */,
EC04CFC02052CF2A00B425BB /* IQKeyboardManager.bundle in Resources */,
EC04CE182052CDA300B425BB /* TopSellingProduct.xib in Resources */,
......@@ -2918,16 +2918,16 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Bhagyashree/Bhagyashree.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_IDENTITY = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
DEVELOPMENT_TEAM = AY4776L6L2;
INFOPLIST_FILE = Bhagyashree/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.gdi.yuanzhongsiuseller;
PRODUCT_BUNDLE_IDENTIFIER = com.gdi.yuanzhongsiumaster;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "dd4d6db4-b04b-4852-bc63-57c403be8da1";
PROVISIONING_PROFILE_SPECIFIER = Seller_Dev;
PROVISIONING_PROFILE = "14cf4f94-331e-40f4-8735-1b68dfa7667f";
PROVISIONING_PROFILE_SPECIFIER = Master_Production;
SWIFT_OBJC_BRIDGING_HEADER = "Bhagyashree/MARKET PLACE/Seller Create Credit Memo/Bhagyashree-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.0;
......@@ -2943,16 +2943,16 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Bhagyashree/Bhagyashree.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_IDENTITY = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
DEVELOPMENT_TEAM = AY4776L6L2;
INFOPLIST_FILE = Bhagyashree/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.gdi.yuanzhongsiuseller;
PRODUCT_BUNDLE_IDENTIFIER = com.gdi.yuanzhongsiumaster;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "dd4d6db4-b04b-4852-bc63-57c403be8da1";
PROVISIONING_PROFILE_SPECIFIER = Seller_Dev;
PROVISIONING_PROFILE = "14cf4f94-331e-40f4-8735-1b68dfa7667f";
PROVISIONING_PROFILE_SPECIFIER = Master_Production;
SWIFT_OBJC_BRIDGING_HEADER = "Bhagyashree/MARKET PLACE/Seller Create Credit Memo/Bhagyashree-Bridging-Header.h";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
......
......@@ -7,7 +7,7 @@
<key>Bhagyashree.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>34</integer>
<integer>35</integer>
</dict>
</dict>
</dict>
......
......@@ -127,8 +127,8 @@
endingColumnNumber = "9223372036854775807"
startingLineNumber = "127"
endingLineNumber = "127"
landmarkName = "tableView(_:didSelectRowAt:)"
landmarkType = "7">
landmarkName = "unknown"
landmarkType = "0">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
......@@ -143,8 +143,8 @@
endingColumnNumber = "9223372036854775807"
startingLineNumber = "124"
endingLineNumber = "124"
landmarkName = "tableView(_:didSelectRowAt:)"
landmarkType = "7">
landmarkName = "unknown"
landmarkType = "0">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
......@@ -159,8 +159,8 @@
endingColumnNumber = "9223372036854775807"
startingLineNumber = "64"
endingLineNumber = "64"
landmarkName = "playAudio(audioPath:success:failure:progress:)"
landmarkType = "7">
landmarkName = "unknown"
landmarkType = "0">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
......
No preview for this file type
......@@ -7,9 +7,9 @@
<key>AD_UNIT_ID_FOR_INTERSTITIAL_TEST</key>
<string>ca-app-pub-3940256099942544/4411468910</string>
<key>CLIENT_ID</key>
<string>360669556539-tr24dr2sh481mum3ijjkassug7p7l04p.apps.googleusercontent.com</string>
<string>360669556539-aobitroejmk5lrne4u0mv22l41l9prv7.apps.googleusercontent.com</string>
<key>REVERSED_CLIENT_ID</key>
<string>com.googleusercontent.apps.360669556539-tr24dr2sh481mum3ijjkassug7p7l04p</string>
<string>com.googleusercontent.apps.360669556539-aobitroejmk5lrne4u0mv22l41l9prv7</string>
<key>API_KEY</key>
<string>AIzaSyBbcoObffadmduuSAhDozLyWbyiqg7Mf9s</string>
<key>GCM_SENDER_ID</key>
......@@ -17,24 +17,24 @@
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>com.gdi.yuanzhongsiuseller</string>
<string>com.gdi.yuanzhongsiumaster</string>
<key>PROJECT_ID</key>
<string>fengshui-customer</string>
<key>STORAGE_BUCKET</key>
<string>fengshui-customer.appspot.com</string>
<key>IS_ADS_ENABLED</key>
<true/>
<true></true>
<key>IS_ANALYTICS_ENABLED</key>
<false/>
<false></false>
<key>IS_APPINVITE_ENABLED</key>
<false/>
<false></false>
<key>IS_GCM_ENABLED</key>
<true/>
<true></true>
<key>IS_SIGNIN_ENABLED</key>
<true/>
<true></true>
<key>GOOGLE_APP_ID</key>
<string>1:360669556539:ios:53c921650750ae37</string>
<string>1:360669556539:ios:a710d90793c1d99a</string>
<key>DATABASE_URL</key>
<string>https://fengshui-customer.firebaseio.com</string>
</dict>
</plist>
</plist>
\ No newline at end of file
......@@ -19,7 +19,7 @@
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>4</string>
<string>2</string>
<key>Fabric</key>
<dict>
<key>APIKey</key>
......
......@@ -341,7 +341,7 @@
<objects>
<viewController storyboardIdentifier="FloorPlanFengshuiViewController" id="zhu-Ue-WYE" customClass="FloorPlanFengshuiViewController" customModule="Bhagyashree" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="vOF-80-GgO">
<rect key="frame" x="0.0" y="0.0" width="375" height="1000"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sXk-Cp-lQo">
......
......@@ -51,12 +51,12 @@ PODS:
- "GoogleToolboxForMac/NSData+zlib (2.1.4)":
- GoogleToolboxForMac/Defines (= 2.1.4)
- GTMSessionFetcher/Core (1.1.15)
- ImageSlideshow (1.7.0):
- ImageSlideshow/Core (= 1.7.0)
- ImageSlideshow/Core (1.7.0)
- ImageSlideshow/SDWebImage (1.7.0):
- ImageSlideshow (1.4.1):
- ImageSlideshow/Core (= 1.4.1)
- ImageSlideshow/Core (1.4.1)
- ImageSlideshow/SDWebImage (1.4.1):
- ImageSlideshow/Core
- SDWebImage (< 5.0, >= 3.7)
- SDWebImage (~> 3.7)
- INSPhotoGallery (1.2.5)
- IQKeyboardManagerSwift (5.0.8)
- Kingfisher (4.7.0)
......@@ -74,9 +74,9 @@ PODS:
- Realm/Headers (3.11.0)
- RealmSwift (3.11.0):
- Realm (= 3.11.0)
- SDWebImage (4.4.2):
- SDWebImage/Core (= 4.4.2)
- SDWebImage/Core (4.4.2)
- SDWebImage (3.8.2):
- SDWebImage/Core (= 3.8.2)
- SDWebImage/Core (3.8.2)
- SVProgressHUD (2.0.3)
- SwiftDate (4.4.1)
- TimeAgoInWords (3.0.0)
......@@ -156,7 +156,7 @@ SPEC CHECKSUMS:
FirebaseStorage: 7ca4bb7b58a25fa647b04f524033fc7cb7eb272b
GoogleToolboxForMac: 91c824d21e85b31c2aae9bb011c5027c9b4e738f
GTMSessionFetcher: 5fa5b80fd20e439ef5f545fb2cb3ca6c6714caa2
ImageSlideshow: f8eec5e37a980f60923b585ff23b0e140fd24018
ImageSlideshow: 1bb0e610e28a71e8936d57265d882f61714a470b
INSPhotoGallery: 8bd5b434e70d06dd698085f8e865f6602d82014b
IQKeyboardManagerSwift: 2e7dc7f98c111458c1ea2b373f893e8cf95e2b97
Kingfisher: da6b005aa96d37698e3e4f1ccfe96a5b9bbf27d6
......@@ -167,7 +167,7 @@ SPEC CHECKSUMS:
Protobuf: 8a9838fba8dae3389230e1b7f8c104aa32389c03
Realm: 92f09a102692b96a9a10e9617f214f15c5ab85fc
RealmSwift: 5f0481cd658bb751c509314b964a35eaa264d2cf
SDWebImage: 624d6e296c69b244bcede364c72ae0430ac14681
SDWebImage: 098e97e6176540799c27e804c96653ee0833d13c
SVProgressHUD: b0830714205bea1317ea1a2ebc71e5633af334d4
SwiftDate: a70a534d4feed03b2a2b575e36bef82dc2286a8d
TimeAgoInWords: 633dbb30810de855333dedd1d5033d28b1ecfd6f
......
......@@ -31,11 +31,11 @@ extension UIActivityIndicatorView: ActivityIndicatorView {
}
public func show() {
startAnimating()
self.startAnimating()
}
public func hide() {
stopAnimating()
self.stopAnimating()
}
}
......@@ -43,8 +43,7 @@ extension UIActivityIndicatorView: ActivityIndicatorView {
@objcMembers
open class DefaultActivityIndicator: ActivityIndicatorFactory {
/// activity indicator style
open var style: UIActivityIndicatorView.Style
open var style: UIActivityIndicatorViewStyle
/// activity indicator color
open var color: UIColor?
......@@ -52,18 +51,14 @@ open class DefaultActivityIndicator: ActivityIndicatorFactory {
///
/// - style: activity indicator style
/// - color: activity indicator color
public init(style: UIActivityIndicatorView.Style = .gray, color: UIColor? = nil) {
public init(style: UIActivityIndicatorViewStyle = .gray, color: UIColor? = nil) {
self.style = style
self.color = color
}
/// create ActivityIndicatorView instance
open func create() -> ActivityIndicatorView {
#if swift(>=4.2)
let activityIndicator = UIActivityIndicatorView(style: style)
#else
let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: style)
#endif
activityIndicator.color = color
activityIndicator.hidesWhenStopped = true
......
......@@ -14,7 +14,7 @@ open class FullScreenSlideshowViewController: UIViewController {
let slideshow = ImageSlideshow()
slideshow.zoomEnabled = true
slideshow.contentScaleMode = UIViewContentMode.scaleAspectFit
slideshow.pageIndicatorPosition = PageIndicatorPosition(horizontal: .center, vertical: .bottom)
slideshow.pageControlPosition = PageControlPosition.insideScrollView
// turns off the timer
slideshow.slideshowInterval = 0
slideshow.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
......@@ -25,9 +25,6 @@ open class FullScreenSlideshowViewController: UIViewController {
/// Close button
open var closeButton = UIButton()
/// Close button frame
open var closeButtonFrame: CGRect?
/// Closure called on page selection
open var pageSelected: ((_ page: Int) -> Void)?
......@@ -62,7 +59,8 @@ open class FullScreenSlideshowViewController: UIViewController {
view.addSubview(slideshow)
// close button configuration
closeButton.setImage(UIImage(named: "ic_cross_white", in: Bundle(for: type(of: self)), compatibleWith: nil), for: UIControlState())
closeButton.frame = CGRect(x: 10, y: 20, width: 40, height: 40)
closeButton.setImage(UIImage(named: "Frameworks/ImageSlideshow.framework/ImageSlideshow.bundle/ic_cross_white@2x"), for: UIControlState())
closeButton.addTarget(self, action: #selector(FullScreenSlideshowViewController.close), for: UIControlEvents.touchUpInside)
view.addSubview(closeButton)
}
......@@ -80,24 +78,7 @@ open class FullScreenSlideshowViewController: UIViewController {
}
}
override open func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
slideshow.slideshowItems.forEach { $0.cancelPendingLoad() }
}
open override func viewDidLayoutSubviews() {
if !isBeingDismissed {
let safeAreaInsets: UIEdgeInsets
if #available(iOS 11.0, *) {
safeAreaInsets = view.safeAreaInsets
} else {
safeAreaInsets = UIEdgeInsets.zero
}
closeButton.frame = closeButtonFrame ?? CGRect(x: max(10, safeAreaInsets.left), y: max(10, safeAreaInsets.top), width: 40, height: 40)
}
slideshow.frame = view.frame
}
......
......@@ -12,25 +12,22 @@ import UIKit
open class ImageSlideshowItem: UIScrollView, UIScrollViewDelegate {
/// Image view to hold the image
public let imageView = UIImageView()
open let imageView = UIImageView()
/// Activity indicator shown during image loading, when nil there won't be shown any
public let activityIndicator: ActivityIndicatorView?
open let activityIndicator: ActivityIndicatorView?
/// Input Source for the item
public let image: InputSource
open let image: InputSource
/// Guesture recognizer to detect double tap to zoom
open var gestureRecognizer: UITapGestureRecognizer?
/// Holds if the zoom feature is enabled
public let zoomEnabled: Bool
open let zoomEnabled: Bool
/// If set to true image is initially zoomed in
open var zoomInInitially = false
/// Maximum zoom scale
open var maximumScale: CGFloat = 2.0
fileprivate var lastFrame = CGRect.zero
fileprivate var imageReleased = false
......@@ -50,11 +47,10 @@ open class ImageSlideshowItem: UIScrollView, UIScrollViewDelegate {
- parameter image: Input Source to load the image
- parameter zoomEnabled: holds if it should be possible to zoom-in the image
*/
init(image: InputSource, zoomEnabled: Bool, activityIndicator: ActivityIndicatorView? = nil, maximumScale: CGFloat = 2.0) {
init(image: InputSource, zoomEnabled: Bool, activityIndicator: ActivityIndicatorView? = nil) {
self.zoomEnabled = zoomEnabled
self.image = image
self.activityIndicator = activityIndicator
self.maximumScale = maximumScale
super.init(frame: CGRect.null)
......@@ -120,34 +116,25 @@ open class ImageSlideshowItem: UIScrollView, UIScrollViewDelegate {
}
/// Request to load Image Source to Image View
public func loadImage() {
func loadImage() {
if self.imageView.image == nil && !isLoading {
isLoading = true
imageReleased = false
activityIndicator?.show()
image.load(to: self.imageView) {[weak self] image in
image.load(to: self.imageView) { image in
// set image to nil if there was a release request during the image load
if let imageRelease = self?.imageReleased, imageRelease {
self?.imageView.image = nil
}else{
self?.imageView.image = image
}
self?.activityIndicator?.hide()
self?.loadFailed = image == nil
self?.isLoading = false
self.imageView.image = self.imageReleased ? nil : image
self.activityIndicator?.hide()
self.loadFailed = image == nil
self.isLoading = false
}
}
}
func releaseImage() {
imageReleased = true
cancelPendingLoad()
self.imageView.image = nil
}
public func cancelPendingLoad() {
image.cancelLoad?(on: imageView)
}
@objc func retryLoadImage() {
self.loadImage()
......@@ -211,7 +198,8 @@ open class ImageSlideshowItem: UIScrollView, UIScrollViewDelegate {
}
fileprivate func calculateMaximumScale() -> CGFloat {
return maximumScale
// maximum scale is fixed to 2.0 for now. This may be overriden to perform a more sophisticated computation
return 2.0
}
fileprivate func setPictoCenter() {
......
......@@ -12,17 +12,11 @@ import UIKit
@objc public protocol InputSource {
/**
Load image from the source to image view.
- parameter imageView: Image view to load the image into.
- parameter callback: Callback called after image was set to the image view.
- parameter imageView: The image view to load the image into.
- parameter callback: Callback called after the image was set to the image view.
- parameter image: Image that was set to the image view.
*/
func load(to imageView: UIImageView, with callback: @escaping (_ image: UIImage?) -> Void)
/**
Cancel image load on the image view
- parameter imageView: Image view that is loading the image
*/
@objc optional func cancelLoad(on imageView: UIImageView)
}
/// Input Source to load plain UIImage
......
//
// PageIndicator.swift
// ImageSlideshow
//
// Created by Petr Zvoníček on 27.05.18.
//
import UIKit
/// Cusotm Page Indicator can be used by implementing this protocol
public protocol PageIndicatorView: class {
/// View of the page indicator
var view: UIView { get }
/// Current page of the page indicator
var page: Int { get set }
/// Total number of pages of the page indicator
var numberOfPages: Int { get set}
}
extension UIPageControl: PageIndicatorView {
public var view: UIView {
return self
}
public var page: Int {
get {
return currentPage
}
set {
currentPage = newValue
}
}
open override func sizeToFit() {
var frame = self.frame
frame.size = size(forNumberOfPages: numberOfPages)
frame.size.height = 30
self.frame = frame
}
}
/// Page indicator that shows page in numeric style, eg. "5/21"
public class LabelPageIndicator: UILabel, PageIndicatorView {
public var view: UIView {
return self
}
public var numberOfPages: Int = 0 {
didSet {
updateLabel()
}
}
public var page: Int = 0 {
didSet {
updateLabel()
}
}
public override init(frame: CGRect) {
super.init(frame: frame)
initialize()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initialize()
}
private func initialize() {
self.textAlignment = .center
}
private func updateLabel() {
text = "\(page+1)/\(numberOfPages)"
}
public override func sizeToFit() {
let maximumString = String(repeating: "8", count: numberOfPages) as NSString
self.frame.size = maximumString.size(withAttributes: [.font: font])
}
}
//
// PageIndicator.swift
// ImageSlideshow
//
// Created by Petr Zvoníček on 04.02.18.
//
import UIKit
/// Describes the configuration of the page indicator position
public struct PageIndicatorPosition {
public enum Horizontal {
case left(padding: CGFloat), center, right(padding: CGFloat)
}
public enum Vertical {
case top, bottom, under, customTop(padding: CGFloat), customBottom(padding: CGFloat), customUnder(padding: CGFloat)
}
/// Horizontal position of the page indicator
var horizontal: Horizontal
/// Vertical position of the page indicator
var vertical: Vertical
/// Creates a new PageIndicatorPosition struct
///
/// - Parameters:
/// - horizontal: horizontal position of the page indicator
/// - vertical: vertical position of the page indicator
public init(horizontal: Horizontal = .center, vertical: Vertical = .bottom) {
self.horizontal = horizontal
self.vertical = vertical
}
/// Computes the additional padding needed for the page indicator under the ImageSlideshow
///
/// - Parameter indicatorSize: size of the page indicator
/// - Returns: padding needed under the ImageSlideshow
func underPadding(for indicatorSize: CGSize) -> CGFloat {
switch vertical {
case .under:
return indicatorSize.height
case .customUnder(let padding):
return indicatorSize.height + padding
default:
return 0
}
}
/// Computes the page indicator frame
///
/// - Parameters:
/// - parentFrame: frame of the parent view – ImageSlideshow
/// - indicatorSize: size of the page indicator
/// - edgeInsets: edge insets of the parent view – ImageSlideshow (used for SafeAreaInsets adjustment)
/// - Returns: frame of the indicator by computing the origin and using `indicatorSize` as size
func indicatorFrame(for parentFrame: CGRect, indicatorSize: CGSize, edgeInsets: UIEdgeInsets) -> CGRect {
var xSize: CGFloat = 0
var ySize: CGFloat = 0
switch horizontal {
case .center:
xSize = parentFrame.size.width / 2 - indicatorSize.width / 2
case .left(let padding):
xSize = padding + edgeInsets.left
case .right(let padding):
xSize = parentFrame.size.width - indicatorSize.width - padding - edgeInsets.right
}
switch vertical {
case .bottom, .under, .customUnder:
ySize = parentFrame.size.height - indicatorSize.height - edgeInsets.bottom
case .customBottom(let padding):
ySize = parentFrame.size.height - indicatorSize.height - padding - edgeInsets.bottom
case .top:
ySize = edgeInsets.top
case .customTop(let padding):
ySize = padding + edgeInsets.top
}
return CGRect(x: xSize, y: ySize, width: indicatorSize.width, height: indicatorSize.height)
}
}
//
// SwiftSupport.swift
// ImageSlideshow
//
// Created by Pierluigi Cifani on 30/07/2018.
//
import UIKit
#if swift(>=4.2)
typealias UIViewContentMode = UIView.ContentMode
typealias UIActivityIndicatorViewStyle = UIActivityIndicatorView.Style
typealias UIControlState = UIControl.State
typealias UIViewAnimationOptions = UIView.AnimationOptions
typealias UIControlEvents = UIControl.Event
typealias UIViewAutoresizing = UIView.AutoresizingMask
#else
#endif
......@@ -13,7 +13,7 @@ open class ZoomAnimatedTransitioningDelegate: NSObject, UIViewControllerTransiti
/// parent image view used for animated transition
open var referenceImageView: UIImageView?
/// parent slideshow view used for animated transition
open weak var referenceSlideshowView: ImageSlideshow?
open var referenceSlideshowView: ImageSlideshow?
// must be weak because FullScreenSlideshowViewController has strong reference to its transitioning delegate
weak var referenceSlideshowController: FullScreenSlideshowViewController?
......@@ -66,7 +66,7 @@ open class ZoomAnimatedTransitioningDelegate: NSObject, UIViewControllerTransiti
return
}
let percent = min(max(abs(gesture.translation(in: gesture.view!).y) / 200.0, 0.0), 1.0)
let percent = min(max(fabs(gesture.translation(in: gesture.view!).y) / 200.0, 0.0), 1.0)
if gesture.state == .began {
interactionController = UIPercentDrivenInteractiveTransition()
......@@ -74,9 +74,10 @@ open class ZoomAnimatedTransitioningDelegate: NSObject, UIViewControllerTransiti
} else if gesture.state == .changed {
interactionController?.update(percent)
} else if gesture.state == .ended || gesture.state == .cancelled || gesture.state == .failed {
let velocity = gesture.velocity(in: referenceSlideshowView)
if abs(velocity.y) > 500 {
if fabs(velocity.y) > 500 {
if let pageSelected = referenceSlideshowController.pageSelected {
pageSelected(referenceSlideshowController.slideshow.currentPage)
}
......@@ -88,6 +89,7 @@ open class ZoomAnimatedTransitioningDelegate: NSObject, UIViewControllerTransiti
}
interactionController?.finish()
} else {
interactionController?.cancel()
}
......@@ -127,7 +129,7 @@ open class ZoomAnimatedTransitioningDelegate: NSObject, UIViewControllerTransiti
extension ZoomAnimatedTransitioningDelegate: UIGestureRecognizerDelegate {
public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
guard let gestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer else {
guard let _ = gestureRecognizer as? UIPanGestureRecognizer else {
return false
}
......@@ -139,11 +141,6 @@ extension ZoomAnimatedTransitioningDelegate: UIGestureRecognizerDelegate {
return false
}
if let view = gestureRecognizer.view {
let velocity = gestureRecognizer.velocity(in: view)
return abs(velocity.x) < abs(velocity.y)
}
return true
}
}
......@@ -170,7 +167,9 @@ class ZoomAnimator: NSObject {
}
@objcMembers
class ZoomInAnimator: ZoomAnimator, UIViewControllerAnimatedTransitioning {
class ZoomInAnimator: ZoomAnimator { }
extension ZoomInAnimator: UIViewControllerAnimatedTransitioning {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.5
......@@ -192,14 +191,8 @@ class ZoomInAnimator: ZoomAnimator, UIViewControllerAnimatedTransitioning {
let transitionBackgroundView = UIView(frame: containerView.frame)
transitionBackgroundView.backgroundColor = toViewController.backgroundColor
containerView.addSubview(transitionBackgroundView)
#if swift(>=4.2)
containerView.sendSubviewToBack(transitionBackgroundView)
#else
containerView.sendSubview(toBack: transitionBackgroundView)
#endif
let finalFrame = toViewController.view.frame
var transitionView: UIImageView?
......@@ -229,9 +222,9 @@ class ZoomInAnimator: ZoomAnimator, UIViewControllerAnimatedTransitioning {
fromViewController.view.alpha = 0
transitionView?.frame = transitionViewFinalFrame
transitionView?.center = CGPoint(x: finalFrame.midX, y: finalFrame.midY)
}, completion: {[ref = self.referenceImageView] _ in
}, completion: {(_) in
fromViewController.view.alpha = 1
ref?.alpha = 1
self.referenceImageView?.alpha = 1
transitionView?.removeFromSuperview()
transitionBackgroundView.removeFromSuperview()
containerView.addSubview(toViewController.view)
......@@ -240,35 +233,19 @@ class ZoomInAnimator: ZoomAnimator, UIViewControllerAnimatedTransitioning {
}
}
class ZoomOutAnimator: ZoomAnimator, UIViewControllerAnimatedTransitioning {
class ZoomOutAnimator: ZoomAnimator { }
private var animatorForCurrentTransition: UIViewImplicitlyAnimating?
extension ZoomOutAnimator: UIViewControllerAnimatedTransitioning {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.25
}
@available(iOS 10.0, *)
func interruptibleAnimator(using transitionContext: UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating {
// as per documentation, the same object should be returned for the ongoing transition
if let animatorForCurrentSession = animatorForCurrentTransition {
return animatorForCurrentSession
}
let params = animationParams(using: transitionContext)
let animator = UIViewPropertyAnimator(duration: params.0, curve: .linear, animations: params.1)
animator.addCompletion(params.2)
animatorForCurrentTransition = animator
return animator
}
private func animationParams(using transitionContext: UIViewControllerContextTransitioning) -> (TimeInterval, () -> (), (Any) -> ()) {
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let toViewController: UIViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!
guard let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from) as? FullScreenSlideshowViewController else {
fatalError("Transition not used with FullScreenSlideshowViewController")
return
}
let containerView = transitionContext.containerView
......@@ -276,11 +253,8 @@ class ZoomOutAnimator: ZoomAnimator, UIViewControllerAnimatedTransitioning {
toViewController.view.frame = transitionContext.finalFrame(for: toViewController)
toViewController.view.alpha = 0
containerView.addSubview(toViewController.view)
#if swift(>=4.2)
containerView.sendSubviewToBack(toViewController.view)
#else
containerView.sendSubview(toBack: toViewController.view)
#endif
var transitionViewInitialFrame: CGRect
if let currentSlideshowItem = fromViewController.slideshow.currentSlideshowItem {
if let image = currentSlideshowItem.imageView.image {
......@@ -316,11 +290,7 @@ class ZoomOutAnimator: ZoomAnimator, UIViewControllerAnimatedTransitioning {
let transitionBackgroundView = UIView(frame: containerView.frame)
transitionBackgroundView.backgroundColor = fromViewController.backgroundColor
containerView.addSubview(transitionBackgroundView)
#if swift(>=4.2)
containerView.sendSubviewToBack(transitionBackgroundView)
#else
containerView.sendSubview(toBack: transitionBackgroundView)
#endif
let transitionView: UIImageView = UIImageView(image: fromViewController.slideshow.currentSlideshowItem?.imageView.image)
transitionView.contentMode = UIViewContentMode.scaleAspectFill
......@@ -350,21 +320,14 @@ class ZoomOutAnimator: ZoomAnimator, UIViewControllerAnimatedTransitioning {
transitionView.removeFromSuperview()
transitionBackgroundView.removeFromSuperview()
self.animatorForCurrentTransition = nil
transitionContext.completeTransition(completed)
}
return (duration, animations, completion)
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
// Working around iOS 10+ breaking change requiring to use UIPropertyAnimator for proper interactive transition instead of UIView.animate
// Working around iOS 10 bug in UIView.animate causing a glitch in interrupted interactive transition
if #available(iOS 10.0, *) {
interruptibleAnimator(using: transitionContext).startAnimation()
UIViewPropertyAnimator.runningPropertyAnimator(withDuration: duration, delay: 0, options: UIViewAnimationOptions(), animations: animations, completion: completion)
} else {
let params = animationParams(using: transitionContext)
UIView.animate(withDuration: params.0, delay: 0, options: UIViewAnimationOptions(), animations: params.1, completion: params.2)
UIView.animate(withDuration: duration, delay: 0, options: UIViewAnimationOptions(), animations: animations, completion: completion)
}
}
}
......@@ -44,8 +44,4 @@ public class SDWebImageSource: NSObject, InputSource {
callback(image)
})
}
public func cancelLoad(on imageView: UIImageView) {
imageView.sd_cancelCurrentImageLoad()
}
}
# 🖼 ImageSlideshow
**Customizable Swift image slideshow with circular scrolling, timer and full screen viewer**
**Swift image slideshow with circular scrolling, timer and full screen viewer**
[![Build Status](https://www.bitrise.io/app/9aaf3e552f3a575c.svg?token=AjiVckTN9ItQtJs873mYMw&branch=master)](https://www.bitrise.io/app/9aaf3e552f3a575c)
[![Version](https://img.shields.io/cocoapods/v/ImageSlideshow.svg?style=flat)](http://cocoapods.org/pods/ImageSlideshow)
......@@ -8,9 +8,7 @@
[![License](https://img.shields.io/cocoapods/l/ImageSlideshow.svg?style=flat)](http://cocoapods.org/pods/ImageSlideshow)
[![Platform](https://img.shields.io/cocoapods/p/ImageSlideshow.svg?style=flat)](http://cocoapods.org/pods/ImageSlideshow)
![](https://dzwonsemrish7.cloudfront.net/items/2R06283n040V3P3p0i42/ezgif.com-optimize.gif)
![](http://cl.ly/image/2v193I0G0h0Z/ImageSlideshow2.gif)
## 📱 Example
......@@ -23,26 +21,26 @@ ImageSlideshow is available through [CocoaPods](http://cocoapods.org). To instal
it, simply add the following line to your Podfile:
```ruby
pod 'ImageSlideshow', '~> 1.6'
pod 'ImageSlideshow', '~> 1.3'
```
### Carthage
To integrate ImageSlideshow into your Xcode project using Carthage, specify it in your Cartfile:
```ruby
github "zvonicek/ImageSlideshow" ~> 1.6
github "zvonicek/ImageSlideshow" "1.3"
```
Carthage does not include InputSources for external providers (due to dependency on those providers) so you need to grab the one you need from `ImageSlideshow/Classes/InputSources` manually.
### Manually
One possibility is to download a built framework (ImageSlideshow.framework.zip) from [releases page](https://github.com/zvonicek/ImageSlideshow/releases/) and link it with your project (under`Linked Frameworks and Libraries` in your target). This is, however, currently problematic because of rapid Swift development -- the framework is built for a single Swift version and may not work on previous/future versions.
One possibility is to download a builded framework (ImageSlideshow.framework.zip) from [releases page](https://github.com/zvonicek/ImageSlideshow/releases/) and link it with your project (under`Linked Frameworks and Libraries` in your target). This is, however, currently problematic because of rapid Swift development -- the framework is builded for a single Swift version and may not work on previous/future versions.
Alternatively can also grab the whole `ImageSlideshow` directory and copy it to your project. Be sure to remove those external Input Sources you don't need.
**Note on Swift 2.3, Swift 3 and Swift 4 support**
**Note on Swift 2.3 and Swift 3 support**
Version 1.4 supports Swift 4. Swift 3 is supported from version 1.0, for Swift 2.2 and Swift 2.3 compatible code use version 0.6 or branch *swift-2.3*.
Version 1.0 supports Swift 3. For Swift 2.2 and Swift 2.3 compatible code use version 0.6 or branch *swift-2.3*.
## 🔨 How to use
......@@ -79,9 +77,7 @@ Behaviour is configurable by those properties:
- ```slideshowInterval``` - slideshow interval in seconds (default `0` – disabled)
- ```zoomEnabled``` - enables zooming (default `false`)
- ```circular``` - enables circular scrolling (default `true`)
- ```activityIndicator``` – allows to set custom activity indicator, see *Activity indicator* section
- ```pageIndicator``` – allows to set custom page indicator, see *Page indicator* section; assign `nil` to hide page indicator
- ```pageIndicatorPosition``` - configures position of the page indicator
- ```pageControlPosition``` - configures position of UIPageControl (default `insideScrollView`, also `hidden`, `underScrollView` or `custom`)
- ```contentScaleMode``` - configures the scaling (default `ScaleAspectFit`)
- ```draggingEnabled``` - enables dragging (default `true`)
- ```currentPageChanged``` - closure called on page change
......@@ -89,37 +85,6 @@ Behaviour is configurable by those properties:
- ```didEndDecelerating``` - closure called on scrollViewDidEndDecelerating
- ```preload``` - image preloading configuration (default `all` preloading, also `fixed`)
### Page Indicator
Page indicator can be customized using the `pageIndicator` property on ImageSlideshow. By defualt, a plain UIPageControl is used. If needed, page control can be customized:
```swift
let pageIndicator = UIPageControl()
pageIndicator.currentPageIndicatorTintColor = UIColor.lightGray
pageIndicator.pageIndicatorTintColor = UIColor.black
slideshow.pageIndicator = pageIndicator
```
Also, a simple label page indicator that shows pages in style "5/21" (fifth page from twenty one) is provided:
```swift
slideshow.pageIndicator = LabelPageIndicator()
```
You can also use your own page indicator by adopting the `PageIndicatorView` protocol.
Position of the page indicator can be configured by assigning a `PageIndicatorPosition` value to the `pageIndicatorPosition` property on ImageSlideshow. You may specify the horizontal and vertical positioning separately.
**Horizontal** positioning options are: `.left(padding: Int)`, `.center`, `.right(padding: Int)`
**Vertical** positioning options are: `.top`, `.bottom`, `.under`, `customTop(padding: Int)`, `customBottom(padding: Int)`, `customUnder(padding: Int)`
Example:
```swift
slideshow.pageIndicatorPosition = PageIndicatorPosition(horizontal: .left(padding: 20), vertical: .bottom)
```
### Activity Indicator
By default activity indicator is not shown, but you can enable it by setting `DefaultActivityIndicator` instance to Image Slideshow:
......
......@@ -51,12 +51,12 @@ PODS:
- "GoogleToolboxForMac/NSData+zlib (2.1.4)":
- GoogleToolboxForMac/Defines (= 2.1.4)
- GTMSessionFetcher/Core (1.1.15)
- ImageSlideshow (1.7.0):
- ImageSlideshow/Core (= 1.7.0)
- ImageSlideshow/Core (1.7.0)
- ImageSlideshow/SDWebImage (1.7.0):
- ImageSlideshow (1.4.1):
- ImageSlideshow/Core (= 1.4.1)
- ImageSlideshow/Core (1.4.1)
- ImageSlideshow/SDWebImage (1.4.1):
- ImageSlideshow/Core
- SDWebImage (< 5.0, >= 3.7)
- SDWebImage (~> 3.7)
- INSPhotoGallery (1.2.5)
- IQKeyboardManagerSwift (5.0.8)
- Kingfisher (4.7.0)
......@@ -74,9 +74,9 @@ PODS:
- Realm/Headers (3.11.0)
- RealmSwift (3.11.0):
- Realm (= 3.11.0)
- SDWebImage (4.4.2):
- SDWebImage/Core (= 4.4.2)
- SDWebImage/Core (4.4.2)
- SDWebImage (3.8.2):
- SDWebImage/Core (= 3.8.2)
- SDWebImage/Core (3.8.2)
- SVProgressHUD (2.0.3)
- SwiftDate (4.4.1)
- TimeAgoInWords (3.0.0)
......@@ -156,7 +156,7 @@ SPEC CHECKSUMS:
FirebaseStorage: 7ca4bb7b58a25fa647b04f524033fc7cb7eb272b
GoogleToolboxForMac: 91c824d21e85b31c2aae9bb011c5027c9b4e738f
GTMSessionFetcher: 5fa5b80fd20e439ef5f545fb2cb3ca6c6714caa2
ImageSlideshow: f8eec5e37a980f60923b585ff23b0e140fd24018
ImageSlideshow: 1bb0e610e28a71e8936d57265d882f61714a470b
INSPhotoGallery: 8bd5b434e70d06dd698085f8e865f6602d82014b
IQKeyboardManagerSwift: 2e7dc7f98c111458c1ea2b373f893e8cf95e2b97
Kingfisher: da6b005aa96d37698e3e4f1ccfe96a5b9bbf27d6
......@@ -167,7 +167,7 @@ SPEC CHECKSUMS:
Protobuf: 8a9838fba8dae3389230e1b7f8c104aa32389c03
Realm: 92f09a102692b96a9a10e9617f214f15c5ab85fc
RealmSwift: 5f0481cd658bb751c509314b964a35eaa264d2cf
SDWebImage: 624d6e296c69b244bcede364c72ae0430ac14681
SDWebImage: 098e97e6176540799c27e804c96653ee0833d13c
SVProgressHUD: b0830714205bea1317ea1a2ebc71e5633af334d4
SwiftDate: a70a534d4feed03b2a2b575e36bef82dc2286a8d
TimeAgoInWords: 633dbb30810de855333dedd1d5033d28b1ecfd6f
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -7,33 +7,30 @@
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForAnalyzing = "YES"
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
buildForArchiving = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "9FB26439C46101C637E927BC50978C09"
BuildableName = "INSPhotoGallery.bundle"
BlueprintName = "INSPhotoGallery-INSPhotoGallery"
ReferencedContainer = "container:Pods.xcodeproj">
ReferencedContainer = "container:Pods.xcodeproj"
BuildableName = "INSPhotoGallery-INSPhotoGallery.bundle">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
......@@ -41,25 +38,17 @@
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
buildConfiguration = "Debug"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "9FB26439C46101C637E927BC50978C09"
BuildableName = "INSPhotoGallery.bundle"
BlueprintName = "INSPhotoGallery-INSPhotoGallery"
ReferencedContainer = "container:Pods.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
debugDocumentVersioning = "YES"
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
......
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForAnalyzing = "YES"
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DC9AB3FA3139B764F352D5BCC210DDB7"
BlueprintName = "ImageSlideshow-ImageSlideshow"
ReferencedContainer = "container:Pods.xcodeproj"
BuildableName = "ImageSlideshow-ImageSlideshow.bundle">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
buildConfiguration = "Debug"
allowLocationSimulation = "YES">
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
......@@ -14,7 +14,7 @@
buildForArchiving = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "64497E66D96A364F588D8C1876566C53"
BlueprintIdentifier = "2339AFBD67988C09BB6EE88F18CFF581"
BlueprintName = "ImageSlideshow"
ReferencedContainer = "container:Pods.xcodeproj"
BuildableName = "ImageSlideshow.framework">
......
......@@ -7,33 +7,30 @@
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForAnalyzing = "YES"
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
buildForArchiving = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F97FDCB797E5DF04953162D3549D7A26"
BuildableName = "Pods_Bhagyashree.framework"
BlueprintName = "Pods-Bhagyashree"
ReferencedContainer = "container:Pods.xcodeproj">
ReferencedContainer = "container:Pods.xcodeproj"
BuildableName = "Pods-Bhagyashree.framework">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
......@@ -41,25 +38,17 @@
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
buildConfiguration = "Debug"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F97FDCB797E5DF04953162D3549D7A26"
BuildableName = "Pods_Bhagyashree.framework"
BlueprintName = "Pods-Bhagyashree"
ReferencedContainer = "container:Pods.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
debugDocumentVersioning = "YES"
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
......
......@@ -14,7 +14,7 @@
buildForArchiving = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2E07C16B760AF46E91B3D867A59A4952"
BlueprintIdentifier = "6B8583CCE3BE778FE818B271F73B3053"
BlueprintName = "SDWebImage"
ReferencedContainer = "container:Pods.xcodeproj"
BuildableName = "SDWebImage.framework">
......
......@@ -7,33 +7,30 @@
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForAnalyzing = "YES"
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
buildForArchiving = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "94117655CE92C34C54AE3BF2F2BC4C75"
BuildableName = "TimeAgoInWords.bundle"
BlueprintName = "TimeAgoInWords-TimeAgoInWords"
ReferencedContainer = "container:Pods.xcodeproj">
ReferencedContainer = "container:Pods.xcodeproj"
BuildableName = "TimeAgoInWords-TimeAgoInWords.bundle">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
......@@ -41,25 +38,17 @@
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
buildConfiguration = "Debug"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "94117655CE92C34C54AE3BF2F2BC4C75"
BuildableName = "TimeAgoInWords.bundle"
BlueprintName = "TimeAgoInWords-TimeAgoInWords"
ReferencedContainer = "container:Pods.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
debugDocumentVersioning = "YES"
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
......
......@@ -7,33 +7,30 @@
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForAnalyzing = "YES"
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
buildForArchiving = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "34371692C0577426FE7C41894182EEA5"
BuildableName = "leveldb.framework"
BlueprintName = "leveldb-library"
ReferencedContainer = "container:Pods.xcodeproj">
ReferencedContainer = "container:Pods.xcodeproj"
BuildableName = "leveldb-library.framework">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
......@@ -41,25 +38,17 @@
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
buildConfiguration = "Debug"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "34371692C0577426FE7C41894182EEA5"
BuildableName = "leveldb.framework"
BlueprintName = "leveldb-library"
ReferencedContainer = "container:Pods.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
debugDocumentVersioning = "YES"
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
......
......@@ -8,197 +8,146 @@
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>6</integer>
</dict>
<key>EasyToast.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>7</integer>
</dict>
<key>FirebaseAuth.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>8</integer>
</dict>
<key>FirebaseCore.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>9</integer>
</dict>
<key>FirebaseDatabase.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>10</integer>
</dict>
<key>FirebaseMessaging.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>11</integer>
</dict>
<key>FirebaseStorage.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>12</integer>
</dict>
<key>GTMSessionFetcher.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>14</integer>
</dict>
<key>GoogleToolboxForMac.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>13</integer>
</dict>
<key>INSPhotoGallery-INSPhotoGallery.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>17</integer>
</dict>
<key>INSPhotoGallery.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>16</integer>
</dict>
<key>IQKeyboardManagerSwift.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>18</integer>
</dict>
<key>ImageSlideshow-ImageSlideshow.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
</dict>
<key>ImageSlideshow.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>15</integer>
</dict>
<key>Kingfisher.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>19</integer>
</dict>
<key>MJRefresh.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>21</integer>
</dict>
<key>Pastel.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>23</integer>
</dict>
<key>Pods-Bhagyashree.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>24</integer>
</dict>
<key>Protobuf.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>25</integer>
</dict>
<key>Realm.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>26</integer>
</dict>
<key>RealmSwift.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>27</integer>
</dict>
<key>SDWebImage.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>28</integer>
</dict>
<key>SVProgressHUD.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>29</integer>
</dict>
<key>SwiftDate.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>30</integer>
</dict>
<key>TimeAgoInWords-TimeAgoInWords.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>32</integer>
</dict>
<key>TimeAgoInWords.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>31</integer>
</dict>
<key>WMPageController.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>33</integer>
</dict>
<key>leveldb-library.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>20</integer>
</dict>
<key>nanopb.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>22</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
......
Copyright (c) 2009-2017 Olivier Poitrey rs@dailymotion.com
Copyright (c) 2016 Olivier Poitrey rs@dailymotion.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
......
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "NSButton+WebCache.h"
#if SD_MAC
#import "objc/runtime.h"
#import "UIView+WebCacheOperation.h"
#import "UIView+WebCache.h"
static inline NSString * imageOperationKey() {
return @"NSButtonImageOperation";
}
static inline NSString * alternateImageOperationKey() {
return @"NSButtonAlternateImageOperation";
}
@implementation NSButton (WebCache)
#pragma mark - Image
- (void)sd_setImageWithURL:(nullable NSURL *)url {
[self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil];
}
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder {
[self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil];
}
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options {
[self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil];
}
- (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock];
}
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:completedBlock];
}
- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock];
}
- (void)sd_setImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock {
self.sd_currentImageURL = url;
__weak typeof(self)weakSelf = self;
[self sd_internalSetImageWithURL:url
placeholderImage:placeholder
options:options
operationKey:imageOperationKey()
setImageBlock:^(NSImage * _Nullable image, NSData * _Nullable imageData) {
weakSelf.image = image;
}
progress:progressBlock
completed:completedBlock];
}
#pragma mark - Alternate Image
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url {
[self sd_setAlternateImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil];
}
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder {
[self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil];
}
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options {
[self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil];
}
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_setAlternateImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock];
}
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:completedBlock];
}
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock {
[self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock];
}
- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url
placeholderImage:(nullable UIImage *)placeholder
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock {
self.sd_currentAlternateImageURL = url;
__weak typeof(self)weakSelf = self;
[self sd_internalSetImageWithURL:url
placeholderImage:placeholder
options:options
operationKey:alternateImageOperationKey()
setImageBlock:^(NSImage * _Nullable image, NSData * _Nullable imageData) {
weakSelf.alternateImage = image;
}
progress:progressBlock
completed:completedBlock];
}
#pragma mark - Cancel
- (void)sd_cancelCurrentImageLoad {
[self sd_cancelImageLoadOperationWithKey:imageOperationKey()];
}
- (void)sd_cancelCurrentAlternateImageLoad {
[self sd_cancelImageLoadOperationWithKey:alternateImageOperationKey()];
}
#pragma mar - Private
- (NSURL *)sd_currentImageURL {
return objc_getAssociatedObject(self, @selector(sd_currentImageURL));
}
- (void)setSd_currentImageURL:(NSURL *)sd_currentImageURL {
objc_setAssociatedObject(self, @selector(sd_currentImageURL), sd_currentImageURL, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSURL *)sd_currentAlternateImageURL {
return objc_getAssociatedObject(self, @selector(sd_currentAlternateImageURL));
}
- (void)setSd_currentAlternateImageURL:(NSURL *)sd_currentAlternateImageURL {
objc_setAssociatedObject(self, @selector(sd_currentAlternateImageURL), sd_currentAlternateImageURL, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
#endif
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
* (c) Fabrice Aneche
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
//
// Created by Fabrice Aneche on 06/01/14.
// Copyright (c) 2014 Dailymotion. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "SDWebImageCompat.h"
typedef NS_ENUM(NSInteger, SDImageFormat) {
SDImageFormatUndefined = -1,
SDImageFormatJPEG = 0,
SDImageFormatPNG,
SDImageFormatGIF,
SDImageFormatTIFF,
SDImageFormatWebP,
SDImageFormatHEIC
};
@interface NSData (ImageContentType)
/**
* Return image format
* Compute the content type for an image data
*
* @param data the input image data
* @param data the input data
*
* @return the image format as `SDImageFormat` (enum)
* @return the content type as string (i.e. image/jpeg, image/gif)
*/
+ (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data;
+ (NSString *)sd_contentTypeForImageData:(NSData *)data;
/**
* Convert SDImageFormat to UTType
*
* @param format Format as SDImageFormat
* @return The UTType as CFStringRef
*/
+ (nonnull CFStringRef)sd_UTTypeFromSDImageFormat:(SDImageFormat)format;
@end
/**
* Convert UTTyppe to SDImageFormat
*
* @param uttype The UTType as CFStringRef
* @return The Format as SDImageFormat
*/
+ (SDImageFormat)sd_imageFormatFromUTType:(nonnull CFStringRef)uttype;
@interface NSData (ImageContentTypeDeprecated)
+ (NSString *)contentTypeForImageData:(NSData *)data __deprecated_msg("Use `sd_contentTypeForImageData:`");
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
* (c) Fabrice Aneche
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
//
// Created by Fabrice Aneche on 06/01/14.
// Copyright (c) 2014 Dailymotion. All rights reserved.
//
#import "NSData+ImageContentType.h"
#if SD_MAC
#import <CoreServices/CoreServices.h>
#else
#import <MobileCoreServices/MobileCoreServices.h>
#endif
// Currently Image/IO does not support WebP
#define kSDUTTypeWebP ((__bridge CFStringRef)@"public.webp")
// AVFileTypeHEIC is defined in AVFoundation via iOS 11, we use this without import AVFoundation
#define kSDUTTypeHEIC ((__bridge CFStringRef)@"public.heic")
@implementation NSData (ImageContentType)
+ (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data {
if (!data) {
return SDImageFormatUndefined;
}
// File signatures table: http://www.garykessler.net/library/file_sigs.html
+ (NSString *)sd_contentTypeForImageData:(NSData *)data {
uint8_t c;
[data getBytes:&c length:1];
switch (c) {
case 0xFF:
return SDImageFormatJPEG;
return @"image/jpeg";
case 0x89:
return SDImageFormatPNG;
return @"image/png";
case 0x47:
return SDImageFormatGIF;
return @"image/gif";
case 0x49:
case 0x4D:
return SDImageFormatTIFF;
case 0x52: {
if (data.length >= 12) {
//RIFF....WEBP
NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {
return SDImageFormatWebP;
}
return @"image/tiff";
case 0x52:
// R as RIFF for WEBP
if ([data length] < 12) {
return nil;
}
break;
}
case 0x00: {
if (data.length >= 12) {
//....ftypheic ....ftypheix ....ftyphevc ....ftyphevx
NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(4, 8)] encoding:NSASCIIStringEncoding];
if ([testString isEqualToString:@"ftypheic"]
|| [testString isEqualToString:@"ftypheix"]
|| [testString isEqualToString:@"ftyphevc"]
|| [testString isEqualToString:@"ftyphevx"]) {
return SDImageFormatHEIC;
}
NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {
return @"image/webp";
}
break;
}
}
return SDImageFormatUndefined;
}
+ (nonnull CFStringRef)sd_UTTypeFromSDImageFormat:(SDImageFormat)format {
CFStringRef UTType;
switch (format) {
case SDImageFormatJPEG:
UTType = kUTTypeJPEG;
break;
case SDImageFormatPNG:
UTType = kUTTypePNG;
break;
case SDImageFormatGIF:
UTType = kUTTypeGIF;
break;
case SDImageFormatTIFF:
UTType = kUTTypeTIFF;
break;
case SDImageFormatWebP:
UTType = kSDUTTypeWebP;
break;
case SDImageFormatHEIC:
UTType = kSDUTTypeHEIC;
break;
default:
// default is kUTTypePNG
UTType = kUTTypePNG;
break;
return nil;
}
return UTType;
return nil;
}
+ (SDImageFormat)sd_imageFormatFromUTType:(CFStringRef)uttype {
if (!uttype) {
return SDImageFormatUndefined;
}
SDImageFormat imageFormat;
if (CFStringCompare(uttype, kUTTypeJPEG, 0) == kCFCompareEqualTo) {
imageFormat = SDImageFormatJPEG;
} else if (CFStringCompare(uttype, kUTTypePNG, 0) == kCFCompareEqualTo) {
imageFormat = SDImageFormatPNG;
} else if (CFStringCompare(uttype, kUTTypeGIF, 0) == kCFCompareEqualTo) {
imageFormat = SDImageFormatGIF;
} else if (CFStringCompare(uttype, kUTTypeTIFF, 0) == kCFCompareEqualTo) {
imageFormat = SDImageFormatTIFF;
} else if (CFStringCompare(uttype, kSDUTTypeWebP, 0) == kCFCompareEqualTo) {
imageFormat = SDImageFormatWebP;
} else if (CFStringCompare(uttype, kSDUTTypeHEIC, 0) == kCFCompareEqualTo) {
imageFormat = SDImageFormatHEIC;
} else {
imageFormat = SDImageFormatUndefined;
}
return imageFormat;
@end
@implementation NSData (ImageContentTypeDeprecated)
+ (NSString *)contentTypeForImageData:(NSData *)data {
return [self sd_contentTypeForImageData:data];
}
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageCompat.h"
#if SD_MAC
#import <Cocoa/Cocoa.h>
@interface NSImage (WebCache)
- (CGImageRef)CGImage;
- (NSArray<NSImage *> *)images;
- (BOOL)isGIF;
@end
#endif
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "NSImage+WebCache.h"
#if SD_MAC
@implementation NSImage (WebCache)
- (CGImageRef)CGImage {
NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height);
CGImageRef cgImage = [self CGImageForProposedRect:&imageRect context:NULL hints:nil];
return cgImage;
}
- (NSArray<NSImage *> *)images {
return nil;
}
- (BOOL)isGIF {
BOOL isGIF = NO;
for (NSImageRep *rep in self.representations) {
if ([rep isKindOfClass:[NSBitmapImageRep class]]) {
NSBitmapImageRep *bitmapRep = (NSBitmapImageRep *)rep;
NSUInteger frameCount = [[bitmapRep valueForProperty:NSImageFrameCount] unsignedIntegerValue];
isGIF = frameCount > 1 ? YES : NO;
break;
}
}
return isGIF;
}
@end
#endif
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageCompat.h"
#if SD_MAC
// A subclass of `NSBitmapImageRep` to fix that GIF loop count issue because `NSBitmapImageRep` will reset `NSImageCurrentFrameDuration` by using `kCGImagePropertyGIFDelayTime` but not `kCGImagePropertyGIFUnclampedDelayTime`.
// Built in GIF coder use this instead of `NSBitmapImageRep` for better GIF rendering. If you do not want this, only enable `SDWebImageImageIOCoder`, which just call `NSImage` API and actually use `NSBitmapImageRep` for GIF image.
@interface SDAnimatedImageRep : NSBitmapImageRep
@end
#endif
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDAnimatedImageRep.h"
#if SD_MAC
#import "SDWebImageGIFCoder.h"
@interface SDWebImageGIFCoder ()
- (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source;
@end
@interface SDAnimatedImageRep ()
@property (nonatomic, assign, readonly, nullable) CGImageSourceRef imageSource;
@end
@implementation SDAnimatedImageRep
// `NSBitmapImageRep` will use `kCGImagePropertyGIFDelayTime` whenever you call `setProperty:withValue:` with `NSImageCurrentFrame` to change the current frame. We override it and use the actual `kCGImagePropertyGIFUnclampedDelayTime` if need.
- (void)setProperty:(NSBitmapImageRepPropertyKey)property withValue:(id)value {
[super setProperty:property withValue:value];
if ([property isEqualToString:NSImageCurrentFrame]) {
// Access the image source
CGImageSourceRef imageSource = self.imageSource;
if (!imageSource) {
return;
}
// Check format type
CFStringRef type = CGImageSourceGetType(imageSource);
if (!type) {
return;
}
NSUInteger index = [value unsignedIntegerValue];
float frameDuration = 0;
// Through we currently process GIF only, in the 5.x we support APNG so we keep the extensibility
if (CFStringCompare(type, kUTTypeGIF, 0) == kCFCompareEqualTo) {
frameDuration = [[SDWebImageGIFCoder sharedCoder] sd_frameDurationAtIndex:index source:imageSource];
}
if (!frameDuration) {
return;
}
// Reset super frame duration with the actual frame duration
[super setProperty:NSImageCurrentFrameDuration withValue:@(frameDuration)];
}
}
- (CGImageSourceRef)imageSource {
if (_tiffData) {
return (__bridge CGImageSourceRef)(_tiffData);
}
return NULL;
}
@end
#endif
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import <Foundation/Foundation.h>
#import "SDWebImageCompat.h"
typedef NS_ENUM(NSUInteger, SDImageCacheConfigExpireType) {
/**
* When the image is accessed it will update this value
*/
SDImageCacheConfigExpireTypeAccessDate,
/**
* The image was obtained from the disk cache (Default)
*/
SDImageCacheConfigExpireTypeModificationDate
};
@interface SDImageCacheConfig : NSObject
/**
* Decompressing images that are downloaded and cached can improve performance but can consume lot of memory.
* Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption.
*/
@property (assign, nonatomic) BOOL shouldDecompressImages;
/**
* Whether or not to disable iCloud backup
* Defaults to YES.
*/
@property (assign, nonatomic) BOOL shouldDisableiCloud;
/**
* Whether or not to use memory cache
* @note When the memory cache is disabled, the weak memory cache will also be disabled.
* Defaults to YES.
*/
@property (assign, nonatomic) BOOL shouldCacheImagesInMemory;
/**
* The option to control weak memory cache for images. When enable, `SDImageCache`'s memory cache will use a weak maptable to store the image at the same time when it stored to memory, and get removed at the same time.
* However when memory warning is triggered, since the weak maptable does not hold a strong reference to image instacnce, even when the memory cache itself is purged, some images which are held strongly by UIImageViews or other live instances can be recovered again, to avoid later re-query from disk cache or network. This may be helpful for the case, for example, when app enter background and memory is purged, cause cell flashing after re-enter foreground.
* Defautls to YES. You can change this option dynamically.
*/
@property (assign, nonatomic) BOOL shouldUseWeakMemoryCache;
/**
* The reading options while reading cache from disk.
* Defaults to 0. You can set this to `NSDataReadingMappedIfSafe` to improve performance.
*/
@property (assign, nonatomic) NSDataReadingOptions diskCacheReadingOptions;
/**
* The writing options while writing cache to disk.
* Defaults to `NSDataWritingAtomic`. You can set this to `NSDataWritingWithoutOverwriting` to prevent overwriting an existing file.
*/
@property (assign, nonatomic) NSDataWritingOptions diskCacheWritingOptions;
/**
* The maximum length of time to keep an image in the cache, in seconds.
*/
@property (assign, nonatomic) NSInteger maxCacheAge;
/**
* The maximum size of the cache, in bytes.
*/
@property (assign, nonatomic) NSUInteger maxCacheSize;
/**
* The attribute which the clear cache will be checked against when clearing the disk cache
* Default is Modified Date
*/
@property (assign, nonatomic) SDImageCacheConfigExpireType diskCacheExpireType;
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDImageCacheConfig.h"
static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
@implementation SDImageCacheConfig
- (instancetype)init {
if (self = [super init]) {
_shouldDecompressImages = YES;
_shouldDisableiCloud = YES;
_shouldCacheImagesInMemory = YES;
_shouldUseWeakMemoryCache = YES;
_diskCacheReadingOptions = 0;
_diskCacheWritingOptions = NSDataWritingAtomic;
_maxCacheAge = kDefaultCacheMaxCacheAge;
_maxCacheSize = 0;
_diskCacheExpireType = SDImageCacheConfigExpireTypeModificationDate;
}
return self;
}
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import <Foundation/Foundation.h>
#import "SDWebImageCompat.h"
#import "NSData+ImageContentType.h"
/**
A Boolean value indicating whether to scale down large images during decompressing. (NSNumber)
*/
FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageCoderScaleDownLargeImagesKey;
/**
Return the shared device-dependent RGB color space created with CGColorSpaceCreateDeviceRGB.
@return The device-dependent RGB color space
*/
CG_EXTERN CGColorSpaceRef _Nonnull SDCGColorSpaceGetDeviceRGB(void);
/**
Check whether CGImageRef contains alpha channel.
@param imageRef The CGImageRef
@return Return YES if CGImageRef contains alpha channel, otherwise return NO
*/
CG_EXTERN BOOL SDCGImageRefContainsAlpha(_Nullable CGImageRef imageRef);
/**
This is the image coder protocol to provide custom image decoding/encoding.
These methods are all required to implement.
@note Pay attention that these methods are not called from main queue.
*/
@protocol SDWebImageCoder <NSObject>
@required
#pragma mark - Decoding
/**
Returns YES if this coder can decode some data. Otherwise, the data should be passed to another coder.
@param data The image data so we can look at it
@return YES if this coder can decode the data, NO otherwise
*/
- (BOOL)canDecodeFromData:(nullable NSData *)data;
/**
Decode the image data to image.
@param data The image data to be decoded
@return The decoded image from data
*/
- (nullable UIImage *)decodedImageWithData:(nullable NSData *)data;
/**
Decompress the image with original image and image data.
@param image The original image to be decompressed
@param data The pointer to original image data. The pointer itself is nonnull but image data can be null. This data will set to cache if needed. If you do not need to modify data at the sametime, ignore this param.
@param optionsDict A dictionary containing any decompressing options. Pass {SDWebImageCoderScaleDownLargeImagesKey: @(YES)} to scale down large images
@return The decompressed image
*/
- (nullable UIImage *)decompressedImageWithImage:(nullable UIImage *)image
data:(NSData * _Nullable * _Nonnull)data
options:(nullable NSDictionary<NSString*, NSObject*>*)optionsDict;
#pragma mark - Encoding
/**
Returns YES if this coder can encode some image. Otherwise, it should be passed to another coder.
@param format The image format
@return YES if this coder can encode the image, NO otherwise
*/
- (BOOL)canEncodeToFormat:(SDImageFormat)format;
/**
Encode the image to image data.
@param image The image to be encoded
@param format The image format to encode, you should note `SDImageFormatUndefined` format is also possible
@return The encoded image data
*/
- (nullable NSData *)encodedDataWithImage:(nullable UIImage *)image format:(SDImageFormat)format;
@end
/**
This is the image coder protocol to provide custom progressive image decoding.
These methods are all required to implement.
@note Pay attention that these methods are not called from main queue.
*/
@protocol SDWebImageProgressiveCoder <SDWebImageCoder>
@required
/**
Returns YES if this coder can incremental decode some data. Otherwise, it should be passed to another coder.
@param data The image data so we can look at it
@return YES if this coder can decode the data, NO otherwise
*/
- (BOOL)canIncrementallyDecodeFromData:(nullable NSData *)data;
/**
Incremental decode the image data to image.
@param data The image data has been downloaded so far
@param finished Whether the download has finished
@warning because incremental decoding need to keep the decoded context, we will alloc a new instance with the same class for each download operation to avoid conflicts
@return The decoded image from data
*/
- (nullable UIImage *)incrementallyDecodedImageWithData:(nullable NSData *)data finished:(BOOL)finished;
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageCoder.h"
NSString * const SDWebImageCoderScaleDownLargeImagesKey = @"scaleDownLargeImages";
CGColorSpaceRef SDCGColorSpaceGetDeviceRGB(void) {
static CGColorSpaceRef colorSpace;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
colorSpace = CGColorSpaceCreateDeviceRGB();
});
return colorSpace;
}
BOOL SDCGImageRefContainsAlpha(CGImageRef imageRef) {
if (!imageRef) {
return NO;
}
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef);
BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone ||
alphaInfo == kCGImageAlphaNoneSkipFirst ||
alphaInfo == kCGImageAlphaNoneSkipLast);
return hasAlpha;
}
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import <Foundation/Foundation.h>
#import "SDWebImageCompat.h"
#import "SDWebImageFrame.h"
@interface SDWebImageCoderHelper : NSObject
/**
Return an animated image with frames array.
For UIKit, this will apply the patch and then create animated UIImage. The patch is because that `+[UIImage animatedImageWithImages:duration:]` just use the average of duration for each image. So it will not work if different frame has different duration. Therefore we repeat the specify frame for specify times to let it work.
For AppKit, NSImage does not support animates other than GIF. This will try to encode the frames to GIF format and then create an animated NSImage for rendering. Attention the animated image may loss some detail if the input frames contain full alpha channel because GIF only supports 1 bit alpha channel. (For 1 pixel, either transparent or not)
@param frames The frames array. If no frames or frames is empty, return nil
@return A animated image for rendering on UIImageView(UIKit) or NSImageView(AppKit)
*/
+ (UIImage * _Nullable)animatedImageWithFrames:(NSArray<SDWebImageFrame *> * _Nullable)frames;
/**
Return frames array from an animated image.
For UIKit, this will unapply the patch for the description above and then create frames array. This will also work for normal animated UIImage.
For AppKit, NSImage does not support animates other than GIF. This will try to decode the GIF imageRep and then create frames array.
@param animatedImage A animated image. If it's not animated, return nil
@return The frames array
*/
+ (NSArray<SDWebImageFrame *> * _Nullable)framesFromAnimatedImage:(UIImage * _Nullable)animatedImage;
#if SD_UIKIT || SD_WATCH
/**
Convert an EXIF image orientation to an iOS one.
@param exifOrientation EXIF orientation
@return iOS orientation
*/
+ (UIImageOrientation)imageOrientationFromEXIFOrientation:(NSInteger)exifOrientation;
/**
Convert an iOS orientation to an EXIF image orientation.
@param imageOrientation iOS orientation
@return EXIF orientation
*/
+ (NSInteger)exifOrientationFromImageOrientation:(UIImageOrientation)imageOrientation;
#endif
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageCoderHelper.h"
#import "SDWebImageFrame.h"
#import "UIImage+MultiFormat.h"
#import "NSImage+WebCache.h"
#import <ImageIO/ImageIO.h>
#import "SDAnimatedImageRep.h"
@implementation SDWebImageCoderHelper
+ (UIImage *)animatedImageWithFrames:(NSArray<SDWebImageFrame *> *)frames {
NSUInteger frameCount = frames.count;
if (frameCount == 0) {
return nil;
}
UIImage *animatedImage;
#if SD_UIKIT || SD_WATCH
NSUInteger durations[frameCount];
for (size_t i = 0; i < frameCount; i++) {
durations[i] = frames[i].duration * 1000;
}
NSUInteger const gcd = gcdArray(frameCount, durations);
__block NSUInteger totalDuration = 0;
NSMutableArray<UIImage *> *animatedImages = [NSMutableArray arrayWithCapacity:frameCount];
[frames enumerateObjectsUsingBlock:^(SDWebImageFrame * _Nonnull frame, NSUInteger idx, BOOL * _Nonnull stop) {
UIImage *image = frame.image;
NSUInteger duration = frame.duration * 1000;
totalDuration += duration;
NSUInteger repeatCount;
if (gcd) {
repeatCount = duration / gcd;
} else {
repeatCount = 1;
}
for (size_t i = 0; i < repeatCount; ++i) {
[animatedImages addObject:image];
}
}];
animatedImage = [UIImage animatedImageWithImages:animatedImages duration:totalDuration / 1000.f];
#else
NSMutableData *imageData = [NSMutableData data];
CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatGIF];
// Create an image destination. GIF does not support EXIF image orientation
CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, frameCount, NULL);
if (!imageDestination) {
// Handle failure.
return nil;
}
for (size_t i = 0; i < frameCount; i++) {
@autoreleasepool {
SDWebImageFrame *frame = frames[i];
float frameDuration = frame.duration;
CGImageRef frameImageRef = frame.image.CGImage;
NSDictionary *frameProperties = @{(__bridge NSString *)kCGImagePropertyGIFDictionary : @{(__bridge NSString *)kCGImagePropertyGIFDelayTime : @(frameDuration)}};
CGImageDestinationAddImage(imageDestination, frameImageRef, (__bridge CFDictionaryRef)frameProperties);
}
}
// Finalize the destination.
if (CGImageDestinationFinalize(imageDestination) == NO) {
// Handle failure.
CFRelease(imageDestination);
return nil;
}
CFRelease(imageDestination);
SDAnimatedImageRep *imageRep = [[SDAnimatedImageRep alloc] initWithData:imageData];
animatedImage = [[NSImage alloc] initWithSize:imageRep.size];
[animatedImage addRepresentation:imageRep];
#endif
return animatedImage;
}
+ (NSArray<SDWebImageFrame *> *)framesFromAnimatedImage:(UIImage *)animatedImage {
if (!animatedImage) {
return nil;
}
NSMutableArray<SDWebImageFrame *> *frames = [NSMutableArray array];
NSUInteger frameCount = 0;
#if SD_UIKIT || SD_WATCH
NSArray<UIImage *> *animatedImages = animatedImage.images;
frameCount = animatedImages.count;
if (frameCount == 0) {
return nil;
}
NSTimeInterval avgDuration = animatedImage.duration / frameCount;
if (avgDuration == 0) {
avgDuration = 0.1; // if it's a animated image but no duration, set it to default 100ms (this do not have that 10ms limit like GIF or WebP to allow custom coder provide the limit)
}
__block NSUInteger index = 0;
__block NSUInteger repeatCount = 1;
__block UIImage *previousImage = animatedImages.firstObject;
[animatedImages enumerateObjectsUsingBlock:^(UIImage * _Nonnull image, NSUInteger idx, BOOL * _Nonnull stop) {
// ignore first
if (idx == 0) {
return;
}
if ([image isEqual:previousImage]) {
repeatCount++;
} else {
SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:previousImage duration:avgDuration * repeatCount];
[frames addObject:frame];
repeatCount = 1;
index++;
}
previousImage = image;
// last one
if (idx == frameCount - 1) {
SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:previousImage duration:avgDuration * repeatCount];
[frames addObject:frame];
}
}];
#else
NSBitmapImageRep *bitmapRep;
for (NSImageRep *imageRep in animatedImage.representations) {
if ([imageRep isKindOfClass:[NSBitmapImageRep class]]) {
bitmapRep = (NSBitmapImageRep *)imageRep;
break;
}
}
if (bitmapRep) {
frameCount = [[bitmapRep valueForProperty:NSImageFrameCount] unsignedIntegerValue];
}
if (frameCount == 0) {
return nil;
}
for (size_t i = 0; i < frameCount; i++) {
@autoreleasepool {
// NSBitmapImageRep need to manually change frame. "Good taste" API
[bitmapRep setProperty:NSImageCurrentFrame withValue:@(i)];
float frameDuration = [[bitmapRep valueForProperty:NSImageCurrentFrameDuration] floatValue];
NSImage *frameImage = [[NSImage alloc] initWithCGImage:bitmapRep.CGImage size:CGSizeZero];
SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:frameImage duration:frameDuration];
[frames addObject:frame];
}
}
#endif
return frames;
}
#if SD_UIKIT || SD_WATCH
// Convert an EXIF image orientation to an iOS one.
+ (UIImageOrientation)imageOrientationFromEXIFOrientation:(NSInteger)exifOrientation {
// CGImagePropertyOrientation is available on iOS 8 above. Currently kept for compatibility
UIImageOrientation imageOrientation = UIImageOrientationUp;
switch (exifOrientation) {
case 1:
imageOrientation = UIImageOrientationUp;
break;
case 3:
imageOrientation = UIImageOrientationDown;
break;
case 8:
imageOrientation = UIImageOrientationLeft;
break;
case 6:
imageOrientation = UIImageOrientationRight;
break;
case 2:
imageOrientation = UIImageOrientationUpMirrored;
break;
case 4:
imageOrientation = UIImageOrientationDownMirrored;
break;
case 5:
imageOrientation = UIImageOrientationLeftMirrored;
break;
case 7:
imageOrientation = UIImageOrientationRightMirrored;
break;
default:
break;
}
return imageOrientation;
}
// Convert an iOS orientation to an EXIF image orientation.
+ (NSInteger)exifOrientationFromImageOrientation:(UIImageOrientation)imageOrientation {
// CGImagePropertyOrientation is available on iOS 8 above. Currently kept for compatibility
NSInteger exifOrientation = 1;
switch (imageOrientation) {
case UIImageOrientationUp:
exifOrientation = 1;
break;
case UIImageOrientationDown:
exifOrientation = 3;
break;
case UIImageOrientationLeft:
exifOrientation = 8;
break;
case UIImageOrientationRight:
exifOrientation = 6;
break;
case UIImageOrientationUpMirrored:
exifOrientation = 2;
break;
case UIImageOrientationDownMirrored:
exifOrientation = 4;
break;
case UIImageOrientationLeftMirrored:
exifOrientation = 5;
break;
case UIImageOrientationRightMirrored:
exifOrientation = 7;
break;
default:
break;
}
return exifOrientation;
}
#endif
#pragma mark - Helper Fuction
#if SD_UIKIT || SD_WATCH
static NSUInteger gcd(NSUInteger a, NSUInteger b) {
NSUInteger c;
while (a != 0) {
c = a;
a = b % a;
b = c;
}
return b;
}
static NSUInteger gcdArray(size_t const count, NSUInteger const * const values) {
if (count == 0) {
return 0;
}
NSUInteger result = values[0];
for (size_t i = 1; i < count; ++i) {
result = gcd(values[i], result);
}
return result;
}
#endif
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import <Foundation/Foundation.h>
#import "SDWebImageCoder.h"
/**
Global object holding the array of coders, so that we avoid passing them from object to object.
Uses a priority queue behind scenes, which means the latest added coders have the highest priority.
This is done so when encoding/decoding something, we go through the list and ask each coder if they can handle the current data.
That way, users can add their custom coders while preserving our existing prebuilt ones
Note: the `coders` getter will return the coders in their reversed order
Example:
- by default we internally set coders = `IOCoder`, `WebPCoder`. (`GIFCoder` is not recommended to add only if you want to get GIF support without `FLAnimatedImage`)
- calling `coders` will return `@[WebPCoder, IOCoder]`
- call `[addCoder:[MyCrazyCoder new]]`
- calling `coders` now returns `@[MyCrazyCoder, WebPCoder, IOCoder]`
Coders
------
A coder must conform to the `SDWebImageCoder` protocol or even to `SDWebImageProgressiveCoder` if it supports progressive decoding
Conformance is important because that way, they will implement `canDecodeFromData` or `canEncodeToFormat`
Those methods are called on each coder in the array (using the priority order) until one of them returns YES.
That means that coder can decode that data / encode to that format
*/
@interface SDWebImageCodersManager : NSObject<SDWebImageCoder>
/**
Shared reusable instance
*/
+ (nonnull instancetype)sharedInstance;
/**
All coders in coders manager. The coders array is a priority queue, which means the later added coder will have the highest priority
*/
@property (nonatomic, copy, readwrite, nullable) NSArray<id<SDWebImageCoder>> *coders;
/**
Add a new coder to the end of coders array. Which has the highest priority.
@param coder coder
*/
- (void)addCoder:(nonnull id<SDWebImageCoder>)coder;
/**
Remove a coder in the coders array.
@param coder coder
*/
- (void)removeCoder:(nonnull id<SDWebImageCoder>)coder;
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageCodersManager.h"
#import "SDWebImageImageIOCoder.h"
#import "SDWebImageGIFCoder.h"
#ifdef SD_WEBP
#import "SDWebImageWebPCoder.h"
#endif
#import "UIImage+MultiFormat.h"
#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
#define UNLOCK(lock) dispatch_semaphore_signal(lock);
@interface SDWebImageCodersManager ()
@property (nonatomic, strong, nonnull) dispatch_semaphore_t codersLock;
@end
@implementation SDWebImageCodersManager
+ (nonnull instancetype)sharedInstance {
static dispatch_once_t once;
static id instance;
dispatch_once(&once, ^{
instance = [self new];
});
return instance;
}
- (instancetype)init {
if (self = [super init]) {
// initialize with default coders
NSMutableArray<id<SDWebImageCoder>> *mutableCoders = [@[[SDWebImageImageIOCoder sharedCoder]] mutableCopy];
#ifdef SD_WEBP
[mutableCoders addObject:[SDWebImageWebPCoder sharedCoder]];
#endif
_coders = [mutableCoders copy];
_codersLock = dispatch_semaphore_create(1);
}
return self;
}
#pragma mark - Coder IO operations
- (void)addCoder:(nonnull id<SDWebImageCoder>)coder {
if (![coder conformsToProtocol:@protocol(SDWebImageCoder)]) {
return;
}
LOCK(self.codersLock);
NSMutableArray<id<SDWebImageCoder>> *mutableCoders = [self.coders mutableCopy];
if (!mutableCoders) {
mutableCoders = [NSMutableArray array];
}
[mutableCoders addObject:coder];
self.coders = [mutableCoders copy];
UNLOCK(self.codersLock);
}
- (void)removeCoder:(nonnull id<SDWebImageCoder>)coder {
if (![coder conformsToProtocol:@protocol(SDWebImageCoder)]) {
return;
}
LOCK(self.codersLock);
NSMutableArray<id<SDWebImageCoder>> *mutableCoders = [self.coders mutableCopy];
[mutableCoders removeObject:coder];
self.coders = [mutableCoders copy];
UNLOCK(self.codersLock);
}
#pragma mark - SDWebImageCoder
- (BOOL)canDecodeFromData:(NSData *)data {
LOCK(self.codersLock);
NSArray<id<SDWebImageCoder>> *coders = self.coders;
UNLOCK(self.codersLock);
for (id<SDWebImageCoder> coder in coders.reverseObjectEnumerator) {
if ([coder canDecodeFromData:data]) {
return YES;
}
}
return NO;
}
- (BOOL)canEncodeToFormat:(SDImageFormat)format {
LOCK(self.codersLock);
NSArray<id<SDWebImageCoder>> *coders = self.coders;
UNLOCK(self.codersLock);
for (id<SDWebImageCoder> coder in coders.reverseObjectEnumerator) {
if ([coder canEncodeToFormat:format]) {
return YES;
}
}
return NO;
}
- (UIImage *)decodedImageWithData:(NSData *)data {
LOCK(self.codersLock);
NSArray<id<SDWebImageCoder>> *coders = self.coders;
UNLOCK(self.codersLock);
for (id<SDWebImageCoder> coder in coders.reverseObjectEnumerator) {
if ([coder canDecodeFromData:data]) {
return [coder decodedImageWithData:data];
}
}
return nil;
}
- (UIImage *)decompressedImageWithImage:(UIImage *)image
data:(NSData *__autoreleasing _Nullable *)data
options:(nullable NSDictionary<NSString*, NSObject*>*)optionsDict {
if (!image) {
return nil;
}
LOCK(self.codersLock);
NSArray<id<SDWebImageCoder>> *coders = self.coders;
UNLOCK(self.codersLock);
for (id<SDWebImageCoder> coder in coders.reverseObjectEnumerator) {
if ([coder canDecodeFromData:*data]) {
UIImage *decompressedImage = [coder decompressedImageWithImage:image data:data options:optionsDict];
decompressedImage.sd_imageFormat = image.sd_imageFormat;
return decompressedImage;
}
}
return nil;
}
- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format {
if (!image) {
return nil;
}
LOCK(self.codersLock);
NSArray<id<SDWebImageCoder>> *coders = self.coders;
UNLOCK(self.codersLock);
for (id<SDWebImageCoder> coder in coders.reverseObjectEnumerator) {
if ([coder canEncodeToFormat:format]) {
return [coder encodedDataWithImage:image format:format];
}
}
return nil;
}
@end
......@@ -10,73 +10,25 @@
#import <TargetConditionals.h>
#ifdef __OBJC_GC__
#error SDWebImage does not support Objective-C Garbage Collection
#error SDWebImage does not support Objective-C Garbage Collection
#endif
// Apple's defines from TargetConditionals.h are a bit weird.
// Seems like TARGET_OS_MAC is always defined (on all platforms).
// To determine if we are running on OSX, we can only rely on TARGET_OS_IPHONE=0 and all the other platforms
#if !TARGET_OS_IPHONE && !TARGET_OS_IOS && !TARGET_OS_TV && !TARGET_OS_WATCH
#define SD_MAC 1
#else
#define SD_MAC 0
#if __IPHONE_OS_VERSION_MIN_REQUIRED != 20000 && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0
#error SDWebImage doesn't support Deployment Target version < 5.0
#endif
// iOS and tvOS are very similar, UIKit exists on both platforms
// Note: watchOS also has UIKit, but it's very limited
#if TARGET_OS_IOS || TARGET_OS_TV
#define SD_UIKIT 1
#else
#define SD_UIKIT 0
#endif
#if TARGET_OS_IOS
#define SD_IOS 1
#else
#define SD_IOS 0
#if !TARGET_OS_IPHONE
#import <AppKit/AppKit.h>
#ifndef UIImage
#define UIImage NSImage
#endif
#if TARGET_OS_TV
#define SD_TV 1
#else
#define SD_TV 0
#ifndef UIImageView
#define UIImageView NSImageView
#endif
#if TARGET_OS_WATCH
#define SD_WATCH 1
#else
#define SD_WATCH 0
#endif
#import <UIKit/UIKit.h>
#if SD_MAC
#import <AppKit/AppKit.h>
#ifndef UIImage
#define UIImage NSImage
#endif
#ifndef UIImageView
#define UIImageView NSImageView
#endif
#ifndef UIView
#define UIView NSView
#endif
#else
#if __IPHONE_OS_VERSION_MIN_REQUIRED != 20000 && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0
#error SDWebImage doesn't support Deployment Target version < 5.0
#endif
#if SD_UIKIT
#import <UIKit/UIKit.h>
#endif
#if SD_WATCH
#import <WatchKit/WatchKit.h>
#ifndef UIView
#define UIView WKInterfaceObject
#endif
#ifndef UIImageView
#define UIImageView WKInterfaceImage
#endif
#endif
#endif
#ifndef NS_ENUM
......@@ -87,21 +39,34 @@
#define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type
#endif
FOUNDATION_EXPORT UIImage *SDScaledImageForKey(NSString *key, UIImage *image);
#if OS_OBJECT_USE_OBJC
#undef SDDispatchQueueRelease
#undef SDDispatchQueueSetterSementics
#define SDDispatchQueueRelease(q)
#define SDDispatchQueueSetterSementics strong
#else
#undef SDDispatchQueueRelease
#undef SDDispatchQueueSetterSementics
#define SDDispatchQueueRelease(q) (dispatch_release(q))
#define SDDispatchQueueSetterSementics assign
#endif
typedef void(^SDWebImageNoParamsBlock)(void);
extern UIImage *SDScaledImageForKey(NSString *key, UIImage *image);
FOUNDATION_EXPORT NSString *const SDWebImageErrorDomain;
typedef void(^SDWebImageNoParamsBlock)();
#ifndef dispatch_queue_async_safe
#define dispatch_queue_async_safe(queue, block)\
if (dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) == dispatch_queue_get_label(queue)) {\
extern NSString *const SDWebImageErrorDomain;
#define dispatch_main_sync_safe(block)\
if ([NSThread isMainThread]) {\
block();\
} else {\
dispatch_async(queue, block);\
dispatch_sync(dispatch_get_main_queue(), block);\
}
#endif
#ifndef dispatch_main_async_safe
#define dispatch_main_async_safe(block) dispatch_queue_async_safe(dispatch_get_main_queue(), block)
#endif
#define dispatch_main_async_safe(block)\
if ([NSThread isMainThread]) {\
block();\
} else {\
dispatch_async(dispatch_get_main_queue(), block);\
}
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
//
// SDWebImageCompat.m
// SDWebImage
//
// Created by Olivier Poitrey on 11/12/12.
// Copyright (c) 2012 Dailymotion. All rights reserved.
//
#import "SDWebImageCompat.h"
#import "UIImage+MultiFormat.h"
#if !__has_feature(objc_arc)
#error SDWebImage is ARC only. Either turn on ARC for the project or use -fobjc-arc flag
#error SDWebImage is ARC only. Either turn on ARC for the project or use -fobjc-arc flag
#endif
#if !OS_OBJECT_USE_OBJC
#error SDWebImage need ARC for dispatch object
#endif
inline UIImage *SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image) {
inline UIImage *SDScaledImageForKey(NSString *key, UIImage *image) {
if (!image) {
return nil;
}
#if SD_MAC
return image;
#elif SD_UIKIT || SD_WATCH
if ((image.images).count > 0) {
NSMutableArray<UIImage *> *scaledImages = [NSMutableArray array];
if ([image.images count] > 0) {
NSMutableArray *scaledImages = [NSMutableArray array];
for (UIImage *tempImage in image.images) {
[scaledImages addObject:SDScaledImageForKey(key, tempImage)];
}
UIImage *animatedImage = [UIImage animatedImageWithImages:scaledImages duration:image.duration];
if (animatedImage) {
animatedImage.sd_imageLoopCount = image.sd_imageLoopCount;
animatedImage.sd_imageFormat = image.sd_imageFormat;
}
return animatedImage;
} else {
#if SD_WATCH
if ([[WKInterfaceDevice currentDevice] respondsToSelector:@selector(screenScale)]) {
#elif SD_UIKIT
return [UIImage animatedImageWithImages:scaledImages duration:image.duration];
}
else {
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
#endif
CGFloat scale = 1;
if (key.length >= 8) {
NSRange range = [key rangeOfString:@"@2x."];
......@@ -58,12 +42,10 @@ inline UIImage *SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullabl
}
UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation];
scaledImage.sd_imageFormat = image.sd_imageFormat;
image = scaledImage;
}
return image;
}
#endif
}
NSString *const SDWebImageErrorDomain = @"SDWebImageErrorDomain";
......@@ -2,16 +2,17 @@
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* Created by james <https://github.com/mystcolor> on 9/28/11.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import <Foundation/Foundation.h>
#import "SDWebImageCompat.h"
@interface UIImage (ForceDecode)
+ (nullable UIImage *)decodedImageWithImage:(nullable UIImage *)image;
+ (nullable UIImage *)decodedAndScaledDownImageWithImage:(nullable UIImage *)image;
+ (UIImage *)decodedImageWithImage:(UIImage *)image;
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* Created by james <https://github.com/mystcolor> on 9/28/11.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageDecoder.h"
@implementation UIImage (ForceDecode)
+ (UIImage *)decodedImageWithImage:(UIImage *)image {
// while downloading huge amount of images
// autorelease the bitmap context
// and all vars to help system to free memory
// when there are memory warning.
// on iOS7, do not forget to call
// [[SDImageCache sharedImageCache] clearMemory];
if (image == nil) { // Prevent "CGBitmapContextCreateImage: invalid context 0x0" error
return nil;
}
@autoreleasepool{
// do not decode animated images
if (image.images != nil) {
return image;
}
CGImageRef imageRef = image.CGImage;
CGImageAlphaInfo alpha = CGImageGetAlphaInfo(imageRef);
BOOL anyAlpha = (alpha == kCGImageAlphaFirst ||
alpha == kCGImageAlphaLast ||
alpha == kCGImageAlphaPremultipliedFirst ||
alpha == kCGImageAlphaPremultipliedLast);
if (anyAlpha) {
return image;
}
// current
CGColorSpaceModel imageColorSpaceModel = CGColorSpaceGetModel(CGImageGetColorSpace(imageRef));
CGColorSpaceRef colorspaceRef = CGImageGetColorSpace(imageRef);
BOOL unsupportedColorSpace = (imageColorSpaceModel == kCGColorSpaceModelUnknown ||
imageColorSpaceModel == kCGColorSpaceModelMonochrome ||
imageColorSpaceModel == kCGColorSpaceModelCMYK ||
imageColorSpaceModel == kCGColorSpaceModelIndexed);
if (unsupportedColorSpace) {
colorspaceRef = CGColorSpaceCreateDeviceRGB();
}
size_t width = CGImageGetWidth(imageRef);
size_t height = CGImageGetHeight(imageRef);
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
// kCGImageAlphaNone is not supported in CGBitmapContextCreate.
// Since the original image here has no alpha info, use kCGImageAlphaNoneSkipLast
// to create bitmap graphics contexts without alpha info.
CGContextRef context = CGBitmapContextCreate(NULL,
width,
height,
bitsPerComponent,
bytesPerRow,
colorspaceRef,
kCGBitmapByteOrderDefault|kCGImageAlphaNoneSkipLast);
// Draw the image into the context and retrieve the new bitmap image without alpha
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGImageRef imageRefWithoutAlpha = CGBitmapContextCreateImage(context);
UIImage *imageWithoutAlpha = [UIImage imageWithCGImage:imageRefWithoutAlpha
scale:image.scale
orientation:image.imageOrientation];
if (unsupportedColorSpace) {
CGColorSpaceRelease(colorspaceRef);
}
CGContextRelease(context);
CGImageRelease(imageRefWithoutAlpha);
return imageWithoutAlpha;
}
}
@end
......@@ -10,48 +10,22 @@
#import "SDWebImageDownloader.h"
#import "SDWebImageOperation.h"
FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStartNotification;
FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadReceiveResponseNotification;
FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStopNotification;
FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification;
extern NSString *const SDWebImageDownloadStartNotification;
extern NSString *const SDWebImageDownloadReceiveResponseNotification;
extern NSString *const SDWebImageDownloadStopNotification;
extern NSString *const SDWebImageDownloadFinishNotification;
/**
Describes a downloader operation. If one wants to use a custom downloader op, it needs to inherit from `NSOperation` and conform to this protocol
For the description about these methods, see `SDWebImageDownloaderOperation`
*/
@protocol SDWebImageDownloaderOperationInterface<NSObject>
- (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request
inSession:(nullable NSURLSession *)session
options:(SDWebImageDownloaderOptions)options;
- (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock;
- (BOOL)shouldDecompressImages;
- (void)setShouldDecompressImages:(BOOL)value;
- (nullable NSURLCredential *)credential;
- (void)setCredential:(nullable NSURLCredential *)value;
- (BOOL)cancel:(nullable id)token;
@end
@interface SDWebImageDownloaderOperation : NSOperation <SDWebImageDownloaderOperationInterface, SDWebImageOperation, NSURLSessionTaskDelegate, NSURLSessionDataDelegate>
@interface SDWebImageDownloaderOperation : NSOperation <SDWebImageOperation, NSURLSessionTaskDelegate, NSURLSessionDataDelegate>
/**
* The request used by the operation's task.
*/
@property (strong, nonatomic, readonly, nullable) NSURLRequest *request;
@property (strong, nonatomic, readonly) NSURLRequest *request;
/**
* The operation's task
*/
@property (strong, nonatomic, readonly, nullable) NSURLSessionTask *dataTask;
@property (strong, nonatomic, readonly) NSURLSessionTask *dataTask;
@property (assign, nonatomic) BOOL shouldDecompressImages;
......@@ -63,11 +37,11 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification
@property (nonatomic, assign) BOOL shouldUseCredentialStorage __deprecated_msg("Property deprecated. Does nothing. Kept only for backwards compatibility");
/**
* The credential used for authentication challenges in `-URLSession:task:didReceiveChallenge:completionHandler:`.
* The credential used for authentication challenges in `-connection:didReceiveAuthenticationChallenge:`.
*
* This will be overridden by any shared credentials that exist for the username or password of the request URL, if present.
*/
@property (nonatomic, strong, nullable) NSURLCredential *credential;
@property (nonatomic, strong) NSURLCredential *credential;
/**
* The SDWebImageDownloaderOptions for the receiver.
......@@ -80,9 +54,9 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification
@property (assign, nonatomic) NSInteger expectedSize;
/**
* The response returned by the operation's task.
* The response returned by the operation's connection.
*/
@property (strong, nonatomic, nullable) NSURLResponse *response;
@property (strong, nonatomic) NSURLResponse *response;
/**
* Initializes a `SDWebImageDownloaderOperation` object
......@@ -92,34 +66,41 @@ FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification
* @param request the URL request
* @param session the URL session in which this operation will run
* @param options downloader options
* @param progressBlock the block executed when a new chunk of data arrives.
* @note the progress block is executed on a background queue
* @param completedBlock the block executed when the download is done.
* @note the completed block is executed on the main queue for success. If errors are found, there is a chance the block will be executed on a background queue
* @param cancelBlock the block executed if the download (operation) is cancelled
*
* @return the initialized instance
*/
- (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request
inSession:(nullable NSURLSession *)session
options:(SDWebImageDownloaderOptions)options NS_DESIGNATED_INITIALIZER;
- (id)initWithRequest:(NSURLRequest *)request
inSession:(NSURLSession *)session
options:(SDWebImageDownloaderOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageDownloaderCompletedBlock)completedBlock
cancelled:(SDWebImageNoParamsBlock)cancelBlock;
/**
* Adds handlers for progress and completion. Returns a tokent that can be passed to -cancel: to cancel this set of
* callbacks.
* Initializes a `SDWebImageDownloaderOperation` object
*
* @see SDWebImageDownloaderOperation
*
* @param request the URL request
* @param options downloader options
* @param progressBlock the block executed when a new chunk of data arrives.
* @note the progress block is executed on a background queue
* @param completedBlock the block executed when the download is done.
* @note the completed block is executed on the main queue for success. If errors are found, there is a chance the block will be executed on a background queue
* @param cancelBlock the block executed if the download (operation) is cancelled
*
* @return the token to use to cancel this set of handlers
*/
- (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock;
/**
* Cancels a set of callbacks. Once all callbacks are canceled, the operation is cancelled.
*
* @param token the token representing a set of callbacks to cancel
*
* @return YES if the operation was stopped because this was the last token to be canceled. NO otherwise.
* @return the initialized instance. The operation will run in a separate session created for this operation
*/
- (BOOL)cancel:(nullable id)token;
- (id)initWithRequest:(NSURLRequest *)request
options:(SDWebImageDownloaderOptions)options
progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageDownloaderCompletedBlock)completedBlock
cancelled:(SDWebImageNoParamsBlock)cancelBlock
__deprecated_msg("Method deprecated. Use `initWithRequest:inSession:options:progress:completed:cancelled`");
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import <Foundation/Foundation.h>
#import "SDWebImageCompat.h"
@interface SDWebImageFrame : NSObject
// This class is used for creating animated images via `animatedImageWithFrames` in `SDWebImageCoderHelper`. Attention if you need to specify animated images loop count, use `sd_imageLoopCount` property in `UIImage+MultiFormat`.
/**
The image of current frame. You should not set an animated image.
*/
@property (nonatomic, strong, readonly, nonnull) UIImage *image;
/**
The duration of current frame to be displayed. The number is seconds but not milliseconds. You should not set this to zero.
*/
@property (nonatomic, readonly, assign) NSTimeInterval duration;
/**
Create a frame instance with specify image and duration
@param image current frame's image
@param duration current frame's duration
@return frame instance
*/
+ (instancetype _Nonnull)frameWithImage:(UIImage * _Nonnull)image duration:(NSTimeInterval)duration;
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageFrame.h"
@interface SDWebImageFrame ()
@property (nonatomic, strong, readwrite, nonnull) UIImage *image;
@property (nonatomic, readwrite, assign) NSTimeInterval duration;
@end
@implementation SDWebImageFrame
+ (instancetype)frameWithImage:(UIImage *)image duration:(NSTimeInterval)duration {
SDWebImageFrame *frame = [[SDWebImageFrame alloc] init];
frame.image = image;
frame.duration = duration;
return frame;
}
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import <Foundation/Foundation.h>
#import "SDWebImageCoder.h"
/**
Built in coder using ImageIO that supports GIF encoding/decoding
@note `SDWebImageIOCoder` supports GIF but only as static (will use the 1st frame).
@note Use `SDWebImageGIFCoder` for fully animated GIFs - less performant than `FLAnimatedImage`
@note If you decide to make all `UIImageView`(including `FLAnimatedImageView`) instance support GIF. You should add this coder to `SDWebImageCodersManager` and make sure that it has a higher priority than `SDWebImageIOCoder`
@note The recommended approach for animated GIFs is using `FLAnimatedImage`. It's more performant than `UIImageView` for GIF displaying
*/
@interface SDWebImageGIFCoder : NSObject <SDWebImageCoder>
+ (nonnull instancetype)sharedCoder;
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageGIFCoder.h"
#import "NSImage+WebCache.h"
#import <ImageIO/ImageIO.h>
#import "NSData+ImageContentType.h"
#import "UIImage+MultiFormat.h"
#import "SDWebImageCoderHelper.h"
#import "SDAnimatedImageRep.h"
@implementation SDWebImageGIFCoder
+ (instancetype)sharedCoder {
static SDWebImageGIFCoder *coder;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
coder = [[SDWebImageGIFCoder alloc] init];
});
return coder;
}
#pragma mark - Decode
- (BOOL)canDecodeFromData:(nullable NSData *)data {
return ([NSData sd_imageFormatForImageData:data] == SDImageFormatGIF);
}
- (UIImage *)decodedImageWithData:(NSData *)data {
if (!data) {
return nil;
}
#if SD_MAC
SDAnimatedImageRep *imageRep = [[SDAnimatedImageRep alloc] initWithData:data];
NSImage *animatedImage = [[NSImage alloc] initWithSize:imageRep.size];
[animatedImage addRepresentation:imageRep];
return animatedImage;
#else
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
if (!source) {
return nil;
}
size_t count = CGImageSourceGetCount(source);
UIImage *animatedImage;
if (count <= 1) {
animatedImage = [[UIImage alloc] initWithData:data];
} else {
NSMutableArray<SDWebImageFrame *> *frames = [NSMutableArray array];
for (size_t i = 0; i < count; i++) {
CGImageRef imageRef = CGImageSourceCreateImageAtIndex(source, i, NULL);
if (!imageRef) {
continue;
}
float duration = [self sd_frameDurationAtIndex:i source:source];
UIImage *image = [[UIImage alloc] initWithCGImage:imageRef];
CGImageRelease(imageRef);
SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:image duration:duration];
[frames addObject:frame];
}
NSUInteger loopCount = 1;
NSDictionary *imageProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(source, nil);
NSDictionary *gifProperties = [imageProperties valueForKey:(__bridge NSString *)kCGImagePropertyGIFDictionary];
if (gifProperties) {
NSNumber *gifLoopCount = [gifProperties valueForKey:(__bridge NSString *)kCGImagePropertyGIFLoopCount];
if (gifLoopCount != nil) {
loopCount = gifLoopCount.unsignedIntegerValue;
}
}
animatedImage = [SDWebImageCoderHelper animatedImageWithFrames:frames];
animatedImage.sd_imageLoopCount = loopCount;
animatedImage.sd_imageFormat = SDImageFormatGIF;
}
CFRelease(source);
return animatedImage;
#endif
}
- (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source {
float frameDuration = 0.1f;
CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
if (!cfFrameProperties) {
return frameDuration;
}
NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
if (delayTimeUnclampedProp != nil) {
frameDuration = [delayTimeUnclampedProp floatValue];
} else {
NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
if (delayTimeProp != nil) {
frameDuration = [delayTimeProp floatValue];
}
}
// Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
// We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
// a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
// for more information.
if (frameDuration < 0.011f) {
frameDuration = 0.100f;
}
CFRelease(cfFrameProperties);
return frameDuration;
}
- (UIImage *)decompressedImageWithImage:(UIImage *)image
data:(NSData *__autoreleasing _Nullable *)data
options:(nullable NSDictionary<NSString*, NSObject*>*)optionsDict {
// GIF do not decompress
return image;
}
#pragma mark - Encode
- (BOOL)canEncodeToFormat:(SDImageFormat)format {
return (format == SDImageFormatGIF);
}
- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format {
if (!image) {
return nil;
}
if (format != SDImageFormatGIF) {
return nil;
}
NSMutableData *imageData = [NSMutableData data];
CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatGIF];
NSArray<SDWebImageFrame *> *frames = [SDWebImageCoderHelper framesFromAnimatedImage:image];
// Create an image destination. GIF does not support EXIF image orientation
CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, frames.count, NULL);
if (!imageDestination) {
// Handle failure.
return nil;
}
if (frames.count == 0) {
// for static single GIF images
CGImageDestinationAddImage(imageDestination, image.CGImage, nil);
} else {
// for animated GIF images
NSUInteger loopCount = image.sd_imageLoopCount;
NSDictionary *gifProperties = @{(__bridge NSString *)kCGImagePropertyGIFDictionary: @{(__bridge NSString *)kCGImagePropertyGIFLoopCount : @(loopCount)}};
CGImageDestinationSetProperties(imageDestination, (__bridge CFDictionaryRef)gifProperties);
for (size_t i = 0; i < frames.count; i++) {
SDWebImageFrame *frame = frames[i];
float frameDuration = frame.duration;
CGImageRef frameImageRef = frame.image.CGImage;
NSDictionary *frameProperties = @{(__bridge NSString *)kCGImagePropertyGIFDictionary : @{(__bridge NSString *)kCGImagePropertyGIFDelayTime : @(frameDuration)}};
CGImageDestinationAddImage(imageDestination, frameImageRef, (__bridge CFDictionaryRef)frameProperties);
}
}
// Finalize the destination.
if (CGImageDestinationFinalize(imageDestination) == NO) {
// Handle failure.
imageData = nil;
}
CFRelease(imageDestination);
return [imageData copy];
}
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import <Foundation/Foundation.h>
#import "SDWebImageCoder.h"
/**
Built in coder that supports PNG, JPEG, TIFF, includes support for progressive decoding.
GIF
Also supports static GIF (meaning will only handle the 1st frame).
For a full GIF support, we recommend `FLAnimatedImage` or our less performant `SDWebImageGIFCoder`
HEIC
This coder also supports HEIC format because ImageIO supports it natively. But it depends on the system capabilities, so it won't work on all devices, see: https://devstreaming-cdn.apple.com/videos/wwdc/2017/511tj33587vdhds/511/511_working_with_heif_and_hevc.pdf
Decode(Software): !Simulator && (iOS 11 || tvOS 11 || macOS 10.13)
Decode(Hardware): !Simulator && ((iOS 11 && A9Chip) || (macOS 10.13 && 6thGenerationIntelCPU))
Encode(Software): macOS 10.13
Encode(Hardware): !Simulator && ((iOS 11 && A10FusionChip) || (macOS 10.13 && 6thGenerationIntelCPU))
*/
@interface SDWebImageImageIOCoder : NSObject <SDWebImageProgressiveCoder>
+ (nonnull instancetype)sharedCoder;
@end
......@@ -23,7 +23,7 @@
* @param finishedCount The total number of images that were prefetched (successful or not)
* @param totalCount The total number of images that were to be prefetched
*/
- (void)imagePrefetcher:(nonnull SDWebImagePrefetcher *)imagePrefetcher didPrefetchURL:(nullable NSURL *)imageURL finishedCount:(NSUInteger)finishedCount totalCount:(NSUInteger)totalCount;
- (void)imagePrefetcher:(SDWebImagePrefetcher *)imagePrefetcher didPrefetchURL:(NSURL *)imageURL finishedCount:(NSUInteger)finishedCount totalCount:(NSUInteger)totalCount;
/**
* Called when all images are prefetched.
......@@ -31,7 +31,7 @@
* @param totalCount The total number of images that were prefetched (whether successful or not)
* @param skippedCount The total number of images that were skipped
*/
- (void)imagePrefetcher:(nonnull SDWebImagePrefetcher *)imagePrefetcher didFinishWithTotalCount:(NSUInteger)totalCount skippedCount:(NSUInteger)skippedCount;
- (void)imagePrefetcher:(SDWebImagePrefetcher *)imagePrefetcher didFinishWithTotalCount:(NSUInteger)totalCount skippedCount:(NSUInteger)skippedCount;
@end
......@@ -46,7 +46,7 @@ typedef void(^SDWebImagePrefetcherCompletionBlock)(NSUInteger noOfFinishedUrls,
/**
* The web image manager
*/
@property (strong, nonatomic, readonly, nonnull) SDWebImageManager *manager;
@property (strong, nonatomic, readonly) SDWebImageManager *manager;
/**
* Maximum number of URLs to prefetch at the same time. Defaults to 3.
......@@ -61,35 +61,33 @@ typedef void(^SDWebImagePrefetcherCompletionBlock)(NSUInteger noOfFinishedUrls,
/**
* Queue options for Prefetcher. Defaults to Main Queue.
*/
@property (strong, nonatomic, nonnull) dispatch_queue_t prefetcherQueue;
@property (nonatomic, assign) dispatch_queue_t prefetcherQueue;
@property (weak, nonatomic, nullable) id <SDWebImagePrefetcherDelegate> delegate;
@property (weak, nonatomic) id <SDWebImagePrefetcherDelegate> delegate;
/**
* Return the global image prefetcher instance.
*/
+ (nonnull instancetype)sharedImagePrefetcher;
+ (SDWebImagePrefetcher *)sharedImagePrefetcher;
/**
* Allows you to instantiate a prefetcher with any arbitrary image manager.
*/
- (nonnull instancetype)initWithImageManager:(nonnull SDWebImageManager *)manager NS_DESIGNATED_INITIALIZER;
- (id)initWithImageManager:(SDWebImageManager *)manager;
/**
* Assign list of URLs to let SDWebImagePrefetcher to queue the prefetching,
* currently one image is downloaded at a time,
* and skips images for failed downloads and proceed to the next image in the list.
* Any previously-running prefetch operations are canceled.
* and skips images for failed downloads and proceed to the next image in the list
*
* @param urls list of URLs to prefetch
*/
- (void)prefetchURLs:(nullable NSArray<NSURL *> *)urls;
- (void)prefetchURLs:(NSArray *)urls;
/**
* Assign list of URLs to let SDWebImagePrefetcher to queue the prefetching,
* currently one image is downloaded at a time,
* and skips images for failed downloads and proceed to the next image in the list.
* Any previously-running prefetch operations are canceled.
* and skips images for failed downloads and proceed to the next image in the list
*
* @param urls list of URLs to prefetch
* @param progressBlock block to be called when progress updates;
......@@ -99,9 +97,7 @@ typedef void(^SDWebImagePrefetcherCompletionBlock)(NSUInteger noOfFinishedUrls,
* first param is the number of completed (successful or not) requests,
* second parameter is the number of skipped requests
*/
- (void)prefetchURLs:(nullable NSArray<NSURL *> *)urls
progress:(nullable SDWebImagePrefetcherProgressBlock)progressBlock
completed:(nullable SDWebImagePrefetcherCompletionBlock)completionBlock;
- (void)prefetchURLs:(NSArray *)urls progress:(SDWebImagePrefetcherProgressBlock)progressBlock completed:(SDWebImagePrefetcherCompletionBlock)completionBlock;
/**
* Remove and cancel queued list
......
......@@ -10,20 +10,20 @@
@interface SDWebImagePrefetcher ()
@property (strong, nonatomic, nonnull) SDWebImageManager *manager;
@property (strong, atomic, nullable) NSArray<NSURL *> *prefetchURLs; // may be accessed from different queue
@property (strong, nonatomic) SDWebImageManager *manager;
@property (strong, nonatomic) NSArray *prefetchURLs;
@property (assign, nonatomic) NSUInteger requestedCount;
@property (assign, nonatomic) NSUInteger skippedCount;
@property (assign, nonatomic) NSUInteger finishedCount;
@property (assign, nonatomic) NSTimeInterval startedTime;
@property (copy, nonatomic, nullable) SDWebImagePrefetcherCompletionBlock completionBlock;
@property (copy, nonatomic, nullable) SDWebImagePrefetcherProgressBlock progressBlock;
@property (copy, nonatomic) SDWebImagePrefetcherCompletionBlock completionBlock;
@property (copy, nonatomic) SDWebImagePrefetcherProgressBlock progressBlock;
@end
@implementation SDWebImagePrefetcher
+ (nonnull instancetype)sharedImagePrefetcher {
+ (SDWebImagePrefetcher *)sharedImagePrefetcher {
static dispatch_once_t once;
static id instance;
dispatch_once(&once, ^{
......@@ -32,11 +32,11 @@
return instance;
}
- (nonnull instancetype)init {
- (id)init {
return [self initWithImageManager:[SDWebImageManager new]];
}
- (nonnull instancetype)initWithImageManager:(SDWebImageManager *)manager {
- (id)initWithImageManager:(SDWebImageManager *)manager {
if ((self = [super init])) {
_manager = manager;
_options = SDWebImageLowPriority;
......@@ -55,33 +55,33 @@
}
- (void)startPrefetchingAtIndex:(NSUInteger)index {
NSURL *currentURL;
@synchronized(self) {
if (index >= self.prefetchURLs.count) return;
currentURL = self.prefetchURLs[index];
self.requestedCount++;
}
[self.manager loadImageWithURL:currentURL options:self.options progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (index >= self.prefetchURLs.count) return;
self.requestedCount++;
[self.manager downloadImageWithURL:self.prefetchURLs[index] options:self.options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (!finished) return;
self.finishedCount++;
if (self.progressBlock) {
self.progressBlock(self.finishedCount,(self.prefetchURLs).count);
if (image) {
if (self.progressBlock) {
self.progressBlock(self.finishedCount,[self.prefetchURLs count]);
}
}
if (!image) {
else {
if (self.progressBlock) {
self.progressBlock(self.finishedCount,[self.prefetchURLs count]);
}
// Add last failed
self.skippedCount++;
}
if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didPrefetchURL:finishedCount:totalCount:)]) {
[self.delegate imagePrefetcher:self
didPrefetchURL:currentURL
didPrefetchURL:self.prefetchURLs[index]
finishedCount:self.finishedCount
totalCount:self.prefetchURLs.count
];
}
if (self.prefetchURLs.count > self.requestedCount) {
dispatch_async(self.prefetcherQueue, ^{
// we need dispatch to avoid function recursion call. This can prevent stack overflow even for huge urls list
[self startPrefetchingAtIndex:self.requestedCount];
});
} else if (self.finishedCount == self.requestedCount) {
......@@ -96,7 +96,7 @@
}
- (void)reportStatus {
NSUInteger total = (self.prefetchURLs).count;
NSUInteger total = [self.prefetchURLs count];
if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didFinishWithTotalCount:skippedCount:)]) {
[self.delegate imagePrefetcher:self
didFinishWithTotalCount:(total - self.skippedCount)
......@@ -105,13 +105,11 @@
}
}
- (void)prefetchURLs:(nullable NSArray<NSURL *> *)urls {
- (void)prefetchURLs:(NSArray *)urls {
[self prefetchURLs:urls progress:nil completed:nil];
}
- (void)prefetchURLs:(nullable NSArray<NSURL *> *)urls
progress:(nullable SDWebImagePrefetcherProgressBlock)progressBlock
completed:(nullable SDWebImagePrefetcherCompletionBlock)completionBlock {
- (void)prefetchURLs:(NSArray *)urls progress:(SDWebImagePrefetcherProgressBlock)progressBlock completed:(SDWebImagePrefetcherCompletionBlock)completionBlock {
[self cancelPrefetching]; // Prevent duplicate prefetch request
self.startedTime = CFAbsoluteTimeGetCurrent();
self.prefetchURLs = urls;
......@@ -132,12 +130,10 @@
}
- (void)cancelPrefetching {
@synchronized(self) {
self.prefetchURLs = nil;
self.skippedCount = 0;
self.requestedCount = 0;
self.finishedCount = 0;
}
self.prefetchURLs = nil;
self.skippedCount = 0;
self.requestedCount = 0;
self.finishedCount = 0;
[self.manager cancelAll];
}
......
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageCompat.h"
#if SD_UIKIT || SD_MAC
#import "SDImageCache.h"
// This class is used to provide a transition animation after the view category load image finished. Use this on `sd_imageTransition` in UIView+WebCache.h
// for UIKit(iOS & tvOS), we use `+[UIView transitionWithView:duration:options:animations:completion]` for transition animation.
// for AppKit(macOS), we use `+[NSAnimationContext runAnimationGroup:completionHandler:]` for transition animation. You can call `+[NSAnimationContext currentContext]` to grab the context during animations block.
// These transition are provided for basic usage. If you need complicated animation, consider to directly use Core Animation or use `SDWebImageAvoidAutoSetImage` and implement your own after image load finished.
#if SD_UIKIT
typedef UIViewAnimationOptions SDWebImageAnimationOptions;
#else
typedef NS_OPTIONS(NSUInteger, SDWebImageAnimationOptions) {
SDWebImageAnimationOptionAllowsImplicitAnimation = 1 << 0, // specify `allowsImplicitAnimation` for the `NSAnimationContext`
};
#endif
typedef void (^SDWebImageTransitionPreparesBlock)(__kindof UIView * _Nonnull view, UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL);
typedef void (^SDWebImageTransitionAnimationsBlock)(__kindof UIView * _Nonnull view, UIImage * _Nullable image);
typedef void (^SDWebImageTransitionCompletionBlock)(BOOL finished);
@interface SDWebImageTransition : NSObject
/**
By default, we set the image to the view at the beginning of the animtions. You can disable this and provide custom set image process
*/
@property (nonatomic, assign) BOOL avoidAutoSetImage;
/**
The duration of the transition animation, measured in seconds. Defaults to 0.5.
*/
@property (nonatomic, assign) NSTimeInterval duration;
/**
The timing function used for all animations within this transition animation (macOS).
*/
@property (nonatomic, strong, nullable) CAMediaTimingFunction *timingFunction NS_AVAILABLE_MAC(10_7);
/**
A mask of options indicating how you want to perform the animations.
*/
@property (nonatomic, assign) SDWebImageAnimationOptions animationOptions;
/**
A block object to be executed before the animation sequence starts.
*/
@property (nonatomic, copy, nullable) SDWebImageTransitionPreparesBlock prepares;
/**
A block object that contains the changes you want to make to the specified view.
*/
@property (nonatomic, copy, nullable) SDWebImageTransitionAnimationsBlock animations;
/**
A block object to be executed when the animation sequence ends.
*/
@property (nonatomic, copy, nullable) SDWebImageTransitionCompletionBlock completion;
@end
// Convenience way to create transition. Remember to specify the duration if needed.
// for UIKit, these transition just use the correspond `animationOptions`. By default we enable `UIViewAnimationOptionAllowUserInteraction` to allow user interaction during transition.
// for AppKit, these transition use Core Animation in `animations`. So your view must be layer-backed. Set `wantsLayer = YES` before you apply it.
@interface SDWebImageTransition (Conveniences)
// class property is available in Xcode 8. We will drop the Xcode 7.3 support in 5.x
#if __has_feature(objc_class_property)
/// Fade transition.
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *fadeTransition;
/// Flip from left transition.
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *flipFromLeftTransition;
/// Flip from right transition.
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *flipFromRightTransition;
/// Flip from top transition.
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *flipFromTopTransition;
/// Flip from bottom transition.
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *flipFromBottomTransition;
/// Curl up transition.
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *curlUpTransition;
/// Curl down transition.
@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *curlDownTransition;
#else
+ (nonnull instancetype)fadeTransition;
+ (nonnull instancetype)flipFromLeftTransition;
+ (nonnull instancetype)flipFromRightTransition;
+ (nonnull instancetype)flipFromTopTransition;
+ (nonnull instancetype)flipFromBottomTransition;
+ (nonnull instancetype)curlUpTransition;
+ (nonnull instancetype)curlDownTransition;
#endif
@end
#endif
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "SDWebImageTransition.h"
#if SD_UIKIT || SD_MAC
#if SD_MAC
#import <QuartzCore/QuartzCore.h>
#endif
@implementation SDWebImageTransition
- (instancetype)init {
self = [super init];
if (self) {
self.duration = 0.5;
}
return self;
}
@end
@implementation SDWebImageTransition (Conveniences)
+ (SDWebImageTransition *)fadeTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionAllowUserInteraction;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionFade;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}
+ (SDWebImageTransition *)flipFromLeftTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionFlipFromLeft | UIViewAnimationOptionAllowUserInteraction;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionPush;
trans.subtype = kCATransitionFromLeft;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}
+ (SDWebImageTransition *)flipFromRightTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionFlipFromRight | UIViewAnimationOptionAllowUserInteraction;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionPush;
trans.subtype = kCATransitionFromRight;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}
+ (SDWebImageTransition *)flipFromTopTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionFlipFromTop | UIViewAnimationOptionAllowUserInteraction;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionPush;
trans.subtype = kCATransitionFromTop;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}
+ (SDWebImageTransition *)flipFromBottomTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionFlipFromBottom | UIViewAnimationOptionAllowUserInteraction;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionPush;
trans.subtype = kCATransitionFromBottom;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}
+ (SDWebImageTransition *)curlUpTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionCurlUp | UIViewAnimationOptionAllowUserInteraction;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionReveal;
trans.subtype = kCATransitionFromTop;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}
+ (SDWebImageTransition *)curlDownTransition {
SDWebImageTransition *transition = [SDWebImageTransition new];
#if SD_UIKIT
transition.animationOptions = UIViewAnimationOptionTransitionCurlDown | UIViewAnimationOptionAllowUserInteraction;
#else
transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) {
CATransition *trans = [CATransition animation];
trans.type = kCATransitionReveal;
trans.subtype = kCATransitionFromBottom;
[view.layer addAnimation:trans forKey:kCATransition];
};
#endif
return transition;
}
@end
#endif
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#import "UIImage+ForceDecode.h"
#import "SDWebImageCodersManager.h"
@implementation UIImage (ForceDecode)
+ (UIImage *)decodedImageWithImage:(UIImage *)image {
if (!image) {
return nil;
}
NSData *tempData;
return [[SDWebImageCodersManager sharedInstance] decompressedImageWithImage:image data:&tempData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(NO)}];
}
+ (UIImage *)decodedAndScaledDownImageWithImage:(UIImage *)image {
if (!image) {
return nil;
}
NSData *tempData;
return [[SDWebImageCodersManager sharedInstance] decompressedImageWithImage:image data:&tempData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(YES)}];
}
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
* (c) Laurin Brandner
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
//
// UIImage+GIF.h
// LBGIFImage
//
// Created by Laurin Brandner on 06.01.12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "SDWebImageCompat.h"
#import <UIKit/UIKit.h>
@interface UIImage (GIF)
/**
* Creates an animated UIImage from an NSData.
* For static GIF, will create an UIImage with `images` array set to nil. For animated GIF, will create an UIImage with valid `images` array.
*/
+ (UIImage *)sd_animatedGIFNamed:(NSString *)name;
+ (UIImage *)sd_animatedGIFWithData:(NSData *)data;
/**
* Checks if an UIImage instance is a GIF. Will use the `images` array.
*/
- (BOOL)isGIF;
- (UIImage *)sd_animatedImageByScalingAndCroppingToSize:(CGSize)size;
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
* (c) Laurin Brandner
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
//
// UIImage+GIF.m
// LBGIFImage
//
// Created by Laurin Brandner on 06.01.12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "UIImage+GIF.h"
#import "SDWebImageGIFCoder.h"
#import "NSImage+WebCache.h"
#import <ImageIO/ImageIO.h>
@implementation UIImage (GIF)
......@@ -17,11 +15,147 @@
if (!data) {
return nil;
}
return [[SDWebImageGIFCoder sharedCoder] decodedImageWithData:data];
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
size_t count = CGImageSourceGetCount(source);
UIImage *animatedImage;
if (count <= 1) {
animatedImage = [[UIImage alloc] initWithData:data];
}
else {
NSMutableArray *images = [NSMutableArray array];
NSTimeInterval duration = 0.0f;
for (size_t i = 0; i < count; i++) {
CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
if (!image) {
continue;
}
duration += [self sd_frameDurationAtIndex:i source:source];
[images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]];
CGImageRelease(image);
}
if (!duration) {
duration = (1.0f / 10.0f) * count;
}
animatedImage = [UIImage animatedImageWithImages:images duration:duration];
}
CFRelease(source);
return animatedImage;
}
+ (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source {
float frameDuration = 0.1f;
CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
if (delayTimeUnclampedProp) {
frameDuration = [delayTimeUnclampedProp floatValue];
}
else {
NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
if (delayTimeProp) {
frameDuration = [delayTimeProp floatValue];
}
}
// Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
// We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
// a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
// for more information.
if (frameDuration < 0.011f) {
frameDuration = 0.100f;
}
CFRelease(cfFrameProperties);
return frameDuration;
}
- (BOOL)isGIF {
return (self.images != nil);
+ (UIImage *)sd_animatedGIFNamed:(NSString *)name {
CGFloat scale = [UIScreen mainScreen].scale;
if (scale > 1.0f) {
NSString *retinaPath = [[NSBundle mainBundle] pathForResource:[name stringByAppendingString:@"@2x"] ofType:@"gif"];
NSData *data = [NSData dataWithContentsOfFile:retinaPath];
if (data) {
return [UIImage sd_animatedGIFWithData:data];
}
NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"];
data = [NSData dataWithContentsOfFile:path];
if (data) {
return [UIImage sd_animatedGIFWithData:data];
}
return [UIImage imageNamed:name];
}
else {
NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"];
NSData *data = [NSData dataWithContentsOfFile:path];
if (data) {
return [UIImage sd_animatedGIFWithData:data];
}
return [UIImage imageNamed:name];
}
}
- (UIImage *)sd_animatedImageByScalingAndCroppingToSize:(CGSize)size {
if (CGSizeEqualToSize(self.size, size) || CGSizeEqualToSize(size, CGSizeZero)) {
return self;
}
CGSize scaledSize = size;
CGPoint thumbnailPoint = CGPointZero;
CGFloat widthFactor = size.width / self.size.width;
CGFloat heightFactor = size.height / self.size.height;
CGFloat scaleFactor = (widthFactor > heightFactor) ? widthFactor : heightFactor;
scaledSize.width = self.size.width * scaleFactor;
scaledSize.height = self.size.height * scaleFactor;
if (widthFactor > heightFactor) {
thumbnailPoint.y = (size.height - scaledSize.height) * 0.5;
}
else if (widthFactor < heightFactor) {
thumbnailPoint.x = (size.width - scaledSize.width) * 0.5;
}
NSMutableArray *scaledImages = [NSMutableArray array];
for (UIImage *image in self.images) {
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
[image drawInRect:CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledSize.width, scaledSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
[scaledImages addObject:newImage];
UIGraphicsEndImageContext();
}
return [UIImage animatedImageWithImages:scaledImages duration:self.duration];
}
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
//
// UIImage+MultiFormat.h
// SDWebImage
//
// Created by Olivier Poitrey on 07/06/13.
// Copyright (c) 2013 Dailymotion. All rights reserved.
//
#import "SDWebImageCompat.h"
#import "NSData+ImageContentType.h"
#import <UIKit/UIKit.h>
@interface UIImage (MultiFormat)
/**
* UIKit:
* For static image format, this value is always 0.
* For animated image format, 0 means infinite looping.
* @note Note that because of the limitations of categories this property can get out of sync if you create another instance with CGImage or other methods.
* AppKit:
* NSImage currently only support animated via GIF imageRep unlike UIImage.
* The getter of this property will get the loop count from GIF imageRep
* The setter of this property will set the loop count from GIF imageRep
*/
@property (nonatomic, assign) NSUInteger sd_imageLoopCount;
/**
* The image format represent the original compressed image data format.
* If you don't manually specify a format, this information is retrieve from CGImage using `CGImageGetUTType`, which may return nil for non-CG based image. At this time it will return `SDImageFormatUndefined` as default value.
* @note Note that because of the limitations of categories this property can get out of sync if you create another instance with CGImage or other methods.
*/
@property (nonatomic, assign) SDImageFormat sd_imageFormat;
+ (nullable UIImage *)sd_imageWithData:(nullable NSData *)data;
- (nullable NSData *)sd_imageData;
- (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat;
+ (UIImage *)sd_imageWithData:(NSData *)data;
@end
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
//
// UIImage+MultiFormat.m
// SDWebImage
//
// Created by Olivier Poitrey on 07/06/13.
// Copyright (c) 2013 Dailymotion. All rights reserved.
//
#import "UIImage+MultiFormat.h"
#import "NSImage+WebCache.h"
#import "SDWebImageCodersManager.h"
#import "objc/runtime.h"
#import "UIImage+GIF.h"
#import "NSData+ImageContentType.h"
#import <ImageIO/ImageIO.h>
#ifdef SD_WEBP
#import "UIImage+WebP.h"
#endif
@implementation UIImage (MultiFormat)
#if SD_MAC
- (NSUInteger)sd_imageLoopCount {
NSUInteger imageLoopCount = 0;
for (NSImageRep *rep in self.representations) {
if ([rep isKindOfClass:[NSBitmapImageRep class]]) {
NSBitmapImageRep *bitmapRep = (NSBitmapImageRep *)rep;
imageLoopCount = [[bitmapRep valueForProperty:NSImageLoopCount] unsignedIntegerValue];
break;
+ (UIImage *)sd_imageWithData:(NSData *)data {
if (!data) {
return nil;
}
UIImage *image;
NSString *imageContentType = [NSData sd_contentTypeForImageData:data];
if ([imageContentType isEqualToString:@"image/gif"]) {
image = [UIImage sd_animatedGIFWithData:data];
}
#ifdef SD_WEBP
else if ([imageContentType isEqualToString:@"image/webp"])
{
image = [UIImage sd_imageWithWebPData:data];
}
#endif
else {
image = [[UIImage alloc] initWithData:data];
UIImageOrientation orientation = [self sd_imageOrientationFromImageData:data];
if (orientation != UIImageOrientationUp) {
image = [UIImage imageWithCGImage:image.CGImage
scale:image.scale
orientation:orientation];
}
}
return imageLoopCount;
return image;
}
- (void)setSd_imageLoopCount:(NSUInteger)sd_imageLoopCount {
for (NSImageRep *rep in self.representations) {
if ([rep isKindOfClass:[NSBitmapImageRep class]]) {
NSBitmapImageRep *bitmapRep = (NSBitmapImageRep *)rep;
[bitmapRep setProperty:NSImageLoopCount withValue:@(sd_imageLoopCount)];
break;
+(UIImageOrientation)sd_imageOrientationFromImageData:(NSData *)imageData {
UIImageOrientation result = UIImageOrientationUp;
CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL);
if (imageSource) {
CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL);
if (properties) {
CFTypeRef val;
int exifOrientation;
val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation);
if (val) {
CFNumberGetValue(val, kCFNumberIntType, &exifOrientation);
result = [self sd_exifOrientationToiOSOrientation:exifOrientation];
} // else - if it's not set it remains at up
CFRelease((CFTypeRef) properties);
} else {
//NSLog(@"NO PROPERTIES, FAIL");
}
CFRelease(imageSource);
}
return result;
}
#else
#pragma mark EXIF orientation tag converter
// Convert an EXIF image orientation to an iOS one.
// reference see here: http://sylvana.net/jpegcrop/exif_orientation.html
+ (UIImageOrientation) sd_exifOrientationToiOSOrientation:(int)exifOrientation {
UIImageOrientation orientation = UIImageOrientationUp;
switch (exifOrientation) {
case 1:
orientation = UIImageOrientationUp;
break;
- (NSUInteger)sd_imageLoopCount {
NSUInteger imageLoopCount = 0;
NSNumber *value = objc_getAssociatedObject(self, @selector(sd_imageLoopCount));
if ([value isKindOfClass:[NSNumber class]]) {
imageLoopCount = value.unsignedIntegerValue;
}
return imageLoopCount;
}
case 3:
orientation = UIImageOrientationDown;
break;
- (void)setSd_imageLoopCount:(NSUInteger)sd_imageLoopCount {
NSNumber *value = @(sd_imageLoopCount);
objc_setAssociatedObject(self, @selector(sd_imageLoopCount), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#endif
case 8:
orientation = UIImageOrientationLeft;
break;
- (SDImageFormat)sd_imageFormat {
SDImageFormat imageFormat = SDImageFormatUndefined;
NSNumber *value = objc_getAssociatedObject(self, @selector(sd_imageFormat));
if ([value isKindOfClass:[NSNumber class]]) {
imageFormat = value.integerValue;
return imageFormat;
}
// Check CGImage's UTType, may return nil for non-Image/IO based image
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability"
if (&CGImageGetUTType != NULL) {
CFStringRef uttype = CGImageGetUTType(self.CGImage);
imageFormat = [NSData sd_imageFormatFromUTType:uttype];
}
#pragma clang diagnostic pop
return imageFormat;
}
case 6:
orientation = UIImageOrientationRight;
break;
- (void)setSd_imageFormat:(SDImageFormat)sd_imageFormat {
objc_setAssociatedObject(self, @selector(sd_imageFormat), @(sd_imageFormat), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
case 2:
orientation = UIImageOrientationUpMirrored;
break;
+ (nullable UIImage *)sd_imageWithData:(nullable NSData *)data {
return [[SDWebImageCodersManager sharedInstance] decodedImageWithData:data];
}
case 4:
orientation = UIImageOrientationDownMirrored;
break;
- (nullable NSData *)sd_imageData {
return [self sd_imageDataAsFormat:SDImageFormatUndefined];
}
case 5:
orientation = UIImageOrientationLeftMirrored;
break;
- (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat {
NSData *imageData = nil;
if (self) {
imageData = [[SDWebImageCodersManager sharedInstance] encodedDataWithImage:self format:imageFormat];
case 7:
orientation = UIImageOrientationRightMirrored;
break;
default:
break;
}
return imageData;
return orientation;
}
@end
......@@ -6,10 +6,8 @@
* file that was distributed with this source code.
*/
#import <UIKit/UIKit.h>
#import "SDWebImageCompat.h"
#if SD_UIKIT
#import "SDWebImageManager.h"
/**
......@@ -24,7 +22,7 @@
*
* @param url The url for the image.
*/
- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url NS_REFINED_FOR_SWIFT;
- (void)sd_setHighlightedImageWithURL:(NSURL *)url;
/**
* Set the imageView `highlightedImage` with an `url` and custom options.
......@@ -34,8 +32,7 @@
* @param url The url for the image.
* @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
*/
- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url
options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT;
- (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options;
/**
* Set the imageView `highlightedImage` with an `url`.
......@@ -49,8 +46,7 @@
* indicating if the image was retrieved from the local cache or from the network.
* The fourth parameter is the original image url.
*/
- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url
completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT;
- (void)sd_setHighlightedImageWithURL:(NSURL *)url completed:(SDWebImageCompletionBlock)completedBlock;
/**
* Set the imageView `highlightedImage` with an `url` and custom options.
......@@ -65,9 +61,7 @@
* indicating if the image was retrieved from the local cache or from the network.
* The fourth parameter is the original image url.
*/
- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url
options:(SDWebImageOptions)options
completed:(nullable SDExternalCompletionBlock)completedBlock;
- (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock;
/**
* Set the imageView `highlightedImage` with an `url` and custom options.
......@@ -77,18 +71,30 @@
* @param url The url for the image.
* @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
* @param progressBlock A block called while image is downloading
* @note the progress block is executed on a background queue
* @param completedBlock A block called when operation has been completed. This block has no return value
* and takes the requested UIImage as first parameter. In case of error the image parameter
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
* indicating if the image was retrieved from the local cache or from the network.
* The fourth parameter is the original image url.
*/
- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url
options:(SDWebImageOptions)options
progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
completed:(nullable SDExternalCompletionBlock)completedBlock;
- (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock;
/**
* Cancel the current download
*/
- (void)sd_cancelCurrentHighlightedImageLoad;
@end
#endif
@interface UIImageView (HighlightedWebCacheDeprecated)
- (void)setHighlightedImageWithURL:(NSURL *)url __deprecated_msg("Method deprecated. Use `sd_setHighlightedImageWithURL:`");
- (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options __deprecated_msg("Method deprecated. Use `sd_setHighlightedImageWithURL:options:`");
- (void)setHighlightedImageWithURL:(NSURL *)url completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setHighlightedImageWithURL:completed:`");
- (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setHighlightedImageWithURL:options:completed:`");
- (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setHighlightedImageWithURL:options:progress:completed:`");
- (void)cancelCurrentHighlightedImageLoad __deprecated_msg("Use `sd_cancelCurrentHighlightedImageLoad`");
@end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment