Authored by Bogdan Poplauschi

Preparing to remove the need for the `recalculateFromImage` param for store in c…

…ache. Only if the data provided is nil and we have an image, we will recaculate. Moved the NSData calculation in the UIImage MultiFormat categ, plus instead of another variant to check for PNG, relly on `sd_imageFormatForImageData`
... ... @@ -39,22 +39,6 @@
@end
static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
// PNG signature bytes and data (below)
static unsigned char kPNGSignatureBytes[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
static NSData *kPNGSignatureData = nil;
BOOL ImageDataHasPNGPreffix(NSData *data);
BOOL ImageDataHasPNGPreffix(NSData *data) {
NSUInteger pngSignatureLength = kPNGSignatureData.length;
if (data.length >= pngSignatureLength) {
if ([[data subdataWithRange:NSMakeRange(0, pngSignatureLength)] isEqualToData:kPNGSignatureData]) {
return YES;
}
}
return NO;
}
FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
#if SD_MAC
... ... @@ -100,10 +84,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
diskCacheDirectory:(nonnull NSString *)directory {
if ((self = [super init])) {
NSString *fullNamespace = [@"com.hackemist.SDWebImageCache." stringByAppendingString:ns];
// initialise PNG signature data
kPNGSignatureData = [NSData dataWithBytes:kPNGSignatureBytes length:8];
// Create IO serial queue
_ioQueue = dispatch_queue_create("com.hackemist.SDWebImageCache", DISPATCH_QUEUE_SERIAL);
... ... @@ -218,46 +199,10 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
if (toDisk) {
dispatch_async(self.ioQueue, ^{
NSData *data = imageData;
if (image && (recalculate || !data)) {
#if SD_UIKIT || SD_WATCH
// We need to determine if the image is a PNG or a JPEG
// PNGs are easier to detect because they have a unique signature (http://www.w3.org/TR/PNG-Structure.html)
// The first eight bytes of a PNG file always contain the following (decimal) values:
// 137 80 78 71 13 10 26 10
// If the imageData is nil (i.e. if trying to save a UIImage directly or the image was transformed on download)
// and the image has an alpha channel, we will consider it PNG to avoid losing the transparency
int alphaInfo = CGImageGetAlphaInfo(image.CGImage);
BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone ||
alphaInfo == kCGImageAlphaNoneSkipFirst ||
alphaInfo == kCGImageAlphaNoneSkipLast);
BOOL imageIsPng = hasAlpha;
// But if we have an image data, we will look at the preffix
if (imageData.length >= kPNGSignatureData.length) {
imageIsPng = ImageDataHasPNGPreffix(imageData);
}
if (imageIsPng) {
data = UIImagePNGRepresentation(image);
}
else {
data = UIImageJPEGRepresentation(image, (CGFloat)1.0);
}
#else
NSString *contentType = [NSData sd_contentTypeForImageData:data];
NSBitmapImageFileType imageFileType = NSJPEGFileType;
if ([contentType isEqualToString:@"image/gif"]) {
imageFileType = NSGIFFileType;
} else if ([contentType isEqualToString:@"image/png"]) {
imageFileType = NSPNGFileType;
}
data = [NSBitmapImageRep representationOfImageRepsInArray:image.representations
usingType:imageFileType
properties:@{}];
#endif
if (!data && image) {
SDImageFormat imageFormatFromData = [NSData sd_imageFormatForImageData:data];
data = [image sd_imageDataAsFormat:imageFormatFromData];
}
[self storeImageDataToDisk:data forKey:key];
... ...
... ... @@ -7,9 +7,12 @@
*/
#import "SDWebImageCompat.h"
#import "NSData+ImageContentType.h"
@interface UIImage (MultiFormat)
+ (nullable UIImage *)sd_imageWithData:(nullable NSData *)data;
- (nullable NSData *)sd_imageData;
- (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat;
@end
... ...
... ... @@ -116,5 +116,46 @@
}
#endif
- (nullable NSData *)sd_imageData {
return [self sd_imageDataAsFormat:SDImageFormatUndefined];
}
- (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat {
NSData *imageData = nil;
if (self) {
#if SD_UIKIT || SD_WATCH
int alphaInfo = CGImageGetAlphaInfo(self.CGImage);
BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone ||
alphaInfo == kCGImageAlphaNoneSkipFirst ||
alphaInfo == kCGImageAlphaNoneSkipLast);
BOOL usePNG = hasAlpha;
// the imageFormat param has priority here. But if the format is undefined, we relly on the alpha channel
if (imageFormat != SDImageFormatUndefined) {
usePNG = (imageFormat == SDImageFormatPNG);
}
if (usePNG) {
imageData = UIImagePNGRepresentation(self);
} else {
imageData = UIImageJPEGRepresentation(self, (CGFloat)1.0);
}
#else
NSBitmapImageFileType imageFileType = NSJPEGFileType;
if (imageFormat == SDImageFormatGIF) {
imageFileType = NSGIFFileType;
} else if (imageFormat == SDImageFormatPNG) {
imageFileType = NSPNGFileType;
}
imageData = [NSBitmapImageRep representationOfImageRepsInArray:self.representations
usingType:imageFileType
properties:@{}];
#endif
}
return imageData;
}
@end
... ...