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