Home | History | Annotate | Download | only in images
      1 /*
      2  * Copyright 2010, The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "SkImageDecoder.h"
     18 #include "SkImageEncoder.h"
     19 #include "SkColorPriv.h"
     20 #include "SkScaledBitmapSampler.h"
     21 #include "SkStream.h"
     22 #include "SkTemplates.h"
     23 #include "SkUtils.h"
     24 
     25 // A WebP decoder only, on top of (subset of) libwebp
     26 // For more information on WebP image format, and libwebp library, see:
     27 //   http://code.google.com/speed/webp/
     28 //   http://www.webmproject.org/code/#libwebp_webp_image_decoder_library
     29 //   http://review.webmproject.org/gitweb?p=libwebp.git
     30 
     31 #include <stdio.h>
     32 extern "C" {
     33 // If moving libwebp out of skia source tree, path for webp headers must be
     34 // updated accordingly. Here, we enforce using local copy in webp sub-directory.
     35 #include "webp/decode.h"
     36 #include "webp/encode.h"
     37 }
     38 
     39 // this enables timing code to report milliseconds for a decode
     40 //#define TIME_DECODE
     41 
     42 //////////////////////////////////////////////////////////////////////////
     43 //////////////////////////////////////////////////////////////////////////
     44 
     45 // Define VP8 I/O on top of Skia stream
     46 
     47 //////////////////////////////////////////////////////////////////////////
     48 //////////////////////////////////////////////////////////////////////////
     49 
     50 static const size_t WEBP_VP8_HEADER_SIZE = 64;
     51 static const size_t WEBP_IDECODE_BUFFER_SZ = (1 << 16);
     52 
     53 // Parse headers of RIFF container, and check for valid Webp (VP8) content.
     54 static bool webp_parse_header(SkStream* stream, int* width, int* height, int* alpha) {
     55     unsigned char buffer[WEBP_VP8_HEADER_SIZE];
     56     size_t bytesToRead = WEBP_VP8_HEADER_SIZE;
     57     size_t totalBytesRead = 0;
     58     do {
     59         unsigned char* dst = buffer + totalBytesRead;
     60         const size_t bytesRead = stream->read(dst, bytesToRead);
     61         if (0 == bytesRead) {
     62             // Could not read any bytes. Check to see if we are at the end (exit
     63             // condition), and continue reading if not. Important for streams
     64             // that do not have all the data ready.
     65             continue;
     66         }
     67         bytesToRead -= bytesRead;
     68         totalBytesRead += bytesRead;
     69         SkASSERT(bytesToRead + totalBytesRead == WEBP_VP8_HEADER_SIZE);
     70     } while (!stream->isAtEnd() && bytesToRead > 0);
     71 
     72     WebPBitstreamFeatures features;
     73     VP8StatusCode status = WebPGetFeatures(buffer, totalBytesRead, &features);
     74     if (VP8_STATUS_OK != status) {
     75         return false; // Invalid WebP file.
     76     }
     77     *width = features.width;
     78     *height = features.height;
     79     *alpha = features.has_alpha;
     80 
     81     // sanity check for image size that's about to be decoded.
     82     {
     83         Sk64 size;
     84         size.setMul(*width, *height);
     85         if (size.isNeg() || !size.is32()) {
     86             return false;
     87         }
     88         // now check that if we are 4-bytes per pixel, we also don't overflow
     89         if (size.get32() > (0x7FFFFFFF >> 2)) {
     90             return false;
     91         }
     92     }
     93     return true;
     94 }
     95 
     96 class SkWEBPImageDecoder: public SkImageDecoder {
     97 public:
     98     SkWEBPImageDecoder() {
     99         fInputStream = NULL;
    100         fOrigWidth = 0;
    101         fOrigHeight = 0;
    102         fHasAlpha = 0;
    103     }
    104     virtual ~SkWEBPImageDecoder() {
    105         SkSafeUnref(fInputStream);
    106     }
    107 
    108     virtual Format getFormat() const SK_OVERRIDE {
    109         return kWEBP_Format;
    110     }
    111 
    112 protected:
    113     virtual bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) SK_OVERRIDE;
    114     virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRIDE;
    115     virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
    116 
    117 private:
    118     /**
    119      *  Called when determining the output config to request to webp.
    120      *  If the image does not have alpha, there is no need to premultiply.
    121      *  If the caller wants unpremultiplied colors, that is respected.
    122      */
    123     bool shouldPremultiply() const {
    124         return SkToBool(fHasAlpha) && !this->getRequireUnpremultipliedColors();
    125     }
    126 
    127     bool setDecodeConfig(SkBitmap* decodedBitmap, int width, int height);
    128 
    129     SkStream* fInputStream;
    130     int fOrigWidth;
    131     int fOrigHeight;
    132     int fHasAlpha;
    133 
    134     typedef SkImageDecoder INHERITED;
    135 };
    136 
    137 //////////////////////////////////////////////////////////////////////////
    138 
    139 #ifdef TIME_DECODE
    140 
    141 #include "SkTime.h"
    142 
    143 class AutoTimeMillis {
    144 public:
    145     AutoTimeMillis(const char label[]) :
    146         fLabel(label) {
    147         if (NULL == fLabel) {
    148             fLabel = "";
    149         }
    150         fNow = SkTime::GetMSecs();
    151     }
    152     ~AutoTimeMillis() {
    153         SkDebugf("---- Time (ms): %s %d\n", fLabel, SkTime::GetMSecs() - fNow);
    154     }
    155 private:
    156     const char* fLabel;
    157     SkMSec fNow;
    158 };
    159 
    160 #endif
    161 
    162 ///////////////////////////////////////////////////////////////////////////////
    163 
    164 // This guy exists just to aid in debugging, as it allows debuggers to just
    165 // set a break-point in one place to see all error exists.
    166 static bool return_false(const SkBitmap& bm, const char msg[]) {
    167     SkDEBUGF(("libwebp error %s [%d %d]", msg, bm.width(), bm.height()));
    168     return false; // must always return false
    169 }
    170 
    171 static WEBP_CSP_MODE webp_decode_mode(const SkBitmap* decodedBitmap, bool premultiply) {
    172     WEBP_CSP_MODE mode = MODE_LAST;
    173     SkBitmap::Config config = decodedBitmap->config();
    174 
    175     if (config == SkBitmap::kARGB_8888_Config) {
    176         mode = premultiply ? MODE_rgbA : MODE_RGBA;
    177     } else if (config == SkBitmap::kARGB_4444_Config) {
    178         mode = premultiply ? MODE_rgbA_4444 : MODE_RGBA_4444;
    179     } else if (config == SkBitmap::kRGB_565_Config) {
    180         mode = MODE_RGB_565;
    181     }
    182     SkASSERT(MODE_LAST != mode);
    183     return mode;
    184 }
    185 
    186 // Incremental WebP image decoding. Reads input buffer of 64K size iteratively
    187 // and decodes this block to appropriate color-space as per config object.
    188 static bool webp_idecode(SkStream* stream, WebPDecoderConfig* config) {
    189     WebPIDecoder* idec = WebPIDecode(NULL, 0, config);
    190     if (NULL == idec) {
    191         WebPFreeDecBuffer(&config->output);
    192         return false;
    193     }
    194 
    195     if (!stream->rewind()) {
    196         SkDebugf("Failed to rewind webp stream!");
    197         return false;
    198     }
    199     const size_t readBufferSize = stream->hasLength() ?
    200             SkTMin(stream->getLength(), WEBP_IDECODE_BUFFER_SZ) : WEBP_IDECODE_BUFFER_SZ;
    201     SkAutoMalloc srcStorage(readBufferSize);
    202     unsigned char* input = (uint8_t*)srcStorage.get();
    203     if (NULL == input) {
    204         WebPIDelete(idec);
    205         WebPFreeDecBuffer(&config->output);
    206         return false;
    207     }
    208 
    209     bool success = true;
    210     VP8StatusCode status = VP8_STATUS_SUSPENDED;
    211     do {
    212         const size_t bytesRead = stream->read(input, readBufferSize);
    213         if (0 == bytesRead) {
    214             success = false;
    215             break;
    216         }
    217 
    218         status = WebPIAppend(idec, input, bytesRead);
    219         if (VP8_STATUS_OK != status && VP8_STATUS_SUSPENDED != status) {
    220             success = false;
    221             break;
    222         }
    223     } while (VP8_STATUS_OK != status);
    224     srcStorage.free();
    225     WebPIDelete(idec);
    226     WebPFreeDecBuffer(&config->output);
    227 
    228     return success;
    229 }
    230 
    231 static bool webp_get_config_resize(WebPDecoderConfig* config,
    232                                    SkBitmap* decodedBitmap,
    233                                    int width, int height, bool premultiply) {
    234     WEBP_CSP_MODE mode = webp_decode_mode(decodedBitmap, premultiply);
    235     if (MODE_LAST == mode) {
    236         return false;
    237     }
    238 
    239     if (0 == WebPInitDecoderConfig(config)) {
    240         return false;
    241     }
    242 
    243     config->output.colorspace = mode;
    244     config->output.u.RGBA.rgba = (uint8_t*)decodedBitmap->getPixels();
    245     config->output.u.RGBA.stride = (int) decodedBitmap->rowBytes();
    246     config->output.u.RGBA.size = decodedBitmap->getSize();
    247     config->output.is_external_memory = 1;
    248 
    249     if (width != decodedBitmap->width() || height != decodedBitmap->height()) {
    250         config->options.use_scaling = 1;
    251         config->options.scaled_width = decodedBitmap->width();
    252         config->options.scaled_height = decodedBitmap->height();
    253     }
    254 
    255     return true;
    256 }
    257 
    258 static bool webp_get_config_resize_crop(WebPDecoderConfig* config,
    259                                         SkBitmap* decodedBitmap,
    260                                         const SkIRect& region, bool premultiply) {
    261 
    262     if (!webp_get_config_resize(config, decodedBitmap, region.width(),
    263                                 region.height(), premultiply)) {
    264       return false;
    265     }
    266 
    267     config->options.use_cropping = 1;
    268     config->options.crop_left = region.fLeft;
    269     config->options.crop_top = region.fTop;
    270     config->options.crop_width = region.width();
    271     config->options.crop_height = region.height();
    272 
    273     return true;
    274 }
    275 
    276 bool SkWEBPImageDecoder::setDecodeConfig(SkBitmap* decodedBitmap,
    277                                          int width, int height) {
    278     SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, SkToBool(fHasAlpha));
    279 
    280     // YUV converter supports output in RGB565, RGBA4444 and RGBA8888 formats.
    281     if (fHasAlpha) {
    282         if (config != SkBitmap::kARGB_4444_Config) {
    283             config = SkBitmap::kARGB_8888_Config;
    284         }
    285     } else {
    286         if (config != SkBitmap::kRGB_565_Config &&
    287             config != SkBitmap::kARGB_4444_Config) {
    288             config = SkBitmap::kARGB_8888_Config;
    289         }
    290     }
    291 
    292     if (!this->chooseFromOneChoice(config, width, height)) {
    293         return false;
    294     }
    295 
    296     return decodedBitmap->setConfig(config, width, height, 0,
    297                                     fHasAlpha ? kPremul_SkAlphaType : kOpaque_SkAlphaType);
    298 }
    299 
    300 bool SkWEBPImageDecoder::onBuildTileIndex(SkStreamRewindable* stream,
    301                                           int *width, int *height) {
    302     int origWidth, origHeight, hasAlpha;
    303     if (!webp_parse_header(stream, &origWidth, &origHeight, &hasAlpha)) {
    304         return false;
    305     }
    306 
    307     if (!stream->rewind()) {
    308         SkDebugf("Failed to rewind webp stream!");
    309         return false;
    310     }
    311 
    312     *width = origWidth;
    313     *height = origHeight;
    314 
    315     SkRefCnt_SafeAssign(this->fInputStream, stream);
    316     this->fOrigWidth = origWidth;
    317     this->fOrigHeight = origHeight;
    318     this->fHasAlpha = hasAlpha;
    319 
    320     return true;
    321 }
    322 
    323 static bool is_config_compatible(const SkBitmap& bitmap) {
    324     SkBitmap::Config config = bitmap.config();
    325     return config == SkBitmap::kARGB_4444_Config ||
    326            config == SkBitmap::kRGB_565_Config ||
    327            config == SkBitmap::kARGB_8888_Config;
    328 }
    329 
    330 bool SkWEBPImageDecoder::onDecodeSubset(SkBitmap* decodedBitmap,
    331                                         const SkIRect& region) {
    332     SkIRect rect = SkIRect::MakeWH(fOrigWidth, fOrigHeight);
    333 
    334     if (!rect.intersect(region)) {
    335         // If the requested region is entirely outsides the image, return false
    336         return false;
    337     }
    338 
    339     const int sampleSize = this->getSampleSize();
    340     SkScaledBitmapSampler sampler(rect.width(), rect.height(), sampleSize);
    341     const int width = sampler.scaledWidth();
    342     const int height = sampler.scaledHeight();
    343 
    344     // The image can be decoded directly to decodedBitmap if
    345     //   1. the region is within the image range
    346     //   2. bitmap's config is compatible
    347     //   3. bitmap's size is same as the required region (after sampled)
    348     bool directDecode = (rect == region) &&
    349                         (decodedBitmap->isNull() ||
    350                          (is_config_compatible(*decodedBitmap) &&
    351                          (decodedBitmap->width() == width) &&
    352                          (decodedBitmap->height() == height)));
    353 
    354     SkBitmap tmpBitmap;
    355     SkBitmap *bitmap = decodedBitmap;
    356 
    357     if (!directDecode) {
    358         bitmap = &tmpBitmap;
    359     }
    360 
    361     if (bitmap->isNull()) {
    362         if (!setDecodeConfig(bitmap, width, height)) {
    363             return false;
    364         }
    365         // alloc from native heap if it is a temp bitmap. (prevent GC)
    366         bool allocResult = (bitmap == decodedBitmap)
    367                                ? allocPixelRef(bitmap, NULL)
    368                                : bitmap->allocPixels();
    369         if (!allocResult) {
    370             return return_false(*decodedBitmap, "allocPixelRef");
    371         }
    372     } else {
    373         // This is also called in setDecodeConfig in above block.
    374         // i.e., when bitmap->isNull() is true.
    375         if (!chooseFromOneChoice(bitmap->config(), width, height)) {
    376             return false;
    377         }
    378     }
    379 
    380     SkAutoLockPixels alp(*bitmap);
    381     WebPDecoderConfig config;
    382     if (!webp_get_config_resize_crop(&config, bitmap, rect,
    383                                      this->shouldPremultiply())) {
    384         return false;
    385     }
    386 
    387     // Decode the WebP image data stream using WebP incremental decoding for
    388     // the specified cropped image-region.
    389     if (!webp_idecode(this->fInputStream, &config)) {
    390         return false;
    391     }
    392 
    393     if (!directDecode) {
    394         cropBitmap(decodedBitmap, bitmap, sampleSize, region.x(), region.y(),
    395                    region.width(), region.height(), rect.x(), rect.y());
    396     }
    397     return true;
    398 }
    399 
    400 bool SkWEBPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
    401                                   Mode mode) {
    402 #ifdef TIME_DECODE
    403     AutoTimeMillis atm("WEBP Decode");
    404 #endif
    405 
    406     int origWidth, origHeight, hasAlpha;
    407     if (!webp_parse_header(stream, &origWidth, &origHeight, &hasAlpha)) {
    408         return false;
    409     }
    410     this->fHasAlpha = hasAlpha;
    411 
    412     const int sampleSize = this->getSampleSize();
    413     SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);
    414     if (!setDecodeConfig(decodedBitmap, sampler.scaledWidth(),
    415                          sampler.scaledHeight())) {
    416         return false;
    417     }
    418 
    419     // If only bounds are requested, done
    420     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
    421         return true;
    422     }
    423 
    424     if (!this->allocPixelRef(decodedBitmap, NULL)) {
    425         return return_false(*decodedBitmap, "allocPixelRef");
    426     }
    427 
    428     SkAutoLockPixels alp(*decodedBitmap);
    429 
    430     WebPDecoderConfig config;
    431     if (!webp_get_config_resize(&config, decodedBitmap, origWidth, origHeight,
    432                                 this->shouldPremultiply())) {
    433         return false;
    434     }
    435 
    436     // Decode the WebP image data stream using WebP incremental decoding.
    437     return webp_idecode(stream, &config);
    438 }
    439 
    440 ///////////////////////////////////////////////////////////////////////////////
    441 
    442 typedef void (*ScanlineImporter)(const uint8_t* in, uint8_t* out, int width,
    443                                  const SkPMColor* SK_RESTRICT ctable);
    444 
    445 static void ARGB_8888_To_RGB(const uint8_t* in, uint8_t* rgb, int width,
    446                              const SkPMColor*) {
    447   const uint32_t* SK_RESTRICT src = (const uint32_t*)in;
    448   for (int i = 0; i < width; ++i) {
    449       const uint32_t c = *src++;
    450       rgb[0] = SkGetPackedR32(c);
    451       rgb[1] = SkGetPackedG32(c);
    452       rgb[2] = SkGetPackedB32(c);
    453       rgb += 3;
    454   }
    455 }
    456 
    457 static void RGB_565_To_RGB(const uint8_t* in, uint8_t* rgb, int width,
    458                            const SkPMColor*) {
    459   const uint16_t* SK_RESTRICT src = (const uint16_t*)in;
    460   for (int i = 0; i < width; ++i) {
    461       const uint16_t c = *src++;
    462       rgb[0] = SkPacked16ToR32(c);
    463       rgb[1] = SkPacked16ToG32(c);
    464       rgb[2] = SkPacked16ToB32(c);
    465       rgb += 3;
    466   }
    467 }
    468 
    469 static void ARGB_4444_To_RGB(const uint8_t* in, uint8_t* rgb, int width,
    470                              const SkPMColor*) {
    471   const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)in;
    472   for (int i = 0; i < width; ++i) {
    473       const SkPMColor16 c = *src++;
    474       rgb[0] = SkPacked4444ToR32(c);
    475       rgb[1] = SkPacked4444ToG32(c);
    476       rgb[2] = SkPacked4444ToB32(c);
    477       rgb += 3;
    478   }
    479 }
    480 
    481 static void Index8_To_RGB(const uint8_t* in, uint8_t* rgb, int width,
    482                           const SkPMColor* SK_RESTRICT ctable) {
    483   const uint8_t* SK_RESTRICT src = (const uint8_t*)in;
    484   for (int i = 0; i < width; ++i) {
    485       const uint32_t c = ctable[*src++];
    486       rgb[0] = SkGetPackedR32(c);
    487       rgb[1] = SkGetPackedG32(c);
    488       rgb[2] = SkGetPackedB32(c);
    489       rgb += 3;
    490   }
    491 }
    492 
    493 static ScanlineImporter ChooseImporter(const SkBitmap::Config& config) {
    494     switch (config) {
    495         case SkBitmap::kARGB_8888_Config:
    496             return ARGB_8888_To_RGB;
    497         case SkBitmap::kRGB_565_Config:
    498             return RGB_565_To_RGB;
    499         case SkBitmap::kARGB_4444_Config:
    500             return ARGB_4444_To_RGB;
    501         case SkBitmap::kIndex8_Config:
    502             return Index8_To_RGB;
    503         default:
    504             return NULL;
    505     }
    506 }
    507 
    508 static int stream_writer(const uint8_t* data, size_t data_size,
    509                          const WebPPicture* const picture) {
    510   SkWStream* const stream = (SkWStream*)picture->custom_ptr;
    511   return stream->write(data, data_size) ? 1 : 0;
    512 }
    513 
    514 class SkWEBPImageEncoder : public SkImageEncoder {
    515 protected:
    516     virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) SK_OVERRIDE;
    517 
    518 private:
    519     typedef SkImageEncoder INHERITED;
    520 };
    521 
    522 bool SkWEBPImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bm,
    523                                   int quality) {
    524     const SkBitmap::Config config = bm.config();
    525     const ScanlineImporter scanline_import = ChooseImporter(config);
    526     if (NULL == scanline_import) {
    527         return false;
    528     }
    529 
    530     SkAutoLockPixels alp(bm);
    531     SkAutoLockColors ctLocker;
    532     if (NULL == bm.getPixels()) {
    533         return false;
    534     }
    535 
    536     WebPConfig webp_config;
    537     if (!WebPConfigPreset(&webp_config, WEBP_PRESET_DEFAULT, (float) quality)) {
    538         return false;
    539     }
    540 
    541     WebPPicture pic;
    542     WebPPictureInit(&pic);
    543     pic.width = bm.width();
    544     pic.height = bm.height();
    545     pic.writer = stream_writer;
    546     pic.custom_ptr = (void*)stream;
    547 
    548     const SkPMColor* colors = ctLocker.lockColors(bm);
    549     const uint8_t* src = (uint8_t*)bm.getPixels();
    550     const int rgbStride = pic.width * 3;
    551 
    552     // Import (for each scanline) the bit-map image (in appropriate color-space)
    553     // to RGB color space.
    554     uint8_t* rgb = new uint8_t[rgbStride * pic.height];
    555     for (int y = 0; y < pic.height; ++y) {
    556         scanline_import(src + y * bm.rowBytes(), rgb + y * rgbStride,
    557                         pic.width, colors);
    558     }
    559 
    560     bool ok = SkToBool(WebPPictureImportRGB(&pic, rgb, rgbStride));
    561     delete[] rgb;
    562 
    563     ok = ok && WebPEncode(&webp_config, &pic);
    564     WebPPictureFree(&pic);
    565 
    566     return ok;
    567 }
    568 
    569 
    570 ///////////////////////////////////////////////////////////////////////////////
    571 DEFINE_DECODER_CREATOR(WEBPImageDecoder);
    572 DEFINE_ENCODER_CREATOR(WEBPImageEncoder);
    573 ///////////////////////////////////////////////////////////////////////////////
    574 
    575 static SkImageDecoder* sk_libwebp_dfactory(SkStreamRewindable* stream) {
    576     int width, height, hasAlpha;
    577     if (!webp_parse_header(stream, &width, &height, &hasAlpha)) {
    578         return NULL;
    579     }
    580 
    581     // Magic matches, call decoder
    582     return SkNEW(SkWEBPImageDecoder);
    583 }
    584 
    585 static SkImageDecoder::Format get_format_webp(SkStreamRewindable* stream) {
    586     int width, height, hasAlpha;
    587     if (webp_parse_header(stream, &width, &height, &hasAlpha)) {
    588         return SkImageDecoder::kWEBP_Format;
    589     }
    590     return SkImageDecoder::kUnknown_Format;
    591 }
    592 
    593 static SkImageEncoder* sk_libwebp_efactory(SkImageEncoder::Type t) {
    594       return (SkImageEncoder::kWEBP_Type == t) ? SkNEW(SkWEBPImageEncoder) : NULL;
    595 }
    596 
    597 static SkImageDecoder_DecodeReg gDReg(sk_libwebp_dfactory);
    598 static SkImageDecoder_FormatReg gFormatReg(get_format_webp);
    599 static SkImageEncoder_EncodeReg gEReg(sk_libwebp_efactory);
    600