├── .gitignore ├── BFRImageViewController ├── BFRBackLoadedImageSource.h ├── BFRBackLoadedImageSource.m ├── BFRImageContainerViewController.h ├── BFRImageContainerViewController.m ├── BFRImageTransitionAnimator.h ├── BFRImageTransitionAnimator.m ├── BFRImageViewController.h ├── BFRImageViewController.m ├── BFRImageViewerConstants.h ├── BFRImageViewerConstants.m ├── BFRImageViewerDownloadProgressView.h ├── BFRImageViewerDownloadProgressView.m ├── BFRImageViewerLocalizations.h └── Resources │ ├── BFRImageViewerLocalizations.bundle │ ├── en.lproj │ │ └── Localizable.strings │ └── es.lproj │ │ └── Localizable.strings │ └── lowResImage.png ├── BFRImageViewer.podspec ├── BFRImageViewerDemo ├── BFRImageViewer.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── BFRImageViewer.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── BFRImageViewer │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── FifthViewController.h │ ├── FifthViewController.m │ ├── FirstViewController.h │ ├── FirstViewController.m │ ├── FourthViewController.h │ ├── FourthViewController.m │ ├── Info.plist │ ├── SecondViewController.h │ ├── SecondViewController.m │ ├── ThirdViewController.h │ ├── ThirdViewController.m │ └── main.m ├── Podfile ├── Podfile.lock └── Pods │ ├── Headers │ ├── Private │ │ ├── PINOperation │ │ │ ├── PINOperation.h │ │ │ ├── PINOperationGroup.h │ │ │ ├── PINOperationMacros.h │ │ │ ├── PINOperationQueue.h │ │ │ └── PINOperationTypes.h │ │ └── PINRemoteImage │ │ │ ├── NSData+ImageDetectors.h │ │ │ ├── NSHTTPURLResponse+MaxAge.h │ │ │ ├── PINAlternateRepresentationProvider.h │ │ │ ├── PINAnimatedImage.h │ │ │ ├── PINAnimatedImageView+PINRemoteImage.h │ │ │ ├── PINAnimatedImageView.h │ │ │ ├── PINButton+PINRemoteImage.h │ │ │ ├── PINCachedAnimatedImage.h │ │ │ ├── PINDisplayLink.h │ │ │ ├── PINGIFAnimatedImage.h │ │ │ ├── PINImage+DecodedImage.h │ │ │ ├── PINImage+ScaledImage.h │ │ │ ├── PINImage+WebP.h │ │ │ ├── PINImageView+PINRemoteImage.h │ │ │ ├── PINProgressiveImage.h │ │ │ ├── PINRemoteImage.h │ │ │ ├── PINRemoteImageBasicCache.h │ │ │ ├── PINRemoteImageCaching.h │ │ │ ├── PINRemoteImageCallbacks.h │ │ │ ├── PINRemoteImageCategoryManager.h │ │ │ ├── PINRemoteImageDownloadQueue.h │ │ │ ├── PINRemoteImageDownloadTask.h │ │ │ ├── PINRemoteImageMacros.h │ │ │ ├── PINRemoteImageManager+Private.h │ │ │ ├── PINRemoteImageManager.h │ │ │ ├── PINRemoteImageManagerConfiguration.h │ │ │ ├── PINRemoteImageManagerResult.h │ │ │ ├── PINRemoteImageMemoryContainer.h │ │ │ ├── PINRemoteImageProcessorTask.h │ │ │ ├── PINRemoteImageTask+Subclassing.h │ │ │ ├── PINRemoteImageTask.h │ │ │ ├── PINRemoteLock.h │ │ │ ├── PINRemoteWeakProxy.h │ │ │ ├── PINRequestRetryStrategy.h │ │ │ ├── PINResume.h │ │ │ ├── PINSpeedRecorder.h │ │ │ ├── PINURLSessionManager.h │ │ │ └── PINWebPAnimatedImage.h │ └── Public │ │ ├── PINOperation │ │ ├── PINOperation.h │ │ ├── PINOperationGroup.h │ │ ├── PINOperationMacros.h │ │ ├── PINOperationQueue.h │ │ └── PINOperationTypes.h │ │ └── PINRemoteImage │ │ ├── NSData+ImageDetectors.h │ │ ├── NSHTTPURLResponse+MaxAge.h │ │ ├── PINAlternateRepresentationProvider.h │ │ ├── PINAnimatedImage.h │ │ ├── PINAnimatedImageView+PINRemoteImage.h │ │ ├── PINAnimatedImageView.h │ │ ├── PINButton+PINRemoteImage.h │ │ ├── PINCachedAnimatedImage.h │ │ ├── PINDisplayLink.h │ │ ├── PINGIFAnimatedImage.h │ │ ├── PINImage+DecodedImage.h │ │ ├── PINImage+ScaledImage.h │ │ ├── PINImage+WebP.h │ │ ├── PINImageView+PINRemoteImage.h │ │ ├── PINProgressiveImage.h │ │ ├── PINRemoteImage.h │ │ ├── PINRemoteImageBasicCache.h │ │ ├── PINRemoteImageCaching.h │ │ ├── PINRemoteImageCallbacks.h │ │ ├── PINRemoteImageCategoryManager.h │ │ ├── PINRemoteImageDownloadQueue.h │ │ ├── PINRemoteImageDownloadTask.h │ │ ├── PINRemoteImageMacros.h │ │ ├── PINRemoteImageManager+Private.h │ │ ├── PINRemoteImageManager.h │ │ ├── PINRemoteImageManagerConfiguration.h │ │ ├── PINRemoteImageManagerResult.h │ │ ├── PINRemoteImageMemoryContainer.h │ │ ├── PINRemoteImageProcessorTask.h │ │ ├── PINRemoteImageTask+Subclassing.h │ │ ├── PINRemoteImageTask.h │ │ ├── PINRemoteLock.h │ │ ├── PINRemoteWeakProxy.h │ │ ├── PINRequestRetryStrategy.h │ │ ├── PINResume.h │ │ ├── PINSpeedRecorder.h │ │ ├── PINURLSessionManager.h │ │ └── PINWebPAnimatedImage.h │ ├── Manifest.lock │ ├── PINOperation │ ├── LICENSE.txt │ ├── README.md │ └── Source │ │ ├── PINOperation.h │ │ ├── PINOperationGroup.h │ │ ├── PINOperationGroup.m │ │ ├── PINOperationMacros.h │ │ ├── PINOperationQueue.h │ │ ├── PINOperationQueue.m │ │ └── PINOperationTypes.h │ ├── PINRemoteImage │ ├── LICENSE │ ├── README.md │ └── Source │ │ └── Classes │ │ ├── AnimatedImages │ │ ├── PINAnimatedImage.m │ │ ├── PINAnimatedImageView.m │ │ ├── PINCachedAnimatedImage.m │ │ ├── PINGIFAnimatedImage.m │ │ └── PINWebPAnimatedImage.m │ │ ├── Categories │ │ ├── NSData+ImageDetectors.m │ │ ├── NSHTTPURLResponse+MaxAge.h │ │ ├── NSHTTPURLResponse+MaxAge.m │ │ ├── PINImage+DecodedImage.h │ │ ├── PINImage+DecodedImage.m │ │ ├── PINImage+ScaledImage.h │ │ ├── PINImage+ScaledImage.m │ │ ├── PINImage+WebP.h │ │ ├── PINImage+WebP.m │ │ └── PINRemoteImageTask+Subclassing.h │ │ ├── ImageCategories │ │ ├── PINAnimatedImageView+PINRemoteImage.m │ │ ├── PINButton+PINRemoteImage.m │ │ └── PINImageView+PINRemoteImage.m │ │ ├── PINAlternateRepresentationProvider.m │ │ ├── PINDisplayLink.h │ │ ├── PINDisplayLink.m │ │ ├── PINProgressiveImage.m │ │ ├── PINRemoteImageBasicCache.h │ │ ├── PINRemoteImageBasicCache.m │ │ ├── PINRemoteImageCallbacks.h │ │ ├── PINRemoteImageCallbacks.m │ │ ├── PINRemoteImageCategoryManager.m │ │ ├── PINRemoteImageDownloadQueue.h │ │ ├── PINRemoteImageDownloadQueue.m │ │ ├── PINRemoteImageDownloadTask.h │ │ ├── PINRemoteImageDownloadTask.m │ │ ├── PINRemoteImageManager+Private.h │ │ ├── PINRemoteImageManager.m │ │ ├── PINRemoteImageManagerConfiguration.h │ │ ├── PINRemoteImageManagerConfiguration.m │ │ ├── PINRemoteImageManagerResult.m │ │ ├── PINRemoteImageMemoryContainer.h │ │ ├── PINRemoteImageMemoryContainer.m │ │ ├── PINRemoteImageProcessorTask.h │ │ ├── PINRemoteImageProcessorTask.m │ │ ├── PINRemoteImageTask.h │ │ ├── PINRemoteImageTask.m │ │ ├── PINRemoteLock.h │ │ ├── PINRemoteLock.m │ │ ├── PINRemoteWeakProxy.h │ │ ├── PINRemoteWeakProxy.m │ │ ├── PINRequestRetryStrategy.m │ │ ├── PINResume.h │ │ ├── PINResume.m │ │ ├── PINSpeedRecorder.h │ │ ├── PINSpeedRecorder.m │ │ ├── PINURLSessionManager.m │ │ └── include │ │ ├── NSData+ImageDetectors.h │ │ ├── PINAlternateRepresentationProvider.h │ │ ├── PINAnimatedImage.h │ │ ├── PINAnimatedImageView+PINRemoteImage.h │ │ ├── PINAnimatedImageView.h │ │ ├── PINButton+PINRemoteImage.h │ │ ├── PINCachedAnimatedImage.h │ │ ├── PINGIFAnimatedImage.h │ │ ├── PINImageView+PINRemoteImage.h │ │ ├── PINProgressiveImage.h │ │ ├── PINRemoteImage.h │ │ ├── PINRemoteImageCaching.h │ │ ├── PINRemoteImageCategoryManager.h │ │ ├── PINRemoteImageMacros.h │ │ ├── PINRemoteImageManager.h │ │ ├── PINRemoteImageManagerResult.h │ │ ├── PINRequestRetryStrategy.h │ │ ├── PINURLSessionManager.h │ │ └── PINWebPAnimatedImage.h │ ├── Pods.xcodeproj │ └── project.pbxproj │ └── Target Support Files │ ├── PINOperation │ ├── PINOperation-dummy.m │ ├── PINOperation-prefix.pch │ ├── PINOperation.debug.xcconfig │ ├── PINOperation.release.xcconfig │ └── PINOperation.xcconfig │ ├── PINRemoteImage │ ├── PINRemoteImage-dummy.m │ ├── PINRemoteImage-prefix.pch │ ├── PINRemoteImage.debug.xcconfig │ ├── PINRemoteImage.release.xcconfig │ └── PINRemoteImage.xcconfig │ └── Pods-BFRImageViewer │ ├── Pods-BFRImageViewer-acknowledgements.markdown │ ├── Pods-BFRImageViewer-acknowledgements.plist │ ├── Pods-BFRImageViewer-dummy.m │ ├── Pods-BFRImageViewer-frameworks.sh │ ├── Pods-BFRImageViewer-resources.sh │ ├── Pods-BFRImageViewer.debug.xcconfig │ └── Pods-BFRImageViewer.release.xcconfig ├── CHANGELOG.md ├── LICENSE ├── demo.gif ├── readme.md └── transition.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | .DS_Store 20 | 21 | # CocoaPods 22 | # 23 | # We recommend against adding the Pods directory to your .gitignore. However 24 | # you should judge for yourself, the pros and cons are mentioned at: 25 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 26 | # 27 | #Pods/ 28 | -------------------------------------------------------------------------------- /BFRImageViewController/BFRBackLoadedImageSource.h: -------------------------------------------------------------------------------- 1 | // 2 | // BFRBackLoadedImageSource.h 3 | // BFRImageViewer 4 | // 5 | // Created by Jordan Morgan on 4/6/17. 6 | // Copyright © 2017 Andrew Yates. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | typedef void(^onHiResDownloadComplete)(UIImage * _Nullable, NSError * _Nullable); 13 | 14 | /*! This class allows you to show an image that you already have available initially, while loading a higher fidelity version in the background which will replace the lower fidelity one. This class assumes that the new image will have the same aspect ratio as the old one. */ 15 | @interface BFRBackLoadedImageSource : NSObject 16 | 17 | /*! The image that is available for use right away. */ 18 | @property (strong, nonatomic, readonly, nonnull) UIImage *image; 19 | 20 | /*! This is called on the main thread when the higher resolution image is finished loading. Assign to this if you wish to do any specific logic when the download completes. NOTE: Do not attempt to assign the image to any @c BFRImageContainerViewController, this is done for you. Use this block soley for any other business logic you might have to carry out. */ 21 | @property (copy) onHiResDownloadComplete _Nullable onCompletion; 22 | 23 | /*! Use initWithInitialImage:hiResURL instead. */ 24 | - (instancetype _Nullable)init NS_UNAVAILABLE; 25 | 26 | /*! Returns an instance of this class that will show the @c UIImage provided first, and then replace it with the high fidelty version when it loads via the passed in @c NSURL. */ 27 | - (instancetype _Nullable)initWithInitialImage:(UIImage * _Nonnull)image hiResURL:(NSURL * _Nonnull)url NS_DESIGNATED_INITIALIZER; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /BFRImageViewController/BFRBackLoadedImageSource.m: -------------------------------------------------------------------------------- 1 | // 2 | // BFRBackLoadedImageSource.m 3 | // BFRImageViewer 4 | // 5 | // Created by Jordan Morgan on 4/6/17. 6 | // Copyright © 2017 Andrew Yates. All rights reserved. 7 | // 8 | 9 | #import "BFRBackLoadedImageSource.h" 10 | #import "BFRImageViewerConstants.h" 11 | #import 12 | #import 13 | #import 14 | 15 | @interface BFRBackLoadedImageSource() 16 | 17 | /*! The high fidelity image that will be loaded in the background and then shown once it's downloaded. */ 18 | @property (strong, nonatomic, nonnull) NSURL *url; 19 | 20 | /*! The image that will show initially. */ 21 | @property (strong, nonatomic, readwrite, nonnull) UIImage *image; 22 | 23 | @end 24 | 25 | @implementation BFRBackLoadedImageSource 26 | 27 | #pragma mark - Initializers 28 | 29 | - (instancetype)initWithInitialImage:(UIImage *)image hiResURL:(NSURL *)url { 30 | self = [super init]; 31 | 32 | if (self) { 33 | self.image = image; 34 | self.url = url; 35 | 36 | [self loadHighFidelityImage]; 37 | } 38 | 39 | return self; 40 | } 41 | 42 | #pragma mark - Backloading 43 | 44 | - (void)loadHighFidelityImage { 45 | [[PINRemoteImageManager sharedImageManager] downloadImageWithURL:self.url options:PINRemoteImageManagerDownloadOptionsNone progressDownload:nil completion:^(PINRemoteImageManagerResult * _Nonnull result) { 46 | dispatch_async(dispatch_get_main_queue(), ^{ 47 | if (self.onCompletion != nil) { 48 | if (result.image) { 49 | self.onCompletion(result.image, nil); 50 | } else { 51 | NSLog(@"BFRImageViewer: Unable to load high resolution photo via backloading."); 52 | NSError *downloadError = [NSError errorWithDomain:HI_RES_IMG_ERROR_DOMAIN 53 | code:HI_RES_IMG_ERROR_CODE 54 | userInfo:@{NSLocalizedFailureReasonErrorKey:[NSString stringWithFormat:@"Failed to download an image for high resolution url %@", self.url.absoluteString]}]; 55 | self.onCompletion(nil, downloadError); 56 | } 57 | } 58 | 59 | id returnResult = result.alternativeRepresentation ? result.alternativeRepresentation : result.image; 60 | [[NSNotificationCenter defaultCenter] postNotificationName:NOTE_HI_RES_IMG_DOWNLOADED object:returnResult]; 61 | }); 62 | }]; 63 | } 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /BFRImageViewController/BFRImageContainerViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // BFRImageContainerViewController.h 3 | // Buffer 4 | // 5 | // Created by Jordan Morgan on 11/10/15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | typedef NS_ENUM(NSUInteger, BFRImageAssetType) { 12 | BFRImageAssetTypeImage, 13 | BFRImageAssetTypeRemoteImage, 14 | BFRImageAssetTypeGIF, 15 | BFRImageAssetTypeLivePhoto, 16 | BFRImageAssetTypeUnknown 17 | }; 18 | 19 | /*! This class holds an image to view, if you need an image viewer alloc @C BFRImageViewController instead. This class isn't meant to instanitated outside of it. */ 20 | @interface BFRImageContainerViewController : UIViewController 21 | 22 | /*! Source of the image, which should either be @c NSURL or @c UIIimage. */ 23 | @property (strong, nonatomic, nonnull) id imgSrc; 24 | 25 | /*! The type of asset that is being represented by the given @p imgSrc. */ 26 | @property (nonatomic, assign) BFRImageAssetType assetType; 27 | 28 | /*! This will determine whether to change certain behaviors for 3D touch considerations based on its value. */ 29 | @property (nonatomic, getter=isBeingUsedFor3DTouch) BOOL usedFor3DTouch; 30 | 31 | /*! A helper integer to simplify using this view controller inside a @c UIPagerViewController when swiping between views. */ 32 | @property (nonatomic, assign) NSUInteger pageIndex; 33 | 34 | /*! Assigning YES to this property will make the background transparent. You typically don't set this property yourself, instead, the value is derived from the containing @c BFRImageViewController instance. */ 35 | @property (nonatomic, getter=isUsingTransparentBackground) BOOL useTransparentBackground; 36 | 37 | /*! Assigning YES to this property will disable long pressing media to present the activity view controller. You typically don't set this property yourself, instead, the value is derived from the containing @c BFRImageViewController instance. */ 38 | @property (nonatomic, getter=shouldDisableSharingLongPress) BOOL disableSharingLongPress; 39 | 40 | /*! If there is more than one image in the containing @c BFRImageViewController - this property is set to YES to make swiping from image to image easier. */ 41 | @property (nonatomic, getter=shouldDisableHorizontalDrag) BOOL disableHorizontalDrag; 42 | 43 | /*! Assigning YES to this property will disable autoplay for live photos when it used with 3DTouch peek feature */ 44 | @property (nonatomic, getter=shouldDisableAutoplayForLivePhoto) BOOL disableAutoplayForLivePhoto; 45 | @property (nonatomic, assign) CGFloat imageMaxScale; 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /BFRImageViewController/BFRImageTransitionAnimator.h: -------------------------------------------------------------------------------- 1 | // 2 | // BFRImageTransitionAnimator.h 3 | // BFRImageViewer 4 | // 5 | // Created by Jordan Morgan on 3/21/17. 6 | // Copyright © 2017 Andrew Yates. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | static const CGFloat DEFAULT_ANIMATION_DURATION = 0.23f; 13 | 14 | @interface BFRImageTransitionAnimator : NSObject 15 | 16 | /*! The view that houses the @c UIImage being aniamted. Typically will be a @c UIImageView. If set, this will be hidden during the animation which looks nicer. */ 17 | @property (strong, nonatomic, nonnull) UIView *animatedImageContainer; 18 | 19 | /*! This is the image that will animate during the transition. A copy of it will be made, and this is just used for reference. This must be set before the animation begins. */ 20 | @property (strong, nonatomic, nonnull) UIImage *animatedImage; 21 | 22 | /*! The frame where the animated image began at, housed in the presenting view controller. When dismissed, the image will animate back to this @t CGRect. */ 23 | @property (nonatomic) CGRect imageOriginFrame; 24 | 25 | /*! Set this to the content mode of the containing view that's holding the image you're animating, otherwise, the frames might look off. */ 26 | @property (nonatomic) UIViewContentMode desiredContentMode; 27 | 28 | /*! The duration of the animation for the custom transition. By default, this is set to DEFAULT_ANIMATION_DURATION. */ 29 | @property (nonatomic) CGFloat animationDuration; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /BFRImageViewController/BFRImageViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // BFRImageViewController.h 3 | // Buffer 4 | // 5 | // Created by Jordan Morgan on 11/13/15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface BFRImageViewController : UIViewController 12 | 13 | - (instancetype _Nullable)init NS_UNAVAILABLE; 14 | 15 | /*! Initializes an instance of @C BFRImageViewController from the image source provided. The array can contain a mix of @c NSURL, @c UIImage, @c PHAsset, @c BFRBackLoadedImageSource or @c NSStrings of URLS. This can be a mix of all these types, or just one. */ 16 | - (instancetype _Nullable)initWithImageSource:(NSArray * _Nonnull)images; 17 | 18 | /*! Initializes an instance of @C BFRImageViewController from the image source provided. The array can contain a mix of @c NSURL, @c UIImage, @c PHAsset, or @c NSStrings of URLS. This can be a mix of all these types, or just one. Additionally, this customizes the user interface to defer showing some of its user interface elements, such as the close button, until it's been fully popped.*/ 19 | - (instancetype _Nullable)initForPeekWithImageSource:(NSArray * _Nonnull)images; 20 | 21 | /*! Reinitialize with a new images array. Can be used to change the view controller's content on demand */ 22 | - (void)setImageSource:(NSArray * _Nonnull)images; 23 | 24 | /*! Assigning YES to this property will make the background transparent. Default is NO. */ 25 | @property (nonatomic, getter=isUsingTransparentBackground) BOOL useTransparentBackground; 26 | 27 | /*! Assigning YES to this property will disable long pressing media to present the activity view controller. Default is NO. */ 28 | @property (nonatomic, getter=shouldDisableSharingLongPress) BOOL disableSharingLongPress; 29 | 30 | /*! Flag property that toggles the doneButton. Defaults to YES */ 31 | @property (nonatomic) BOOL enableDoneButton; 32 | 33 | /*! Flag property that sets the doneButton position (left or right side). Defaults to YES */ 34 | @property (nonatomic) BOOL showDoneButtonOnLeft; 35 | 36 | /*! Allows you to assign an index which to show first when opening multiple images. */ 37 | @property (nonatomic, assign) NSInteger startingIndex; 38 | 39 | /*! Retrieve the index of the currently showing image. */ 40 | @property (nonatomic, assign, readonly) NSInteger currentIndex; 41 | 42 | /*! Allows you to enable autoplay for peek&play feature on photo live view. Default to YES */ 43 | @property (nonatomic, getter=shouldDisableAutoplayForLivePhoto) BOOL disableAutoplayForLivePhoto; 44 | 45 | /*! Allows you to set image max scale */ 46 | @property (nonatomic, assign) CGFloat maxScale; 47 | 48 | /*! Dismiss properly with animations */ 49 | - (void)dismiss; 50 | 51 | /*! Dismiss properly with animations and an optional completion handler */ 52 | - (void)dismissWithCompletion:(void (^ __nullable)(void))completion; 53 | 54 | /*! Dismiss properly without custom animations */ 55 | - (void)dismissWithoutCustomAnimation; 56 | 57 | /*! Dismiss properly without custom animations and an optional completion handler */ 58 | - (void)dismissWithoutCustomAnimationWithCompletion:(void (^ __nullable)(void))completion; 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /BFRImageViewController/BFRImageViewerConstants.h: -------------------------------------------------------------------------------- 1 | // 2 | // BFRImageViewerConstants.h 3 | // BFRImageViewer 4 | // 5 | // Created by Jordan Morgan on 10/5/17. 6 | // Copyright © 2017 Andrew Yates. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface BFRImageViewerConstants : NSObject 12 | 13 | // Notifications 14 | extern NSString * const NOTE_VC_POPPED; 15 | extern NSString * const NOTE_HI_RES_IMG_DOWNLOADED; 16 | extern NSString * const NOTE_VC_SHOULD_DISMISS; 17 | extern NSString * const NOTE_VC_SHOULD_DISMISS_FROM_DRAGGING; 18 | extern NSString * const NOTE_VC_SHOULD_CANCEL_CUSTOM_TRANSITION; 19 | extern NSString * const NOTE_IMG_FAILED; 20 | 21 | // NSError 22 | extern NSString * const ERROR_TITLE; 23 | extern NSString * const ERROR_MESSAGE; 24 | extern NSString * const GENERAL_OK; 25 | extern NSString * const HI_RES_IMG_ERROR_DOMAIN; 26 | extern NSInteger const HI_RES_IMG_ERROR_CODE; 27 | 28 | // Misc 29 | extern NSInteger const PARALLAX_EFFECT_WIDTH; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /BFRImageViewController/BFRImageViewerConstants.m: -------------------------------------------------------------------------------- 1 | // 2 | // BFRImageViewerConstants.m 3 | // BFRImageViewer 4 | // 5 | // Created by Jordan Morgan on 10/5/17. 6 | // Copyright © 2017 Andrew Yates. All rights reserved. 7 | // 8 | 9 | #import "BFRImageViewerConstants.h" 10 | 11 | @implementation BFRImageViewerConstants 12 | 13 | NSString * const NOTE_VC_POPPED = @"ViewControllerPopped"; 14 | NSString * const NOTE_HI_RES_IMG_DOWNLOADED = @"HiResDownloadDone"; 15 | NSString * const NOTE_VC_SHOULD_DISMISS = @"DismissController"; 16 | NSString * const NOTE_VC_SHOULD_DISMISS_FROM_DRAGGING = @"DimissUIFromDraggingGesture"; 17 | NSString * const NOTE_VC_SHOULD_CANCEL_CUSTOM_TRANSITION = @"CancelCustomDismissalTransition"; 18 | NSString * const NOTE_IMG_FAILED = @"ImageLoadingError"; 19 | 20 | NSString * const ERROR_TITLE = @"Whoops"; 21 | NSString * const ERROR_MESSAGE = @"Looks like we ran into an issue loading the image, sorry about that!"; 22 | NSString * const GENERAL_OK = @"Ok"; 23 | NSString * const HI_RES_IMG_ERROR_DOMAIN = @"com.bfrImageViewer.backLoadedImgSource"; 24 | NSInteger const HI_RES_IMG_ERROR_CODE = 44; 25 | 26 | NSInteger const PARALLAX_EFFECT_WIDTH = 20; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /BFRImageViewController/BFRImageViewerDownloadProgressView.h: -------------------------------------------------------------------------------- 1 | // 2 | // BFRImageViewerDownloadProgressView.h 3 | // BFRImageViewer 4 | // 5 | // Created by Jordan Morgan on 8/22/18. 6 | // Copyright © 2018 Andrew Yates. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface BFRImageViewerDownloadProgressView : UIView 12 | 13 | @property (nonatomic, readonly) CGSize progessSize; 14 | @property (nonatomic) CGFloat progress; 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /BFRImageViewController/BFRImageViewerDownloadProgressView.m: -------------------------------------------------------------------------------- 1 | // 2 | // BFRImageViewerDownloadProgressView.m 3 | // BFRImageViewer 4 | // 5 | // Created by Jordan Morgan on 8/22/18. 6 | // Copyright © 2018 Andrew Yates. All rights reserved. 7 | // 8 | 9 | #import "BFRImageViewerDownloadProgressView.h" 10 | 11 | static const CGFloat BFR_PROGRESS_LINE_WIDTH = 3.0f; 12 | 13 | @interface BFRImageViewerDownloadProgressView() 14 | 15 | @property (strong, nonatomic, nonnull) CAShapeLayer *progressBackingLayer; 16 | @property (strong, nonatomic, nonnull) CAShapeLayer *progressLayer; 17 | @property (strong, nonatomic, nonnull) UIBezierPath *progressPath; 18 | @property (nonatomic, readwrite) CGSize progessSize; 19 | 20 | @end 21 | 22 | @implementation BFRImageViewerDownloadProgressView 23 | 24 | #pragma mark - Lazy Loads 25 | 26 | - (CAShapeLayer *)progressBackingLayer { 27 | if (!_progressBackingLayer) { 28 | _progressBackingLayer = [CAShapeLayer new]; 29 | _progressBackingLayer.strokeColor = [UIColor lightTextColor].CGColor; 30 | _progressBackingLayer.fillColor = [UIColor clearColor].CGColor; 31 | _progressBackingLayer.strokeEnd = 1; 32 | _progressBackingLayer.lineCap = kCALineCapRound; 33 | _progressBackingLayer.lineWidth = BFR_PROGRESS_LINE_WIDTH; 34 | } 35 | 36 | return _progressBackingLayer; 37 | } 38 | 39 | - (CAShapeLayer *)progressLayer { 40 | if (!_progressLayer) { 41 | _progressLayer = [CAShapeLayer new]; 42 | _progressLayer.strokeColor = [UIColor whiteColor].CGColor; 43 | _progressLayer.fillColor = [UIColor clearColor].CGColor; 44 | _progressLayer.strokeEnd = 0; 45 | _progressLayer.lineCap = kCALineCapRound; 46 | _progressLayer.lineWidth = BFR_PROGRESS_LINE_WIDTH; 47 | } 48 | 49 | return _progressLayer; 50 | } 51 | 52 | #pragma mark - Custom setters 53 | 54 | - (void)setProgress:(CGFloat)progress { 55 | _progress = progress; 56 | if (_progressLayer == nil) return; 57 | _progressLayer.strokeEnd = progress; 58 | } 59 | 60 | #pragma mark - Initializers 61 | 62 | - (instancetype)init { 63 | self = [super init]; 64 | 65 | if (self) { 66 | CGFloat targetHeightWidth = floorf([UIScreen mainScreen].bounds.size.width * .15f); 67 | self.progessSize = CGSizeMake(targetHeightWidth, targetHeightWidth); 68 | 69 | CGRect baseRect = CGRectMake(0, 0, self.progessSize.width, self.progessSize.height); 70 | CGRect targetRect = CGRectInset(baseRect, BFR_PROGRESS_LINE_WIDTH/2, BFR_PROGRESS_LINE_WIDTH/2); 71 | 72 | // Progress circle 73 | CGFloat startAngle = M_PI_2 * 3.0f;; 74 | CGFloat endAngle = startAngle + (M_PI * 2.0); 75 | CGFloat width = CGRectGetWidth(targetRect)/2.0f; 76 | CGFloat height = CGRectGetHeight(targetRect)/2.0f; 77 | CGPoint centerPoint = CGPointMake(width, height); 78 | float radius = targetRect.size.width/2; 79 | 80 | self.progressPath = [UIBezierPath bezierPathWithArcCenter:centerPoint 81 | radius:radius 82 | startAngle:startAngle 83 | endAngle:endAngle 84 | clockwise:YES]; 85 | 86 | self.progressBackingLayer.path = self.progressPath.CGPath; 87 | self.progressLayer.path = self.progressPath.CGPath; 88 | 89 | self.backgroundColor = [UIColor clearColor]; 90 | self.clipsToBounds = NO; 91 | 92 | [self.layer addSublayer:self.progressBackingLayer]; 93 | [self.layer addSublayer:self.progressLayer]; 94 | } 95 | 96 | return self; 97 | } 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /BFRImageViewController/BFRImageViewerLocalizations.h: -------------------------------------------------------------------------------- 1 | // 2 | // BFRImageViewerLocalizations.h 3 | // BFRImageViewer 4 | // 5 | // Created by Jordan Morgan on 9/29/16. 6 | // Copyright © 2016 Andrew Yates. All rights reserved. 7 | // 8 | 9 | #ifndef BFRImageViewerLocalizations_h 10 | #define BFRImageViewerLocalizations_h 11 | 12 | #ifndef BFRImageViewerLocalizedStrings 13 | #define BFRImageViewerLocalizedStrings(key, comment) \ 14 | NSLocalizedStringFromTableInBundle(key, nil, [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"BFRImageViewerLocalizations" ofType:@"bundle"]], comment) 15 | #endif 16 | 17 | #endif /* BFRImageViewerLocalizations_h */ 18 | -------------------------------------------------------------------------------- /BFRImageViewController/Resources/BFRImageViewerLocalizations.bundle/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | 4 | 5 | Created by Jordan Morgan on 9/29/16. 6 | 7 | */ 8 | 9 | "imageViewController.closeButton.text" = "Close"; 10 | -------------------------------------------------------------------------------- /BFRImageViewController/Resources/BFRImageViewerLocalizations.bundle/es.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | 4 | 5 | Created by Jordan Morgan on 9/29/16. 6 | 7 | */ 8 | 9 | "imageViewController.closeButton.text" = "Cerca"; 10 | -------------------------------------------------------------------------------- /BFRImageViewController/Resources/lowResImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bufferapp/buffer-ios-image-viewer/1e5744cfc6282a053c61b9199051ce601663d2e2/BFRImageViewController/Resources/lowResImage.png -------------------------------------------------------------------------------- /BFRImageViewer.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "BFRImageViewer" 3 | s.version = "1.3.1" 4 | s.summary = "A turnkey solution to display photos and images of all kinds in your app." 5 | s.description = <<-DESC 6 | The BFRImageViewer is a turnkey solution to present images within your iOS app 🎉! 7 | 8 | If features swipe gestures to dismiss, parallax scrolling, image scaling, zooming and panning, supports multiple images, image types, and plays nicely with live photos! We use it all over the place in Buffer for iOS :-). 9 | DESC 10 | s.homepage = "https://github.com/bufferapp/buffer-ios-image-viewer" 11 | s.screenshot = "https://github.com/bufferapp/buffer-ios-image-viewer/blob/master/demo.gif?raw=true" 12 | s.license = "MIT" 13 | s.authors = {"Andrew Yates" => "andy@bufferapp.com", 14 | "Jordan Morgan" => "jordan@bufferapp.com"} 15 | s.social_media_url = "https://twitter.com/bufferdevs" 16 | s.source = { :git => "https://github.com/bufferapp/buffer-ios-image-viewer.git", :tag => '1.3.1' } 17 | s.source_files = 'Classes', 'BFRImageViewController/**/*.{h,m}' 18 | s.resources = ['BFRImageViewController/**/BFRImageViewerLocalizations.bundle'] 19 | s.exclude_files = 'BFRImageViewController/**/lowResImage.png' 20 | s.platform = :ios, '13.0' 21 | s.requires_arc = true 22 | s.frameworks = "UIKit", "Photos" 23 | s.dependency 'PINRemoteImage/iOS', '~> 3.0.0' 24 | end 25 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/BFRImageViewer.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/BFRImageViewer.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/BFRImageViewer.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/BFRImageViewer/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // BFRImageViewer 4 | // 5 | // Created by Andrew Yates on 20/11/2015. 6 | // Copyright © 2015 Andrew Yates. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/BFRImageViewer/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // BFRImageViewer 4 | // 5 | // Created by Andrew Yates on 20/11/2015. 6 | // Copyright © 2015 Andrew Yates. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "FirstViewController.h" 11 | #import "SecondViewController.h" 12 | #import "ThirdViewController.h" 13 | #import "FourthViewController.h" 14 | #import "FifthViewController.h" 15 | 16 | @interface AppDelegate () 17 | 18 | @end 19 | 20 | @implementation AppDelegate 21 | 22 | 23 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 24 | self.window = [UIWindow new]; 25 | 26 | UITabBarController *tabVC = [UITabBarController new]; 27 | tabVC.view.backgroundColor = [UIColor whiteColor]; 28 | tabVC.viewControllers = @[[FirstViewController new], 29 | [SecondViewController new], 30 | [ThirdViewController new], 31 | [FourthViewController new], 32 | [FifthViewController new]]; 33 | 34 | self.window.rootViewController = tabVC; 35 | [self.window makeKeyAndVisible]; 36 | 37 | return YES; 38 | } 39 | 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/BFRImageViewer/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/BFRImageViewer/FifthViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // FifthViewController.h 3 | // BFRImageViewer 4 | // 5 | // Created by Omer Emre Aslan on 18.10.2017. 6 | // Copyright © 2017 Andrew Yates. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface FifthViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/BFRImageViewer/FirstViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // FirstViewController.h 3 | // BFRImageViewer 4 | // 5 | // Created by Andrew Yates on 20/11/2015. 6 | // Copyright © 2015 Andrew Yates. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface FirstViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/BFRImageViewer/FirstViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // FirstViewController.m 3 | // BFRImageViewer 4 | // 5 | // Created by Andrew Yates on 20/11/2015. 6 | // Copyright © 2015 Andrew Yates. All rights reserved. 7 | // 8 | 9 | #import "FirstViewController.h" 10 | #import "BFRImageViewController.h" 11 | 12 | @interface FirstViewController () 13 | @property (strong, nonatomic) NSURL *imgURL; 14 | @end 15 | 16 | @implementation FirstViewController 17 | 18 | - (instancetype) init { 19 | if (self = [super init]) { 20 | self.title = @"Single GIF"; 21 | } 22 | 23 | return self; 24 | } 25 | 26 | 27 | - (void)viewDidLoad { 28 | [super viewDidLoad]; 29 | 30 | [self addImageButtonToView]; 31 | 32 | self.imgURL = [NSURL URLWithString:@"https://media0.giphy.com/media/huJmPXfeir5JlpPAx0/200.gif"]; 33 | } 34 | 35 | - (void)openImage { 36 | //Here, the image source could be an array containing/a mix of URL strings, NSURLs, PHAssets, or UIImages 37 | BFRImageViewController *imageVC = [[BFRImageViewController alloc] initWithImageSource:@[self.imgURL]]; 38 | [self presentViewController:imageVC animated:YES completion:nil]; 39 | } 40 | 41 | #pragma mark - Misc 42 | - (void)addImageButtonToView { 43 | UIButton *openImageFromURL = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 44 | openImageFromURL.translatesAutoresizingMaskIntoConstraints = NO; 45 | [openImageFromURL setTitle:@"Open Image" forState:UIControlStateNormal]; 46 | [openImageFromURL addTarget:self action:@selector(openImage) forControlEvents:UIControlEventTouchUpInside]; 47 | [self.view addSubview:openImageFromURL]; 48 | [openImageFromURL.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = YES; 49 | [openImageFromURL.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor].active = YES; 50 | } 51 | @end 52 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/BFRImageViewer/FourthViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // FourthViewController.h 3 | // BFRImageViewer 4 | // 5 | // Created by Jordan Morgan on 4/6/17. 6 | // Copyright © 2017 Andrew Yates. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface FourthViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/BFRImageViewer/FourthViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // FourthViewController.m 3 | // BFRImageViewer 4 | // 5 | // Created by Jordan Morgan on 4/6/17. 6 | // Copyright © 2017 Andrew Yates. All rights reserved. 7 | // 8 | 9 | #import "FourthViewController.h" 10 | #import "BFRBackLoadedImageSource.h" 11 | #import "BFRImageViewController.h" 12 | 13 | @interface FourthViewController () 14 | 15 | @end 16 | 17 | @implementation FourthViewController 18 | 19 | - (instancetype) init { 20 | if (self = [super init]) { 21 | self.title = @"Backloading"; 22 | } 23 | 24 | return self; 25 | } 26 | 27 | - (void)viewDidLoad { 28 | [super viewDidLoad]; 29 | 30 | UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 31 | [btn addTarget:self action:@selector(openImageViewer) forControlEvents:UIControlEventTouchUpInside]; 32 | btn.translatesAutoresizingMaskIntoConstraints = NO; 33 | [btn setTitle:@"Backload URL Image" forState:UIControlStateNormal]; 34 | [self.view addSubview:btn]; 35 | [btn.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = YES; 36 | [btn.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor constant:-20].active = YES; 37 | 38 | 39 | UIButton *btnClosure = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 40 | [btnClosure addTarget:self action:@selector(openImageViewerWithCompletionHandler) forControlEvents:UIControlEventTouchUpInside]; 41 | btnClosure.translatesAutoresizingMaskIntoConstraints = NO; 42 | [btnClosure setTitle:@"Backload URL Image + Completion Handler" forState:UIControlStateNormal]; 43 | [self.view addSubview:btnClosure]; 44 | [btnClosure.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = YES; 45 | [btnClosure.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor constant:20].active = YES; 46 | } 47 | 48 | - (void)openImageViewer { 49 | BFRBackLoadedImageSource *backloadedImage = [[BFRBackLoadedImageSource alloc] initWithInitialImage:[UIImage imageNamed:@"lowResImage"] hiResURL:[NSURL URLWithString:@"https://images.unsplash.com/photo-1620910423680-80b93f872962?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1234&q=80"]]; 50 | 51 | BFRImageViewController *imageVC = [[BFRImageViewController alloc] initWithImageSource:@[backloadedImage]]; 52 | [self presentViewController:imageVC animated:YES completion:nil]; 53 | } 54 | 55 | - (void)openImageViewerWithCompletionHandler { 56 | BFRBackLoadedImageSource *backloadedImage = [[BFRBackLoadedImageSource alloc] initWithInitialImage:[UIImage imageNamed:@"lowResImage"] hiResURL:[NSURL URLWithString:@"https://images.unsplash.com/photo-1620910423680-80b93f872962?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1234&q=80"]]; 57 | 58 | backloadedImage.onCompletion = ^(UIImage * _Nullable img, NSError * _Nullable error) { 59 | UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"Download Done" message:[NSString stringWithFormat:@"Finished downloading hi res image.\nImage:%@\nError:%@", img, error] preferredStyle:UIAlertControllerStyleAlert]; 60 | 61 | UIAlertAction *close = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]; 62 | [alertVC addAction:close]; 63 | 64 | UIViewController *topController = self.view.window.windowScene.windows.firstObject.rootViewController; 65 | while (topController.presentedViewController) { 66 | topController = topController.presentedViewController; 67 | } 68 | 69 | [topController presentViewController:alertVC animated:YES completion:nil]; 70 | }; 71 | 72 | BFRImageViewController *imageVC = [[BFRImageViewController alloc] initWithImageSource:@[backloadedImage]]; 73 | [self presentViewController:imageVC animated:YES completion:nil]; 74 | } 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/BFRImageViewer/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPhotoLibraryUsageDescription 6 | The app will open an image from your library. 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | 32 | UILaunchStoryboardName 33 | LaunchScreen 34 | UIRequiredDeviceCapabilities 35 | 36 | armv7 37 | 38 | UIStatusBarTintParameters 39 | 40 | UINavigationBar 41 | 42 | Style 43 | UIBarStyleDefault 44 | Translucent 45 | 46 | 47 | 48 | UISupportedInterfaceOrientations 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | UISupportedInterfaceOrientations~ipad 55 | 56 | UIInterfaceOrientationPortrait 57 | UIInterfaceOrientationPortraitUpsideDown 58 | UIInterfaceOrientationLandscapeLeft 59 | UIInterfaceOrientationLandscapeRight 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/BFRImageViewer/SecondViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.h 3 | // BFRImageViewer 4 | // 5 | // Created by Andrew Yates on 20/11/2015. 6 | // Copyright © 2015 Andrew Yates. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SecondViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/BFRImageViewer/SecondViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.m 3 | // BFRImageViewer 4 | // 5 | // Created by Andrew Yates on 20/11/2015. 6 | // Copyright © 2015 Andrew Yates. All rights reserved. 7 | // 8 | 9 | #import "SecondViewController.h" 10 | #import "BFRImageViewController.h" 11 | 12 | @interface SecondViewController () 13 | @property (strong, nonatomic) NSArray *imgURLs; 14 | @end 15 | 16 | @implementation SecondViewController 17 | 18 | - (instancetype) init { 19 | if (self = [super init]) { 20 | self.title = @"Multiple Images"; 21 | } 22 | 23 | return self; 24 | } 25 | 26 | - (void)viewDidLoad { 27 | [super viewDidLoad]; 28 | 29 | UIButton *openImageFromURL = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 30 | openImageFromURL.translatesAutoresizingMaskIntoConstraints = NO; 31 | [openImageFromURL setTitle:@"Open Images" forState:UIControlStateNormal]; 32 | [openImageFromURL addTarget:self action:@selector(openImage) forControlEvents:UIControlEventTouchUpInside]; 33 | [self.view addSubview:openImageFromURL]; 34 | [openImageFromURL.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = YES; 35 | [openImageFromURL.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor].active = YES; 36 | 37 | NSURL *url1 = [NSURL URLWithString:@"https://images.unsplash.com/photo-1593642634443-44adaa06623a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2425&q=80"]; 38 | NSURL *url2 = [NSURL URLWithString:@"https://images.unsplash.com/photo-1519389950473-47ba0277781c?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=2700&q=80"]; 39 | NSURL *url3 = [NSURL URLWithString:@"http://i.imgur.com/XBnuETM.jpg"]; 40 | self.imgURLs = @[url1, url2, url3]; 41 | } 42 | 43 | - (void)openImage { 44 | BFRImageViewController *imageVC = [[BFRImageViewController alloc] initWithImageSource:self.imgURLs]; 45 | imageVC.startingIndex = 0; // Default 46 | [self presentViewController:imageVC animated:YES completion:nil]; 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/BFRImageViewer/ThirdViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ThirdViewController.h 3 | // BFRImageViewer 4 | // 5 | // Created by Jordan Morgan on 3/21/17. 6 | // Copyright © 2017 Andrew Yates. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ThirdViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/BFRImageViewer/ThirdViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ThirdViewController.m 3 | // BFRImageViewer 4 | // 5 | // Created by Jordan Morgan on 3/21/17. 6 | // Copyright © 2017 Andrew Yates. All rights reserved. 7 | // 8 | 9 | #import "ThirdViewController.h" 10 | #import "BFRImageTransitionAnimator.h" 11 | #import "BFRImageViewController.h" 12 | 13 | @interface ThirdViewController () 14 | 15 | @property (strong, nonatomic) BFRImageTransitionAnimator *imageViewAnimator; 16 | @property (strong, nonatomic) UIImageView *imageView; 17 | 18 | @end 19 | 20 | @implementation ThirdViewController 21 | 22 | - (instancetype) init { 23 | if (self = [super init]) { 24 | self.title = @"Custom Transition"; 25 | } 26 | 27 | return self; 28 | } 29 | 30 | - (void)viewDidLoad { 31 | [super viewDidLoad]; 32 | 33 | // To use the custom transition animation with BFRImageViewer 34 | // 1) Have an instance of BFRImageTransitionAnimator around 35 | // 2) Set its animatedImage, animatedImageContainer and imageOriginFrame. Optionally, set the desiredContentMode 36 | // 3) When you present the BFRImageViewController, set its transitioningDelegate to your BFRImageTransitionAnimator instance. 37 | // You can see all of this in action in openImageViewerWithTransition below 38 | 39 | // Object to create all the animations 40 | self.imageViewAnimator = [BFRImageTransitionAnimator new]; 41 | 42 | self.imageView = [UIImageView new]; 43 | self.imageView.contentMode = UIViewContentModeScaleAspectFit; 44 | self.imageView.userInteractionEnabled = YES; 45 | [self.view addSubview:self.imageView]; 46 | 47 | [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://open.buffer.com/wp-content/uploads/2017/03/Moo.jpg"] completionHandler:^ (NSData *data, NSURLResponse *response, NSError *error) { 48 | dispatch_async(dispatch_get_main_queue(), ^ { 49 | if (data) { 50 | self.imageView.image = [UIImage imageWithData:data]; 51 | 52 | UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(openImageViewerWithTransition)]; 53 | [self.imageView addGestureRecognizer:gestureRecognizer]; 54 | } 55 | }); 56 | }] resume]; 57 | } 58 | 59 | - (void)viewWillLayoutSubviews { 60 | [super viewWillLayoutSubviews]; 61 | self.imageView.frame = CGRectMake(0, 100, self.view.frame.size.width, 300); 62 | } 63 | 64 | - (void)openImageViewerWithTransition { 65 | BFRImageViewController *imageVC = [[BFRImageViewController alloc] initWithImageSource:@[self.imageView.image]]; 66 | 67 | // This houses the image being animated, and will be hidden during the animations. Typically an image view 68 | self.imageViewAnimator.animatedImageContainer = self.imageView; 69 | // The image that will be animated 70 | self.imageViewAnimator.animatedImage = self.imageView.image; 71 | // The rect the image will animate to and from 72 | self.imageViewAnimator.imageOriginFrame = self.imageView.frame; 73 | // Optional - but you'll want this to match the view's content mode that the image is housed in 74 | self.imageViewAnimator.desiredContentMode = self.imageView.contentMode; 75 | 76 | // This triggers the custom animation, if you forget this, no custom transition occurs 77 | imageVC.transitioningDelegate = self.imageViewAnimator; 78 | 79 | [self presentViewController:imageVC animated:YES completion:nil]; 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/BFRImageViewer/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // BFRImageViewer 4 | // 5 | // Created by Andrew Yates on 20/11/2015. 6 | // Copyright © 2015 Andrew Yates. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '13.0' 2 | 3 | inhibit_all_warnings! 4 | 5 | target 'BFRImageViewer' do 6 | 7 | pod 'PINRemoteImage/iOS', '~> 3.0.0' 8 | 9 | end 10 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - PINOperation (1.2.1) 3 | - PINRemoteImage/Core (3.0.3): 4 | - PINOperation 5 | - PINRemoteImage/iOS (3.0.3): 6 | - PINRemoteImage/Core 7 | 8 | DEPENDENCIES: 9 | - PINRemoteImage/iOS (~> 3.0.0) 10 | 11 | SPEC REPOS: 12 | trunk: 13 | - PINOperation 14 | - PINRemoteImage 15 | 16 | SPEC CHECKSUMS: 17 | PINOperation: 00c935935f1e8cf0d1e2d6b542e75b88fc3e5e20 18 | PINRemoteImage: f1295b29f8c5e640e25335a1b2bd9d805171bd01 19 | 20 | PODFILE CHECKSUM: 9a080f8a24bf4d7e3dd1b620f4fb743f1f4c8104 21 | 22 | COCOAPODS: 1.10.1 23 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINOperation/PINOperation.h: -------------------------------------------------------------------------------- 1 | ../../../PINOperation/Source/PINOperation.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINOperation/PINOperationGroup.h: -------------------------------------------------------------------------------- 1 | ../../../PINOperation/Source/PINOperationGroup.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINOperation/PINOperationMacros.h: -------------------------------------------------------------------------------- 1 | ../../../PINOperation/Source/PINOperationMacros.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINOperation/PINOperationQueue.h: -------------------------------------------------------------------------------- 1 | ../../../PINOperation/Source/PINOperationQueue.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINOperation/PINOperationTypes.h: -------------------------------------------------------------------------------- 1 | ../../../PINOperation/Source/PINOperationTypes.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/NSData+ImageDetectors.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/NSData+ImageDetectors.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/NSHTTPURLResponse+MaxAge.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/Categories/NSHTTPURLResponse+MaxAge.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINAlternateRepresentationProvider.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINAlternateRepresentationProvider.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINAnimatedImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINAnimatedImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINAnimatedImageView+PINRemoteImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINAnimatedImageView+PINRemoteImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINAnimatedImageView.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINAnimatedImageView.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINButton+PINRemoteImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINButton+PINRemoteImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINCachedAnimatedImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINCachedAnimatedImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINDisplayLink.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINDisplayLink.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINGIFAnimatedImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINGIFAnimatedImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINImage+DecodedImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/Categories/PINImage+DecodedImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINImage+ScaledImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/Categories/PINImage+ScaledImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINImage+WebP.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/Categories/PINImage+WebP.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINImageView+PINRemoteImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINImageView+PINRemoteImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINProgressiveImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINProgressiveImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINRemoteImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINRemoteImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINRemoteImageBasicCache.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteImageBasicCache.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINRemoteImageCaching.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINRemoteImageCaching.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINRemoteImageCallbacks.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteImageCallbacks.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINRemoteImageCategoryManager.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINRemoteImageCategoryManager.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINRemoteImageDownloadQueue.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteImageDownloadQueue.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINRemoteImageDownloadTask.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteImageDownloadTask.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINRemoteImageMacros.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINRemoteImageMacros.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINRemoteImageManager+Private.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteImageManager+Private.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINRemoteImageManager.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINRemoteImageManager.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINRemoteImageManagerConfiguration.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteImageManagerConfiguration.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINRemoteImageManagerResult.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINRemoteImageManagerResult.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINRemoteImageMemoryContainer.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteImageMemoryContainer.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINRemoteImageProcessorTask.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteImageProcessorTask.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINRemoteImageTask+Subclassing.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/Categories/PINRemoteImageTask+Subclassing.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINRemoteImageTask.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteImageTask.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINRemoteLock.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteLock.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINRemoteWeakProxy.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteWeakProxy.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINRequestRetryStrategy.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINRequestRetryStrategy.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINResume.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINResume.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINSpeedRecorder.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINSpeedRecorder.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINURLSessionManager.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINURLSessionManager.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Private/PINRemoteImage/PINWebPAnimatedImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINWebPAnimatedImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINOperation/PINOperation.h: -------------------------------------------------------------------------------- 1 | ../../../PINOperation/Source/PINOperation.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINOperation/PINOperationGroup.h: -------------------------------------------------------------------------------- 1 | ../../../PINOperation/Source/PINOperationGroup.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINOperation/PINOperationMacros.h: -------------------------------------------------------------------------------- 1 | ../../../PINOperation/Source/PINOperationMacros.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINOperation/PINOperationQueue.h: -------------------------------------------------------------------------------- 1 | ../../../PINOperation/Source/PINOperationQueue.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINOperation/PINOperationTypes.h: -------------------------------------------------------------------------------- 1 | ../../../PINOperation/Source/PINOperationTypes.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/NSData+ImageDetectors.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/NSData+ImageDetectors.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/NSHTTPURLResponse+MaxAge.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/Categories/NSHTTPURLResponse+MaxAge.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINAlternateRepresentationProvider.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINAlternateRepresentationProvider.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINAnimatedImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINAnimatedImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINAnimatedImageView+PINRemoteImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINAnimatedImageView+PINRemoteImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINAnimatedImageView.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINAnimatedImageView.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINButton+PINRemoteImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINButton+PINRemoteImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINCachedAnimatedImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINCachedAnimatedImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINDisplayLink.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINDisplayLink.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINGIFAnimatedImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINGIFAnimatedImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINImage+DecodedImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/Categories/PINImage+DecodedImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINImage+ScaledImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/Categories/PINImage+ScaledImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINImage+WebP.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/Categories/PINImage+WebP.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINImageView+PINRemoteImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINImageView+PINRemoteImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINProgressiveImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINProgressiveImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINRemoteImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINRemoteImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINRemoteImageBasicCache.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteImageBasicCache.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINRemoteImageCaching.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINRemoteImageCaching.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINRemoteImageCallbacks.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteImageCallbacks.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINRemoteImageCategoryManager.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINRemoteImageCategoryManager.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINRemoteImageDownloadQueue.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteImageDownloadQueue.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINRemoteImageDownloadTask.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteImageDownloadTask.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINRemoteImageMacros.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINRemoteImageMacros.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINRemoteImageManager+Private.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteImageManager+Private.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINRemoteImageManager.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINRemoteImageManager.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINRemoteImageManagerConfiguration.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteImageManagerConfiguration.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINRemoteImageManagerResult.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINRemoteImageManagerResult.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINRemoteImageMemoryContainer.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteImageMemoryContainer.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINRemoteImageProcessorTask.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteImageProcessorTask.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINRemoteImageTask+Subclassing.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/Categories/PINRemoteImageTask+Subclassing.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINRemoteImageTask.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteImageTask.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINRemoteLock.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteLock.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINRemoteWeakProxy.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINRemoteWeakProxy.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINRequestRetryStrategy.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINRequestRetryStrategy.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINResume.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINResume.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINSpeedRecorder.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/PINSpeedRecorder.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINURLSessionManager.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINURLSessionManager.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Headers/Public/PINRemoteImage/PINWebPAnimatedImage.h: -------------------------------------------------------------------------------- 1 | ../../../PINRemoteImage/Source/Classes/include/PINWebPAnimatedImage.h -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - PINOperation (1.2.1) 3 | - PINRemoteImage/Core (3.0.3): 4 | - PINOperation 5 | - PINRemoteImage/iOS (3.0.3): 6 | - PINRemoteImage/Core 7 | 8 | DEPENDENCIES: 9 | - PINRemoteImage/iOS (~> 3.0.0) 10 | 11 | SPEC REPOS: 12 | trunk: 13 | - PINOperation 14 | - PINRemoteImage 15 | 16 | SPEC CHECKSUMS: 17 | PINOperation: 00c935935f1e8cf0d1e2d6b542e75b88fc3e5e20 18 | PINRemoteImage: f1295b29f8c5e640e25335a1b2bd9d805171bd01 19 | 20 | PODFILE CHECKSUM: 9a080f8a24bf4d7e3dd1b620f4fb743f1f4c8104 21 | 22 | COCOAPODS: 1.10.1 23 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINOperation/README.md: -------------------------------------------------------------------------------- 1 | # PINOperation 2 | 3 | [![CocoaPods](https://img.shields.io/cocoapods/v/PINOperation.svg)](http://cocoadocs.org/docsets/PINOperation/) 4 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 5 | [![Build status](https://github.com/pinterest/PINOperation/workflows/CI/badge.svg)](https://github.com/pinterest/PINOperation/actions?query=workflow%3ACI+branch%3Amaster) 6 | 7 | ## Fast, concurrency-limited task queue for iOS and macOS. 8 | 9 | ## Installation 10 | 11 | ### Manually 12 | 13 | [Download the latest tag](https://github.com/pinterest/PINOperation/tags) and drag the `PINOperation` folder into your Xcode project. 14 | 15 | Install the docs by double clicking the `.docset` file under `docs/`, or view them online at [cocoadocs.org](http://cocoadocs.org/docsets/PINOperation/) 16 | 17 | ### Git Submodule 18 | 19 | git submodule add https://github.com/pinterest/PINOperation.git 20 | git submodule update --init 21 | 22 | ### CocoaPods 23 | 24 | Add [PINOperation](http://cocoapods.org/?q=name%3APINOperation) to your `Podfile` and run `pod install`. 25 | 26 | ### Carthage 27 | 28 | Add the following line to your `Cartfile` and run `carthage update --platform ios`. Then follow [this instruction of Carthage](https://github.com/carthage/carthage#adding-frameworks-to-unit-tests-or-a-framework) to embed the framework. 29 | 30 | ```github "pinterest/PINOperation"``` 31 | 32 | ## Requirements 33 | 34 | __PINOperation__ requires iOS 8.0, tvOS 9.0, macOS 10.8 or watchOS 2.0 and greater. 35 | 36 | ## Contact 37 | 38 | [Garrett Moon](mailto:garrett@pinterest.com) 39 | 40 | ## License 41 | 42 | Copyright 2013 Tumblr, Inc. 43 | Copyright 2015 Pinterest, Inc. 44 | 45 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 46 | 47 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. [See the License](LICENSE.txt) for the specific language governing permissions and limitations under the License. 48 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINOperation/Source/PINOperation.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINOperation.h 3 | // PINOperation 4 | // 5 | // Created by Adlai Holler on 1/10/17. 6 | // Copyright © 2017 Pinterest. All rights reserved. 7 | // 8 | 9 | #import "PINOperationMacros.h" 10 | #import "PINOperationTypes.h" 11 | #import "PINOperationQueue.h" 12 | #import "PINOperationGroup.h" 13 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINOperation/Source/PINOperationGroup.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINOperationGroup.h 3 | // PINQueue 4 | // 5 | // Created by Garrett Moon on 10/8/16. 6 | // Copyright © 2016 Pinterest. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PINOperationTypes.h" 11 | #import "PINOperationMacros.h" 12 | 13 | @class PINOperationQueue; 14 | 15 | NS_ASSUME_NONNULL_BEGIN 16 | 17 | @protocol PINGroupOperationReference; 18 | 19 | PINOP_SUBCLASSING_RESTRICTED 20 | @interface PINOperationGroup : NSObject 21 | 22 | - (instancetype)init NS_UNAVAILABLE; 23 | + (instancetype)asyncOperationGroupWithQueue:(PINOperationQueue *)operationQueue; 24 | 25 | - (nullable id )addOperation:(dispatch_block_t)operation; 26 | - (nullable id )addOperation:(dispatch_block_t)operation withPriority:(PINOperationQueuePriority)priority; 27 | - (void)start; 28 | - (void)cancel; 29 | - (void)setCompletion:(dispatch_block_t)completion; 30 | - (void)waitUntilComplete; 31 | 32 | @end 33 | 34 | @protocol PINGroupOperationReference 35 | 36 | @end 37 | 38 | NS_ASSUME_NONNULL_END 39 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINOperation/Source/PINOperationGroup.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINOperationGroup.m 3 | // PINQueue 4 | // 5 | // Created by Garrett Moon on 10/8/16. 6 | // Copyright © 2016 Pinterest. All rights reserved. 7 | // 8 | 9 | #import "PINOperationGroup.h" 10 | #import "PINOperation.h" 11 | #import 12 | 13 | @interface NSNumber (PINGroupOperationQueue) 14 | @end 15 | 16 | @interface PINOperationGroup () 17 | { 18 | pthread_mutex_t _lock; 19 | 20 | PINOperationQueue *_operationQueue; 21 | NSMutableArray *_operations; 22 | NSMutableArray *_operationPriorities; 23 | NSMutableArray > *_operationReferences; 24 | NSMapTable , id > *_groupToOperationReferences; 25 | NSUInteger _operationReferenceCount; 26 | 27 | dispatch_group_t _group; 28 | 29 | dispatch_block_t _completion; 30 | 31 | BOOL _started; 32 | BOOL _canceled; 33 | } 34 | 35 | - (instancetype)initWithOperationQueue:(PINOperationQueue *)operationQueue NS_DESIGNATED_INITIALIZER; 36 | 37 | @end 38 | 39 | @implementation PINOperationGroup 40 | 41 | - (instancetype)initWithOperationQueue:(PINOperationQueue *)operationQueue 42 | { 43 | if (self = [super init]) { 44 | pthread_mutex_init(&_lock, NULL); 45 | 46 | _operationQueue = operationQueue; 47 | 48 | _operations = [[NSMutableArray alloc] init]; 49 | _operationReferences = [[NSMutableArray alloc] init]; 50 | _operationPriorities = [[NSMutableArray alloc] init]; 51 | 52 | _groupToOperationReferences = [NSMapTable weakToStrongObjectsMapTable]; 53 | _group = dispatch_group_create(); 54 | } 55 | return self; 56 | } 57 | 58 | - (void)dealloc 59 | { 60 | pthread_mutex_destroy(&_lock); 61 | } 62 | 63 | + (instancetype)asyncOperationGroupWithQueue:(PINOperationQueue *)operationQueue 64 | { 65 | return [[self alloc] initWithOperationQueue:operationQueue]; 66 | } 67 | 68 | - (id )locked_nextOperationReference 69 | { 70 | id reference = [NSNumber numberWithUnsignedInteger:++_operationReferenceCount]; 71 | return reference; 72 | } 73 | 74 | - (void)start 75 | { 76 | [self lock]; 77 | NSAssert(_canceled == NO, @"Operation group canceled."); 78 | if (_started == NO && _canceled == NO) { 79 | for (NSUInteger idx = 0; idx < _operations.count; idx++) { 80 | dispatch_group_enter(_group); 81 | dispatch_block_t originalOperation = _operations[idx]; 82 | dispatch_block_t groupBlock = ^{ 83 | originalOperation(); 84 | dispatch_group_leave(self->_group); 85 | }; 86 | 87 | id operationReference = [_operationQueue scheduleOperation:groupBlock withPriority:[_operationPriorities[idx] unsignedIntegerValue]]; 88 | [_groupToOperationReferences setObject:operationReference forKey:_operationReferences[idx]]; 89 | } 90 | 91 | if (_completion) { 92 | dispatch_queue_t completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 93 | dispatch_group_notify(_group, completionQueue, ^{ 94 | [self runCompletionIfNeeded]; 95 | }); 96 | } 97 | 98 | _operations = nil; 99 | _operationPriorities = nil; 100 | _operationReferences = nil; 101 | } 102 | [self unlock]; 103 | } 104 | 105 | - (void)cancel 106 | { 107 | [self lock]; 108 | _canceled = YES; 109 | 110 | for (id operationReference in [_groupToOperationReferences objectEnumerator]) { 111 | if ([_operationQueue cancelOperation:operationReference]) { 112 | dispatch_group_leave(_group); 113 | } 114 | } 115 | 116 | //TODO just nil out instead? Does it make sense to support adding operations after cancelation? 117 | [_groupToOperationReferences removeAllObjects]; 118 | [_operations removeAllObjects]; 119 | [_operationPriorities removeAllObjects]; 120 | [_operationReferences removeAllObjects]; 121 | 122 | _completion = nil; 123 | [self unlock]; 124 | } 125 | 126 | - (id )addOperation:(dispatch_block_t)operation 127 | { 128 | return [self addOperation:operation withPriority:PINOperationQueuePriorityDefault]; 129 | } 130 | 131 | - (id )addOperation:(dispatch_block_t)operation withPriority:(PINOperationQueuePriority)priority 132 | { 133 | [self lock]; 134 | id reference = nil; 135 | NSAssert(_started == NO && _canceled == NO, @"Operation group already started or canceled."); 136 | if (_started == NO && _canceled == NO) { 137 | reference = [self locked_nextOperationReference]; 138 | [_operations addObject:operation]; 139 | [_operationPriorities addObject:@(priority)]; 140 | [_operationReferences addObject:reference]; 141 | } 142 | [self unlock]; 143 | 144 | return reference; 145 | } 146 | 147 | - (void)setCompletion:(dispatch_block_t)completion 148 | { 149 | [self lock]; 150 | NSAssert(_started == NO && _canceled == NO, @"Operation group already started or canceled."); 151 | if (_started == NO && _canceled == NO) { 152 | _completion = completion; 153 | } 154 | [self unlock]; 155 | } 156 | 157 | - (void)waitUntilComplete 158 | { 159 | [self start]; 160 | dispatch_group_wait(_group, DISPATCH_TIME_FOREVER); 161 | [self runCompletionIfNeeded]; 162 | } 163 | 164 | - (void)runCompletionIfNeeded 165 | { 166 | dispatch_block_t completion; 167 | [self lock]; 168 | completion = _completion; 169 | _completion = nil; 170 | [self unlock]; 171 | 172 | if (completion) { 173 | completion(); 174 | } 175 | } 176 | 177 | - (void)lock 178 | { 179 | pthread_mutex_lock(&_lock); 180 | } 181 | 182 | - (void)unlock 183 | { 184 | pthread_mutex_unlock(&_lock); 185 | } 186 | 187 | @end 188 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINOperation/Source/PINOperationMacros.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINOperationMacros.h 3 | // PINOperation 4 | // 5 | // Created by Adlai Holler on 1/10/17. 6 | // Copyright © 2017 Pinterest. All rights reserved. 7 | // 8 | 9 | #ifndef PINOP_SUBCLASSING_RESTRICTED 10 | #if defined(__has_attribute) && __has_attribute(objc_subclassing_restricted) 11 | #define PINOP_SUBCLASSING_RESTRICTED __attribute__((objc_subclassing_restricted)) 12 | #else 13 | #define PINOP_SUBCLASSING_RESTRICTED 14 | #endif // #if defined(__has_attribute) && __has_attribute(objc_subclassing_restricted) 15 | #endif // #ifndef PINOP_SUBCLASSING_RESTRICTED 16 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINOperation/Source/PINOperationQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINOperationQueue.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 8/23/16. 6 | // 7 | // 8 | 9 | #import 10 | #import "PINOperationTypes.h" 11 | #import "PINOperationMacros.h" 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | typedef void(^PINOperationBlock)(id _Nullable data); 16 | typedef _Nullable id(^PINOperationDataCoalescingBlock)(id _Nullable existingData, id _Nullable newData); 17 | 18 | @protocol PINOperationReference; 19 | 20 | PINOP_SUBCLASSING_RESTRICTED 21 | @interface PINOperationQueue : NSObject 22 | 23 | - (instancetype)init NS_UNAVAILABLE; 24 | 25 | /** 26 | * Initializes and returns a newly allocated operation queue with the specified number of maximum concurrent operations. 27 | * 28 | * @param maxConcurrentOperations The maximum number of queued operations that can execute at the same time. 29 | * 30 | */ 31 | - (instancetype)initWithMaxConcurrentOperations:(NSUInteger)maxConcurrentOperations; 32 | 33 | /** 34 | * Initializes and returns a newly allocated operation queue with the specified number of maximum concurrent operations and the concurrent queue they will be scheduled on. 35 | * 36 | * @param maxConcurrentOperations The maximum number of queued operations that can execute at the same time. 37 | * @param concurrentQueue The operation queue to schedule concurrent operations 38 | * 39 | */ 40 | - (instancetype)initWithMaxConcurrentOperations:(NSUInteger)maxConcurrentOperations concurrentQueue:(dispatch_queue_t)concurrentQueue NS_DESIGNATED_INITIALIZER; 41 | 42 | /** 43 | * Returns the shared instance of the PINOperationQueue class. 44 | */ 45 | + (instancetype)sharedOperationQueue; 46 | 47 | /** 48 | * Adds the specified operation object to the receiver. 49 | * 50 | * @param operation The operation object to be added to the queue. 51 | * 52 | */ 53 | - (id )scheduleOperation:(dispatch_block_t)operation; 54 | 55 | /** 56 | * Adds the specified operation object to the receiver. 57 | * 58 | * @param operation The operation object to be added to the queue. 59 | * @param priority The execution priority of the operation in an operation queue. 60 | */ 61 | - (id )scheduleOperation:(dispatch_block_t)operation withPriority:(PINOperationQueuePriority)priority; 62 | 63 | /** 64 | * Adds the specified operation object to the receiver. 65 | * 66 | * @param operation The operation object to be added to the queue. 67 | * @param priority The execution priority of the operation in an operation queue. 68 | * @param identifier A string that identifies the operations that can be coalesced. 69 | * @param coalescingData The optional data consumed by this operation that needs to be updated/coalesced with data of a new operation when coalescing the two operations happens. 70 | * @param dataCoalescingBlock The optional block called to update/coalesce the data of this operation with data of a new operation when coalescing the two operations happens. 71 | * @param completion The block to execute after the operation finished. 72 | */ 73 | - (id )scheduleOperation:(PINOperationBlock)operation 74 | withPriority:(PINOperationQueuePriority)priority 75 | identifier:(nullable NSString *)identifier 76 | coalescingData:(nullable id)coalescingData 77 | dataCoalescingBlock:(nullable PINOperationDataCoalescingBlock)dataCoalescingBlock 78 | completion:(nullable dispatch_block_t)completion; 79 | 80 | /** 81 | * The maximum number of queued operations that can execute at the same time. 82 | * 83 | * @discussion The value in this property affects only the operations that the current queue has executing at the same time. Other operation queues can also execute their maximum number of operations in parallel. 84 | * Reducing the number of concurrent operations does not affect any operations that are currently executing. 85 | * 86 | * Setting this value to 1 the operations will not be processed by priority as the operations will processed in a FIFO order to prevent deadlocks if operations depend on certain other operations to run in order. 87 | * 88 | */ 89 | @property (assign) NSUInteger maxConcurrentOperations; 90 | 91 | /** 92 | * Marks the operation as cancelled 93 | */ 94 | - (BOOL)cancelOperation:(id )operationReference; 95 | 96 | /** 97 | * Cancels all queued operations 98 | */ 99 | - (void)cancelAllOperations; 100 | 101 | /** 102 | * Blocks the current thread until all of the receiver’s queued and executing operations finish executing. 103 | * 104 | * @discussion When called, this method blocks the current thread and waits for the receiver’s current and queued 105 | * operations to finish executing. While the current thread is blocked, the receiver continues to launch already 106 | * queued operations and monitor those that are executing. 107 | * 108 | * @warning This should never be called from within an operation submitted to the PINOperationQueue as this will result 109 | * in a deadlock. 110 | */ 111 | - (void)waitUntilAllOperationsAreFinished; 112 | 113 | /** 114 | * Sets the priority for a operation via it's reference 115 | * 116 | * @param priority The new priority for the operation 117 | * @param reference The reference for the operation 118 | * 119 | */ 120 | - (void)setOperationPriority:(PINOperationQueuePriority)priority withReference:(id )reference; 121 | 122 | #pragma mark - Deprecated 123 | 124 | - (id )addOperation:(dispatch_block_t)operation __deprecated_msg("Use scheduleOperation: instead."); 125 | 126 | - (id )addOperation:(dispatch_block_t)operation withPriority:(PINOperationQueuePriority)priority __deprecated_msg("Use scheduleOperation:withPriority: instead."); 127 | 128 | - (id )addOperation:(PINOperationBlock)operation 129 | withPriority:(PINOperationQueuePriority)priority 130 | identifier:(nullable NSString *)identifier 131 | coalescingData:(nullable id)coalescingData 132 | dataCoalescingBlock:(nullable PINOperationDataCoalescingBlock)dataCoalescingBlock 133 | completion:(nullable dispatch_block_t)completion __deprecated_msg("Use scheduleOperation:withPriority:identifier:coalescingData:dataCoalescingBlock:completion: instead."); 134 | 135 | @end 136 | 137 | @protocol PINOperationReference 138 | 139 | @end 140 | 141 | NS_ASSUME_NONNULL_END 142 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINOperation/Source/PINOperationTypes.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINOperationTypes.h 3 | // PINOperation 4 | // 5 | // Created by Adlai Holler on 1/10/17. 6 | // Copyright © 2017 Pinterest. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef NS_ENUM(NSUInteger, PINOperationQueuePriority) { 12 | PINOperationQueuePriorityLow, 13 | PINOperationQueuePriorityDefault, 14 | PINOperationQueuePriorityHigh, 15 | }; 16 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/AnimatedImages/PINAnimatedImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINAnimatedImage.m 3 | // PINRemoteImage 4 | // 5 | // Created by Garrett Moon on 9/17/17. 6 | // Copyright © 2017 Pinterest. All rights reserved. 7 | // 8 | 9 | #import "PINAnimatedImage.h" 10 | 11 | NSErrorDomain const kPINAnimatedImageErrorDomain = @"kPINAnimatedImageErrorDomain"; 12 | 13 | //http://nullsleep.tumblr.com/post/16524517190/animated-gif-minimum-frame-delay-browser 14 | const Float32 kPINAnimatedImageDefaultDuration = 0.1; 15 | 16 | @interface PINAnimatedImage () 17 | { 18 | CFTimeInterval _totalDuration; 19 | } 20 | @end 21 | 22 | @implementation PINAnimatedImage 23 | 24 | + (NSInteger)maximumFramesPerSecond 25 | { 26 | static dispatch_once_t onceToken; 27 | static NSInteger maximumFramesPerSecond = 60; 28 | 29 | dispatch_once(&onceToken, ^{ 30 | #if PIN_TARGET_IOS 31 | if (@available(iOS 10.3, tvOS 10.3, *)) { 32 | maximumFramesPerSecond = 0; 33 | for (UIScreen *screen in [UIScreen screens]) { 34 | if ([screen maximumFramesPerSecond] > maximumFramesPerSecond) { 35 | maximumFramesPerSecond = [screen maximumFramesPerSecond]; 36 | } 37 | } 38 | } 39 | #endif 40 | }); 41 | return maximumFramesPerSecond; 42 | } 43 | 44 | - (instancetype)init 45 | { 46 | if (self = [super init]) { 47 | _totalDuration = -1; 48 | } 49 | return self; 50 | } 51 | 52 | - (CFTimeInterval)durationAtIndex:(NSUInteger)index 53 | { 54 | NSAssert(NO, @"Must be overridden by subclass"); 55 | return 0; 56 | } 57 | 58 | - (size_t)frameCount 59 | { 60 | NSAssert(NO, @"Must be overridden by subclass"); 61 | return 0; 62 | } 63 | 64 | 65 | - (CFTimeInterval)totalDuration 66 | { 67 | if (_totalDuration == -1) { 68 | _totalDuration = 0; 69 | for (NSUInteger idx = 0; idx < self.frameCount; idx++) { 70 | _totalDuration += [self durationAtIndex:idx]; 71 | } 72 | } 73 | 74 | return _totalDuration; 75 | } 76 | 77 | - (NSUInteger)frameInterval 78 | { 79 | return MAX(self.minimumFrameInterval * [PINAnimatedImage maximumFramesPerSecond], 1); 80 | } 81 | 82 | //Credit to FLAnimatedImage ( https://github.com/Flipboard/FLAnimatedImage ) for display link interval calculations 83 | - (NSTimeInterval)minimumFrameInterval 84 | { 85 | static dispatch_once_t onceToken; 86 | static NSTimeInterval kGreatestCommonDivisorPrecision; 87 | dispatch_once(&onceToken, ^{ 88 | kGreatestCommonDivisorPrecision = 2.0 / (1.0 / [PINAnimatedImage maximumFramesPerSecond]); 89 | }); 90 | 91 | // Scales the frame delays by `kGreatestCommonDivisorPrecision` 92 | // then converts it to an UInteger for in order to calculate the GCD. 93 | NSUInteger scaledGCD = lrint([self durationAtIndex:0] * kGreatestCommonDivisorPrecision); 94 | for (NSUInteger durationIdx = 1; durationIdx < self.frameCount; durationIdx++) { 95 | CFTimeInterval duration = [self durationAtIndex:durationIdx]; 96 | scaledGCD = gcd(lrint(duration * kGreatestCommonDivisorPrecision), scaledGCD); 97 | } 98 | 99 | // Reverse to scale to get the value back into seconds. 100 | return (scaledGCD / kGreatestCommonDivisorPrecision); 101 | } 102 | 103 | // This likely isn't the most efficient but it's easy to reason about and we don't call it 104 | // with super large numbers. 105 | static NSUInteger gcd(NSUInteger a, NSUInteger b) 106 | { 107 | // http://en.wikipedia.org/wiki/Greatest_common_divisor 108 | NSCAssert(a > 0 && b > 0, @"A and B must be greater than 0"); 109 | 110 | while (a != b) { 111 | if (a > b) { 112 | a = a - b; 113 | } else { 114 | b = b - a; 115 | } 116 | } 117 | return a; 118 | } 119 | 120 | // Used only in testing 121 | + (NSUInteger)greatestCommonDivisorOfA:(NSUInteger)a andB:(NSUInteger)b 122 | { 123 | return gcd(a, b); 124 | } 125 | 126 | @end 127 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/AnimatedImages/PINGIFAnimatedImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINGIFAnimatedImage.m 3 | // PINRemoteImage 4 | // 5 | // Created by Garrett Moon on 9/17/17. 6 | // Copyright © 2017 Pinterest. All rights reserved. 7 | // 8 | 9 | #import "PINGIFAnimatedImage.h" 10 | 11 | #import 12 | #if PIN_TARGET_IOS 13 | #import 14 | #elif PIN_TARGET_MAC 15 | #import 16 | #endif 17 | 18 | #import "PINImage+DecodedImage.h" 19 | #import "NSData+ImageDetectors.h" 20 | 21 | @interface PINGIFAnimatedImage () 22 | { 23 | NSData *_animatedImageData; 24 | CGImageSourceRef _imageSource; 25 | uint32_t _width; 26 | uint32_t _height; 27 | BOOL _hasAlpha; 28 | size_t _frameCount; 29 | size_t _loopCount; 30 | CFTimeInterval *_durations; 31 | NSError *_error; 32 | } 33 | @end 34 | 35 | @implementation PINGIFAnimatedImage 36 | 37 | - (instancetype)initWithAnimatedImageData:(NSData *)animatedImageData 38 | { 39 | if (self = [super init]) { 40 | _animatedImageData = animatedImageData; 41 | _imageSource = 42 | CGImageSourceCreateWithData((CFDataRef)animatedImageData, 43 | (CFDictionaryRef)@{(__bridge NSString *)kCGImageSourceTypeIdentifierHint: 44 | (__bridge NSString *)kUTTypeGIF, 45 | (__bridge NSString *)kCGImageSourceShouldCache: 46 | (__bridge NSNumber *)kCFBooleanFalse}); 47 | if (_imageSource && [animatedImageData pin_isGIF]) { 48 | _frameCount = (uint32_t)CGImageSourceGetCount(_imageSource); 49 | NSDictionary *imageProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(_imageSource, nil); 50 | _loopCount = (uint32_t)[[[imageProperties objectForKey:(__bridge NSString *)kCGImagePropertyGIFDictionary] 51 | objectForKey:(__bridge NSString *)kCGImagePropertyGIFLoopCount] unsignedLongValue]; 52 | _durations = malloc(sizeof(CFTimeInterval) * _frameCount); 53 | imageProperties = (__bridge_transfer NSDictionary *) 54 | CGImageSourceCopyPropertiesAtIndex(_imageSource, 55 | 0, 56 | (CFDictionaryRef)@{(__bridge NSString *)kCGImageSourceShouldCache: 57 | (__bridge NSNumber *)kCFBooleanFalse}); 58 | _width = (uint32_t)[(NSNumber *)imageProperties[(__bridge NSString *)kCGImagePropertyPixelWidth] unsignedIntegerValue]; 59 | _height = (uint32_t)[(NSNumber *)imageProperties[(__bridge NSString *)kCGImagePropertyPixelHeight] unsignedIntegerValue]; 60 | 61 | for (NSUInteger frameIdx = 0; frameIdx < _frameCount; frameIdx++) { 62 | _durations[frameIdx] = [PINGIFAnimatedImage frameDurationAtIndex:frameIdx source:_imageSource]; 63 | } 64 | } else { 65 | return nil; 66 | } 67 | } 68 | return self; 69 | } 70 | 71 | + (Float32)frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source 72 | { 73 | Float32 frameDuration = kPINAnimatedImageDefaultDuration; 74 | NSDictionary *frameProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(source, index, nil); 75 | // use unclamped delay time before delay time before default 76 | NSNumber *unclamedDelayTime = frameProperties[(__bridge NSString *)kCGImagePropertyGIFDictionary][(__bridge NSString *)kCGImagePropertyGIFUnclampedDelayTime]; 77 | if (unclamedDelayTime != nil) { 78 | frameDuration = [unclamedDelayTime floatValue]; 79 | } else { 80 | NSNumber *delayTime = frameProperties[(__bridge NSString *)kCGImagePropertyGIFDictionary][(__bridge NSString *)kCGImagePropertyGIFDelayTime]; 81 | if (delayTime != nil) { 82 | frameDuration = [delayTime floatValue]; 83 | } 84 | } 85 | 86 | static dispatch_once_t onceToken; 87 | static Float32 maximumFrameDuration; 88 | dispatch_once(&onceToken, ^{ 89 | maximumFrameDuration = 1.0 / [PINAnimatedImage maximumFramesPerSecond]; 90 | }); 91 | 92 | if (frameDuration < maximumFrameDuration) { 93 | frameDuration = kPINAnimatedImageDefaultDuration; 94 | } 95 | 96 | return frameDuration; 97 | } 98 | 99 | - (void)dealloc 100 | { 101 | if (_imageSource) { 102 | CFRelease(_imageSource); 103 | } 104 | if (_durations) { 105 | free(_durations); 106 | } 107 | } 108 | 109 | - (NSData *)data 110 | { 111 | return _animatedImageData; 112 | } 113 | 114 | - (size_t)frameCount 115 | { 116 | return _frameCount; 117 | } 118 | 119 | - (size_t)loopCount 120 | { 121 | return _loopCount; 122 | } 123 | 124 | - (uint32_t)width 125 | { 126 | return _width; 127 | } 128 | 129 | - (uint32_t)height 130 | { 131 | return _height; 132 | } 133 | 134 | - (uint32_t)bytesPerFrame 135 | { 136 | return _width * _height * 4; 137 | } 138 | 139 | - (NSError *)error 140 | { 141 | return _error; 142 | } 143 | 144 | - (CFTimeInterval)durationAtIndex:(NSUInteger)index 145 | { 146 | return _durations[index]; 147 | } 148 | 149 | - (CGImageRef)imageAtIndex:(NSUInteger)index cacheProvider:(nullable id)cacheProvider 150 | { 151 | // I believe this is threadsafe as CGImageSource *seems* immutable… 152 | CGImageRef imageRef = 153 | CGImageSourceCreateImageAtIndex(_imageSource, 154 | index, 155 | (CFDictionaryRef)@{(__bridge NSString *)kCGImageSourceShouldCache: 156 | (__bridge NSNumber *)kCFBooleanFalse}); 157 | if (imageRef) { 158 | CGImageRef decodedImageRef = [PINImage pin_decodedImageRefWithCGImageRef:imageRef]; 159 | CGImageRelease(imageRef); 160 | imageRef = decodedImageRef; 161 | } 162 | 163 | return imageRef; 164 | } 165 | 166 | @end 167 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/Categories/NSData+ImageDetectors.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+ImageDetectors.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 11/19/14. 6 | // 7 | // 8 | 9 | #import "NSData+ImageDetectors.h" 10 | 11 | #if PIN_WEBP 12 | #if SWIFT_PACKAGE 13 | @import libwebp; 14 | #else 15 | #import "webp/demux.h" 16 | #endif 17 | #endif 18 | 19 | @implementation NSData (PINImageDetectors) 20 | 21 | - (BOOL)pin_isGIF 22 | { 23 | const NSInteger length = 3; 24 | Byte firstBytes[length]; 25 | if ([self length] >= length) { 26 | [self getBytes:&firstBytes length:length]; 27 | //G, I, F 28 | if (firstBytes[0] == 0x47 && firstBytes[1] == 0x49 && firstBytes[2] == 0x46) { 29 | return YES; 30 | } 31 | } 32 | return NO; 33 | } 34 | 35 | #define BREAK_IF_INVALID(position) if (position >= length) break; 36 | 37 | static inline BOOL advancePositionWithCount(NSUInteger *position, NSUInteger length, NSUInteger count) 38 | { 39 | if (*position + count >= length) { 40 | return NO; 41 | } 42 | *position = *position + count; 43 | 44 | return YES; 45 | } 46 | 47 | static inline BOOL advancePositionWithBytes(NSUInteger *position, Byte *bytes, NSUInteger length, NSUInteger count) 48 | { 49 | BOOL readAgain; 50 | do { 51 | readAgain = NO; 52 | if (*position + count >= length ) { 53 | return NO; 54 | } 55 | *position = *position + count; 56 | NSUInteger bytesToAdvance = *(bytes + *position); 57 | if (bytesToAdvance == 0xFF) { 58 | readAgain = YES; 59 | count = 0; 60 | } 61 | // Advance the byte read as well. 62 | bytesToAdvance++; 63 | 64 | if (*position + bytesToAdvance >= length) { 65 | return NO; 66 | } 67 | *position = *position + bytesToAdvance; 68 | } while (readAgain); 69 | 70 | return YES; 71 | } 72 | 73 | - (BOOL)pin_isAnimatedGIF 74 | { 75 | if ([self pin_isGIF] == NO) { 76 | return NO; 77 | } 78 | 79 | Byte *bytes = (Byte *)self.bytes; 80 | NSUInteger length = self.length; 81 | NSUInteger position = 0; 82 | NSUInteger GCECount = 0; 83 | 84 | while (bytes && position < length) { 85 | // Look for Graphic Control Extension 86 | if (*(bytes + position) == 0x21) { 87 | if (!advancePositionWithCount(&position, length, 1)) break; 88 | if (*(bytes + position) == 0xF9) { 89 | GCECount++; 90 | if (GCECount > 1) { 91 | break; 92 | } 93 | // Found GCE, advance to image. Next byte is size of GCE 94 | if (!advancePositionWithBytes(&position, bytes, length, 1)) break; 95 | // Advance 1 for 00 at the end of GCE 96 | if (!advancePositionWithCount(&position, length, 1)) break; 97 | // Advance image descriptor 98 | if (!advancePositionWithCount(&position, length, 11)) break; 99 | // Advance image 100 | if (!advancePositionWithBytes(&position, bytes, length, 0)) break; 101 | // Advance 1 for 00 at the end of image 102 | if (!advancePositionWithCount(&position, length, 1)) break; 103 | } 104 | continue; 105 | } 106 | if (!advancePositionWithCount(&position, length, 1)) break; 107 | } 108 | 109 | return GCECount > 1; 110 | } 111 | 112 | #if PIN_WEBP 113 | - (BOOL)pin_isWebP 114 | { 115 | const NSInteger length = 12; 116 | Byte firstBytes[length]; 117 | if ([self length] >= length) { 118 | [self getBytes:&firstBytes length:length]; 119 | //R, I, F, F, -, -, -, -, W, E, B, P 120 | if (firstBytes[0] == 0x52 && firstBytes[1] == 0x49 && firstBytes[2] == 0x46 && firstBytes[3] == 0x46 && firstBytes[8] == 0x57 && firstBytes[9] == 0x45 && firstBytes[10] == 0x42 && firstBytes[11] == 0x50) { 121 | return YES; 122 | } 123 | } 124 | return NO; 125 | } 126 | 127 | - (BOOL)pin_isAnimatedWebP 128 | { 129 | WebPBitstreamFeatures features; 130 | if (WebPGetFeatures([self bytes], [self length], &features) == VP8_STATUS_OK) { 131 | return features.has_animation; 132 | } 133 | 134 | return NO; 135 | } 136 | 137 | #endif 138 | 139 | @end 140 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/Categories/NSHTTPURLResponse+MaxAge.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSHTTPURLResponse+MaxAge.m 3 | // 4 | // Created by Kevin Smith on 6/15/18. 5 | // 6 | // 7 | 8 | #import 9 | 10 | @interface NSHTTPURLResponse (MaxAge) 11 | 12 | - (NSNumber *)findMaxAge; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/Categories/NSHTTPURLResponse+MaxAge.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSHTTPURLResponse+MaxAge.m 3 | // 4 | // Created by Kevin Smith on 6/15/18. 5 | // 6 | // 7 | 8 | #import "NSHTTPURLResponse+MaxAge.h" 9 | 10 | @implementation NSHTTPURLResponse (MaxAge) 11 | 12 | static NSDateFormatter *sharedFormatter; 13 | static dispatch_once_t sharedFormatterToken; 14 | 15 | + (NSDateFormatter *)RFC7231PreferredDateFormatter 16 | { 17 | dispatch_once(&sharedFormatterToken, ^{ 18 | NSLocale *enUSPOSIXLocale; 19 | 20 | sharedFormatter = [[NSDateFormatter alloc] init]; 21 | 22 | enUSPOSIXLocale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]; 23 | 24 | [sharedFormatter setLocale:enUSPOSIXLocale]; 25 | [sharedFormatter setDateFormat:@"E, d MMM yyyy HH:mm:ss Z"]; 26 | 27 | }); 28 | return sharedFormatter; 29 | } 30 | 31 | - (NSNumber *)findMaxAge 32 | { 33 | NSDictionary * headerFields = [self allHeaderFields]; 34 | NSNumber *maxAge = nil; 35 | 36 | for (NSString * component in [headerFields[@"Cache-Control"] componentsSeparatedByString:@","]) { 37 | NSString * trimmed = [[component stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] lowercaseString]; 38 | 39 | if ([trimmed isEqualToString:@"no-store"] || [trimmed isEqualToString:@"must-revalidate"] || [trimmed isEqualToString:@"no-cache"]) { 40 | maxAge = @(0); 41 | break; 42 | } else { 43 | // max-age 44 | NSArray * split = [trimmed componentsSeparatedByString:@"max-age="]; 45 | if ([split count] == 2) { 46 | // if the max-age provided is invalid (does not parse into an 47 | // int), we wind up with 0 which will be treated as do-not-cache. 48 | // This is the RFC defined behavior for a malformed "expires" header, 49 | // and while I cannot find any explicit instruction of how to behave 50 | // with a malformed "max-age" header, it seems like a reasonable approach. 51 | maxAge = @([split[1] integerValue]); 52 | } else if ([split count] > 2) { 53 | // very weird case "maxage=maxage=123" 54 | maxAge = @(0); 55 | } 56 | } 57 | } 58 | 59 | // If there is a Cache-Control header with the "max-age" directive in the response, the Expires header is ignored. 60 | if (!maxAge && headerFields[@"Expires"]) { 61 | NSString * expires = headerFields[@"Expires"]; 62 | NSDate * date = [[NSHTTPURLResponse RFC7231PreferredDateFormatter] dateFromString:expires]; 63 | 64 | // Invalid dates (notably "0") or dates in the past must not be cached (RFC7231 5.3) 65 | maxAge = @((NSInteger) MAX(([date timeIntervalSinceNow]), 0)); 66 | } 67 | 68 | return maxAge; 69 | } 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/Categories/PINImage+DecodedImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+DecodedImage.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 11/19/14. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #import "PINRemoteImageMacros.h" 12 | 13 | #if PIN_TARGET_IOS 14 | #import 15 | #elif PIN_TARGET_MAC 16 | #import 17 | #endif 18 | 19 | #if !PIN_TARGET_IOS 20 | @interface NSImage (PINiOSMapping) 21 | 22 | @property(nonatomic, readonly, nullable) CGImageRef CGImage; 23 | 24 | + (nullable NSImage *)imageWithData:(nonnull NSData *)imageData; 25 | + (nullable NSImage *)imageWithContentsOfFile:(nonnull NSString *)path; 26 | + (nonnull NSImage *)imageWithCGImage:(nonnull CGImageRef)imageRef; 27 | 28 | @end 29 | #endif 30 | 31 | NSData * __nullable PINImageJPEGRepresentation(PINImage * __nonnull image, CGFloat compressionQuality); 32 | NSData * __nullable PINImagePNGRepresentation(PINImage * __nonnull image); 33 | 34 | @interface PINImage (PINDecodedImage) 35 | 36 | + (nullable PINImage *)pin_decodedImageWithData:(nonnull NSData *)data; 37 | + (nullable PINImage *)pin_decodedImageWithData:(nonnull NSData *)data skipDecodeIfPossible:(BOOL)skipDecodeIfPossible; 38 | + (nullable PINImage *)pin_decodedImageWithCGImageRef:(nonnull CGImageRef)imageRef; 39 | #if PIN_TARGET_IOS 40 | + (nullable PINImage *)pin_decodedImageWithCGImageRef:(nonnull CGImageRef)imageRef orientation:(UIImageOrientation) orientation; 41 | #endif 42 | + (nullable CGImageRef)pin_decodedImageRefWithCGImageRef:(nonnull CGImageRef)imageRef; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/Categories/PINImage+ScaledImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+ScaledImage.h 3 | // Pods 4 | // 5 | // Created by Michael Schneider on 2/9/17. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #import "PINRemoteImageMacros.h" 12 | 13 | #if PIN_TARGET_IOS 14 | #import 15 | #elif PIN_TARGET_MAC 16 | #import 17 | #endif 18 | 19 | @interface PINImage (PINScaledImage) 20 | 21 | - (PINImage *)pin_scaledImageForKey:(NSString *)key; 22 | + (PINImage *)pin_scaledImageForImage:(PINImage *)image withKey:(NSString *)key; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/Categories/PINImage+ScaledImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+ScaledImage.m 3 | // Pods 4 | // 5 | // Created by Michael Schneider on 2/9/17. 6 | // 7 | // 8 | 9 | #import "PINImage+ScaledImage.h" 10 | 11 | static inline PINImage *PINScaledImageForKey(NSString * __nullable key, PINImage * __nullable image) { 12 | if (image == nil) { 13 | return nil; 14 | } 15 | 16 | #if PIN_TARGET_IOS 17 | 18 | NSCAssert(image.CGImage != NULL, @"CGImage should not be NULL"); 19 | 20 | CGFloat scale = 1.0; 21 | if (key.length >= 8) { 22 | if ([key rangeOfString:@"_2x."].location != NSNotFound || 23 | [key rangeOfString:@"@2x."].location != NSNotFound) { 24 | scale = 2.0; 25 | } 26 | 27 | if ([key rangeOfString:@"_3x."].location != NSNotFound || 28 | [key rangeOfString:@"@3x."].location != NSNotFound) { 29 | scale = 3.0; 30 | } 31 | } 32 | 33 | if (scale != image.scale) { 34 | return [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; 35 | } 36 | 37 | return image; 38 | 39 | #elif PIN_TARGET_MAC 40 | return image; 41 | #endif 42 | } 43 | 44 | @implementation PINImage (ScaledImage) 45 | 46 | - (PINImage *)pin_scaledImageForKey:(NSString *)key 47 | { 48 | return PINScaledImageForKey(key, self); 49 | } 50 | 51 | + (PINImage *)pin_scaledImageForImage:(PINImage *)image withKey:(NSString *)key 52 | { 53 | return PINScaledImageForKey(key, image); 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/Categories/PINImage+WebP.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+WebP.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 11/18/14. 6 | // 7 | // 8 | 9 | #import "PINRemoteImageMacros.h" 10 | 11 | #if PIN_WEBP 12 | 13 | #if PIN_TARGET_IOS 14 | #import 15 | #elif PIN_TARGET_MAC 16 | #import 17 | #endif 18 | 19 | @interface PINImage (PINWebP) 20 | 21 | + (PINImage *)pin_imageWithWebPData:(NSData *)webPData; 22 | 23 | @end 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/Categories/PINImage+WebP.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+WebP.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 11/18/14. 6 | // 7 | // 8 | 9 | #import "PINImage+WebP.h" 10 | 11 | #if PIN_WEBP 12 | 13 | #if SWIFT_PACKAGE 14 | @import libwebp; 15 | #else 16 | #import "webp/decode.h" 17 | #endif 18 | 19 | static void releaseData(void *info, const void *data, size_t size) 20 | { 21 | WebPFree((void *)data); 22 | } 23 | 24 | @implementation PINImage (PINWebP) 25 | 26 | + (PINImage *)pin_imageWithWebPData:(NSData *)webPData 27 | { 28 | WebPBitstreamFeatures features; 29 | if (WebPGetFeatures([webPData bytes], [webPData length], &features) == VP8_STATUS_OK) { 30 | // Decode the WebP image data into a RGBA value array 31 | int height, width; 32 | uint8_t *data = NULL; 33 | int pixelLength = 0; 34 | 35 | if (features.has_alpha) { 36 | data = WebPDecodeRGBA([webPData bytes], [webPData length], &width, &height); 37 | pixelLength = 4; 38 | } else { 39 | data = WebPDecodeRGB([webPData bytes], [webPData length], &width, &height); 40 | pixelLength = 3; 41 | } 42 | 43 | if (data) { 44 | CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, data, width * height * pixelLength, releaseData); 45 | 46 | CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); 47 | CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault; 48 | 49 | if (features.has_alpha) { 50 | bitmapInfo |= kCGImageAlphaLast; 51 | } else { 52 | bitmapInfo |= kCGImageAlphaNone; 53 | } 54 | 55 | CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; 56 | CGImageRef imageRef = CGImageCreate(width, 57 | height, 58 | 8, 59 | 8 * pixelLength, 60 | pixelLength * width, 61 | colorSpaceRef, 62 | bitmapInfo, 63 | provider, 64 | NULL, 65 | NO, 66 | renderingIntent); 67 | 68 | PINImage *image = nil; 69 | #if PIN_TARGET_IOS 70 | image = [UIImage imageWithCGImage:imageRef]; 71 | #elif PIN_TARGET_MAC 72 | image = [[self alloc] initWithCGImage:imageRef size:CGSizeZero]; 73 | #endif 74 | 75 | CGImageRelease(imageRef); 76 | CGColorSpaceRelease(colorSpaceRef); 77 | CGDataProviderRelease(provider); 78 | 79 | return image; 80 | } 81 | } 82 | return nil; 83 | } 84 | 85 | @end 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/Categories/PINRemoteImageTask+Subclassing.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageTask+Subclassing.h 3 | // PINRemoteImage 4 | // 5 | // Created by Garrett Moon on 5/22/17. 6 | // Copyright © 2017 Pinterest. All rights reserved. 7 | // 8 | 9 | #import "PINRemoteImageTask.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface PINRemoteImageTask (Subclassing) 14 | 15 | - (NSMutableDictionary *)l_callbackBlocks; 16 | - (BOOL)l_cancelWithUUID:(NSUUID *)UUID; 17 | 18 | @end 19 | 20 | NS_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/ImageCategories/PINAnimatedImageView+PINRemoteImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINAnimatedImageView+PINRemoteImage.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 4/19/18. 6 | // 7 | 8 | #import "PINAnimatedImageView+PINRemoteImage.h" 9 | 10 | #import "PINAnimatedImage.h" 11 | 12 | @implementation PINAnimatedImageView (PINRemoteImage) 13 | 14 | - (void)pin_setImageFromURL:(NSURL *)url 15 | { 16 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url]; 17 | } 18 | 19 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(PINImage *)placeholderImage 20 | { 21 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url placeholderImage:placeholderImage]; 22 | } 23 | 24 | - (void)pin_setImageFromURL:(NSURL *)url completion:(PINRemoteImageManagerImageCompletion)completion 25 | { 26 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url completion:completion]; 27 | } 28 | 29 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(PINImage *)placeholderImage completion:(PINRemoteImageManagerImageCompletion)completion 30 | { 31 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url placeholderImage:placeholderImage completion:completion]; 32 | } 33 | 34 | - (void)pin_setImageFromURL:(NSURL *)url processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor 35 | { 36 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url processorKey:processorKey processor:processor]; 37 | } 38 | 39 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(PINImage *)placeholderImage processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor 40 | { 41 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url placeholderImage:placeholderImage processorKey:processorKey processor:processor]; 42 | } 43 | 44 | - (void)pin_setImageFromURL:(NSURL *)url processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor completion:(PINRemoteImageManagerImageCompletion)completion 45 | { 46 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url processorKey:processorKey processor:processor completion:completion]; 47 | } 48 | 49 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(PINImage *)placeholderImage processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor completion:(PINRemoteImageManagerImageCompletion)completion 50 | { 51 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:@[url] placeholderImage:placeholderImage processorKey:processorKey processor:processor completion:completion]; 52 | } 53 | 54 | - (void)pin_setImageFromURLs:(NSArray *)urls 55 | { 56 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:urls]; 57 | } 58 | 59 | - (void)pin_setImageFromURLs:(NSArray *)urls placeholderImage:(PINImage *)placeholderImage 60 | { 61 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:urls placeholderImage:placeholderImage]; 62 | } 63 | 64 | - (void)pin_setImageFromURLs:(NSArray *)urls placeholderImage:(PINImage *)placeholderImage completion:(PINRemoteImageManagerImageCompletion)completion 65 | { 66 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:urls placeholderImage:placeholderImage completion:completion]; 67 | } 68 | 69 | - (void)pin_cancelImageDownload 70 | { 71 | [PINRemoteImageCategoryManager cancelImageDownloadOnView:self]; 72 | } 73 | 74 | - (NSUUID *)pin_downloadImageOperationUUID 75 | { 76 | return [PINRemoteImageCategoryManager downloadImageOperationUUIDOnView:self]; 77 | } 78 | 79 | - (void)pin_setDownloadImageOperationUUID:(NSUUID *)downloadImageOperationUUID 80 | { 81 | [PINRemoteImageCategoryManager setDownloadImageOperationUUID:downloadImageOperationUUID onView:self]; 82 | } 83 | 84 | - (BOOL)pin_updateWithProgress 85 | { 86 | return [PINRemoteImageCategoryManager updateWithProgressOnView:self]; 87 | } 88 | 89 | - (void)setPin_updateWithProgress:(BOOL)updateWithProgress 90 | { 91 | [PINRemoteImageCategoryManager setUpdateWithProgressOnView:updateWithProgress onView:self]; 92 | } 93 | 94 | - (void)pin_setPlaceholderWithImage:(PINImage *)image 95 | { 96 | self.image = image; 97 | } 98 | 99 | - (void)pin_updateUIWithRemoteImageManagerResult:(PINRemoteImageManagerResult *)result 100 | { 101 | if (result.alternativeRepresentation && [result.alternativeRepresentation isKindOfClass:[PINCachedAnimatedImage class]]) { 102 | self.animatedImage = (PINCachedAnimatedImage *)result.alternativeRepresentation; 103 | } else if (result.image) { 104 | self.image = result.image; 105 | } 106 | } 107 | 108 | - (void)pin_clearImages 109 | { 110 | self.animatedImage = nil; 111 | self.image = nil; 112 | } 113 | 114 | - (BOOL)pin_ignoreGIFs 115 | { 116 | return NO; 117 | } 118 | 119 | @end 120 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/ImageCategories/PINButton+PINRemoteImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIButton+PINRemoteImage.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 8/18/14. 6 | // 7 | // 8 | 9 | #import "PINButton+PINRemoteImage.h" 10 | 11 | @implementation PINButton (PINRemoteImage) 12 | 13 | - (void)pin_setImageFromURL:(NSURL *)url 14 | { 15 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url]; 16 | } 17 | 18 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(PINImage *)placeholderImage 19 | { 20 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url placeholderImage:placeholderImage]; 21 | } 22 | 23 | - (void)pin_setImageFromURL:(NSURL *)url completion:(PINRemoteImageManagerImageCompletion)completion 24 | { 25 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url completion:completion]; 26 | } 27 | 28 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(PINImage *)placeholderImage completion:(PINRemoteImageManagerImageCompletion)completion 29 | { 30 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url placeholderImage:placeholderImage completion:completion]; 31 | } 32 | 33 | - (void)pin_setImageFromURL:(NSURL *)url processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor 34 | { 35 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url processorKey:processorKey processor:processor]; 36 | } 37 | 38 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(PINImage *)placeholderImage processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor 39 | { 40 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url placeholderImage:placeholderImage processorKey:processorKey processor:processor]; 41 | } 42 | 43 | - (void)pin_setImageFromURL:(NSURL *)url processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor completion:(PINRemoteImageManagerImageCompletion)completion 44 | { 45 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url processorKey:processorKey processor:processor completion:completion]; 46 | } 47 | 48 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(PINImage *)placeholderImage processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor completion:(PINRemoteImageManagerImageCompletion)completion 49 | { 50 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:url?@[url]:nil placeholderImage:placeholderImage processorKey:processorKey processor:processor completion:completion]; 51 | } 52 | 53 | - (void)pin_setImageFromURLs:(NSArray *)urls 54 | { 55 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:urls]; 56 | } 57 | 58 | - (void)pin_setImageFromURLs:(NSArray *)urls placeholderImage:(PINImage *)placeholderImage 59 | { 60 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:urls placeholderImage:placeholderImage]; 61 | } 62 | 63 | - (void)pin_setImageFromURLs:(NSArray *)urls placeholderImage:(PINImage *)placeholderImage completion:(PINRemoteImageManagerImageCompletion)completion 64 | { 65 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:urls placeholderImage:placeholderImage completion:completion]; 66 | } 67 | 68 | - (void)pin_cancelImageDownload 69 | { 70 | [PINRemoteImageCategoryManager cancelImageDownloadOnView:self]; 71 | } 72 | 73 | - (NSUUID *)pin_downloadImageOperationUUID 74 | { 75 | return [PINRemoteImageCategoryManager downloadImageOperationUUIDOnView:self]; 76 | } 77 | 78 | - (void)pin_setDownloadImageOperationUUID:(NSUUID *)downloadImageOperationUUID 79 | { 80 | [PINRemoteImageCategoryManager setDownloadImageOperationUUID:downloadImageOperationUUID onView:self]; 81 | } 82 | 83 | - (BOOL)pin_updateWithProgress 84 | { 85 | return [PINRemoteImageCategoryManager updateWithProgressOnView:self]; 86 | } 87 | 88 | - (void)setPin_updateWithProgress:(BOOL)updateWithProgress 89 | { 90 | [PINRemoteImageCategoryManager setUpdateWithProgressOnView:updateWithProgress onView:self]; 91 | } 92 | 93 | - (void)pin_setPlaceholderWithImage:(PINImage *)image 94 | { 95 | #if PIN_TARGET_IOS 96 | [self setImage:image forState:UIControlStateNormal]; 97 | #elif PIN_TARGET_MAC 98 | [self setImage:image]; 99 | #endif 100 | } 101 | 102 | - (void)pin_updateUIWithRemoteImageManagerResult:(PINRemoteImageManagerResult *)result 103 | { 104 | if (result.image) { 105 | #if PIN_TARGET_IOS 106 | [self setImage:result.image forState:UIControlStateNormal]; 107 | [self setNeedsLayout]; 108 | #elif PIN_TARGET_MAC 109 | [self setImage:result.image]; 110 | [self setNeedsLayout:YES]; 111 | #endif 112 | } 113 | } 114 | 115 | - (void)pin_clearImages 116 | { 117 | #if PIN_TARGET_IOS 118 | [self setImage:nil forState:UIControlStateNormal]; 119 | [self setNeedsLayout]; 120 | #elif PIN_TARGET_MAC 121 | [self setImage:nil]; 122 | [self setNeedsLayout:YES]; 123 | #endif 124 | } 125 | 126 | - (BOOL)pin_ignoreGIFs 127 | { 128 | return YES; 129 | } 130 | 131 | @end 132 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/ImageCategories/PINImageView+PINRemoteImage.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImageView+PINRemoteImage.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 8/17/14. 6 | // 7 | // 8 | 9 | #import "PINImageView+PINRemoteImage.h" 10 | 11 | @implementation PINImageView (PINRemoteImage) 12 | 13 | - (void)pin_setImageFromURL:(NSURL *)url 14 | { 15 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url]; 16 | } 17 | 18 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(PINImage *)placeholderImage 19 | { 20 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url placeholderImage:placeholderImage]; 21 | } 22 | 23 | - (void)pin_setImageFromURL:(NSURL *)url completion:(PINRemoteImageManagerImageCompletion)completion 24 | { 25 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url completion:completion]; 26 | } 27 | 28 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(PINImage *)placeholderImage completion:(PINRemoteImageManagerImageCompletion)completion 29 | { 30 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url placeholderImage:placeholderImage completion:completion]; 31 | } 32 | 33 | - (void)pin_setImageFromURL:(NSURL *)url processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor 34 | { 35 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url processorKey:processorKey processor:processor]; 36 | } 37 | 38 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(PINImage *)placeholderImage processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor 39 | { 40 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url placeholderImage:placeholderImage processorKey:processorKey processor:processor]; 41 | } 42 | 43 | - (void)pin_setImageFromURL:(NSURL *)url processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor completion:(PINRemoteImageManagerImageCompletion)completion 44 | { 45 | [PINRemoteImageCategoryManager setImageOnView:self fromURL:url processorKey:processorKey processor:processor completion:completion]; 46 | } 47 | 48 | - (void)pin_setImageFromURL:(NSURL *)url placeholderImage:(PINImage *)placeholderImage processorKey:(NSString *)processorKey processor:(PINRemoteImageManagerImageProcessor)processor completion:(PINRemoteImageManagerImageCompletion)completion 49 | { 50 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:url?@[url]:nil placeholderImage:placeholderImage processorKey:processorKey processor:processor completion:completion]; 51 | } 52 | 53 | - (void)pin_setImageFromURLs:(NSArray *)urls 54 | { 55 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:urls]; 56 | } 57 | 58 | - (void)pin_setImageFromURLs:(NSArray *)urls placeholderImage:(PINImage *)placeholderImage 59 | { 60 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:urls placeholderImage:placeholderImage]; 61 | } 62 | 63 | - (void)pin_setImageFromURLs:(NSArray *)urls placeholderImage:(PINImage *)placeholderImage completion:(PINRemoteImageManagerImageCompletion)completion 64 | { 65 | [PINRemoteImageCategoryManager setImageOnView:self fromURLs:urls placeholderImage:placeholderImage completion:completion]; 66 | } 67 | 68 | - (void)pin_cancelImageDownload 69 | { 70 | [PINRemoteImageCategoryManager cancelImageDownloadOnView:self]; 71 | } 72 | 73 | - (NSUUID *)pin_downloadImageOperationUUID 74 | { 75 | return [PINRemoteImageCategoryManager downloadImageOperationUUIDOnView:self]; 76 | } 77 | 78 | - (void)pin_setDownloadImageOperationUUID:(NSUUID *)downloadImageOperationUUID 79 | { 80 | [PINRemoteImageCategoryManager setDownloadImageOperationUUID:downloadImageOperationUUID onView:self]; 81 | } 82 | 83 | - (BOOL)pin_updateWithProgress 84 | { 85 | return [PINRemoteImageCategoryManager updateWithProgressOnView:self]; 86 | } 87 | 88 | - (void)setPin_updateWithProgress:(BOOL)updateWithProgress 89 | { 90 | [PINRemoteImageCategoryManager setUpdateWithProgressOnView:updateWithProgress onView:self]; 91 | } 92 | 93 | - (void)pin_setPlaceholderWithImage:(PINImage *)image 94 | { 95 | self.image = image; 96 | } 97 | 98 | - (void)pin_updateUIWithRemoteImageManagerResult:(PINRemoteImageManagerResult *)result 99 | { 100 | if (result.image) { 101 | self.image = result.image; 102 | 103 | #if PIN_TARGET_IOS 104 | [self setNeedsLayout]; 105 | #elif PIN_TARGET_MAC 106 | [self setNeedsLayout:YES]; 107 | #endif 108 | } 109 | } 110 | 111 | - (void)pin_clearImages 112 | { 113 | self.image = nil; 114 | 115 | #if PIN_TARGET_IOS 116 | [self setNeedsLayout]; 117 | #elif PIN_TARGET_MAC 118 | [self setNeedsLayout:YES]; 119 | #endif 120 | } 121 | 122 | - (BOOL)pin_ignoreGIFs 123 | { 124 | return YES; 125 | } 126 | 127 | @end 128 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINAlternateRepresentationProvider.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINAlternateRepresentationProvider.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/17/16. 6 | // 7 | // 8 | 9 | #import "PINAlternateRepresentationProvider.h" 10 | 11 | #import "PINCachedAnimatedImage.h" 12 | #import "NSData+ImageDetectors.h" 13 | 14 | @implementation PINAlternateRepresentationProvider 15 | 16 | - (id)alternateRepresentationWithData:(NSData *)data options:(PINRemoteImageManagerDownloadOptions)options 17 | { 18 | #if PIN_WEBP 19 | if ([data pin_isAnimatedGIF] || [data pin_isAnimatedWebP]) { 20 | return [[PINCachedAnimatedImage alloc] initWithAnimatedImageData:data]; 21 | } 22 | #else 23 | if ([data pin_isAnimatedGIF]) { 24 | return [[PINCachedAnimatedImage alloc] initWithAnimatedImageData:data]; 25 | } 26 | #endif 27 | return nil; 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINDisplayLink.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINDisplayLink.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 4/23/18. 6 | // 7 | 8 | #import 9 | 10 | #import "PINRemoteImageMacros.h" 11 | 12 | #if PIN_TARGET_IOS 13 | #define PINDisplayLink CADisplayLink 14 | #elif PIN_TARGET_MAC 15 | @interface PINDisplayLink : NSObject 16 | 17 | + (PINDisplayLink *)displayLinkWithTarget:(id)target selector:(SEL)sel; 18 | - (void)addToRunLoop:(NSRunLoop *)runloop forMode:(NSRunLoopMode)mode; 19 | - (void)removeFromRunLoop:(NSRunLoop *)runloop forMode:(NSRunLoopMode)mode; 20 | 21 | @property(getter=isPaused, nonatomic) BOOL paused; 22 | @property(nonatomic) NSInteger frameInterval; 23 | 24 | @end 25 | #endif 26 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINDisplayLink.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINDisplayLink.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 4/23/18. 6 | // 7 | 8 | #import "PINDisplayLink.h" 9 | 10 | #if PIN_TARGET_MAC 11 | 12 | #if SWIFT_PACKAGE 13 | @import CoreVideo.CVDisplayLink; 14 | #else 15 | #import 16 | #endif 17 | 18 | @interface PINDisplayLink () 19 | 20 | @property (nonatomic, readonly) id target; 21 | @property (nonatomic, readonly) SEL selector; 22 | @property (nonatomic, readonly) NSRunLoop *runloop; 23 | @property (nonatomic, readonly) NSRunLoopMode mode; 24 | 25 | - (void)displayLinkFired; 26 | 27 | @end 28 | 29 | static CVReturn displayLinkFired (CVDisplayLinkRef displayLink, 30 | const CVTimeStamp *inNow, 31 | const CVTimeStamp *inOutputTime, 32 | CVOptionFlags flagsIn, 33 | CVOptionFlags *flagsOut, 34 | void *displayLinkContext) 35 | { 36 | PINDisplayLink *link = (__bridge PINDisplayLink *)displayLinkContext; 37 | [link displayLinkFired]; 38 | return kCVReturnSuccess; 39 | } 40 | 41 | @implementation PINDisplayLink 42 | { 43 | CVDisplayLinkRef _displayLinkRef; 44 | 45 | BOOL _paused; 46 | NSInteger _frameInterval; 47 | } 48 | 49 | + (PINDisplayLink *)displayLinkWithTarget:(id)target selector:(SEL)sel 50 | { 51 | return [[PINDisplayLink alloc] initWithTarget:target selector:sel]; 52 | } 53 | 54 | - (PINDisplayLink *)initWithTarget:(id)target selector:(SEL)sel 55 | { 56 | if (self = [super init]) { 57 | _target = target; 58 | _selector = sel; 59 | CVDisplayLinkCreateWithActiveCGDisplays(&_displayLinkRef); 60 | CVDisplayLinkSetOutputCallback(_displayLinkRef, &displayLinkFired, (__bridge void * _Nullable)(self)); 61 | } 62 | return self; 63 | } 64 | 65 | - (void)dealloc 66 | { 67 | if (_displayLinkRef) { 68 | CVDisplayLinkRelease(_displayLinkRef); 69 | } 70 | } 71 | 72 | - (void)displayLinkFired 73 | { 74 | dispatch_async(dispatch_get_main_queue(), ^{ 75 | [self.runloop performSelector:self.selector target:self.target argument:self order:NSUIntegerMax modes:@[self.mode]]; 76 | }); 77 | } 78 | 79 | - (void)addToRunLoop:(NSRunLoop *)runloop forMode:(NSRunLoopMode)mode 80 | { 81 | PINAssertMain(); 82 | NSAssert(runloop && mode, @"Must set a runloop and a mode."); 83 | _runloop = runloop; 84 | _mode = mode; 85 | if (_paused == NO) { 86 | CVDisplayLinkStart(_displayLinkRef); 87 | } 88 | } 89 | 90 | - (void)removeFromRunLoop:(NSRunLoop *)runloop forMode:(NSRunLoopMode)mode 91 | { 92 | _runloop = nil; 93 | _mode = nil; 94 | if (_paused == NO) { 95 | CVDisplayLinkStop(_displayLinkRef); 96 | } 97 | } 98 | 99 | - (BOOL)isPaused 100 | { 101 | PINAssertMain(); 102 | return _paused; 103 | } 104 | 105 | - (void)setPaused:(BOOL)paused 106 | { 107 | PINAssertMain(); 108 | if (_paused == paused) { 109 | return; 110 | } 111 | 112 | _paused = paused; 113 | if (paused) { 114 | CVDisplayLinkStop(_displayLinkRef); 115 | } else { 116 | CVDisplayLinkStart(_displayLinkRef); 117 | } 118 | } 119 | 120 | - (NSInteger)frameInterval 121 | { 122 | PINAssertMain(); 123 | return _frameInterval; 124 | } 125 | 126 | - (void)setFrameInterval:(NSInteger)frameInterval 127 | { 128 | PINAssertMain(); 129 | _frameInterval = frameInterval; 130 | } 131 | 132 | @end 133 | #endif 134 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRemoteImageBasicCache.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageBasicCache.h 3 | // Pods 4 | // 5 | // Created by Aleksei Shevchenko on 7/28/16. 6 | // 7 | // 8 | 9 | #import 10 | #import "PINRemoteImageCaching.h" 11 | 12 | /** 13 | * Simplistic wrapper based on NSCache. 14 | * 15 | * No data is persisted on disk. The disk cache methods are no-op. 16 | */ 17 | @interface PINRemoteImageBasicCache : NSObject 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRemoteImageBasicCache.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageBasicCache.m 3 | // Pods 4 | // 5 | // Created by Aleksei Shevchenko on 7/28/16. 6 | // 7 | // 8 | 9 | #import "PINRemoteImageBasicCache.h" 10 | 11 | @interface PINRemoteImageBasicCache() 12 | @property (nonatomic, strong) NSCache *cache; 13 | @end 14 | 15 | @implementation PINRemoteImageBasicCache 16 | 17 | - (instancetype)init 18 | { 19 | self = [super init]; 20 | if (self) { 21 | self.cache = [[NSCache alloc] init]; 22 | } 23 | return self; 24 | } 25 | 26 | //****************************************************************************************************** 27 | // Memory cache methods 28 | //****************************************************************************************************** 29 | -(nullable id)objectFromMemoryForKey:(NSString *)key 30 | { 31 | return [self.cache objectForKey:key]; 32 | } 33 | 34 | -(void)setObjectInMemory:(id)object forKey:(NSString *)key withCost:(NSUInteger)cost 35 | { 36 | [self.cache setObject:object forKey:key cost:cost]; 37 | } 38 | 39 | - (void)removeObjectForKeyFromMemory:(NSString *)key 40 | { 41 | [self.cache removeObjectForKey:key]; 42 | } 43 | 44 | //****************************************************************************************************** 45 | // Disk cache methods 46 | //****************************************************************************************************** 47 | -(nullable id)objectFromDiskForKey:(NSString *)key 48 | { 49 | return nil; 50 | } 51 | 52 | -(void)objectFromDiskForKey:(NSString *)key completion:(PINRemoteImageCachingObjectBlock)completion 53 | { 54 | __weak typeof(self) weakSelf = self; 55 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 56 | if (completion) { 57 | typeof(self) strongSelf = weakSelf; 58 | completion(strongSelf, key, nil); 59 | } 60 | }); 61 | } 62 | 63 | -(void)setObjectOnDisk:(id)object forKey:(NSString *)key 64 | { 65 | 66 | } 67 | 68 | //****************************************************************************************************** 69 | // Common methods, should apply to both in-memory and disk storage 70 | //****************************************************************************************************** 71 | - (BOOL)objectExistsForKey:(NSString *)key 72 | { 73 | return [self.cache objectForKey:key] != nil; 74 | } 75 | 76 | - (void)removeObjectForKey:(NSString *)key 77 | { 78 | [self.cache removeObjectForKey:key]; 79 | } 80 | 81 | - (void)removeObjectForKey:(NSString *)key completion:(PINRemoteImageCachingObjectBlock)completion 82 | { 83 | __weak typeof(self) weakSelf = self; 84 | id object = [self.cache objectForKey:key]; 85 | [self.cache removeObjectForKey:key]; 86 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 87 | if (completion) { 88 | typeof(self) strongSelf = weakSelf; 89 | completion(strongSelf, key, object); 90 | } 91 | }); 92 | } 93 | 94 | - (void)removeAllObjects 95 | { 96 | [self.cache removeAllObjects]; 97 | } 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRemoteImageCallbacks.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageCallbacks.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/9/15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #import "PINRemoteImageManager.h" 12 | 13 | @interface PINRemoteImageCallbacks : NSObject 14 | 15 | @property (atomic, strong, nullable) PINRemoteImageManagerImageCompletion completionBlock; 16 | @property (atomic, strong, nullable) PINRemoteImageManagerImageCompletion progressImageBlock; 17 | @property (atomic, strong, nullable) PINRemoteImageManagerProgressDownload progressDownloadBlock; 18 | @property (assign, readonly) CFTimeInterval requestTime; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRemoteImageCallbacks.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageCallbacks.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/9/15. 6 | // 7 | // 8 | 9 | #import "PINRemoteImageCallbacks.h" 10 | 11 | @implementation PINRemoteImageCallbacks 12 | 13 | - (instancetype)init 14 | { 15 | if (self = [super init]) { 16 | _requestTime = CACurrentMediaTime(); 17 | } 18 | return self; 19 | } 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRemoteImageDownloadQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageDownloadQueue.h 3 | // PINRemoteImage 4 | // 5 | // Created by Garrett Moon on 3/1/17. 6 | // Copyright © 2017 Pinterest. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "PINRemoteImageManager.h" 12 | 13 | @class PINURLSessionManager; 14 | 15 | NS_ASSUME_NONNULL_BEGIN 16 | 17 | typedef void (^PINRemoteImageDownloadCompletion)(NSURLResponse * _Nullable response, NSError *error); 18 | 19 | @interface PINRemoteImageDownloadQueue : NSObject 20 | 21 | @property (atomic, assign) NSUInteger maxNumberOfConcurrentDownloads; 22 | 23 | - (instancetype)init NS_UNAVAILABLE; 24 | + (PINRemoteImageDownloadQueue *)queueWithMaxConcurrentDownloads:(NSUInteger)maxNumberOfConcurrentDownloads; 25 | 26 | - (NSURLSessionDataTask *)addDownloadWithSessionManager:(PINURLSessionManager *)sessionManager 27 | request:(NSURLRequest *)request 28 | priority:(PINRemoteImageManagerPriority)priority 29 | completionHandler:(PINRemoteImageDownloadCompletion)completionHandler; 30 | 31 | /*** 32 | This prevents a task from being run if it hasn't already started yet. It is the caller's responsibility to cancel 33 | the task if it has already been started. 34 | 35 | @return BOOL Returns YES if the task was in the queue. 36 | */ 37 | - (BOOL)removeDownloadTaskFromQueue:(NSURLSessionDataTask *)downloadTask; 38 | 39 | /* 40 | This sets the tasks priority of execution. It is the caller's responsibility to set the priority on the task itself 41 | for NSURLSessionManager. 42 | */ 43 | - (void)setQueuePriority:(PINRemoteImageManagerPriority)priority forTask:(NSURLSessionDataTask *)downloadTask; 44 | 45 | NS_ASSUME_NONNULL_END 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRemoteImageDownloadTask.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageDownloadTask.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/9/15. 6 | // 7 | // 8 | 9 | #if SWIFT_PACKAGE 10 | @import PINOperation; 11 | #else 12 | #import 13 | #endif 14 | 15 | #import "PINRemoteImageManager+Private.h" 16 | #import "PINRemoteImageTask.h" 17 | #import "PINProgressiveImage.h" 18 | #import "PINResume.h" 19 | 20 | @interface PINRemoteImageDownloadTask : PINRemoteImageTask 21 | 22 | @property (nonatomic, strong, nullable, readonly) NSURL *URL; 23 | @property (nonatomic, copy, nullable) NSString *ifRange; 24 | @property (nonatomic, copy, readonly, nullable) NSData *data; 25 | 26 | @property (nonatomic, readonly) CFTimeInterval estimatedRemainingTime; 27 | 28 | - (void)scheduleDownloadWithRequest:(nonnull NSURLRequest *)request 29 | resume:(nullable PINResume *)resume 30 | skipRetry:(BOOL)skipRetry 31 | priority:(PINRemoteImageManagerPriority)priority 32 | completionHandler:(nonnull PINRemoteImageManagerDataCompletion)completionHandler; 33 | 34 | - (void)didReceiveData:(nonnull NSData *)data; 35 | - (void)didReceiveResponse:(nonnull NSURLResponse *)response; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRemoteImageManager+Private.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageManager+Private.h 3 | // PINRemoteImage 4 | // 5 | // Created by Garrett Moon on 5/18/17. 6 | // Copyright © 2017 Pinterest. All rights reserved. 7 | // 8 | 9 | #ifndef PINRemoteImageManager_Private_h 10 | #define PINRemoteImageManager_Private_h 11 | 12 | #import "PINRemoteImageDownloadQueue.h" 13 | 14 | typedef void (^PINRemoteImageManagerDataCompletion)(NSData *data, NSURLResponse *response, NSError *error); 15 | 16 | @interface PINRemoteImageManager (PrivateExtension) 17 | 18 | @property (nonatomic, strong, readonly) dispatch_queue_t callbackQueue; 19 | @property (nonatomic, strong, readonly) PINOperationQueue *concurrentOperationQueue; 20 | @property (nonatomic, strong, readonly) PINRemoteImageDownloadQueue *urlSessionTaskQueue; 21 | @property (nonatomic, strong, readonly) PINURLSessionManager *sessionManager; 22 | 23 | @property (nonatomic, readonly) NSArray *progressThresholds; 24 | @property (nonatomic, readonly) NSTimeInterval estimatedRemainingTimeThreshold; 25 | @property (nonatomic, readonly) BOOL shouldBlurProgressive; 26 | @property (nonatomic, readonly) CGSize maxProgressiveRenderSize; 27 | 28 | @end 29 | 30 | #endif /* PINRemoteImageManager_Private_h */ 31 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRemoteImageManagerConfiguration.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageManagerConfiguration.h 3 | // Pods 4 | // 5 | // Created by Ryan Quan on 2/22/19. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #import "PINRemoteImageMacros.h" 12 | 13 | #if PIN_TARGET_IOS 14 | #import 15 | #elif PIN_TARGET_MAC 16 | #import 17 | #endif 18 | 19 | /** A configuration object used to customize a PINRemoteImageManager instance **/ 20 | @interface PINRemoteImageManagerConfiguration : NSObject 21 | 22 | /** The maximum number of concurrent operations. Defaults to NSOperationQueueDefaultMaxConcurrentOperationCount. */ 23 | @property (nonatomic, readwrite, assign) NSUInteger maxConcurrentOperations; 24 | 25 | /** The maximum number of concurrent downloads. Defaults to 10, maximum 65535. */ 26 | @property (nonatomic, readwrite, assign) NSUInteger maxConcurrentDownloads; 27 | 28 | /** The estimated remaining time threshold used to decide to skip progressive rendering. Defaults to 0.1. */ 29 | @property (nonatomic, readwrite, assign) NSTimeInterval estimatedRemainingTimeThreshold; 30 | 31 | /** A bool value indicating whether PINRemoteImage should blur progressive render results */ 32 | @property (nonatomic, readwrite, assign) BOOL shouldBlurProgressive; 33 | 34 | /** A CGSize which indicates the max size PINRemoteImage will render a progressive image. If an image is larger in either dimension, progressive rendering will be skipped */ 35 | @property (nonatomic, readwrite, assign) CGSize maxProgressiveRenderSize; 36 | 37 | /** The minimum BPS to download the highest quality image in a set. */ 38 | @property (nonatomic, readwrite, assign) float highQualityBPSThreshold; 39 | 40 | /** The maximum BPS to download the lowest quality image in a set. */ 41 | @property (nonatomic, readwrite, assign) float lowQualityBPSThreshold; 42 | 43 | /** Whether high quality images should be downloaded when a low quality image is cached if network connectivity has improved. */ 44 | @property (nonatomic, readwrite, assign) BOOL shouldUpgradeLowQualityImages; 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRemoteImageManagerConfiguration.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageManagerConfiguration.m 3 | // Pods 4 | // 5 | // Created by Ryan Quan on 2/22/19. 6 | // 7 | // 8 | 9 | #import "PINRemoteImageManagerConfiguration.h" 10 | 11 | #import "PINRemoteImageManager.h" 12 | 13 | @implementation PINRemoteImageManagerConfiguration 14 | 15 | - (nonnull instancetype)init { 16 | if (self = [super init]) { 17 | _maxConcurrentOperations = [[NSProcessInfo processInfo] activeProcessorCount] * 2; 18 | _maxConcurrentDownloads = 10; 19 | _estimatedRemainingTimeThreshold = 0.1; 20 | _shouldBlurProgressive = YES; 21 | _maxProgressiveRenderSize = CGSizeMake(1024, 1024); 22 | _highQualityBPSThreshold = 500000; 23 | _lowQualityBPSThreshold = 50000; // approximately edge speed 24 | _shouldUpgradeLowQualityImages = NO; 25 | } 26 | return self; 27 | } 28 | 29 | #pragma mark - Setters 30 | 31 | - (void)setMaxConcurrentDownloads:(NSUInteger)maxConcurrentDownloads { 32 | NSAssert(maxConcurrentDownloads <= PINRemoteImageHTTPMaximumConnectionsPerHost, @"maxNumberOfConcurrentDownloads must be less than or equal to %d", PINRemoteImageHTTPMaximumConnectionsPerHost); 33 | _maxConcurrentDownloads = maxConcurrentDownloads; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRemoteImageManagerResult.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageManagerResult.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/9/15. 6 | // 7 | // 8 | 9 | #import "PINRemoteImageManagerResult.h" 10 | 11 | @implementation PINRemoteImageManagerResult 12 | 13 | + (nonnull instancetype)imageResultWithImage:(nullable PINImage *)image 14 | alternativeRepresentation:(nullable id)alternativeRepresentation 15 | requestLength:(NSTimeInterval)requestLength 16 | resultType:(PINRemoteImageResultType)resultType 17 | UUID:(nullable NSUUID *)uuid 18 | response:(nullable NSURLResponse *)response 19 | error:(nullable NSError *)error 20 | { 21 | return [self imageResultWithImage:image 22 | alternativeRepresentation:alternativeRepresentation 23 | requestLength:requestLength 24 | resultType:resultType 25 | UUID:uuid 26 | response:response 27 | error:error 28 | renderedImageQuality:1.0]; 29 | } 30 | 31 | + (nonnull instancetype)imageResultWithImage:(nullable PINImage *)image 32 | alternativeRepresentation:(nullable id)alternativeRepresentation 33 | requestLength:(NSTimeInterval)requestLength 34 | resultType:(PINRemoteImageResultType)resultType 35 | UUID:(nullable NSUUID *)uuid 36 | response:(nullable NSURLResponse *)response 37 | error:(nullable NSError *)error 38 | bytesSavedByResuming:(NSUInteger)bytesSavedByResuming 39 | { 40 | return [[self alloc] initWithImage:image 41 | alternativeRepresentation:alternativeRepresentation 42 | requestLength:requestLength 43 | error:error 44 | resultType:resultType 45 | UUID:uuid 46 | response:response 47 | renderedImageQuality:1.0 48 | bytesSavedByResuming:bytesSavedByResuming]; 49 | } 50 | 51 | + (nonnull instancetype)imageResultWithImage:(nullable PINImage *)image 52 | alternativeRepresentation:(nullable id)alternativeRepresentation 53 | requestLength:(NSTimeInterval)requestLength 54 | resultType:(PINRemoteImageResultType)resultType 55 | UUID:(nullable NSUUID *)uuid 56 | response:(nullable NSURLResponse *)response 57 | error:(nullable NSError *)error 58 | renderedImageQuality:(CGFloat)renderedImageQuality 59 | { 60 | return [[self alloc] initWithImage:image 61 | alternativeRepresentation:alternativeRepresentation 62 | requestLength:requestLength 63 | error:error 64 | resultType:resultType 65 | UUID:uuid 66 | response:response 67 | renderedImageQuality:renderedImageQuality 68 | bytesSavedByResuming:0]; 69 | } 70 | 71 | - (instancetype)initWithImage:(PINImage *)image 72 | alternativeRepresentation:(id)alternativeRepresentation 73 | requestLength:(NSTimeInterval)requestLength 74 | error:(NSError *)error 75 | resultType:(PINRemoteImageResultType)resultType 76 | UUID:(NSUUID *)uuid 77 | response:(NSURLResponse *)response 78 | renderedImageQuality:(CGFloat)renderedImageQuality 79 | bytesSavedByResuming:(NSUInteger)bytesSavedByResuming; 80 | { 81 | if (self = [super init]) { 82 | _image = image; 83 | _alternativeRepresentation = alternativeRepresentation; 84 | _requestDuration = requestLength; 85 | _error = error; 86 | _resultType = resultType; 87 | _UUID = uuid; 88 | _response = response; 89 | _renderedImageQuality = renderedImageQuality; 90 | _bytesSavedByResuming = bytesSavedByResuming; 91 | } 92 | return self; 93 | } 94 | 95 | - (NSString *)description 96 | { 97 | NSString *description = [super description]; 98 | description = [description stringByAppendingString:[NSString stringWithFormat:@"image: %@", self.image]]; 99 | description = [description stringByAppendingString:@"\n"]; 100 | description = [description stringByAppendingString:[NSString stringWithFormat:@"alternativeRepresentation: %@", self.alternativeRepresentation]]; 101 | description = [description stringByAppendingString:@"\n"]; 102 | description = [description stringByAppendingString:[NSString stringWithFormat:@"requestDuration: %f", self.requestDuration]]; 103 | description = [description stringByAppendingString:@"\n"]; 104 | description = [description stringByAppendingString:[NSString stringWithFormat:@"error: %@", self.error]]; 105 | description = [description stringByAppendingString:@"\n"]; 106 | description = [description stringByAppendingString:[NSString stringWithFormat:@"resultType: %lu", (unsigned long)self.resultType]]; 107 | description = [description stringByAppendingString:@"\n"]; 108 | description = [description stringByAppendingString:[NSString stringWithFormat:@"UUID: %@", self.UUID]]; 109 | description = [description stringByAppendingString:@"\n"]; 110 | description = [description stringByAppendingString:[NSString stringWithFormat:@"response: %@", self.response]]; 111 | description = [description stringByAppendingString:@"\n"]; 112 | description = [description stringByAppendingString:[NSString stringWithFormat:@"renderedImageQuality: %f", self.renderedImageQuality]]; 113 | description = [description stringByAppendingString:@"\n"]; 114 | description = [description stringByAppendingString:[NSString stringWithFormat:@"bytesSavedByResuming: %lu", (unsigned long)self.bytesSavedByResuming]]; 115 | return description; 116 | } 117 | 118 | @end 119 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRemoteImageMemoryContainer.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageMemoryContainer.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/17/16. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #import "PINRemoteImageMacros.h" 12 | #import "PINRemoteLock.h" 13 | 14 | @class PINImage; 15 | 16 | @interface PINRemoteImageMemoryContainer : NSObject 17 | 18 | @property (nonatomic, strong) PINImage *image; 19 | @property (nonatomic, strong) NSData *data; 20 | @property (nonatomic, strong) PINRemoteLock *lock; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRemoteImageMemoryContainer.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageMemoryContainer.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/17/16. 6 | // 7 | // 8 | 9 | #import "PINRemoteImageMemoryContainer.h" 10 | 11 | @implementation PINRemoteImageMemoryContainer 12 | 13 | - (instancetype)init 14 | { 15 | if (self = [super init]) { 16 | _lock = [[PINRemoteLock alloc] initWithName:@"PINRemoteImageMemoryContainer" lockType:PINRemoteLockTypeNonRecursive]; 17 | } 18 | return self; 19 | } 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRemoteImageProcessorTask.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageProcessorTask.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/9/15. 6 | // 7 | // 8 | 9 | #import "PINRemoteImageTask.h" 10 | 11 | @interface PINRemoteImageProcessorTask : PINRemoteImageTask 12 | 13 | @property (nonatomic, strong, nullable) NSUUID *downloadTaskUUID; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRemoteImageProcessorTask.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageProcessorTask.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/9/15. 6 | // 7 | // 8 | 9 | #import "PINRemoteImageProcessorTask.h" 10 | 11 | @implementation PINRemoteImageProcessorTask 12 | 13 | @synthesize downloadTaskUUID = _downloadTaskUUID; 14 | 15 | - (BOOL)cancelWithUUID:(NSUUID *)UUID resume:(PINResume **)resume 16 | { 17 | BOOL noMoreCompletions = [super cancelWithUUID:UUID resume:resume]; 18 | [self.lock lockWithBlock:^{ 19 | if (noMoreCompletions && self->_downloadTaskUUID) { 20 | [self.manager cancelTaskWithUUID:self->_downloadTaskUUID]; 21 | self->_downloadTaskUUID = nil; 22 | } 23 | }]; 24 | return noMoreCompletions; 25 | } 26 | 27 | - (void)setDownloadTaskUUID:(NSUUID *)downloadTaskUUID 28 | { 29 | [self.lock lockWithBlock:^{ 30 | NSAssert(self->_downloadTaskUUID == nil, @"downloadTaskUUID should be nil"); 31 | self->_downloadTaskUUID = downloadTaskUUID; 32 | }]; 33 | } 34 | 35 | - (NSUUID *)downloadTaskUUID 36 | { 37 | __block NSUUID *downloadTaskUUID; 38 | [self.lock lockWithBlock:^{ 39 | downloadTaskUUID = self->_downloadTaskUUID; 40 | }]; 41 | return downloadTaskUUID; 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRemoteImageTask.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageTask.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/9/15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #if SWIFT_PACKAGE 12 | @import PINOperation; 13 | #else 14 | #import 15 | #endif 16 | 17 | #import "PINRemoteImageCallbacks.h" 18 | #import "PINRemoteImageManager.h" 19 | #import "PINRemoteImageMacros.h" 20 | #import "PINRemoteLock.h" 21 | #import "PINResume.h" 22 | 23 | @interface PINRemoteImageTask : NSObject 24 | 25 | @property (nonatomic, strong, readonly, nonnull) PINRemoteLock *lock; 26 | 27 | @property (nonatomic, copy, readonly, nonnull) NSDictionary *callbackBlocks; 28 | 29 | @property (nonatomic, weak, nullable) PINRemoteImageManager *manager; 30 | 31 | @property (nonatomic, strong, nullable) id retryStrategy; 32 | 33 | @property (nonatomic, copy, nullable) NSString *key; 34 | 35 | - (_Nonnull instancetype)init NS_UNAVAILABLE; 36 | - (_Nonnull instancetype)initWithManager:(nonnull PINRemoteImageManager *)manager NS_DESIGNATED_INITIALIZER; 37 | 38 | - (void)addCallbacksWithCompletionBlock:(nonnull PINRemoteImageManagerImageCompletion)completionBlock 39 | progressImageBlock:(nullable PINRemoteImageManagerImageCompletion)progressImageBlock 40 | progressDownloadBlock:(nullable PINRemoteImageManagerProgressDownload)progressDownloadBlock 41 | withUUID:(nonnull NSUUID *)UUID; 42 | 43 | - (void)removeCallbackWithUUID:(nonnull NSUUID *)UUID; 44 | 45 | - (void)callCompletionsWithImage:(nullable PINImage *)image 46 | alternativeRepresentation:(nullable id)alternativeRepresentation 47 | cached:(BOOL)cached 48 | response:(nullable NSURLResponse *)response 49 | error:(nullable NSError *)error 50 | remove:(BOOL)remove; 51 | 52 | //returns YES if no more attached completionBlocks 53 | - (BOOL)cancelWithUUID:(nonnull NSUUID *)UUID resume:(PINResume * _Nullable * _Nullable)resume; 54 | 55 | - (void)setPriority:(PINRemoteImageManagerPriority)priority; 56 | 57 | - (nonnull PINRemoteImageManagerResult *)imageResultWithImage:(nullable PINImage *)image 58 | alternativeRepresentation:(nullable id)alternativeRepresentation 59 | requestLength:(NSTimeInterval)requestLength 60 | resultType:(PINRemoteImageResultType)resultType 61 | UUID:(nullable NSUUID *)uuid 62 | response:(nullable NSURLResponse *)response 63 | error:(nullable NSError *)error; 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRemoteImageTask.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageTask.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/9/15. 6 | // 7 | // 8 | 9 | #import "PINRemoteImageTask.h" 10 | 11 | #import "PINRemoteImageCallbacks.h" 12 | #import "PINRemoteImageManager+Private.h" 13 | 14 | @interface PINRemoteImageTask () 15 | { 16 | NSMutableDictionary *_callbackBlocks; // We need to copy/retain `NSUUID`, because `PINRemoteImageManager` has a weak table `UUIDs` to store all UUIDs. 17 | } 18 | 19 | @end 20 | 21 | @implementation PINRemoteImageTask 22 | 23 | @synthesize lock = _lock; 24 | 25 | - (instancetype)initWithManager:(PINRemoteImageManager *)manager 26 | { 27 | if (self = [super init]) { 28 | _lock = [[PINRemoteLock alloc] initWithName:@"Task Lock"]; 29 | _manager = manager; 30 | _callbackBlocks = [[NSMutableDictionary alloc] init]; 31 | } 32 | return self; 33 | } 34 | 35 | - (NSString *)description 36 | { 37 | return [NSString stringWithFormat:@"<%@: %p> completionBlocks: %lu", NSStringFromClass([self class]), self, (unsigned long)self.callbackBlocks.count]; 38 | } 39 | 40 | - (void)addCallbacksWithCompletionBlock:(PINRemoteImageManagerImageCompletion)completionBlock 41 | progressImageBlock:(PINRemoteImageManagerImageCompletion)progressImageBlock 42 | progressDownloadBlock:(PINRemoteImageManagerProgressDownload)progressDownloadBlock 43 | withUUID:(NSUUID *)UUID 44 | { 45 | PINRemoteImageCallbacks *completion = [[PINRemoteImageCallbacks alloc] init]; 46 | completion.completionBlock = completionBlock; 47 | completion.progressImageBlock = progressImageBlock; 48 | completion.progressDownloadBlock = progressDownloadBlock; 49 | 50 | [self.lock lockWithBlock:^{ 51 | [self->_callbackBlocks setObject:completion forKey:UUID]; 52 | }]; 53 | } 54 | 55 | - (void)removeCallbackWithUUID:(NSUUID *)UUID 56 | { 57 | [self.lock lockWithBlock:^{ 58 | [self l_removeCallbackWithUUID:UUID]; 59 | }]; 60 | } 61 | 62 | - (void)l_removeCallbackWithUUID:(NSUUID *)UUID 63 | { 64 | [_callbackBlocks removeObjectForKey:UUID]; 65 | } 66 | 67 | - (NSDictionary *)callbackBlocks 68 | { 69 | __block NSDictionary *callbackBlocks; 70 | [self.lock lockWithBlock:^{ 71 | callbackBlocks = [self->_callbackBlocks copy]; 72 | }]; 73 | return callbackBlocks; 74 | } 75 | 76 | - (void)callCompletionsWithImage:(PINImage *)image 77 | alternativeRepresentation:(id)alternativeRepresentation 78 | cached:(BOOL)cached 79 | response:(NSURLResponse *)response 80 | error:(NSError *)error 81 | remove:(BOOL)remove; 82 | { 83 | __weak typeof(self) weakSelf = self; 84 | [self.callbackBlocks enumerateKeysAndObjectsUsingBlock:^(NSUUID *UUID, PINRemoteImageCallbacks *callback, BOOL *stop) { 85 | typeof(self) strongSelf = weakSelf; 86 | PINRemoteImageManagerImageCompletion completionBlock = callback.completionBlock; 87 | if (completionBlock != nil) { 88 | PINLog(@"calling completion for UUID: %@ key: %@", UUID, strongSelf.key); 89 | CFTimeInterval requestTime = callback.requestTime; 90 | 91 | dispatch_async(self.manager.callbackQueue, ^ 92 | { 93 | PINRemoteImageResultType result; 94 | if (image || alternativeRepresentation) { 95 | result = cached ? PINRemoteImageResultTypeCache : PINRemoteImageResultTypeDownload; 96 | } else { 97 | result = PINRemoteImageResultTypeNone; 98 | } 99 | completionBlock([self imageResultWithImage:image 100 | alternativeRepresentation:alternativeRepresentation 101 | requestLength:CACurrentMediaTime() - requestTime 102 | resultType:result 103 | UUID:UUID 104 | response:response 105 | error:error]); 106 | }); 107 | } 108 | if (remove) { 109 | [strongSelf removeCallbackWithUUID:UUID]; 110 | } 111 | }]; 112 | } 113 | 114 | - (BOOL)cancelWithUUID:(NSUUID *)UUID resume:(PINResume **)resume 115 | { 116 | __block BOOL noMoreCompletions; 117 | [self.lock lockWithBlock:^{ 118 | noMoreCompletions = [self l_cancelWithUUID:UUID]; 119 | }]; 120 | return noMoreCompletions; 121 | } 122 | 123 | - (BOOL)l_cancelWithUUID:(NSUUID *)UUID 124 | { 125 | BOOL noMoreCompletions = NO; 126 | [self l_removeCallbackWithUUID:UUID]; 127 | if ([_callbackBlocks count] == 0) { 128 | noMoreCompletions = YES; 129 | } 130 | return noMoreCompletions; 131 | } 132 | 133 | - (void)setPriority:(PINRemoteImageManagerPriority)priority 134 | { 135 | 136 | } 137 | 138 | - (nonnull PINRemoteImageManagerResult *)imageResultWithImage:(nullable PINImage *)image 139 | alternativeRepresentation:(nullable id)alternativeRepresentation 140 | requestLength:(NSTimeInterval)requestLength 141 | resultType:(PINRemoteImageResultType)resultType 142 | UUID:(nullable NSUUID *)UUID 143 | response:(NSURLResponse *)response 144 | error:(nullable NSError *)error 145 | { 146 | return [PINRemoteImageManagerResult imageResultWithImage:image 147 | alternativeRepresentation:alternativeRepresentation 148 | requestLength:requestLength 149 | resultType:resultType 150 | UUID:UUID 151 | response:response 152 | error:error]; 153 | } 154 | 155 | - (NSMutableDictionary *)l_callbackBlocks 156 | { 157 | return _callbackBlocks; 158 | } 159 | 160 | @end 161 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRemoteLock.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteLock.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/17/16. 6 | // 7 | // 8 | 9 | #import 10 | 11 | /** The type of lock, either recursive or non-recursive */ 12 | typedef NS_ENUM(NSUInteger, PINRemoteLockType) { 13 | /** A non-recursive version of the lock. The default. */ 14 | PINRemoteLockTypeNonRecursive = 0, 15 | /** A recursive version of the lock. More expensive. */ 16 | PINRemoteLockTypeRecursive, 17 | }; 18 | 19 | @interface PINRemoteLock : NSObject 20 | 21 | - (instancetype)initWithName:(NSString *)lockName lockType:(PINRemoteLockType)lockType NS_DESIGNATED_INITIALIZER; 22 | - (instancetype)initWithName:(NSString *)lockName; 23 | - (void)lockWithBlock:(dispatch_block_t)block; 24 | 25 | - (void)lock; 26 | - (void)unlock; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRemoteLock.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteLock.m 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/17/16. 6 | // 7 | // 8 | 9 | #import "PINRemoteLock.h" 10 | 11 | #import 12 | 13 | #if !defined(PINREMOTELOCK_DEBUG) && defined(DEBUG) 14 | #define PINREMOTELOCK_DEBUG DEBUG 15 | #endif 16 | 17 | @interface PINRemoteLock () 18 | { 19 | #if PINREMOTELOCK_DEBUG 20 | NSLock *_lock; 21 | NSRecursiveLock *_recursiveLock; 22 | #else 23 | pthread_mutex_t _lock; 24 | #endif 25 | } 26 | 27 | @end 28 | 29 | @implementation PINRemoteLock 30 | 31 | - (instancetype)init 32 | { 33 | return [self initWithName:nil]; 34 | } 35 | 36 | - (instancetype)initWithName:(NSString *)lockName lockType:(PINRemoteLockType)lockType 37 | { 38 | if (self = [super init]) { 39 | #if PINREMOTELOCK_DEBUG 40 | if (lockType == PINRemoteLockTypeNonRecursive) { 41 | _lock = [[NSLock alloc] init]; 42 | } else { 43 | _recursiveLock = [[NSRecursiveLock alloc] init]; 44 | } 45 | 46 | if (lockName) { 47 | [_lock setName:lockName]; 48 | [_recursiveLock setName:lockName]; 49 | } 50 | #else 51 | pthread_mutexattr_t attr; 52 | 53 | pthread_mutexattr_init(&attr); 54 | if (lockType == PINRemoteLockTypeRecursive) { 55 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 56 | } 57 | pthread_mutex_init(&_lock, &attr); 58 | #endif 59 | } 60 | return self; 61 | } 62 | 63 | - (instancetype)initWithName:(NSString *)lockName 64 | { 65 | return [self initWithName:lockName lockType:PINRemoteLockTypeNonRecursive]; 66 | } 67 | 68 | #if ! PINREMOTELOCK_DEBUG 69 | - (void)dealloc 70 | { 71 | pthread_mutex_destroy(&_lock); 72 | } 73 | #endif 74 | 75 | - (void)lockWithBlock:(dispatch_block_t)block 76 | { 77 | #if PINREMOTELOCK_DEBUG 78 | [_lock lock]; 79 | [_recursiveLock lock]; 80 | #else 81 | pthread_mutex_lock(&_lock); 82 | #endif 83 | block(); 84 | #if PINREMOTELOCK_DEBUG 85 | [_lock unlock]; 86 | [_recursiveLock unlock]; 87 | #else 88 | pthread_mutex_unlock(&_lock); 89 | #endif 90 | } 91 | 92 | - (void)lock 93 | { 94 | #if PINREMOTELOCK_DEBUG 95 | [_lock lock]; 96 | [_recursiveLock lock]; 97 | #else 98 | pthread_mutex_lock(&_lock); 99 | #endif 100 | } 101 | 102 | - (void)unlock 103 | { 104 | #if PINREMOTELOCK_DEBUG 105 | [_lock unlock]; 106 | [_recursiveLock unlock]; 107 | #else 108 | pthread_mutex_unlock(&_lock); 109 | #endif 110 | } 111 | 112 | @end 113 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRemoteWeakProxy.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteWeakProxy.h 3 | // PINRemoteImage 4 | // 5 | // Created by Garrett Moon on 4/24/18. 6 | // Copyright © 2018 Pinterest. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PINRemoteWeakProxy : NSProxy 12 | 13 | + (PINRemoteWeakProxy *)weakProxyWithTarget:(id)target; 14 | - (instancetype)initWithTarget:(id)target; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRemoteWeakProxy.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteWeakProxy.m 3 | // PINRemoteImage 4 | // 5 | // Created by Garrett Moon on 4/24/18. 6 | // Copyright © 2018 Pinterest. All rights reserved. 7 | // 8 | 9 | #import "PINRemoteWeakProxy.h" 10 | 11 | @interface PINRemoteWeakProxy () 12 | { 13 | __weak id _target; 14 | Class _targetClass; 15 | } 16 | @end 17 | 18 | @implementation PINRemoteWeakProxy 19 | 20 | + (PINRemoteWeakProxy *)weakProxyWithTarget:(id)target 21 | { 22 | return [[PINRemoteWeakProxy alloc] initWithTarget:target]; 23 | } 24 | 25 | - (instancetype)initWithTarget:(id)target 26 | { 27 | if (self) { 28 | _target = target; 29 | _targetClass = [target class]; 30 | } 31 | return self; 32 | } 33 | 34 | - (BOOL)respondsToSelector:(SEL)aSelector 35 | { 36 | return [_target respondsToSelector:aSelector]; 37 | } 38 | 39 | - (BOOL)conformsToProtocol:(Protocol *)aProtocol 40 | { 41 | return [_target conformsToProtocol:aProtocol]; 42 | } 43 | 44 | - (id)forwardingTargetForSelector:(SEL)aSelector 45 | { 46 | return _target; 47 | } 48 | 49 | - (void)forwardInvocation:(NSInvocation *)invocation 50 | { 51 | // Drop it since we shouldn't get here if _target is nil 52 | } 53 | 54 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel 55 | { 56 | return _target ? [_target methodSignatureForSelector:sel] : [_targetClass instanceMethodSignatureForSelector:sel]; 57 | } 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINRequestRetryStrategy.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINRequestRetryStrategy.m 3 | // Pods 4 | // 5 | // Created by Hovhannes Safaryan on 9/24/16. 6 | // 7 | // 8 | 9 | #import "PINRequestRetryStrategy.h" 10 | #import "PINURLSessionManager.h" 11 | #import "PINRemoteImageManager.h" 12 | 13 | @interface PINRequestExponentialRetryStrategy () 14 | 15 | @property (nonatomic, assign) int retryMaxCount; 16 | @property (nonatomic, assign) int retryCount; 17 | @property (nonatomic, assign) int delayBase; 18 | 19 | @end 20 | 21 | @implementation PINRequestExponentialRetryStrategy 22 | 23 | - (instancetype)initWithRetryMaxCount:(int)retryMaxCount delayBase:(int)delayBase 24 | { 25 | if (self = [super init]) { 26 | _retryCount = 0; 27 | _retryMaxCount = retryMaxCount; 28 | _delayBase = delayBase; 29 | } 30 | return self; 31 | } 32 | 33 | - (int)numberOfRetries 34 | { 35 | return self.retryCount; 36 | } 37 | 38 | - (BOOL)shouldRetryWithError:(NSError *)error 39 | { 40 | if (error == nil || ![[self class] retriableError:error] || 41 | self.retryCount >= self.retryMaxCount) { 42 | return NO; 43 | } 44 | return YES; 45 | } 46 | 47 | - (int)nextDelay 48 | { 49 | return powf(self.delayBase, self.retryCount); 50 | } 51 | 52 | - (void)incrementRetryCount 53 | { 54 | self.retryCount++; 55 | } 56 | 57 | + (BOOL)retriableError:(NSError *)remoteImageError 58 | { 59 | if ([remoteImageError.domain isEqualToString:PINURLErrorDomain]) { 60 | return remoteImageError.code >= 500; 61 | } else if ([remoteImageError.domain isEqualToString:NSURLErrorDomain] && remoteImageError.code == NSURLErrorUnsupportedURL) { 62 | return NO; 63 | } else if ([remoteImageError.domain isEqualToString:PINRemoteImageManagerErrorDomain]) { 64 | return NO; 65 | } 66 | return YES; 67 | } 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINResume.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINResume.h 3 | // PINRemoteImage 4 | // 5 | // Created by Garrett Moon on 3/10/17. 6 | // Copyright © 2017 Pinterest. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface PINResume : NSObject 14 | 15 | - (id)init NS_UNAVAILABLE; 16 | + (PINResume *)resumeData:(NSData *)resumeData ifRange:(NSString *)ifRange totalBytes:(long long)totalBytes; 17 | 18 | @property (nonatomic, strong, readonly) NSData *resumeData; 19 | @property (nonatomic, copy, readonly) NSString *ifRange; 20 | @property (nonatomic, assign, readonly) long long totalBytes; 21 | 22 | @end 23 | 24 | NS_ASSUME_NONNULL_END 25 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINResume.m: -------------------------------------------------------------------------------- 1 | // 2 | // PINResume.m 3 | // PINRemoteImage 4 | // 5 | // Created by Garrett Moon on 3/10/17. 6 | // Copyright © 2017 Pinterest. All rights reserved. 7 | // 8 | 9 | #import "PINResume.h" 10 | 11 | @implementation PINResume 12 | 13 | NSString * const kResumeDataKey = @"kResumeDataKey"; 14 | NSString * const kIfRangeKey = @"kIfRangeKey"; 15 | NSString * const kTotalBytesKey = @"kTotalBytesKey"; 16 | 17 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 18 | { 19 | if (self = [super init]) { 20 | _resumeData = [aDecoder decodeObjectForKey:kResumeDataKey]; 21 | _ifRange = [aDecoder decodeObjectForKey:kIfRangeKey]; 22 | _totalBytes = [aDecoder decodeInt64ForKey:kTotalBytesKey]; 23 | } 24 | return self; 25 | } 26 | 27 | - (void)encodeWithCoder:(NSCoder *)aCoder 28 | { 29 | [aCoder encodeObject:_resumeData forKey:kResumeDataKey]; 30 | [aCoder encodeObject:_ifRange forKey:kIfRangeKey]; 31 | [aCoder encodeInt64:_totalBytes forKey:kTotalBytesKey]; 32 | } 33 | 34 | + (PINResume *)resumeData:(NSData *)resumeData ifRange:(NSString *)ifRange totalBytes:(long long)totalBytes 35 | { 36 | PINResume *resume = [[PINResume alloc] initWithResumeData:resumeData ifRange:ifRange totalBytes:totalBytes]; 37 | return resume; 38 | } 39 | 40 | - (PINResume *)initWithResumeData:(NSData *)resumeData ifRange:(NSString *)ifRange totalBytes:(long long)totalBytes 41 | { 42 | if (self = [super init]) { 43 | NSAssert(resumeData.length > 0 && ifRange.length > 0 && totalBytes > 0, @"PINResume must have all fields non-nil and non-zero length."); 44 | _resumeData = resumeData; 45 | _ifRange = ifRange; 46 | _totalBytes = totalBytes; 47 | } 48 | return self; 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/PINSpeedRecorder.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINSpeedRecorder.h 3 | // PINRemoteImage 4 | // 5 | // Created by Garrett Moon on 8/30/17. 6 | // Copyright © 2017 Pinterest. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef enum : NSUInteger { 12 | PINSpeedRecorderConnectionStatusNotReachable, 13 | PINSpeedRecorderConnectionStatusWWAN, 14 | PINSpeedRecorderConnectionStatusWiFi 15 | } PINSpeedRecorderConnectionStatus; 16 | 17 | @interface PINSpeedRecorder : NSObject 18 | 19 | + (PINSpeedRecorder *)sharedRecorder; 20 | + (NSUInteger)appropriateImageIdxForURLsGivenHistoricalNetworkConditions:(NSArray *)urls 21 | lowQualityQPSThreshold:(float)lowQualityQPSThreshold 22 | highQualityQPSThreshold:(float)highQualityQPSThreshold; 23 | 24 | - (void)processMetrics:(NSURLSessionTaskMetrics *)metrics forTask:(NSURLSessionTask *)task API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)); 25 | 26 | /* 27 | Returns a weighted average of the bytes per second of a transfer with the time to first byte subtracted. 28 | More specifically, we get the time to first byte for every task that completes, 29 | subtract it from the total transfer time, calculate bytes per second 30 | and add it to an existing average using exponential weighted average and adjusting 31 | for starting bias. 32 | This is all done on a per host basis. 33 | */ 34 | - (float)weightedAdjustedBytesPerSecondForHost:(NSString *)host; 35 | 36 | /* 37 | Returns a weighted average of time to first byte for the specified host. 38 | More specifically, we get the time to first byte for every task that completes 39 | and add it to an existing average using exponential weighted average and adjusting 40 | for starting bias. 41 | This is all done on a per host basis. 42 | */ 43 | - (NSTimeInterval)weightedTimeToFirstByteForHost:(NSString *)host; 44 | 45 | - (PINSpeedRecorderConnectionStatus)connectionStatus; 46 | 47 | #if DEBUG 48 | - (void)setCurrentBytesPerSecond:(float)currentBPS; 49 | #endif 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/include/NSData+ImageDetectors.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+ImageDetectors.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 11/19/14. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #import "PINRemoteImageMacros.h" 12 | 13 | @interface NSData (PINImageDetectors) 14 | 15 | - (BOOL)pin_isGIF; 16 | - (BOOL)pin_isAnimatedGIF; 17 | #if PIN_WEBP 18 | - (BOOL)pin_isWebP; 19 | - (BOOL)pin_isAnimatedWebP; 20 | #endif 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/include/PINAlternateRepresentationProvider.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINAlternateRepresentationProvider.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/17/16. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #import "PINRemoteImageManager.h" 12 | 13 | @protocol PINRemoteImageManagerAlternateRepresentationProvider 14 | @required 15 | 16 | /** 17 | @discussion This method will be called with data off the wire or stored in the cache. Return an object to have it returned as the alternativeRepresentation object in the PINRemoteImageManagerResult. @warning this method can be called on the main thread, be careful of doing expensive work. 18 | */ 19 | - (id)alternateRepresentationWithData:(NSData *)data options:(PINRemoteImageManagerDownloadOptions)options; 20 | 21 | @end 22 | 23 | @interface PINAlternateRepresentationProvider : NSObject 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/include/PINAnimatedImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINAnimatedImage.h 3 | // PINRemoteImage 4 | // 5 | // Created by Garrett Moon on 9/17/17. 6 | // Copyright © 2017 Pinterest. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PINRemoteImageMacros.h" 11 | 12 | #if PIN_TARGET_IOS 13 | #import 14 | #elif PIN_TARGET_MAC 15 | #import 16 | #endif 17 | 18 | NS_ASSUME_NONNULL_BEGIN 19 | 20 | extern NSErrorDomain const kPINAnimatedImageErrorDomain; 21 | 22 | /** 23 | PINAnimatedImage decoding and processing errors. 24 | */ 25 | typedef NS_ERROR_ENUM(kPINAnimatedImageErrorDomain, PINAnimatedImageErrorCode) { 26 | /** No error, yay! */ 27 | PINAnimatedImageErrorNoError = 0, 28 | /** Could not create a necessary file. */ 29 | PINAnimatedImageErrorFileCreationError, 30 | /** Could not get a file handle to the necessary file. */ 31 | PINAnimatedImageErrorFileHandleError, 32 | /** Could not decode the image. */ 33 | PINAnimatedImageErrorImageFrameError, 34 | /** Could not memory map the file. */ 35 | PINAnimatedImageErrorMappingError, 36 | /** File write error */ 37 | PINAnimatedImageErrorFileWrite, 38 | }; 39 | 40 | /** 41 | The processing status of the animated image. 42 | */ 43 | typedef NS_ENUM(NSUInteger, PINAnimatedImageStatus) { 44 | /** No work has been done. */ 45 | PINAnimatedImageStatusUnprocessed = 0, 46 | /** Info about the animated image and the cover image are available. */ 47 | PINAnimatedImageStatusInfoProcessed, 48 | /** At least one set of frames has been decoded to a file. It's safe to start playback. */ 49 | PINAnimatedImageStatusFirstFileProcessed, 50 | /** The entire animated image has been processed. */ 51 | PINAnimatedImageStatusProcessed, 52 | /** Processing was canceled. */ 53 | PINAnimatedImageStatusCanceled, 54 | /** There was an error in processing. */ 55 | PINAnimatedImageStatusError, 56 | }; 57 | 58 | extern const Float32 kPINAnimatedImageDefaultDuration; 59 | 60 | /** 61 | Called when the cover image of an animatedImage is ready. 62 | */ 63 | typedef void(^PINAnimatedImageInfoReady)(PINImage * _Nonnull coverImage); 64 | 65 | @protocol PINAnimatedImage; 66 | 67 | @interface PINAnimatedImage : NSObject 68 | 69 | /** 70 | @abstract The maximum number of frames per second supported. 71 | */ 72 | + (NSInteger)maximumFramesPerSecond; 73 | 74 | /** 75 | @abstract Return the duration at a given index. 76 | 77 | @warning *Must be overridden by subclass 78 | */ 79 | - (CFTimeInterval)durationAtIndex:(NSUInteger)index; 80 | 81 | /** 82 | @abstract Return the total number of frames in the animated image. 83 | 84 | @warning *Must be overridden by subclass 85 | */ 86 | @property (nonatomic, readonly) size_t frameCount; 87 | 88 | /** 89 | @abstract Return the total duration of the animated image's playback. 90 | */ 91 | @property (nonatomic, readonly) CFTimeInterval totalDuration; 92 | 93 | /** 94 | The number of frames to play per second * display refresh rate (defined as 60 which appears to be true on iOS). You probably want to 95 | set this value on a displayLink. 96 | @warning Access to this property before status == PINAnimatedImageStatusInfoProcessed is undefined. 97 | */ 98 | @property (nonatomic, readonly) NSUInteger frameInterval; 99 | 100 | @end 101 | 102 | @protocol PINCachedAnimatedFrameProvider 103 | 104 | @required 105 | 106 | - (nullable CGImageRef)cachedFrameImageAtIndex:(NSUInteger)index; 107 | 108 | @end 109 | 110 | @protocol PINAnimatedImage 111 | 112 | /** 113 | @abstract the underlying data of the animated image if available. 114 | */ 115 | @property (nonatomic, readonly) NSData *data; 116 | 117 | /** 118 | @abstract the native width of the animated image. 119 | */ 120 | @property (nonatomic, readonly) uint32_t width; 121 | 122 | /** 123 | @abstract the native height of the animated image. 124 | */ 125 | @property (nonatomic, readonly) uint32_t height; 126 | 127 | /** 128 | @abstract number of bytes per frame. 129 | */ 130 | @property (nonatomic, readonly) uint32_t bytesPerFrame; 131 | 132 | /** 133 | @abstract Return the total duration of the animated image's playback. 134 | */ 135 | @property (nonatomic, readonly) CFTimeInterval totalDuration; 136 | /** 137 | @abstract Return the interval at which playback should occur. Will be set to a CADisplayLink's frame interval. 138 | */ 139 | @property (nonatomic, readonly) NSUInteger frameInterval; 140 | /** 141 | @abstract Return the total number of loops the animated image should play or 0 to loop infinitely. 142 | */ 143 | @property (nonatomic, readonly) size_t loopCount; 144 | /** 145 | @abstract Return the total number of frames in the animated image. 146 | */ 147 | @property (nonatomic, readonly) size_t frameCount; 148 | /** 149 | @abstract Return any error that has occurred. Playback will be paused if this returns non-nil. 150 | */ 151 | @property (nonatomic, readonly, nullable) NSError *error; 152 | 153 | /** 154 | @abstract Return the image at a given index. 155 | */ 156 | - (nullable CGImageRef)imageAtIndex:(NSUInteger)index cacheProvider:(nullable id)cacheProvider; 157 | /** 158 | 159 | @abstract Return the duration at a given index. 160 | */ 161 | - (CFTimeInterval)durationAtIndex:(NSUInteger)index; 162 | 163 | @end 164 | 165 | NS_ASSUME_NONNULL_END 166 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/include/PINAnimatedImageView+PINRemoteImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINAnimatedImageView+PINRemoteImage.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 4/19/18. 6 | // 7 | 8 | #import "PINAnimatedImageView.h" 9 | 10 | #import "PINRemoteImageCategoryManager.h" 11 | 12 | @interface PINAnimatedImageView (PINRemoteImage) 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/include/PINAnimatedImageView.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINAnimatedImageView.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 4/17/18. 6 | // 7 | 8 | #import "PINRemoteImageMacros.h" 9 | 10 | #if PIN_TARGET_IOS 11 | #import 12 | #elif PIN_TARGET_MAC 13 | #import 14 | #endif 15 | 16 | #import "PINCachedAnimatedImage.h" 17 | 18 | @interface PINAnimatedImageView : PINImageView 19 | 20 | - (nonnull instancetype)initWithAnimatedImage:(nonnull PINCachedAnimatedImage *)animatedImage NS_DESIGNATED_INITIALIZER; 21 | - (nonnull instancetype)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER; 22 | - (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER; 23 | 24 | @property (nullable, nonatomic, strong) PINCachedAnimatedImage *animatedImage; 25 | @property (nullable, nonatomic, strong) NSString *animatedImageRunLoopMode; 26 | @property (nonatomic, assign, getter=isPlaybackPaused) BOOL playbackPaused; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/include/PINButton+PINRemoteImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIButton+PINRemoteImage.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 8/18/14. 6 | // 7 | // 8 | 9 | #import "PINRemoteImageMacros.h" 10 | 11 | #if PIN_TARGET_IOS 12 | #import 13 | #elif PIN_TARGET_MAC 14 | #import 15 | #endif 16 | 17 | #import "PINRemoteImageManager.h" 18 | #import "PINRemoteImageCategoryManager.h" 19 | 20 | @interface PINButton (PINRemoteImage) 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/include/PINCachedAnimatedImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINCachedAnimatedImage.h 3 | // PINRemoteImage 4 | // 5 | // Created by Garrett Moon on 9/17/17. 6 | // Copyright © 2017 Pinterest. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "PINRemoteImageMacros.h" 12 | #import "PINAnimatedImage.h" 13 | 14 | @interface PINCachedAnimatedImage : NSObject 15 | 16 | - (instancetype)init NS_UNAVAILABLE; 17 | - (instancetype)initWithAnimatedImage:(id )animatedImage NS_DESIGNATED_INITIALIZER; 18 | - (instancetype)initWithAnimatedImageData:(NSData *)animatedImageData; 19 | 20 | /** 21 | @abstract A block which receives the cover image. Should be called when the objects cover image is ready. 22 | */ 23 | @property (nonatomic, readwrite) PINAnimatedImageInfoReady coverImageReadyCallback; 24 | 25 | /** 26 | @abstract Return the objects's cover image. 27 | */ 28 | @property (nonatomic, readonly) PINImage *coverImage; 29 | /** 30 | @abstract Return a boolean to indicate that the cover image is ready. 31 | */ 32 | @property (nonatomic, readonly) BOOL coverImageReady; 33 | /** 34 | @abstract Return the total duration of the animated image's playback. 35 | */ 36 | @property (nonatomic, readonly) CFTimeInterval totalDuration; 37 | /** 38 | @abstract Return the interval at which playback should occur. Will be set to a CADisplayLink's frame interval. 39 | */ 40 | @property (nonatomic, readonly) NSUInteger frameInterval; 41 | /** 42 | @abstract Return the size of the underlying animated image. 43 | */ 44 | @property (nonatomic, readonly) CGSize size; 45 | /** 46 | @abstract Return the total number of loops the animated image should play or 0 to loop infinitely. 47 | */ 48 | @property (nonatomic, readonly) size_t loopCount; 49 | /** 50 | @abstract Return the total number of frames in the animated image. 51 | */ 52 | @property (nonatomic, readonly) size_t frameCount; 53 | /** 54 | @abstract Return the underlying data if available; 55 | */ 56 | @property (nonatomic, readonly) NSData *data; 57 | /** 58 | @abstract Return YES when playback is ready to occur. 59 | */ 60 | @property (nonatomic, readonly) BOOL playbackReady; 61 | /** 62 | @abstract Return any error that has occurred. Playback will be paused if this returns non-nil. 63 | */ 64 | @property (nonatomic, readonly) NSError *error; 65 | /** 66 | @abstract Should be called when playback is ready. 67 | */ 68 | @property (nonatomic, readwrite) dispatch_block_t playbackReadyCallback; 69 | 70 | /** 71 | @abstract Return the image at a given index. 72 | */ 73 | - (CGImageRef)imageAtIndex:(NSUInteger)index; 74 | /** 75 | @abstract Return the duration at a given index. 76 | */ 77 | - (CFTimeInterval)durationAtIndex:(NSUInteger)index; 78 | /** 79 | @abstract Clear any cached data. Called when playback is paused. 80 | */ 81 | - (void)clearAnimatedImageCache; 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/include/PINGIFAnimatedImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINGIFAnimatedImage.h 3 | // PINRemoteImage 4 | // 5 | // Created by Garrett Moon on 9/17/17. 6 | // Copyright © 2017 Pinterest. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "PINAnimatedImage.h" 12 | 13 | @interface PINGIFAnimatedImage : PINAnimatedImage 14 | 15 | - (instancetype)init NS_UNAVAILABLE; 16 | - (instancetype)initWithAnimatedImageData:(NSData *)animatedImageData NS_DESIGNATED_INITIALIZER; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/include/PINImageView+PINRemoteImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImageView+PINRemoteImage.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 8/17/14. 6 | // 7 | // 8 | 9 | #import "PINRemoteImageMacros.h" 10 | 11 | #if PIN_TARGET_IOS 12 | #import 13 | #elif PIN_TARGET_MAC 14 | #import 15 | #endif 16 | 17 | #import "PINRemoteImageManager.h" 18 | #import "PINRemoteImageCategoryManager.h" 19 | 20 | @interface PINImageView (PINRemoteImage) 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/include/PINProgressiveImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINProgressiveImage.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 2/9/15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #import "PINRemoteImageMacros.h" 12 | 13 | #if PIN_TARGET_IOS 14 | #import 15 | #elif PIN_TARGET_MAC 16 | #import 17 | #endif 18 | 19 | @class PINRemoteImageDownloadTask; 20 | 21 | /** An object which store the data of a downloading image and vends progressive scans **/ 22 | @interface PINProgressiveImage : NSObject 23 | 24 | @property (atomic, copy, nonnull) NSArray *progressThresholds; 25 | @property (atomic, assign) CFTimeInterval estimatedRemainingTimeThreshold; 26 | @property (nonatomic, strong, readonly, nonnull) NSURLSessionDataTask * dataTask; 27 | @property (nonatomic, readonly) CFTimeInterval estimatedRemainingTime; 28 | 29 | - (nonnull instancetype)init NS_UNAVAILABLE; 30 | - (nonnull instancetype)initWithDataTask:(nonnull NSURLSessionDataTask *)dataTask; 31 | 32 | - (void)updateProgressiveImageWithData:(nonnull NSData *)data expectedNumberOfBytes:(int64_t)expectedNumberOfBytes isResume:(BOOL)isResume; 33 | 34 | /** 35 | Returns the latest image based on thresholds, returns nil if no new image is generated. 36 | 37 | @param blurred A boolean to indicate if the image should be blurred. 38 | @param maxProgressiveRenderSize The maximum dimensions at which to apply a blur. If an image exceeds either the height. 39 | or width of this dimension, the image will *not* be blurred regardless of the blurred parameter. 40 | @param renderedImageQuality Value between 0 and 1. Computed by dividing the received number of bytes by the expected number of bytes. 41 | @return PINImage A progressive scan of the image or nil if a new one has not been generated. 42 | */ 43 | - (nullable PINImage *)currentImageBlurred:(BOOL)blurred maxProgressiveRenderSize:(CGSize)maxProgressiveRenderSize renderedImageQuality:(nonnull out CGFloat *)renderedImageQuality; 44 | 45 | /** 46 | Returns the current data for the image. 47 | 48 | @return NSData The current data for the image. 49 | */ 50 | - (nullable NSData *)data; 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/include/PINRemoteImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImage.h 3 | // 4 | // Created by Garrett Moon on 8/17/14. 5 | // 6 | // 7 | 8 | #import "PINRemoteImageMacros.h" 9 | 10 | #if USE_PINCACHE 11 | #import "PINCache+PINRemoteImageCaching.h" 12 | #endif 13 | 14 | #import "NSData+ImageDetectors.h" 15 | #import "PINAlternateRepresentationProvider.h" 16 | #import "PINCachedAnimatedImage.h" 17 | #import "PINGIFAnimatedImage.h" 18 | #import "PINWebPAnimatedImage.h" 19 | #import "PINRemoteImageManager.h" 20 | #import "PINRemoteImageCategoryManager.h" 21 | #import "PINRemoteImageManagerResult.h" 22 | #import "PINRemoteImageCaching.h" 23 | #import "PINProgressiveImage.h" 24 | #import "PINURLSessionManager.h" 25 | #import "PINRequestRetryStrategy.h" 26 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/include/PINRemoteImageCaching.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageCaching.h 3 | // Pods 4 | // 5 | // Created by Aleksei Shevchenko on 7/25/16. 6 | // 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @protocol PINRemoteImageCaching; 14 | typedef void (^PINRemoteImageCachingObjectBlock)(id cache, NSString *key, id __nullable object); 15 | 16 | /** 17 | * Image Cache is responsible for actual image caching. 18 | */ 19 | @protocol PINRemoteImageCaching 20 | 21 | //****************************************************************************************************** 22 | // Memory cache methods 23 | //****************************************************************************************************** 24 | - (nullable id)objectFromMemoryForKey:(NSString *)key; 25 | - (void)setObjectInMemory:(id)object forKey:(NSString *)key withCost:(NSUInteger)cost; 26 | 27 | //****************************************************************************************************** 28 | // Disk cache methods 29 | //****************************************************************************************************** 30 | - (nullable id)objectFromDiskForKey:(NSString *)key; 31 | - (void)objectFromDiskForKey:(NSString *)key completion:(nullable PINRemoteImageCachingObjectBlock)completion; 32 | - (void)setObjectOnDisk:(id)object forKey:(NSString *)key; 33 | 34 | 35 | - (BOOL)objectExistsForKey:(NSString *)key; 36 | 37 | - (void)removeObjectForKey:(NSString *)key; 38 | - (void)removeObjectForKey:(NSString *)key completion:(nullable PINRemoteImageCachingObjectBlock)completion; 39 | - (void)removeAllObjects; 40 | 41 | @optional 42 | 43 | - (void)removeObjectForKeyFromMemory:(NSString *)key; 44 | - (void)setObjectInMemory:(id)object forKey:(NSString *)key withCost:(NSUInteger)cost withAgeLimit:(NSTimeInterval)ageLimit; 45 | - (void)setObjectOnDisk:(id)object forKey:(NSString *)key withAgeLimit:(NSTimeInterval)ageLimit; 46 | - (BOOL)memoryCacheIsTTLCache; 47 | - (BOOL)diskCacheIsTTLCache; 48 | 49 | @end 50 | 51 | 52 | NS_ASSUME_NONNULL_END 53 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/include/PINRemoteImageMacros.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageMacros.h 3 | // PINRemoteImage 4 | // 5 | 6 | #import 7 | 8 | #ifndef PINRemoteImageMacros_h 9 | #define PINRemoteImageMacros_h 10 | 11 | #define PIN_TARGET_IOS (TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR || TARGET_OS_TV) 12 | #define PIN_TARGET_MAC TARGET_OS_OSX 13 | 14 | #define PINRemoteImageLogging 0 15 | #if PINRemoteImageLogging 16 | #define PINLog(args...) NSLog(args) 17 | #else 18 | #define PINLog(args...) 19 | #endif 20 | 21 | #ifndef USE_PINCACHE 22 | #if __has_include() || __has_include("PINCache.h") 23 | #define USE_PINCACHE 1 24 | #else 25 | #define USE_PINCACHE 0 26 | #endif 27 | #endif 28 | 29 | #ifndef PIN_WEBP 30 | #if __has_include() || __has_include() 31 | #define PIN_WEBP 1 32 | #else 33 | #define PIN_WEBP 0 34 | #endif 35 | #endif 36 | 37 | #if PIN_TARGET_IOS 38 | #define PINImage UIImage 39 | #define PINImageView UIImageView 40 | #define PINButton UIButton 41 | #define PINNSOperationSupportsBlur (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_8_0) 42 | #elif PIN_TARGET_MAC 43 | #define PINImage NSImage 44 | #define PINImageView NSImageView 45 | #define PINButton NSButton 46 | #define PINNSOperationSupportsBlur (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber10_10) 47 | #define PINNSURLSessionTaskSupportsPriority (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber10_10) 48 | #endif 49 | 50 | #define PINWeakify(var) __weak typeof(var) PINWeak_##var = var; 51 | 52 | #define PINStrongify(var) \ 53 | _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wshadow\"") __strong typeof(var) var = \ 54 | PINWeak_##var; \ 55 | _Pragma("clang diagnostic pop") 56 | 57 | #define BlockAssert(condition, desc, ...) \ 58 | do { \ 59 | __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \ 60 | if (!(condition)) { \ 61 | [[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \ 62 | object:strongSelf file:[NSString stringWithUTF8String:__FILE__] \ 63 | lineNumber:__LINE__ description:(desc), ##__VA_ARGS__]; \ 64 | } \ 65 | __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \ 66 | } while(0); 67 | 68 | #define PINAssertMain() NSAssert([NSThread isMainThread], @"Expected to be on the main thread."); 69 | 70 | #endif /* PINRemoteImageMacros_h */ 71 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/include/PINRemoteImageManagerResult.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRemoteImageManagerResult.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 3/9/15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #import "PINRemoteImageMacros.h" 12 | 13 | #if PIN_TARGET_IOS 14 | #import 15 | #elif PIN_TARGET_MAC 16 | #import 17 | #endif 18 | 19 | /** How the image was fetched. */ 20 | typedef NS_ENUM(NSUInteger, PINRemoteImageResultType) { 21 | /** Returned if no image is returned */ 22 | PINRemoteImageResultTypeNone = 0, 23 | /** Image was fetched from the memory cache */ 24 | PINRemoteImageResultTypeMemoryCache, 25 | /** Image was fetched from the disk cache */ 26 | PINRemoteImageResultTypeCache, 27 | /** Image was downloaded */ 28 | PINRemoteImageResultTypeDownload, 29 | /** Image is progress */ 30 | PINRemoteImageResultTypeProgress, 31 | }; 32 | 33 | @interface PINRemoteImageManagerResult : NSObject 34 | 35 | @property (nonatomic, readonly, strong, nullable) PINImage *image; 36 | @property (nonatomic, readonly, strong, nullable) id alternativeRepresentation; 37 | @property (nonatomic, readonly, assign) NSTimeInterval requestDuration; 38 | @property (nonatomic, readonly, strong, nullable) NSError *error; 39 | @property (nonatomic, readonly, assign) PINRemoteImageResultType resultType; 40 | @property (nonatomic, readonly, strong, nullable) NSUUID *UUID; 41 | @property (nonatomic, readonly, assign) CGFloat renderedImageQuality; 42 | @property (nonatomic, readonly, assign) NSUInteger bytesSavedByResuming; 43 | @property (nonatomic, readonly, strong, nullable) NSURLResponse *response; 44 | 45 | + (nonnull instancetype)imageResultWithImage:(nullable PINImage *)image 46 | alternativeRepresentation:(nullable id)alternativeRepresentation 47 | requestLength:(NSTimeInterval)requestLength 48 | resultType:(PINRemoteImageResultType)resultType 49 | UUID:(nullable NSUUID *)uuid 50 | response:(nullable NSURLResponse *)response 51 | error:(nullable NSError *)error; 52 | 53 | + (nonnull instancetype)imageResultWithImage:(nullable PINImage *)image 54 | alternativeRepresentation:(nullable id)alternativeRepresentation 55 | requestLength:(NSTimeInterval)requestLength 56 | resultType:(PINRemoteImageResultType)resultType 57 | UUID:(nullable NSUUID *)uuid 58 | response:(nullable NSURLResponse *)response 59 | error:(nullable NSError *)error 60 | bytesSavedByResuming:(NSUInteger)bytesSavedByResuming; 61 | 62 | + (nonnull instancetype)imageResultWithImage:(nullable PINImage *)image 63 | alternativeRepresentation:(nullable id)alternativeRepresentation 64 | requestLength:(NSTimeInterval)requestLength 65 | resultType:(PINRemoteImageResultType)resultType 66 | UUID:(nullable NSUUID *)uuid 67 | response:(nullable NSURLResponse *)response 68 | error:(nullable NSError *)error 69 | renderedImageQuality:(CGFloat)renderedImageQuality; 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/include/PINRequestRetryStrategy.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINRequestRetryStrategy.h 3 | // Pods 4 | // 5 | // Created by Hovhannes Safaryan on 9/24/16. 6 | // 7 | // 8 | 9 | #import 10 | 11 | /* 12 | Decide whether request should be retried based on the error. 13 | **/ 14 | 15 | @protocol PINRequestRetryStrategy 16 | 17 | - (BOOL)shouldRetryWithError:(NSError *)error; 18 | - (int)nextDelay; 19 | - (void)incrementRetryCount; 20 | - (int)numberOfRetries; 21 | 22 | @end 23 | 24 | @interface PINRequestExponentialRetryStrategy : NSObject 25 | 26 | - (instancetype)initWithRetryMaxCount:(int)retryMaxCount delayBase:(int)delayBase; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/include/PINURLSessionManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINURLSessionManager.h 3 | // Pods 4 | // 5 | // Created by Garrett Moon on 6/26/15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #import "PINRemoteImageManager.h" 12 | 13 | extern NSErrorDomain _Nonnull const PINURLErrorDomain; 14 | 15 | @protocol PINURLSessionManagerDelegate 16 | 17 | @required 18 | - (void)didReceiveData:(nonnull NSData *)data forTask:(nonnull NSURLSessionTask *)task; 19 | 20 | @optional 21 | - (void)didCollectMetrics:(nonnull NSURLSessionTaskMetrics *)metrics forURL:(nonnull NSURL *)url API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)); 22 | - (void)didReceiveResponse:(nonnull NSURLResponse *)response forTask:(nonnull NSURLSessionTask *)task; 23 | - (void)didReceiveAuthenticationChallenge:(nonnull NSURLAuthenticationChallenge *)challenge forTask:(nullable NSURLSessionTask *)task completionHandler:(nonnull void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler; 24 | - (void)didCompleteTask:(nonnull NSURLSessionTask *)task withError:(nullable NSError *)error; 25 | 26 | @end 27 | 28 | typedef void (^PINURLSessionDataTaskCompletion)(NSURLSessionTask * _Nonnull task, NSError * _Nullable error); 29 | 30 | @interface PINURLSessionManager : NSObject 31 | 32 | - (nonnull instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)configuration; 33 | 34 | - (nonnull NSURLSessionDataTask *)dataTaskWithRequest:(nonnull NSURLRequest *)request 35 | completionHandler:(nonnull PINURLSessionDataTaskCompletion)completionHandler; 36 | 37 | - (nonnull NSURLSessionDataTask *)dataTaskWithRequest:(nonnull NSURLRequest *)request 38 | priority:(PINRemoteImageManagerPriority)priority 39 | completionHandler:(nonnull PINURLSessionDataTaskCompletion)completionHandler; 40 | 41 | - (void)invalidateSessionAndCancelTasks; 42 | 43 | - (void)URLSession:(nonnull NSURLSession *)session task:(nonnull NSURLSessionTask *)task didFinishCollectingMetrics:(nonnull NSURLSessionTaskMetrics *)metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)); 44 | 45 | @property (atomic, weak, nullable) id delegate; 46 | 47 | #if DEBUG 48 | - (void)concurrentDownloads:(void (^_Nullable)(NSUInteger concurrentDownloads))concurrentDownloadsCompletion; 49 | #endif 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/PINRemoteImage/Source/Classes/include/PINWebPAnimatedImage.h: -------------------------------------------------------------------------------- 1 | // 2 | // PINWebPAnimatedImage.h 3 | // PINRemoteImage 4 | // 5 | // Created by Garrett Moon on 9/14/17. 6 | // Copyright © 2017 Pinterest. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | #import "PINAnimatedImage.h" 13 | 14 | @interface PINWebPAnimatedImage : PINAnimatedImage 15 | 16 | - (instancetype)init NS_UNAVAILABLE; 17 | - (instancetype)initWithAnimatedImageData:(NSData *)animatedImageData NS_DESIGNATED_INITIALIZER; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Target Support Files/PINOperation/PINOperation-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_PINOperation : NSObject 3 | @end 4 | @implementation PodsDummy_PINOperation 5 | @end 6 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Target Support Files/PINOperation/PINOperation-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #ifndef TARGET_OS_WATCH 14 | #define TARGET_OS_WATCH 0 15 | #endif 16 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Target Support Files/PINOperation/PINOperation.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PINOperation 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/PINOperation" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/PINOperation" 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/PINOperation 9 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | SKIP_INSTALL = YES 12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 13 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Target Support Files/PINOperation/PINOperation.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PINOperation 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/PINOperation" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/PINOperation" 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/PINOperation 9 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | SKIP_INSTALL = YES 12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 13 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Target Support Files/PINOperation/PINOperation.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PINOperation 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/PINOperation" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/PINOperation" 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/PINOperation 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Target Support Files/PINRemoteImage/PINRemoteImage-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_PINRemoteImage : NSObject 3 | @end 4 | @implementation PodsDummy_PINRemoteImage 5 | @end 6 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Target Support Files/PINRemoteImage/PINRemoteImage-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Target Support Files/PINRemoteImage/PINRemoteImage.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PINRemoteImage 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/PINRemoteImage" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/PINOperation" "${PODS_ROOT}/Headers/Public/PINRemoteImage" 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/PINRemoteImage 9 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | SKIP_INSTALL = YES 12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 13 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Target Support Files/PINRemoteImage/PINRemoteImage.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PINRemoteImage 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/PINRemoteImage" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/PINOperation" "${PODS_ROOT}/Headers/Public/PINRemoteImage" 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/PINRemoteImage 9 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | SKIP_INSTALL = YES 12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 13 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Target Support Files/PINRemoteImage/PINRemoteImage.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PINRemoteImage 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/PINRemoteImage" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/PINCache" "${PODS_ROOT}/Headers/Public/PINOperation" "${PODS_ROOT}/Headers/Public/PINRemoteImage" 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/PINRemoteImage 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Target Support Files/Pods-BFRImageViewer/Pods-BFRImageViewer-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_BFRImageViewer : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_BFRImageViewer 5 | @end 6 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Target Support Files/Pods-BFRImageViewer/Pods-BFRImageViewer.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/PINOperation" "${PODS_ROOT}/Headers/Public/PINRemoteImage" 4 | LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PINOperation" "${PODS_CONFIGURATION_BUILD_DIR}/PINRemoteImage" 5 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/PINOperation" -isystem "${PODS_ROOT}/Headers/Public/PINRemoteImage" 6 | OTHER_LDFLAGS = $(inherited) -ObjC -l"PINOperation" -l"PINRemoteImage" -framework "Accelerate" -framework "Foundation" -framework "ImageIO" -framework "UIKit" 7 | PODS_BUILD_DIR = ${BUILD_DIR} 8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 9 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 10 | PODS_ROOT = ${SRCROOT}/Pods 11 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 13 | -------------------------------------------------------------------------------- /BFRImageViewerDemo/Pods/Target Support Files/Pods-BFRImageViewer/Pods-BFRImageViewer.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/PINOperation" "${PODS_ROOT}/Headers/Public/PINRemoteImage" 4 | LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PINOperation" "${PODS_CONFIGURATION_BUILD_DIR}/PINRemoteImage" 5 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/PINOperation" -isystem "${PODS_ROOT}/Headers/Public/PINRemoteImage" 6 | OTHER_LDFLAGS = $(inherited) -ObjC -l"PINOperation" -l"PINRemoteImage" -framework "Accelerate" -framework "Foundation" -framework "ImageIO" -framework "UIKit" 7 | PODS_BUILD_DIR = ${BUILD_DIR} 8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 9 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 10 | PODS_ROOT = ${SRCROOT}/Pods 11 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Buffer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bufferapp/buffer-ios-image-viewer/1e5744cfc6282a053c61b9199051ce601663d2e2/demo.gif -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # BFRImageViewer 2 | 3 |

4 | Demo 5 |

6 |

7 | 8 | 9 | 10 |

11 | 12 | ### Summary 13 | The BFRImageViewer is a turnkey solution to present images within your iOS app 🎉! 14 | 15 | It features swipe gestures to dismiss, automatic image scaling, zooming and panning, supports multiple images, image types, URL backloading, custom view controller transitions, built in parallax effect, live photos and plays nicely with 3D touch! We use it all over the place in [Buffer for iOS](https://itunes.apple.com/us/app/buffer-for-twitter-pinterest/id490474324?mt=8) :-). 16 | 17 | We've got code samples of each feature in the demo app, feel free to take a peek 👀. 18 | 19 | ### Installation 20 | The BFRImageViewer is hosted on CocoaPods and is the recommended way to install it: 21 | ```ruby 22 | pod 'BFRImageViewer' 23 | ``` 24 | 25 | 26 | ### Quickstart 27 | To get up and running quickly with BFRImageViewer, just initialize it - that's really about it! 28 | ```objc 29 | //Image source can be an array containing a mix of PHAssets, NSURLs, URL strings, UIImage, PHLivePhoto or BFRBackLoadedImageSource 30 | BFRImageViewController *imageVC = [[BFRImageViewController alloc] initWithImageSource:@[image]]; 31 | ``` 32 | ```swift 33 | let imageVC = BFRImageViewController(imageSource: [image]) 34 | ``` 35 | From there, you'll have every photo automagically loaded up and be able to page between them. If you want some additional context, just fire up the demo project and take a peek 👌! 36 | 37 | ### Custom Transition 38 | If you'd like to use a custom view controller transition, which zooms the selected image into the image viewer, just set up some properties on the dedicated image viewer animator class: 39 | ```objc 40 | // In viewDidLoad... 41 | self.imageViewAnimator = [BFRImageTransitionAnimator new]; 42 | 43 | // Later on, when you want to show an image... 44 | self.imageViewAnimator.animatedImageContainer = self.imageView; 45 | self.imageViewAnimator.animatedImage = self.imageView.image; 46 | self.imageViewAnimator.imageOriginFrame = self.imageView.frame; 47 | self.imageViewAnimator.desiredContentMode = self.imageView.contentMode; //Optional 48 | 49 | BFRImageViewController *imageVC = [[BFRImageViewController alloc] initWithImageSource:@[self.imageView.image]]; 50 | imageVC.transitioningDelegate = self.imageViewAnimator; 51 | 52 | [self presentViewController:imageVC animated:YES completion:nil]; 53 | ``` 54 | That will give you this effect (excuse the low quality gif 🙈): 55 |

56 | AnimationDemo 57 |

58 | 59 | ### URL Backloading 60 | Say you've got a thumbnail of an image, but also a URL of the higher fidelity version too. Using URL backloading, you can quickly show the lower resolution image while loading the better version in the background. When it loads - we'll automatically swap it out for you. This allows you to have the best of worlds. You don't need to have users wait for the URL to load, or settle for always viewing the degraded image. 61 | ```objc 62 | - (void)openImageViewer { 63 | BFRBackLoadedImageSource *backloadedImage = [[BFRBackLoadedImageSource alloc] initWithInitialImage:[UIImage imageNamed:@"lowResImage"] hiResURL:[NSURL URLWithString:@"cdn.theURl.png"]]; 64 | BFRImageViewController *imageVC = [[BFRImageViewController alloc] initWithImageSource:@[backloadedImage]]; 65 | [self presentViewController:imageVC animated:YES completion:nil]; 66 | } 67 | ``` 68 | 69 | ### Going Forward 70 | We regularly maintain this code, and you can also rest assured that it's been battle tested against thousands of users in production 👍. That said, we get things wrong from time to time - so feel free to open an issue for anything you spot! 71 | 72 | We are always happy to talk shop, so feel free to give us a shout on Twitter: 73 | 74 | + Andy - [@ay8s](http://www.twitter.com/ay8s) 75 | + Jordan - [@jordanmorgan10](http://www.twitter.com/jordanmorgan10) 76 | 77 | Or, hey - why not work on the BFRImageViewer and get paid for it!? [We're hiring](http://www.buffer.com/journey)! 78 | 79 | - - - 80 | #### Licence 81 | _This project uses MIT License._ 82 | -------------------------------------------------------------------------------- /transition.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bufferapp/buffer-ios-image-viewer/1e5744cfc6282a053c61b9199051ce601663d2e2/transition.gif --------------------------------------------------------------------------------