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

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

Powered by Google App Engine
This is Rietveld 408576698