SkImageDecoder_libgif.cpp revision 6c22573edb234ad14df947278cfed010669a39a7
1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkColor.h"
9#include "SkColorPriv.h"
10#include "SkColorTable.h"
11#include "SkImageDecoder.h"
12#include "SkRTConf.h"
13#include "SkScaledBitmapSampler.h"
14#include "SkStream.h"
15#include "SkTemplates.h"
16#include "SkUtils.h"
17
18#include "gif_lib.h"
19
20class SkGIFImageDecoder : public SkImageDecoder {
21public:
22    virtual Format getFormat() const SK_OVERRIDE {
23        return kGIF_Format;
24    }
25
26protected:
27    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRIDE;
28
29private:
30    typedef SkImageDecoder INHERITED;
31};
32
33static const uint8_t gStartingIterlaceYValue[] = {
34    0, 4, 2, 1
35};
36static const uint8_t gDeltaIterlaceYValue[] = {
37    8, 8, 4, 2
38};
39
40SK_CONF_DECLARE(bool, c_suppressGIFImageDecoderWarnings,
41                "images.gif.suppressDecoderWarnings", true,
42                "Suppress GIF warnings and errors when calling image decode "
43                "functions.");
44
45
46/*  Implement the GIF interlace algorithm in an iterator.
47    1) grab every 8th line beginning at 0
48    2) grab every 8th line beginning at 4
49    3) grab every 4th line beginning at 2
50    4) grab every 2nd line beginning at 1
51*/
52class GifInterlaceIter {
53public:
54    GifInterlaceIter(int height) : fHeight(height) {
55        fStartYPtr = gStartingIterlaceYValue;
56        fDeltaYPtr = gDeltaIterlaceYValue;
57
58        fCurrY = *fStartYPtr++;
59        fDeltaY = *fDeltaYPtr++;
60    }
61
62    int currY() const {
63        SkASSERT(fStartYPtr);
64        SkASSERT(fDeltaYPtr);
65        return fCurrY;
66    }
67
68    void next() {
69        SkASSERT(fStartYPtr);
70        SkASSERT(fDeltaYPtr);
71
72        int y = fCurrY + fDeltaY;
73        // We went from an if statement to a while loop so that we iterate
74        // through fStartYPtr until a valid row is found. This is so that images
75        // that are smaller than 5x5 will not trash memory.
76        while (y >= fHeight) {
77            if (gStartingIterlaceYValue +
78                    SK_ARRAY_COUNT(gStartingIterlaceYValue) == fStartYPtr) {
79                // we done
80                SkDEBUGCODE(fStartYPtr = NULL;)
81                SkDEBUGCODE(fDeltaYPtr = NULL;)
82                y = 0;
83            } else {
84                y = *fStartYPtr++;
85                fDeltaY = *fDeltaYPtr++;
86            }
87        }
88        fCurrY = y;
89    }
90
91private:
92    const int fHeight;
93    int fCurrY;
94    int fDeltaY;
95    const uint8_t* fStartYPtr;
96    const uint8_t* fDeltaYPtr;
97};
98
99///////////////////////////////////////////////////////////////////////////////
100
101static int DecodeCallBackProc(GifFileType* fileType, GifByteType* out,
102                              int size) {
103    SkStream* stream = (SkStream*) fileType->UserData;
104    return (int) stream->read(out, size);
105}
106
107void CheckFreeExtension(SavedImage* Image) {
108    if (Image->ExtensionBlocks) {
109#if GIFLIB_MAJOR < 5
110        FreeExtension(Image);
111#else
112        GifFreeExtensions(&Image->ExtensionBlockCount, &Image->ExtensionBlocks);
113#endif
114    }
115}
116
117// return NULL on failure
118static const ColorMapObject* find_colormap(const GifFileType* gif) {
119    const ColorMapObject* cmap = gif->Image.ColorMap;
120    if (NULL == cmap) {
121        cmap = gif->SColorMap;
122    }
123
124    if (NULL == cmap) {
125        // no colormap found
126        return NULL;
127    }
128    // some sanity checks
129    if (cmap && ((unsigned)cmap->ColorCount > 256 ||
130                 cmap->ColorCount != (1 << cmap->BitsPerPixel))) {
131        cmap = NULL;
132    }
133    return cmap;
134}
135
136// return -1 if not found (i.e. we're completely opaque)
137static int find_transpIndex(const SavedImage& image, int colorCount) {
138    int transpIndex = -1;
139    for (int i = 0; i < image.ExtensionBlockCount; ++i) {
140        const ExtensionBlock* eb = image.ExtensionBlocks + i;
141        if (eb->Function == 0xF9 && eb->ByteCount == 4) {
142            if (eb->Bytes[0] & 1) {
143                transpIndex = (unsigned char)eb->Bytes[3];
144                // check for valid transpIndex
145                if (transpIndex >= colorCount) {
146                    transpIndex = -1;
147                }
148                break;
149            }
150        }
151    }
152    return transpIndex;
153}
154
155static bool error_return(const SkBitmap& bm, const char msg[]) {
156    if (!c_suppressGIFImageDecoderWarnings) {
157        SkDebugf("libgif error [%s] bitmap [%d %d] pixels %p colortable %p\n",
158                 msg, bm.width(), bm.height(), bm.getPixels(),
159                 bm.getColorTable());
160    }
161    return false;
162}
163static void gif_warning(const SkBitmap& bm, const char msg[]) {
164    if (!c_suppressGIFImageDecoderWarnings) {
165        SkDebugf("libgif warning [%s] bitmap [%d %d] pixels %p colortable %p\n",
166                 msg, bm.width(), bm.height(), bm.getPixels(),
167                 bm.getColorTable());
168    }
169}
170
171/**
172 *  Skip rows in the source gif image.
173 *  @param gif Source image.
174 *  @param dst Scratch output needed by gif library call. Must be >= width bytes.
175 *  @param width Bytes per row in the source image.
176 *  @param rowsToSkip Number of rows to skip.
177 *  @return True on success, false on GIF_ERROR.
178 */
179static bool skip_src_rows(GifFileType* gif, uint8_t* dst, int width, int rowsToSkip) {
180    for (int i = 0; i < rowsToSkip; i++) {
181        if (DGifGetLine(gif, dst, width) == GIF_ERROR) {
182            return false;
183        }
184    }
185    return true;
186}
187
188/**
189 *  GIFs with fewer then 256 color entries will sometimes index out of
190 *  bounds of the color table (this is malformed, but libgif does not
191 *  check sicne it is rare).  This function checks for this error and
192 *  fixes it.  This makes the output image consistantly deterministic.
193 */
194static void sanitize_indexed_bitmap(SkBitmap* bm) {
195    if ((SkBitmap::kIndex8_Config == bm->config()) && !(bm->empty())) {
196        SkAutoLockPixels alp(*bm);
197        if (NULL != bm->getPixels()) {
198            SkColorTable* ct = bm->getColorTable();  // Index8 must have it.
199            SkASSERT(ct != NULL);
200            uint32_t count = ct->count();
201            SkASSERT(count > 0);
202            SkASSERT(count <= 0x100);
203            if (count != 0x100) {  // Full colortables can't go wrong.
204                // Count is a power of 2; asserted elsewhere.
205                uint8_t byteMask = (~(count - 1));
206                bool warning = false;
207                uint8_t* addr = static_cast<uint8_t*>(bm->getPixels());
208                int height = bm->height();
209                int width = bm->width();
210                size_t rowBytes = bm->rowBytes();
211                while (--height >= 0) {
212                    uint8_t* ptr = addr;
213                    int x = width;
214                    while (--x >= 0) {
215                        if (0 != ((*ptr) & byteMask)) {
216                            warning = true;
217                            *ptr = 0;
218                        }
219                        ++ptr;
220                    }
221                    addr += rowBytes;
222                }
223                if (warning) {
224                    gif_warning(*bm, "Index out of bounds.");
225                }
226            }
227        }
228    }
229}
230
231bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) {
232#if GIFLIB_MAJOR < 5
233    GifFileType* gif = DGifOpen(sk_stream, DecodeCallBackProc);
234#else
235    GifFileType* gif = DGifOpen(sk_stream, DecodeCallBackProc, NULL);
236#endif
237    if (NULL == gif) {
238        return error_return(*bm, "DGifOpen");
239    }
240
241    SkAutoTCallIProc<GifFileType, DGifCloseFile> acp(gif);
242
243    SavedImage temp_save;
244    temp_save.ExtensionBlocks=NULL;
245    temp_save.ExtensionBlockCount=0;
246    SkAutoTCallVProc<SavedImage, CheckFreeExtension> acp2(&temp_save);
247
248    int width, height;
249    GifRecordType recType;
250    GifByteType *extData;
251#if GIFLIB_MAJOR >= 5
252    int extFunction;
253#endif
254    int transpIndex = -1;   // -1 means we don't have it (yet)
255    int fillIndex = gif->SBackGroundColor;
256
257    do {
258        if (DGifGetRecordType(gif, &recType) == GIF_ERROR) {
259            return error_return(*bm, "DGifGetRecordType");
260        }
261
262        switch (recType) {
263        case IMAGE_DESC_RECORD_TYPE: {
264            if (DGifGetImageDesc(gif) == GIF_ERROR) {
265                return error_return(*bm, "IMAGE_DESC_RECORD_TYPE");
266            }
267
268            if (gif->ImageCount < 1) {    // sanity check
269                return error_return(*bm, "ImageCount < 1");
270            }
271
272            width = gif->SWidth;
273            height = gif->SHeight;
274
275            SavedImage* image = &gif->SavedImages[gif->ImageCount-1];
276            const GifImageDesc& desc = image->ImageDesc;
277
278            int imageLeft = desc.Left;
279            int imageTop = desc.Top;
280            const int innerWidth = desc.Width;
281            const int innerHeight = desc.Height;
282            if (innerWidth <= 0 || innerHeight <= 0) {
283                return error_return(*bm, "invalid dimensions");
284            }
285
286            // check for valid descriptor
287            if (innerWidth > width) {
288                gif_warning(*bm, "image too wide, expanding output to size");
289                width = innerWidth;
290                imageLeft = 0;
291            } else if (imageLeft + innerWidth > width) {
292                gif_warning(*bm, "shifting image left to fit");
293                imageLeft = width - innerWidth;
294            } else if (imageLeft < 0) {
295                gif_warning(*bm, "shifting image right to fit");
296                imageLeft = 0;
297            }
298
299
300            if (innerHeight > height) {
301                gif_warning(*bm, "image too tall,  expanding output to size");
302                height = innerHeight;
303                imageTop = 0;
304            } else if (imageTop + innerHeight > height) {
305                gif_warning(*bm, "shifting image up to fit");
306                imageTop = height - innerHeight;
307            } else if (imageTop < 0) {
308                gif_warning(*bm, "shifting image down to fit");
309                imageTop = 0;
310            }
311
312            // FIXME: We could give the caller a choice of images or configs.
313            if (!this->chooseFromOneChoice(kIndex_8_SkColorType, width, height)) {
314                return error_return(*bm, "chooseFromOneChoice");
315            }
316
317            SkScaledBitmapSampler sampler(width, height, this->getSampleSize());
318
319            bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(),
320                                          kIndex_8_SkColorType, kPremul_SkAlphaType));
321
322            if (SkImageDecoder::kDecodeBounds_Mode == mode) {
323                return true;
324            }
325
326
327            // now we decode the colortable
328            int colorCount = 0;
329            {
330                // Declare colorPtr here for scope.
331                SkPMColor colorPtr[256]; // storage for worst-case
332                const ColorMapObject* cmap = find_colormap(gif);
333                SkAlphaType alphaType = kOpaque_SkAlphaType;
334                if (cmap != NULL) {
335                    SkASSERT(cmap->ColorCount == (1 << (cmap->BitsPerPixel)));
336                    colorCount = cmap->ColorCount;
337                    if (colorCount > 256) {
338                        colorCount = 256;  // our kIndex8 can't support more
339                    }
340                    for (int index = 0; index < colorCount; index++) {
341                        colorPtr[index] = SkPackARGB32(0xFF,
342                                                       cmap->Colors[index].Red,
343                                                       cmap->Colors[index].Green,
344                                                       cmap->Colors[index].Blue);
345                    }
346                } else {
347                    // find_colormap() returned NULL.  Some (rare, broken)
348                    // GIFs don't have a color table, so we force one.
349                    gif_warning(*bm, "missing colormap");
350                    colorCount = 256;
351                    sk_memset32(colorPtr, SK_ColorWHITE, colorCount);
352                }
353                transpIndex = find_transpIndex(temp_save, colorCount);
354                if (transpIndex >= 0) {
355                    colorPtr[transpIndex] = SK_ColorTRANSPARENT; // ram in a transparent SkPMColor
356                    alphaType = kPremul_SkAlphaType;
357                    fillIndex = transpIndex;
358                } else if (fillIndex >= colorCount) {
359                    // gif->SBackGroundColor should be less than colorCount.
360                    fillIndex = 0;  // If not, fix it.
361                }
362
363                SkAutoTUnref<SkColorTable> ctable(SkNEW_ARGS(SkColorTable,
364                                                  (colorPtr, colorCount,
365                                                   alphaType)));
366                if (!this->allocPixelRef(bm, ctable)) {
367                    return error_return(*bm, "allocPixelRef");
368                }
369            }
370
371            // abort if either inner dimension is <= 0
372            if (innerWidth <= 0 || innerHeight <= 0) {
373                return error_return(*bm, "non-pos inner width/height");
374            }
375
376            SkAutoLockPixels alp(*bm);
377
378            SkAutoMalloc storage(innerWidth);
379            uint8_t* scanline = (uint8_t*) storage.get();
380
381            // GIF has an option to store the scanlines of an image, plus a larger background,
382            // filled by a fill color. In this case, we will use a subset of the larger bitmap
383            // for sampling.
384            SkBitmap subset;
385            SkBitmap* workingBitmap;
386            // are we only a subset of the total bounds?
387            if ((imageTop | imageLeft) > 0 ||
388                 innerWidth < width || innerHeight < height) {
389                // Fill the background.
390                memset(bm->getPixels(), fillIndex, bm->getSize());
391
392                // Create a subset of the bitmap.
393                SkIRect subsetRect(SkIRect::MakeXYWH(imageLeft / sampler.srcDX(),
394                                                     imageTop / sampler.srcDY(),
395                                                     innerWidth / sampler.srcDX(),
396                                                     innerHeight / sampler.srcDY()));
397                if (!bm->extractSubset(&subset, subsetRect)) {
398                    return error_return(*bm, "Extract failed.");
399                }
400                // Update the sampler. We'll now be only sampling into the subset.
401                sampler = SkScaledBitmapSampler(innerWidth, innerHeight, this->getSampleSize());
402                workingBitmap = &subset;
403            } else {
404                workingBitmap = bm;
405            }
406
407            // bm is already locked, but if we had to take a subset, it must be locked also,
408            // so that getPixels() will point to its pixels.
409            SkAutoLockPixels alpWorking(*workingBitmap);
410
411            if (!sampler.begin(workingBitmap, SkScaledBitmapSampler::kIndex, *this)) {
412                return error_return(*bm, "Sampler failed to begin.");
413            }
414
415            // now decode each scanline
416            if (gif->Image.Interlace) {
417                // Iterate over the height of the source data. The sampler will
418                // take care of skipping unneeded rows.
419                GifInterlaceIter iter(innerHeight);
420                for (int y = 0; y < innerHeight; y++) {
421                    if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) {
422                        gif_warning(*bm, "interlace DGifGetLine");
423                        memset(scanline, fillIndex, innerWidth);
424                        for (; y < innerHeight; y++) {
425                            sampler.sampleInterlaced(scanline, iter.currY());
426                            iter.next();
427                        }
428                        return true;
429                    }
430                    sampler.sampleInterlaced(scanline, iter.currY());
431                    iter.next();
432                }
433            } else {
434                // easy, non-interlace case
435                const int outHeight = workingBitmap->height();
436                skip_src_rows(gif, scanline, innerWidth, sampler.srcY0());
437                for (int y = 0; y < outHeight; y++) {
438                    if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) {
439                        gif_warning(*bm, "DGifGetLine");
440                        memset(scanline, fillIndex, innerWidth);
441                        for (; y < outHeight; y++) {
442                            sampler.next(scanline);
443                        }
444                        return true;
445                    }
446                    // scanline now contains the raw data. Sample it.
447                    sampler.next(scanline);
448                    if (y < outHeight - 1) {
449                        skip_src_rows(gif, scanline, innerWidth, sampler.srcDY() - 1);
450                    }
451                }
452                // skip the rest of the rows (if any)
453                int read = (outHeight - 1) * sampler.srcDY() + sampler.srcY0() + 1;
454                SkASSERT(read <= innerHeight);
455                skip_src_rows(gif, scanline, innerWidth, innerHeight - read);
456            }
457            sanitize_indexed_bitmap(bm);
458            return true;
459            } break;
460
461        case EXTENSION_RECORD_TYPE:
462#if GIFLIB_MAJOR < 5
463            if (DGifGetExtension(gif, &temp_save.Function,
464                                 &extData) == GIF_ERROR) {
465#else
466            if (DGifGetExtension(gif, &extFunction, &extData) == GIF_ERROR) {
467#endif
468                return error_return(*bm, "DGifGetExtension");
469            }
470
471            while (extData != NULL) {
472                /* Create an extension block with our data */
473#if GIFLIB_MAJOR < 5
474                if (AddExtensionBlock(&temp_save, extData[0],
475                                      &extData[1]) == GIF_ERROR) {
476#else
477                if (GifAddExtensionBlock(&gif->ExtensionBlockCount,
478                                         &gif->ExtensionBlocks,
479                                         extFunction,
480                                         extData[0],
481                                         &extData[1]) == GIF_ERROR) {
482#endif
483                    return error_return(*bm, "AddExtensionBlock");
484                }
485                if (DGifGetExtensionNext(gif, &extData) == GIF_ERROR) {
486                    return error_return(*bm, "DGifGetExtensionNext");
487                }
488#if GIFLIB_MAJOR < 5
489                temp_save.Function = 0;
490#endif
491            }
492            break;
493
494        case TERMINATE_RECORD_TYPE:
495            break;
496
497        default:    /* Should be trapped by DGifGetRecordType */
498            break;
499        }
500    } while (recType != TERMINATE_RECORD_TYPE);
501
502    sanitize_indexed_bitmap(bm);
503    return true;
504}
505
506///////////////////////////////////////////////////////////////////////////////
507DEFINE_DECODER_CREATOR(GIFImageDecoder);
508///////////////////////////////////////////////////////////////////////////////
509
510static bool is_gif(SkStreamRewindable* stream) {
511    char buf[GIF_STAMP_LEN];
512    if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN) {
513        if (memcmp(GIF_STAMP,   buf, GIF_STAMP_LEN) == 0 ||
514                memcmp(GIF87_STAMP, buf, GIF_STAMP_LEN) == 0 ||
515                memcmp(GIF89_STAMP, buf, GIF_STAMP_LEN) == 0) {
516            return true;
517        }
518    }
519    return false;
520}
521
522static SkImageDecoder* sk_libgif_dfactory(SkStreamRewindable* stream) {
523    if (is_gif(stream)) {
524        return SkNEW(SkGIFImageDecoder);
525    }
526    return NULL;
527}
528
529static SkImageDecoder_DecodeReg gReg(sk_libgif_dfactory);
530
531static SkImageDecoder::Format get_format_gif(SkStreamRewindable* stream) {
532    if (is_gif(stream)) {
533        return SkImageDecoder::kGIF_Format;
534    }
535    return SkImageDecoder::kUnknown_Format;
536}
537
538static SkImageDecoder_FormatReg gFormatReg(get_format_gif);
539