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

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: Gif rewinding that actually works 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
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 113 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 * If it returned true, and codecOut was not NULL,
137 * it will be set to a new SkGifCodec.
138 */
139
140 bool SkGifCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, GifFileType** gifOut) {
141 SkAutoTDelete<SkStream> streamDeleter(stream);
142
143 // Read gif header, logical screen descriptor, and global color table
144 SkAutoTCallIProc<GifFileType, CloseGif> gif(open_gif(stream));
145
146 if (NULL == gif) {
147 gif_error("DGifOpen failed.\n");
148 return false;
149 }
150
151 if (NULL != codecOut) {
152 // Get fields from header
153 const int32_t width = gif->SWidth;
154 const int32_t height = gif->SHeight;
155 if (width <= 0 || height <= 0) {
156 gif_error("Invalid dimensions.\n");
157 return false;
158 }
159
160 // Return the codec
161 // kIndex is the most natural color type for gifs, so we set this as
162 // the default.
163 // Many gifs specify a color table index for transparent pixels. Every
164 // other pixel is guaranteed to be opaque. Despite this, because of the
165 // possiblity of transparent pixels, we cannot assume that the image is
166 // opaque. We have the option to set the alpha type as kPremul or
167 // kUnpremul. Both are valid since the alpha component will always be
168 // 0xFF or the entire 32-bit pixel will be set to zero. We prefer
169 // kPremul because we support kPremul, and it is more efficient to
170 // use kPremul directly even when kUnpremul is supported.
171 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height,
172 kIndex_8_SkColorType, kPremul_SkAlphaType);
173 *codecOut = SkNEW_ARGS(SkGifCodec, (imageInfo, streamDeleter.detach(), g if.detach()));
174 } else {
175 SkASSERT(NULL != gifOut);
176 streamDeleter.detach();
177 *gifOut = gif.detach();
178 }
179 return true;
180 }
181
182 /*
134 * Assumes IsGif was called and returned true 183 * Assumes IsGif was called and returned true
135 * Creates a gif decoder 184 * Creates a gif decoder
136 * Reads enough of the stream to determine the image format 185 * Reads enough of the stream to determine the image format
137 */ 186 */
138 SkCodec* SkGifCodec::NewFromStream(SkStream* stream) { 187 SkCodec* SkGifCodec::NewFromStream(SkStream* stream) {
139 SkAutoTDelete<SkStream> streamDeleter(stream); 188 SkCodec* codec = NULL;
140 // Read gif header, logical screen descriptor, and global color table 189 if (ReadHeader(stream, &codec, NULL)) {
141 SkAutoTCallIProc<GifFileType, CloseGif> gif(open_gif(stream)); 190 return codec;
142
143 if (NULL == gif) {
144 gif_error("DGifOpen failed.\n");
145 return NULL;
146 } 191 }
147 192 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 } 193 }
171 194
172 SkGifCodec::SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream, 195 SkGifCodec::SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream,
173 GifFileType* gif) 196 GifFileType* gif)
174 : INHERITED(srcInfo, stream) 197 : INHERITED(srcInfo, stream)
175 , fGif(gif) 198 , fGif(gif)
176 {} 199 {}
177 200
178 /* 201 /*
179 * Checks if the conversion between the input image and the requested output 202 * Checks if the conversion between the input image and the requested output
180 * image has been implemented 203 * image has been implemented
181 */ 204 */
182 static bool conversion_possible(const SkImageInfo& dst, 205 static bool conversion_possible(const SkImageInfo& dst,
183 const SkImageInfo& src) { 206 const SkImageInfo& src) {
184 // Ensure that the profile type is unchanged 207 // Ensure that the profile type is unchanged
185 if (dst.profileType() != src.profileType()) { 208 if (dst.profileType() != src.profileType()) {
186 return false; 209 return false;
187 } 210 }
188 211
189 // Check for supported color and alpha types 212 // Check for supported color and alpha types
190 switch (dst.colorType()) { 213 switch (dst.colorType()) {
191 case kN32_SkColorType: 214 case kN32_SkColorType:
192 return kPremul_SkAlphaType == dst.alphaType() || 215 return kPremul_SkAlphaType == dst.alphaType() ||
193 kUnpremul_SkAlphaType == dst.alphaType(); 216 kUnpremul_SkAlphaType == dst.alphaType();
217 case kIndex_8_SkColorType:
218 return kPremul_SkAlphaType == dst.alphaType() ||
219 kUnpremul_SkAlphaType == dst.alphaType();
194 default: 220 default:
195 return false; 221 return false;
196 } 222 }
197 } 223 }
198 224
199 /* 225 /*
200 * Initiates the gif decode 226 * Initiates the gif decode
201 */ 227 */
202 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, 228 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo,
203 void* dst, size_t dstRowBytes, 229 void* dst, size_t dstRowBytes,
204 const Options& opts, SkPMColor*, int*) { 230 const Options& opts,
231 SkPMColor* inputColorPtr,
232 int* inputColorCount) {
233 // Rewind if necessary
234 SkCodec::RewindState rewindState = this->rewindIfNeeded();
235 if (rewindState == kCouldNotRewind_RewindState) {
236 return kCouldNotRewind;
237 } else if (rewindState == kRewound_RewindState) {
238 GifFileType* gifOut = NULL;
239 if (!ReadHeader(this->stream(), NULL, &gifOut)) {
240 return kCouldNotRewind;
241 } else {
242 SkASSERT(NULL != gifOut);
243 fGif.reset(gifOut);
244 }
245 }
246
205 // Check for valid input parameters 247 // Check for valid input parameters
206 if (!this->rewindIfNeeded()) {
207 return kCouldNotRewind;
208 }
209 if (dstInfo.dimensions() != this->getInfo().dimensions()) { 248 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
210 return gif_error("Scaling not supported.\n", kInvalidScale); 249 return gif_error("Scaling not supported.\n", kInvalidScale);
211 } 250 }
212 if (!conversion_possible(dstInfo, this->getInfo())) { 251 if (!conversion_possible(dstInfo, this->getInfo())) {
213 return gif_error("Cannot convert input type to output type.\n", 252 return gif_error("Cannot convert input type to output type.\n",
214 kInvalidConversion); 253 kInvalidConversion);
215 } 254 }
216 255
217 // Use this as a container to hold information about any gif extension 256 // Use this as a container to hold information about any gif extension
218 // blocks. This generally stores transparency and animation instructions. 257 // blocks. This generally stores transparency and animation instructions.
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 innerHeight = height; 317 innerHeight = height;
279 imageTop = 0; 318 imageTop = 0;
280 } else if (imageTop + innerHeight > height) { 319 } else if (imageTop + innerHeight > height) {
281 gif_warning("Shifting inner image up to fit.\n"); 320 gif_warning("Shifting inner image up to fit.\n");
282 imageTop = height - innerHeight; 321 imageTop = height - innerHeight;
283 } else if (imageTop < 0) { 322 } else if (imageTop < 0) {
284 gif_warning("Shifting image down to fit\n"); 323 gif_warning("Shifting image down to fit\n");
285 imageTop = 0; 324 imageTop = 0;
286 } 325 }
287 326
327 // Create a color table to store colors the giflib colorMap
328 SkPMColor alternateColorPtr[256];
329 SkPMColor* colorTable;
330 SkColorType dstColorType = dstInfo.colorType();
331 if (kIndex_8_SkColorType == dstColorType) {
332 SkASSERT(NULL != inputColorPtr);
333 SkASSERT(NULL != inputColorCount);
334 SkASSERT(256 == *inputColorCount);
335 colorTable = inputColorPtr;
336 } else {
337 colorTable = alternateColorPtr;
338 }
339
288 // Set up the color table 340 // Set up the color table
289 uint32_t colorCount = 0; 341 uint32_t colorCount = 0;
290 // Allocate maximum storage to deal with invalid indices safely 342 // Allocate maximum storage to deal with invalid indices safely
291 const uint32_t maxColors = 256; 343 const uint32_t maxColors = 256;
292 SkPMColor colorTable[maxColors];
293 ColorMapObject* colorMap = fGif->Image.ColorMap; 344 ColorMapObject* colorMap = fGif->Image.ColorMap;
294 // If there is no local color table, use the global color table 345 // If there is no local color table, use the global color table
295 if (NULL == colorMap) { 346 if (NULL == colorMap) {
296 colorMap = fGif->SColorMap; 347 colorMap = fGif->SColorMap;
297 } 348 }
298 if (NULL != colorMap) { 349 if (NULL != colorMap) {
299 colorCount = colorMap->ColorCount; 350 colorCount = colorMap->ColorCount;
300 SkASSERT(colorCount == 351 SkASSERT(colorCount ==
301 (unsigned) (1 << (colorMap->BitsPerPixel))); 352 (unsigned) (1 << (colorMap->BitsPerPixel)));
302 SkASSERT(colorCount <= 256); 353 SkASSERT(colorCount <= 256);
303 for (uint32_t i = 0; i < colorCount; i++) { 354 for (uint32_t i = 0; i < colorCount; i++) {
304 colorTable[i] = SkPackARGB32(0xFF, 355 colorTable[i] = SkPackARGB32(0xFF,
305 colorMap->Colors[i].Red, 356 colorMap->Colors[i].Red,
306 colorMap->Colors[i].Green, 357 colorMap->Colors[i].Green,
307 colorMap->Colors[i].Blue); 358 colorMap->Colors[i].Blue);
308 } 359 }
309 } 360 }
310 361
311 // This is used to fill unspecified pixels in the image data. 362 // This is used to fill unspecified pixels in the image data.
312 uint32_t fillIndex = fGif->SBackGroundColor; 363 uint32_t fillIndex = fGif->SBackGroundColor;
313 bool fillBackground = true;
314 ZeroInitialized zeroInit = opts.fZeroInitialized; 364 ZeroInitialized zeroInit = opts.fZeroInitialized;
315 365
316 // Gifs have the option to specify the color at a single 366 // Gifs have the option to specify the color at a single
317 // index of the color table as transparent. 367 // index of the color table as transparent.
318 { 368 {
319 // Get the transparent index. If the return value of this 369 // Get the transparent index. If the return value of this
320 // function is greater than the colorCount, we know that 370 // function is greater than the colorCount, we know that
321 // there is no valid transparent color in the color table. 371 // there is no valid transparent color in the color table.
322 // This occurs if there is no graphics control extension or 372 // This occurs if there is no graphics control extension or
323 // if the index specified by the graphics control extension 373 // if the index specified by the graphics control extension
324 // is out of range. 374 // is out of range.
325 uint32_t transIndex = find_trans_index(saveExt); 375 uint32_t transIndex = find_trans_index(saveExt);
326 376
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) { 377 if (transIndex < colorCount) {
330 colorTable[transIndex] = SK_ColorTRANSPARENT; 378 colorTable[transIndex] = SK_ColorTRANSPARENT;
331 // If there is a transparent index, we also use this as 379 // If there is a transparent index, we also use this as
332 // the fill index. 380 // the fill index.
333 fillIndex = transIndex; 381 fillIndex = transIndex;
334 fillBackground = (kYes_ZeroInitialized != zeroInit);
335 } else if (fillIndex >= colorCount) { 382 } else if (fillIndex >= colorCount) {
336 // If the fill index is invalid, we default to 0. This 383 // If the fill index is invalid, we default to 0. This
337 // behavior is unspecified but matches SkImageDecoder. 384 // behavior is unspecified but matches SkImageDecoder.
338 fillIndex = 0; 385 fillIndex = 0;
339 } 386 }
340 } 387 }
341 388
389 // Check if we can skip filling the background of the image. We
390 // may be able to if the memory is zero initialized.
391 bool skipBackground =
392 ((kN32_SkColorType == dstColorType && colorTable[fillInd ex] == 0) ||
393 (kIndex_8_SkColorType == dstColorType && fillIndex == 0) ) &&
394 kYes_ZeroInitialized == zeroInit;
395
396
342 // Fill in the color table for indices greater than color count. 397 // Fill in the color table for indices greater than color count.
343 // This allows for predictable, safe behavior. 398 // This allows for predictable, safe behavior.
344 for (uint32_t i = colorCount; i < maxColors; i++) { 399 for (uint32_t i = colorCount; i < maxColors; i++) {
345 colorTable[i] = colorTable[fillIndex]; 400 colorTable[i] = colorTable[fillIndex];
346 } 401 }
347 402
348 // Check if image is only a subset of the image frame 403 // Check if image is only a subset of the image frame
349 SkAutoTDelete<SkSwizzler> swizzler(NULL); 404 SkAutoTDelete<SkSwizzler> swizzler(NULL);
350 if (innerWidth < width || innerHeight < height) { 405 if (innerWidth < width || innerHeight < height) {
351 406
352 // Modify the destination info 407 // Modify the destination info
353 const SkImageInfo subsetDstInfo = 408 const SkImageInfo subsetDstInfo =
354 dstInfo.makeWH(innerWidth, innerHeight); 409 dstInfo.makeWH(innerWidth, innerHeight);
355 410
356 // Fill the destination with the fill color 411 // Fill the destination with the fill color
357 // FIXME: This may not be the behavior that we want for 412 // FIXME: This may not be the behavior that we want for
358 // animated gifs where we draw on top of the 413 // animated gifs where we draw on top of the
359 // previous frame. 414 // previous frame.
360 SkColorType dstColorType = dstInfo.colorType(); 415 if (!skipBackground) {
361 if (fillBackground) { 416 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 } 417 }
374 418
375 // Modify the dst pointer 419 // Modify the dst pointer
376 const int32_t dstBytesPerPixel = 420 const int32_t dstBytesPerPixel =
377 SkColorTypeBytesPerPixel(dstColorType); 421 SkColorTypeBytesPerPixel(dstColorType);
378 void* subsetDst = SkTAddOffset<void*>(dst, 422 void* subsetDst = SkTAddOffset<void*>(dst,
379 dstRowBytes * imageTop + 423 dstRowBytes * imageTop +
380 dstBytesPerPixel * imageLeft); 424 dstBytesPerPixel * imageLeft);
381 425
382 // Create the subset swizzler 426 // Create the subset swizzler
(...skipping 14 matching lines...) Expand all
397 // Check the interlace flag and iterate over rows of the input 441 // Check the interlace flag and iterate over rows of the input
398 if (fGif->Image.Interlace) { 442 if (fGif->Image.Interlace) {
399 // In interlace mode, the rows of input are rearranged in 443 // In interlace mode, the rows of input are rearranged in
400 // the output image. We use an iterator to take care of 444 // the output image. We use an iterator to take care of
401 // the rearranging. 445 // the rearranging.
402 SkGifInterlaceIter iter(innerHeight); 446 SkGifInterlaceIter iter(innerHeight);
403 for (int32_t y = 0; y < innerHeight; y++) { 447 for (int32_t y = 0; y < innerHeight; y++) {
404 if (GIF_ERROR == DGifGetLine(fGif, buffer.get(), 448 if (GIF_ERROR == DGifGetLine(fGif, buffer.get(),
405 innerWidth)) { 449 innerWidth)) {
406 // Recover from error by filling remainder of image 450 // Recover from error by filling remainder of image
407 if (fillBackground) { 451 if (!skipBackground) {
408 memset(buffer.get(), fillIndex, innerWidth); 452 memset(buffer.get(), fillIndex, innerWidth);
409 for (; y < innerHeight; y++) { 453 for (; y < innerHeight; y++) {
410 swizzler->next(buffer.get(), iter.nextY()); 454 swizzler->next(buffer.get(), iter.nextY());
411 } 455 }
412 } 456 }
413 return gif_error(SkStringPrintf( 457 return gif_error(SkStringPrintf(
414 "Could not decode line %d of %d.\n", 458 "Could not decode line %d of %d.\n",
415 y, height - 1).c_str(), kIncompleteInput); 459 y, height - 1).c_str(), kIncompleteInput);
416 } 460 }
417 swizzler->next(buffer.get(), iter.nextY()); 461 swizzler->next(buffer.get(), iter.nextY());
418 } 462 }
419 } else { 463 } else {
420 // Standard mode 464 // Standard mode
421 for (int32_t y = 0; y < innerHeight; y++) { 465 for (int32_t y = 0; y < innerHeight; y++) {
422 if (GIF_ERROR == DGifGetLine(fGif, buffer.get(), 466 if (GIF_ERROR == DGifGetLine(fGif, buffer.get(),
423 innerWidth)) { 467 innerWidth)) {
424 if (fillBackground) { 468 if (!skipBackground) {
425 SkPMColor* dstPtr = (SkPMColor*) SkTAddOffset 469 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, y, f illIndex,
426 <void*>(dst, y * dstRowBytes); 470 colorTable);
427 sk_memset32(dstPtr, colorTable[fillIndex],
428 (height - y) * ((int) dstRowBytes)
429 / sizeof(SkPMColor));
430 } 471 }
431 return gif_error(SkStringPrintf( 472 return gif_error(SkStringPrintf(
432 "Could not decode line %d of %d.\n", 473 "Could not decode line %d of %d.\n",
433 y, height - 1).c_str(), kIncompleteInput); 474 y, height - 1).c_str(), kIncompleteInput);
434 } 475 }
435 swizzler->next(buffer.get()); 476 swizzler->next(buffer.get());
436 } 477 }
437 } 478 }
438 479
439 // FIXME: Gif files may have multiple images stored in a single 480 // 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. 550 // giflib returns an error code if the record type is not known.
510 // We should catch this error immediately. 551 // We should catch this error immediately.
511 SkASSERT(false); 552 SkASSERT(false);
512 break; 553 break;
513 } 554 }
514 } while (TERMINATE_RECORD_TYPE != recordType); 555 } while (TERMINATE_RECORD_TYPE != recordType);
515 556
516 return gif_error("Could not find any images to decode in gif file.\n", 557 return gif_error("Could not find any images to decode in gif file.\n",
517 kInvalidInput); 558 kInvalidInput);
518 } 559 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698