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.
Showing
1 changed file
with
55 additions
and
12 deletions
@@ -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 |
-
Please register or login to post a comment