Index: src/codec/SkCodec_libgif.cpp |
diff --git a/src/codec/SkCodec_libgif.cpp b/src/codec/SkCodec_libgif.cpp |
index 2a1d81fc00f99a71f3453579ee1ba49ad764442b..aa06f0d94707c12e981754949ea172f8ca91d7b1 100644 |
--- a/src/codec/SkCodec_libgif.cpp |
+++ b/src/codec/SkCodec_libgif.cpp |
@@ -131,41 +131,58 @@ static uint32_t find_trans_index(const SavedImage& image) { |
} |
/* |
- * Assumes IsGif was called and returned true |
- * Creates a gif decoder |
- * Reads enough of the stream to determine the image format |
+ * Read enough of the stream to initialize the SkGifCodec. |
+ * Returns a bool representing success or failure. |
+ * If it returned true, and codecOut was not NULL, |
+ * it will be set to a new SkGifCodec. |
*/ |
-SkCodec* SkGifCodec::NewFromStream(SkStream* stream) { |
+bool SkGifCodec::ReadHeader(SkStream* stream, SkCodec** codecOut) { |
// Read gif header, logical screen descriptor, and global color table |
SkAutoTCallIProc<GifFileType, CloseGif> gif(open_gif(stream)); |
if (NULL == gif) { |
gif_error("DGifOpen failed.\n"); |
- return NULL; |
+ return false; |
} |
- // Get fields from header |
- const int32_t width = gif->SWidth; |
- const int32_t height = gif->SHeight; |
- if (width <= 0 || height <= 0) { |
- gif_error("Invalid dimensions.\n"); |
- return NULL; |
+ if (NULL != codecOut) { |
+ // Get fields from header |
+ const int32_t width = gif->SWidth; |
+ const int32_t height = gif->SHeight; |
+ if (width <= 0 || height <= 0) { |
+ gif_error("Invalid dimensions.\n"); |
+ return false; |
+ } |
+ |
+ // Return the codec |
+ // kIndex is the most natural color type for gifs, so we set this as |
+ // the default. |
+ // Many gifs specify a color table index for transparent pixels. Every |
+ // other pixel is guaranteed to be opaque. Despite this, because of the |
+ // possiblity of transparent pixels, we cannot assume that the image is |
+ // opaque. We have the option to set the alpha type as kPremul or |
+ // kUnpremul. Both are valid since the alpha component will always be |
+ // 0xFF or the entire 32-bit pixel will be set to zero. We prefer |
+ // kPremul because we support kPremul, and it is more efficient to |
+ // use kPremul directly even when kUnpremul is supported. |
+ const SkImageInfo& imageInfo = SkImageInfo::Make(width, height, |
+ kIndex_8_SkColorType, kPremul_SkAlphaType); |
+ *codecOut = SkNEW_ARGS(SkGifCodec, (imageInfo, stream, gif.detach())); |
} |
+ return true; |
+} |
- // Return the codec |
- // kIndex is the most natural color type for gifs, so we set this as |
- // the default. |
- // Many gifs specify a color table index for transparent pixels. Every |
- // other pixel is guaranteed to be opaque. Despite this, because of the |
- // possiblity of transparent pixels, we cannot assume that the image is |
- // opaque. We have the option to set the alpha type as kPremul or |
- // kUnpremul. Both are valid since the alpha component will always be |
- // 0xFF or the entire 32-bit pixel will be set to zero. We prefer |
- // kPremul because we support kPremul, and it is more efficient to |
- // use kPremul directly even when kUnpremul is supported. |
- const SkImageInfo& imageInfo = SkImageInfo::Make(width, height, |
- kIndex_8_SkColorType, kPremul_SkAlphaType); |
- return SkNEW_ARGS(SkGifCodec, (imageInfo, stream, gif.detach())); |
+/* |
+ * Assumes IsGif was called and returned true |
+ * Creates a gif decoder |
+ * Reads enough of the stream to determine the image format |
+ */ |
+SkCodec* SkGifCodec::NewFromStream(SkStream* stream) { |
+ SkCodec* codec = NULL; |
+ if (ReadHeader(stream, &codec)) { |
+ return codec; |
+ } |
+ return NULL; |
} |
SkGifCodec::SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream, |
@@ -190,6 +207,9 @@ static bool conversion_possible(const SkImageInfo& dst, |
case kN32_SkColorType: |
return kPremul_SkAlphaType == dst.alphaType() || |
kUnpremul_SkAlphaType == dst.alphaType(); |
+ case kIndex_8_SkColorType: |
+ return kPremul_SkAlphaType == dst.alphaType() || |
+ kUnpremul_SkAlphaType == dst.alphaType(); |
default: |
return false; |
} |
@@ -200,11 +220,20 @@ static bool conversion_possible(const SkImageInfo& dst, |
*/ |
SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, |
void* dst, size_t dstRowBytes, |
- const Options& opts, SkPMColor*, int*) { |
- // Check for valid input parameters |
- if (!this->rewindIfNeeded()) { |
+ const Options& opts, |
+ SkPMColor* inputColorPtr, |
+ int* inputColorCount) { |
+ // Rewind if necessary |
+ SkCodec::RewindState rewindState = this->rewindIfNeeded(); |
+ if (rewindState == kCouldNotRewind_RewindState) { |
return kCouldNotRewind; |
+ } else if (rewindState == kRewound_RewindState) { |
+ if (!ReadHeader(this->stream(), NULL)) { |
+ return kCouldNotRewind; |
+ } |
} |
+ |
+ // Check for valid input parameters |
if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
return gif_error("Scaling not supported.\n", kInvalidScale); |
} |
@@ -284,11 +313,15 @@ SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, |
imageTop = 0; |
} |
+ // Create a color table to store colors the giflib colorMap |
+ SkPMColor alternateColorPtr[256]; |
+ SkPMColor* colorTable = get_color_table_ptr(dstInfo.colorType(), |
+ inputColorPtr, inputColorCount, alternateColorPtr); |
+ |
// Set up the color table |
uint32_t colorCount = 0; |
// Allocate maximum storage to deal with invalid indices safely |
const uint32_t maxColors = 256; |
- SkPMColor colorTable[maxColors]; |
ColorMapObject* colorMap = fGif->Image.ColorMap; |
// If there is no local color table, use the global color table |
if (NULL == colorMap) { |
@@ -346,6 +379,7 @@ SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, |
// Check if image is only a subset of the image frame |
SkAutoTDelete<SkSwizzler> swizzler(NULL); |
+ SkColorType dstColorType = dstInfo.colorType(); |
if (innerWidth < width || innerHeight < height) { |
// Modify the destination info |
@@ -356,7 +390,6 @@ SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, |
// FIXME: This may not be the behavior that we want for |
// animated gifs where we draw on top of the |
// previous frame. |
- SkColorType dstColorType = dstInfo.colorType(); |
if (fillBackground) { |
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
|
case kN32_SkColorType: |
@@ -365,6 +398,11 @@ SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, |
((int) dstRowBytes) * height |
/ sizeof(SkPMColor)); |
break; |
+ case kIndex_8_SkColorType: |
+ memset((SkPMColor*) dst, |
+ fillIndex, |
+ ((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
|
+ break; |
default: |
SkASSERT(false); |
break; |
@@ -421,11 +459,22 @@ SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, |
if (GIF_ERROR == DGifGetLine(fGif, buffer.get(), |
innerWidth)) { |
if (fillBackground) { |
- SkPMColor* dstPtr = (SkPMColor*) SkTAddOffset |
- <void*>(dst, y * dstRowBytes); |
- sk_memset32(dstPtr, colorTable[fillIndex], |
- (height - y) * ((int) dstRowBytes) |
- / sizeof(SkPMColor)); |
+ switch (dstColorType) { |
+ case kN32_SkColorType: |
+ sk_memset32((SkPMColor*) dst, |
+ colorTable[fillIndex], |
+ (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.
|
+ / sizeof(SkPMColor)); |
+ break; |
+ case kIndex_8_SkColorType: |
+ memset((SkPMColor*) dst, |
+ fillIndex, |
+ (height - y) * ((int) dstRowBytes)); |
+ break; |
+ default: |
+ SkASSERT(false); |
+ break; |
+ } |
} |
return gif_error(SkStringPrintf( |
"Could not decode line %d of %d.\n", |