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 "SkBmpRLECodec.h" | 8 #include "SkBmpRLECodec.h" |
9 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
(...skipping 20 matching lines...) Expand all Loading... |
31 , fSampleX(1) | 31 , fSampleX(1) |
32 {} | 32 {} |
33 | 33 |
34 /* | 34 /* |
35 * Initiates the bitmap decode | 35 * Initiates the bitmap decode |
36 */ | 36 */ |
37 SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, | 37 SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, |
38 void* dst, size_t dstRowBytes, | 38 void* dst, size_t dstRowBytes, |
39 const Options& opts, | 39 const Options& opts, |
40 SkPMColor* inputColorPtr, | 40 SkPMColor* inputColorPtr, |
41 int* inputColorCount) { | 41 int* inputColorCount, |
| 42 int* rowsDecoded) { |
42 if (opts.fSubset) { | 43 if (opts.fSubset) { |
43 // Subsets are not supported. | 44 // Subsets are not supported. |
44 return kUnimplemented; | 45 return kUnimplemented; |
45 } | 46 } |
46 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 47 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
47 SkCodecPrintf("Error: scaling not supported.\n"); | 48 SkCodecPrintf("Error: scaling not supported.\n"); |
48 return kInvalidScale; | 49 return kInvalidScale; |
49 } | 50 } |
50 if (!conversion_possible(dstInfo, this->getInfo())) { | 51 if (!conversion_possible(dstInfo, this->getInfo())) { |
51 SkCodecPrintf("Error: cannot convert input type to output type.\n"); | 52 SkCodecPrintf("Error: cannot convert input type to output type.\n"); |
52 return kInvalidConversion; | 53 return kInvalidConversion; |
53 } | 54 } |
54 | 55 |
55 Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputCol
orCount); | 56 Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputCol
orCount); |
56 if (kSuccess != result) { | 57 if (kSuccess != result) { |
57 return result; | 58 return result; |
58 } | 59 } |
59 | 60 |
60 // Perform the decode | 61 // Perform the decode |
61 return this->decodeRows(dstInfo, dst, dstRowBytes, opts); | 62 uint32_t rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts); |
| 63 if (rows != dstInfo.height()) { |
| 64 // We set rowsDecoded equal to the height because the background has alr
eady |
| 65 // been filled. RLE encodings sometimes skip pixels, so we always start
by |
| 66 // filling the background. |
| 67 *rowsDecoded = dstInfo.height(); |
| 68 return kIncompleteInput; |
| 69 } |
62 } | 70 } |
63 | 71 |
64 /* | 72 /* |
65 * Process the color table for the bmp input | 73 * Process the color table for the bmp input |
66 */ | 74 */ |
67 bool SkBmpRLECodec::createColorTable(int* numColors) { | 75 bool SkBmpRLECodec::createColorTable(int* numColors) { |
68 // Allocate memory for color table | 76 // Allocate memory for color table |
69 uint32_t colorBytes = 0; | 77 uint32_t colorBytes = 0; |
70 SkPMColor colorTable[256]; | 78 SkPMColor colorTable[256]; |
71 if (this->bitsPerPixel() <= 8) { | 79 if (this->bitsPerPixel() <= 8) { |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
271 | 279 |
272 SkScaledCodec::ComputeSampleSize(dstInfo, this->getInfo(), &fSampleX, NULL); | 280 SkScaledCodec::ComputeSampleSize(dstInfo, this->getInfo(), &fSampleX, NULL); |
273 | 281 |
274 return SkCodec::kSuccess; | 282 return SkCodec::kSuccess; |
275 } | 283 } |
276 | 284 |
277 /* | 285 /* |
278 * Performs the bitmap decoding for RLE input format | 286 * Performs the bitmap decoding for RLE input format |
279 * RLE decoding is performed all at once, rather than a one row at a time | 287 * RLE decoding is performed all at once, rather than a one row at a time |
280 */ | 288 */ |
281 SkCodec::Result SkBmpRLECodec::decodeRows(const SkImageInfo& dstInfo, | 289 uint32_t SkBmpRLECodec::decodeRows(const SkImageInfo& dstInfo, void* dst, size_t
dstRowBytes, |
282 void* dst, size_t dstRowBytes, | 290 const Options& opts) { |
283 const Options& opts) { | |
284 // Set RLE flags | 291 // Set RLE flags |
285 static const uint8_t RLE_ESCAPE = 0; | 292 static const uint8_t RLE_ESCAPE = 0; |
286 static const uint8_t RLE_EOL = 0; | 293 static const uint8_t RLE_EOL = 0; |
287 static const uint8_t RLE_EOF = 1; | 294 static const uint8_t RLE_EOF = 1; |
288 static const uint8_t RLE_DELTA = 2; | 295 static const uint8_t RLE_DELTA = 2; |
289 | 296 |
290 // Set constant values | 297 // Set constant values |
291 const int width = this->getInfo().width(); | 298 const int width = this->getInfo().width(); |
292 const int height = dstInfo.height(); | 299 const int height = dstInfo.height(); |
293 | 300 |
294 // Destination parameters | 301 // Destination parameters |
295 int x = 0; | 302 int x = 0; |
296 int y = 0; | 303 int y = 0; |
297 | 304 |
298 // Set the background as transparent. Then, if the RLE code skips pixels, | 305 // Set the background as transparent. Then, if the RLE code skips pixels, |
299 // the skipped pixels will be transparent. | 306 // the skipped pixels will be transparent. |
300 // Because of the need for transparent pixels, kN32 is the only color | 307 // Because of the need for transparent pixels, kN32 is the only color |
301 // type that makes sense for the destination format. | 308 // type that makes sense for the destination format. |
302 SkASSERT(kN32_SkColorType == dstInfo.colorType()); | 309 SkASSERT(kN32_SkColorType == dstInfo.colorType()); |
303 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, height, SK_ColorTRANSPARENT, | 310 SkSwizzler::Fill(dst, dstInfo, dstRowBytes, SK_ColorTRANSPARENT, opts.fZeroI
nitialized); |
304 NULL, opts.fZeroInitialized); | |
305 | 311 |
306 while (true) { | 312 while (true) { |
307 // If we have reached a row that is beyond the requested height, we have | 313 // If we have reached a row that is beyond the requested height, we have |
308 // succeeded. | 314 // succeeded. |
309 if (y >= height) { | 315 if (y >= height) { |
310 // It would be better to check for the EOF marker before returning | 316 // It would be better to check for the EOF marker before indicating |
311 // success, but we may be performing a scanline decode, which | 317 // success, but we may be performing a scanline decode, which |
312 // may require us to stop before decoding the full height. | 318 // would require us to stop before decoding the full height. |
313 return kSuccess; | 319 return height; |
314 } | 320 } |
315 | 321 |
316 // Every entry takes at least two bytes | 322 // Every entry takes at least two bytes |
317 if ((int) fRLEBytes - fCurrRLEByte < 2) { | 323 if ((int) fRLEBytes - fCurrRLEByte < 2) { |
318 SkCodecPrintf("Warning: might be incomplete RLE input.\n"); | 324 SkCodecPrintf("Warning: might be incomplete RLE input.\n"); |
319 if (this->checkForMoreData() < 2) { | 325 if (this->checkForMoreData() < 2) { |
320 return kIncompleteInput; | 326 return y; |
321 } | 327 } |
322 } | 328 } |
323 | 329 |
324 // Read the next two bytes. These bytes have different meanings | 330 // Read the next two bytes. These bytes have different meanings |
325 // depending on their values. In the first interpretation, the first | 331 // depending on their values. In the first interpretation, the first |
326 // byte is an escape flag and the second byte indicates what special | 332 // byte is an escape flag and the second byte indicates what special |
327 // task to perform. | 333 // task to perform. |
328 const uint8_t flag = fStreamBuffer.get()[fCurrRLEByte++]; | 334 const uint8_t flag = fStreamBuffer.get()[fCurrRLEByte++]; |
329 const uint8_t task = fStreamBuffer.get()[fCurrRLEByte++]; | 335 const uint8_t task = fStreamBuffer.get()[fCurrRLEByte++]; |
330 | 336 |
331 // Perform decoding | 337 // Perform decoding |
332 if (RLE_ESCAPE == flag) { | 338 if (RLE_ESCAPE == flag) { |
333 switch (task) { | 339 switch (task) { |
334 case RLE_EOL: | 340 case RLE_EOL: |
335 x = 0; | 341 x = 0; |
336 y++; | 342 y++; |
337 break; | 343 break; |
338 case RLE_EOF: | 344 case RLE_EOF: |
339 return kSuccess; | 345 return kSuccess; |
340 case RLE_DELTA: { | 346 case RLE_DELTA: { |
341 // Two bytes are needed to specify delta | 347 // Two bytes are needed to specify delta |
342 if ((int) fRLEBytes - fCurrRLEByte < 2) { | 348 if ((int) fRLEBytes - fCurrRLEByte < 2) { |
343 SkCodecPrintf("Warning: might be incomplete RLE input.\n
"); | 349 SkCodecPrintf("Warning: might be incomplete RLE input.\n
"); |
344 if (this->checkForMoreData() < 2) { | 350 if (this->checkForMoreData() < 2) { |
345 return kIncompleteInput; | 351 return y; |
346 } | 352 } |
347 } | 353 } |
348 // Modify x and y | 354 // Modify x and y |
349 const uint8_t dx = fStreamBuffer.get()[fCurrRLEByte++]; | 355 const uint8_t dx = fStreamBuffer.get()[fCurrRLEByte++]; |
350 const uint8_t dy = fStreamBuffer.get()[fCurrRLEByte++]; | 356 const uint8_t dy = fStreamBuffer.get()[fCurrRLEByte++]; |
351 x += dx; | 357 x += dx; |
352 y += dy; | 358 y += dy; |
353 if (x > width || y > height) { | 359 if (x > width || y > height) { |
354 SkCodecPrintf("Warning: invalid RLE input.\n"); | 360 SkCodecPrintf("Warning: invalid RLE input.\n"); |
355 return kInvalidInput; | 361 return y - dy; |
356 } | 362 } |
357 break; | 363 break; |
358 } | 364 } |
359 default: { | 365 default: { |
360 // If task does not match any of the above signals, it | 366 // If task does not match any of the above signals, it |
361 // indicates that we have a sequence of non-RLE pixels. | 367 // indicates that we have a sequence of non-RLE pixels. |
362 // Furthermore, the value of task is equal to the number | 368 // Furthermore, the value of task is equal to the number |
363 // of pixels to interpret. | 369 // of pixels to interpret. |
364 uint8_t numPixels = task; | 370 uint8_t numPixels = task; |
365 const size_t rowBytes = compute_row_bytes(numPixels, | 371 const size_t rowBytes = compute_row_bytes(numPixels, |
366 this->bitsPerPixel()); | 372 this->bitsPerPixel()); |
367 // Abort if setting numPixels moves us off the edge of the | 373 // Abort if setting numPixels moves us off the edge of the |
368 // image. | 374 // image. |
369 if (x + numPixels > width) { | 375 if (x + numPixels > width) { |
370 SkCodecPrintf("Warning: invalid RLE input.\n"); | 376 SkCodecPrintf("Warning: invalid RLE input.\n"); |
371 return kInvalidInput; | 377 return y; |
372 } | 378 } |
373 // Also abort if there are not enough bytes | 379 // Also abort if there are not enough bytes |
374 // remaining in the stream to set numPixels. | 380 // remaining in the stream to set numPixels. |
375 if ((int) fRLEBytes - fCurrRLEByte < SkAlign2(rowBytes)) { | 381 if ((int) fRLEBytes - fCurrRLEByte < SkAlign2(rowBytes)) { |
376 SkCodecPrintf("Warning: might be incomplete RLE input.\n
"); | 382 SkCodecPrintf("Warning: might be incomplete RLE input.\n
"); |
377 if (this->checkForMoreData() < SkAlign2(rowBytes)) { | 383 if (this->checkForMoreData() < SkAlign2(rowBytes)) { |
378 return kIncompleteInput; | 384 return y; |
379 } | 385 } |
380 } | 386 } |
381 // Set numPixels number of pixels | 387 // Set numPixels number of pixels |
382 while (numPixels > 0) { | 388 while (numPixels > 0) { |
383 switch(this->bitsPerPixel()) { | 389 switch(this->bitsPerPixel()) { |
384 case 4: { | 390 case 4: { |
385 SkASSERT(fCurrRLEByte < fRLEBytes); | 391 SkASSERT(fCurrRLEByte < fRLEBytes); |
386 uint8_t val = fStreamBuffer.get()[fCurrRLEByte++
]; | 392 uint8_t val = fStreamBuffer.get()[fCurrRLEByte++
]; |
387 setPixel(dst, dstRowBytes, dstInfo, x++, | 393 setPixel(dst, dstRowBytes, dstInfo, x++, |
388 y, val >> 4); | 394 y, val >> 4); |
(...skipping 15 matching lines...) Expand all Loading... |
404 SkASSERT(fCurrRLEByte + 2 < fRLEBytes); | 410 SkASSERT(fCurrRLEByte + 2 < fRLEBytes); |
405 uint8_t blue = fStreamBuffer.get()[fCurrRLEByte+
+]; | 411 uint8_t blue = fStreamBuffer.get()[fCurrRLEByte+
+]; |
406 uint8_t green = fStreamBuffer.get()[fCurrRLEByte
++]; | 412 uint8_t green = fStreamBuffer.get()[fCurrRLEByte
++]; |
407 uint8_t red = fStreamBuffer.get()[fCurrRLEByte++
]; | 413 uint8_t red = fStreamBuffer.get()[fCurrRLEByte++
]; |
408 setRGBPixel(dst, dstRowBytes, dstInfo, | 414 setRGBPixel(dst, dstRowBytes, dstInfo, |
409 x++, y, red, green, blue); | 415 x++, y, red, green, blue); |
410 numPixels--; | 416 numPixels--; |
411 } | 417 } |
412 default: | 418 default: |
413 SkASSERT(false); | 419 SkASSERT(false); |
414 return kInvalidInput; | 420 return y; |
415 } | 421 } |
416 } | 422 } |
417 // Skip a byte if necessary to maintain alignment | 423 // Skip a byte if necessary to maintain alignment |
418 if (!SkIsAlign2(rowBytes)) { | 424 if (!SkIsAlign2(rowBytes)) { |
419 fCurrRLEByte++; | 425 fCurrRLEByte++; |
420 } | 426 } |
421 break; | 427 break; |
422 } | 428 } |
423 } | 429 } |
424 } else { | 430 } else { |
425 // If the first byte read is not a flag, it indicates the number of | 431 // If the first byte read is not a flag, it indicates the number of |
426 // pixels to set in RLE mode. | 432 // pixels to set in RLE mode. |
427 const uint8_t numPixels = flag; | 433 const uint8_t numPixels = flag; |
428 const int endX = SkTMin<int>(x + numPixels, width); | 434 const int endX = SkTMin<int>(x + numPixels, width); |
429 | 435 |
430 if (24 == this->bitsPerPixel()) { | 436 if (24 == this->bitsPerPixel()) { |
431 // In RLE24, the second byte read is part of the pixel color. | 437 // In RLE24, the second byte read is part of the pixel color. |
432 // There are two more required bytes to finish encoding the | 438 // There are two more required bytes to finish encoding the |
433 // color. | 439 // color. |
434 if ((int) fRLEBytes - fCurrRLEByte < 2) { | 440 if ((int) fRLEBytes - fCurrRLEByte < 2) { |
435 SkCodecPrintf("Warning: might be incomplete RLE input.\n"); | 441 SkCodecPrintf("Warning: might be incomplete RLE input.\n"); |
436 if (this->checkForMoreData() < 2) { | 442 if (this->checkForMoreData() < 2) { |
437 return kIncompleteInput; | 443 return y; |
438 } | 444 } |
439 } | 445 } |
440 | 446 |
441 // Fill the pixels up to endX with the specified color | 447 // Fill the pixels up to endX with the specified color |
442 uint8_t blue = task; | 448 uint8_t blue = task; |
443 uint8_t green = fStreamBuffer.get()[fCurrRLEByte++]; | 449 uint8_t green = fStreamBuffer.get()[fCurrRLEByte++]; |
444 uint8_t red = fStreamBuffer.get()[fCurrRLEByte++]; | 450 uint8_t red = fStreamBuffer.get()[fCurrRLEByte++]; |
445 while (x < endX) { | 451 while (x < endX) { |
446 setRGBPixel(dst, dstRowBytes, dstInfo, x++, y, red, green, b
lue); | 452 setRGBPixel(dst, dstRowBytes, dstInfo, x++, y, red, green, b
lue); |
447 } | 453 } |
(...skipping 11 matching lines...) Expand all Loading... |
459 | 465 |
460 // Set the indicated number of pixels | 466 // Set the indicated number of pixels |
461 for (int which = 0; x < endX; x++) { | 467 for (int which = 0; x < endX; x++) { |
462 setPixel(dst, dstRowBytes, dstInfo, x, y, indices[which]); | 468 setPixel(dst, dstRowBytes, dstInfo, x, y, indices[which]); |
463 which = !which; | 469 which = !which; |
464 } | 470 } |
465 } | 471 } |
466 } | 472 } |
467 } | 473 } |
468 } | 474 } |
OLD | NEW |