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(const SkImageInfo& dstInfo) {
     34     switch (dstInfo.colorType()) {
     35         case kRGBA_8888_SkColorType:
     36         case kBGRA_8888_SkColorType:
     37         case kIndex_8_SkColorType:
     38         case kGray_8_SkColorType:
     39         case kRGB_565_SkColorType:
     40             return true;
     41         case kRGBA_F16_SkColorType:
     42             return dstInfo.colorSpace() && dstInfo.colorSpace()->gammaIsLinear();
     43         default:
     44             return false;
     45     }
     46 }
     47 
     48 static bool read_byte(SkStream* stream, uint8_t* data)
     49 {
     50     return stream->read(data, 1) == 1;
     51 }
     52 
     53 // http://en.wikipedia.org/wiki/Variable-length_quantity
     54 static bool read_mbf(SkStream* stream, uint64_t* value) {
     55     uint64_t n = 0;
     56     uint8_t data;
     57     const uint64_t kLimit = 0xFE00000000000000;
     58     SkASSERT(kLimit == ~((~static_cast<uint64_t>(0)) >> 7));
     59     do {
     60         if (n & kLimit) { // Will overflow on shift by 7.
     61             return false;
     62         }
     63         if (stream->read(&data, 1) != 1) {
     64             return false;
     65         }
     66         n = (n << 7) | (data & 0x7F);
     67     } while (data & 0x80);
     68     *value = n;
     69     return true;
     70 }
     71 
     72 static bool read_header(SkStream* stream, SkISize* size) {
     73     {
     74         uint8_t data;
     75         if (!read_byte(stream, &data) || data != 0) { // unknown type
     76             return false;
     77         }
     78         if (!read_byte(stream, &data) || (data & 0x9F)) { // skip fixed header
     79             return false;
     80         }
     81     }
     82 
     83     uint64_t width, height;
     84     if (!read_mbf(stream, &width) || width > 0xFFFF || !width) {
     85         return false;
     86     }
     87     if (!read_mbf(stream, &height) || height > 0xFFFF || !height) {
     88         return false;
     89     }
     90     if (size) {
     91         *size = SkISize::Make(SkToS32(width), SkToS32(height));
     92     }
     93     return true;
     94 }
     95 
     96 bool SkWbmpCodec::onRewind() {
     97     return read_header(this->stream(), nullptr);
     98 }
     99 
    100 SkSwizzler* SkWbmpCodec::initializeSwizzler(const SkImageInfo& info, const SkPMColor* ctable,
    101         const Options& opts) {
    102     return SkSwizzler::CreateSwizzler(this->getEncodedInfo(), ctable, info, opts);
    103 }
    104 
    105 bool SkWbmpCodec::readRow(uint8_t* row) {
    106     return this->stream()->read(row, fSrcRowBytes) == fSrcRowBytes;
    107 }
    108 
    109 SkWbmpCodec::SkWbmpCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream)
    110     : INHERITED(width, height, info, stream, SkColorSpace::MakeSRGB())
    111     , fSrcRowBytes(get_src_row_bytes(this->getInfo().width()))
    112     , fSwizzler(nullptr)
    113     , fColorTable(nullptr)
    114 {}
    115 
    116 SkEncodedImageFormat SkWbmpCodec::onGetEncodedFormat() const {
    117     return SkEncodedImageFormat::kWBMP;
    118 }
    119 
    120 SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info,
    121                                          void* dst,
    122                                          size_t rowBytes,
    123                                          const Options& options,
    124                                          SkPMColor ctable[],
    125                                          int* ctableCount,
    126                                          int* rowsDecoded) {
    127     if (options.fSubset) {
    128         // Subsets are not supported.
    129         return kUnimplemented;
    130     }
    131 
    132     if (!valid_color_type(info) || !valid_alpha(info.alphaType(), this->getInfo().alphaType())) {
    133         return kInvalidConversion;
    134     }
    135 
    136     // Prepare a color table if necessary
    137     setup_color_table(info.colorType(), ctable, ctableCount);
    138 
    139     // Initialize the swizzler
    140     std::unique_ptr<SkSwizzler> swizzler(this->initializeSwizzler(info, ctable, options));
    141     SkASSERT(swizzler);
    142 
    143     // Perform the decode
    144     SkISize size = info.dimensions();
    145     SkAutoTMalloc<uint8_t> src(fSrcRowBytes);
    146     void* dstRow = dst;
    147     for (int y = 0; y < size.height(); ++y) {
    148         if (!this->readRow(src.get())) {
    149             *rowsDecoded = y;
    150             return kIncompleteInput;
    151         }
    152         swizzler->swizzle(dstRow, src.get());
    153         dstRow = SkTAddOffset<void>(dstRow, rowBytes);
    154     }
    155     return kSuccess;
    156 }
    157 
    158 bool SkWbmpCodec::IsWbmp(const void* buffer, size_t bytesRead) {
    159     SkMemoryStream stream(buffer, bytesRead, false);
    160     return read_header(&stream, nullptr);
    161 }
    162 
    163 SkCodec* SkWbmpCodec::NewFromStream(SkStream* stream) {
    164     std::unique_ptr<SkStream> streamDeleter(stream);
    165     SkISize size;
    166     if (!read_header(stream, &size)) {
    167         return nullptr;
    168     }
    169     SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kGray_Color,
    170             SkEncodedInfo::kOpaque_Alpha, 1);
    171     return new SkWbmpCodec(size.width(), size.height(), info, streamDeleter.release());
    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) ||
    199         !valid_alpha(dstInfo.alphaType(), this->getInfo().alphaType()))
    200     {
    201         return kInvalidConversion;
    202     }
    203 
    204     // Fill in the color table
    205     setup_color_table(dstInfo.colorType(), inputColorTable, inputColorCount);
    206 
    207     // Copy the color table to a pointer that can be owned by the scanline decoder
    208     if (kIndex_8_SkColorType == dstInfo.colorType()) {
    209         fColorTable.reset(new SkColorTable(inputColorTable, 2));
    210     }
    211 
    212     // Initialize the swizzler
    213     fSwizzler.reset(this->initializeSwizzler(dstInfo, get_color_ptr(fColorTable.get()), options));
    214     SkASSERT(fSwizzler);
    215 
    216     fSrcBuffer.reset(fSrcRowBytes);
    217 
    218     return kSuccess;
    219 }
    220