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 "SkCodec_libbmp.h" | 8 #include "SkCodec_libbmp.h" |
9 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
11 #include "SkStream.h" | 11 #include "SkStream.h" |
12 | 12 |
13 /* | 13 /* |
14 * | 14 * |
15 * Checks if the conversion between the input image and the requested output | 15 * Checks if the conversion between the input image and the requested output |
16 * image has been implemented | 16 * image has been implemented |
17 * | 17 * |
18 */ | 18 */ |
19 static bool conversion_possible(const SkImageInfo& dst, | 19 static bool conversion_possible(const SkImageInfo& dst, |
20 const SkImageInfo& src) { | 20 const SkImageInfo& src) { |
21 // All of the swizzles convert to kN32 | 21 // Check for supported color types |
22 // TODO: Update this when more swizzles are supported | 22 if (kN32_SkColorType != dst.colorType() && |
23 if (kN32_SkColorType != dst.colorType()) { | 23 kRGB_565_SkColorType != dst.colorType()) { |
24 return false; | 24 return false; |
25 } | 25 } |
26 // Support the swizzle if the requested alpha type is the same as our guess | 26 // Support the swizzle if the requested alpha type is the same as our guess |
27 // for the input alpha type | 27 // for the input alpha type |
28 if (src.alphaType() == dst.alphaType()) { | 28 if (src.alphaType() == dst.alphaType()) { |
29 return true; | 29 return true; |
30 } | 30 } |
31 // TODO: Support more swizzles, especially premul | 31 |
32 return false; | 32 // Support premul as the destination when the source is unpremul |
33 return premul_and_unpremul(dst.alphaType(), src.alphaType()); | |
33 } | 34 } |
34 | 35 |
35 /* | 36 /* |
36 * | 37 * |
37 * Defines the version and type of the second bitmap header | 38 * Defines the version and type of the second bitmap header |
38 * | 39 * |
39 */ | 40 */ |
40 enum BitmapHeaderType { | 41 enum BitmapHeaderType { |
41 kInfoV1_BitmapHeaderType, | 42 kInfoV1_BitmapHeaderType, |
42 kInfoV2_BitmapHeaderType, | 43 kInfoV2_BitmapHeaderType, |
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
385 } | 386 } |
386 | 387 |
387 // Check that input bit masks are valid and create the masks object | 388 // Check that input bit masks are valid and create the masks object |
388 SkAutoTDelete<SkMasks> | 389 SkAutoTDelete<SkMasks> |
389 masks(SkMasks::CreateMasks(inputMasks, bitsPerPixel)); | 390 masks(SkMasks::CreateMasks(inputMasks, bitsPerPixel)); |
390 if (NULL == masks) { | 391 if (NULL == masks) { |
391 SkDebugf("Error: invalid input masks.\n"); | 392 SkDebugf("Error: invalid input masks.\n"); |
392 return NULL; | 393 return NULL; |
393 } | 394 } |
394 | 395 |
395 // Process the color table | 396 // Verify the number of colors in the color table |
396 uint32_t colorBytes = 0; | 397 const uint32_t maxColors = 1 << bitsPerPixel; |
scroggo
2015/03/17 13:27:22
Could you move all of this into SkBmpCodec's onGet
msarett
2015/03/17 16:54:05
Doing these checks in onGetPixels actually causes
scroggo
2015/03/17 20:02:58
I think we can get around this...
How about this:
msarett
2015/03/18 13:02:52
Yes great! That's a much better way to do it.
| |
397 SkPMColor* colorTable = NULL; | 398 // Zero is a default for maxColors |
398 if (bitsPerPixel < 16) { | 399 // Also set numColors to maxColors when input is too large |
399 // Verify the number of colors for the color table | 400 if (numColors <= 0 || numColors > maxColors) { |
400 const uint32_t maxColors = 1 << bitsPerPixel; | 401 numColors = maxColors; |
401 // Zero is a default for maxColors | |
402 // Also set numColors to maxColors when input is too large | |
403 if (numColors <= 0 || numColors > maxColors) { | |
404 numColors = maxColors; | |
405 } | |
406 colorTable = SkNEW_ARRAY(SkPMColor, maxColors); | |
407 | |
408 // Construct the color table | |
409 colorBytes = numColors * bytesPerColor; | |
410 SkAutoTDeleteArray<uint8_t> cBuffer(SkNEW_ARRAY(uint8_t, colorBytes)); | |
411 if (stream->read(cBuffer.get(), colorBytes) != colorBytes) { | |
412 SkDebugf("Error: unable to read color table.\n"); | |
413 return NULL; | |
414 } | |
415 | |
416 // Fill in the color table (colors are stored unpremultiplied) | |
417 uint32_t i = 0; | |
418 for (; i < numColors; i++) { | |
419 uint8_t blue = get_byte(cBuffer.get(), i*bytesPerColor); | |
420 uint8_t green = get_byte(cBuffer.get(), i*bytesPerColor + 1); | |
421 uint8_t red = get_byte(cBuffer.get(), i*bytesPerColor + 2); | |
422 uint8_t alpha = 0xFF; | |
423 if (kOpaque_SkAlphaType != alphaType) { | |
424 alpha = (inputMasks.alpha >> 24) & | |
425 get_byte(cBuffer.get(), i*bytesPerColor + 3); | |
426 } | |
427 // Store the unpremultiplied color | |
428 colorTable[i] = SkPackARGB32NoCheck(alpha, red, green, blue); | |
429 } | |
430 | |
431 // To avoid segmentation faults on bad pixel data, fill the end of the | |
432 // color table with black. This is the same the behavior as the | |
433 // chromium decoder. | |
434 for (; i < maxColors; i++) { | |
435 colorTable[i] = SkPackARGB32NoCheck(0xFF, 0, 0, 0); | |
436 } | |
437 } | 402 } |
438 | 403 |
439 // Ensure that the stream now points to the start of the pixel array | 404 // Account for the color table size |
405 uint32_t colorBytes; | |
406 if (bitsPerPixel < 16) { | |
407 colorBytes = numColors * bytesPerColor; | |
408 } else { | |
409 colorBytes = 0; | |
410 } | |
411 | |
412 // Calculate the number of bytes read so far (including the color table) | |
440 uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes + colorBytes; | 413 uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes + colorBytes; |
441 | 414 |
442 // Check that we have not read past the pixel array offset | 415 // Check that we have not read past the pixel array offset |
443 if(bytesRead > offset) { | 416 if(bytesRead > offset) { |
444 // This may occur on OS 2.1 and other old versions where the color | 417 // This may occur on OS 2.1 and other old versions where the color |
445 // table defaults to max size, and the bmp tries to use a smaller color | 418 // table defaults to max size, and the bmp tries to use a smaller color |
446 // table. This is invalid, and our decision is to indicate an error, | 419 // table. This is invalid, and our decision is to indicate an error, |
447 // rather than try to guess the intended size of the color table and | 420 // rather than try to guess the intended size of the color table. |
448 // rewind the stream to display the image. | |
449 SkDebugf("Error: pixel data offset less than header size.\n"); | 421 SkDebugf("Error: pixel data offset less than header size.\n"); |
450 return NULL; | 422 return NULL; |
451 } | 423 } |
452 | 424 |
453 // Skip to the start of the pixel array | |
454 if (stream->skip(offset - bytesRead) != offset - bytesRead) { | |
455 SkDebugf("Error: unable to skip to image data.\n"); | |
456 return NULL; | |
457 } | |
458 | |
459 // Remaining bytes is only used for RLE | 425 // Remaining bytes is only used for RLE |
460 const int remainingBytes = totalBytes - offset; | 426 const int remainingBytes = totalBytes - offset; |
461 if (remainingBytes <= 0 && kRLE_BitmapInputFormat == inputFormat) { | 427 if (remainingBytes <= 0 && kRLE_BitmapInputFormat == inputFormat) { |
462 SkDebugf("Error: RLE requires valid input size.\n"); | 428 SkDebugf("Error: RLE requires valid input size.\n"); |
463 return NULL; | 429 return NULL; |
464 } | 430 } |
465 | 431 |
466 // Return the codec | 432 // Return the codec |
467 // We will use ImageInfo to store width, height, and alpha type. We will | 433 // We will use ImageInfo to store width, height, and alpha type. We will |
468 // choose kN32_SkColorType as the input color type because that is the | 434 // set color type to kN32_SkColorType because that should be the default |
469 // expected choice for a destination color type. In reality, the input | 435 // output. |
470 // color type has many possible formats. | |
471 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height, | 436 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height, |
472 kN32_SkColorType, alphaType); | 437 kN32_SkColorType, alphaType); |
473 return SkNEW_ARGS(SkBmpCodec, (imageInfo, stream, bitsPerPixel, | 438 return SkNEW_ARGS(SkBmpCodec, (imageInfo, stream, bitsPerPixel, |
474 inputFormat, masks.detach(), colorTable, | 439 inputFormat, masks.detach(), numColors, |
440 bytesPerColor, offset - bytesRead, | |
475 rowOrder, remainingBytes)); | 441 rowOrder, remainingBytes)); |
476 } | 442 } |
477 | 443 |
478 /* | 444 /* |
479 * | 445 * |
480 * Creates an instance of the decoder | 446 * Creates an instance of the decoder |
481 * Called only by NewFromStream | 447 * Called only by NewFromStream |
482 * | 448 * |
483 */ | 449 */ |
484 SkBmpCodec::SkBmpCodec(const SkImageInfo& info, SkStream* stream, | 450 SkBmpCodec::SkBmpCodec(const SkImageInfo& info, SkStream* stream, |
485 uint16_t bitsPerPixel, BitmapInputFormat inputFormat, | 451 uint16_t bitsPerPixel, BitmapInputFormat inputFormat, |
486 SkMasks* masks, SkPMColor* colorTable, | 452 SkMasks* masks, uint32_t numColors, |
487 RowOrder rowOrder, | 453 uint32_t bytesPerColor, uint32_t offset, |
488 const uint32_t remainingBytes) | 454 RowOrder rowOrder, uint32_t remainingBytes) |
489 : INHERITED(info, stream) | 455 : INHERITED(info, stream) |
490 , fBitsPerPixel(bitsPerPixel) | 456 , fBitsPerPixel(bitsPerPixel) |
491 , fInputFormat(inputFormat) | 457 , fInputFormat(inputFormat) |
492 , fMasks(masks) | 458 , fMasks(masks) |
493 , fColorTable(colorTable) | 459 , fColorTable(NULL) |
460 , fNumColors(numColors) | |
461 , fBytesPerColor(bytesPerColor) | |
462 , fOffset(offset) | |
494 , fRowOrder(rowOrder) | 463 , fRowOrder(rowOrder) |
495 , fRemainingBytes(remainingBytes) | 464 , fRemainingBytes(remainingBytes) |
496 {} | 465 {} |
497 | 466 |
498 /* | 467 /* |
499 * | 468 * |
500 * Initiates the bitmap decode | 469 * Initiates the bitmap decode |
501 * | 470 * |
502 */ | 471 */ |
503 SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo, | 472 SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo, |
504 void* dst, size_t dstRowBytes, | 473 void* dst, size_t dstRowBytes, |
505 SkPMColor*, int*) { | 474 SkPMColor*, int*) { |
475 // Check for proper input and output formats | |
506 if (!this->rewindIfNeeded()) { | 476 if (!this->rewindIfNeeded()) { |
507 return kCouldNotRewind; | 477 return kCouldNotRewind; |
508 } | 478 } |
509 if (dstInfo.dimensions() != this->getOriginalInfo().dimensions()) { | 479 if (dstInfo.dimensions() != this->getOriginalInfo().dimensions()) { |
510 SkDebugf("Error: scaling not supported.\n"); | 480 SkDebugf("Error: scaling not supported.\n"); |
511 return kInvalidScale; | 481 return kInvalidScale; |
512 } | 482 } |
513 if (!conversion_possible(dstInfo, this->getOriginalInfo())) { | 483 if (!conversion_possible(dstInfo, this->getOriginalInfo())) { |
514 SkDebugf("Error: cannot convert input type to output type.\n"); | 484 SkDebugf("Error: cannot convert input type to output type.\n"); |
515 return kInvalidConversion; | 485 return kInvalidConversion; |
516 } | 486 } |
517 | 487 |
488 // Create the color table if necessary and prepare the stream for decode | |
489 if (!createColorTable(dstInfo.alphaType())) { | |
490 SkDebugf("Error: could not create color table.\n"); | |
491 return kInvalidInput; | |
492 } | |
493 | |
494 // Perform the decode | |
518 switch (fInputFormat) { | 495 switch (fInputFormat) { |
519 case kBitMask_BitmapInputFormat: | 496 case kBitMask_BitmapInputFormat: |
520 return decodeMask(dstInfo, dst, dstRowBytes); | 497 return decodeMask(dstInfo, dst, dstRowBytes); |
521 case kRLE_BitmapInputFormat: | 498 case kRLE_BitmapInputFormat: |
522 return decodeRLE(dstInfo, dst, dstRowBytes); | 499 return decodeRLE(dstInfo, dst, dstRowBytes); |
523 case kStandard_BitmapInputFormat: | 500 case kStandard_BitmapInputFormat: |
524 return decode(dstInfo, dst, dstRowBytes); | 501 return decode(dstInfo, dst, dstRowBytes); |
525 default: | 502 default: |
526 SkASSERT(false); | 503 SkASSERT(false); |
527 return kInvalidInput; | 504 return kInvalidInput; |
528 } | 505 } |
529 } | 506 } |
530 | 507 |
531 /* | 508 /* |
532 * | 509 * |
510 * Process the color table for the bmp input | |
511 * | |
512 */ | |
513 bool SkBmpCodec::createColorTable(const SkAlphaType alphaType) { | |
514 SkPMColor* colorTable = NULL; | |
515 if (fBitsPerPixel < 16) { | |
516 // Allocate memory for a color table | |
517 const uint32_t maxColors = 1 << fBitsPerPixel; | |
518 colorTable = SkNEW_ARRAY(SkPMColor, maxColors); | |
scroggo
2015/03/17 13:27:22
colorTable will leak if we return NULL below.
msarett
2015/03/17 16:54:06
Done.
| |
519 | |
520 // Read the color table from the stream | |
521 uint32_t colorBytes = fNumColors * fBytesPerColor; | |
522 SkAutoTDeleteArray<uint8_t> cBuffer(SkNEW_ARRAY(uint8_t, colorBytes)); | |
523 if (stream()->read(cBuffer.get(), colorBytes) != colorBytes) { | |
524 SkDebugf("Error: unable to read color table.\n"); | |
525 return NULL; | |
526 } | |
527 | |
528 // Fill in the color table | |
529 uint32_t i = 0; | |
530 for (; i < fNumColors; i++) { | |
531 uint8_t blue = get_byte(cBuffer.get(), i*fBytesPerColor); | |
532 uint8_t green = get_byte(cBuffer.get(), i*fBytesPerColor + 1); | |
533 uint8_t red = get_byte(cBuffer.get(), i*fBytesPerColor + 2); | |
534 uint8_t alpha; | |
535 switch (alphaType) { | |
536 case kOpaque_SkAlphaType: | |
537 alpha = 0xFF; | |
538 colorTable[i] = SkPackARGB32NoCheck(alpha, red, green, | |
scroggo
2015/03/17 13:27:22
nit: no need to update the variable alpha. You can
msarett
2015/03/17 16:54:05
Done.
| |
539 blue); | |
540 break; | |
541 case kUnpremul_SkAlphaType: | |
542 alpha = (fMasks->getAlphaMask() >> 24) & | |
543 get_byte(cBuffer.get(), i*fBytesPerColor + 3); | |
544 colorTable[i] = SkPackARGB32NoCheck(alpha, red, green, | |
545 blue); | |
546 break; | |
547 case kPremul_SkAlphaType: | |
548 alpha = (fMasks->getAlphaMask() >> 24) & | |
549 get_byte(cBuffer.get(), i*fBytesPerColor + 3); | |
550 colorTable[i] = SkPreMultiplyARGB(alpha, red, green, blue); | |
551 break; | |
552 default: | |
553 // This should not be reached because conversion possible | |
554 // should fail if the alpha type is not one of the above | |
555 // values. | |
556 SkASSERT(false); | |
557 break; | |
558 } | |
559 } | |
560 | |
561 // To avoid segmentation faults on bad pixel data, fill the end of the | |
562 // color table with black. This is the same the behavior as the | |
563 // chromium decoder. | |
564 for (; i < maxColors; i++) { | |
565 colorTable[i] = SkPackARGB32NoCheck(0xFF, 0, 0, 0); | |
566 } | |
567 } | |
568 | |
569 // After reading the color table, skip to the start of the pixel array | |
570 if (stream()->skip(fOffset) != fOffset) { | |
571 SkDebugf("Error: unable to skip to image data.\n"); | |
572 return false; | |
573 } | |
574 | |
575 // Set the color table and return true on success | |
576 fColorTable.reset(colorTable); | |
577 return true; | |
578 } | |
579 | |
580 /* | |
581 * | |
533 * Performs the bitmap decoding for bit masks input format | 582 * Performs the bitmap decoding for bit masks input format |
534 * | 583 * |
535 */ | 584 */ |
536 SkCodec::Result SkBmpCodec::decodeMask(const SkImageInfo& dstInfo, | 585 SkCodec::Result SkBmpCodec::decodeMask(const SkImageInfo& dstInfo, |
537 void* dst, size_t dstRowBytes) { | 586 void* dst, size_t dstRowBytes) { |
538 // Set constant values | 587 // Set constant values |
539 const int width = dstInfo.width(); | 588 const int width = dstInfo.width(); |
540 const int height = dstInfo.height(); | 589 const int height = dstInfo.height(); |
541 const size_t rowBytes = SkAlign4(compute_row_bytes(width, fBitsPerPixel)); | 590 const size_t rowBytes = SkAlign4(compute_row_bytes(width, fBitsPerPixel)); |
542 | 591 |
543 // Allocate space for a row buffer and a source for the swizzler | 592 // Allocate a buffer large enough to hold the full input stream |
544 SkAutoTDeleteArray<uint8_t> srcBuffer(SkNEW_ARRAY(uint8_t, rowBytes)); | 593 uint8_t* srcBuffer(SkNEW_ARRAY(uint8_t, height*rowBytes)); |
msarett
2015/03/16 20:21:53
I know that it is preferred to use an SkAutoTDelet
scroggo
2015/03/17 13:27:22
You should definitely use some sort of auto delete
msarett
2015/03/17 16:54:06
Agreed, not sure what I was thinking.
| |
594 uint8_t* srcRow = srcBuffer; | |
545 | 595 |
546 // Get the destination start row and delta | 596 // Get the destination start row and delta |
597 SkPMColor* dstStart; | |
547 SkPMColor* dstRow; | 598 SkPMColor* dstRow; |
548 int delta; | 599 int delta; |
549 if (kTopDown_RowOrder == fRowOrder) { | 600 if (kTopDown_RowOrder == fRowOrder) { |
550 dstRow = (SkPMColor*) dst; | 601 dstStart = (SkPMColor*) dst; |
602 dstRow = dstStart; | |
551 delta = (int) dstRowBytes; | 603 delta = (int) dstRowBytes; |
552 } else { | 604 } else { |
553 dstRow = (SkPMColor*) SkTAddOffset<void>(dst, (height-1) * dstRowBytes); | 605 dstStart = (SkPMColor*) SkTAddOffset<void>( |
606 dst, (height - 1) * dstRowBytes); | |
607 dstRow = dstStart; | |
554 delta = -((int) dstRowBytes); | 608 delta = -((int) dstRowBytes); |
555 } | 609 } |
556 | 610 |
557 // Create the swizzler | 611 // Create the swizzler |
558 SkMaskSwizzler* swizzler = SkMaskSwizzler::CreateMaskSwizzler( | 612 SkMaskSwizzler* swizzler = SkMaskSwizzler::CreateMaskSwizzler( |
559 dstInfo, fMasks, fBitsPerPixel); | 613 dstInfo, fMasks, fBitsPerPixel); |
560 | 614 |
561 // Iterate over rows of the image | 615 // Iterate over rows of the image |
562 bool transparent = true; | 616 bool transparent = true; |
563 for (int y = 0; y < height; y++) { | 617 for (int y = 0; y < height; y++) { |
564 // Read a row of the input | 618 // Read a row of the input |
565 if (stream()->read(srcBuffer.get(), rowBytes) != rowBytes) { | 619 if (stream()->read(srcRow, rowBytes) != rowBytes) { |
566 SkDebugf("Warning: incomplete input stream.\n"); | 620 SkDebugf("Warning: incomplete input stream.\n"); |
621 SkDELETE_ARRAY(srcBuffer); | |
567 return kIncompleteInput; | 622 return kIncompleteInput; |
568 } | 623 } |
569 | 624 |
570 // Decode the row in destination format | 625 // Decode the row in destination format |
571 SkSwizzler::ResultAlpha r = swizzler->next(dstRow, srcBuffer.get()); | 626 SkSwizzler::ResultAlpha r = swizzler->next(dstRow, srcRow); |
572 transparent &= SkSwizzler::IsTransparent(r); | 627 transparent &= SkSwizzler::IsTransparent(r); |
573 | 628 |
574 // Move to the next row | 629 // Move to the next row |
575 dstRow = SkTAddOffset<SkPMColor>(dstRow, delta); | 630 dstRow = SkTAddOffset<SkPMColor>(dstRow, delta); |
631 srcRow = SkTAddOffset<uint8_t>(srcRow, rowBytes); | |
scroggo
2015/03/17 13:27:22
How did this work before?
msarett
2015/03/17 16:54:05
We used to overwrite the same row buffer for each
scroggo
2015/03/17 20:02:58
Ah, of course!
| |
576 } | 632 } |
577 | 633 |
578 // Some fully transparent bmp images are intended to be opaque. Here, we | 634 // Some fully transparent bmp images are intended to be opaque. Here, we |
579 // correct for this possibility. | 635 // correct for this possibility. |
580 dstRow = (SkPMColor*) dst; | |
581 if (transparent) { | 636 if (transparent) { |
637 const SkImageInfo& newInfo = dstInfo.makeAlphaType(kOpaque_SkAlphaType); | |
scroggo
2015/03/17 13:27:22
nit: Maybe this should be opaqueInfo? Or maskInfo?
msarett
2015/03/17 16:54:06
Done.
| |
638 SkMaskSwizzler* newSwizzler = SkMaskSwizzler::CreateMaskSwizzler( | |
scroggo
2015/03/17 13:27:22
This will leak.
scroggo
2015/03/17 13:27:22
nit: Maybe name this maskSwizzler?
msarett
2015/03/17 16:54:05
Yeah it looks like it. I think this is not the on
| |
639 newInfo, fMasks, fBitsPerPixel); | |
msarett
2015/03/16 20:21:53
Increase indent
| |
640 srcRow = srcBuffer; | |
641 dstRow = dstStart; | |
582 for (int y = 0; y < height; y++) { | 642 for (int y = 0; y < height; y++) { |
583 for (int x = 0; x < width; x++) { | 643 // Decode the row in new format |
584 dstRow[x] |= 0xFF000000; | 644 newSwizzler->next(dstRow, srcRow); |
585 } | 645 |
586 dstRow = SkTAddOffset<SkPMColor>(dstRow, dstRowBytes); | 646 // Move to the next row |
647 dstRow = SkTAddOffset<SkPMColor>(dstRow, delta); | |
648 srcRow = SkTAddOffset<uint8_t>(srcRow, rowBytes); | |
587 } | 649 } |
588 } | 650 } |
589 | 651 |
652 // Clean up memory | |
653 SkDELETE_ARRAY(srcBuffer); | |
654 | |
590 // Finished decoding the entire image | 655 // Finished decoding the entire image |
591 return kSuccess; | 656 return kSuccess; |
592 } | 657 } |
593 | 658 |
594 /* | 659 /* |
595 * | 660 * |
596 * Set an RLE pixel using the color table | 661 * Set an RLE pixel using the color table |
597 * | 662 * |
598 */ | 663 */ |
599 void SkBmpCodec::setRLEPixel(SkPMColor* dst, size_t dstRowBytes, int height, | 664 void SkBmpCodec::setRLEPixel(SkPMColor* dst, size_t dstRowBytes, |
600 uint32_t x, uint32_t y, uint8_t index) { | 665 const SkImageInfo& dstInfo, uint32_t x, uint32_t y, |
666 uint8_t index) { | |
667 // Set the row | |
668 int height = dstInfo.height(); | |
669 int row; | |
601 if (kBottomUp_RowOrder == fRowOrder) { | 670 if (kBottomUp_RowOrder == fRowOrder) { |
602 y = height - y - 1; | 671 row = height - y - 1; |
672 } else { | |
673 row = y; | |
603 } | 674 } |
604 SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, y * dstRowBytes); | 675 |
605 dstRow[x] = fColorTable.get()[index]; | 676 // Set the pixel based on destination color type |
677 switch (dstInfo.colorType()) { | |
678 case kN32_SkColorType: { | |
679 SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, | |
680 row * (int) dstRowBytes); | |
681 dstRow[x] = fColorTable.get()[index]; | |
682 break; | |
683 } | |
684 case kRGB_565_SkColorType: { | |
685 uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, | |
686 row * (int) dstRowBytes); | |
687 dstRow[x] = SkPixel32ToPixel16(fColorTable.get()[index]); | |
688 break; | |
689 } | |
690 default: | |
691 // This case should not be reached. We should catch an invalid | |
692 // color type when we check that the conversion is possible. | |
693 SkASSERT(false); | |
694 break; | |
695 } | |
606 } | 696 } |
607 | 697 |
608 /* | 698 /* |
699 * | |
700 * Set an RLE pixel from R, G, B values | |
701 * | |
702 */ | |
703 void SkBmpCodec::setRLE24Pixel(SkPMColor* dst, size_t dstRowBytes, | |
704 const SkImageInfo& dstInfo, uint32_t x, | |
705 uint32_t y, uint8_t red, uint8_t green, | |
706 uint8_t blue) { | |
707 // Set the row | |
708 int height = dstInfo.height(); | |
709 int row; | |
710 if (kBottomUp_RowOrder == fRowOrder) { | |
711 row = height - y - 1; | |
712 } else { | |
713 row = y; | |
714 } | |
715 | |
716 // Set the pixel based on destination color type | |
717 switch (dstInfo.colorType()) { | |
718 case kN32_SkColorType: { | |
719 SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, | |
720 row * (int) dstRowBytes); | |
721 dstRow[x] = SkPackARGB32NoCheck(0xFF, red, green, blue); | |
722 break; | |
723 } | |
724 case kRGB_565_SkColorType: { | |
725 uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, | |
726 row * (int) dstRowBytes); | |
727 dstRow[x] = SkPack888ToRGB16(red, green, blue); | |
728 break; | |
729 } | |
730 default: | |
731 // This case should not be reached. We should catch an invalid | |
732 // color type when we check that the conversion is possible. | |
733 SkASSERT(false); | |
734 break; | |
735 } | |
736 } | |
737 | |
738 /* | |
609 * | 739 * |
610 * Performs the bitmap decoding for RLE input format | 740 * Performs the bitmap decoding for RLE input format |
611 * RLE decoding is performed all at once, rather than a one row at a time | 741 * RLE decoding is performed all at once, rather than a one row at a time |
612 * | 742 * |
613 */ | 743 */ |
614 SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, | 744 SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, |
615 void* dst, size_t dstRowBytes) { | 745 void* dst, size_t dstRowBytes) { |
616 // Set RLE flags | 746 // Set RLE flags |
617 static const uint8_t RLE_ESCAPE = 0; | 747 static const uint8_t RLE_ESCAPE = 0; |
618 static const uint8_t RLE_EOL = 0; | 748 static const uint8_t RLE_EOL = 0; |
619 static const uint8_t RLE_EOF = 1; | 749 static const uint8_t RLE_EOF = 1; |
620 static const uint8_t RLE_DELTA = 2; | 750 static const uint8_t RLE_DELTA = 2; |
621 | 751 |
622 // Set constant values | 752 // Set constant values |
623 const int width = dstInfo.width(); | 753 const int width = dstInfo.width(); |
624 const int height = dstInfo.height(); | 754 const int height = dstInfo.height(); |
625 | 755 |
626 // Input buffer parameters | 756 // Input buffer parameters |
627 uint32_t currByte = 0; | 757 uint32_t currByte = 0; |
628 SkAutoTDeleteArray<uint8_t> buffer(SkNEW_ARRAY(uint8_t, fRemainingBytes)); | 758 SkAutoTDeleteArray<uint8_t> buffer(SkNEW_ARRAY(uint8_t, fRemainingBytes)); |
629 size_t totalBytes = stream()->read(buffer.get(), fRemainingBytes); | 759 size_t totalBytes = stream()->read(buffer.get(), fRemainingBytes); |
630 if ((uint32_t) totalBytes < fRemainingBytes) { | 760 if (totalBytes < fRemainingBytes) { |
631 SkDebugf("Warning: incomplete RLE file.\n"); | 761 SkDebugf("Warning: incomplete RLE file.\n"); |
632 } else if (totalBytes <= 0) { | 762 } else if (totalBytes <= 0) { |
633 SkDebugf("Error: could not read RLE image data.\n"); | 763 SkDebugf("Error: could not read RLE image data.\n"); |
634 return kInvalidInput; | 764 return kInvalidInput; |
635 } | 765 } |
636 | 766 |
637 // Destination parameters | 767 // Destination parameters |
638 int x = 0; | 768 int x = 0; |
639 int y = 0; | 769 int y = 0; |
640 // If the code skips pixels, remaining pixels are transparent or black | 770 // If the code skips pixels, remaining pixels are transparent or black |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
699 fBitsPerPixel); | 829 fBitsPerPixel); |
700 // Abort if setting numPixels moves us off the edge of the | 830 // Abort if setting numPixels moves us off the edge of the |
701 // image. Also abort if there are not enough bytes | 831 // image. Also abort if there are not enough bytes |
702 // remaining in the stream to set numPixels. | 832 // remaining in the stream to set numPixels. |
703 if (x + numPixels > width || | 833 if (x + numPixels > width || |
704 (int) totalBytes - currByte < SkAlign2(rowBytes)) { | 834 (int) totalBytes - currByte < SkAlign2(rowBytes)) { |
705 SkDebugf("Warning: invalid RLE input.\n"); | 835 SkDebugf("Warning: invalid RLE input.\n"); |
706 return kIncompleteInput; | 836 return kIncompleteInput; |
707 } | 837 } |
708 // Set numPixels number of pixels | 838 // Set numPixels number of pixels |
709 SkPMColor* dstRow = SkTAddOffset<SkPMColor>( | |
710 dstPtr, y * dstRowBytes); | |
711 while (numPixels > 0) { | 839 while (numPixels > 0) { |
712 switch(fBitsPerPixel) { | 840 switch(fBitsPerPixel) { |
713 case 4: { | 841 case 4: { |
714 SkASSERT(currByte < totalBytes); | 842 SkASSERT(currByte < totalBytes); |
715 uint8_t val = buffer.get()[currByte++]; | 843 uint8_t val = buffer.get()[currByte++]; |
716 setRLEPixel(dstPtr, dstRowBytes, height, x++, y, | 844 setRLEPixel(dstPtr, dstRowBytes, dstInfo, x++, |
717 val >> 4); | 845 y, val >> 4); |
718 numPixels--; | 846 numPixels--; |
719 if (numPixels != 0) { | 847 if (numPixels != 0) { |
720 setRLEPixel(dstPtr, dstRowBytes, height, | 848 setRLEPixel(dstPtr, dstRowBytes, dstInfo, |
721 x++, y, val & 0xF); | 849 x++, y, val & 0xF); |
722 numPixels--; | 850 numPixels--; |
723 } | 851 } |
724 break; | 852 break; |
725 } | 853 } |
726 case 8: | 854 case 8: |
727 SkASSERT(currByte < totalBytes); | 855 SkASSERT(currByte < totalBytes); |
728 setRLEPixel(dstPtr, dstRowBytes, height, x++, y, | 856 setRLEPixel(dstPtr, dstRowBytes, dstInfo, x++, |
729 buffer.get()[currByte++]); | 857 y, buffer.get()[currByte++]); |
730 numPixels--; | 858 numPixels--; |
731 break; | 859 break; |
732 case 24: { | 860 case 24: { |
733 SkASSERT(currByte + 2 < totalBytes); | 861 SkASSERT(currByte + 2 < totalBytes); |
734 uint8_t blue = buffer.get()[currByte++]; | 862 uint8_t blue = buffer.get()[currByte++]; |
735 uint8_t green = buffer.get()[currByte++]; | 863 uint8_t green = buffer.get()[currByte++]; |
736 uint8_t red = buffer.get()[currByte++]; | 864 uint8_t red = buffer.get()[currByte++]; |
737 SkPMColor color = SkPackARGB32NoCheck( | 865 setRLE24Pixel(dstPtr, dstRowBytes, dstInfo, |
738 0xFF, red, green, blue); | 866 x++, y, red, green, blue); |
739 dstRow[x++] = color; | |
740 numPixels--; | 867 numPixels--; |
741 } | 868 } |
742 default: | 869 default: |
743 SkASSERT(false); | 870 SkASSERT(false); |
744 return kInvalidInput; | 871 return kInvalidInput; |
745 } | 872 } |
746 } | 873 } |
747 // Skip a byte if necessary to maintain alignment | 874 // Skip a byte if necessary to maintain alignment |
748 if (!SkIsAlign2(rowBytes)) { | 875 if (!SkIsAlign2(rowBytes)) { |
749 currByte++; | 876 currByte++; |
(...skipping 13 matching lines...) Expand all Loading... | |
763 // color. | 890 // color. |
764 if ((int) totalBytes - currByte < 2) { | 891 if ((int) totalBytes - currByte < 2) { |
765 SkDebugf("Warning: incomplete RLE input\n"); | 892 SkDebugf("Warning: incomplete RLE input\n"); |
766 return kIncompleteInput; | 893 return kIncompleteInput; |
767 } | 894 } |
768 | 895 |
769 // Fill the pixels up to endX with the specified color | 896 // Fill the pixels up to endX with the specified color |
770 uint8_t blue = task; | 897 uint8_t blue = task; |
771 uint8_t green = buffer.get()[currByte++]; | 898 uint8_t green = buffer.get()[currByte++]; |
772 uint8_t red = buffer.get()[currByte++]; | 899 uint8_t red = buffer.get()[currByte++]; |
773 SkPMColor color = SkPackARGB32NoCheck(0xFF, red, green, blue); | |
774 SkPMColor* dstRow = | |
775 SkTAddOffset<SkPMColor>(dstPtr, y * dstRowBytes); | |
776 while (x < endX) { | 900 while (x < endX) { |
777 dstRow[x++] = color; | 901 setRLE24Pixel(dstPtr, dstRowBytes, dstInfo, x++, y, red, |
902 green, blue); | |
778 } | 903 } |
779 } else { | 904 } else { |
780 // In RLE8 or RLE4, the second byte read gives the index in the | 905 // In RLE8 or RLE4, the second byte read gives the index in the |
781 // color table to look up the pixel color. | 906 // color table to look up the pixel color. |
782 // RLE8 has one color index that gets repeated | 907 // RLE8 has one color index that gets repeated |
783 // RLE4 has two color indexes in the upper and lower 4 bits of | 908 // RLE4 has two color indexes in the upper and lower 4 bits of |
784 // the bytes, which are alternated | 909 // the bytes, which are alternated |
785 uint8_t indices[2] = { task, task }; | 910 uint8_t indices[2] = { task, task }; |
786 if (4 == fBitsPerPixel) { | 911 if (4 == fBitsPerPixel) { |
787 indices[0] >>= 4; | 912 indices[0] >>= 4; |
788 indices[1] &= 0xf; | 913 indices[1] &= 0xf; |
789 } | 914 } |
790 | 915 |
791 // Set the indicated number of pixels | 916 // Set the indicated number of pixels |
792 for (int which = 0; x < endX; x++) { | 917 for (int which = 0; x < endX; x++) { |
793 setRLEPixel(dstPtr, dstRowBytes, height, x, y, | 918 setRLEPixel(dstPtr, dstRowBytes, dstInfo, x, y, |
794 indices[which]); | 919 indices[which]); |
795 which = !which; | 920 which = !which; |
796 } | 921 } |
797 } | 922 } |
798 } | 923 } |
799 } | 924 } |
800 } | 925 } |
801 | 926 |
802 /* | 927 /* |
803 * | 928 * |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
894 } | 1019 } |
895 dstRow = SkTAddOffset<SkPMColor>(dstRow, dstRowBytes); | 1020 dstRow = SkTAddOffset<SkPMColor>(dstRow, dstRowBytes); |
896 } | 1021 } |
897 } | 1022 } |
898 } | 1023 } |
899 */ | 1024 */ |
900 | 1025 |
901 // Finished decoding the entire image | 1026 // Finished decoding the entire image |
902 return kSuccess; | 1027 return kSuccess; |
903 } | 1028 } |
OLD | NEW |