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

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: 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 bool SkGifCodec::ReadHeader(SkStream* stream, SkCodec** codecOut) {
140 // Read gif header, logical screen descriptor, and global color table
141 SkAutoTCallIProc<GifFileType, CloseGif> gif(open_gif(stream));
142
143 if (NULL == gif) {
144 gif_error("DGifOpen failed.\n");
145 return false;
146 }
147
148 if (NULL != codecOut) {
149 // Get fields from header
150 const int32_t width = gif->SWidth;
151 const int32_t height = gif->SHeight;
152 if (width <= 0 || height <= 0) {
153 gif_error("Invalid dimensions.\n");
154 return false;
155 }
156
157 // Return the codec
158 // kIndex is the most natural color type for gifs, so we set this as
159 // the default.
160 // Many gifs specify a color table index for transparent pixels. Every
161 // other pixel is guaranteed to be opaque. Despite this, because of the
162 // possiblity of transparent pixels, we cannot assume that the image is
163 // opaque. We have the option to set the alpha type as kPremul or
164 // kUnpremul. Both are valid since the alpha component will always be
165 // 0xFF or the entire 32-bit pixel will be set to zero. We prefer
166 // kPremul because we support kPremul, and it is more efficient to
167 // use kPremul directly even when kUnpremul is supported.
168 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height,
169 kIndex_8_SkColorType, kPremul_SkAlphaType);
170 *codecOut = SkNEW_ARGS(SkGifCodec, (imageInfo, stream, gif.detach()));
171 }
172 return true;
173 }
174
175 /*
134 * Assumes IsGif was called and returned true 176 * Assumes IsGif was called and returned true
135 * Creates a gif decoder 177 * Creates a gif decoder
136 * Reads enough of the stream to determine the image format 178 * Reads enough of the stream to determine the image format
137 */ 179 */
138 SkCodec* SkGifCodec::NewFromStream(SkStream* stream) { 180 SkCodec* SkGifCodec::NewFromStream(SkStream* stream) {
139 // Read gif header, logical screen descriptor, and global color table 181 SkCodec* codec = NULL;
140 SkAutoTCallIProc<GifFileType, CloseGif> gif(open_gif(stream)); 182 if (ReadHeader(stream, &codec)) {
141 183 return codec;
142 if (NULL == gif) {
143 gif_error("DGifOpen failed.\n");
144 return NULL;
145 } 184 }
146 185 return NULL;
147 // Get fields from header
148 const int32_t width = gif->SWidth;
149 const int32_t height = gif->SHeight;
150 if (width <= 0 || height <= 0) {
151 gif_error("Invalid dimensions.\n");
152 return NULL;
153 }
154
155 // Return the codec
156 // kIndex is the most natural color type for gifs, so we set this as
157 // the default.
158 // Many gifs specify a color table index for transparent pixels. Every
159 // other pixel is guaranteed to be opaque. Despite this, because of the
160 // possiblity of transparent pixels, we cannot assume that the image is
161 // opaque. We have the option to set the alpha type as kPremul or
162 // kUnpremul. Both are valid since the alpha component will always be
163 // 0xFF or the entire 32-bit pixel will be set to zero. We prefer
164 // kPremul because we support kPremul, and it is more efficient to
165 // use kPremul directly even when kUnpremul is supported.
166 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height,
167 kIndex_8_SkColorType, kPremul_SkAlphaType);
168 return SkNEW_ARGS(SkGifCodec, (imageInfo, stream, gif.detach()));
169 } 186 }
170 187
171 SkGifCodec::SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream, 188 SkGifCodec::SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream,
172 GifFileType* gif) 189 GifFileType* gif)
173 : INHERITED(srcInfo, stream) 190 : INHERITED(srcInfo, stream)
174 , fGif(gif) 191 , fGif(gif)
175 {} 192 {}
176 193
177 /* 194 /*
178 * Checks if the conversion between the input image and the requested output 195 * Checks if the conversion between the input image and the requested output
179 * image has been implemented 196 * image has been implemented
180 */ 197 */
181 static bool conversion_possible(const SkImageInfo& dst, 198 static bool conversion_possible(const SkImageInfo& dst,
182 const SkImageInfo& src) { 199 const SkImageInfo& src) {
183 // Ensure that the profile type is unchanged 200 // Ensure that the profile type is unchanged
184 if (dst.profileType() != src.profileType()) { 201 if (dst.profileType() != src.profileType()) {
185 return false; 202 return false;
186 } 203 }
187 204
188 // Check for supported color and alpha types 205 // Check for supported color and alpha types
189 switch (dst.colorType()) { 206 switch (dst.colorType()) {
190 case kN32_SkColorType: 207 case kN32_SkColorType:
191 return kPremul_SkAlphaType == dst.alphaType() || 208 return kPremul_SkAlphaType == dst.alphaType() ||
192 kUnpremul_SkAlphaType == dst.alphaType(); 209 kUnpremul_SkAlphaType == dst.alphaType();
210 case kIndex_8_SkColorType:
211 return kPremul_SkAlphaType == dst.alphaType() ||
212 kUnpremul_SkAlphaType == dst.alphaType();
193 default: 213 default:
194 return false; 214 return false;
195 } 215 }
196 } 216 }
197 217
198 /* 218 /*
199 * Initiates the gif decode 219 * Initiates the gif decode
200 */ 220 */
201 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, 221 SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo,
202 void* dst, size_t dstRowBytes, 222 void* dst, size_t dstRowBytes,
203 const Options& opts, SkPMColor*, int*) { 223 const Options& opts,
224 SkPMColor* inputColorPtr,
225 int* inputColorCount) {
226 // Rewind if necessary
227 SkCodec::RewindState rewindState = this->rewindIfNeeded();
228 if (rewindState == kCouldNotRewind_RewindState) {
229 return kCouldNotRewind;
230 } else if (rewindState == kRewound_RewindState) {
231 if (!ReadHeader(this->stream(), NULL)) {
232 return kCouldNotRewind;
233 }
234 }
235
204 // Check for valid input parameters 236 // Check for valid input parameters
205 if (!this->rewindIfNeeded()) {
206 return kCouldNotRewind;
207 }
208 if (dstInfo.dimensions() != this->getInfo().dimensions()) { 237 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
209 return gif_error("Scaling not supported.\n", kInvalidScale); 238 return gif_error("Scaling not supported.\n", kInvalidScale);
210 } 239 }
211 if (!conversion_possible(dstInfo, this->getInfo())) { 240 if (!conversion_possible(dstInfo, this->getInfo())) {
212 return gif_error("Cannot convert input type to output type.\n", 241 return gif_error("Cannot convert input type to output type.\n",
213 kInvalidConversion); 242 kInvalidConversion);
214 } 243 }
215 244
216 // Use this as a container to hold information about any gif extension 245 // Use this as a container to hold information about any gif extension
217 // blocks. This generally stores transparency and animation instructions. 246 // blocks. This generally stores transparency and animation instructions.
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
277 innerHeight = height; 306 innerHeight = height;
278 imageTop = 0; 307 imageTop = 0;
279 } else if (imageTop + innerHeight > height) { 308 } else if (imageTop + innerHeight > height) {
280 gif_warning("Shifting inner image up to fit.\n"); 309 gif_warning("Shifting inner image up to fit.\n");
281 imageTop = height - innerHeight; 310 imageTop = height - innerHeight;
282 } else if (imageTop < 0) { 311 } else if (imageTop < 0) {
283 gif_warning("Shifting image down to fit\n"); 312 gif_warning("Shifting image down to fit\n");
284 imageTop = 0; 313 imageTop = 0;
285 } 314 }
286 315
316 // Create a color table to store colors the giflib colorMap
317 SkPMColor alternateColorPtr[256];
318 SkPMColor* colorTable = get_color_table_ptr(dstInfo.colorType(),
319 inputColorPtr, inputColorCount, alternateColorPtr);
320
287 // Set up the color table 321 // Set up the color table
288 uint32_t colorCount = 0; 322 uint32_t colorCount = 0;
289 // Allocate maximum storage to deal with invalid indices safely 323 // Allocate maximum storage to deal with invalid indices safely
290 const uint32_t maxColors = 256; 324 const uint32_t maxColors = 256;
291 SkPMColor colorTable[maxColors];
292 ColorMapObject* colorMap = fGif->Image.ColorMap; 325 ColorMapObject* colorMap = fGif->Image.ColorMap;
293 // If there is no local color table, use the global color table 326 // If there is no local color table, use the global color table
294 if (NULL == colorMap) { 327 if (NULL == colorMap) {
295 colorMap = fGif->SColorMap; 328 colorMap = fGif->SColorMap;
296 } 329 }
297 if (NULL != colorMap) { 330 if (NULL != colorMap) {
298 colorCount = colorMap->ColorCount; 331 colorCount = colorMap->ColorCount;
299 SkASSERT(colorCount == 332 SkASSERT(colorCount ==
300 (unsigned) (1 << (colorMap->BitsPerPixel))); 333 (unsigned) (1 << (colorMap->BitsPerPixel)));
301 SkASSERT(colorCount <= 256); 334 SkASSERT(colorCount <= 256);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
339 } 372 }
340 373
341 // Fill in the color table for indices greater than color count. 374 // Fill in the color table for indices greater than color count.
342 // This allows for predictable, safe behavior. 375 // This allows for predictable, safe behavior.
343 for (uint32_t i = colorCount; i < maxColors; i++) { 376 for (uint32_t i = colorCount; i < maxColors; i++) {
344 colorTable[i] = colorTable[fillIndex]; 377 colorTable[i] = colorTable[fillIndex];
345 } 378 }
346 379
347 // Check if image is only a subset of the image frame 380 // Check if image is only a subset of the image frame
348 SkAutoTDelete<SkSwizzler> swizzler(NULL); 381 SkAutoTDelete<SkSwizzler> swizzler(NULL);
382 SkColorType dstColorType = dstInfo.colorType();
349 if (innerWidth < width || innerHeight < height) { 383 if (innerWidth < width || innerHeight < height) {
350 384
351 // Modify the destination info 385 // Modify the destination info
352 const SkImageInfo subsetDstInfo = 386 const SkImageInfo subsetDstInfo =
353 dstInfo.makeWH(innerWidth, innerHeight); 387 dstInfo.makeWH(innerWidth, innerHeight);
354 388
355 // Fill the destination with the fill color 389 // Fill the destination with the fill color
356 // FIXME: This may not be the behavior that we want for 390 // FIXME: This may not be the behavior that we want for
357 // animated gifs where we draw on top of the 391 // animated gifs where we draw on top of the
358 // previous frame. 392 // previous frame.
359 SkColorType dstColorType = dstInfo.colorType();
360 if (fillBackground) { 393 if (fillBackground) {
361 switch (dstColorType) { 394 switch (dstColorType) {
msarett 2015/04/02 17:26:29 I've been looking at factoring this into the swizz
scroggo 2015/04/02 19:20:31 That should be determined by the SrcConfig, correc
msarett 2015/04/03 18:01:32 I added a SkSwizzler::Fill() function. It turns o
362 case kN32_SkColorType: 395 case kN32_SkColorType:
363 sk_memset32((SkPMColor*) dst, 396 sk_memset32((SkPMColor*) dst,
364 colorTable[fillIndex], 397 colorTable[fillIndex],
365 ((int) dstRowBytes) * height 398 ((int) dstRowBytes) * height
366 / sizeof(SkPMColor)); 399 / sizeof(SkPMColor));
367 break; 400 break;
401 case kIndex_8_SkColorType:
402 memset((SkPMColor*) dst,
403 fillIndex,
404 ((int) dstRowBytes) * height);
scroggo 2015/04/02 19:20:31 Why did you cast to an int? (Sorry if this came up
msarett 2015/04/03 18:01:32 The cast was added for sk_memset32 which takes an
405 break;
368 default: 406 default:
369 SkASSERT(false); 407 SkASSERT(false);
370 break; 408 break;
371 } 409 }
372 } 410 }
373 411
374 // Modify the dst pointer 412 // Modify the dst pointer
375 const int32_t dstBytesPerPixel = 413 const int32_t dstBytesPerPixel =
376 SkColorTypeBytesPerPixel(dstColorType); 414 SkColorTypeBytesPerPixel(dstColorType);
377 void* subsetDst = SkTAddOffset<void*>(dst, 415 void* subsetDst = SkTAddOffset<void*>(dst,
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
414 y, height - 1).c_str(), kIncompleteInput); 452 y, height - 1).c_str(), kIncompleteInput);
415 } 453 }
416 swizzler->next(buffer.get(), iter.nextY()); 454 swizzler->next(buffer.get(), iter.nextY());
417 } 455 }
418 } else { 456 } else {
419 // Standard mode 457 // Standard mode
420 for (int32_t y = 0; y < innerHeight; y++) { 458 for (int32_t y = 0; y < innerHeight; y++) {
421 if (GIF_ERROR == DGifGetLine(fGif, buffer.get(), 459 if (GIF_ERROR == DGifGetLine(fGif, buffer.get(),
422 innerWidth)) { 460 innerWidth)) {
423 if (fillBackground) { 461 if (fillBackground) {
424 SkPMColor* dstPtr = (SkPMColor*) SkTAddOffset 462 switch (dstColorType) {
425 <void*>(dst, y * dstRowBytes); 463 case kN32_SkColorType:
426 sk_memset32(dstPtr, colorTable[fillIndex], 464 sk_memset32((SkPMColor*) dst,
427 (height - y) * ((int) dstRowBytes) 465 colorTable[fillIndex],
428 / sizeof(SkPMColor)); 466 (height - y) * ((int) dstRowBytes)
scroggo 2015/04/02 19:20:31 Again, for both of these, we need to be careful ab
msarett 2015/04/03 18:01:32 Acknowledged.
467 / sizeof(SkPMColor));
468 break;
469 case kIndex_8_SkColorType:
470 memset((SkPMColor*) dst,
471 fillIndex,
472 (height - y) * ((int) dstRowBytes));
473 break;
474 default:
475 SkASSERT(false);
476 break;
477 }
429 } 478 }
430 return gif_error(SkStringPrintf( 479 return gif_error(SkStringPrintf(
431 "Could not decode line %d of %d.\n", 480 "Could not decode line %d of %d.\n",
432 y, height - 1).c_str(), kIncompleteInput); 481 y, height - 1).c_str(), kIncompleteInput);
433 } 482 }
434 swizzler->next(buffer.get()); 483 swizzler->next(buffer.get());
435 } 484 }
436 } 485 }
437 486
438 // FIXME: Gif files may have multiple images stored in a single 487 // FIXME: Gif files may have multiple images stored in a single
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
508 // giflib returns an error code if the record type is not known. 557 // giflib returns an error code if the record type is not known.
509 // We should catch this error immediately. 558 // We should catch this error immediately.
510 SkASSERT(false); 559 SkASSERT(false);
511 break; 560 break;
512 } 561 }
513 } while (TERMINATE_RECORD_TYPE != recordType); 562 } while (TERMINATE_RECORD_TYPE != recordType);
514 563
515 return gif_error("Could not find any images to decode in gif file.\n", 564 return gif_error("Could not find any images to decode in gif file.\n",
516 kInvalidInput); 565 kInvalidInput);
517 } 566 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698