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

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

Issue 1013743003: Adding premul and 565 swizzles for bmp: (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Clean up before public code review Created 5 years, 9 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
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 "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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698