OLD | NEW |
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" |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 } | 46 } |
47 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 47 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
48 SkCodecPrintf("Error: scaling not supported.\n"); | 48 SkCodecPrintf("Error: scaling not supported.\n"); |
49 return kInvalidScale; | 49 return kInvalidScale; |
50 } | 50 } |
51 if (!conversion_possible(dstInfo, this->getInfo())) { | 51 if (!conversion_possible(dstInfo, this->getInfo())) { |
52 SkCodecPrintf("Error: cannot convert input type to output type.\n"); | 52 SkCodecPrintf("Error: cannot convert input type to output type.\n"); |
53 return kInvalidConversion; | 53 return kInvalidConversion; |
54 } | 54 } |
55 | 55 |
56 // Create the color table if necessary and prepare the stream for decode | 56 Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputCol
orCount); |
57 // Note that if it is non-NULL, inputColorCount will be modified | 57 if (kSuccess != result) { |
58 if (!this->createColorTable(dstInfo.alphaType(), inputColorCount)) { | 58 return result; |
59 SkCodecPrintf("Error: could not create color table.\n"); | |
60 return kInvalidInput; | |
61 } | |
62 | |
63 // Copy the color table to the client if necessary | |
64 copy_color_table(dstInfo, fColorTable, inputColorPtr, inputColorCount); | |
65 | |
66 // Initialize a swizzler if necessary | |
67 if (!this->initializeSwizzler(dstInfo, opts)) { | |
68 SkCodecPrintf("Error: cannot initialize swizzler.\n"); | |
69 return kInvalidConversion; | |
70 } | 59 } |
71 | 60 |
72 return this->decode(dstInfo, dst, dstRowBytes, opts); | 61 return this->decode(dstInfo, dst, dstRowBytes, opts); |
73 } | 62 } |
74 | 63 |
75 /* | 64 /* |
76 * Process the color table for the bmp input | 65 * Process the color table for the bmp input |
77 */ | 66 */ |
78 bool SkBmpStandardCodec::createColorTable(SkAlphaType alphaType, int* numColors
) { | 67 bool SkBmpStandardCodec::createColorTable(SkAlphaType alphaType, int* numColors
) { |
79 // Allocate memory for color table | 68 // Allocate memory for color table |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 } | 152 } |
164 } | 153 } |
165 | 154 |
166 // Return true on success | 155 // Return true on success |
167 return true; | 156 return true; |
168 } | 157 } |
169 | 158 |
170 bool SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo, | 159 bool SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo, |
171 const Options& opts) { | 160 const Options& opts) { |
172 // Allocate space for a row buffer | 161 // Allocate space for a row buffer |
173 const size_t rowBytes = SkAlign4(compute_row_bytes(dstInfo.width(), this->bi
tsPerPixel())); | 162 const size_t rowBytes = SkAlign4(compute_row_bytes(this->getInfo().width(), |
| 163 this->bitsPerPixel())); |
174 fSrcBuffer.reset(SkNEW_ARRAY(uint8_t, rowBytes)); | 164 fSrcBuffer.reset(SkNEW_ARRAY(uint8_t, rowBytes)); |
175 | 165 |
176 // Get swizzler configuration | 166 // Get swizzler configuration |
177 SkSwizzler::SrcConfig config; | 167 SkSwizzler::SrcConfig config; |
178 switch (this->bitsPerPixel()) { | 168 switch (this->bitsPerPixel()) { |
179 case 1: | 169 case 1: |
180 config = SkSwizzler::kIndex1; | 170 config = SkSwizzler::kIndex1; |
181 break; | 171 break; |
182 case 2: | 172 case 2: |
183 config = SkSwizzler::kIndex2; | 173 config = SkSwizzler::kIndex2; |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 SkASSERT(false); | 234 SkASSERT(false); |
245 return 0; | 235 return 0; |
246 } | 236 } |
247 return fillColorOrIndex; | 237 return fillColorOrIndex; |
248 } | 238 } |
249 | 239 |
250 /* | 240 /* |
251 * Performs the bitmap decoding for standard input format | 241 * Performs the bitmap decoding for standard input format |
252 */ | 242 */ |
253 SkCodec::Result SkBmpStandardCodec::decode(const SkImageInfo& dstInfo, | 243 SkCodec::Result SkBmpStandardCodec::decode(const SkImageInfo& dstInfo, |
254 void* dst, size_t dstRowBytes, | 244 void* dst, size_t dstRowBytes, |
255 const Options& opts) { | 245 const Options& opts) { |
256 // Set constant values | 246 // Set constant values |
257 const int width = dstInfo.width(); | 247 const int width = this->getInfo().width(); |
258 const int height = dstInfo.height(); | 248 const int height = dstInfo.height(); |
259 const size_t rowBytes = SkAlign4(compute_row_bytes(width, this->bitsPerPixel
())); | 249 const size_t rowBytes = SkAlign4(compute_row_bytes(width, this->bitsPerPixel
())); |
260 | 250 |
261 // Iterate over rows of the image | 251 // Iterate over rows of the image |
262 for (int y = 0; y < height; y++) { | 252 for (int y = 0; y < height; y++) { |
263 // Read a row of the input | 253 // Read a row of the input |
264 if (this->stream()->read(fSrcBuffer.get(), rowBytes) != rowBytes) { | 254 if (this->stream()->read(fSrcBuffer.get(), rowBytes) != rowBytes) { |
265 SkCodecPrintf("Warning: incomplete input stream.\n"); | 255 SkCodecPrintf("Warning: incomplete input stream.\n"); |
266 // Fill the destination image on failure | 256 // Fill the destination image on failure |
267 // Get the fill color/index and check if it is 0 | 257 // Get the fill color/index and check if it is 0 |
268 uint32_t fillColorOrIndex = get_fill_color_or_index(this->bitsPerPix
el(), | 258 uint32_t fillColorOrIndex = get_fill_color_or_index(this->bitsPerPix
el(), |
269 dstInfo.alphaType()); | 259 dstInfo.alphaType()); |
270 bool zeroFill = (0 == fillColorOrIndex); | 260 bool zeroFill = (0 == fillColorOrIndex); |
271 | 261 |
272 if (kNo_ZeroInitialized == opts.fZeroInitialized || !zeroFill) { | 262 if (kNo_ZeroInitialized == opts.fZeroInitialized || !zeroFill) { |
273 // Get a pointer to the color table if it exists | 263 // Get a pointer to the color table if it exists |
274 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); | 264 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); |
275 | 265 |
276 void* dstStart = this->getDstStartRow(dst, dstRowBytes, y); | 266 void* dstStart = this->getDstStartRow(dst, dstRowBytes, y); |
277 SkSwizzler::Fill(dstStart, dstInfo, dstRowBytes, dstInfo.height(
) - y, | 267 SkSwizzler::Fill(dstStart, dstInfo, dstRowBytes, dstInfo.height(
) - y, |
278 fillColorOrIndex, colorPtr); | 268 fillColorOrIndex, colorPtr); |
279 } | 269 } |
280 return kIncompleteInput; | 270 return kIncompleteInput; |
281 } | 271 } |
282 | 272 |
283 // Decode the row in destination format | 273 // Decode the row in destination format |
284 uint32_t row; | 274 uint32_t row = this->getDstRow(y); |
285 if (SkBmpCodec::kTopDown_RowOrder == this->rowOrder()) { | |
286 row = y; | |
287 } else { | |
288 row = height - 1 - y; | |
289 } | |
290 | 275 |
291 void* dstRow = SkTAddOffset<void>(dst, row * dstRowBytes); | 276 void* dstRow = SkTAddOffset<void>(dst, row * dstRowBytes); |
292 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); | 277 fSwizzler->swizzle(dstRow, fSrcBuffer.get()); |
293 } | 278 } |
294 | 279 |
295 // Finally, apply the AND mask for bmp-in-ico images | 280 // Finally, apply the AND mask for bmp-in-ico images |
296 if (fInIco) { | 281 if (fInIco) { |
297 // BMP in ICO have transparency, so this cannot be 565, and this mask | 282 // 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 | 283 // prevents us from using kIndex8. The below code depends on the output |
299 // being an SkPMColor. | 284 // being an SkPMColor. |
300 SkASSERT(dstInfo.colorType() == kN32_SkColorType); | 285 SkASSERT(dstInfo.colorType() == kN32_SkColorType); |
301 | 286 |
302 // The AND mask is always 1 bit per pixel | 287 // The AND mask is always 1 bit per pixel |
303 const size_t rowBytes = SkAlign4(compute_row_bytes(width, 1)); | 288 const size_t rowBytes = SkAlign4(compute_row_bytes(width, 1)); |
304 | 289 |
305 SkPMColor* dstPtr = (SkPMColor*) dst; | 290 SkPMColor* dstPtr = (SkPMColor*) dst; |
306 for (int y = 0; y < height; y++) { | 291 for (int y = 0; y < height; y++) { |
307 // The srcBuffer will at least be large enough | 292 // The srcBuffer will at least be large enough |
308 if (stream()->read(fSrcBuffer.get(), rowBytes) != rowBytes) { | 293 if (stream()->read(fSrcBuffer.get(), rowBytes) != rowBytes) { |
309 SkCodecPrintf("Warning: incomplete AND mask for bmp-in-ico.\n"); | 294 SkCodecPrintf("Warning: incomplete AND mask for bmp-in-ico.\n"); |
310 return kIncompleteInput; | 295 return kIncompleteInput; |
311 } | 296 } |
312 | 297 |
313 int row; | 298 int row = this->getDstRow(y); |
314 if (SkBmpCodec::kBottomUp_RowOrder == this->rowOrder()) { | |
315 row = height - y - 1; | |
316 } else { | |
317 row = y; | |
318 } | |
319 | 299 |
320 SkPMColor* dstRow = | 300 SkPMColor* dstRow = |
321 SkTAddOffset<SkPMColor>(dstPtr, row * dstRowBytes); | 301 SkTAddOffset<SkPMColor>(dstPtr, row * dstRowBytes); |
322 | 302 |
323 for (int x = 0; x < width; x++) { | 303 for (int x = 0; x < width; x++) { |
324 int quotient; | 304 int quotient; |
325 int modulus; | 305 int modulus; |
326 SkTDivMod(x, 8, "ient, &modulus); | 306 SkTDivMod(x, 8, "ient, &modulus); |
327 uint32_t shift = 7 - modulus; | 307 uint32_t shift = 7 - modulus; |
328 uint32_t alphaBit = | 308 uint32_t alphaBit = |
329 (fSrcBuffer.get()[quotient] >> shift) & 0x1; | 309 (fSrcBuffer.get()[quotient] >> shift) & 0x1; |
330 dstRow[x] &= alphaBit - 1; | 310 dstRow[x] &= alphaBit - 1; |
331 } | 311 } |
332 } | 312 } |
333 } | 313 } |
334 | 314 |
335 // Finished decoding the entire image | 315 // Finished decoding the entire image |
336 return kSuccess; | 316 return kSuccess; |
337 } | 317 } |
| 318 |
| 319 SkCodec::Result SkBmpStandardCodec::prepareToDecode(const SkImageInfo& dstInfo, |
| 320 const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputCo
lorCount) { |
| 321 // Create the color table if necessary and prepare the stream for decode |
| 322 // Note that if it is non-NULL, inputColorCount will be modified |
| 323 if (!this->createColorTable(dstInfo.alphaType(), inputColorCount)) { |
| 324 SkCodecPrintf("Error: could not create color table.\n"); |
| 325 return SkCodec::kInvalidInput; |
| 326 } |
| 327 |
| 328 // Copy the color table to the client if necessary |
| 329 copy_color_table(dstInfo, this->fColorTable, inputColorPtr, inputColorCount)
; |
| 330 |
| 331 // Initialize a swizzler if necessary |
| 332 if (!this->initializeSwizzler(dstInfo, options)) { |
| 333 SkCodecPrintf("Error: cannot initialize swizzler.\n"); |
| 334 return SkCodec::kInvalidConversion; |
| 335 } |
| 336 return SkCodec::kSuccess; |
| 337 } |
OLD | NEW |