123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695 |
- //
- // YBIBImageData.m
- // YBImageBrowserDemo
- //
- // Created by 波儿菜 on 2019/6/5.
- // Copyright © 2019 波儿菜. All rights reserved.
- //
- #import "YBImage.h"
- #import "YBIBImageData.h"
- #import "YBIBImageCell.h"
- #import "YBIBPhotoAlbumManager.h"
- #import "YBIBImageData+Internal.h"
- #import "YBIBUtilities.h"
- #import "YBIBImageCache+Internal.h"
- #import "YBIBSentinel.h"
- #import "YBIBCopywriter.h"
- #import <AssetsLibrary/AssetsLibrary.h>
- extern CGImageRef YYCGImageCreateDecodedCopy(CGImageRef imageRef, BOOL decodeForDisplay);
- static dispatch_queue_t YBIBImageProcessingQueue(void) {
- static dispatch_queue_t queue;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- queue = dispatch_queue_create("com.yangbo.imagebrowser.imageprocessing", DISPATCH_QUEUE_CONCURRENT);
- });
- return queue;
- }
- @implementation YBIBImageData {
- __weak id _downloadToken;
- YBIBSentinel *_cuttingSentinel;
- /// Stop processing tasks when in freeze.
- BOOL _freezing;
- }
- #pragma mark - life cycle
- - (void)dealloc {
- if (_downloadToken && [self.yb_webImageMediator() respondsToSelector:@selector(yb_cancelTaskWithDownloadToken:)]) {
- [self.yb_webImageMediator() yb_cancelTaskWithDownloadToken:_downloadToken];
- }
- [self.imageCache removeForKey:self.cacheKey];
- }
- - (instancetype)init {
- self = [super init];
- if (self) {
- [self initValue];
- }
- return self;
- }
- - (void)initValue {
- _defaultLayout = _layout = [YBIBImageLayout new];
- _loadingStatus = YBIBImageLoadingStatusNone;
- _compressingSize = 4096 * 4096;
- _shouldPreDecodeAsync = YES;
- _freezing = NO;
- _cuttingSentinel = [YBIBSentinel new];
- _interactionProfile = [YBIBInteractionProfile new];
- _allowSaveToPhotoAlbum = YES;
- }
- #pragma mark - load data
- - (void)loadData {
- _freezing = NO;
-
- // Avoid handling asynchronous tasks repeatedly.
- if (self.loadingStatus != YBIBImageLoadingStatusNone) {
- [self loadThumbImage];
- self.loadingStatus = self.loadingStatus;
- return;
- }
-
- if (self.originImage) {
- [self loadOriginImage];
- } else if (self.imageName || self.imagePath || self.imageData) {
- [self loadYBImage];
- } else if (self.image) {
- [self loadImageBlock];
- } else if (self.imageURL) {
- [self loadThumbImage];
- [self loadURL];
- } else if (self.imagePHAsset) {
- [self loadThumbImage];
- [self loadPHAsset];
- } else {
- [self.delegate yb_imageIsInvalidForData:self];
- }
- }
- - (void)loadOriginImage {
- if (_freezing) return;
- if (!self.originImage) return;
-
- if ([self shouldCompress]) {
- if (self.compressedImage) {
- [self.delegate yb_imageData:self readyForCompressedImage:self.compressedImage];
- } else {
- [self loadThumbImage];
- [self loadOriginImage_compress];
- }
- } else {
- [self.delegate yb_imageData:self readyForImage:self.originImage];
- }
- }
- - (void)loadOriginImage_compress {
- if (_freezing) return;
- if (!self.originImage) return;
-
- self.loadingStatus = YBIBImageLoadingStatusCompressing;
- __weak typeof(self) wSelf = self;
- CGSize size = [self bestSizeOfCompressing];
- YBIB_DISPATCH_ASYNC(YBIBImageProcessingQueue(), ^{
- if (self->_freezing) {
- self.loadingStatus = YBIBImageLoadingStatusNone;
- return;
- }
- // Ensure the best display effect.
- UIGraphicsBeginImageContextWithOptions(size, NO, UIScreen.mainScreen.scale);
- [self.originImage drawInRect:CGRectMake(0, 0, size.width, size.height)];
- if (self->_freezing) {
- UIGraphicsEndImageContext();
- self.loadingStatus = YBIBImageLoadingStatusNone;
- return;
- }
- UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- YBIB_DISPATCH_ASYNC_MAIN(^{
- __strong typeof(wSelf) self = wSelf;
- if (!self) return;
-
- self.loadingStatus = YBIBImageLoadingStatusNone;
-
- [self modifyImageWithModifier:self.compressedImageModifier image:resultImage completion:^(UIImage *processedImage) {
- __strong typeof(wSelf) self = wSelf;
- if (!self) return;
- self.compressedImage = processedImage ?: self.originImage;
- [self.delegate yb_imageData:self readyForCompressedImage:self.compressedImage];
- }];
- })
- })
- }
- - (void)loadYBImage {
- if (_freezing) return;
- NSString *name = self.imageName.copy;
- NSString *path = self.imagePath.copy;
- NSData *data = self.imageData ? self.imageData().copy : nil;
- if (name.length == 0 && path.length == 0 && data.length == 0) return;
-
- YBImageDecodeDecision decision = [self defaultDecodeDecision];
-
- __block YBImage *image;
- __weak typeof(self) wSelf = self;
- void(^dealBlock)(void) = ^{
- if (name.length > 0) {
- image = [YBImage imageNamed:name decodeDecision:decision];
- } else if (path.length > 0) {
- image = [YBImage imageWithContentsOfFile:path decodeDecision:decision];
- } else if (data.length > 0) {
- image = [YBImage imageWithData:data scale:UIScreen.mainScreen.scale decodeDecision:decision];
- }
- YBIB_DISPATCH_ASYNC_MAIN(^{
- __strong typeof(wSelf) self = wSelf;
- if (!self) return;
- self.loadingStatus = YBIBImageLoadingStatusNone;
- if (image) {
- [self setOriginImageAndLoadWithImage:image];
- } else {
- [self.delegate yb_imageIsInvalidForData:self];
- }
- })
- };
-
- if (self.shouldPreDecodeAsync) {
- [self loadThumbImage];
- self.loadingStatus = YBIBImageLoadingStatusDecoding;
- YBIB_DISPATCH_ASYNC(YBIBImageProcessingQueue(), dealBlock)
- } else {
- self.loadingStatus = YBIBImageLoadingStatusDecoding;
- dealBlock();
- }
- }
- - (void)loadImageBlock {
- if (_freezing) return;
- __block UIImage *image = self.image ? self.image() : nil;
- if (!image) return;
-
- BOOL shouldPreDecode = self.preDecodeDecision ? self.preDecodeDecision(self, image.size, image.scale) : ![self shouldCompressWithImage:image];
-
- __weak typeof(self) wSelf = self;
- void(^dealBlock)(void) = ^{
- // Do not need to decode If 'image' conformed 'YYAnimatedImage'. (Not entirely accurate.)
- if (![image conformsToProtocol:@protocol(YYAnimatedImage)]) {
- CGImageRef cgImage = YYCGImageCreateDecodedCopy(image.CGImage, shouldPreDecode);
- image = [UIImage imageWithCGImage:cgImage scale:image.scale orientation:image.imageOrientation];
- if (cgImage) CGImageRelease(cgImage);
- }
- YBIB_DISPATCH_ASYNC_MAIN(^{
- __strong typeof(wSelf) self = wSelf;
- if (!self) return;
- self.loadingStatus = YBIBImageLoadingStatusNone;
- [self setOriginImageAndLoadWithImage:image];
- })
- };
-
- if (self.shouldPreDecodeAsync) {
- [self loadThumbImage];
- self.loadingStatus = YBIBImageLoadingStatusDecoding;
- YBIB_DISPATCH_ASYNC(YBIBImageProcessingQueue(), dealBlock)
- } else {
- self.loadingStatus = YBIBImageLoadingStatusDecoding;
- dealBlock();
- }
- }
- - (void)loadURL {
- if (!self.imageURL || self.imageURL.absoluteString.length == 0) return;
- [self loadURL_queryCache];
- }
- - (void)loadURL_queryCache {
- if (_freezing) return;
- if (!self.imageURL || self.imageURL.absoluteString.length == 0) return;
-
- YBImageDecodeDecision decision = [self defaultDecodeDecision];
-
- self.loadingStatus = YBIBImageLoadingStatusQuerying;
- [self.yb_webImageMediator() yb_queryCacheOperationForKey:self.imageURL completed:^(UIImage * _Nullable image, NSData * _Nullable imageData) {
- if (!imageData || imageData.length == 0) {
- YBIB_DISPATCH_ASYNC_MAIN(^{
- self.loadingStatus = YBIBImageLoadingStatusNone;
- [self loadURL_download];
- })
- return;
- }
-
- YBIB_DISPATCH_ASYNC(YBIBImageProcessingQueue(), ^{
- if (self->_freezing) {
- self.loadingStatus = YBIBImageLoadingStatusNone;
- return;
- }
- YBImage *image = [YBImage imageWithData:imageData scale:UIScreen.mainScreen.scale decodeDecision:decision];
- __weak typeof(self) wSelf = self;
- YBIB_DISPATCH_ASYNC_MAIN(^{
- __strong typeof(wSelf) self = wSelf;
- if (!self) return;
- self.loadingStatus = YBIBImageLoadingStatusNone;
- if (image) { // Maybe the image data is invalid.
- [self setOriginImageAndLoadWithImage:image];
- } else {
- [self loadURL_download];
- }
- })
- })
- }];
- }
- - (void)loadURL_download {
- if (_freezing) return;
- if (!self.imageURL || self.imageURL.absoluteString.length == 0) return;
-
- YBImageDecodeDecision decision = [self defaultDecodeDecision];
-
- self.loadingStatus = YBIBImageLoadingStatusDownloading;
- __weak typeof(self) wSelf = self;
- _downloadToken = [self.yb_webImageMediator() yb_downloadImageWithURL:self.imageURL requestModifier:^NSURLRequest * _Nullable(NSURLRequest * _Nonnull request) {
- return self.requestModifier ? self.requestModifier(self, request) : request;
- } progress:^(NSInteger receivedSize, NSInteger expectedSize) {
- CGFloat progress = receivedSize * 1.0 / expectedSize ?: 0;
- YBIB_DISPATCH_ASYNC_MAIN(^{
- __strong typeof(wSelf) self = wSelf;
- if (!self) return;
- [self.delegate yb_imageData:self downloadProgress:progress];
- })
- } success:^(NSData * _Nullable imageData, BOOL finished) {
- if (!finished) return;
-
- YBIB_DISPATCH_ASYNC(YBIBImageProcessingQueue(), ^{
- if (self->_freezing) {
- self.loadingStatus = YBIBImageLoadingStatusNone;
- return;
- }
- YBImage *image = [YBImage imageWithData:imageData scale:UIScreen.mainScreen.scale decodeDecision:decision];
- YBIB_DISPATCH_ASYNC_MAIN(^{
- __strong typeof(wSelf) self = wSelf;
- if (!self) return;
- [self.yb_webImageMediator() yb_storeToDiskWithImageData:imageData forKey:self.imageURL];
- self.loadingStatus = YBIBImageLoadingStatusNone;
- if (image) {
- [self setOriginImageAndLoadWithImage:image];
- } else {
- [self.delegate yb_imageIsInvalidForData:self];
- }
- })
- })
- } failed:^(NSError * _Nullable error, BOOL finished) {
- if (!finished) return;
- __strong typeof(wSelf) self = wSelf;
- if (!self) return;
- self.loadingStatus = YBIBImageLoadingStatusNone;
- [self.delegate yb_imageDownloadFailedForData:self];
- }];
- }
- - (void)loadPHAsset {
- if (_freezing) return;
- if (!self.imagePHAsset) return;
-
- YBImageDecodeDecision decision = [self defaultDecodeDecision];
-
- self.loadingStatus = YBIBImageLoadingStatusReadingPHAsset;
- YBIB_DISPATCH_ASYNC(YBIBImageProcessingQueue(), ^{
- [YBIBPhotoAlbumManager getImageDataWithPHAsset:self.imagePHAsset completion:^(NSData * _Nullable data) {
- if (self->_freezing) {
- self.loadingStatus = YBIBImageLoadingStatusNone;
- return;
- }
- YBImage *image = [YBImage imageWithData:data scale:UIScreen.mainScreen.scale decodeDecision:decision];
- __weak typeof(self) wSelf = self;
- YBIB_DISPATCH_ASYNC_MAIN(^{
- __strong typeof(wSelf) self = wSelf;
- if (!self) return;
-
- self.loadingStatus = YBIBImageLoadingStatusNone;
- if (image) {
- [self setOriginImageAndLoadWithImage:image];
- } else {
- [self.delegate yb_imageIsInvalidForData:self];
- }
- })
- }];
- })
- }
- - (void)loadThumbImage {
- if (_freezing) return;
- if (self.thumbImage) {
- [self.delegate yb_imageData:self readyForThumbImage:self.thumbImage];
- } else if (self.thumbURL) {
- __weak typeof(self) wSelf = self;
- [self.yb_webImageMediator() yb_queryCacheOperationForKey:self.thumbURL completed:^(UIImage * _Nullable image, NSData * _Nullable imageData) {
- __strong typeof(wSelf) self = wSelf;
- if (!self) return;
-
- UIImage *thumbImage;
- if (image) {
- thumbImage = image;
- } else if (imageData) {
- thumbImage = [UIImage imageWithData:imageData];
- }
- // If the target image is ready, ignore the thumb image.
- BOOL shouldIgnore = [self shouldCompress] ? (self.compressedImage != nil) : (self.originImage != nil);
- if (!shouldIgnore && thumbImage) {
- [self.delegate yb_imageData:self readyForThumbImage:thumbImage];
- }
- }];
- } else if (self.projectiveView && [self.projectiveView isKindOfClass:UIImageView.self] && ((UIImageView *)self.projectiveView).image) {
- UIImage *thumbImage = ((UIImageView *)self.projectiveView).image;
- [self.delegate yb_imageData:self readyForThumbImage:thumbImage];
- }
- }
- #pragma mark - internal
- - (void)cuttingImageToRect:(CGRect)rect complete:(void (^)(UIImage * _Nullable))complete {
- if (_freezing) return;
- if (!self.originImage) return;
-
- int32_t value = [_cuttingSentinel increase];
- BOOL (^isCancelled)(void) = ^BOOL(void) {
- if (self->_freezing) return YES;
- return value != self->_cuttingSentinel.value;
- };
-
- YBIB_DISPATCH_ASYNC(YBIBImageProcessingQueue(), ^{
- if (isCancelled()) {
- complete(nil);
- return;
- }
- CGFloat scale = self.originImage.scale;
- CGFloat width = self.originImage.size.width;
- CGFloat height = self.originImage.size.height;
-
- BOOL reverseWidthHeight = NO;
- CGAffineTransform transform = CGAffineTransformIdentity;
- switch (self.originImage.imageOrientation) {
- case UIImageOrientationDown:
- case UIImageOrientationDownMirrored:
- CGAffineTransformTranslate(CGAffineTransformMakeRotation(-M_PI), -width, -height);
- break;
- case UIImageOrientationLeft:
- case UIImageOrientationLeftMirrored:
- transform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(M_PI_2), 0, -height);
- reverseWidthHeight = YES;
- break;
- case UIImageOrientationRight:
- case UIImageOrientationRightMirrored:
- transform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(-M_PI_2), -width, 0);
- reverseWidthHeight = YES;
- break;
- default: break;
- }
- transform = CGAffineTransformScale(transform, scale, scale);
- CGRect correctRect = CGRectApplyAffineTransform(rect, transform);
- CGImageRef cgImage = CGImageCreateWithImageInRect(self.originImage.CGImage, correctRect);
-
- if (isCancelled()) {
- complete(nil);
- if (cgImage) CGImageRelease(cgImage);
- return;
- }
- CGFloat cgWidth = reverseWidthHeight ? CGImageGetHeight(cgImage) : CGImageGetWidth(cgImage);
- CGFloat cgHeight = reverseWidthHeight ? CGImageGetWidth(cgImage) : CGImageGetHeight(cgImage);
- CGSize size = [self bestSizeOfCuttingWithOriginSize:CGSizeMake(cgWidth / scale, cgHeight / scale)];
- UIImage *tmpImage = [UIImage imageWithCGImage:cgImage scale:self.originImage.scale orientation:self.originImage.imageOrientation];
- if (isCancelled()) {
- complete(nil);
- if (cgImage) CGImageRelease(cgImage);
- return;
- }
-
- // Ensure the best display effect.
- UIGraphicsBeginImageContextWithOptions(size, NO, UIScreen.mainScreen.scale);
- [tmpImage drawInRect:CGRectMake(0, 0, size.width, size.height)];
- if (isCancelled()) {
- complete(nil);
- UIGraphicsEndImageContext();
- if (cgImage) CGImageRelease(cgImage);
- return;
- }
- UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- if (cgImage) CGImageRelease(cgImage);
-
- __weak typeof(self) wSelf = self;
- YBIB_DISPATCH_ASYNC_MAIN(^{
- __strong typeof(wSelf) self = wSelf;
- if (!self) return;
-
- [self modifyImageWithModifier:self.cuttedImageModifier image:resultImage completion:^(UIImage *image) {
- __strong typeof(wSelf) self = wSelf;
- if (!self) return;
- complete(image);
- }];
- })
- })
- }
- - (BOOL)shouldCompress {
- return [self shouldCompressWithImage:self.originImage];
- }
- #pragma mark - public
- - (BOOL)shouldCompressWithImage:(UIImage *)image {
- if (!image) return NO;
- return [self shouldCompressWithImageSize:image.size scale:image.scale];
- }
- - (void)stopLoading {
- _freezing = YES;
- self.loadingStatus = YBIBImageLoadingStatusNone;
- }
- - (void)clearCache {
- [self.imageCache removeForKey:self.cacheKey];
- }
- #pragma mark - private
- /// 'size': logic pixel.
- - (BOOL)shouldCompressWithImageSize:(CGSize)size scale:(CGFloat)scale {
- return size.width * scale * size.height * scale > self.compressingSize;
- }
- /// Logic pixel.
- - (CGSize)bestSizeOfCompressing {
- if (!self.originImage) return CGSizeZero;
- UIDeviceOrientation orientation = self.yb_currentOrientation();
- CGRect imageViewFrame = [self.layout yb_imageViewFrameWithContainerSize:self.yb_containerSize(orientation) imageSize:self.originImage.size orientation:orientation];
- return imageViewFrame.size;
- }
- /// Logic pixel.
- - (CGSize)bestSizeOfCuttingWithOriginSize:(CGSize)originSize {
- CGSize containerSize = self.yb_containerSize(self.yb_currentOrientation());
- CGFloat maxWidth = containerSize.width, maxHeight = containerSize.height;
- CGFloat oWidth = originSize.width, oHeight = originSize.height;
- if (maxWidth <= 0 || maxHeight <= 0 || oWidth <= 0 || oHeight <= 0) return CGSizeZero;
-
- if (oWidth <= maxWidth && oHeight <= maxHeight) {
- return originSize;
- }
- CGFloat rWidth = 0, rHeight = 0;
- if (oWidth / maxWidth < oHeight / maxHeight) {
- rHeight = maxHeight;
- rWidth = oWidth / oHeight * rHeight;
- } else {
- rWidth = maxWidth;
- rHeight = oHeight / oWidth * rWidth;
- }
- return CGSizeMake(rWidth, rHeight);
- }
- - (YBImageDecodeDecision)defaultDecodeDecision {
- __weak typeof(self) wSelf = self;
- return ^BOOL(CGSize imageSize, CGFloat scale) {
- __strong typeof(wSelf) self = wSelf;
- if (!self) return NO;
- CGSize logicSize = CGSizeMake(imageSize.width / scale, imageSize.height / scale);
- if (self.preDecodeDecision) return self.preDecodeDecision(self, logicSize, scale);
- if ([self shouldCompressWithImageSize:logicSize scale:scale]) return NO;
- return YES;
- };
- }
- - (void)modifyImageWithModifier:(YBIBImageModifierBlock)modifier image:(UIImage *)image completion:(void(^)(UIImage *processedImage))completion {
- if (modifier) {
- self.loadingStatus = YBIBImageLoadingStatusProcessing;
- __weak typeof(self) wSelf = self;
- modifier(self, image, ^(UIImage *processedImage){
- // This step is necessary, maybe 'self' is already 'dealloc' if processing code takes too much time.
- __strong typeof(wSelf) self = wSelf;
- if (!self) return;
- self.loadingStatus = YBIBImageLoadingStatusNone;
- completion(processedImage);
- });
- } else {
- completion(image);
- }
- }
- - (void)setOriginImageAndLoadWithImage:(UIImage *)image {
- __weak typeof(self) wSelf = self;
- [self modifyImageWithModifier:self.originImageModifier image:image completion:^(UIImage *processedImage) {
- __strong typeof(wSelf) self = wSelf;
- if (!self) return;
- self.originImage = processedImage;
- [self loadOriginImage];
- }];
- }
- - (void)saveToPhotoAlbumCompleteWithError:(nullable NSError *)error {
- if (error) {
- [self.yb_auxiliaryViewHandler() yb_showIncorrectToastWithContainer:self.yb_containerView text:[YBIBCopywriter sharedCopywriter].saveToPhotoAlbumFailed];
- } else {
- [self.yb_auxiliaryViewHandler() yb_showCorrectToastWithContainer:self.yb_containerView text:[YBIBCopywriter sharedCopywriter].saveToPhotoAlbumSuccess];
- }
- }
- - (void)UIImageWriteToSavedPhotosAlbum_completedWithImage:(UIImage *)image error:(NSError *)error context:(void *)context {
- [self saveToPhotoAlbumCompleteWithError:error];
- }
- - (YBIBImageCache *)imageCache {
- return self.yb_backView.ybib_imageCache;
- }
- #pragma mark - <YBIBDataProtocol>
- @synthesize yb_isHideTransitioning = _yb_isHideTransitioning;
- @synthesize yb_currentOrientation = _yb_currentOrientation;
- @synthesize yb_containerSize = _yb_containerSize;
- @synthesize yb_containerView = _yb_containerView;
- @synthesize yb_auxiliaryViewHandler = _yb_auxiliaryViewHandler;
- @synthesize yb_webImageMediator = _yb_webImageMediator;
- @synthesize yb_backView = _yb_backView;
- - (nonnull Class)yb_classOfCell {
- return YBIBImageCell.self;
- }
- - (UIView *)yb_projectiveView {
- return self.projectiveView;
- }
- - (CGRect)yb_imageViewFrameWithContainerSize:(CGSize)containerSize imageSize:(CGSize)imageSize orientation:(UIDeviceOrientation)orientation {
- return [self.layout yb_imageViewFrameWithContainerSize:containerSize imageSize:imageSize orientation:orientation];
- }
- - (void)yb_preload {
- if (!self.delegate) {
- [self loadData];
- }
- }
- - (BOOL)yb_allowSaveToPhotoAlbum {
- return self.allowSaveToPhotoAlbum;
- }
- - (void)yb_saveToPhotoAlbum {
- void(^saveData)(NSData *) = ^(NSData * _Nonnull data){
- [[ALAssetsLibrary new] writeImageDataToSavedPhotosAlbum:data metadata:nil completionBlock:^(NSURL *assetURL, NSError *error) {
- [self saveToPhotoAlbumCompleteWithError:error];
- }];
- };
- void(^saveImage)(UIImage *) = ^(UIImage * _Nonnull image){
- UIImageWriteToSavedPhotosAlbum(image, self, @selector(UIImageWriteToSavedPhotosAlbum_completedWithImage:error:context:), NULL);
- };
- void(^unableToSave)(void) = ^(){
- [self.yb_auxiliaryViewHandler() yb_showIncorrectToastWithContainer:self.yb_containerView text:[YBIBCopywriter sharedCopywriter].unableToSave];
- };
-
- [YBIBPhotoAlbumManager getPhotoAlbumAuthorizationSuccess:^{
- if ([self.originImage conformsToProtocol:@protocol(YYAnimatedImage)] && [self.originImage respondsToSelector:@selector(animatedImageData)] && [self.originImage performSelector:@selector(animatedImageData)]) {
- NSData *data = [self.originImage performSelector:@selector(animatedImageData)];
- data ? saveData(data) : unableToSave();
- } else if (self.originImage) {
- saveImage(self.originImage);
- } else if (self.imageURL) {
- [self.yb_webImageMediator() yb_queryCacheOperationForKey:self.imageURL completed:^(UIImage * _Nullable image, NSData * _Nullable data) {
- if (data) {
- saveData(data);
- } else if (image) {
- saveImage(image);
- } else {
- unableToSave();
- }
- }];
- } else {
- unableToSave();
- }
- } failed:^{
- [self.yb_auxiliaryViewHandler() yb_showIncorrectToastWithContainer:self.yb_containerView text:[YBIBCopywriter sharedCopywriter].getPhotoAlbumAuthorizationFailed];
- }];
- }
- #pragma mark - getters & setters
- @synthesize delegate = _delegate;
- - (void)setDelegate:(id<YBIBImageDataDelegate>)delegate {
- _delegate = delegate;
- if (delegate) {
- [self loadData];
- } else {
- _freezing = YES;
- // Remove the resident cache if '_delegate' is nil.
- [self.imageCache removeResidentForKey:self.cacheKey];
- }
- }
- - (id<YBIBImageDataDelegate>)delegate {
- // Stop sending data to the '_delegate' if it is transiting.
- return self.yb_isHideTransitioning() ? nil : _delegate;
- }
- - (void)setImageURL:(NSURL *)imageURL {
- _imageURL = [imageURL isKindOfClass:NSString.class] ? [NSURL URLWithString:(NSString *)imageURL] : imageURL;
- }
- - (NSString *)cacheKey {
- return [NSString stringWithFormat:@"%p", self];
- }
- - (void)setOriginImage:(__kindof UIImage *)originImage {
- // 'image' should be resident if '_delegate' exists.
- [self.imageCache setImage:originImage type:YBIBImageCacheTypeOrigin forKey:self.cacheKey resident:self->_delegate != nil];
- }
- - (UIImage *)originImage {
- return [self.imageCache imageForKey:self.cacheKey type:YBIBImageCacheTypeOrigin];
- }
- - (void)setCompressedImage:(UIImage *)compressedImage {
- // 'image' should be resident if '_delegate' exists.
- [self.imageCache setImage:compressedImage type:YBIBImageCacheTypeCompressed forKey:self.cacheKey resident:_delegate != nil];
- }
- - (UIImage *)compressedImage {
- return [self.imageCache imageForKey:self.cacheKey type:YBIBImageCacheTypeCompressed];
- }
- - (void)setLoadingStatus:(YBIBImageLoadingStatus)loadingStatus {
- // Ensure thread safety.
- YBIB_DISPATCH_ASYNC_MAIN(^{
- self->_loadingStatus = loadingStatus;
- [self.delegate yb_imageData:self startLoadingWithStatus:loadingStatus];
- });
- }
- - (CGFloat)cuttingZoomScale {
- if (_cuttingZoomScale >= 1) return _cuttingZoomScale;
- _cuttingZoomScale = 1.1;
- if (!self.originImage) return _cuttingZoomScale;
- CGFloat imagePixel = self.originImage.size.width * self.originImage.size.height * self.originImage.scale * self.originImage.scale;
- // The larger the image size, the larger the '_cuttingZoomScale', in order to reduce the burden of CPU and memory.
- CGFloat scale = YBIBLowMemory() ? 0.28 : 0.19;
- _cuttingZoomScale += (imagePixel / self.compressingSize * scale);
- return _cuttingZoomScale;
- }
- @end
|