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 "SkColorData.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,
     99                          std::unique_ptr<SkStream> stream)
    100     // Wbmp does not need a colorXform, so choose an arbitrary srcFormat.
    101     : INHERITED(width, height, info, SkColorSpaceXform::ColorFormat(),
    102                 std::move(stream), SkColorSpace::MakeSRGB())
    103     , fSrcRowBytes(get_src_row_bytes(this->getInfo().width()))
    104     , fSwizzler(nullptr)
    105 {}
    106 
    107 SkEncodedImageFormat SkWbmpCodec::onGetEncodedFormat() const {
    108     return SkEncodedImageFormat::kWBMP;
    109 }
    110 
    111 bool SkWbmpCodec::conversionSupported(const SkImageInfo& dst, SkColorType /*srcColor*/,
    112                                       bool srcIsOpaque, const SkColorSpace* srcCS) const {
    113     return valid_color_type(dst) && valid_alpha(dst.alphaType(), srcIsOpaque);
    114 }
    115 
    116 SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info,
    117                                          void* dst,
    118                                          size_t rowBytes,
    119                                          const Options& options,
    120                                          int* rowsDecoded) {
    121     if (options.fSubset) {
    122         // Subsets are not supported.
    123         return kUnimplemented;
    124     }
    125 
    126     // Initialize the swizzler
    127     std::unique_ptr<SkSwizzler> swizzler(this->initializeSwizzler(info, options));
    128     SkASSERT(swizzler);
    129 
    130     // Perform the decode
    131     SkISize size = info.dimensions();
    132     SkAutoTMalloc<uint8_t> src(fSrcRowBytes);
    133     void* dstRow = dst;
    134     for (int y = 0; y < size.height(); ++y) {
    135         if (!this->readRow(src.get())) {
    136             *rowsDecoded = y;
    137             return kIncompleteInput;
    138         }
    139         swizzler->swizzle(dstRow, src.get());
    140         dstRow = SkTAddOffset<void>(dstRow, rowBytes);
    141     }
    142     return kSuccess;
    143 }
    144 
    145 bool SkWbmpCodec::IsWbmp(const void* buffer, size_t bytesRead) {
    146     SkMemoryStream stream(buffer, bytesRead, false);
    147     return read_header(&stream, nullptr);
    148 }
    149 
    150 std::unique_ptr<SkCodec> SkWbmpCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
    151                                                      Result* result) {
    152     SkISize size;
    153     if (!read_header(stream.get(), &size)) {
    154         // This already succeeded in IsWbmp, so this stream was corrupted in/
    155         // after rewind.
    156         *result = kCouldNotRewind;
    157         return nullptr;
    158     }
    159     *result = kSuccess;
    160     SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kGray_Color,
    161             SkEncodedInfo::kOpaque_Alpha, 1);
    162     return std::unique_ptr<SkCodec>(new SkWbmpCodec(size.width(), size.height(), info,
    163                                                     std::move(stream)));
    164 }
    165 
    166 int SkWbmpCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
    167     void* dstRow = dst;
    168     for (int y = 0; y < count; ++y) {
    169         if (!this->readRow(fSrcBuffer.get())) {
    170             return y;
    171         }
    172         fSwizzler->swizzle(dstRow, fSrcBuffer.get());
    173         dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
    174     }
    175     return count;
    176 }
    177 
    178 bool SkWbmpCodec::onSkipScanlines(int count) {
    179     const size_t bytesToSkip = count * fSrcRowBytes;
    180     return this->stream()->skip(bytesToSkip) == bytesToSkip;
    181 }
    182 
    183 SkCodec::Result SkWbmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
    184         const Options& options) {
    185     if (options.fSubset) {
    186         // Subsets are not supported.
    187         return kUnimplemented;
    188     }
    189 
    190     // Initialize the swizzler
    191     fSwizzler.reset(this->initializeSwizzler(dstInfo, options));
    192     SkASSERT(fSwizzler);
    193 
    194     fSrcBuffer.reset(fSrcRowBytes);
    195 
    196     return kSuccess;
    197 }
    198