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