Committed by
GitHub
Merge pull request #2040 from dreampiggy/Fix_progressive_download_gray_background
Use CGImageSourceCreateIncremental to perform progressive decoding in…
Showing
2 changed files
with
32 additions
and
18 deletions
@@ -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 |
-
Please register or login to post a comment