Home | History | Annotate | Download | only in images
      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 
     20 class SkGIFImageDecoder : public SkImageDecoder {
     21 public:
     22     virtual Format getFormat() const SK_OVERRIDE {
     23         return kGIF_Format;
     24     }
     25 
     26 protected:
     27     virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRIDE;
     28 
     29 private:
     30     typedef SkImageDecoder INHERITED;
     31 };
     32 
     33 static const uint8_t gStartingIterlaceYValue[] = {
     34     0, 4, 2, 1
     35 };
     36 static const uint8_t gDeltaIterlaceYValue[] = {
     37     8, 8, 4, 2
     38 };
     39 
     40 SK_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 */
     52 class GifInterlaceIter {
     53 public:
     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 
     91 private:
     92     const int fHeight;
     93     int fCurrY;
     94     int fDeltaY;
     95     const uint8_t* fStartYPtr;
     96     const uint8_t* fDeltaYPtr;
     97 };
     98 
     99 ///////////////////////////////////////////////////////////////////////////////
    100 
    101 static int DecodeCallBackProc(GifFileType* fileType, GifByteType* out,
    102                               int size) {
    103     SkStream* stream = (SkStream*) fileType->UserData;
    104     return (int) stream->read(out, size);
    105 }
    106 
    107 void 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
    118 static 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)
    137 static 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 
    155 static 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 }
    163 static 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  */
    179 static 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 bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) {
    189 #if GIFLIB_MAJOR < 5
    190     GifFileType* gif = DGifOpen(sk_stream, DecodeCallBackProc);
    191 #else
    192     GifFileType* gif = DGifOpen(sk_stream, DecodeCallBackProc, NULL);
    193 #endif
    194     if (NULL == gif) {
    195         return error_return(*bm, "DGifOpen");
    196     }
    197 
    198     SkAutoTCallIProc<GifFileType, DGifCloseFile> acp(gif);
    199 
    200     SavedImage temp_save;
    201     temp_save.ExtensionBlocks=NULL;
    202     temp_save.ExtensionBlockCount=0;
    203     SkAutoTCallVProc<SavedImage, CheckFreeExtension> acp2(&temp_save);
    204 
    205     int width, height;
    206     GifRecordType recType;
    207     GifByteType *extData;
    208 #if GIFLIB_MAJOR >= 5
    209     int extFunction;
    210 #endif
    211     int transpIndex = -1;   // -1 means we don't have it (yet)
    212     int fillIndex = gif->SBackGroundColor;
    213 
    214     do {
    215         if (DGifGetRecordType(gif, &recType) == GIF_ERROR) {
    216             return error_return(*bm, "DGifGetRecordType");
    217         }
    218 
    219         switch (recType) {
    220         case IMAGE_DESC_RECORD_TYPE: {
    221             if (DGifGetImageDesc(gif) == GIF_ERROR) {
    222                 return error_return(*bm, "IMAGE_DESC_RECORD_TYPE");
    223             }
    224 
    225             if (gif->ImageCount < 1) {    // sanity check
    226                 return error_return(*bm, "ImageCount < 1");
    227             }
    228 
    229             width = gif->SWidth;
    230             height = gif->SHeight;
    231 
    232             SavedImage* image = &gif->SavedImages[gif->ImageCount-1];
    233             const GifImageDesc& desc = image->ImageDesc;
    234 
    235             int imageLeft = desc.Left;
    236             int imageTop = desc.Top;
    237             const int innerWidth = desc.Width;
    238             const int innerHeight = desc.Height;
    239             if (innerWidth <= 0 || innerHeight <= 0) {
    240                 return error_return(*bm, "invalid dimensions");
    241             }
    242 
    243             // check for valid descriptor
    244             if (innerWidth > width) {
    245                 gif_warning(*bm, "image too wide, expanding output to size");
    246                 width = innerWidth;
    247                 imageLeft = 0;
    248             } else if (imageLeft + innerWidth > width) {
    249                 gif_warning(*bm, "shifting image left to fit");
    250                 imageLeft = width - innerWidth;
    251             } else if (imageLeft < 0) {
    252                 gif_warning(*bm, "shifting image right to fit");
    253                 imageLeft = 0;
    254             }
    255 
    256 
    257             if (innerHeight > height) {
    258                 gif_warning(*bm, "image too tall,  expanding output to size");
    259                 height = innerHeight;
    260                 imageTop = 0;
    261             } else if (imageTop + innerHeight > height) {
    262                 gif_warning(*bm, "shifting image up to fit");
    263                 imageTop = height - innerHeight;
    264             } else if (imageTop < 0) {
    265                 gif_warning(*bm, "shifting image down to fit");
    266                 imageTop = 0;
    267             }
    268 
    269             // FIXME: We could give the caller a choice of images or configs.
    270             if (!this->chooseFromOneChoice(SkBitmap::kIndex8_Config, width, height)) {
    271                 return error_return(*bm, "chooseFromOneChoice");
    272             }
    273 
    274             SkScaledBitmapSampler sampler(width, height, this->getSampleSize());
    275 
    276             bm->setConfig(SkBitmap::kIndex8_Config, sampler.scaledWidth(),
    277                           sampler.scaledHeight());
    278 
    279             if (SkImageDecoder::kDecodeBounds_Mode == mode) {
    280                 return true;
    281             }
    282 
    283 
    284             // now we decode the colortable
    285             int colorCount = 0;
    286             {
    287                 // Declare colorPtr here for scope.
    288                 SkPMColor colorPtr[256]; // storage for worst-case
    289                 const ColorMapObject* cmap = find_colormap(gif);
    290                 SkAlphaType alphaType = kOpaque_SkAlphaType;
    291                 if (cmap != NULL) {
    292                     colorCount = cmap->ColorCount;
    293                     if (colorCount > 256) {
    294                         colorCount = 256;  // our kIndex8 can't support more
    295                     }
    296                     for (int index = 0; index < colorCount; index++) {
    297                         colorPtr[index] = SkPackARGB32(0xFF,
    298                                                        cmap->Colors[index].Red,
    299                                                        cmap->Colors[index].Green,
    300                                                        cmap->Colors[index].Blue);
    301                     }
    302                 } else {
    303                     // find_colormap() returned NULL.  Some (rare, broken)
    304                     // GIFs don't have a color table, so we force one.
    305                     gif_warning(*bm, "missing colormap");
    306                     colorCount = 256;
    307                     sk_memset32(colorPtr, SK_ColorWHITE, colorCount);
    308                 }
    309                 transpIndex = find_transpIndex(temp_save, colorCount);
    310                 if (transpIndex >= 0) {
    311                     colorPtr[transpIndex] = SK_ColorTRANSPARENT; // ram in a transparent SkPMColor
    312                     alphaType = kPremul_SkAlphaType;
    313                     fillIndex = transpIndex;
    314                 } else if (fillIndex >= colorCount) {
    315                     // gif->SBackGroundColor should be less than colorCount.
    316                     fillIndex = 0;  // If not, fix it.
    317                 }
    318 
    319                 SkAutoTUnref<SkColorTable> ctable(SkNEW_ARGS(SkColorTable,
    320                                                   (colorPtr, colorCount,
    321                                                    alphaType)));
    322                 if (!this->allocPixelRef(bm, ctable)) {
    323                     return error_return(*bm, "allocPixelRef");
    324                 }
    325             }
    326 
    327             // abort if either inner dimension is <= 0
    328             if (innerWidth <= 0 || innerHeight <= 0) {
    329                 return error_return(*bm, "non-pos inner width/height");
    330             }
    331 
    332             SkAutoLockPixels alp(*bm);
    333 
    334             SkAutoMalloc storage(innerWidth);
    335             uint8_t* scanline = (uint8_t*) storage.get();
    336 
    337             // GIF has an option to store the scanlines of an image, plus a larger background,
    338             // filled by a fill color. In this case, we will use a subset of the larger bitmap
    339             // for sampling.
    340             SkBitmap subset;
    341             SkBitmap* workingBitmap;
    342             // are we only a subset of the total bounds?
    343             if ((imageTop | imageLeft) > 0 ||
    344                  innerWidth < width || innerHeight < height) {
    345                 // Fill the background.
    346                 memset(bm->getPixels(), fillIndex, bm->getSize());
    347 
    348                 // Create a subset of the bitmap.
    349                 SkIRect subsetRect(SkIRect::MakeXYWH(imageLeft / sampler.srcDX(),
    350                                                      imageTop / sampler.srcDY(),
    351                                                      innerWidth / sampler.srcDX(),
    352                                                      innerHeight / sampler.srcDY()));
    353                 if (!bm->extractSubset(&subset, subsetRect)) {
    354                     return error_return(*bm, "Extract failed.");
    355                 }
    356                 // Update the sampler. We'll now be only sampling into the subset.
    357                 sampler = SkScaledBitmapSampler(innerWidth, innerHeight, this->getSampleSize());
    358                 workingBitmap = &subset;
    359             } else {
    360                 workingBitmap = bm;
    361             }
    362 
    363             // bm is already locked, but if we had to take a subset, it must be locked also,
    364             // so that getPixels() will point to its pixels.
    365             SkAutoLockPixels alpWorking(*workingBitmap);
    366 
    367             if (!sampler.begin(workingBitmap, SkScaledBitmapSampler::kIndex, *this)) {
    368                 return error_return(*bm, "Sampler failed to begin.");
    369             }
    370 
    371             // now decode each scanline
    372             if (gif->Image.Interlace) {
    373                 // Iterate over the height of the source data. The sampler will
    374                 // take care of skipping unneeded rows.
    375                 GifInterlaceIter iter(innerHeight);
    376                 for (int y = 0; y < innerHeight; y++) {
    377                     if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) {
    378                         gif_warning(*bm, "interlace DGifGetLine");
    379                         memset(scanline, fillIndex, innerWidth);
    380                         for (; y < innerHeight; y++) {
    381                             sampler.sampleInterlaced(scanline, iter.currY());
    382                             iter.next();
    383                         }
    384                         return true;
    385                     }
    386                     sampler.sampleInterlaced(scanline, iter.currY());
    387                     iter.next();
    388                 }
    389             } else {
    390                 // easy, non-interlace case
    391                 const int outHeight = workingBitmap->height();
    392                 skip_src_rows(gif, scanline, innerWidth, sampler.srcY0());
    393                 for (int y = 0; y < outHeight; y++) {
    394                     if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) {
    395                         gif_warning(*bm, "DGifGetLine");
    396                         memset(scanline, fillIndex, innerWidth);
    397                         for (; y < outHeight; y++) {
    398                             sampler.next(scanline);
    399                         }
    400                         return true;
    401                     }
    402                     // scanline now contains the raw data. Sample it.
    403                     sampler.next(scanline);
    404                     if (y < outHeight - 1) {
    405                         skip_src_rows(gif, scanline, innerWidth, sampler.srcDY() - 1);
    406                     }
    407                 }
    408                 // skip the rest of the rows (if any)
    409                 int read = (outHeight - 1) * sampler.srcDY() + sampler.srcY0() + 1;
    410                 SkASSERT(read <= innerHeight);
    411                 skip_src_rows(gif, scanline, innerWidth, innerHeight - read);
    412             }
    413             return true;
    414             } break;
    415 
    416         case EXTENSION_RECORD_TYPE:
    417 #if GIFLIB_MAJOR < 5
    418             if (DGifGetExtension(gif, &temp_save.Function,
    419                                  &extData) == GIF_ERROR) {
    420 #else
    421             if (DGifGetExtension(gif, &extFunction, &extData) == GIF_ERROR) {
    422 #endif
    423                 return error_return(*bm, "DGifGetExtension");
    424             }
    425 
    426             while (extData != NULL) {
    427                 /* Create an extension block with our data */
    428 #if GIFLIB_MAJOR < 5
    429                 if (AddExtensionBlock(&temp_save, extData[0],
    430                                       &extData[1]) == GIF_ERROR) {
    431 #else
    432                 if (GifAddExtensionBlock(&gif->ExtensionBlockCount,
    433                                          &gif->ExtensionBlocks,
    434                                          extFunction,
    435                                          extData[0],
    436                                          &extData[1]) == GIF_ERROR) {
    437 #endif
    438                     return error_return(*bm, "AddExtensionBlock");
    439                 }
    440                 if (DGifGetExtensionNext(gif, &extData) == GIF_ERROR) {
    441                     return error_return(*bm, "DGifGetExtensionNext");
    442                 }
    443 #if GIFLIB_MAJOR < 5
    444                 temp_save.Function = 0;
    445 #endif
    446             }
    447             break;
    448 
    449         case TERMINATE_RECORD_TYPE:
    450             break;
    451 
    452         default:    /* Should be trapped by DGifGetRecordType */
    453             break;
    454         }
    455     } while (recType != TERMINATE_RECORD_TYPE);
    456 
    457     return true;
    458 }
    459 
    460 ///////////////////////////////////////////////////////////////////////////////
    461 DEFINE_DECODER_CREATOR(GIFImageDecoder);
    462 ///////////////////////////////////////////////////////////////////////////////
    463 
    464 static bool is_gif(SkStreamRewindable* stream) {
    465     char buf[GIF_STAMP_LEN];
    466     if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN) {
    467         if (memcmp(GIF_STAMP,   buf, GIF_STAMP_LEN) == 0 ||
    468                 memcmp(GIF87_STAMP, buf, GIF_STAMP_LEN) == 0 ||
    469                 memcmp(GIF89_STAMP, buf, GIF_STAMP_LEN) == 0) {
    470             return true;
    471         }
    472     }
    473     return false;
    474 }
    475 
    476 static SkImageDecoder* sk_libgif_dfactory(SkStreamRewindable* stream) {
    477     if (is_gif(stream)) {
    478         return SkNEW(SkGIFImageDecoder);
    479     }
    480     return NULL;
    481 }
    482 
    483 static SkImageDecoder_DecodeReg gReg(sk_libgif_dfactory);
    484 
    485 static SkImageDecoder::Format get_format_gif(SkStreamRewindable* stream) {
    486     if (is_gif(stream)) {
    487         return SkImageDecoder::kGIF_Format;
    488     }
    489     return SkImageDecoder::kUnknown_Format;
    490 }
    491 
    492 static SkImageDecoder_FormatReg gFormatReg(get_format_gif);
    493