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     Format getFormat() const override {
     23         return kGIF_Format;
     24     }
     25 
     26 protected:
     27     Result onDecode(SkStream* stream, SkBitmap* bm, Mode mode) 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 = nullptr;)
     81                 SkDEBUGCODE(fDeltaYPtr = nullptr;)
     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 nullptr on failure
    118 static const ColorMapObject* find_colormap(const GifFileType* gif) {
    119     const ColorMapObject* cmap = gif->Image.ColorMap;
    120     if (nullptr == cmap) {
    121         cmap = gif->SColorMap;
    122     }
    123 
    124     if (nullptr == cmap) {
    125         // no colormap found
    126         return nullptr;
    127     }
    128     // some sanity checks
    129     if (cmap && ((unsigned)cmap->ColorCount > 256 ||
    130                  cmap->ColorCount != (1 << cmap->BitsPerPixel))) {
    131         cmap = nullptr;
    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 SkImageDecoder::Result 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 SkImageDecoder::kFailure;
    162 }
    163 
    164 static void gif_warning(const SkBitmap& bm, const char msg[]) {
    165     if (!c_suppressGIFImageDecoderWarnings) {
    166         SkDebugf("libgif warning [%s] bitmap [%d %d] pixels %p colortable %p\n",
    167                  msg, bm.width(), bm.height(), bm.getPixels(),
    168                  bm.getColorTable());
    169     }
    170 }
    171 
    172 /**
    173  *  Skip rows in the source gif image.
    174  *  @param gif Source image.
    175  *  @param dst Scratch output needed by gif library call. Must be >= width bytes.
    176  *  @param width Bytes per row in the source image.
    177  *  @param rowsToSkip Number of rows to skip.
    178  *  @return True on success, false on GIF_ERROR.
    179  */
    180 static bool skip_src_rows(GifFileType* gif, uint8_t* dst, int width, int rowsToSkip) {
    181     for (int i = 0; i < rowsToSkip; i++) {
    182         if (DGifGetLine(gif, dst, width) == GIF_ERROR) {
    183             return false;
    184         }
    185     }
    186     return true;
    187 }
    188 
    189 /**
    190  *  GIFs with fewer then 256 color entries will sometimes index out of
    191  *  bounds of the color table (this is malformed, but libgif does not
    192  *  check sicne it is rare).  This function checks for this error and
    193  *  fixes it.  This makes the output image consistantly deterministic.
    194  */
    195 static void sanitize_indexed_bitmap(SkBitmap* bm) {
    196     if ((kIndex_8_SkColorType == bm->colorType()) && !(bm->empty())) {
    197         SkAutoLockPixels alp(*bm);
    198         if (bm->getPixels()) {
    199             SkColorTable* ct = bm->getColorTable();  // Index8 must have it.
    200             SkASSERT(ct != nullptr);
    201             uint32_t count = ct->count();
    202             SkASSERT(count > 0);
    203             SkASSERT(count <= 0x100);
    204             if (count != 0x100) {  // Full colortables can't go wrong.
    205                 // Count is a power of 2; asserted elsewhere.
    206                 uint8_t byteMask = (~(count - 1));
    207                 bool warning = false;
    208                 uint8_t* addr = static_cast<uint8_t*>(bm->getPixels());
    209                 int height = bm->height();
    210                 int width = bm->width();
    211                 size_t rowBytes = bm->rowBytes();
    212                 while (--height >= 0) {
    213                     uint8_t* ptr = addr;
    214                     int x = width;
    215                     while (--x >= 0) {
    216                         if (0 != ((*ptr) & byteMask)) {
    217                             warning = true;
    218                             *ptr = 0;
    219                         }
    220                         ++ptr;
    221                     }
    222                     addr += rowBytes;
    223                 }
    224                 if (warning) {
    225                     gif_warning(*bm, "Index out of bounds.");
    226                 }
    227             }
    228         }
    229     }
    230 }
    231 
    232 namespace {
    233 // This function is a template argument, so can't be static.
    234 int close_gif(GifFileType* gif) {
    235 #if GIFLIB_MAJOR < 5 || (GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 0)
    236     return DGifCloseFile(gif);
    237 #else
    238     return DGifCloseFile(gif, nullptr);
    239 #endif
    240 }
    241 }//namespace
    242 
    243 SkImageDecoder::Result SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) {
    244 #if GIFLIB_MAJOR < 5
    245     GifFileType* gif = DGifOpen(sk_stream, DecodeCallBackProc);
    246 #else
    247     GifFileType* gif = DGifOpen(sk_stream, DecodeCallBackProc, nullptr);
    248 #endif
    249     if (nullptr == gif) {
    250         return error_return(*bm, "DGifOpen");
    251     }
    252 
    253     SkAutoTCallIProc<GifFileType, close_gif> acp(gif);
    254 
    255     SavedImage temp_save;
    256     temp_save.ExtensionBlocks=nullptr;
    257     temp_save.ExtensionBlockCount=0;
    258     SkAutoTCallVProc<SavedImage, CheckFreeExtension> acp2(&temp_save);
    259 
    260     int width, height;
    261     GifRecordType recType;
    262     GifByteType *extData;
    263 #if GIFLIB_MAJOR >= 5
    264     int extFunction;
    265 #endif
    266     int transpIndex = -1;   // -1 means we don't have it (yet)
    267     int fillIndex = gif->SBackGroundColor;
    268 
    269     do {
    270         if (DGifGetRecordType(gif, &recType) == GIF_ERROR) {
    271             return error_return(*bm, "DGifGetRecordType");
    272         }
    273 
    274         switch (recType) {
    275         case IMAGE_DESC_RECORD_TYPE: {
    276             if (DGifGetImageDesc(gif) == GIF_ERROR) {
    277                 return error_return(*bm, "IMAGE_DESC_RECORD_TYPE");
    278             }
    279 
    280             if (gif->ImageCount < 1) {    // sanity check
    281                 return error_return(*bm, "ImageCount < 1");
    282             }
    283 
    284             width = gif->SWidth;
    285             height = gif->SHeight;
    286 
    287             SavedImage* image = &gif->SavedImages[gif->ImageCount-1];
    288             const GifImageDesc& desc = image->ImageDesc;
    289 
    290             int imageLeft = desc.Left;
    291             int imageTop = desc.Top;
    292             const int innerWidth = desc.Width;
    293             const int innerHeight = desc.Height;
    294             if (innerWidth <= 0 || innerHeight <= 0) {
    295                 return error_return(*bm, "invalid dimensions");
    296             }
    297 
    298             // check for valid descriptor
    299             if (innerWidth > width) {
    300                 gif_warning(*bm, "image too wide, expanding output to size");
    301                 width = innerWidth;
    302                 imageLeft = 0;
    303             } else if (imageLeft + innerWidth > width) {
    304                 gif_warning(*bm, "shifting image left to fit");
    305                 imageLeft = width - innerWidth;
    306             } else if (imageLeft < 0) {
    307                 gif_warning(*bm, "shifting image right to fit");
    308                 imageLeft = 0;
    309             }
    310 
    311 
    312             if (innerHeight > height) {
    313                 gif_warning(*bm, "image too tall,  expanding output to size");
    314                 height = innerHeight;
    315                 imageTop = 0;
    316             } else if (imageTop + innerHeight > height) {
    317                 gif_warning(*bm, "shifting image up to fit");
    318                 imageTop = height - innerHeight;
    319             } else if (imageTop < 0) {
    320                 gif_warning(*bm, "shifting image down to fit");
    321                 imageTop = 0;
    322             }
    323 
    324             SkScaledBitmapSampler sampler(width, height, this->getSampleSize());
    325 
    326             bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(),
    327                                           kIndex_8_SkColorType, kPremul_SkAlphaType));
    328 
    329             if (SkImageDecoder::kDecodeBounds_Mode == mode) {
    330                 return kSuccess;
    331             }
    332 
    333 
    334             // now we decode the colortable
    335             int colorCount = 0;
    336             {
    337                 // Declare colorPtr here for scope.
    338                 SkPMColor colorPtr[256]; // storage for worst-case
    339                 const ColorMapObject* cmap = find_colormap(gif);
    340                 if (cmap != nullptr) {
    341                     SkASSERT(cmap->ColorCount == (1 << (cmap->BitsPerPixel)));
    342                     colorCount = cmap->ColorCount;
    343                     if (colorCount > 256) {
    344                         colorCount = 256;  // our kIndex8 can't support more
    345                     }
    346                     for (int index = 0; index < colorCount; index++) {
    347                         colorPtr[index] = SkPackARGB32(0xFF,
    348                                                        cmap->Colors[index].Red,
    349                                                        cmap->Colors[index].Green,
    350                                                        cmap->Colors[index].Blue);
    351                     }
    352                 } else {
    353                     // find_colormap() returned nullptr.  Some (rare, broken)
    354                     // GIFs don't have a color table, so we force one.
    355                     gif_warning(*bm, "missing colormap");
    356                     colorCount = 256;
    357                     sk_memset32(colorPtr, SK_ColorWHITE, colorCount);
    358                 }
    359                 transpIndex = find_transpIndex(temp_save, colorCount);
    360                 if (transpIndex >= 0) {
    361                     colorPtr[transpIndex] = SK_ColorTRANSPARENT; // ram in a transparent SkPMColor
    362                     fillIndex = transpIndex;
    363                 } else if (fillIndex >= colorCount) {
    364                     // gif->SBackGroundColor should be less than colorCount.
    365                     fillIndex = 0;  // If not, fix it.
    366                 }
    367 
    368                 SkAutoTUnref<SkColorTable> ctable(new SkColorTable(colorPtr, colorCount));
    369                 if (!this->allocPixelRef(bm, ctable)) {
    370                     return error_return(*bm, "allocPixelRef");
    371                 }
    372             }
    373 
    374             // abort if either inner dimension is <= 0
    375             if (innerWidth <= 0 || innerHeight <= 0) {
    376                 return error_return(*bm, "non-pos inner width/height");
    377             }
    378 
    379             SkAutoLockPixels alp(*bm);
    380 
    381             SkAutoTMalloc<uint8_t> storage(innerWidth);
    382             uint8_t* scanline = storage.get();
    383 
    384             // GIF has an option to store the scanlines of an image, plus a larger background,
    385             // filled by a fill color. In this case, we will use a subset of the larger bitmap
    386             // for sampling.
    387             SkBitmap subset;
    388             SkBitmap* workingBitmap;
    389             // are we only a subset of the total bounds?
    390             if ((imageTop | imageLeft) > 0 ||
    391                  innerWidth < width || innerHeight < height) {
    392                 // Fill the background.
    393                 memset(bm->getPixels(), fillIndex, bm->getSize());
    394 
    395                 // Create a subset of the bitmap.
    396                 SkIRect subsetRect(SkIRect::MakeXYWH(imageLeft / sampler.srcDX(),
    397                                                      imageTop / sampler.srcDY(),
    398                                                      innerWidth / sampler.srcDX(),
    399                                                      innerHeight / sampler.srcDY()));
    400                 if (!bm->extractSubset(&subset, subsetRect)) {
    401                     return error_return(*bm, "Extract failed.");
    402                 }
    403                 // Update the sampler. We'll now be only sampling into the subset.
    404                 sampler = SkScaledBitmapSampler(innerWidth, innerHeight, this->getSampleSize());
    405                 workingBitmap = &subset;
    406             } else {
    407                 workingBitmap = bm;
    408             }
    409 
    410             // bm is already locked, but if we had to take a subset, it must be locked also,
    411             // so that getPixels() will point to its pixels.
    412             SkAutoLockPixels alpWorking(*workingBitmap);
    413 
    414             if (!sampler.begin(workingBitmap, SkScaledBitmapSampler::kIndex, *this)) {
    415                 return error_return(*bm, "Sampler failed to begin.");
    416             }
    417 
    418             // now decode each scanline
    419             if (gif->Image.Interlace) {
    420                 // Iterate over the height of the source data. The sampler will
    421                 // take care of skipping unneeded rows.
    422                 GifInterlaceIter iter(innerHeight);
    423                 for (int y = 0; y < innerHeight; y++) {
    424                     if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) {
    425                         gif_warning(*bm, "interlace DGifGetLine");
    426                         memset(scanline, fillIndex, innerWidth);
    427                         for (; y < innerHeight; y++) {
    428                             sampler.sampleInterlaced(scanline, iter.currY());
    429                             iter.next();
    430                         }
    431                         return kPartialSuccess;
    432                     }
    433                     sampler.sampleInterlaced(scanline, iter.currY());
    434                     iter.next();
    435                 }
    436             } else {
    437                 // easy, non-interlace case
    438                 const int outHeight = workingBitmap->height();
    439                 skip_src_rows(gif, scanline, innerWidth, sampler.srcY0());
    440                 for (int y = 0; y < outHeight; y++) {
    441                     if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) {
    442                         gif_warning(*bm, "DGifGetLine");
    443                         memset(scanline, fillIndex, innerWidth);
    444                         for (; y < outHeight; y++) {
    445                             sampler.next(scanline);
    446                         }
    447                         return kPartialSuccess;
    448                     }
    449                     // scanline now contains the raw data. Sample it.
    450                     sampler.next(scanline);
    451                     if (y < outHeight - 1) {
    452                         skip_src_rows(gif, scanline, innerWidth, sampler.srcDY() - 1);
    453                     }
    454                 }
    455                 // skip the rest of the rows (if any)
    456                 int read = (outHeight - 1) * sampler.srcDY() + sampler.srcY0() + 1;
    457                 SkASSERT(read <= innerHeight);
    458                 skip_src_rows(gif, scanline, innerWidth, innerHeight - read);
    459             }
    460             sanitize_indexed_bitmap(bm);
    461             return kSuccess;
    462             } break;
    463 
    464         case EXTENSION_RECORD_TYPE:
    465 #if GIFLIB_MAJOR < 5
    466             if (DGifGetExtension(gif, &temp_save.Function,
    467                                  &extData) == GIF_ERROR) {
    468 #else
    469             if (DGifGetExtension(gif, &extFunction, &extData) == GIF_ERROR) {
    470 #endif
    471                 return error_return(*bm, "DGifGetExtension");
    472             }
    473 
    474             while (extData != nullptr) {
    475                 /* Create an extension block with our data */
    476 #if GIFLIB_MAJOR < 5
    477                 if (AddExtensionBlock(&temp_save, extData[0],
    478                                       &extData[1]) == GIF_ERROR) {
    479 #else
    480                 if (GifAddExtensionBlock(&temp_save.ExtensionBlockCount,
    481                                          &temp_save.ExtensionBlocks,
    482                                          extFunction,
    483                                          extData[0],
    484                                          &extData[1]) == GIF_ERROR) {
    485 #endif
    486                     return error_return(*bm, "AddExtensionBlock");
    487                 }
    488                 if (DGifGetExtensionNext(gif, &extData) == GIF_ERROR) {
    489                     return error_return(*bm, "DGifGetExtensionNext");
    490                 }
    491 #if GIFLIB_MAJOR < 5
    492                 temp_save.Function = 0;
    493 #endif
    494             }
    495             break;
    496 
    497         case TERMINATE_RECORD_TYPE:
    498             break;
    499 
    500         default:    /* Should be trapped by DGifGetRecordType */
    501             break;
    502         }
    503     } while (recType != TERMINATE_RECORD_TYPE);
    504 
    505     sanitize_indexed_bitmap(bm);
    506     return kSuccess;
    507 }
    508 
    509 ///////////////////////////////////////////////////////////////////////////////
    510 DEFINE_DECODER_CREATOR(GIFImageDecoder);
    511 ///////////////////////////////////////////////////////////////////////////////
    512 
    513 static bool is_gif(SkStreamRewindable* stream) {
    514     char buf[GIF_STAMP_LEN];
    515     if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN) {
    516         if (memcmp(GIF_STAMP,   buf, GIF_STAMP_LEN) == 0 ||
    517                 memcmp(GIF87_STAMP, buf, GIF_STAMP_LEN) == 0 ||
    518                 memcmp(GIF89_STAMP, buf, GIF_STAMP_LEN) == 0) {
    519             return true;
    520         }
    521     }
    522     return false;
    523 }
    524 
    525 static SkImageDecoder* sk_libgif_dfactory(SkStreamRewindable* stream) {
    526     if (is_gif(stream)) {
    527         return new SkGIFImageDecoder;
    528     }
    529     return nullptr;
    530 }
    531 
    532 static SkImageDecoder_DecodeReg gReg(sk_libgif_dfactory);
    533 
    534 static SkImageDecoder::Format get_format_gif(SkStreamRewindable* stream) {
    535     if (is_gif(stream)) {
    536         return SkImageDecoder::kGIF_Format;
    537     }
    538     return SkImageDecoder::kUnknown_Format;
    539 }
    540 
    541 static SkImageDecoder_FormatReg gFormatReg(get_format_gif);
    542