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 bool valid_color_type(const SkImageInfo& dstInfo) {
     25     switch (dstInfo.colorType()) {
     26         case kRGBA_8888_SkColorType:
     27         case kBGRA_8888_SkColorType:
     28         case kGray_8_SkColorType:
     29         case kRGB_565_SkColorType:
     30             return true;
     31         case kRGBA_F16_SkColorType:
     32             return dstInfo.colorSpace() && dstInfo.colorSpace()->gammaIsLinear();
     33         default:
     34             return false;
     35     }
     36 }
     37 
     38 static bool read_byte(SkStream* stream, uint8_t* data)
     39 {
     40     return stream->read(data, 1) == 1;
     41 }
     42 
     43 // http://en.wikipedia.org/wiki/Variable-length_quantity
     44 static bool read_mbf(SkStream* stream, uint64_t* value) {
     45     uint64_t n = 0;
     46     uint8_t data;
     47     const uint64_t kLimit = 0xFE00000000000000;
     48     SkASSERT(kLimit == ~((~static_cast<uint64_t>(0)) >> 7));
     49     do {
     50         if (n & kLimit) { // Will overflow on shift by 7.
     51             return false;
     52         }
     53         if (stream->read(&data, 1) != 1) {
     54             return false;
     55         }
     56         n = (n << 7) | (data & 0x7F);
     57     } while (data & 0x80);
     58     *value = n;
     59     return true;
     60 }
     61 
     62 static bool read_header(SkStream* stream, SkISize* size) {
     63     {
     64         uint8_t data;
     65         if (!read_byte(stream, &data) || data != 0) { // unknown type
     66             return false;
     67         }
     68         if (!read_byte(stream, &data) || (data & 0x9F)) { // skip fixed header
     69             return false;
     70         }
     71     }
     72 
     73     uint64_t width, height;
     74     if (!read_mbf(stream, &width) || width > 0xFFFF || !width) {
     75         return false;
     76     }
     77     if (!read_mbf(stream, &height) || height > 0xFFFF || !height) {
     78         return false;
     79     }
     80     if (size) {
     81         *size = SkISize::Make(SkToS32(width), SkToS32(height));
     82     }
     83     return true;
     84 }
     85 
     86 bool SkWbmpCodec::onRewind() {
     87     return read_header(this->stream(), nullptr);
     88 }
     89 
     90 SkSwizzler* SkWbmpCodec::initializeSwizzler(const SkImageInfo& info, const Options& opts) {
     91     return SkSwizzler::CreateSwizzler(this->getEncodedInfo(), nullptr, info, opts);
     92 }
     93 
     94 bool SkWbmpCodec::readRow(uint8_t* row) {
     95     return this->stream()->read(row, fSrcRowBytes) == fSrcRowBytes;
     96 }
     97 
     98 SkWbmpCodec::SkWbmpCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream)
     99     // Wbmp does not need a colorXform, so choose an arbitrary srcFormat.
    100     : INHERITED(width, height, info, SkColorSpaceXform::ColorFormat(),
    101                 stream, SkColorSpace::MakeSRGB())
    102     , fSrcRowBytes(get_src_row_bytes(this->getInfo().width()))
    103     , fSwizzler(nullptr)
    104 {}
    105 
    106 SkEncodedImageFormat SkWbmpCodec::onGetEncodedFormat() const {
    107     return SkEncodedImageFormat::kWBMP;
    108 }
    109 
    110 SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info,
    111                                          void* dst,
    112                                          size_t rowBytes,
    113                                          const Options& options,
    114                                          int* rowsDecoded) {
    115     if (options.fSubset) {
    116         // Subsets are not supported.
    117         return kUnimplemented;
    118     }
    119 
    120     if (!valid_color_type(info) || !valid_alpha(info.alphaType(), this->getInfo().alphaType())) {
    121         return kInvalidConversion;
    122     }
    123 
    124     // Initialize the swizzler
    125     std::unique_ptr<SkSwizzler> swizzler(this->initializeSwizzler(info, options));
    126     SkASSERT(swizzler);
    127 
    128     // Perform the decode
    129     SkISize size = info.dimensions();
    130     SkAutoTMalloc<uint8_t> src(fSrcRowBytes);
    131     void* dstRow = dst;
    132     for (int y = 0; y < size.height(); ++y) {
    133         if (!this->readRow(src.get())) {
    134             *rowsDecoded = y;
    135             return kIncompleteInput;
    136         }
    137         swizzler->swizzle(dstRow, src.get());
    138         dstRow = SkTAddOffset<void>(dstRow, rowBytes);
    139     }
    140     return kSuccess;
    141 }
    142 
    143 bool SkWbmpCodec::IsWbmp(const void* buffer, size_t bytesRead) {
    144     SkMemoryStream stream(buffer, bytesRead, false);
    145     return read_header(&stream, nullptr);
    146 }
    147 
    148 SkCodec* SkWbmpCodec::NewFromStream(SkStream* stream, Result* result) {
    149     std::unique_ptr<SkStream> streamDeleter(stream);
    150     SkISize size;
    151     if (!read_header(stream, &size)) {
    152         // This already succeeded in IsWbmp, so this stream was corrupted in/
    153         // after rewind.
    154         *result = kCouldNotRewind;
    155         return nullptr;
    156     }
    157     *result = kSuccess;
    158     SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kGray_Color,
    159             SkEncodedInfo::kOpaque_Alpha, 1);
    160     return new SkWbmpCodec(size.width(), size.height(), info, streamDeleter.release());
    161 }
    162 
    163 int SkWbmpCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
    164     void* dstRow = dst;
    165     for (int y = 0; y < count; ++y) {
    166         if (!this->readRow(fSrcBuffer.get())) {
    167             return y;
    168         }
    169         fSwizzler->swizzle(dstRow, fSrcBuffer.get());
    170         dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
    171     }
    172     return count;
    173 }
    174 
    175 bool SkWbmpCodec::onSkipScanlines(int count) {
    176     const size_t bytesToSkip = count * fSrcRowBytes;
    177     return this->stream()->skip(bytesToSkip) == bytesToSkip;
    178 }
    179 
    180 SkCodec::Result SkWbmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
    181         const Options& options) {
    182     if (options.fSubset) {
    183         // Subsets are not supported.
    184         return kUnimplemented;
    185     }
    186 
    187     if (!valid_color_type(dstInfo) ||
    188         !valid_alpha(dstInfo.alphaType(), this->getInfo().alphaType()))
    189     {
    190         return kInvalidConversion;
    191     }
    192 
    193     // Initialize the swizzler
    194     fSwizzler.reset(this->initializeSwizzler(dstInfo, options));
    195     SkASSERT(fSwizzler);
    196 
    197     fSrcBuffer.reset(fSrcRowBytes);
    198 
    199     return kSuccess;
    200 }
    201