blob: 86dce5cc89e95590f8d0d138df9bda352994f95d [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"
halcanarya096d7a2015-03-27 12:16:53 -070012#include "SkStream.h"
13#include "SkCodec_wbmp.h"
14
msarett99f567e2015-08-05 12:58:26 -070015// Each bit represents a pixel, so width is actually a number of bits.
16// A row will always be stored in bytes, so we round width up to the
17// nearest multiple of 8 to get the number of bits actually in the row.
18// We then divide by 8 to convert to bytes.
19static inline size_t get_src_row_bytes(int width) {
20 return SkAlign8(width) >> 3;
21}
22
23static inline void setup_color_table(SkColorType colorType,
24 SkPMColor* colorPtr, int* colorCount) {
25 if (kIndex_8_SkColorType == colorType) {
26 colorPtr[0] = SK_ColorBLACK;
27 colorPtr[1] = SK_ColorWHITE;
28 *colorCount = 2;
29 }
30}
31
halcanarya096d7a2015-03-27 12:16:53 -070032// http://en.wikipedia.org/wiki/Variable-length_quantity
33static bool read_mbf(SkStream* stream, uint64_t* value) {
34 uint64_t n = 0;
35 uint8_t data;
36 const uint64_t kLimit = 0xFE00000000000000;
37 SkASSERT(kLimit == ~((~static_cast<uint64_t>(0)) >> 7));
38 do {
39 if (n & kLimit) { // Will overflow on shift by 7.
40 return false;
41 }
42 if (stream->read(&data, 1) != 1) {
43 return false;
44 }
45 n = (n << 7) | (data & 0x7F);
46 } while (data & 0x80);
47 *value = n;
48 return true;
49}
50
51static bool read_header(SkStream* stream, SkISize* size) {
52 uint64_t width, height;
53 uint16_t data;
54 if (stream->read(&data, 2) != 2 || data != 0) {
55 return false;
56 }
57 if (!read_mbf(stream, &width) || width > 0xFFFF || !width) {
58 return false;
59 }
msarett99f567e2015-08-05 12:58:26 -070060 if (!read_mbf(stream, &height) || height > 0xFFFF || !height) {
halcanarya096d7a2015-03-27 12:16:53 -070061 return false;
62 }
63 if (size) {
64 *size = SkISize::Make(SkToS32(width), SkToS32(height));
65 }
66 return true;
67}
68
msarett99f567e2015-08-05 12:58:26 -070069bool SkWbmpCodec::handleRewind() {
70 SkCodec::RewindState rewindState = this->rewindIfNeeded();
71 if (rewindState == kCouldNotRewind_RewindState) {
72 return false;
73 } else if (rewindState == kRewound_RewindState) {
74 if (!read_header(this->stream(), NULL)) {
75 return false;
halcanarya096d7a2015-03-27 12:16:53 -070076 }
halcanarya096d7a2015-03-27 12:16:53 -070077 }
msarett99f567e2015-08-05 12:58:26 -070078 return true;
79}
80
81SkSwizzler* SkWbmpCodec::initializeSwizzler(const SkImageInfo& info,
82 const SkPMColor* ctable, const Options& opts) {
83 // TODO (msarett): Reenable support for 565 if it is desired
84 // skbug.com/3683
85
86 // Create the swizzler based on the desired color type
87 switch (info.colorType()) {
88 case kIndex_8_SkColorType:
89 case kN32_SkColorType:
90 case kGray_8_SkColorType:
91 return SkSwizzler::CreateSwizzler(
92 SkSwizzler::kBit, ctable, info, opts.fZeroInitialized);
93 default:
94 return NULL;
halcanarya096d7a2015-03-27 12:16:53 -070095 }
96}
97
msarett99f567e2015-08-05 12:58:26 -070098SkCodec::Result SkWbmpCodec::readRow(uint8_t* row) {
99 if (this->stream()->read(row, fSrcRowBytes) != fSrcRowBytes) {
100 return kIncompleteInput;
101 }
102 return kSuccess;
103}
104
halcanarya096d7a2015-03-27 12:16:53 -0700105SkWbmpCodec::SkWbmpCodec(const SkImageInfo& info, SkStream* stream)
msarett99f567e2015-08-05 12:58:26 -0700106 : INHERITED(info, stream)
107 , fSrcRowBytes(get_src_row_bytes(this->getInfo().width()))
108{}
halcanarya096d7a2015-03-27 12:16:53 -0700109
110SkEncodedFormat SkWbmpCodec::onGetEncodedFormat() const {
111 return kWBMP_SkEncodedFormat;
112}
113
scroggoeb602a52015-07-09 08:16:03 -0700114SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info,
msarett99f567e2015-08-05 12:58:26 -0700115 void* dst,
scroggoeb602a52015-07-09 08:16:03 -0700116 size_t rowBytes,
scroggob636b452015-07-22 07:16:20 -0700117 const Options& options,
scroggoeb602a52015-07-09 08:16:03 -0700118 SkPMColor ctable[],
119 int* ctableCount) {
msarett99f567e2015-08-05 12:58:26 -0700120 if (!this->handleRewind()) {
scroggoeb602a52015-07-09 08:16:03 -0700121 return kCouldNotRewind;
halcanarya096d7a2015-03-27 12:16:53 -0700122 }
scroggob636b452015-07-22 07:16:20 -0700123 if (options.fSubset) {
124 // Subsets are not supported.
125 return kUnimplemented;
126 }
halcanarya096d7a2015-03-27 12:16:53 -0700127 if (info.dimensions() != this->getInfo().dimensions()) {
scroggoeb602a52015-07-09 08:16:03 -0700128 return kInvalidScale;
halcanarya096d7a2015-03-27 12:16:53 -0700129 }
msarett99f567e2015-08-05 12:58:26 -0700130
131 // Prepare a color table if necessary
132 setup_color_table(info.colorType(), ctable, ctableCount);
133
134
135 // Initialize the swizzler
136 SkAutoTDelete<SkSwizzler> swizzler(this->initializeSwizzler(info, ctable, options));
137 if (NULL == swizzler.get()) {
138 return kInvalidConversion;
halcanarya096d7a2015-03-27 12:16:53 -0700139 }
msarett99f567e2015-08-05 12:58:26 -0700140
141 // Perform the decode
halcanarya096d7a2015-03-27 12:16:53 -0700142 SkISize size = info.dimensions();
msarett99f567e2015-08-05 12:58:26 -0700143 SkAutoTMalloc<uint8_t> src(fSrcRowBytes);
144 void* dstRow = dst;
halcanarya096d7a2015-03-27 12:16:53 -0700145 for (int y = 0; y < size.height(); ++y) {
msarett99f567e2015-08-05 12:58:26 -0700146 Result rowResult = this->readRow(src.get());
147 if (kSuccess != rowResult) {
148 return rowResult;
halcanarya096d7a2015-03-27 12:16:53 -0700149 }
msarett99f567e2015-08-05 12:58:26 -0700150 swizzler->swizzle(dstRow, src.get());
151 dstRow = SkTAddOffset<void>(dstRow, rowBytes);
halcanarya096d7a2015-03-27 12:16:53 -0700152 }
scroggoeb602a52015-07-09 08:16:03 -0700153 return kSuccess;
halcanarya096d7a2015-03-27 12:16:53 -0700154}
155
156bool SkWbmpCodec::IsWbmp(SkStream* stream) {
157 return read_header(stream, NULL);
158}
159
160SkCodec* SkWbmpCodec::NewFromStream(SkStream* stream) {
scroggo0a7e69c2015-04-03 07:22:22 -0700161 SkAutoTDelete<SkStream> streamDeleter(stream);
halcanarya096d7a2015-03-27 12:16:53 -0700162 SkISize size;
163 if (!read_header(stream, &size)) {
164 return NULL;
165 }
msarett99f567e2015-08-05 12:58:26 -0700166 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(),
167 kGray_8_SkColorType, kOpaque_SkAlphaType);
scroggo0a7e69c2015-04-03 07:22:22 -0700168 return SkNEW_ARGS(SkWbmpCodec, (info, streamDeleter.detach()));
halcanarya096d7a2015-03-27 12:16:53 -0700169}
msarett99f567e2015-08-05 12:58:26 -0700170
171class SkWbmpScanlineDecoder : public SkScanlineDecoder {
172public:
173 /*
174 * Takes ownership of all pointer paramters.
175 */
176 SkWbmpScanlineDecoder(SkWbmpCodec* codec)
177 : INHERITED(codec->getInfo())
178 , fCodec(codec)
179 , fColorTable(NULL)
180 , fSwizzler(NULL)
181 , fSrcBuffer(codec->fSrcRowBytes)
182 {}
183
184 SkCodec::Result onGetScanlines(void* dst, int count, size_t dstRowBytes) override {
185 void* dstRow = dst;
186 for (int y = 0; y < count; ++y) {
187 SkCodec::Result rowResult = fCodec->readRow(fSrcBuffer.get());
188 if (SkCodec::kSuccess != rowResult) {
189 return rowResult;
190 }
191 fSwizzler->swizzle(dstRow, fSrcBuffer.get());
192 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
193 }
194 return SkCodec::kSuccess;
195 }
196
197 SkCodec::Result onStart(const SkImageInfo& dstInfo,
198 const SkCodec::Options& options, SkPMColor inputColorTable[],
199 int* inputColorCount) {
200 if (!fCodec->handleRewind()) {
201 return SkCodec::kCouldNotRewind;
202 }
203 if (options.fSubset) {
204 // Subsets are not supported.
205 return SkCodec::kUnimplemented;
206 }
207 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
208 return SkCodec::kInvalidScale;
209 }
210
211 // Fill in the color table
212 setup_color_table(dstInfo.colorType(), inputColorTable, inputColorCount);
213
214 // Copy the color table to a pointer that can be owned by the scanline decoder
215 if (kIndex_8_SkColorType == dstInfo.colorType()) {
216 fColorTable.reset(SkNEW_ARGS(SkColorTable, (inputColorTable, 2)));
217 }
218
219 // Initialize the swizzler
220 fSwizzler.reset(fCodec->initializeSwizzler(dstInfo,
221 get_color_ptr(fColorTable.get()), options));
222 if (NULL == fSwizzler.get()) {
223 return SkCodec::kInvalidInput;
224 }
225
226 return SkCodec::kSuccess;
227 }
228
229private:
230 SkAutoTDelete<SkWbmpCodec> fCodec;
231 SkAutoTUnref<SkColorTable> fColorTable;
232 SkAutoTDelete<SkSwizzler> fSwizzler;
233 SkAutoTMalloc<uint8_t> fSrcBuffer;
234
235 typedef SkScanlineDecoder INHERITED;
236};
237
238SkScanlineDecoder* SkWbmpCodec::NewSDFromStream(SkStream* stream) {
239 SkAutoTDelete<SkWbmpCodec> codec(static_cast<SkWbmpCodec*>(
240 SkWbmpCodec::NewFromStream(stream)));
241 if (!codec) {
242 return NULL;
243 }
244
245 // Return the new scanline decoder
246 return SkNEW_ARGS(SkWbmpScanlineDecoder, (codec.detach()));
247}