Authored by DreamPiggy

Fixed animated WebP image frame size wrong

Fix animated WebP image decoder bug causing rendering canvas in current canvas size context but not image size context for multiple frame.
@@ -56,9 +56,9 @@ static void FreeImageData(void *info, const void *data, size_t size) { @@ -56,9 +56,9 @@ static void FreeImageData(void *info, const void *data, size_t size) {
56 do { 56 do {
57 UIImage *image; 57 UIImage *image;
58 if (iter.blend_method == WEBP_MUX_BLEND) { 58 if (iter.blend_method == WEBP_MUX_BLEND) {
59 - image = [self sd_blendWebpImageWithOriginImage:[images lastObject] iterator:iter]; 59 + image = [self sd_blendWebpImageWithOriginImage:[images lastObject] demuxer:demuxer iterator:iter];
60 } else { 60 } else {
61 - image = [self sd_rawWepImageWithData:iter.fragment]; 61 + image = [self sd_nonblendWebpImageWithData:iter.fragment demuxer:demuxer iterator:iter];
62 } 62 }
63 63
64 if (!image) { 64 if (!image) {
@@ -85,22 +85,24 @@ static void FreeImageData(void *info, const void *data, size_t size) { @@ -85,22 +85,24 @@ static void FreeImageData(void *info, const void *data, size_t size) {
85 } 85 }
86 86
87 87
88 -+ (nullable UIImage *)sd_blendWebpImageWithOriginImage:(nullable UIImage *)originImage iterator:(WebPIterator)iter { 88 ++ (nullable UIImage *)sd_blendWebpImageWithOriginImage:(nullable UIImage *)originImage demuxer:(WebPDemuxer *)demuxer iterator:(WebPIterator)iter {
89 if (!originImage) { 89 if (!originImage) {
90 return nil; 90 return nil;
91 } 91 }
92 92
93 - CGSize size = originImage.size;  
94 - CGFloat tmpX = iter.x_offset;  
95 - CGFloat tmpY = size.height - iter.height - iter.y_offset;  
96 - CGRect imageRect = CGRectMake(tmpX, tmpY, iter.width, iter.height);  
97 -  
98 UIImage *image = [self sd_rawWepImageWithData:iter.fragment]; 93 UIImage *image = [self sd_rawWepImageWithData:iter.fragment];
99 if (!image) { 94 if (!image) {
100 return nil; 95 return nil;
101 } 96 }
102 97
103 - CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); 98 + int canvasWidth = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_WIDTH);
  99 + int canvasHeight = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_HEIGHT);
  100 + CGSize size = CGSizeMake(canvasWidth, canvasHeight);
  101 + CGFloat tmpX = iter.x_offset;
  102 + CGFloat tmpY = size.height - iter.height - iter.y_offset;
  103 + CGRect imageRect = CGRectMake(tmpX, tmpY, iter.width, iter.height);
  104 +
  105 + CGColorSpaceRef colorSpaceRef = sd_CGColorSpaceGetDeviceRGB();
104 uint32_t bitmapInfo = iter.has_alpha ? kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast : 0; 106 uint32_t bitmapInfo = iter.has_alpha ? kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast : 0;
105 CGContextRef blendCanvas = CGBitmapContextCreate(NULL, size.width, size.height, 8, 0, colorSpaceRef, bitmapInfo); 107 CGContextRef blendCanvas = CGBitmapContextCreate(NULL, size.width, size.height, 8, 0, colorSpaceRef, bitmapInfo);
106 CGContextDrawImage(blendCanvas, CGRectMake(0, 0, size.width, size.height), originImage.CGImage); 108 CGContextDrawImage(blendCanvas, CGRectMake(0, 0, size.width, size.height), originImage.CGImage);
@@ -115,7 +117,40 @@ static void FreeImageData(void *info, const void *data, size_t size) { @@ -115,7 +117,40 @@ static void FreeImageData(void *info, const void *data, size_t size) {
115 117
116 CGImageRelease(newImageRef); 118 CGImageRelease(newImageRef);
117 CGContextRelease(blendCanvas); 119 CGContextRelease(blendCanvas);
118 - CGColorSpaceRelease(colorSpaceRef); 120 +
  121 + return image;
  122 +}
  123 +
  124 ++ (nullable UIImage *)sd_nonblendWebpImageWithData:(WebPData)webpData demuxer:(WebPDemuxer *)demuxer iterator:(WebPIterator)iter {
  125 + UIImage *image = [self sd_rawWepImageWithData:iter.fragment];
  126 + if (!image) {
  127 + return nil;
  128 + }
  129 +
  130 + int canvasWidth = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_WIDTH);
  131 + int canvasHeight = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_HEIGHT);
  132 + CGSize size = CGSizeMake(canvasWidth, canvasHeight);
  133 + CGFloat tmpX = iter.x_offset;
  134 + CGFloat tmpY = size.height - iter.height - iter.y_offset;
  135 + CGRect imageRect = CGRectMake(tmpX, tmpY, iter.width, iter.height);
  136 + if (CGRectEqualToRect(imageRect, CGRectMake(0, 0, canvasWidth, canvasHeight))) {
  137 + return image;
  138 + }
  139 +
  140 + CGColorSpaceRef colorSpaceRef = sd_CGColorSpaceGetDeviceRGB();
  141 + uint32_t bitmapInfo = kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast;
  142 + CGContextRef canvas = CGBitmapContextCreate(NULL, size.width, size.height, 8, 0, colorSpaceRef, bitmapInfo);
  143 + CGContextDrawImage(canvas, imageRect, image.CGImage);
  144 + CGImageRef newImageRef = CGBitmapContextCreateImage(canvas);
  145 +
  146 +#if SD_UIKIT || SD_WATCH
  147 + image = [UIImage imageWithCGImage:newImageRef];
  148 +#elif SD_MAC
  149 + image = [[UIImage alloc] initWithCGImage:newImageRef size:NSZeroSize];
  150 +#endif
  151 +
  152 + CGImageRelease(newImageRef);
  153 + CGContextRelease(canvas);
119 154
120 return image; 155 return image;
121 } 156 }
@@ -148,13 +183,12 @@ static void FreeImageData(void *info, const void *data, size_t size) { @@ -148,13 +183,12 @@ static void FreeImageData(void *info, const void *data, size_t size) {
148 // Construct a UIImage from the decoded RGBA value array. 183 // Construct a UIImage from the decoded RGBA value array.
149 CGDataProviderRef provider = 184 CGDataProviderRef provider =
150 CGDataProviderCreateWithData(NULL, config.output.u.RGBA.rgba, config.output.u.RGBA.size, FreeImageData); 185 CGDataProviderCreateWithData(NULL, config.output.u.RGBA.rgba, config.output.u.RGBA.size, FreeImageData);
151 - CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); 186 + CGColorSpaceRef colorSpaceRef = sd_CGColorSpaceGetDeviceRGB();
152 CGBitmapInfo bitmapInfo = config.input.has_alpha ? kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast : 0; 187 CGBitmapInfo bitmapInfo = config.input.has_alpha ? kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast : 0;
153 size_t components = config.input.has_alpha ? 4 : 3; 188 size_t components = config.input.has_alpha ? 4 : 3;
154 CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; 189 CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
155 CGImageRef imageRef = CGImageCreate(width, height, 8, components * 8, components * width, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent); 190 CGImageRef imageRef = CGImageCreate(width, height, 8, components * 8, components * width, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
156 191
157 - CGColorSpaceRelease(colorSpaceRef);  
158 CGDataProviderRelease(provider); 192 CGDataProviderRelease(provider);
159 193
160 #if SD_UIKIT || SD_WATCH 194 #if SD_UIKIT || SD_WATCH
@@ -167,6 +201,15 @@ static void FreeImageData(void *info, const void *data, size_t size) { @@ -167,6 +201,15 @@ static void FreeImageData(void *info, const void *data, size_t size) {
167 return image; 201 return image;
168 } 202 }
169 203
  204 +CGColorSpaceRef sd_CGColorSpaceGetDeviceRGB() {
  205 + static CGColorSpaceRef space;
  206 + static dispatch_once_t onceToken;
  207 + dispatch_once(&onceToken, ^{
  208 + space = CGColorSpaceCreateDeviceRGB();
  209 + });
  210 + return space;
  211 +}
  212 +
170 @end 213 @end
171 214
172 #endif 215 #endif