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