Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Side by Side Diff: src/codec/SkBmpStandardCodec.cpp

Issue 1287423002: Scanline decoding for bmp (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Fix windows errors Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/codec/SkBmpStandardCodec.h ('k') | src/codec/SkCodecPriv.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkBmpStandardCodec.h" 8 #include "SkBmpStandardCodec.h"
9 #include "SkCodecPriv.h" 9 #include "SkCodecPriv.h"
10 #include "SkColorPriv.h" 10 #include "SkColorPriv.h"
11 #include "SkScanlineDecoder.h" 11 #include "SkScanlineDecoder.h"
12 #include "SkStream.h" 12 #include "SkStream.h"
13 13
14 /* 14 /*
15 * Creates an instance of the decoder 15 * Creates an instance of the decoder
16 * Called only by NewFromStream 16 * Called only by NewFromStream
17 */ 17 */
18 SkBmpStandardCodec::SkBmpStandardCodec(const SkImageInfo& info, SkStream* stream , 18 SkBmpStandardCodec::SkBmpStandardCodec(const SkImageInfo& info, SkStream* stream ,
19 uint16_t bitsPerPixel, uint32_t numColors , 19 uint16_t bitsPerPixel, uint32_t numColors ,
20 uint32_t bytesPerColor, uint32_t offset, 20 uint32_t bytesPerColor, uint32_t offset,
21 SkBmpCodec::RowOrder rowOrder, bool inIco ) 21 SkScanlineDecoder::SkScanlineOrder rowOrd er, bool inIco)
22 : INHERITED(info, stream, bitsPerPixel, rowOrder) 22 : INHERITED(info, stream, bitsPerPixel, rowOrder)
23 , fColorTable(nullptr) 23 , fColorTable(nullptr)
24 , fNumColors(this->computeNumColors(numColors)) 24 , fNumColors(this->computeNumColors(numColors))
25 , fBytesPerColor(bytesPerColor) 25 , fBytesPerColor(bytesPerColor)
26 , fOffset(offset) 26 , fOffset(offset)
27 , fSwizzler(nullptr) 27 , fSwizzler(nullptr)
28 , fSrcBuffer(nullptr) 28 , fSrcRowBytes(SkAlign4(compute_row_bytes(this->getInfo().width(), this->bit sPerPixel())))
29 , fSrcBuffer(new uint8_t [fSrcRowBytes])
29 , fInIco(inIco) 30 , fInIco(inIco)
30 {} 31 {}
31 32
32 /* 33 /*
33 * Initiates the bitmap decode 34 * Initiates the bitmap decode
34 */ 35 */
35 SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, 36 SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo,
36 void* dst, size_t dstRowBytes, 37 void* dst, size_t dstRowBytes,
37 const Options& opts, 38 const Options& opts,
38 SkPMColor* inputColorPtr, 39 SkPMColor* inputColorPtr,
39 int* inputColorCount) { 40 int* inputColorCount) {
40 if (!this->rewindIfNeeded()) { 41 if (!this->rewindIfNeeded()) {
41 return kCouldNotRewind; 42 return kCouldNotRewind;
42 } 43 }
43 if (opts.fSubset) { 44 if (opts.fSubset) {
44 // Subsets are not supported. 45 // Subsets are not supported.
45 return kUnimplemented; 46 return kUnimplemented;
46 } 47 }
47 if (dstInfo.dimensions() != this->getInfo().dimensions()) { 48 if (dstInfo.dimensions() != this->getInfo().dimensions()) {
48 SkCodecPrintf("Error: scaling not supported.\n"); 49 SkCodecPrintf("Error: scaling not supported.\n");
49 return kInvalidScale; 50 return kInvalidScale;
50 } 51 }
51 if (!conversion_possible(dstInfo, this->getInfo())) { 52 if (!conversion_possible(dstInfo, this->getInfo())) {
52 SkCodecPrintf("Error: cannot convert input type to output type.\n"); 53 SkCodecPrintf("Error: cannot convert input type to output type.\n");
53 return kInvalidConversion; 54 return kInvalidConversion;
54 } 55 }
55 56
56 // Create the color table if necessary and prepare the stream for decode 57 Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputCol orCount);
57 // Note that if it is non-nullptr, inputColorCount will be modified 58 if (kSuccess != result) {
58 if (!this->createColorTable(dstInfo.alphaType(), inputColorCount)) { 59 return result;
59 SkCodecPrintf("Error: could not create color table.\n");
60 return kInvalidInput;
61 } 60 }
62 61 result = this->decodeRows(dstInfo, dst, dstRowBytes, opts);
63 // Copy the color table to the client if necessary 62 if (kSuccess != result) {
64 copy_color_table(dstInfo, fColorTable, inputColorPtr, inputColorCount); 63 return result;
65
66 // Initialize a swizzler if necessary
67 if (!this->initializeSwizzler(dstInfo, opts)) {
68 SkCodecPrintf("Error: cannot initialize swizzler.\n");
69 return kInvalidConversion;
70 } 64 }
71 65 if (fInIco) {
72 return this->decode(dstInfo, dst, dstRowBytes, opts); 66 return this->decodeIcoMask(dstInfo, dst, dstRowBytes);
67 }
68 return kSuccess;
73 } 69 }
74 70
75 /* 71 /*
76 * Process the color table for the bmp input 72 * Process the color table for the bmp input
77 */ 73 */
78 bool SkBmpStandardCodec::createColorTable(SkAlphaType alphaType, int* numColors ) { 74 bool SkBmpStandardCodec::createColorTable(SkAlphaType alphaType, int* numColors ) {
79 // Allocate memory for color table 75 // Allocate memory for color table
80 uint32_t colorBytes = 0; 76 uint32_t colorBytes = 0;
81 SkPMColor colorTable[256]; 77 SkPMColor colorTable[256];
82 if (this->bitsPerPixel() <= 8) { 78 if (this->bitsPerPixel() <= 8) {
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 return false; 158 return false;
163 } 159 }
164 } 160 }
165 161
166 // Return true on success 162 // Return true on success
167 return true; 163 return true;
168 } 164 }
169 165
170 bool SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo, 166 bool SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo,
171 const Options& opts) { 167 const Options& opts) {
172 // Allocate space for a row buffer
173 const size_t rowBytes = SkAlign4(compute_row_bytes(dstInfo.width(), this->bi tsPerPixel()));
174 fSrcBuffer.reset(new uint8_t[rowBytes]);
175
176 // Get swizzler configuration 168 // Get swizzler configuration
177 SkSwizzler::SrcConfig config; 169 SkSwizzler::SrcConfig config;
178 switch (this->bitsPerPixel()) { 170 switch (this->bitsPerPixel()) {
179 case 1: 171 case 1:
180 config = SkSwizzler::kIndex1; 172 config = SkSwizzler::kIndex1;
181 break; 173 break;
182 case 2: 174 case 2:
183 config = SkSwizzler::kIndex2; 175 config = SkSwizzler::kIndex2;
184 break; 176 break;
185 case 4: 177 case 4:
(...skipping 23 matching lines...) Expand all
209 // Create swizzler 201 // Create swizzler
210 fSwizzler.reset(SkSwizzler::CreateSwizzler(config, 202 fSwizzler.reset(SkSwizzler::CreateSwizzler(config,
211 colorPtr, dstInfo, opts.fZeroInitialized, this->getInfo())); 203 colorPtr, dstInfo, opts.fZeroInitialized, this->getInfo()));
212 204
213 if (nullptr == fSwizzler.get()) { 205 if (nullptr == fSwizzler.get()) {
214 return false; 206 return false;
215 } 207 }
216 return true; 208 return true;
217 } 209 }
218 210
219 /* 211 SkCodec::Result SkBmpStandardCodec::prepareToDecode(const SkImageInfo& dstInfo,
220 * Choose a fill for failures due to an incomplete image. We will use zero as 212 const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputCo lorCount) {
221 * the default palette index, black for opaque images, and transparent for 213 // Create the color table if necessary and prepare the stream for decode
222 * non-opaque images. 214 // Note that if it is non-NULL, inputColorCount will be modified
223 */ 215 if (!this->createColorTable(dstInfo.alphaType(), inputColorCount)) {
224 static uint32_t get_fill_color_or_index(uint16_t bitsPerPixels, SkAlphaType alph aType) { 216 SkCodecPrintf("Error: could not create color table.\n");
225 uint32_t fillColorOrIndex; 217 return SkCodec::kInvalidInput;
226 switch (bitsPerPixels) {
227 case 1:
228 case 2:
229 case 4:
230 case 8:
231 fillColorOrIndex = 0;
232 break;
233 case 24:
234 fillColorOrIndex = SK_ColorBLACK;
235 break;
236 case 32:
237 if (kOpaque_SkAlphaType == alphaType) {
238 fillColorOrIndex = SK_ColorBLACK;
239 } else {
240 fillColorOrIndex = SK_ColorTRANSPARENT;
241 }
242 break;
243 default:
244 SkASSERT(false);
245 return 0;
246 } 218 }
247 return fillColorOrIndex; 219
220 // Copy the color table to the client if necessary
221 copy_color_table(dstInfo, this->fColorTable, inputColorPtr, inputColorCount) ;
222
223 // Initialize a swizzler if necessary
224 if (!this->initializeSwizzler(dstInfo, options)) {
225 SkCodecPrintf("Error: cannot initialize swizzler.\n");
226 return SkCodec::kInvalidConversion;
227 }
228 return SkCodec::kSuccess;
248 } 229 }
249 230
250 /* 231 /*
251 * Performs the bitmap decoding for standard input format 232 * Performs the bitmap decoding for standard input format
252 */ 233 */
253 SkCodec::Result SkBmpStandardCodec::decode(const SkImageInfo& dstInfo, 234 SkCodec::Result SkBmpStandardCodec::decodeRows(const SkImageInfo& dstInfo,
254 void* dst, size_t dstRowBytes, 235 void* dst, size_t dstRowBytes,
255 const Options& opts) { 236 const Options& opts) {
256 // Set constant values 237 // Iterate over rows of the image
257 const int width = dstInfo.width();
258 const int height = dstInfo.height(); 238 const int height = dstInfo.height();
259 const size_t rowBytes = SkAlign4(compute_row_bytes(width, this->bitsPerPixel ()));
260
261 // Iterate over rows of the image
262 for (int y = 0; y < height; y++) { 239 for (int y = 0; y < height; y++) {
263 // Read a row of the input 240 // Read a row of the input
264 if (this->stream()->read(fSrcBuffer.get(), rowBytes) != rowBytes) { 241 if (this->stream()->read(fSrcBuffer.get(), fSrcRowBytes) != fSrcRowBytes ) {
265 SkCodecPrintf("Warning: incomplete input stream.\n"); 242 SkCodecPrintf("Warning: incomplete input stream.\n");
266 // Fill the destination image on failure 243 // Fill the destination image on failure
267 // Get the fill color/index and check if it is 0 244 void* dstStart = this->getDstStartRow(dst, dstRowBytes, y);
268 uint32_t fillColorOrIndex = get_fill_color_or_index(this->bitsPerPix el(), 245 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
269 dstInfo.alphaType()); 246 uint32_t fillColorOrIndex = get_fill_color_or_index(dstInfo.alphaTyp e());
270 bool zeroFill = (0 == fillColorOrIndex); 247 SkSwizzler::Fill(dstStart, dstInfo, dstRowBytes, dstInfo.height() - y,
271 248 fillColorOrIndex, colorPtr, opts.fZeroInitialized);
272 if (kNo_ZeroInitialized == opts.fZeroInitialized || !zeroFill) {
273 // Get a pointer to the color table if it exists
274 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
275
276 void* dstStart = this->getDstStartRow(dst, dstRowBytes, y);
277 SkSwizzler::Fill(dstStart, dstInfo, dstRowBytes, dstInfo.height( ) - y,
278 fillColorOrIndex, colorPtr);
279 }
280 return kIncompleteInput; 249 return kIncompleteInput;
281 } 250 }
282 251
283 // Decode the row in destination format 252 // Decode the row in destination format
284 uint32_t row; 253 uint32_t row = this->getDstRow(y, dstInfo.height());
285 if (SkBmpCodec::kTopDown_RowOrder == this->rowOrder()) {
286 row = y;
287 } else {
288 row = height - 1 - y;
289 }
290 254
291 void* dstRow = SkTAddOffset<void>(dst, row * dstRowBytes); 255 void* dstRow = SkTAddOffset<void>(dst, row * dstRowBytes);
292 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); 256 fSwizzler->swizzle(dstRow, fSrcBuffer.get());
293 } 257 }
294 258
295 // Finally, apply the AND mask for bmp-in-ico images
296 if (fInIco) {
297 // BMP in ICO have transparency, so this cannot be 565, and this mask
298 // prevents us from using kIndex8. The below code depends on the output
299 // being an SkPMColor.
300 SkASSERT(dstInfo.colorType() == kN32_SkColorType);
301
302 // The AND mask is always 1 bit per pixel
303 const size_t rowBytes = SkAlign4(compute_row_bytes(width, 1));
304
305 SkPMColor* dstPtr = (SkPMColor*) dst;
306 for (int y = 0; y < height; y++) {
307 // The srcBuffer will at least be large enough
308 if (stream()->read(fSrcBuffer.get(), rowBytes) != rowBytes) {
309 SkCodecPrintf("Warning: incomplete AND mask for bmp-in-ico.\n");
310 return kIncompleteInput;
311 }
312
313 int row;
314 if (SkBmpCodec::kBottomUp_RowOrder == this->rowOrder()) {
315 row = height - y - 1;
316 } else {
317 row = y;
318 }
319
320 SkPMColor* dstRow =
321 SkTAddOffset<SkPMColor>(dstPtr, row * dstRowBytes);
322
323 for (int x = 0; x < width; x++) {
324 int quotient;
325 int modulus;
326 SkTDivMod(x, 8, &quotient, &modulus);
327 uint32_t shift = 7 - modulus;
328 uint32_t alphaBit =
329 (fSrcBuffer.get()[quotient] >> shift) & 0x1;
330 dstRow[x] &= alphaBit - 1;
331 }
332 }
333 }
334
335 // Finished decoding the entire image 259 // Finished decoding the entire image
336 return kSuccess; 260 return kSuccess;
337 } 261 }
262
263 // TODO (msarett): This function will need to be modified in order to perform ro w by row decodes
264 // when the Ico scanline decoder is implemented.
265 SkCodec::Result SkBmpStandardCodec::decodeIcoMask(const SkImageInfo& dstInfo,
266 void* dst, size_t dstRowBytes) {
267 // BMP in ICO have transparency, so this cannot be 565, and this mask
268 // prevents us from using kIndex8. The below code depends on the output
269 // being an SkPMColor.
270 SkASSERT(dstInfo.colorType() == kN32_SkColorType);
271
272 // The AND mask is always 1 bit per pixel
273 const int width = this->getInfo().width();
274 const size_t rowBytes = SkAlign4(compute_row_bytes(width, 1));
275
276 SkPMColor* dstPtr = (SkPMColor*) dst;
277 for (int y = 0; y < dstInfo.height(); y++) {
278 // The srcBuffer will at least be large enough
279 if (stream()->read(fSrcBuffer.get(), rowBytes) != rowBytes) {
280 SkCodecPrintf("Warning: incomplete AND mask for bmp-in-ico.\n");
281 return kIncompleteInput;
282 }
283
284 int row = this->getDstRow(y, dstInfo.height());
285
286 SkPMColor* dstRow =
287 SkTAddOffset<SkPMColor>(dstPtr, row * dstRowBytes);
288
289 for (int x = 0; x < width; x++) {
290 int quotient;
291 int modulus;
292 SkTDivMod(x, 8, &quotient, &modulus);
293 uint32_t shift = 7 - modulus;
294 uint32_t alphaBit =
295 (fSrcBuffer.get()[quotient] >> shift) & 0x1;
296 dstRow[x] &= alphaBit - 1;
297 }
298 }
299 return kSuccess;
300 }
OLDNEW
« no previous file with comments | « src/codec/SkBmpStandardCodec.h ('k') | src/codec/SkCodecPriv.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698