Merge branch 'master' into 5.x

This commit is contained in:
Bogdan Poplauschi 2017-10-19 20:52:36 +03:00
commit 9d80374064
8 changed files with 63 additions and 30 deletions

View File

@ -44,7 +44,8 @@ script:
- echo Run the tests
- pod install --project-directory=Tests
- xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS static' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c
- xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS' -sdk iphonesimulator PLATFORM_NAME=iphonesimulator -configuration Debug | xcpretty -c
- xcodebuild clean -workspace SDWebImage.xcworkspace -scheme 'SDWebImage iOS Demo' -configuration Debug -destination 'name=iPhone 6s' | xcpretty -c
- xcodebuild test -workspace SDWebImage.xcworkspace -scheme 'Tests' -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6,OS=latest' -configuration Debug | xcpretty -c
after_success:

View File

@ -322,14 +322,14 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
- (nullable NSData *)diskImageDataBySearchingAllPathsForKey:(nullable NSString *)key {
NSString *defaultPath = [self defaultCachePathForKey:key];
NSData *data = [NSData dataWithContentsOfFile:defaultPath];
NSData *data = [NSData dataWithContentsOfFile:defaultPath options:self.config.diskCacheReadingOptions error:nil];
if (data) {
return data;
}
// fallback because of https://github.com/rs/SDWebImage/pull/976 that added the extension to the disk file name
// checking the key with and without the extension
data = [NSData dataWithContentsOfFile:defaultPath.stringByDeletingPathExtension];
data = [NSData dataWithContentsOfFile:defaultPath.stringByDeletingPathExtension options:self.config.diskCacheReadingOptions error:nil];
if (data) {
return data;
}
@ -337,14 +337,14 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {
NSArray<NSString *> *customPaths = [self.customPaths copy];
for (NSString *path in customPaths) {
NSString *filePath = [self cachePathForKey:key inPath:path];
NSData *imageData = [NSData dataWithContentsOfFile:filePath];
NSData *imageData = [NSData dataWithContentsOfFile:filePath options:self.config.diskCacheReadingOptions error:nil];
if (imageData) {
return imageData;
}
// fallback because of https://github.com/rs/SDWebImage/pull/976 that added the extension to the disk file name
// checking the key with and without the extension
imageData = [NSData dataWithContentsOfFile:filePath.stringByDeletingPathExtension];
imageData = [NSData dataWithContentsOfFile:filePath.stringByDeletingPathExtension options:self.config.diskCacheReadingOptions error:nil];
if (imageData) {
return imageData;
}

View File

@ -18,7 +18,7 @@
@property (assign, nonatomic) BOOL shouldDecompressImages;
/**
* disable iCloud backup [defaults to YES]
* disable iCloud backup [defaults to YES]
*/
@property (assign, nonatomic) BOOL shouldDisableiCloud;
@ -28,7 +28,13 @@
@property (assign, nonatomic) BOOL shouldCacheImagesInMemory;
/**
* The maximum length of time to keep an image in the cache, in seconds
* The reading options while reading cache from disk.
* Defaults to 0. You can set this to mapped file to improve performance.
*/
@property (assign, nonatomic) NSDataReadingOptions diskCacheReadingOptions;
/**
* The maximum length of time to keep an image in the cache, in seconds.
*/
@property (assign, nonatomic) NSInteger maxCacheAge;

View File

@ -17,6 +17,7 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
_shouldDecompressImages = YES;
_shouldDisableiCloud = YES;
_shouldCacheImagesInMemory = YES;
_diskCacheReadingOptions = 0;
_maxCacheAge = kDefaultCacheMaxCacheAge;
_maxCacheSize = 0;
}

View File

@ -45,8 +45,7 @@
if (count <= 1) {
animatedImage = [[UIImage alloc] initWithData:data];
}
else {
} else {
NSMutableArray *images = [NSMutableArray array];
NSTimeInterval duration = 0.0f;
@ -103,9 +102,7 @@
NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
if (delayTimeUnclampedProp) {
frameDuration = [delayTimeUnclampedProp floatValue];
}
else {
} else {
NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
if (delayTimeProp) {
frameDuration = [delayTimeProp floatValue];
@ -147,11 +144,22 @@
}
NSMutableData *imageData = [NSMutableData data];
NSUInteger frameCount = 0; // assume static images by default
CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:format];
NSUInteger frameCount = 1;
if (image.images) {
frameCount = image.images.count;
#if SD_MAC
NSBitmapImageRep *bitmapRep;
for (NSImageRep *imageRep in image.representations) {
if ([imageRep isKindOfClass:[NSBitmapImageRep class]]) {
bitmapRep = (NSBitmapImageRep *)imageRep;
break;
}
}
if (bitmapRep) {
frameCount = [[bitmapRep valueForProperty:NSImageFrameCount] unsignedIntegerValue];
}
#else
frameCount = image.images.count;
#endif
// Create an image destination. GIF does not support EXIF image orientation
CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, frameCount, NULL);
@ -160,25 +168,30 @@
return nil;
}
if (!image.images) {
if (frameCount == 0) {
// for static single GIF images
CGImageDestinationAddImage(imageDestination, image.CGImage, nil);
} else {
// for animated GIF images
NSUInteger loopCount = image.sd_imageLoopCount;
NSTimeInterval totalDuration = image.duration;
NSTimeInterval frameDuration = totalDuration / frameCount;
NSDictionary *gifProperties = @{(__bridge_transfer NSString *)kCGImagePropertyGIFDictionary: @{(__bridge_transfer NSString *)kCGImagePropertyGIFLoopCount : @(loopCount)}};
CGImageDestinationSetProperties(imageDestination, (__bridge CFDictionaryRef)gifProperties);
for (size_t i = 0; i < frameCount; i++) {
@autoreleasepool {
NSDictionary *frameProperties = @{(__bridge_transfer NSString *)kCGImagePropertyGIFDictionary : @{(__bridge_transfer NSString *)kCGImagePropertyGIFUnclampedDelayTime : @(frameDuration)}};
#if SD_MAC
// NSBitmapImageRep need to manually change frame. "Good taste" API
[bitmapRep setProperty:NSImageCurrentFrame withValue:@(i)];
float frameDuration = [[bitmapRep valueForProperty:NSImageCurrentFrameDuration] floatValue];
CGImageRef frameImageRef = bitmapRep.CGImage;
#else
float frameDuration = image.duration / frameCount;
CGImageRef frameImageRef = image.images[i].CGImage;
#endif
NSDictionary *frameProperties = @{(__bridge_transfer NSString *)kCGImagePropertyGIFDictionary : @{(__bridge_transfer NSString *)kCGImagePropertyGIFUnclampedDelayTime : @(frameDuration)}};
CGImageDestinationAddImage(imageDestination, frameImageRef, (__bridge CFDictionaryRef)frameProperties);
}
}
}
// Finalize the destination.
if (CGImageDestinationFinalize(imageDestination) == NO) {
// Handle failure.

View File

@ -90,6 +90,10 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
}
UIImage *image = [[UIImage alloc] initWithData:data];
#if SD_MAC
return image;
#else
if (!image) {
return nil;
}
@ -101,16 +105,15 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
image = [UIImage animatedImageWithImages:@[image] duration:image.duration];
return image;
}
#if SD_UIKIT || SD_WATCH
UIImageOrientation orientation = [[self class] sd_imageOrientationFromImageData:data];
if (orientation != UIImageOrientationUp) {
image = [UIImage imageWithCGImage:image.CGImage
scale:image.scale
orientation:orientation];
}
#endif
return image;
#endif
}
- (UIImage *)incrementallyDecodedImageWithData:(NSData *)data finished:(BOOL)finished {

View File

@ -190,11 +190,12 @@
return nil;
}
int width;
int height;
uint8_t *rgba = WebPIDecGetRGB(_idec, NULL, (int *)&width, (int *)&height, NULL);
if (width + height > 0) {
int width = 0;
int height = 0;
int last_y = 0;
int stride = 0;
uint8_t *rgba = WebPIDecGetRGB(_idec, &last_y, &width, &height, &stride);
if (width + height > 0 && height >= last_y) {
// Construct a UIImage from the decoded RGBA value array
CGDataProviderRef provider =
CGDataProviderCreateWithData(NULL, rgba, 0, NULL);
@ -203,7 +204,13 @@
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast;
size_t components = 4;
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
CGImageRef imageRef = CGImageCreate(width, height, 8, components * 8, components * width, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
// Why to use last_y for image height is because of libwebp's bug (https://bugs.chromium.org/p/webp/issues/detail?id=362)
// It will not keep memory barrier safe on x86 architechure (macOS & iPhone simulator) but on ARM architecture (iPhone & iPad & tv & watch) it works great
// If different threads use WebPIDecGetRGB to grab rgba bitmap, it will contain the previous decoded bitmap data
// So this will cause our drawed image looks strange(above is the current part but below is the previous part)
// We only grab the last_y height and draw the last_y heigh instead of total height image
// Besides fix, this can enhance performance since we do not need to create extra bitmap
CGImageRef imageRef = CGImageCreate(width, last_y, 8, components * 8, components * width, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
CGDataProviderRelease(provider);
@ -217,7 +224,8 @@
return nil;
}
CGContextDrawImage(canvas, CGRectMake(0, 0, width, height), imageRef);
// Only draw the last_y image height, keep remains transparent, in Core Graphics coordinate system
CGContextDrawImage(canvas, CGRectMake(0, height - last_y, width, last_y), imageRef);
CGImageRef newImageRef = CGBitmapContextCreateImage(canvas);
CGImageRelease(imageRef);
if (!newImageRef) {

View File

@ -192,7 +192,8 @@ NSString *kImageTestKey = @"TestImageKey.jpg";
// TODO -- Testing image data insertion
- (void)test40InsertionOfImageData {
// TODO -- this test is driving me crazy keeps failing for unknown reasons, sometimes the image data is not written to disk - disabling the test for now
- (void)a40InsertionOfImageData {
XCTestExpectation *expectation = [self expectationWithDescription:@"Insertion of image data works"];
UIImage *image = [UIImage imageWithContentsOfFile:[self testImagePath]];