OLD | NEW |
| (Empty) |
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 "SkCodec_wbmp.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 bool read_byte(SkStream* stream, uint8_t* data) | |
34 { | |
35 return stream->read(data, 1) == 1; | |
36 } | |
37 | |
38 // http://en.wikipedia.org/wiki/Variable-length_quantity | |
39 static bool read_mbf(SkStream* stream, uint64_t* value) { | |
40 uint64_t n = 0; | |
41 uint8_t data; | |
42 const uint64_t kLimit = 0xFE00000000000000; | |
43 SkASSERT(kLimit == ~((~static_cast<uint64_t>(0)) >> 7)); | |
44 do { | |
45 if (n & kLimit) { // Will overflow on shift by 7. | |
46 return false; | |
47 } | |
48 if (stream->read(&data, 1) != 1) { | |
49 return false; | |
50 } | |
51 n = (n << 7) | (data & 0x7F); | |
52 } while (data & 0x80); | |
53 *value = n; | |
54 return true; | |
55 } | |
56 | |
57 static bool read_header(SkStream* stream, SkISize* size) { | |
58 { | |
59 uint8_t data; | |
60 if (!read_byte(stream, &data) || data != 0) { // unknown type | |
61 return false; | |
62 } | |
63 if (!read_byte(stream, &data) || (data & 0x9F)) { // skip fixed header | |
64 return false; | |
65 } | |
66 } | |
67 | |
68 uint64_t width, height; | |
69 if (!read_mbf(stream, &width) || width > 0xFFFF || !width) { | |
70 return false; | |
71 } | |
72 if (!read_mbf(stream, &height) || height > 0xFFFF || !height) { | |
73 return false; | |
74 } | |
75 if (size) { | |
76 *size = SkISize::Make(SkToS32(width), SkToS32(height)); | |
77 } | |
78 return true; | |
79 } | |
80 | |
81 bool SkWbmpCodec::onRewind() { | |
82 return read_header(this->stream(), nullptr); | |
83 } | |
84 | |
85 SkSwizzler* SkWbmpCodec::initializeSwizzler(const SkImageInfo& info, const SkPMC
olor* ctable, | |
86 const Options& opts) { | |
87 // Create the swizzler based on the desired color type | |
88 switch (info.colorType()) { | |
89 case kIndex_8_SkColorType: | |
90 case kN32_SkColorType: | |
91 case kRGB_565_SkColorType: | |
92 case kGray_8_SkColorType: | |
93 break; | |
94 default: | |
95 return nullptr; | |
96 } | |
97 return SkSwizzler::CreateSwizzler(SkSwizzler::kBit, ctable, info, opts); | |
98 } | |
99 | |
100 bool SkWbmpCodec::readRow(uint8_t* row) { | |
101 return this->stream()->read(row, fSrcRowBytes) == fSrcRowBytes; | |
102 } | |
103 | |
104 SkWbmpCodec::SkWbmpCodec(const SkImageInfo& info, SkStream* stream) | |
105 : INHERITED(info, stream) | |
106 , fSrcRowBytes(get_src_row_bytes(this->getInfo().width())) | |
107 , fSwizzler(nullptr) | |
108 , fColorTable(nullptr) | |
109 {} | |
110 | |
111 SkEncodedFormat SkWbmpCodec::onGetEncodedFormat() const { | |
112 return kWBMP_SkEncodedFormat; | |
113 } | |
114 | |
115 SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info, | |
116 void* dst, | |
117 size_t rowBytes, | |
118 const Options& options, | |
119 SkPMColor ctable[], | |
120 int* ctableCount, | |
121 int* rowsDecoded) { | |
122 if (options.fSubset) { | |
123 // Subsets are not supported. | |
124 return kUnimplemented; | |
125 } | |
126 | |
127 if (!valid_alpha(info.alphaType(), this->getInfo().alphaType())) { | |
128 return kInvalidConversion; | |
129 } | |
130 | |
131 // Prepare a color table if necessary | |
132 setup_color_table(info.colorType(), ctable, ctableCount); | |
133 | |
134 // Initialize the swizzler | |
135 SkAutoTDelete<SkSwizzler> swizzler(this->initializeSwizzler(info, ctable, op
tions)); | |
136 if (nullptr == swizzler.get()) { | |
137 return kInvalidConversion; | |
138 } | |
139 | |
140 // Perform the decode | |
141 SkISize size = info.dimensions(); | |
142 SkAutoTMalloc<uint8_t> src(fSrcRowBytes); | |
143 void* dstRow = dst; | |
144 for (int y = 0; y < size.height(); ++y) { | |
145 if (!this->readRow(src.get())) { | |
146 *rowsDecoded = y; | |
147 return kIncompleteInput; | |
148 } | |
149 swizzler->swizzle(dstRow, src.get()); | |
150 dstRow = SkTAddOffset<void>(dstRow, rowBytes); | |
151 } | |
152 return kSuccess; | |
153 } | |
154 | |
155 bool SkWbmpCodec::IsWbmp(const void* buffer, size_t bytesRead) { | |
156 SkAutoTUnref<SkData> data(SkData::NewWithoutCopy(buffer, bytesRead)); | |
157 SkMemoryStream stream(data); | |
158 return read_header(&stream, nullptr); | |
159 } | |
160 | |
161 SkCodec* SkWbmpCodec::NewFromStream(SkStream* stream) { | |
162 SkAutoTDelete<SkStream> streamDeleter(stream); | |
163 SkISize size; | |
164 if (!read_header(stream, &size)) { | |
165 return nullptr; | |
166 } | |
167 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), | |
168 kGray_8_SkColorType, kOpaque_SkAlphaType); | |
169 return new SkWbmpCodec(info, streamDeleter.detach()); | |
170 } | |
171 | |
172 int SkWbmpCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) { | |
173 void* dstRow = dst; | |
174 for (int y = 0; y < count; ++y) { | |
175 if (!this->readRow(fSrcBuffer.get())) { | |
176 return y; | |
177 } | |
178 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); | |
179 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); | |
180 } | |
181 return count; | |
182 } | |
183 | |
184 SkCodec::Result SkWbmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, | |
185 const Options& options, SkPMColor inputColorTable[], int* inputColorCoun
t) { | |
186 if (options.fSubset) { | |
187 // Subsets are not supported. | |
188 return kUnimplemented; | |
189 } | |
190 | |
191 if (!valid_alpha(dstInfo.alphaType(), this->getInfo().alphaType())) { | |
192 return kInvalidConversion; | |
193 } | |
194 | |
195 // Fill in the color table | |
196 setup_color_table(dstInfo.colorType(), inputColorTable, inputColorCount); | |
197 | |
198 // Copy the color table to a pointer that can be owned by the scanline decod
er | |
199 if (kIndex_8_SkColorType == dstInfo.colorType()) { | |
200 fColorTable.reset(new SkColorTable(inputColorTable, 2)); | |
201 } | |
202 | |
203 // Initialize the swizzler | |
204 fSwizzler.reset(this->initializeSwizzler(dstInfo, get_color_ptr(fColorTable.
get()), options)); | |
205 if (nullptr == fSwizzler.get()) { | |
206 return kInvalidConversion; | |
207 } | |
208 | |
209 fSrcBuffer.reset(fSrcRowBytes); | |
210 | |
211 return kSuccess; | |
212 } | |
OLD | NEW |