Add support to animted WebP dispose method
dispose method is widely used in animated WebP images and should add support
Showing
1 changed file
with
29 additions
and
28 deletions
@@ -53,12 +53,16 @@ static void FreeImageData(void *info, const void *data, size_t size) { | @@ -53,12 +53,16 @@ static void FreeImageData(void *info, const void *data, size_t size) { | ||
53 | NSMutableArray *images = [NSMutableArray array]; | 53 | NSMutableArray *images = [NSMutableArray array]; |
54 | NSTimeInterval duration = 0; | 54 | NSTimeInterval duration = 0; |
55 | 55 | ||
56 | + int canvasWidth = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_WIDTH); | ||
57 | + int canvasHeight = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_HEIGHT); | ||
58 | + CGContextRef canvas = CGBitmapContextCreate(NULL, canvasWidth, canvasHeight, 8, 0, sd_CGColorSpaceGetDeviceRGB(), kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast); | ||
59 | + | ||
56 | do { | 60 | do { |
57 | UIImage *image; | 61 | UIImage *image; |
58 | if (iter.blend_method == WEBP_MUX_BLEND) { | 62 | if (iter.blend_method == WEBP_MUX_BLEND) { |
59 | - image = [self sd_blendWebpImageWithOriginImage:images.lastObject demuxer:demuxer iterator:iter]; | 63 | + image = [self sd_blendWebpImageWithCanvas:canvas iterator:iter]; |
60 | } else { | 64 | } else { |
61 | - image = [self sd_nonblendWebpImageWithDemuxer:demuxer iterator:iter]; | 65 | + image = [self sd_nonblendWebpImageWithCanvas:canvas iterator:iter]; |
62 | } | 66 | } |
63 | 67 | ||
64 | if (!image) { | 68 | if (!image) { |
@@ -72,6 +76,7 @@ static void FreeImageData(void *info, const void *data, size_t size) { | @@ -72,6 +76,7 @@ static void FreeImageData(void *info, const void *data, size_t size) { | ||
72 | 76 | ||
73 | WebPDemuxReleaseIterator(&iter); | 77 | WebPDemuxReleaseIterator(&iter); |
74 | WebPDemuxDelete(demuxer); | 78 | WebPDemuxDelete(demuxer); |
79 | + CGContextRelease(canvas); | ||
75 | 80 | ||
76 | UIImage *finalImage = nil; | 81 | UIImage *finalImage = nil; |
77 | #if SD_UIKIT || SD_WATCH | 82 | #if SD_UIKIT || SD_WATCH |
@@ -85,29 +90,21 @@ static void FreeImageData(void *info, const void *data, size_t size) { | @@ -85,29 +90,21 @@ static void FreeImageData(void *info, const void *data, size_t size) { | ||
85 | } | 90 | } |
86 | 91 | ||
87 | 92 | ||
88 | -+ (nullable UIImage *)sd_blendWebpImageWithOriginImage:(nullable UIImage *)originImage demuxer:(WebPDemuxer *)demuxer iterator:(WebPIterator)iter { | ||
89 | - if (!originImage) { | ||
90 | - return nil; | ||
91 | - } | ||
92 | - | 93 | ++ (nullable UIImage *)sd_blendWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter { |
93 | UIImage *image = [self sd_rawWebpImageWithData:iter.fragment]; | 94 | UIImage *image = [self sd_rawWebpImageWithData:iter.fragment]; |
94 | if (!image) { | 95 | if (!image) { |
95 | return nil; | 96 | return nil; |
96 | } | 97 | } |
97 | 98 | ||
98 | - int canvasWidth = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_WIDTH); | ||
99 | - int canvasHeight = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_HEIGHT); | 99 | + size_t canvasWidth = CGBitmapContextGetWidth(canvas); |
100 | + size_t canvasHeight = CGBitmapContextGetHeight(canvas); | ||
100 | CGSize size = CGSizeMake(canvasWidth, canvasHeight); | 101 | CGSize size = CGSizeMake(canvasWidth, canvasHeight); |
101 | CGFloat tmpX = iter.x_offset; | 102 | CGFloat tmpX = iter.x_offset; |
102 | CGFloat tmpY = size.height - iter.height - iter.y_offset; | 103 | CGFloat tmpY = size.height - iter.height - iter.y_offset; |
103 | CGRect imageRect = CGRectMake(tmpX, tmpY, iter.width, iter.height); | 104 | CGRect imageRect = CGRectMake(tmpX, tmpY, iter.width, iter.height); |
104 | 105 | ||
105 | - CGColorSpaceRef colorSpaceRef = sd_CGColorSpaceGetDeviceRGB(); | ||
106 | - uint32_t bitmapInfo = iter.has_alpha ? kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast : kCGBitmapByteOrder32Big | kCGImageAlphaNoneSkipLast; | ||
107 | - CGContextRef blendCanvas = CGBitmapContextCreate(NULL, size.width, size.height, 8, 0, colorSpaceRef, bitmapInfo); | ||
108 | - CGContextDrawImage(blendCanvas, CGRectMake(0, 0, size.width, size.height), originImage.CGImage); | ||
109 | - CGContextDrawImage(blendCanvas, imageRect, image.CGImage); | ||
110 | - CGImageRef newImageRef = CGBitmapContextCreateImage(blendCanvas); | 106 | + CGContextDrawImage(canvas, imageRect, image.CGImage); |
107 | + CGImageRef newImageRef = CGBitmapContextCreateImage(canvas); | ||
111 | 108 | ||
112 | #if SD_UIKIT || SD_WATCH | 109 | #if SD_UIKIT || SD_WATCH |
113 | image = [UIImage imageWithCGImage:newImageRef]; | 110 | image = [UIImage imageWithCGImage:newImageRef]; |
@@ -116,31 +113,30 @@ static void FreeImageData(void *info, const void *data, size_t size) { | @@ -116,31 +113,30 @@ static void FreeImageData(void *info, const void *data, size_t size) { | ||
116 | #endif | 113 | #endif |
117 | 114 | ||
118 | CGImageRelease(newImageRef); | 115 | CGImageRelease(newImageRef); |
119 | - CGContextRelease(blendCanvas); | 116 | + |
117 | + if (iter.dispose_method == WEBP_MUX_DISPOSE_NONE) { | ||
118 | + // do not dispose | ||
119 | + } else { | ||
120 | + CGContextClearRect(canvas, imageRect); | ||
121 | + } | ||
120 | 122 | ||
121 | return image; | 123 | return image; |
122 | } | 124 | } |
123 | 125 | ||
124 | -+ (nullable UIImage *)sd_nonblendWebpImageWithDemuxer:(WebPDemuxer *)demuxer iterator:(WebPIterator)iter { | 126 | ++ (nullable UIImage *)sd_nonblendWebpImageWithCanvas:(CGContextRef)canvas iterator:(WebPIterator)iter { |
125 | UIImage *image = [self sd_rawWebpImageWithData:iter.fragment]; | 127 | UIImage *image = [self sd_rawWebpImageWithData:iter.fragment]; |
126 | if (!image) { | 128 | if (!image) { |
127 | return nil; | 129 | return nil; |
128 | } | 130 | } |
129 | 131 | ||
130 | - if (iter.x_offset == 0 && iter.y_offset == 0) { | ||
131 | - return image; | ||
132 | - } | ||
133 | - | ||
134 | - int canvasWidth = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_WIDTH); | ||
135 | - int canvasHeight = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_HEIGHT); | 132 | + size_t canvasWidth = CGBitmapContextGetWidth(canvas); |
133 | + size_t canvasHeight = CGBitmapContextGetHeight(canvas); | ||
136 | CGSize size = CGSizeMake(canvasWidth, canvasHeight); | 134 | CGSize size = CGSizeMake(canvasWidth, canvasHeight); |
137 | CGFloat tmpX = iter.x_offset; | 135 | CGFloat tmpX = iter.x_offset; |
138 | CGFloat tmpY = size.height - iter.height - iter.y_offset; | 136 | CGFloat tmpY = size.height - iter.height - iter.y_offset; |
139 | CGRect imageRect = CGRectMake(tmpX, tmpY, iter.width, iter.height); | 137 | CGRect imageRect = CGRectMake(tmpX, tmpY, iter.width, iter.height); |
140 | 138 | ||
141 | - CGColorSpaceRef colorSpaceRef = sd_CGColorSpaceGetDeviceRGB(); | ||
142 | - uint32_t bitmapInfo = iter.has_alpha ? kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast : kCGBitmapByteOrder32Big | kCGImageAlphaNoneSkipLast; | ||
143 | - CGContextRef canvas = CGBitmapContextCreate(NULL, size.width, size.height, 8, 0, colorSpaceRef, bitmapInfo); | 139 | + CGContextClearRect(canvas, imageRect); |
144 | CGContextDrawImage(canvas, imageRect, image.CGImage); | 140 | CGContextDrawImage(canvas, imageRect, image.CGImage); |
145 | CGImageRef newImageRef = CGBitmapContextCreateImage(canvas); | 141 | CGImageRef newImageRef = CGBitmapContextCreateImage(canvas); |
146 | 142 | ||
@@ -151,7 +147,12 @@ static void FreeImageData(void *info, const void *data, size_t size) { | @@ -151,7 +147,12 @@ static void FreeImageData(void *info, const void *data, size_t size) { | ||
151 | #endif | 147 | #endif |
152 | 148 | ||
153 | CGImageRelease(newImageRef); | 149 | CGImageRelease(newImageRef); |
154 | - CGContextRelease(canvas); | 150 | + |
151 | + if (iter.dispose_method == WEBP_MUX_DISPOSE_NONE) { | ||
152 | + // do not dispose | ||
153 | + } else { | ||
154 | + CGContextClearRect(canvas, imageRect); | ||
155 | + } | ||
155 | 156 | ||
156 | return image; | 157 | return image; |
157 | } | 158 | } |
@@ -202,7 +203,7 @@ static void FreeImageData(void *info, const void *data, size_t size) { | @@ -202,7 +203,7 @@ static void FreeImageData(void *info, const void *data, size_t size) { | ||
202 | return image; | 203 | return image; |
203 | } | 204 | } |
204 | 205 | ||
205 | -CGColorSpaceRef sd_CGColorSpaceGetDeviceRGB() { | 206 | +static CGColorSpaceRef sd_CGColorSpaceGetDeviceRGB() { |
206 | static CGColorSpaceRef space; | 207 | static CGColorSpaceRef space; |
207 | static dispatch_once_t onceToken; | 208 | static dispatch_once_t onceToken; |
208 | dispatch_once(&onceToken, ^{ | 209 | dispatch_once(&onceToken, ^{ |
-
Please register or login to post a comment