Authored by DreamPiggy
Committed by GitHub

Merge pull request #2040 from dreampiggy/Fix_progressive_download_gray_background

Use CGImageSourceCreateIncremental to perform progressive decoding in…
@@ -8,7 +8,6 @@ @@ -8,7 +8,6 @@
8 8
9 #import "SDWebImageDownloader.h" 9 #import "SDWebImageDownloader.h"
10 #import "SDWebImageDownloaderOperation.h" 10 #import "SDWebImageDownloaderOperation.h"
11 -#import <ImageIO/ImageIO.h>  
12 11
13 @implementation SDWebImageDownloadToken 12 @implementation SDWebImageDownloadToken
14 @end 13 @end
@@ -48,10 +48,11 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary; @@ -48,10 +48,11 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
48 @end 48 @end
49 49
50 @implementation SDWebImageDownloaderOperation { 50 @implementation SDWebImageDownloaderOperation {
51 - size_t width, height; 51 + size_t _width, _height;
52 #if SD_UIKIT || SD_WATCH 52 #if SD_UIKIT || SD_WATCH
53 - UIImageOrientation orientation; 53 + UIImageOrientation _orientation;
54 #endif 54 #endif
  55 + CGImageSourceRef _imageSource;
55 } 56 }
56 57
57 @synthesize executing = _executing; 58 @synthesize executing = _executing;
@@ -80,6 +81,10 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary; @@ -80,6 +81,10 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
80 81
81 - (void)dealloc { 82 - (void)dealloc {
82 SDDispatchQueueRelease(_barrierQueue); 83 SDDispatchQueueRelease(_barrierQueue);
  84 + if (_imageSource) {
  85 + CFRelease(_imageSource);
  86 + _imageSource = NULL;
  87 + }
83 } 88 }
84 89
85 - (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock 90 - (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
@@ -318,20 +323,27 @@ didReceiveResponse:(NSURLResponse *)response @@ -318,20 +323,27 @@ didReceiveResponse:(NSURLResponse *)response
318 // The following code is from http://www.cocoaintheshell.com/2011/05/progressive-images-download-imageio/ 323 // The following code is from http://www.cocoaintheshell.com/2011/05/progressive-images-download-imageio/
319 // Thanks to the author @Nyx0uf 324 // Thanks to the author @Nyx0uf
320 325
  326 + // Get the image data
  327 + NSData *imageData = [self.imageData copy];
321 // Get the total bytes downloaded 328 // Get the total bytes downloaded
322 - const NSInteger totalSize = self.imageData.length; 329 + const NSInteger totalSize = imageData.length;
  330 + // Get the finish status
  331 + BOOL finished = (self.expectedSize == totalSize);
323 332
  333 + if (!_imageSource) {
  334 + _imageSource = CGImageSourceCreateIncremental(NULL);
  335 + }
324 // Update the data source, we must pass ALL the data, not just the new bytes 336 // Update the data source, we must pass ALL the data, not just the new bytes
325 - CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)self.imageData, NULL); 337 + CGImageSourceUpdateData(_imageSource, (__bridge CFDataRef)imageData, finished);
326 338
327 - if (width + height == 0) {  
328 - CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL); 339 + if (_width + _height == 0) {
  340 + CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(_imageSource, 0, NULL);
329 if (properties) { 341 if (properties) {
330 NSInteger orientationValue = -1; 342 NSInteger orientationValue = -1;
331 CFTypeRef val = CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight); 343 CFTypeRef val = CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight);
332 - if (val) CFNumberGetValue(val, kCFNumberLongType, &height); 344 + if (val) CFNumberGetValue(val, kCFNumberLongType, &_height);
333 val = CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth); 345 val = CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth);
334 - if (val) CFNumberGetValue(val, kCFNumberLongType, &width); 346 + if (val) CFNumberGetValue(val, kCFNumberLongType, &_width);
335 val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation); 347 val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation);
336 if (val) CFNumberGetValue(val, kCFNumberNSIntegerType, &orientationValue); 348 if (val) CFNumberGetValue(val, kCFNumberNSIntegerType, &orientationValue);
337 CFRelease(properties); 349 CFRelease(properties);
@@ -341,24 +353,24 @@ didReceiveResponse:(NSURLResponse *)response @@ -341,24 +353,24 @@ didReceiveResponse:(NSURLResponse *)response
341 // oriented incorrectly sometimes. (Unlike the image born of initWithData 353 // oriented incorrectly sometimes. (Unlike the image born of initWithData
342 // in didCompleteWithError.) So save it here and pass it on later. 354 // in didCompleteWithError.) So save it here and pass it on later.
343 #if SD_UIKIT || SD_WATCH 355 #if SD_UIKIT || SD_WATCH
344 - orientation = [[self class] orientationFromPropertyValue:(orientationValue == -1 ? 1 : orientationValue)]; 356 + _orientation = [[self class] orientationFromPropertyValue:(orientationValue == -1 ? 1 : orientationValue)];
345 #endif 357 #endif
346 } 358 }
347 } 359 }
348 360
349 - if (width + height > 0 && totalSize < self.expectedSize) { 361 + if (_width + _height > 0 && !finished) {
350 // Create the image 362 // Create the image
351 - CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL); 363 + CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(_imageSource, 0, NULL);
352 364
353 #if SD_UIKIT || SD_WATCH 365 #if SD_UIKIT || SD_WATCH
354 // Workaround for iOS anamorphic image 366 // Workaround for iOS anamorphic image
355 if (partialImageRef) { 367 if (partialImageRef) {
356 const size_t partialHeight = CGImageGetHeight(partialImageRef); 368 const size_t partialHeight = CGImageGetHeight(partialImageRef);
357 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 369 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
358 - CGContextRef bmContext = CGBitmapContextCreate(NULL, width, height, 8, width * 4, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst); 370 + CGContextRef bmContext = CGBitmapContextCreate(NULL, _width, _height, 8, _width * 4, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
359 CGColorSpaceRelease(colorSpace); 371 CGColorSpaceRelease(colorSpace);
360 if (bmContext) { 372 if (bmContext) {
361 - CGContextDrawImage(bmContext, (CGRect){.origin.x = 0.0f, .origin.y = 0.0f, .size.width = width, .size.height = partialHeight}, partialImageRef); 373 + CGContextDrawImage(bmContext, (CGRect){.origin.x = 0.0f, .origin.y = 0.0f, .size.width = _width, .size.height = partialHeight}, partialImageRef);
362 CGImageRelease(partialImageRef); 374 CGImageRelease(partialImageRef);
363 partialImageRef = CGBitmapContextCreateImage(bmContext); 375 partialImageRef = CGBitmapContextCreateImage(bmContext);
364 CGContextRelease(bmContext); 376 CGContextRelease(bmContext);
@@ -372,10 +384,11 @@ didReceiveResponse:(NSURLResponse *)response @@ -372,10 +384,11 @@ didReceiveResponse:(NSURLResponse *)response
372 384
373 if (partialImageRef) { 385 if (partialImageRef) {
374 #if SD_UIKIT || SD_WATCH 386 #if SD_UIKIT || SD_WATCH
375 - UIImage *image = [UIImage imageWithCGImage:partialImageRef scale:1 orientation:orientation]; 387 + UIImage *image = [UIImage imageWithCGImage:partialImageRef scale:1 orientation:_orientation];
376 #elif SD_MAC 388 #elif SD_MAC
377 UIImage *image = [[UIImage alloc] initWithCGImage:partialImageRef size:NSZeroSize]; 389 UIImage *image = [[UIImage alloc] initWithCGImage:partialImageRef size:NSZeroSize];
378 #endif 390 #endif
  391 + CGImageRelease(partialImageRef);
379 NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; 392 NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL];
380 UIImage *scaledImage = [self scaledImageForKey:key image:image]; 393 UIImage *scaledImage = [self scaledImageForKey:key image:image];
381 if (self.shouldDecompressImages) { 394 if (self.shouldDecompressImages) {
@@ -384,14 +397,16 @@ didReceiveResponse:(NSURLResponse *)response @@ -384,14 +397,16 @@ didReceiveResponse:(NSURLResponse *)response
384 else { 397 else {
385 image = scaledImage; 398 image = scaledImage;
386 } 399 }
387 - CGImageRelease(partialImageRef);  
388 400
389 [self callCompletionBlocksWithImage:image imageData:nil error:nil finished:NO]; 401 [self callCompletionBlocksWithImage:image imageData:nil error:nil finished:NO];
390 } 402 }
391 } 403 }
392 404
393 - if (imageSource) {  
394 - CFRelease(imageSource); 405 + if (finished) {
  406 + if (_imageSource) {
  407 + CFRelease(_imageSource);
  408 + _imageSource = NULL;
  409 + }
395 } 410 }
396 } 411 }
397 412