From 3e8437ae559487362fae3525beb79c534c213a51 Mon Sep 17 00:00:00 2001
From: 单军华
Date: Thu, 12 Jul 2018 13:44:34 +0800
Subject: [PATCH] bug修复和功能优化
---
screendisplay/Pods/SDWebImage/SDWebImage/SDWebImageImageIOCoder.m | 507 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 507 insertions(+), 0 deletions(-)
diff --git a/screendisplay/Pods/SDWebImage/SDWebImage/SDWebImageImageIOCoder.m b/screendisplay/Pods/SDWebImage/SDWebImage/SDWebImageImageIOCoder.m
new file mode 100644
index 0000000..0447ed3
--- /dev/null
+++ b/screendisplay/Pods/SDWebImage/SDWebImage/SDWebImageImageIOCoder.m
@@ -0,0 +1,507 @@
+/*
+ * This file is part of the SDWebImage package.
+ * (c) Olivier Poitrey <rs@dailymotion.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+#import "SDWebImageImageIOCoder.h"
+#import "SDWebImageCoderHelper.h"
+#import "NSImage+WebCache.h"
+#import <ImageIO/ImageIO.h>
+#import "NSData+ImageContentType.h"
+
+#if SD_UIKIT || SD_WATCH
+static const size_t kBytesPerPixel = 4;
+static const size_t kBitsPerComponent = 8;
+
+/*
+ * Defines the maximum size in MB of the decoded image when the flag `SDWebImageScaleDownLargeImages` is set
+ * Suggested value for iPad1 and iPhone 3GS: 60.
+ * Suggested value for iPad2 and iPhone 4: 120.
+ * Suggested value for iPhone 3G and iPod 2 and earlier devices: 30.
+ */
+static const CGFloat kDestImageSizeMB = 60.0f;
+
+/*
+ * Defines the maximum size in MB of a tile used to decode image when the flag `SDWebImageScaleDownLargeImages` is set
+ * Suggested value for iPad1 and iPhone 3GS: 20.
+ * Suggested value for iPad2 and iPhone 4: 40.
+ * Suggested value for iPhone 3G and iPod 2 and earlier devices: 10.
+ */
+static const CGFloat kSourceImageTileSizeMB = 20.0f;
+
+static const CGFloat kBytesPerMB = 1024.0f * 1024.0f;
+static const CGFloat kPixelsPerMB = kBytesPerMB / kBytesPerPixel;
+static const CGFloat kDestTotalPixels = kDestImageSizeMB * kPixelsPerMB;
+static const CGFloat kTileTotalPixels = kSourceImageTileSizeMB * kPixelsPerMB;
+
+static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to overlap the seems where tiles meet.
+#endif
+
+@implementation SDWebImageImageIOCoder {
+ size_t _width, _height;
+#if SD_UIKIT || SD_WATCH
+ UIImageOrientation _orientation;
+#endif
+ CGImageSourceRef _imageSource;
+}
+
+- (void)dealloc {
+ if (_imageSource) {
+ CFRelease(_imageSource);
+ _imageSource = NULL;
+ }
+}
+
++ (instancetype)sharedCoder {
+ static SDWebImageImageIOCoder *coder;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ coder = [[SDWebImageImageIOCoder alloc] init];
+ });
+ return coder;
+}
+
+#pragma mark - Decode
+- (BOOL)canDecodeFromData:(nullable NSData *)data {
+ switch ([NSData sd_imageFormatForImageData:data]) {
+ case SDImageFormatWebP:
+ // Do not support WebP decoding
+ return NO;
+ case SDImageFormatHEIC:
+ // Check HEIC decoding compatibility
+ return [[self class] canDecodeFromHEICFormat];
+ default:
+ return YES;
+ }
+}
+
+- (BOOL)canIncrementallyDecodeFromData:(NSData *)data {
+ switch ([NSData sd_imageFormatForImageData:data]) {
+ case SDImageFormatWebP:
+ // Do not support WebP progressive decoding
+ return NO;
+ case SDImageFormatHEIC:
+ // Check HEIC decoding compatibility
+ return [[self class] canDecodeFromHEICFormat];
+ default:
+ return YES;
+ }
+}
+
+- (UIImage *)decodedImageWithData:(NSData *)data {
+ if (!data) {
+ return nil;
+ }
+
+ UIImage *image = [[UIImage alloc] initWithData:data];
+
+ return image;
+}
+
+- (UIImage *)incrementallyDecodedImageWithData:(NSData *)data finished:(BOOL)finished {
+ if (!_imageSource) {
+ _imageSource = CGImageSourceCreateIncremental(NULL);
+ }
+ UIImage *image;
+
+ // The following code is from http://www.cocoaintheshell.com/2011/05/progressive-images-download-imageio/
+ // Thanks to the author @Nyx0uf
+
+ // Update the data source, we must pass ALL the data, not just the new bytes
+ CGImageSourceUpdateData(_imageSource, (__bridge CFDataRef)data, finished);
+
+ if (_width + _height == 0) {
+ CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(_imageSource, 0, NULL);
+ if (properties) {
+ NSInteger orientationValue = 1;
+ CFTypeRef val = CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight);
+ if (val) CFNumberGetValue(val, kCFNumberLongType, &_height);
+ val = CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth);
+ if (val) CFNumberGetValue(val, kCFNumberLongType, &_width);
+ val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation);
+ if (val) CFNumberGetValue(val, kCFNumberNSIntegerType, &orientationValue);
+ CFRelease(properties);
+
+ // When we draw to Core Graphics, we lose orientation information,
+ // which means the image below born of initWithCGIImage will be
+ // oriented incorrectly sometimes. (Unlike the image born of initWithData
+ // in didCompleteWithError.) So save it here and pass it on later.
+#if SD_UIKIT || SD_WATCH
+ _orientation = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:orientationValue];
+#endif
+ }
+ }
+
+ if (_width + _height > 0) {
+ // Create the image
+ CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(_imageSource, 0, NULL);
+
+ if (partialImageRef) {
+#if SD_UIKIT || SD_WATCH
+ image = [[UIImage alloc] initWithCGImage:partialImageRef scale:1 orientation:_orientation];
+#elif SD_MAC
+ image = [[UIImage alloc] initWithCGImage:partialImageRef size:NSZeroSize];
+#endif
+ CGImageRelease(partialImageRef);
+ }
+ }
+
+ if (finished) {
+ if (_imageSource) {
+ CFRelease(_imageSource);
+ _imageSource = NULL;
+ }
+ }
+
+ return image;
+}
+
+- (UIImage *)decompressedImageWithImage:(UIImage *)image
+ data:(NSData *__autoreleasing _Nullable *)data
+ options:(nullable NSDictionary<NSString*, NSObject*>*)optionsDict {
+#if SD_MAC
+ return image;
+#endif
+#if SD_UIKIT || SD_WATCH
+ BOOL shouldScaleDown = NO;
+ if (optionsDict != nil) {
+ NSNumber *scaleDownLargeImagesOption = nil;
+ if ([optionsDict[SDWebImageCoderScaleDownLargeImagesKey] isKindOfClass:[NSNumber class]]) {
+ scaleDownLargeImagesOption = (NSNumber *)optionsDict[SDWebImageCoderScaleDownLargeImagesKey];
+ }
+ if (scaleDownLargeImagesOption != nil) {
+ shouldScaleDown = [scaleDownLargeImagesOption boolValue];
+ }
+ }
+ if (!shouldScaleDown) {
+ return [self sd_decompressedImageWithImage:image];
+ } else {
+ UIImage *scaledDownImage = [self sd_decompressedAndScaledDownImageWithImage:image];
+ if (scaledDownImage && !CGSizeEqualToSize(scaledDownImage.size, image.size)) {
+ // if the image is scaled down, need to modify the data pointer as well
+ SDImageFormat format = [NSData sd_imageFormatForImageData:*data];
+ NSData *imageData = [self encodedDataWithImage:scaledDownImage format:format];
+ if (imageData) {
+ *data = imageData;
+ }
+ }
+ return scaledDownImage;
+ }
+#endif
+}
+
+#if SD_UIKIT || SD_WATCH
+- (nullable UIImage *)sd_decompressedImageWithImage:(nullable UIImage *)image {
+ if (![[self class] shouldDecodeImage:image]) {
+ return image;
+ }
+
+ // autorelease the bitmap context and all vars to help system to free memory when there are memory warning.
+ // on iOS7, do not forget to call [[SDImageCache sharedImageCache] clearMemory];
+ @autoreleasepool{
+
+ CGImageRef imageRef = image.CGImage;
+ // device color space
+ CGColorSpaceRef colorspaceRef = SDCGColorSpaceGetDeviceRGB();
+ BOOL hasAlpha = SDCGImageRefContainsAlpha(imageRef);
+ // iOS display alpha info (BRGA8888/BGRX8888)
+ CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host;
+ bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
+
+ size_t width = CGImageGetWidth(imageRef);
+ size_t height = CGImageGetHeight(imageRef);
+
+ // kCGImageAlphaNone is not supported in CGBitmapContextCreate.
+ // Since the original image here has no alpha info, use kCGImageAlphaNoneSkipLast
+ // to create bitmap graphics contexts without alpha info.
+ CGContextRef context = CGBitmapContextCreate(NULL,
+ width,
+ height,
+ kBitsPerComponent,
+ 0,
+ colorspaceRef,
+ bitmapInfo);
+ if (context == NULL) {
+ return image;
+ }
+
+ // Draw the image into the context and retrieve the new bitmap image without alpha
+ CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
+ CGImageRef imageRefWithoutAlpha = CGBitmapContextCreateImage(context);
+ UIImage *imageWithoutAlpha = [[UIImage alloc] initWithCGImage:imageRefWithoutAlpha scale:image.scale orientation:image.imageOrientation];
+ CGContextRelease(context);
+ CGImageRelease(imageRefWithoutAlpha);
+
+ return imageWithoutAlpha;
+ }
+}
+
+- (nullable UIImage *)sd_decompressedAndScaledDownImageWithImage:(nullable UIImage *)image {
+ if (![[self class] shouldDecodeImage:image]) {
+ return image;
+ }
+
+ if (![[self class] shouldScaleDownImage:image]) {
+ return [self sd_decompressedImageWithImage:image];
+ }
+
+ CGContextRef destContext;
+
+ // autorelease the bitmap context and all vars to help system to free memory when there are memory warning.
+ // on iOS7, do not forget to call [[SDImageCache sharedImageCache] clearMemory];
+ @autoreleasepool {
+ CGImageRef sourceImageRef = image.CGImage;
+
+ CGSize sourceResolution = CGSizeZero;
+ sourceResolution.width = CGImageGetWidth(sourceImageRef);
+ sourceResolution.height = CGImageGetHeight(sourceImageRef);
+ float sourceTotalPixels = sourceResolution.width * sourceResolution.height;
+ // Determine the scale ratio to apply to the input image
+ // that results in an output image of the defined size.
+ // see kDestImageSizeMB, and how it relates to destTotalPixels.
+ float imageScale = kDestTotalPixels / sourceTotalPixels;
+ CGSize destResolution = CGSizeZero;
+ destResolution.width = (int)(sourceResolution.width*imageScale);
+ destResolution.height = (int)(sourceResolution.height*imageScale);
+
+ // device color space
+ CGColorSpaceRef colorspaceRef = SDCGColorSpaceGetDeviceRGB();
+ BOOL hasAlpha = SDCGImageRefContainsAlpha(sourceImageRef);
+ // iOS display alpha info (BGRA8888/BGRX8888)
+ CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host;
+ bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
+
+ // kCGImageAlphaNone is not supported in CGBitmapContextCreate.
+ // Since the original image here has no alpha info, use kCGImageAlphaNoneSkipLast
+ // to create bitmap graphics contexts without alpha info.
+ destContext = CGBitmapContextCreate(NULL,
+ destResolution.width,
+ destResolution.height,
+ kBitsPerComponent,
+ 0,
+ colorspaceRef,
+ bitmapInfo);
+
+ if (destContext == NULL) {
+ return image;
+ }
+ CGContextSetInterpolationQuality(destContext, kCGInterpolationHigh);
+
+ // Now define the size of the rectangle to be used for the
+ // incremental blits from the input image to the output image.
+ // we use a source tile width equal to the width of the source
+ // image due to the way that iOS retrieves image data from disk.
+ // iOS must decode an image from disk in full width 'bands', even
+ // if current graphics context is clipped to a subrect within that
+ // band. Therefore we fully utilize all of the pixel data that results
+ // from a decoding opertion by achnoring our tile size to the full
+ // width of the input image.
+ CGRect sourceTile = CGRectZero;
+ sourceTile.size.width = sourceResolution.width;
+ // The source tile height is dynamic. Since we specified the size
+ // of the source tile in MB, see how many rows of pixels high it
+ // can be given the input image width.
+ sourceTile.size.height = (int)(kTileTotalPixels / sourceTile.size.width );
+ sourceTile.origin.x = 0.0f;
+ // The output tile is the same proportions as the input tile, but
+ // scaled to image scale.
+ CGRect destTile;
+ destTile.size.width = destResolution.width;
+ destTile.size.height = sourceTile.size.height * imageScale;
+ destTile.origin.x = 0.0f;
+ // The source seem overlap is proportionate to the destination seem overlap.
+ // this is the amount of pixels to overlap each tile as we assemble the ouput image.
+ float sourceSeemOverlap = (int)((kDestSeemOverlap/destResolution.height)*sourceResolution.height);
+ CGImageRef sourceTileImageRef;
+ // calculate the number of read/write operations required to assemble the
+ // output image.
+ int iterations = (int)( sourceResolution.height / sourceTile.size.height );
+ // If tile height doesn't divide the image height evenly, add another iteration
+ // to account for the remaining pixels.
+ int remainder = (int)sourceResolution.height % (int)sourceTile.size.height;
+ if(remainder) {
+ iterations++;
+ }
+ // Add seem overlaps to the tiles, but save the original tile height for y coordinate calculations.
+ float sourceTileHeightMinusOverlap = sourceTile.size.height;
+ sourceTile.size.height += sourceSeemOverlap;
+ destTile.size.height += kDestSeemOverlap;
+ for( int y = 0; y < iterations; ++y ) {
+ @autoreleasepool {
+ sourceTile.origin.y = y * sourceTileHeightMinusOverlap + sourceSeemOverlap;
+ destTile.origin.y = destResolution.height - (( y + 1 ) * sourceTileHeightMinusOverlap * imageScale + kDestSeemOverlap);
+ sourceTileImageRef = CGImageCreateWithImageInRect( sourceImageRef, sourceTile );
+ if( y == iterations - 1 && remainder ) {
+ float dify = destTile.size.height;
+ destTile.size.height = CGImageGetHeight( sourceTileImageRef ) * imageScale;
+ dify -= destTile.size.height;
+ destTile.origin.y += dify;
+ }
+ CGContextDrawImage( destContext, destTile, sourceTileImageRef );
+ CGImageRelease( sourceTileImageRef );
+ }
+ }
+
+ CGImageRef destImageRef = CGBitmapContextCreateImage(destContext);
+ CGContextRelease(destContext);
+ if (destImageRef == NULL) {
+ return image;
+ }
+ UIImage *destImage = [[UIImage alloc] initWithCGImage:destImageRef scale:image.scale orientation:image.imageOrientation];
+ CGImageRelease(destImageRef);
+ if (destImage == nil) {
+ return image;
+ }
+ return destImage;
+ }
+}
+#endif
+
+#pragma mark - Encode
+- (BOOL)canEncodeToFormat:(SDImageFormat)format {
+ switch (format) {
+ case SDImageFormatWebP:
+ // Do not support WebP encoding
+ return NO;
+ case SDImageFormatHEIC:
+ // Check HEIC encoding compatibility
+ return [[self class] canEncodeToHEICFormat];
+ default:
+ return YES;
+ }
+}
+
+- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format {
+ if (!image) {
+ return nil;
+ }
+
+ if (format == SDImageFormatUndefined) {
+ BOOL hasAlpha = SDCGImageRefContainsAlpha(image.CGImage);
+ if (hasAlpha) {
+ format = SDImageFormatPNG;
+ } else {
+ format = SDImageFormatJPEG;
+ }
+ }
+
+ NSMutableData *imageData = [NSMutableData data];
+ CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:format];
+
+ // Create an image destination.
+ CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, 1, NULL);
+ if (!imageDestination) {
+ // Handle failure.
+ return nil;
+ }
+
+ NSMutableDictionary *properties = [NSMutableDictionary dictionary];
+#if SD_UIKIT || SD_WATCH
+ NSInteger exifOrientation = [SDWebImageCoderHelper exifOrientationFromImageOrientation:image.imageOrientation];
+ [properties setValue:@(exifOrientation) forKey:(__bridge_transfer NSString *)kCGImagePropertyOrientation];
+#endif
+
+ // Add your image to the destination.
+ CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)properties);
+
+ // Finalize the destination.
+ if (CGImageDestinationFinalize(imageDestination) == NO) {
+ // Handle failure.
+ imageData = nil;
+ }
+
+ CFRelease(imageDestination);
+
+ return [imageData copy];
+}
+
+#pragma mark - Helper
++ (BOOL)shouldDecodeImage:(nullable UIImage *)image {
+ // Prevent "CGBitmapContextCreateImage: invalid context 0x0" error
+ if (image == nil) {
+ return NO;
+ }
+
+ // do not decode animated images
+ if (image.images != nil) {
+ return NO;
+ }
+
+ return YES;
+}
+
++ (BOOL)canDecodeFromHEICFormat {
+ static BOOL canDecode = NO;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability"
+#if TARGET_OS_SIMULATOR || SD_WATCH
+ canDecode = NO;
+#elif SD_MAC
+ NSProcessInfo *processInfo = [NSProcessInfo processInfo];
+ if ([processInfo respondsToSelector:@selector(operatingSystemVersion)]) {
+ // macOS 10.13+
+ canDecode = processInfo.operatingSystemVersion.minorVersion >= 13;
+ } else {
+ canDecode = NO;
+ }
+#elif SD_UIKIT
+ NSProcessInfo *processInfo = [NSProcessInfo processInfo];
+ if ([processInfo respondsToSelector:@selector(operatingSystemVersion)]) {
+ // iOS 11+ && tvOS 11+
+ canDecode = processInfo.operatingSystemVersion.majorVersion >= 11;
+ } else {
+ canDecode = NO;
+ }
+#endif
+#pragma clang diagnostic pop
+ });
+ return canDecode;
+}
+
++ (BOOL)canEncodeToHEICFormat {
+ static BOOL canEncode = NO;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ NSMutableData *imageData = [NSMutableData data];
+ CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatHEIC];
+
+ // Create an image destination.
+ CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, 1, NULL);
+ if (!imageDestination) {
+ // Can't encode to HEIC
+ canEncode = NO;
+ } else {
+ // Can encode to HEIC
+ CFRelease(imageDestination);
+ canEncode = YES;
+ }
+ });
+ return canEncode;
+}
+
+#if SD_UIKIT || SD_WATCH
++ (BOOL)shouldScaleDownImage:(nonnull UIImage *)image {
+ BOOL shouldScaleDown = YES;
+
+ CGImageRef sourceImageRef = image.CGImage;
+ CGSize sourceResolution = CGSizeZero;
+ sourceResolution.width = CGImageGetWidth(sourceImageRef);
+ sourceResolution.height = CGImageGetHeight(sourceImageRef);
+ float sourceTotalPixels = sourceResolution.width * sourceResolution.height;
+ float imageScale = kDestTotalPixels / sourceTotalPixels;
+ if (imageScale < 1) {
+ shouldScaleDown = YES;
+ } else {
+ shouldScaleDown = NO;
+ }
+
+ return shouldScaleDown;
+}
+#endif
+
+@end
--
Gitblit v1.8.0