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

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

Issue 1305123002: Scanline decoding for gifs (Closed) Base URL: https://skia.googlesource.com/skia.git@real-bmp-scan
Patch Set: Make kScanline_Mode test kOutOfOrder correctly in dm Created 5 years, 3 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
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"
11 #include "SkColorTable.h" 11 #include "SkColorTable.h"
12 #include "SkScaledCodec.h"
12 #include "SkStream.h" 13 #include "SkStream.h"
13 #include "SkSwizzler.h" 14 #include "SkSwizzler.h"
14 #include "SkUtils.h" 15 #include "SkUtils.h"
15 16
16 /* 17 /*
17 * Checks the start of the stream to see if the image is a gif 18 * Checks the start of the stream to see if the image is a gif
18 */ 19 */
19 bool SkGifCodec::IsGif(SkStream* stream) { 20 bool SkGifCodec::IsGif(SkStream* stream) {
20 char buf[GIF_STAMP_LEN]; 21 char buf[GIF_STAMP_LEN];
21 if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN) { 22 if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 return (int32_t) stream->read(out, size); 54 return (int32_t) stream->read(out, size);
54 } 55 }
55 56
56 /* 57 /*
57 * Open the gif file 58 * Open the gif file
58 */ 59 */
59 static GifFileType* open_gif(SkStream* stream) { 60 static GifFileType* open_gif(SkStream* stream) {
60 return DGifOpen(stream, read_bytes_callback, nullptr); 61 return DGifOpen(stream, read_bytes_callback, nullptr);
61 } 62 }
62 63
63 /*
64 * This function cleans up the gif object after the decode completes
65 * It is used in a SkAutoTCallIProc template
66 */
67 void SkGifCodec::CloseGif(GifFileType* gif) {
68 DGifCloseFile(gif, nullptr);
69 }
70
71 /*
72 * This function free extension data that has been saved to assist the image
73 * decoder
74 */
75 void SkGifCodec::FreeExtension(SavedImage* image) {
76 if (nullptr != image->ExtensionBlocks) {
77 GifFreeExtensions(&image->ExtensionBlockCount, &image->ExtensionBlocks);
78 }
79 }
80
81 /* 64 /*
82 * Check if a there is an index of the color table for a transparent pixel 65 * Check if a there is an index of the color table for a transparent pixel
83 */ 66 */
84 static uint32_t find_trans_index(const SavedImage& image) { 67 static uint32_t find_trans_index(const SavedImage& image) {
85 // If there is a transparent index specified, it will be contained in an 68 // If there is a transparent index specified, it will be contained in an
86 // extension block. We will loop through extension blocks in reverse order 69 // extension block. We will loop through extension blocks in reverse order
87 // to check the most recent extension blocks first. 70 // to check the most recent extension blocks first.
88 for (int32_t i = image.ExtensionBlockCount - 1; i >= 0; i--) { 71 for (int32_t i = image.ExtensionBlockCount - 1; i >= 0; i--) {
89 // Get an extension block 72 // Get an extension block
90 const ExtensionBlock& extBlock = image.ExtensionBlocks[i]; 73 const ExtensionBlock& extBlock = image.ExtensionBlocks[i];
91 74
92 // Specifically, we need to check for a graphics control extension, 75 // Specifically, we need to check for a graphics control extension,
93 // which may contain transparency information. Also, note that a valid 76 // which may contain transparency information. Also, note that a valid
94 // graphics control extension is always four bytes. The fourth byte 77 // graphics control extension is always four bytes. The fourth byte
95 // is the transparent index (if it exists), so we need at least four 78 // is the transparent index (if it exists), so we need at least four
96 // bytes. 79 // bytes.
97 if (GRAPHICS_EXT_FUNC_CODE == extBlock.Function && extBlock.ByteCount >= 4) { 80 if (GRAPHICS_EXT_FUNC_CODE == extBlock.Function && extBlock.ByteCount >= 4) {
98
99 // Check the transparent color flag which indicates whether a 81 // Check the transparent color flag which indicates whether a
100 // transparent index exists. It is the least significant bit of 82 // transparent index exists. It is the least significant bit of
101 // the first byte of the extension block. 83 // the first byte of the extension block.
102 if (1 == (extBlock.Bytes[0] & 1)) { 84 if (1 == (extBlock.Bytes[0] & 1)) {
103
104 // Use uint32_t to prevent sign extending 85 // Use uint32_t to prevent sign extending
105 return extBlock.Bytes[3]; 86 return extBlock.Bytes[3];
106 } 87 }
107 88
108 // There should only be one graphics control extension for the image frame 89 // There should only be one graphics control extension for the image frame
109 break; 90 break;
110 } 91 }
111 } 92 }
112 93
113 // Use maximum unsigned int (surely an invalid index) to indicate that a val id 94 // Use maximum unsigned int (surely an invalid index) to indicate that a val id
(...skipping 20 matching lines...) Expand all
134 } 115 }
135 // Third pass 116 // Third pass
136 if (encodedRow * 2 < height) { 117 if (encodedRow * 2 < height) {
137 return 2 + 4 * (encodedRow - ceil_div(height, 4)); 118 return 2 + 4 * (encodedRow - ceil_div(height, 4));
138 } 119 }
139 // Fourth pass 120 // Fourth pass
140 return 1 + 2 * (encodedRow - ceil_div(height, 2)); 121 return 1 + 2 * (encodedRow - ceil_div(height, 2));
141 } 122 }
142 123
143 /* 124 /*
125 * This function cleans up the gif object after the decode completes
126 * It is used in a SkAutoTCallIProc template
127 */
128 void SkGifCodec::CloseGif(GifFileType* gif) {
129 DGifCloseFile(gif, NULL);
130 }
131
132 /*
133 * This function free extension data that has been saved to assist the image
134 * decoder
135 */
136 void SkGifCodec::FreeExtension(SavedImage* image) {
137 if (NULL != image->ExtensionBlocks) {
138 GifFreeExtensions(&image->ExtensionBlockCount, &image->ExtensionBlocks);
139 }
140 }
141
142 /*
144 * Read enough of the stream to initialize the SkGifCodec. 143 * Read enough of the stream to initialize the SkGifCodec.
145 * Returns a bool representing success or failure. 144 * Returns a bool representing success or failure.
146 * 145 *
147 * @param codecOut 146 * @param codecOut
148 * If it returned true, and codecOut was not nullptr, 147 * If it returned true, and codecOut was not nullptr,
149 * codecOut will be set to a new SkGifCodec. 148 * codecOut will be set to a new SkGifCodec.
150 * 149 *
151 * @param gifOut 150 * @param gifOut
152 * If it returned true, and codecOut was nullptr, 151 * If it returned true, and codecOut was nullptr,
153 * gifOut must be non-nullptr and gifOut will be set to a new 152 * gifOut must be non-nullptr and gifOut will be set to a new
(...skipping 30 matching lines...) Expand all
184 // the default. 183 // the default.
185 // Many gifs specify a color table index for transparent pixels. Every 184 // Many gifs specify a color table index for transparent pixels. Every
186 // other pixel is guaranteed to be opaque. Despite this, because of the 185 // other pixel is guaranteed to be opaque. Despite this, because of the
187 // possiblity of transparent pixels, we cannot assume that the image is 186 // possiblity of transparent pixels, we cannot assume that the image is
188 // opaque. We have the option to set the alpha type as kPremul or 187 // opaque. We have the option to set the alpha type as kPremul or
189 // kUnpremul. Both are valid since the alpha component will always be 188 // kUnpremul. Both are valid since the alpha component will always be
190 // 0xFF or the entire 32-bit pixel will be set to zero. We prefer 189 // 0xFF or the entire 32-bit pixel will be set to zero. We prefer
191 // kPremul because we support kPremul, and it is more efficient to 190 // kPremul because we support kPremul, and it is more efficient to
192 // use kPremul directly even when kUnpremul is supported. 191 // use kPremul directly even when kUnpremul is supported.
193 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height, 192 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height,
194 kIndex_8_SkColorType, k Premul_SkAlphaType); 193 kIndex_8_SkColorType, kPremul_SkAlphaType);
195 *codecOut = new SkGifCodec(imageInfo, streamDeleter.detach(), gif.detach ()); 194 *codecOut = new SkGifCodec(imageInfo, streamDeleter.detach(), gif.detach ());
196 } else { 195 } else {
197 SkASSERT(nullptr != gifOut); 196 SkASSERT(nullptr != gifOut);
198 streamDeleter.detach(); 197 streamDeleter.detach();
199 *gifOut = gif.detach(); 198 *gifOut = gif.detach();
200 } 199 }
201 return true; 200 return true;
202 } 201 }
203 202
204 /* 203 /*
205 * Assumes IsGif was called and returned true 204 * Assumes IsGif was called and returned true
206 * Creates a gif decoder 205 * Creates a gif decoder
207 * Reads enough of the stream to determine the image format 206 * Reads enough of the stream to determine the image format
208 */ 207 */
209 SkCodec* SkGifCodec::NewFromStream(SkStream* stream) { 208 SkCodec* SkGifCodec::NewFromStream(SkStream* stream) {
210 SkCodec* codec = nullptr; 209 SkCodec* codec = nullptr;
211 if (ReadHeader(stream, &codec, nullptr)) { 210 if (ReadHeader(stream, &codec, nullptr)) {
212 return codec; 211 return codec;
213 } 212 }
214 return nullptr; 213 return nullptr;
215 } 214 }
216 215
217 SkGifCodec::SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream, GifFileType * gif) 216 SkGifCodec::SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream, GifFileType * gif)
218 : INHERITED(srcInfo, stream) 217 : INHERITED(srcInfo, stream)
219 , fGif(gif) 218 , fGif(gif)
219 , fSrcBuffer(SkNEW_ARRAY(uint8_t, this->getInfo().width()))
scroggo 2015/09/02 22:45:48 nit: new
msarett 2015/09/03 17:13:31 Done.
220 , fFillIndex(SK_MaxU32)
scroggo 2015/09/02 22:45:48 Is this a sentinel value? Maybe it should be label
msarett 2015/09/03 17:13:31 This has changed a bit. Will add comments here.
221 , fFrameDims(SkIRect::MakeEmpty())
222 , fFrameIsSubset(false)
223 , fColorTable(NULL)
224 , fSwizzler(NULL)
220 {} 225 {}
221 226
222 bool SkGifCodec::onRewind() { 227 bool SkGifCodec::onRewind() {
223 GifFileType* gifOut = nullptr; 228 GifFileType* gifOut = nullptr;
224 if (!ReadHeader(this->stream(), nullptr, &gifOut)) { 229 if (!ReadHeader(this->stream(), nullptr, &gifOut)) {
225 return false; 230 return false;
226 } 231 }
227 232
228 SkASSERT(nullptr != gifOut); 233 SkASSERT(nullptr != gifOut);
229 fGif.reset(gifOut); 234 fGif.reset(gifOut);
230 return true; 235 return true;
231 } 236 }
232 237
233 /* 238 SkCodec::Result SkGifCodec::readUpToFirstImage(uint32_t* transIndex) {
234 * Initiates the gif decode
235 */
236 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo,
237 void* dst, size_t dstRowBytes,
238 const Options& opts,
239 SkPMColor* inputColorPtr,
240 int* inputColorCount) {
241 // Rewind if necessary
242 if (!this->rewindIfNeeded()) {
243 return kCouldNotRewind;
244 }
245
246 // Check for valid input parameters
247 if (opts.fSubset) {
248 // Subsets are not supported.
249 return kUnimplemented;
250 }
251 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
252 return gif_error("Scaling not supported.\n", kInvalidScale);
253 }
254 if (!conversion_possible(dstInfo, this->getInfo())) {
255 return gif_error("Cannot convert input type to output type.\n", kInvalid Conversion);
256 }
257
258 // Use this as a container to hold information about any gif extension 239 // Use this as a container to hold information about any gif extension
259 // blocks. This generally stores transparency and animation instructions. 240 // blocks. This generally stores transparency and animation instructions.
260 SavedImage saveExt; 241 SavedImage saveExt;
261 SkAutoTCallVProc<SavedImage, FreeExtension> autoFreeExt(&saveExt); 242 SkAutoTCallVProc<SavedImage, FreeExtension> autoFreeExt(&saveExt);
262 saveExt.ExtensionBlocks = nullptr; 243 saveExt.ExtensionBlocks = nullptr;
263 saveExt.ExtensionBlockCount = 0; 244 saveExt.ExtensionBlockCount = 0;
264 GifByteType* extData; 245 GifByteType* extData;
265 int32_t extFunction; 246 int32_t extFunction;
266 247
267 // We will loop over components of gif images until we find an image. Once 248 // We will loop over components of gif images until we find an image. Once
268 // we find an image, we will decode and return it. While many gif files 249 // we find an image, we will decode and return it. While many gif files
269 // contain more than one image, we will simply decode the first image. 250 // contain more than one image, we will simply decode the first image.
270 const int32_t width = dstInfo.width();
271 const int32_t height = dstInfo.height();
272 GifRecordType recordType; 251 GifRecordType recordType;
273 do { 252 do {
274 // Get the current record type 253 // Get the current record type
275 if (GIF_ERROR == DGifGetRecordType(fGif, &recordType)) { 254 if (GIF_ERROR == DGifGetRecordType(fGif, &recordType)) {
276 return gif_error("DGifGetRecordType failed.\n", kInvalidInput); 255 return gif_error("DGifGetRecordType failed.\n", kInvalidInput);
277 } 256 }
278
279 switch (recordType) { 257 switch (recordType) {
280 case IMAGE_DESC_RECORD_TYPE: { 258 case IMAGE_DESC_RECORD_TYPE: {
281 // Read the image descriptor 259 *transIndex = find_trans_index(saveExt);
282 if (GIF_ERROR == DGifGetImageDesc(fGif)) {
283 return gif_error("DGifGetImageDesc failed.\n", kInvalidInput );
284 }
285
286 // If reading the image descriptor is successful, the image
287 // count will be incremented
288 SkASSERT(fGif->ImageCount >= 1);
289 SavedImage* image = &fGif->SavedImages[fGif->ImageCount - 1];
290
291 // Process the descriptor
292 const GifImageDesc& desc = image->ImageDesc;
293 int32_t imageLeft = desc.Left;
294 int32_t imageTop = desc.Top;
295 int32_t innerWidth = desc.Width;
296 int32_t innerHeight = desc.Height;
297 // Fail on non-positive dimensions
298 if (innerWidth <= 0 || innerHeight <= 0) {
299 return gif_error("Invalid dimensions for inner image.\n", kI nvalidInput);
300 }
301 // Treat the following cases as warnings and try to fix
302 if (innerWidth > width) {
303 gif_warning("Inner image too wide, shrinking.\n");
304 innerWidth = width;
305 imageLeft = 0;
306 } else if (imageLeft + innerWidth > width) {
307 gif_warning("Shifting inner image to left to fit.\n");
308 imageLeft = width - innerWidth;
309 } else if (imageLeft < 0) {
310 gif_warning("Shifting image to right to fit\n");
311 imageLeft = 0;
312 }
313 if (innerHeight > height) {
314 gif_warning("Inner image too tall, shrinking.\n");
315 innerHeight = height;
316 imageTop = 0;
317 } else if (imageTop + innerHeight > height) {
318 gif_warning("Shifting inner image up to fit.\n");
319 imageTop = height - innerHeight;
320 } else if (imageTop < 0) {
321 gif_warning("Shifting image down to fit\n");
322 imageTop = 0;
323 }
324
325 // Create a color table to store colors the giflib colorMap
326 SkPMColor alternateColorPtr[256];
327 SkPMColor* colorTable;
328 SkColorType dstColorType = dstInfo.colorType();
329 if (kIndex_8_SkColorType == dstColorType) {
330 SkASSERT(nullptr != inputColorPtr);
331 SkASSERT(nullptr != inputColorCount);
332 colorTable = inputColorPtr;
333 } else {
334 colorTable = alternateColorPtr;
335 }
336
337 // Set up the color table
338 uint32_t colorCount = 0;
339 // Allocate maximum storage to deal with invalid indices safely
340 const uint32_t maxColors = 256;
341 ColorMapObject* colorMap = fGif->Image.ColorMap;
342 // If there is no local color table, use the global color table
343 if (nullptr == colorMap) {
344 colorMap = fGif->SColorMap;
345 }
346 if (nullptr != colorMap) {
347 colorCount = colorMap->ColorCount;
348 SkASSERT(colorCount == (unsigned) (1 << (colorMap->BitsPerPi xel)));
349 SkASSERT(colorCount <= 256);
350 for (uint32_t i = 0; i < colorCount; i++) {
351 colorTable[i] = SkPackARGB32(0xFF,
352 colorMap->Colors[i].Red,
353 colorMap->Colors[i].Green,
354 colorMap->Colors[i].Blue);
355 }
356 }
357
358 // This is used to fill unspecified pixels in the image data.
359 uint32_t fillIndex = fGif->SBackGroundColor;
360 ZeroInitialized zeroInit = opts.fZeroInitialized;
361
362 // Gifs have the option to specify the color at a single
363 // index of the color table as transparent.
364 {
365 // Get the transparent index. If the return value of this
366 // function is greater than the colorCount, we know that
367 // there is no valid transparent color in the color table.
368 // This occurs if there is no graphics control extension or
369 // if the index specified by the graphics control extension
370 // is out of range.
371 uint32_t transIndex = find_trans_index(saveExt);
372
373 if (transIndex < colorCount) {
374 colorTable[transIndex] = SK_ColorTRANSPARENT;
375 // If there is a transparent index, we also use this as
376 // the fill index.
377 fillIndex = transIndex;
378 } else if (fillIndex >= colorCount) {
379 // If the fill index is invalid, we default to 0. This
380 // behavior is unspecified but matches SkImageDecoder.
381 fillIndex = 0;
382 }
383 }
384
385 // Fill in the color table for indices greater than color count.
386 // This allows for predictable, safe behavior.
387 for (uint32_t i = colorCount; i < maxColors; i++) {
388 colorTable[i] = colorTable[fillIndex];
389 }
390
391 // Check if image is only a subset of the image frame
392 SkAutoTDelete<SkSwizzler> swizzler(nullptr);
393 if (innerWidth < width || innerHeight < height) {
394
395 // Modify the destination info
396 const SkImageInfo subsetDstInfo = dstInfo.makeWH(innerWidth, innerHeight);
397
398 // Fill the destination with the fill color
399 // FIXME: This may not be the behavior that we want for
400 // animated gifs where we draw on top of the
401 // previous frame.
402 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, height, fillInde x, colorTable,
403 zeroInit);
404
405 // Modify the dst pointer
406 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(ds tColorType);
407 dst = SkTAddOffset<void*>(dst,
408 dstRowBytes * imageTop +
409 dstBytesPerPixel * imageLeft);
410
411 // Create the subset swizzler
412 swizzler.reset(SkSwizzler::CreateSwizzler(
413 SkSwizzler::kIndex, colorTable, subsetDstInfo,
414 zeroInit, this->getInfo()));
415 } else {
416 // Create the fully dimensional swizzler
417 swizzler.reset(SkSwizzler::CreateSwizzler(
418 SkSwizzler::kIndex, colorTable, dstInfo,
419 zeroInit, this->getInfo()));
420 }
421
422 // Stores output from dgiflib and input to the swizzler
423 SkAutoTDeleteArray<uint8_t> buffer(new uint8_t[innerWidth]);
424
425 // Check the interlace flag and iterate over rows of the input
426 if (fGif->Image.Interlace) {
427 for (int32_t y = 0; y < innerHeight; y++) {
428 if (GIF_ERROR == DGifGetLine(fGif, buffer.get(), innerWi dth)) {
429 // Recover from error by filling remainder of image
430 memset(buffer.get(), fillIndex, innerWidth);
431 for (; y < innerHeight; y++) {
432 void* dstRow = SkTAddOffset<void>(dst, dstRowByt es *
433 get_output_row_interlaced(y, innerHeight ));
434 swizzler->swizzle(dstRow, buffer.get());
435 }
436 return gif_error(SkStringPrintf(
437 "Could not decode line %d of %d.\n",
438 y, height - 1).c_str(), kIncompleteInput);
439 }
440 void* dstRow = SkTAddOffset<void>(dst,
441 dstRowBytes * get_output_row_interlaced(y, inner Height));
442 swizzler->swizzle(dstRow, buffer.get());
443 }
444 } else {
445 // Standard mode
446 void* dstRow = dst;
447 for (int32_t y = 0; y < innerHeight; y++) {
448 if (GIF_ERROR == DGifGetLine(fGif, buffer.get(), innerWi dth)) {
449 SkSwizzler::Fill(dstRow, dstInfo, dstRowBytes, inner Height - y,
450 fillIndex, colorTable, zeroInit);
451 return gif_error(SkStringPrintf(
452 "Could not decode line %d of %d.\n",
453 y, height - 1).c_str(), kIncompleteInput);
454 }
455 swizzler->swizzle(dstRow, buffer.get());
456 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
457 }
458 }
459
460 // FIXME: Gif files may have multiple images stored in a single 260 // FIXME: Gif files may have multiple images stored in a single
461 // file. This is most commonly used to enable 261 // file. This is most commonly used to enable
462 // animations. Since we are leaving animated gifs as a 262 // animations. Since we are leaving animated gifs as a
463 // TODO, we will return kSuccess after decoding the 263 // TODO, we will return kSuccess after decoding the
464 // first image in the file. This is the same behavior 264 // first image in the file. This is the same behavior
465 // as SkImageDecoder_libgif. 265 // as SkImageDecoder_libgif.
466 // 266 //
467 // Most times this works pretty well, but sometimes it 267 // Most times this works pretty well, but sometimes it
468 // doesn't. For example, I have an animated test image 268 // doesn't. For example, I have an animated test image
469 // where the first image in the file is 1x1, but the 269 // where the first image in the file is 1x1, but the
470 // subsequent images are meaningful. This currently 270 // subsequent images are meaningful. This currently
471 // displays the 1x1 image, which is not ideal. Right 271 // displays the 1x1 image, which is not ideal. Right
472 // now I am leaving this as an issue that will be 272 // now I am leaving this as an issue that will be
473 // addressed when we implement animated gifs. 273 // addressed when we implement animated gifs.
474 // 274 //
475 // It is also possible (not explicitly disallowed in the 275 // It is also possible (not explicitly disallowed in the
476 // specification) that gif files provide multiple 276 // specification) that gif files provide multiple
477 // images in a single file that are all meant to be 277 // images in a single file that are all meant to be
478 // displayed in the same frame together. I will 278 // displayed in the same frame together. I will
479 // currently leave this unimplemented until I find a 279 // currently leave this unimplemented until I find a
480 // test case that expects this behavior. 280 // test case that expects this behavior.
481 return kSuccess; 281 return kSuccess;
482 } 282 }
483
484 // Extensions are used to specify special properties of the image 283 // Extensions are used to specify special properties of the image
485 // such as transparency or animation. 284 // such as transparency or animation.
486 case EXTENSION_RECORD_TYPE: 285 case EXTENSION_RECORD_TYPE:
487 // Read extension data 286 // Read extension data
488 if (GIF_ERROR == DGifGetExtension(fGif, &extFunction, &extData)) { 287 if (GIF_ERROR == DGifGetExtension(fGif, &extFunction, &extData)) {
489 return gif_error("Could not get extension.\n", kIncompleteIn put); 288 return gif_error("Could not get extension.\n", kIncompleteIn put);
490 } 289 }
491 290
492 // Create an extension block with our data 291 // Create an extension block with our data
493 while (nullptr != extData) { 292 while (nullptr != extData) {
494 // Add a single block 293 // Add a single block
495 if (GIF_ERROR == GifAddExtensionBlock(&saveExt.ExtensionBloc kCount, 294 if (GIF_ERROR == GifAddExtensionBlock(&saveExt.ExtensionBloc kCount,
496 &saveExt.ExtensionBloc ks, 295 &saveExt.ExtensionBloc ks,
497 extFunction, extData[0 ], &extData[1])) 296 extFunction, extData[0 ], &extData[1]))
498 { 297 {
499 return gif_error("Could not add extension block.\n", kIn completeInput); 298 return gif_error("Could not add extension block.\n", kIn completeInput);
500 } 299 }
501 // Move to the next block 300 // Move to the next block
502 if (GIF_ERROR == DGifGetExtensionNext(fGif, &extData)) { 301 if (GIF_ERROR == DGifGetExtensionNext(fGif, &extData)) {
503 return gif_error("Could not get next extension.\n", kInc ompleteInput); 302 return gif_error("Could not get next extension.\n", kInc ompleteInput);
504 } 303 }
505 } 304 }
506 break; 305 break;
507 306
508 // Signals the end of the gif file 307 // Signals the end of the gif file
509 case TERMINATE_RECORD_TYPE: 308 case TERMINATE_RECORD_TYPE:
510 break; 309 break;
511 310
512 default: 311 default:
513 // giflib returns an error code if the record type is not known. 312 // DGifGetRecordType returns an error if the record type does
514 // We should catch this error immediately. 313 // not match one of the above cases. This should not be
314 // reached.
515 SkASSERT(false); 315 SkASSERT(false);
516 break; 316 break;
517 } 317 }
518 } while (TERMINATE_RECORD_TYPE != recordType); 318 } while (TERMINATE_RECORD_TYPE != recordType);
519 319
520 return gif_error("Could not find any images to decode in gif file.\n", kInva lidInput); 320 return gif_error("Could not find any images to decode in gif file.\n", kInva lidInput);
521 } 321 }
322
323 /*
324 * A gif may contain many image frames, all of different sizes.
325 * This function checks if the frame dimensions are valid and corrects them if
326 * necessary.
327 */
328 bool SkGifCodec::setFrameDimensions(const GifImageDesc& desc) {
329 // Fail on non-positive dimensions
330 int32_t frameLeft = desc.Left;
331 int32_t frameTop = desc.Top;
332 int32_t frameWidth = desc.Width;
333 int32_t frameHeight = desc.Height;
334 int32_t height = this->getInfo().height();
335 int32_t width = this->getInfo().width();
336 if (frameWidth <= 0 || frameHeight <= 0) {
337 return false;
338 }
339
340 // Treat the following cases as warnings and try to fix
341 if (frameWidth > width) {
342 gif_warning("Image frame too wide, shrinking.\n");
343 frameWidth = width;
344 frameLeft = 0;
345 } else if (frameLeft + frameWidth > width) {
346 gif_warning("Shifting image frame to left to fit.\n");
347 frameLeft = width - frameWidth;
348 } else if (frameLeft < 0) {
349 gif_warning("Shifting image frame to right to fit\n");
350 frameLeft = 0;
351 }
352 if (frameHeight > height) {
353 gif_warning("Image frame too tall, shrinking.\n");
354 frameHeight = height;
355 frameTop = 0;
356 } else if (frameTop + frameHeight > height) {
357 gif_warning("Shifting image frame up to fit.\n");
358 frameTop = height - frameHeight;
359 } else if (frameTop < 0) {
360 gif_warning("Shifting image frame down to fit\n");
361 frameTop = 0;
362 }
363 fFrameDims.setXYWH(frameLeft, frameTop, frameWidth, frameHeight);
364
365 // Indicate if the frame dimensions do not match the header dimensions
366 if (this->getInfo().width() != fFrameDims.width() ||
scroggo 2015/09/02 22:45:48 I think you can simplify this to if (fFrameDims.s
msarett 2015/09/03 17:13:31 +1
367 this->getInfo().height() != fFrameDims.height()) {
368 fFrameIsSubset = true;
369 }
370
371 return true;
372 }
373
374 void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* inp utColorPtr,
375 int* inputColorCount, uint32_t transIndex) {
376 // Set up our own color table
377 const uint32_t maxColors = 256;
378 SkPMColor colorPtr[256];
379 if (NULL != inputColorCount) {
380 // We set the number of colors to maxColors in order to ensure
381 // safe memory accesses. Otherwise, an invalid pixel could
382 // access memory outside of our color table array.
383 *inputColorCount = maxColors;
384 }
385
386 // Get local color table
387 ColorMapObject* colorMap = fGif->Image.ColorMap;
388 // If there is no local color table, use the global color table
389 if (NULL == colorMap) {
390 colorMap = fGif->SColorMap;
391 }
392
393 uint32_t colorCount = 0;
394 if (NULL != colorMap) {
395 colorCount = colorMap->ColorCount;
396 // giflib guarantees these properties
397 SkASSERT(colorCount == (unsigned) (1 << (colorMap->BitsPerPixel)));
398 SkASSERT(colorCount <= 256);
399 for (uint32_t i = 0; i < colorCount; i++) {
400 colorPtr[i] = SkPackARGB32(0xFF, colorMap->Colors[i].Red,
401 colorMap->Colors[i].Green, colorMap->Colors[i].Blue);
402 }
403 }
404
405 // This is used to fill unspecified pixels in the image data.
406 uint32_t fillIndex = fGif->SBackGroundColor;
407
408 // Gifs have the option to specify the color at a single index of the color
409 // table as transparent. If the transparent index is greater than the
410 // colorCount, we know that there is no valid transparent color in the
411 // color table. This occurs if there is no graphics control extension or
412 // if the index specified by the graphics control extension is out of range.
413 if (transIndex < colorCount) {
414 colorPtr[transIndex] = SK_ColorTRANSPARENT;
415 // If there is a transparent index, we also use this as the fill index.
416 fillIndex = transIndex;
417 } else if (fillIndex >= colorCount) {
418 // If the fill index is invalid, we default to 0. This behavior is
419 // unspecified but matches SkImageDecoder.
420 fillIndex = 0;
421 }
422
423 // Fill in the color table for indices greater than color count.
424 // This allows for predictable, safe behavior.
425 for (uint32_t i = colorCount; i < maxColors; i++) {
426 colorPtr[i] = colorPtr[fillIndex];
427 }
428
429 fColorTable.reset(SkNEW_ARGS(SkColorTable, (colorPtr, maxColors)));
scroggo 2015/09/02 22:45:48 nit: new
msarett 2015/09/03 17:13:31 Done.
430 copy_color_table(dstInfo, this->fColorTable, inputColorPtr, inputColorCount) ;
431 fFillIndex = fillIndex;
432 }
433
434 SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo,
435 ZeroInitialized zeroInit) {
436 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
437 fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex,
438 colorPtr, dstInfo, zeroInit, this->getInfo()));
439 if (NULL != fSwizzler.get()) {
scroggo 2015/09/02 22:45:48 nit: nullptr
msarett 2015/09/03 17:13:31 Done.
440 return kSuccess;
441 }
442 return kUnimplemented;
443 }
444
445 SkCodec::Result SkGifCodec::readRow() {
446 if (GIF_ERROR == DGifGetLine(fGif, fSrcBuffer.get(), fFrameDims.width())) {
447 return kIncompleteInput;
448 }
449 return kSuccess;
450 }
451
452 /*
453 * Initiates the gif decode
454 */
455 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo,
456 void* dst, size_t dstRowBytes,
457 const Options& opts,
458 SkPMColor* inputColorPtr,
459 int* inputColorCount) {
460 // Rewind if necessary
461 if (!this->rewindIfNeeded()) {
462 return kCouldNotRewind;
463 }
464
465 // Check for valid input parameters
466 if (opts.fSubset) {
467 // Subsets are not supported.
468 return kUnimplemented;
469 }
470 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
471 return gif_error("Scaling not supported.\n", kInvalidScale);
472 }
473 if (!conversion_possible(dstInfo, this->getInfo())) {
474 return gif_error("Cannot convert input type to output type.\n",
475 kInvalidConversion);
476 }
477
478 // Read through gif extensions to get to the image data. Set the
479 // transparent index based on the extension data.
480 uint32_t transIndex;
481 SkCodec::Result result = this->readUpToFirstImage(&transIndex);
482 if (kSuccess != result){
483 return result;
484 }
485
486 // Read the image descriptor
487 if (GIF_ERROR == DGifGetImageDesc(fGif)) {
488 return gif_error("DGifGetImageDesc failed.\n", kInvalidInput);
489 }
490
491 // If reading the image descriptor is successful, the image count will be
492 // incremented
493 SkASSERT(fGif->ImageCount >= 1);
494 SavedImage* image = &fGif->SavedImages[fGif->ImageCount - 1];
495 const GifImageDesc& desc = image->ImageDesc;
496
497 // Check that the frame dimensions are valid and set them
498 if(!this->setFrameDimensions(desc)) {
499 return gif_error("Invalid dimensions for image frame.\n", kInvalidInput) ;
500 }
501
502 // Initialize color table and copy to the client if necessary
503 this->initializeColorTable(dstInfo, inputColorPtr, inputColorCount, transInd ex);
504
505 // Initialize the swizzler
506 if (fFrameIsSubset) {
507 const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameDims.width(), fFr ameDims.height());
508 if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitia lized)) {
509 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ;
510 }
511
512 // Fill the background
513 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
514 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, this->getInfo().height(),
515 fFillIndex, colorPtr, opts.fZeroInitialized);
516
517 // Modify the dst pointer
518 const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorT ype());
519 dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameDims.top() +
520 dstBytesPerPixel * fFrameDims.left());
521 } else {
522 if (kSuccess != this->initializeSwizzler(dstInfo, opts.fZeroInitialized) ) {
523 return gif_error("Could not initialize swizzler.\n", kUnimplemented) ;
524 }
525 }
526
527 // Check the interlace flag and iterate over rows of the input
528 uint32_t width = fFrameDims.width();
529 uint32_t height = fFrameDims.height();
530 if (fGif->Image.Interlace) {
531 // In interlace mode, the rows of input are rearranged in
532 // the output image. We use an iterator to take care of
scroggo 2015/09/02 22:45:48 no longer use an iterator
msarett 2015/09/03 17:13:31 Thanks, will change the comment.
533 // the rearranging.
534 for (int32_t y = 0; y < height; y++) {
535 if (kSuccess != this->readRow()) {
536 // Recover from error by filling remainder of image
537 memset(fSrcBuffer.get(), fFillIndex, width);
538 for (; y < height; y++) {
539 void* dstRow = SkTAddOffset<void>(dst,
540 dstRowBytes * get_output_row_interlaced(y, height));
541 fSwizzler->swizzle(dstRow, fSrcBuffer.get());
542 }
543 return gif_error("Could not decode line.\n", kIncompleteInput);
544 }
545 void* dstRow = SkTAddOffset<void>(dst,
546 dstRowBytes * get_output_row_interlaced(y, height));
547 fSwizzler->swizzle(dstRow, fSrcBuffer.get());
548 }
549 } else {
550 // Standard mode
551 void* dstRow = dst;
552 for (int32_t y = 0; y < height; y++) {
553 if (kSuccess != this->readRow()) {
554 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
555 SkSwizzler::Fill(dstRow, dstInfo, dstRowBytes,
556 height - y, fFillIndex, colorPtr, opts.fZeroInitialized) ;
557 return gif_error("Could not decode line\n", kIncompleteInput);
558 }
559 fSwizzler->swizzle(dstRow, fSrcBuffer.get());
560 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
561 }
562 }
563 return kSuccess;
564 }
565
566 // TODO (msarett): skbug.com/3582
567 // Should we implement reallyHasAlpha? Or should we read extens ion blocks in the
568 // header? Or should we do both?
569
570 class SkGifScanlineDecoder : public SkScanlineDecoder {
571 public:
572 SkGifScanlineDecoder(const SkImageInfo& srcInfo, SkGifCodec* codec)
573 : INHERITED(srcInfo)
574 , fCodec(codec)
575 {}
576
577 SkEncodedFormat onGetEncodedFormat() const override {
578 return kGIF_SkEncodedFormat;
579 }
580
581 SkCodec::Result onStart(const SkImageInfo& dstInfo, const SkCodec::Options& opts,
582 SkPMColor inputColorPtr[], int* inputColorCount) ove rride {
583
584 // Rewind if necessary
585 if (!fCodec->rewindIfNeeded()) {
586 return SkCodec::kCouldNotRewind;
587 }
588 // Check for valid input parameters
589 if (opts.fSubset) {
590 // Subsets are not supported.
591 return SkCodec::kUnimplemented;
592 }
593 // Check to see if scaling was requested.
594 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
595 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) {
596 return gif_error("Scaling not supported.\n", SkCodec::kInvalidSc ale);
597 }
598 }
599 if (!conversion_possible(dstInfo, this->getInfo())) {
600 return gif_error("Cannot convert input type to output type.\n",
601 SkCodec::kInvalidConversion);
602 }
603
604 // Read through gif extensions to get to the image data
scroggo 2015/09/02 22:45:48 A lot of this code looks similar to code in onGetP
msarett 2015/09/03 17:13:30 This has been moved to ReadHeader(), so now it's s
605 uint32_t transIndex;
606 SkCodec::Result result = fCodec->readUpToFirstImage(&transIndex);
607 if (SkCodec::kSuccess != result){
608 return result;
609 }
610
611 // Read the image descriptor
612 if (GIF_ERROR == DGifGetImageDesc(fCodec->fGif)) {
613 return gif_error("DGifGetImageDesc failed.\n", SkCodec::kInvalidInpu t);
614 }
615
616 // If reading the image descriptor is successful, the image count will b e
617 // incremented
618 SkASSERT(fCodec->fGif->ImageCount >= 1);
619 SavedImage* image = &fCodec->fGif->SavedImages[fCodec->fGif->ImageCount - 1];
620 const GifImageDesc& desc = image->ImageDesc;
621
622 // Check that the frame dimensions are valid and set them
623 if(!fCodec->setFrameDimensions(desc)) {
624 return gif_error("Invalid dimensions for image frame.\n", SkCodec::k InvalidInput);
625 }
626
627 // Initialize color table and copy to the client if necessary
628 fCodec->initializeColorTable(dstInfo, inputColorPtr, inputColorCount, tr ansIndex);
629
630 // Initialize the swizzler
631 if (fCodec->fFrameIsSubset) {
632 int sampleX;
633 SkScaledCodec::ComputeSampleSize(dstInfo, fCodec->getInfo(), &sample X, NULL);
634 const SkImageInfo subsetDstInfo = dstInfo.makeWH(
635 get_scaled_dimension(fCodec->fFrameDims.width(), sampleX),
636 fCodec->fFrameDims.height());
637 if (SkCodec::kSuccess != fCodec->initializeSwizzler(subsetDstInfo,
638 opts.fZeroInitialized)) {
639 return gif_error("Could not initialize swizzler.\n", SkCodec::kU nimplemented);
640 }
641 } else {
642 if (SkCodec::kSuccess != fCodec->initializeSwizzler(dstInfo, opts.fZ eroInitialized)) {
643 return gif_error("Could not initialize swizzler.\n", SkCodec::kU nimplemented);
644 }
645 }
646
647 return SkCodec::kSuccess;
648 }
649
650 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de {
651 if (fCodec->fFrameIsSubset) {
652 // Fill the requested rows
653 const SkPMColor* colorPtr = get_color_ptr(fCodec->fColorTable.get()) ;
654 SkSwizzler::Fill(dst, this->dstInfo(), rowBytes, count, fCodec->fFil lIndex,
655 colorPtr, this->options().fZeroInitialized);
656
657 // Do nothing for rows before the image frame
658 int rowsBeforeFrame = fCodec->fFrameDims.top() - INHERITED::getY();
659 if (rowsBeforeFrame > 0) {
660 count = SkTMin(0, count - rowsBeforeFrame);
661 dst = SkTAddOffset<void>(dst, rowBytes * rowsBeforeFrame);
662 }
663
664 // Do nothing for rows after the image frame
665 int rowsAfterFrame = INHERITED::getY() + count - fCodec->fFrameDims. bottom();
666 if (rowsAfterFrame > 0) {
667 count = SkTMin(0, count - rowsAfterFrame);
668 }
669
670 // Adjust dst pointer for left offset
671 dst = SkTAddOffset<void>(dst, SkColorTypeBytesPerPixel(
672 this->dstInfo().colorType()) * fCodec->fFrameDims.left());
673 }
674
675 for (int i = 0; i < count; i++) {
676 if (SkCodec::kSuccess != fCodec->readRow()) {
677 const SkPMColor* colorPtr = get_color_ptr(fCodec->fColorTable.ge t());
678 SkSwizzler::Fill(dst, this->dstInfo(), rowBytes,
679 count - i, fCodec->fFillIndex, colorPtr,
680 this->options().fZeroInitialized);
681 return gif_error("Could not decode line\n", SkCodec::kIncomplete Input);
682 }
683 fCodec->fSwizzler->swizzle(dst, fCodec->fSrcBuffer.get());
684 dst = SkTAddOffset<void>(dst, rowBytes);
685 }
686 return SkCodec::kSuccess;
687 }
688
689 SkScanlineOrder onGetScanlineOrder() const override {
690 if (fCodec->fGif->Image.Interlace) {
691 return kOutOfOrder_SkScanlineOrder;
692 } else {
693 return kTopDown_SkScanlineOrder;
694 }
695 }
696
697 int onGetY() const override {
698 if (fCodec->fGif->Image.Interlace) {
699 return get_output_row_interlaced(INHERITED::onGetY(), this->dstInfo ().height());
scroggo 2015/09/02 22:45:48 nit: extra space here
msarett 2015/09/03 17:13:31 Done.
700 } else {
701 return INHERITED::onGetY();
702 }
703 }
704
705 private:
706 SkAutoTDelete<SkGifCodec> fCodec;
707
708 typedef SkScanlineDecoder INHERITED;
709 };
710
711 SkScanlineDecoder* SkGifCodec::NewSDFromStream(SkStream* stream) {
712 SkAutoTDelete<SkGifCodec> codec (static_cast<SkGifCodec*>(SkGifCodec::NewFro mStream(stream)));
713 if (!codec) {
714 return NULL;
715 }
716
717 const SkImageInfo& srcInfo = codec->getInfo();
718
719 return SkNEW_ARGS(SkGifScanlineDecoder, (srcInfo, codec.detach()));
720 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698