Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(128)

Side by Side Diff: src/codec/SkCodec_libgif.cpp

Issue 1055743003: Swizzler changes Index8 and 565 (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Fix windows errors Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/codec/SkCodec_libgif.h ('k') | src/codec/SkCodec_libpng.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkCodec_libgif.h" 8 #include "SkCodec_libgif.h"
9 #include "SkCodecPriv.h" 9 #include "SkCodecPriv.h"
10 #include "SkColorPriv.h" 10 #include "SkColorPriv.h"
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 return DGifOpen(stream, read_bytes_callback); 63 return DGifOpen(stream, read_bytes_callback);
64 #else 64 #else
65 return DGifOpen(stream, read_bytes_callback, NULL); 65 return DGifOpen(stream, read_bytes_callback, NULL);
66 #endif 66 #endif
67 } 67 }
68 68
69 /* 69 /*
70 * This function cleans up the gif object after the decode completes 70 * This function cleans up the gif object after the decode completes
71 * It is used in a SkAutoTCallIProc template 71 * It is used in a SkAutoTCallIProc template
72 */ 72 */
73 int32_t SkGifCodec::CloseGif(GifFileType* gif) { 73 void SkGifCodec::CloseGif(GifFileType* gif) {
74 #if GIFLIB_MAJOR < 5 || (GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 0) 74 #if GIFLIB_MAJOR < 5 || (GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 0)
75 return DGifCloseFile(gif); 75 DGifCloseFile(gif);
76 #else 76 #else
77 return DGifCloseFile(gif, NULL); 77 DGifCloseFile(gif, NULL);
78 #endif 78 #endif
79 } 79 }
80 80
81 /* 81 /*
82 * This function free extension data that has been saved to assist the image 82 * This function free extension data that has been saved to assist the image
83 * decoder 83 * decoder
84 */ 84 */
85 void SkGifCodec::FreeExtension(SavedImage* image) { 85 void SkGifCodec::FreeExtension(SavedImage* image) {
86 if (NULL != image->ExtensionBlocks) { 86 if (NULL != image->ExtensionBlocks) {
87 #if GIFLIB_MAJOR < 5 87 #if GIFLIB_MAJOR < 5
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 break; 124 break;
125 } 125 }
126 } 126 }
127 127
128 // Use maximum unsigned int (surely an invalid index) to indicate that a val id 128 // Use maximum unsigned int (surely an invalid index) to indicate that a val id
129 // index was not found. 129 // index was not found.
130 return SK_MaxU32; 130 return SK_MaxU32;
131 } 131 }
132 132
133 /* 133 /*
134 * Read enough of the stream to initialize the SkGifCodec.
135 * Returns a bool representing success or failure.
136 *
137 * @param codecOut
138 * If it returned true, and codecOut was not NULL,
139 * codecOut will be set to a new SkGifCodec.
140 *
141 * @param gifOut
142 * If it returned true, and codecOut was NULL,
143 * gifOut must be non-NULL and gifOut will be set to a new
144 * GifFileType pointer.
145 *
146 * @param stream
147 * Deleted on failure.
148 * codecOut will take ownership of it in the case where we created a codec.
149 * Ownership is unchanged when we returned a gifOut.
150 *
151 */
152 bool SkGifCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, GifFileType** gifOut) {
153 SkAutoTDelete<SkStream> streamDeleter(stream);
154
155 // Read gif header, logical screen descriptor, and global color table
156 SkAutoTCallVProc<GifFileType, CloseGif> gif(open_gif(stream));
157
158 if (NULL == gif) {
159 gif_error("DGifOpen failed.\n");
160 return false;
161 }
162
163 if (NULL != codecOut) {
164 // Get fields from header
165 const int32_t width = gif->SWidth;
166 const int32_t height = gif->SHeight;
167 if (width <= 0 || height <= 0) {
168 gif_error("Invalid dimensions.\n");
169 return false;
170 }
171
172 // Return the codec
173 // kIndex is the most natural color type for gifs, so we set this as
174 // the default.
175 // Many gifs specify a color table index for transparent pixels. Every
176 // other pixel is guaranteed to be opaque. Despite this, because of the
177 // possiblity of transparent pixels, we cannot assume that the image is
178 // opaque. We have the option to set the alpha type as kPremul or
179 // kUnpremul. Both are valid since the alpha component will always be
180 // 0xFF or the entire 32-bit pixel will be set to zero. We prefer
181 // kPremul because we support kPremul, and it is more efficient to
182 // use kPremul directly even when kUnpremul is supported.
183 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height,
184 kIndex_8_SkColorType, kPremul_SkAlphaType);
185 *codecOut = SkNEW_ARGS(SkGifCodec, (imageInfo, streamDeleter.detach(), g if.detach()));
186 } else {
187 SkASSERT(NULL != gifOut);
188 streamDeleter.detach();
189 *gifOut = gif.detach();
190 }
191 return true;
192 }
193
194 /*
134 * Assumes IsGif was called and returned true 195 * Assumes IsGif was called and returned true
135 * Creates a gif decoder 196 * Creates a gif decoder
136 * Reads enough of the stream to determine the image format 197 * Reads enough of the stream to determine the image format
137 */ 198 */
138 SkCodec* SkGifCodec::NewFromStream(SkStream* stream) { 199 SkCodec* SkGifCodec::NewFromStream(SkStream* stream) {
139 SkAutoTDelete<SkStream> streamDeleter(stream); 200 SkCodec* codec = NULL;
140 // Read gif header, logical screen descriptor, and global color table 201 if (ReadHeader(stream, &codec, NULL)) {
141 SkAutoTCallIProc<GifFileType, CloseGif> gif(open_gif(stream)); 202 return codec;
142
143 if (NULL == gif) {
144 gif_error("DGifOpen failed.\n");
145 return NULL;
146 } 203 }
147 204 return NULL;
148 // Get fields from header
149 const int32_t width = gif->SWidth;
150 const int32_t height = gif->SHeight;
151 if (width <= 0 || height <= 0) {
152 gif_error("Invalid dimensions.\n");
153 return NULL;
154 }
155
156 // Return the codec
157 // kIndex is the most natural color type for gifs, so we set this as
158 // the default.
159 // Many gifs specify a color table index for transparent pixels. Every
160 // other pixel is guaranteed to be opaque. Despite this, because of the
161 // possiblity of transparent pixels, we cannot assume that the image is
162 // opaque. We have the option to set the alpha type as kPremul or
163 // kUnpremul. Both are valid since the alpha component will always be
164 // 0xFF or the entire 32-bit pixel will be set to zero. We prefer
165 // kPremul because we support kPremul, and it is more efficient to
166 // use kPremul directly even when kUnpremul is supported.
167 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height,
168 kIndex_8_SkColorType, kPremul_SkAlphaType);
169 return SkNEW_ARGS(SkGifCodec, (imageInfo, streamDeleter.detach(), gif.detach ()));
170 } 205 }
171 206
172 SkGifCodec::SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream, 207 SkGifCodec::SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream,
173 GifFileType* gif) 208 GifFileType* gif)
174 : INHERITED(srcInfo, stream) 209 : INHERITED(srcInfo, stream)
175 , fGif(gif) 210 , fGif(gif)
176 {} 211 {}
177 212
178 /* 213 /*
179 * Checks if the conversion between the input image and the requested output 214 * Checks if the conversion between the input image and the requested output
180 * image has been implemented 215 * image has been implemented
181 */ 216 */
182 static bool conversion_possible(const SkImageInfo& dst, 217 static bool conversion_possible(const SkImageInfo& dst,
183 const SkImageInfo& src) { 218 const SkImageInfo& src) {
184 // Ensure that the profile type is unchanged 219 // Ensure that the profile type is unchanged
185 if (dst.profileType() != src.profileType()) { 220 if (dst.profileType() != src.profileType()) {
186 return false; 221 return false;
187 } 222 }
188 223
189 // Check for supported color and alpha types 224 // Check for supported color and alpha types
190 switch (dst.colorType()) { 225 switch (dst.colorType()) {
191 case kN32_SkColorType: 226 case kN32_SkColorType:
192 return kPremul_SkAlphaType == dst.alphaType() || 227 return kPremul_SkAlphaType == dst.alphaType() ||
193 kUnpremul_SkAlphaType == dst.alphaType(); 228 kUnpremul_SkAlphaType == dst.alphaType();
229 case kIndex_8_SkColorType:
230 return kPremul_SkAlphaType == dst.alphaType() ||
231 kUnpremul_SkAlphaType == dst.alphaType();
194 default: 232 default:
195 return false; 233 return false;
196 } 234 }
197 } 235 }
198 236
199 /* 237 /*
200 * Initiates the gif decode 238 * Initiates the gif decode
201 */ 239 */
202 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, 240 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo,
203 void* dst, size_t dstRowBytes, 241 void* dst, size_t dstRowBytes,
204 const Options& opts, SkPMColor*, int*) { 242 const Options& opts,
243 SkPMColor* inputColorPtr,
244 int* inputColorCount) {
245 // Rewind if necessary
246 SkCodec::RewindState rewindState = this->rewindIfNeeded();
247 if (rewindState == kCouldNotRewind_RewindState) {
248 return kCouldNotRewind;
249 } else if (rewindState == kRewound_RewindState) {
250 GifFileType* gifOut = NULL;
251 if (!ReadHeader(this->stream(), NULL, &gifOut)) {
252 return kCouldNotRewind;
253 } else {
254 SkASSERT(NULL != gifOut);
255 fGif.reset(gifOut);
256 }
257 }
258
205 // Check for valid input parameters 259 // Check for valid input parameters
206 if (!this->rewindIfNeeded()) {
207 return kCouldNotRewind;
208 }
209 if (dstInfo.dimensions() != this->getInfo().dimensions()) { 260 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
210 return gif_error("Scaling not supported.\n", kInvalidScale); 261 return gif_error("Scaling not supported.\n", kInvalidScale);
211 } 262 }
212 if (!conversion_possible(dstInfo, this->getInfo())) { 263 if (!conversion_possible(dstInfo, this->getInfo())) {
213 return gif_error("Cannot convert input type to output type.\n", 264 return gif_error("Cannot convert input type to output type.\n",
214 kInvalidConversion); 265 kInvalidConversion);
215 } 266 }
216 267
217 // Use this as a container to hold information about any gif extension 268 // Use this as a container to hold information about any gif extension
218 // blocks. This generally stores transparency and animation instructions. 269 // blocks. This generally stores transparency and animation instructions.
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 innerHeight = height; 329 innerHeight = height;
279 imageTop = 0; 330 imageTop = 0;
280 } else if (imageTop + innerHeight > height) { 331 } else if (imageTop + innerHeight > height) {
281 gif_warning("Shifting inner image up to fit.\n"); 332 gif_warning("Shifting inner image up to fit.\n");
282 imageTop = height - innerHeight; 333 imageTop = height - innerHeight;
283 } else if (imageTop < 0) { 334 } else if (imageTop < 0) {
284 gif_warning("Shifting image down to fit\n"); 335 gif_warning("Shifting image down to fit\n");
285 imageTop = 0; 336 imageTop = 0;
286 } 337 }
287 338
339 // Create a color table to store colors the giflib colorMap
340 SkPMColor alternateColorPtr[256];
341 SkPMColor* colorTable;
342 SkColorType dstColorType = dstInfo.colorType();
343 if (kIndex_8_SkColorType == dstColorType) {
344 SkASSERT(NULL != inputColorPtr);
345 SkASSERT(NULL != inputColorCount);
346 SkASSERT(256 == *inputColorCount);
347 colorTable = inputColorPtr;
348 } else {
349 colorTable = alternateColorPtr;
350 }
351
288 // Set up the color table 352 // Set up the color table
289 uint32_t colorCount = 0; 353 uint32_t colorCount = 0;
290 // Allocate maximum storage to deal with invalid indices safely 354 // Allocate maximum storage to deal with invalid indices safely
291 const uint32_t maxColors = 256; 355 const uint32_t maxColors = 256;
292 SkPMColor colorTable[maxColors];
293 ColorMapObject* colorMap = fGif->Image.ColorMap; 356 ColorMapObject* colorMap = fGif->Image.ColorMap;
294 // If there is no local color table, use the global color table 357 // If there is no local color table, use the global color table
295 if (NULL == colorMap) { 358 if (NULL == colorMap) {
296 colorMap = fGif->SColorMap; 359 colorMap = fGif->SColorMap;
297 } 360 }
298 if (NULL != colorMap) { 361 if (NULL != colorMap) {
299 colorCount = colorMap->ColorCount; 362 colorCount = colorMap->ColorCount;
300 SkASSERT(colorCount == 363 SkASSERT(colorCount ==
301 (unsigned) (1 << (colorMap->BitsPerPixel))); 364 (unsigned) (1 << (colorMap->BitsPerPixel)));
302 SkASSERT(colorCount <= 256); 365 SkASSERT(colorCount <= 256);
303 for (uint32_t i = 0; i < colorCount; i++) { 366 for (uint32_t i = 0; i < colorCount; i++) {
304 colorTable[i] = SkPackARGB32(0xFF, 367 colorTable[i] = SkPackARGB32(0xFF,
305 colorMap->Colors[i].Red, 368 colorMap->Colors[i].Red,
306 colorMap->Colors[i].Green, 369 colorMap->Colors[i].Green,
307 colorMap->Colors[i].Blue); 370 colorMap->Colors[i].Blue);
308 } 371 }
309 } 372 }
310 373
311 // This is used to fill unspecified pixels in the image data. 374 // This is used to fill unspecified pixels in the image data.
312 uint32_t fillIndex = fGif->SBackGroundColor; 375 uint32_t fillIndex = fGif->SBackGroundColor;
313 bool fillBackground = true;
314 ZeroInitialized zeroInit = opts.fZeroInitialized; 376 ZeroInitialized zeroInit = opts.fZeroInitialized;
315 377
316 // Gifs have the option to specify the color at a single 378 // Gifs have the option to specify the color at a single
317 // index of the color table as transparent. 379 // index of the color table as transparent.
318 { 380 {
319 // Get the transparent index. If the return value of this 381 // Get the transparent index. If the return value of this
320 // function is greater than the colorCount, we know that 382 // function is greater than the colorCount, we know that
321 // there is no valid transparent color in the color table. 383 // there is no valid transparent color in the color table.
322 // This occurs if there is no graphics control extension or 384 // This occurs if there is no graphics control extension or
323 // if the index specified by the graphics control extension 385 // if the index specified by the graphics control extension
324 // is out of range. 386 // is out of range.
325 uint32_t transIndex = find_trans_index(saveExt); 387 uint32_t transIndex = find_trans_index(saveExt);
326 388
327 // If the background is already zeroed and we have a valid
328 // transparent index, we do not need to fill the background.
329 if (transIndex < colorCount) { 389 if (transIndex < colorCount) {
330 colorTable[transIndex] = SK_ColorTRANSPARENT; 390 colorTable[transIndex] = SK_ColorTRANSPARENT;
331 // If there is a transparent index, we also use this as 391 // If there is a transparent index, we also use this as
332 // the fill index. 392 // the fill index.
333 fillIndex = transIndex; 393 fillIndex = transIndex;
334 fillBackground = (kYes_ZeroInitialized != zeroInit);
335 } else if (fillIndex >= colorCount) { 394 } else if (fillIndex >= colorCount) {
336 // If the fill index is invalid, we default to 0. This 395 // If the fill index is invalid, we default to 0. This
337 // behavior is unspecified but matches SkImageDecoder. 396 // behavior is unspecified but matches SkImageDecoder.
338 fillIndex = 0; 397 fillIndex = 0;
339 } 398 }
340 } 399 }
341 400
401 // Check if we can skip filling the background of the image. We
402 // may be able to if the memory is zero initialized.
403 bool skipBackground =
404 ((kN32_SkColorType == dstColorType && colorTable[fillInd ex] == 0) ||
405 (kIndex_8_SkColorType == dstColorType && fillIndex == 0) ) &&
406 kYes_ZeroInitialized == zeroInit;
407
408
342 // Fill in the color table for indices greater than color count. 409 // Fill in the color table for indices greater than color count.
343 // This allows for predictable, safe behavior. 410 // This allows for predictable, safe behavior.
344 for (uint32_t i = colorCount; i < maxColors; i++) { 411 for (uint32_t i = colorCount; i < maxColors; i++) {
345 colorTable[i] = colorTable[fillIndex]; 412 colorTable[i] = colorTable[fillIndex];
346 } 413 }
347 414
348 // Check if image is only a subset of the image frame 415 // Check if image is only a subset of the image frame
349 SkAutoTDelete<SkSwizzler> swizzler(NULL); 416 SkAutoTDelete<SkSwizzler> swizzler(NULL);
350 if (innerWidth < width || innerHeight < height) { 417 if (innerWidth < width || innerHeight < height) {
351 418
352 // Modify the destination info 419 // Modify the destination info
353 const SkImageInfo subsetDstInfo = 420 const SkImageInfo subsetDstInfo =
354 dstInfo.makeWH(innerWidth, innerHeight); 421 dstInfo.makeWH(innerWidth, innerHeight);
355 422
356 // Fill the destination with the fill color 423 // Fill the destination with the fill color
357 // FIXME: This may not be the behavior that we want for 424 // FIXME: This may not be the behavior that we want for
358 // animated gifs where we draw on top of the 425 // animated gifs where we draw on top of the
359 // previous frame. 426 // previous frame.
360 SkColorType dstColorType = dstInfo.colorType(); 427 if (!skipBackground) {
361 if (fillBackground) { 428 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, 0, fillIndex , colorTable);
362 switch (dstColorType) {
363 case kN32_SkColorType:
364 sk_memset32((SkPMColor*) dst,
365 colorTable[fillIndex],
366 ((int) dstRowBytes) * height
367 / sizeof(SkPMColor));
368 break;
369 default:
370 SkASSERT(false);
371 break;
372 }
373 } 429 }
374 430
375 // Modify the dst pointer 431 // Modify the dst pointer
376 const int32_t dstBytesPerPixel = 432 const int32_t dstBytesPerPixel =
377 SkColorTypeBytesPerPixel(dstColorType); 433 SkColorTypeBytesPerPixel(dstColorType);
378 void* subsetDst = SkTAddOffset<void*>(dst, 434 void* subsetDst = SkTAddOffset<void*>(dst,
379 dstRowBytes * imageTop + 435 dstRowBytes * imageTop +
380 dstBytesPerPixel * imageLeft); 436 dstBytesPerPixel * imageLeft);
381 437
382 // Create the subset swizzler 438 // Create the subset swizzler
(...skipping 14 matching lines...) Expand all
397 // Check the interlace flag and iterate over rows of the input 453 // Check the interlace flag and iterate over rows of the input
398 if (fGif->Image.Interlace) { 454 if (fGif->Image.Interlace) {
399 // In interlace mode, the rows of input are rearranged in 455 // In interlace mode, the rows of input are rearranged in
400 // the output image. We use an iterator to take care of 456 // the output image. We use an iterator to take care of
401 // the rearranging. 457 // the rearranging.
402 SkGifInterlaceIter iter(innerHeight); 458 SkGifInterlaceIter iter(innerHeight);
403 for (int32_t y = 0; y < innerHeight; y++) { 459 for (int32_t y = 0; y < innerHeight; y++) {
404 if (GIF_ERROR == DGifGetLine(fGif, buffer.get(), 460 if (GIF_ERROR == DGifGetLine(fGif, buffer.get(),
405 innerWidth)) { 461 innerWidth)) {
406 // Recover from error by filling remainder of image 462 // Recover from error by filling remainder of image
407 if (fillBackground) { 463 if (!skipBackground) {
408 memset(buffer.get(), fillIndex, innerWidth); 464 memset(buffer.get(), fillIndex, innerWidth);
409 for (; y < innerHeight; y++) { 465 for (; y < innerHeight; y++) {
410 swizzler->next(buffer.get(), iter.nextY()); 466 swizzler->next(buffer.get(), iter.nextY());
411 } 467 }
412 } 468 }
413 return gif_error(SkStringPrintf( 469 return gif_error(SkStringPrintf(
414 "Could not decode line %d of %d.\n", 470 "Could not decode line %d of %d.\n",
415 y, height - 1).c_str(), kIncompleteInput); 471 y, height - 1).c_str(), kIncompleteInput);
416 } 472 }
417 swizzler->next(buffer.get(), iter.nextY()); 473 swizzler->next(buffer.get(), iter.nextY());
418 } 474 }
419 } else { 475 } else {
420 // Standard mode 476 // Standard mode
421 for (int32_t y = 0; y < innerHeight; y++) { 477 for (int32_t y = 0; y < innerHeight; y++) {
422 if (GIF_ERROR == DGifGetLine(fGif, buffer.get(), 478 if (GIF_ERROR == DGifGetLine(fGif, buffer.get(),
423 innerWidth)) { 479 innerWidth)) {
424 if (fillBackground) { 480 if (!skipBackground) {
425 SkPMColor* dstPtr = (SkPMColor*) SkTAddOffset 481 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, y, f illIndex,
426 <void*>(dst, y * dstRowBytes); 482 colorTable);
427 sk_memset32(dstPtr, colorTable[fillIndex],
428 (height - y) * ((int) dstRowBytes)
429 / sizeof(SkPMColor));
430 } 483 }
431 return gif_error(SkStringPrintf( 484 return gif_error(SkStringPrintf(
432 "Could not decode line %d of %d.\n", 485 "Could not decode line %d of %d.\n",
433 y, height - 1).c_str(), kIncompleteInput); 486 y, height - 1).c_str(), kIncompleteInput);
434 } 487 }
435 swizzler->next(buffer.get()); 488 swizzler->next(buffer.get());
436 } 489 }
437 } 490 }
438 491
439 // FIXME: Gif files may have multiple images stored in a single 492 // FIXME: Gif files may have multiple images stored in a single
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
509 // giflib returns an error code if the record type is not known. 562 // giflib returns an error code if the record type is not known.
510 // We should catch this error immediately. 563 // We should catch this error immediately.
511 SkASSERT(false); 564 SkASSERT(false);
512 break; 565 break;
513 } 566 }
514 } while (TERMINATE_RECORD_TYPE != recordType); 567 } while (TERMINATE_RECORD_TYPE != recordType);
515 568
516 return gif_error("Could not find any images to decode in gif file.\n", 569 return gif_error("Could not find any images to decode in gif file.\n",
517 kInvalidInput); 570 kInvalidInput);
518 } 571 }
OLDNEW
« no previous file with comments | « src/codec/SkCodec_libgif.h ('k') | src/codec/SkCodec_libpng.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698