SkImageDecoder_libgif.cpp revision c5e15a1afab2621e860a251c3fcf5917867ad49f
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 ((kIndex_8_SkColorType == bm->colorType()) && !(bm->empty())) {
196        SkAutoLockPixels alp(*bm);
197        if (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#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
313            // FIXME: We could give the caller a choice of images or configs.
314            if (!this->chooseFromOneChoice(kIndex_8_SkColorType, width, height)) {
315                return error_return(*bm, "chooseFromOneChoice");
316            }
317#endif
318
319            SkScaledBitmapSampler sampler(width, height, this->getSampleSize());
320
321            bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(),
322                                          kIndex_8_SkColorType, kPremul_SkAlphaType));
323
324            if (SkImageDecoder::kDecodeBounds_Mode == mode) {
325                return true;
326            }
327
328
329            // now we decode the colortable
330            int colorCount = 0;
331            {
332                // Declare colorPtr here for scope.
333                SkPMColor colorPtr[256]; // storage for worst-case
334                const ColorMapObject* cmap = find_colormap(gif);
335                if (cmap != NULL) {
336                    SkASSERT(cmap->ColorCount == (1 << (cmap->BitsPerPixel)));
337                    colorCount = cmap->ColorCount;
338                    if (colorCount > 256) {
339                        colorCount = 256;  // our kIndex8 can't support more
340                    }
341                    for (int index = 0; index < colorCount; index++) {
342                        colorPtr[index] = SkPackARGB32(0xFF,
343                                                       cmap->Colors[index].Red,
344                                                       cmap->Colors[index].Green,
345                                                       cmap->Colors[index].Blue);
346                    }
347                } else {
348                    // find_colormap() returned NULL.  Some (rare, broken)
349                    // GIFs don't have a color table, so we force one.
350                    gif_warning(*bm, "missing colormap");
351                    colorCount = 256;
352                    sk_memset32(colorPtr, SK_ColorWHITE, colorCount);
353                }
354                transpIndex = find_transpIndex(temp_save, colorCount);
355                if (transpIndex >= 0) {
356                    colorPtr[transpIndex] = SK_ColorTRANSPARENT; // ram in a transparent SkPMColor
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, (colorPtr, colorCount)));
364                if (!this->allocPixelRef(bm, ctable)) {
365                    return error_return(*bm, "allocPixelRef");
366                }
367            }
368
369            // abort if either inner dimension is <= 0
370            if (innerWidth <= 0 || innerHeight <= 0) {
371                return error_return(*bm, "non-pos inner width/height");
372            }
373
374            SkAutoLockPixels alp(*bm);
375
376            SkAutoMalloc storage(innerWidth);
377            uint8_t* scanline = (uint8_t*) storage.get();
378
379            // GIF has an option to store the scanlines of an image, plus a larger background,
380            // filled by a fill color. In this case, we will use a subset of the larger bitmap
381            // for sampling.
382            SkBitmap subset;
383            SkBitmap* workingBitmap;
384            // are we only a subset of the total bounds?
385            if ((imageTop | imageLeft) > 0 ||
386                 innerWidth < width || innerHeight < height) {
387                // Fill the background.
388                memset(bm->getPixels(), fillIndex, bm->getSize());
389
390                // Create a subset of the bitmap.
391                SkIRect subsetRect(SkIRect::MakeXYWH(imageLeft / sampler.srcDX(),
392                                                     imageTop / sampler.srcDY(),
393                                                     innerWidth / sampler.srcDX(),
394                                                     innerHeight / sampler.srcDY()));
395                if (!bm->extractSubset(&subset, subsetRect)) {
396                    return error_return(*bm, "Extract failed.");
397                }
398                // Update the sampler. We'll now be only sampling into the subset.
399                sampler = SkScaledBitmapSampler(innerWidth, innerHeight, this->getSampleSize());
400                workingBitmap = &subset;
401            } else {
402                workingBitmap = bm;
403            }
404
405            // bm is already locked, but if we had to take a subset, it must be locked also,
406            // so that getPixels() will point to its pixels.
407            SkAutoLockPixels alpWorking(*workingBitmap);
408
409            if (!sampler.begin(workingBitmap, SkScaledBitmapSampler::kIndex, *this)) {
410                return error_return(*bm, "Sampler failed to begin.");
411            }
412
413            // now decode each scanline
414            if (gif->Image.Interlace) {
415                // Iterate over the height of the source data. The sampler will
416                // take care of skipping unneeded rows.
417                GifInterlaceIter iter(innerHeight);
418                for (int y = 0; y < innerHeight; y++) {
419                    if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) {
420                        gif_warning(*bm, "interlace DGifGetLine");
421                        memset(scanline, fillIndex, innerWidth);
422                        for (; y < innerHeight; y++) {
423                            sampler.sampleInterlaced(scanline, iter.currY());
424                            iter.next();
425                        }
426                        return true;
427                    }
428                    sampler.sampleInterlaced(scanline, iter.currY());
429                    iter.next();
430                }
431            } else {
432                // easy, non-interlace case
433                const int outHeight = workingBitmap->height();
434                skip_src_rows(gif, scanline, innerWidth, sampler.srcY0());
435                for (int y = 0; y < outHeight; y++) {
436                    if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) {
437                        gif_warning(*bm, "DGifGetLine");
438                        memset(scanline, fillIndex, innerWidth);
439                        for (; y < outHeight; y++) {
440                            sampler.next(scanline);
441                        }
442                        return true;
443                    }
444                    // scanline now contains the raw data. Sample it.
445                    sampler.next(scanline);
446                    if (y < outHeight - 1) {
447                        skip_src_rows(gif, scanline, innerWidth, sampler.srcDY() - 1);
448                    }
449                }
450                // skip the rest of the rows (if any)
451                int read = (outHeight - 1) * sampler.srcDY() + sampler.srcY0() + 1;
452                SkASSERT(read <= innerHeight);
453                skip_src_rows(gif, scanline, innerWidth, innerHeight - read);
454            }
455            sanitize_indexed_bitmap(bm);
456            return true;
457            } break;
458
459        case EXTENSION_RECORD_TYPE:
460#if GIFLIB_MAJOR < 5
461            if (DGifGetExtension(gif, &temp_save.Function,
462                                 &extData) == GIF_ERROR) {
463#else
464            if (DGifGetExtension(gif, &extFunction, &extData) == GIF_ERROR) {
465#endif
466                return error_return(*bm, "DGifGetExtension");
467            }
468
469            while (extData != NULL) {
470                /* Create an extension block with our data */
471#if GIFLIB_MAJOR < 5
472                if (AddExtensionBlock(&temp_save, extData[0],
473                                      &extData[1]) == GIF_ERROR) {
474#else
475                if (GifAddExtensionBlock(&gif->ExtensionBlockCount,
476                                         &gif->ExtensionBlocks,
477                                         extFunction,
478                                         extData[0],
479                                         &extData[1]) == GIF_ERROR) {
480#endif
481                    return error_return(*bm, "AddExtensionBlock");
482                }
483                if (DGifGetExtensionNext(gif, &extData) == GIF_ERROR) {
484                    return error_return(*bm, "DGifGetExtensionNext");
485                }
486#if GIFLIB_MAJOR < 5
487                temp_save.Function = 0;
488#endif
489            }
490            break;
491
492        case TERMINATE_RECORD_TYPE:
493            break;
494
495        default:    /* Should be trapped by DGifGetRecordType */
496            break;
497        }
498    } while (recType != TERMINATE_RECORD_TYPE);
499
500    sanitize_indexed_bitmap(bm);
501    return true;
502}
503
504///////////////////////////////////////////////////////////////////////////////
505DEFINE_DECODER_CREATOR(GIFImageDecoder);
506///////////////////////////////////////////////////////////////////////////////
507
508static bool is_gif(SkStreamRewindable* stream) {
509    char buf[GIF_STAMP_LEN];
510    if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN) {
511        if (memcmp(GIF_STAMP,   buf, GIF_STAMP_LEN) == 0 ||
512                memcmp(GIF87_STAMP, buf, GIF_STAMP_LEN) == 0 ||
513                memcmp(GIF89_STAMP, buf, GIF_STAMP_LEN) == 0) {
514            return true;
515        }
516    }
517    return false;
518}
519
520static SkImageDecoder* sk_libgif_dfactory(SkStreamRewindable* stream) {
521    if (is_gif(stream)) {
522        return SkNEW(SkGIFImageDecoder);
523    }
524    return NULL;
525}
526
527static SkImageDecoder_DecodeReg gReg(sk_libgif_dfactory);
528
529static SkImageDecoder::Format get_format_gif(SkStreamRewindable* stream) {
530    if (is_gif(stream)) {
531        return SkImageDecoder::kGIF_Format;
532    }
533    return SkImageDecoder::kUnknown_Format;
534}
535
536static SkImageDecoder_FormatReg gFormatReg(get_format_gif);
537