blob: 22f2bacce0d22f4fb4246a7f8c06338c1f09be17 [file] [log] [blame]
halcanarya096d7a2015-03-27 12:16:53 -07001/*
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"
msarett99f567e2015-08-05 12:58:26 -07009#include "SkCodecPriv.h"
halcanarya096d7a2015-03-27 12:16:53 -070010#include "SkColorPriv.h"
msarett99f567e2015-08-05 12:58:26 -070011#include "SkColorTable.h"
emmaleer8f4ba762015-08-14 07:44:46 -070012#include "SkScaledCodec.h"
halcanarya096d7a2015-03-27 12:16:53 -070013#include "SkStream.h"
14#include "SkCodec_wbmp.h"
15
msarett99f567e2015-08-05 12:58:26 -070016// 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.
20static inline size_t get_src_row_bytes(int width) {
21 return SkAlign8(width) >> 3;
22}
23
24static 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
halcanarya096d7a2015-03-27 12:16:53 -070033// http://en.wikipedia.org/wiki/Variable-length_quantity
34static bool read_mbf(SkStream* stream, uint64_t* value) {
35 uint64_t n = 0;
36 uint8_t data;
37 const uint64_t kLimit = 0xFE00000000000000;
38 SkASSERT(kLimit == ~((~static_cast<uint64_t>(0)) >> 7));
39 do {
40 if (n & kLimit) { // Will overflow on shift by 7.
41 return false;
42 }
43 if (stream->read(&data, 1) != 1) {
44 return false;
45 }
46 n = (n << 7) | (data & 0x7F);
47 } while (data & 0x80);
48 *value = n;
49 return true;
50}
51
52static bool read_header(SkStream* stream, SkISize* size) {
53 uint64_t width, height;
54 uint16_t data;
55 if (stream->read(&data, 2) != 2 || data != 0) {
56 return false;
57 }
58 if (!read_mbf(stream, &width) || width > 0xFFFF || !width) {
59 return false;
60 }
msarett99f567e2015-08-05 12:58:26 -070061 if (!read_mbf(stream, &height) || height > 0xFFFF || !height) {
halcanarya096d7a2015-03-27 12:16:53 -070062 return false;
63 }
64 if (size) {
65 *size = SkISize::Make(SkToS32(width), SkToS32(height));
66 }
67 return true;
68}
69
scroggob427db12015-08-12 07:24:13 -070070bool SkWbmpCodec::onRewind() {
halcanary96fcdcc2015-08-27 07:41:13 -070071 return read_header(this->stream(), nullptr);
msarett99f567e2015-08-05 12:58:26 -070072}
73
74SkSwizzler* SkWbmpCodec::initializeSwizzler(const SkImageInfo& info,
75 const SkPMColor* ctable, const Options& opts) {
msarett99f567e2015-08-05 12:58:26 -070076 // Create the swizzler based on the desired color type
77 switch (info.colorType()) {
78 case kIndex_8_SkColorType:
79 case kN32_SkColorType:
scroggocc2feb12015-08-14 08:32:46 -070080 case kRGB_565_SkColorType:
msarett99f567e2015-08-05 12:58:26 -070081 case kGray_8_SkColorType:
emmaleer8f4ba762015-08-14 07:44:46 -070082 return SkSwizzler::CreateSwizzler(SkSwizzler::kBit, ctable, info, opts.fZeroInitialized,
83 this->getInfo());
msarett99f567e2015-08-05 12:58:26 -070084 default:
halcanary96fcdcc2015-08-27 07:41:13 -070085 return nullptr;
halcanarya096d7a2015-03-27 12:16:53 -070086 }
87}
88
msarett99f567e2015-08-05 12:58:26 -070089SkCodec::Result SkWbmpCodec::readRow(uint8_t* row) {
90 if (this->stream()->read(row, fSrcRowBytes) != fSrcRowBytes) {
91 return kIncompleteInput;
92 }
93 return kSuccess;
94}
95
halcanarya096d7a2015-03-27 12:16:53 -070096SkWbmpCodec::SkWbmpCodec(const SkImageInfo& info, SkStream* stream)
msarett99f567e2015-08-05 12:58:26 -070097 : INHERITED(info, stream)
98 , fSrcRowBytes(get_src_row_bytes(this->getInfo().width()))
99{}
halcanarya096d7a2015-03-27 12:16:53 -0700100
101SkEncodedFormat SkWbmpCodec::onGetEncodedFormat() const {
102 return kWBMP_SkEncodedFormat;
103}
104
scroggoeb602a52015-07-09 08:16:03 -0700105SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info,
msarett99f567e2015-08-05 12:58:26 -0700106 void* dst,
scroggoeb602a52015-07-09 08:16:03 -0700107 size_t rowBytes,
scroggob636b452015-07-22 07:16:20 -0700108 const Options& options,
scroggoeb602a52015-07-09 08:16:03 -0700109 SkPMColor ctable[],
110 int* ctableCount) {
scroggob427db12015-08-12 07:24:13 -0700111 if (!this->rewindIfNeeded()) {
scroggoeb602a52015-07-09 08:16:03 -0700112 return kCouldNotRewind;
halcanarya096d7a2015-03-27 12:16:53 -0700113 }
scroggob636b452015-07-22 07:16:20 -0700114 if (options.fSubset) {
115 // Subsets are not supported.
116 return kUnimplemented;
117 }
halcanarya096d7a2015-03-27 12:16:53 -0700118 if (info.dimensions() != this->getInfo().dimensions()) {
scroggoeb602a52015-07-09 08:16:03 -0700119 return kInvalidScale;
halcanarya096d7a2015-03-27 12:16:53 -0700120 }
msarett99f567e2015-08-05 12:58:26 -0700121
scroggod1bc5742015-08-12 08:31:44 -0700122 if (!valid_alpha(info.alphaType(), this->getInfo().alphaType())) {
123 return SkCodec::kInvalidConversion;
124 }
125
msarett99f567e2015-08-05 12:58:26 -0700126 // Prepare a color table if necessary
127 setup_color_table(info.colorType(), ctable, ctableCount);
128
129
130 // Initialize the swizzler
131 SkAutoTDelete<SkSwizzler> swizzler(this->initializeSwizzler(info, ctable, options));
halcanary96fcdcc2015-08-27 07:41:13 -0700132 if (nullptr == swizzler.get()) {
msarett99f567e2015-08-05 12:58:26 -0700133 return kInvalidConversion;
halcanarya096d7a2015-03-27 12:16:53 -0700134 }
msarett99f567e2015-08-05 12:58:26 -0700135
136 // Perform the decode
halcanarya096d7a2015-03-27 12:16:53 -0700137 SkISize size = info.dimensions();
msarett99f567e2015-08-05 12:58:26 -0700138 SkAutoTMalloc<uint8_t> src(fSrcRowBytes);
139 void* dstRow = dst;
halcanarya096d7a2015-03-27 12:16:53 -0700140 for (int y = 0; y < size.height(); ++y) {
msarett99f567e2015-08-05 12:58:26 -0700141 Result rowResult = this->readRow(src.get());
142 if (kSuccess != rowResult) {
143 return rowResult;
halcanarya096d7a2015-03-27 12:16:53 -0700144 }
msarett99f567e2015-08-05 12:58:26 -0700145 swizzler->swizzle(dstRow, src.get());
146 dstRow = SkTAddOffset<void>(dstRow, rowBytes);
halcanarya096d7a2015-03-27 12:16:53 -0700147 }
scroggoeb602a52015-07-09 08:16:03 -0700148 return kSuccess;
halcanarya096d7a2015-03-27 12:16:53 -0700149}
150
151bool SkWbmpCodec::IsWbmp(SkStream* stream) {
halcanary96fcdcc2015-08-27 07:41:13 -0700152 return read_header(stream, nullptr);
halcanarya096d7a2015-03-27 12:16:53 -0700153}
154
155SkCodec* SkWbmpCodec::NewFromStream(SkStream* stream) {
scroggo0a7e69c2015-04-03 07:22:22 -0700156 SkAutoTDelete<SkStream> streamDeleter(stream);
halcanarya096d7a2015-03-27 12:16:53 -0700157 SkISize size;
158 if (!read_header(stream, &size)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700159 return nullptr;
halcanarya096d7a2015-03-27 12:16:53 -0700160 }
msarett99f567e2015-08-05 12:58:26 -0700161 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(),
162 kGray_8_SkColorType, kOpaque_SkAlphaType);
halcanary385fe4d2015-08-26 13:07:48 -0700163 return new SkWbmpCodec(info, streamDeleter.detach());
halcanarya096d7a2015-03-27 12:16:53 -0700164}
msarett99f567e2015-08-05 12:58:26 -0700165
166class SkWbmpScanlineDecoder : public SkScanlineDecoder {
167public:
168 /*
169 * Takes ownership of all pointer paramters.
170 */
171 SkWbmpScanlineDecoder(SkWbmpCodec* codec)
172 : INHERITED(codec->getInfo())
173 , fCodec(codec)
halcanary96fcdcc2015-08-27 07:41:13 -0700174 , fColorTable(nullptr)
175 , fSwizzler(nullptr)
msarett99f567e2015-08-05 12:58:26 -0700176 , fSrcBuffer(codec->fSrcRowBytes)
177 {}
178
179 SkCodec::Result onGetScanlines(void* dst, int count, size_t dstRowBytes) override {
180 void* dstRow = dst;
181 for (int y = 0; y < count; ++y) {
182 SkCodec::Result rowResult = fCodec->readRow(fSrcBuffer.get());
183 if (SkCodec::kSuccess != rowResult) {
184 return rowResult;
185 }
186 fSwizzler->swizzle(dstRow, fSrcBuffer.get());
187 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
188 }
189 return SkCodec::kSuccess;
190 }
191
192 SkCodec::Result onStart(const SkImageInfo& dstInfo,
193 const SkCodec::Options& options, SkPMColor inputColorTable[],
194 int* inputColorCount) {
scroggob427db12015-08-12 07:24:13 -0700195 if (!fCodec->rewindIfNeeded()) {
msarett99f567e2015-08-05 12:58:26 -0700196 return SkCodec::kCouldNotRewind;
197 }
198 if (options.fSubset) {
199 // Subsets are not supported.
200 return SkCodec::kUnimplemented;
201 }
202 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
emmaleer8f4ba762015-08-14 07:44:46 -0700203 if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) {
204 return SkCodec::kInvalidScale;
205 }
msarett99f567e2015-08-05 12:58:26 -0700206 }
207
scroggod1bc5742015-08-12 08:31:44 -0700208 if (!valid_alpha(dstInfo.alphaType(), this->getInfo().alphaType())) {
209 return SkCodec::kInvalidConversion;
210 }
211
msarett99f567e2015-08-05 12:58:26 -0700212 // Fill in the color table
213 setup_color_table(dstInfo.colorType(), inputColorTable, inputColorCount);
214
215 // Copy the color table to a pointer that can be owned by the scanline decoder
216 if (kIndex_8_SkColorType == dstInfo.colorType()) {
halcanary385fe4d2015-08-26 13:07:48 -0700217 fColorTable.reset(new SkColorTable(inputColorTable, 2));
msarett99f567e2015-08-05 12:58:26 -0700218 }
219
220 // Initialize the swizzler
221 fSwizzler.reset(fCodec->initializeSwizzler(dstInfo,
222 get_color_ptr(fColorTable.get()), options));
halcanary96fcdcc2015-08-27 07:41:13 -0700223 if (nullptr == fSwizzler.get()) {
emmaleer8f4ba762015-08-14 07:44:46 -0700224 return SkCodec::kInvalidConversion;
msarett99f567e2015-08-05 12:58:26 -0700225 }
226
227 return SkCodec::kSuccess;
228 }
229
emmaleer8f4ba762015-08-14 07:44:46 -0700230 SkEncodedFormat onGetEncodedFormat() const {
231 return kWBMP_SkEncodedFormat;
232 }
233
msarett99f567e2015-08-05 12:58:26 -0700234private:
235 SkAutoTDelete<SkWbmpCodec> fCodec;
236 SkAutoTUnref<SkColorTable> fColorTable;
237 SkAutoTDelete<SkSwizzler> fSwizzler;
238 SkAutoTMalloc<uint8_t> fSrcBuffer;
239
240 typedef SkScanlineDecoder INHERITED;
241};
242
243SkScanlineDecoder* SkWbmpCodec::NewSDFromStream(SkStream* stream) {
244 SkAutoTDelete<SkWbmpCodec> codec(static_cast<SkWbmpCodec*>(
245 SkWbmpCodec::NewFromStream(stream)));
246 if (!codec) {
halcanary96fcdcc2015-08-27 07:41:13 -0700247 return nullptr;
msarett99f567e2015-08-05 12:58:26 -0700248 }
249
250 // Return the new scanline decoder
halcanary385fe4d2015-08-26 13:07:48 -0700251 return new SkWbmpScanlineDecoder(codec.detach());
msarett99f567e2015-08-05 12:58:26 -0700252}