Home | History | Annotate | Download | only in codec
      1 /*
      2  * Copyright 2015 Google Inc.
      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 "SkCodec.h"
      9 #include "SkCodecPriv.h"
     10 #include "SkColorPriv.h"
     11 #include "SkColorTable.h"
     12 #include "SkData.h"
     13 #include "SkStream.h"
     14 #include "SkWbmpCodec.h"
     15 
     16 // Each bit represents a pixel, so width is actually a number of bits.
     17 // A row will always be stored in bytes, so we round width up to the
     18 // nearest multiple of 8 to get the number of bits actually in the row.
     19 // We then divide by 8 to convert to bytes.
     20 static inline size_t get_src_row_bytes(int width) {
     21     return SkAlign8(width) >> 3;
     22 }
     23 
     24 static inline void setup_color_table(SkColorType colorType,
     25         SkPMColor* colorPtr, int* colorCount) {
     26     if (kIndex_8_SkColorType == colorType) {
     27         colorPtr[0] = SK_ColorBLACK;
     28         colorPtr[1] = SK_ColorWHITE;
     29         *colorCount = 2;
     30     }
     31 }
     32 
     33 static inline bool valid_color_type(SkColorType colorType, SkAlphaType alphaType) {
     34     switch (colorType) {
     35         case kN32_SkColorType:
     36         case kIndex_8_SkColorType:
     37             return true;
     38         case kGray_8_SkColorType:
     39         case kRGB_565_SkColorType:
     40             return kOpaque_SkAlphaType == alphaType;
     41         default:
     42             return false;
     43     }
     44 }
     45 
     46 static bool read_byte(SkStream* stream, uint8_t* data)
     47 {
     48     return stream->read(data, 1) == 1;
     49 }
     50 
     51 // http://en.wikipedia.org/wiki/Variable-length_quantity
     52 static bool read_mbf(SkStream* stream, uint64_t* value) {
     53     uint64_t n = 0;
     54     uint8_t data;
     55     const uint64_t kLimit = 0xFE00000000000000;
     56     SkASSERT(kLimit == ~((~static_cast<uint64_t>(0)) >> 7));
     57     do {
     58         if (n & kLimit) { // Will overflow on shift by 7.
     59             return false;
     60         }
     61         if (stream->read(&data, 1) != 1) {
     62             return false;
     63         }
     64         n = (n << 7) | (data & 0x7F);
     65     } while (data & 0x80);
     66     *value = n;
     67     return true;
     68 }
     69 
     70 static bool read_header(SkStream* stream, SkISize* size) {
     71     {
     72         uint8_t data;
     73         if (!read_byte(stream, &data) || data != 0) { // unknown type
     74             return false;
     75         }
     76         if (!read_byte(stream, &data) || (data & 0x9F)) { // skip fixed header
     77             return false;
     78         }
     79     }
     80 
     81     uint64_t width, height;
     82     if (!read_mbf(stream, &width) || width > 0xFFFF || !width) {
     83         return false;
     84     }
     85     if (!read_mbf(stream, &height) || height > 0xFFFF || !height) {
     86         return false;
     87     }
     88     if (size) {
     89         *size = SkISize::Make(SkToS32(width), SkToS32(height));
     90     }
     91     return true;
     92 }
     93 
     94 bool SkWbmpCodec::onRewind() {
     95     return read_header(this->stream(), nullptr);
     96 }
     97 
     98 SkSwizzler* SkWbmpCodec::initializeSwizzler(const SkImageInfo& info, const SkPMColor* ctable,
     99         const Options& opts) {
    100     return SkSwizzler::CreateSwizzler(SkSwizzler::kBit, ctable, info, opts);
    101 }
    102 
    103 bool SkWbmpCodec::readRow(uint8_t* row) {
    104     return this->stream()->read(row, fSrcRowBytes) == fSrcRowBytes;
    105 }
    106 
    107 SkWbmpCodec::SkWbmpCodec(const SkImageInfo& info, SkStream* stream)
    108     : INHERITED(info, stream)
    109     , fSrcRowBytes(get_src_row_bytes(this->getInfo().width()))
    110     , fSwizzler(nullptr)
    111     , fColorTable(nullptr)
    112 {}
    113 
    114 SkEncodedFormat SkWbmpCodec::onGetEncodedFormat() const {
    115     return kWBMP_SkEncodedFormat;
    116 }
    117 
    118 SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info,
    119                                          void* dst,
    120                                          size_t rowBytes,
    121                                          const Options& options,
    122                                          SkPMColor ctable[],
    123                                          int* ctableCount,
    124                                          int* rowsDecoded) {
    125     if (options.fSubset) {
    126         // Subsets are not supported.
    127         return kUnimplemented;
    128     }
    129 
    130     if (!valid_color_type(info.colorType(), info.alphaType()) ||
    131             !valid_alpha(info.alphaType(), this->getInfo().alphaType())) {
    132         return kInvalidConversion;
    133     }
    134 
    135     // Prepare a color table if necessary
    136     setup_color_table(info.colorType(), ctable, ctableCount);
    137 
    138     // Initialize the swizzler
    139     SkAutoTDelete<SkSwizzler> swizzler(this->initializeSwizzler(info, ctable, options));
    140     SkASSERT(swizzler);
    141 
    142     // Perform the decode
    143     SkISize size = info.dimensions();
    144     SkAutoTMalloc<uint8_t> src(fSrcRowBytes);
    145     void* dstRow = dst;
    146     for (int y = 0; y < size.height(); ++y) {
    147         if (!this->readRow(src.get())) {
    148             *rowsDecoded = y;
    149             return kIncompleteInput;
    150         }
    151         swizzler->swizzle(dstRow, src.get());
    152         dstRow = SkTAddOffset<void>(dstRow, rowBytes);
    153     }
    154     return kSuccess;
    155 }
    156 
    157 bool SkWbmpCodec::IsWbmp(const void* buffer, size_t bytesRead) {
    158     SkAutoTUnref<SkData> data(SkData::NewWithoutCopy(buffer, bytesRead));
    159     SkMemoryStream stream(data);
    160     return read_header(&stream, nullptr);
    161 }
    162 
    163 SkCodec* SkWbmpCodec::NewFromStream(SkStream* stream) {
    164     SkAutoTDelete<SkStream> streamDeleter(stream);
    165     SkISize size;
    166     if (!read_header(stream, &size)) {
    167         return nullptr;
    168     }
    169     SkImageInfo info = SkImageInfo::Make(size.width(), size.height(),
    170             kGray_8_SkColorType, kOpaque_SkAlphaType);
    171     return new SkWbmpCodec(info, streamDeleter.detach());
    172 }
    173 
    174 int SkWbmpCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
    175     void* dstRow = dst;
    176     for (int y = 0; y < count; ++y) {
    177         if (!this->readRow(fSrcBuffer.get())) {
    178             return y;
    179         }
    180         fSwizzler->swizzle(dstRow, fSrcBuffer.get());
    181         dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
    182     }
    183     return count;
    184 }
    185 
    186 bool SkWbmpCodec::onSkipScanlines(int count) {
    187     const size_t bytesToSkip = count * fSrcRowBytes;
    188     return this->stream()->skip(bytesToSkip) == bytesToSkip;
    189 }
    190 
    191 SkCodec::Result SkWbmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
    192         const Options& options, SkPMColor inputColorTable[], int* inputColorCount) {
    193     if (options.fSubset) {
    194         // Subsets are not supported.
    195         return kUnimplemented;
    196     }
    197 
    198     if (!valid_color_type(dstInfo.colorType(), dstInfo.alphaType()) ||
    199             !valid_alpha(dstInfo.alphaType(), this->getInfo().alphaType())) {
    200         return kInvalidConversion;
    201     }
    202 
    203     // Fill in the color table
    204     setup_color_table(dstInfo.colorType(), inputColorTable, inputColorCount);
    205 
    206     // Copy the color table to a pointer that can be owned by the scanline decoder
    207     if (kIndex_8_SkColorType == dstInfo.colorType()) {
    208         fColorTable.reset(new SkColorTable(inputColorTable, 2));
    209     }
    210 
    211     // Initialize the swizzler
    212     fSwizzler.reset(this->initializeSwizzler(dstInfo, get_color_ptr(fColorTable.get()), options));
    213     SkASSERT(fSwizzler);
    214 
    215     fSrcBuffer.reset(fSrcRowBytes);
    216 
    217     return kSuccess;
    218 }
    219