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

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: Added profile type check 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
« no previous file with comments | « src/codec/SkCodec_libbmp.h ('k') | src/codec/SkCodec_libpng.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // Ensure that the profile type is unchanged
22 // TODO: Update this when more swizzles are supported 22 if (dst.profileType() != src.profileType()) {
23 if (kN32_SkColorType != dst.colorType()) {
24 return false; 23 return false;
25 } 24 }
26 // Support the swizzle if the requested alpha type is the same as our guess 25
27 // for the input alpha type 26 // Check for supported color and alpha types
28 if (src.alphaType() == dst.alphaType()) { 27 switch (dst.colorType()) {
29 return true; 28 case kN32_SkColorType:
29 return src.alphaType() == dst.alphaType() ||
30 (kPremul_SkAlphaType == dst.alphaType() &&
31 kUnpremul_SkAlphaType == src.alphaType());
32 case kRGB_565_SkColorType:
33 return src.alphaType() == dst.alphaType() &&
34 kOpaque_SkAlphaType == dst.alphaType();
35 default:
36 return false;
30 } 37 }
31 // TODO: Support more swizzles, especially premul
32 return false;
33 } 38 }
34 39
35 /* 40 /*
36 * 41 *
37 * Defines the version and type of the second bitmap header 42 * Defines the version and type of the second bitmap header
38 * 43 *
39 */ 44 */
40 enum BitmapHeaderType { 45 enum BitmapHeaderType {
41 kInfoV1_BitmapHeaderType, 46 kInfoV1_BitmapHeaderType,
42 kInfoV2_BitmapHeaderType, 47 kInfoV2_BitmapHeaderType,
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 } 245 }
241 static const int kBmpMaxDim = 1 << 16; 246 static const int kBmpMaxDim = 1 << 16;
242 if (width < 0 || width >= kBmpMaxDim || height >= kBmpMaxDim) { 247 if (width < 0 || width >= kBmpMaxDim || height >= kBmpMaxDim) {
243 // TODO: Decide if we want to support really large bmps. 248 // TODO: Decide if we want to support really large bmps.
244 SkDebugf("Error: invalid bitmap dimensions.\n"); 249 SkDebugf("Error: invalid bitmap dimensions.\n");
245 return NULL; 250 return NULL;
246 } 251 }
247 252
248 // Create mask struct 253 // Create mask struct
249 SkMasks::InputMasks inputMasks; 254 SkMasks::InputMasks inputMasks;
250 memset(&inputMasks, 0, 4*sizeof(uint32_t)); 255 memset(&inputMasks, 0, sizeof(SkMasks::InputMasks));
251 256
252 // Determine the input compression format and set bit masks if necessary 257 // Determine the input compression format and set bit masks if necessary
253 uint32_t maskBytes = 0; 258 uint32_t maskBytes = 0;
254 BitmapInputFormat inputFormat = kUnknown_BitmapInputFormat; 259 BitmapInputFormat inputFormat = kUnknown_BitmapInputFormat;
255 switch (compression) { 260 switch (compression) {
256 case kNone_BitmapCompressionMethod: 261 case kNone_BitmapCompressionMethod:
257 inputFormat = kStandard_BitmapInputFormat; 262 inputFormat = kStandard_BitmapInputFormat;
258 break; 263 break;
259 case k8BitRLE_BitmapCompressionMethod: 264 case k8BitRLE_BitmapCompressionMethod:
260 if (bitsPerPixel != 8) { 265 if (bitsPerPixel != 8) {
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
385 } 390 }
386 391
387 // Check that input bit masks are valid and create the masks object 392 // Check that input bit masks are valid and create the masks object
388 SkAutoTDelete<SkMasks> 393 SkAutoTDelete<SkMasks>
389 masks(SkMasks::CreateMasks(inputMasks, bitsPerPixel)); 394 masks(SkMasks::CreateMasks(inputMasks, bitsPerPixel));
390 if (NULL == masks) { 395 if (NULL == masks) {
391 SkDebugf("Error: invalid input masks.\n"); 396 SkDebugf("Error: invalid input masks.\n");
392 return NULL; 397 return NULL;
393 } 398 }
394 399
395 // Process the color table 400 // Check for a valid number of total bytes when in RLE mode
396 uint32_t colorBytes = 0; 401 if (totalBytes <= offset && kRLE_BitmapInputFormat == inputFormat) {
397 SkPMColor* colorTable = NULL; 402 SkDebugf("Error: RLE requires valid input size.\n");
398 if (bitsPerPixel < 16) {
399 // Verify the number of colors for the color table
400 const uint32_t maxColors = 1 << bitsPerPixel;
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 }
438
439 // Ensure that the stream now points to the start of the pixel array
440 uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes + colorBytes;
441
442 // Check that we have not read past the pixel array offset
443 if(bytesRead > offset) {
444 // 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
446 // 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
448 // rewind the stream to display the image.
449 SkDebugf("Error: pixel data offset less than header size.\n");
450 return NULL; 403 return NULL;
451 } 404 }
405 const size_t RLEBytes = totalBytes - offset;
452 406
453 // Skip to the start of the pixel array 407 // Calculate the number of bytes read so far
454 if (stream->skip(offset - bytesRead) != offset - bytesRead) { 408 const uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes;
455 SkDebugf("Error: unable to skip to image data.\n"); 409 if (offset < bytesRead) {
456 return NULL; 410 SkDebugf("Error: pixel data offset less than header size.\n");
457 }
458
459 // Remaining bytes is only used for RLE
460 const int remainingBytes = totalBytes - offset;
461 if (remainingBytes <= 0 && kRLE_BitmapInputFormat == inputFormat) {
462 SkDebugf("Error: RLE requires valid input size.\n");
463 return NULL; 411 return NULL;
464 } 412 }
465 413
466 // Return the codec 414 // Return the codec
467 // We will use ImageInfo to store width, height, and alpha type. We will 415 // 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 416 // set color type to kN32_SkColorType because that should be the default
scroggo 2015/03/18 14:59:32 This doesn't need to be fixed in this CL, but I ta
msarett 2015/03/18 15:57:00 That's a good point, and something we should proba
469 // expected choice for a destination color type. In reality, the input 417 // output.
470 // color type has many possible formats.
471 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height, 418 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height,
472 kN32_SkColorType, alphaType); 419 kN32_SkColorType, alphaType);
473 return SkNEW_ARGS(SkBmpCodec, (imageInfo, stream, bitsPerPixel, 420 return SkNEW_ARGS(SkBmpCodec, (imageInfo, stream, bitsPerPixel,
474 inputFormat, masks.detach(), colorTable, 421 inputFormat, masks.detach(), numColors,
475 rowOrder, remainingBytes)); 422 bytesPerColor, offset - bytesRead,
423 rowOrder, RLEBytes));
476 } 424 }
477 425
478 /* 426 /*
479 * 427 *
480 * Creates an instance of the decoder 428 * Creates an instance of the decoder
481 * Called only by NewFromStream 429 * Called only by NewFromStream
482 * 430 *
483 */ 431 */
484 SkBmpCodec::SkBmpCodec(const SkImageInfo& info, SkStream* stream, 432 SkBmpCodec::SkBmpCodec(const SkImageInfo& info, SkStream* stream,
485 uint16_t bitsPerPixel, BitmapInputFormat inputFormat, 433 uint16_t bitsPerPixel, BitmapInputFormat inputFormat,
486 SkMasks* masks, SkPMColor* colorTable, 434 SkMasks* masks, uint32_t numColors,
487 RowOrder rowOrder, 435 uint32_t bytesPerColor, uint32_t offset,
488 const uint32_t remainingBytes) 436 RowOrder rowOrder, size_t RLEBytes)
489 : INHERITED(info, stream) 437 : INHERITED(info, stream)
490 , fBitsPerPixel(bitsPerPixel) 438 , fBitsPerPixel(bitsPerPixel)
491 , fInputFormat(inputFormat) 439 , fInputFormat(inputFormat)
492 , fMasks(masks) 440 , fMasks(masks)
493 , fColorTable(colorTable) 441 , fColorTable(NULL)
442 , fNumColors(numColors)
443 , fBytesPerColor(bytesPerColor)
444 , fOffset(offset)
494 , fRowOrder(rowOrder) 445 , fRowOrder(rowOrder)
495 , fRemainingBytes(remainingBytes) 446 , fRLEBytes(RLEBytes)
496 {} 447 {}
497 448
498 /* 449 /*
499 * 450 *
500 * Initiates the bitmap decode 451 * Initiates the bitmap decode
501 * 452 *
502 */ 453 */
503 SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo, 454 SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo,
504 void* dst, size_t dstRowBytes, 455 void* dst, size_t dstRowBytes,
505 const Options&, 456 const Options&,
506 SkPMColor*, int*) { 457 SkPMColor*, int*) {
458 // Check for proper input and output formats
507 if (!this->rewindIfNeeded()) { 459 if (!this->rewindIfNeeded()) {
508 return kCouldNotRewind; 460 return kCouldNotRewind;
509 } 461 }
510 if (dstInfo.dimensions() != this->getOriginalInfo().dimensions()) { 462 if (dstInfo.dimensions() != this->getOriginalInfo().dimensions()) {
511 SkDebugf("Error: scaling not supported.\n"); 463 SkDebugf("Error: scaling not supported.\n");
512 return kInvalidScale; 464 return kInvalidScale;
513 } 465 }
514 if (!conversion_possible(dstInfo, this->getOriginalInfo())) { 466 if (!conversion_possible(dstInfo, this->getOriginalInfo())) {
515 SkDebugf("Error: cannot convert input type to output type.\n"); 467 SkDebugf("Error: cannot convert input type to output type.\n");
516 return kInvalidConversion; 468 return kInvalidConversion;
517 } 469 }
518 470
471 // Create the color table if necessary and prepare the stream for decode
472 if (!createColorTable(dstInfo.alphaType())) {
473 SkDebugf("Error: could not create color table.\n");
474 return kInvalidInput;
475 }
476
477 // Perform the decode
519 switch (fInputFormat) { 478 switch (fInputFormat) {
520 case kBitMask_BitmapInputFormat: 479 case kBitMask_BitmapInputFormat:
521 return decodeMask(dstInfo, dst, dstRowBytes); 480 return decodeMask(dstInfo, dst, dstRowBytes);
522 case kRLE_BitmapInputFormat: 481 case kRLE_BitmapInputFormat:
523 return decodeRLE(dstInfo, dst, dstRowBytes); 482 return decodeRLE(dstInfo, dst, dstRowBytes);
524 case kStandard_BitmapInputFormat: 483 case kStandard_BitmapInputFormat:
525 return decode(dstInfo, dst, dstRowBytes); 484 return decode(dstInfo, dst, dstRowBytes);
526 default: 485 default:
527 SkASSERT(false); 486 SkASSERT(false);
528 return kInvalidInput; 487 return kInvalidInput;
529 } 488 }
530 } 489 }
531 490
532 /* 491 /*
533 * 492 *
493 * Process the color table for the bmp input
494 *
495 */
496 bool SkBmpCodec::createColorTable(SkAlphaType alphaType) {
497
498 // Allocate memory for color table
499 uint32_t colorBytes = 0;
500 uint32_t maxColors = fBitsPerPixel <= 8 ? 1 << fBitsPerPixel : 0;
scroggo 2015/03/18 14:59:32 nit: const
msarett 2015/03/18 15:57:00 Done.
501 SkPMColor colorTable[maxColors];
502 if (fBitsPerPixel <= 8) {
503 // Read the color table from the stream
504 colorBytes = fNumColors * fBytesPerColor;
scroggo 2015/03/18 14:59:32 Is it possible for fNumColors to be greater than m
msarett 2015/03/18 15:57:00 There was code that fixes this possibility that se
505 SkAutoTDeleteArray<uint8_t> cBuffer(SkNEW_ARRAY(uint8_t, colorBytes));
506 if (stream()->read(cBuffer.get(), colorBytes) != colorBytes) {
507 SkDebugf("Error: unable to read color table.\n");
508 return NULL;
509 }
510
511 // Fill in the color table
512 uint32_t i = 0;
513 for (; i < fNumColors; i++) {
514 uint8_t blue = get_byte(cBuffer.get(), i*fBytesPerColor);
515 uint8_t green = get_byte(cBuffer.get(), i*fBytesPerColor + 1);
516 uint8_t red = get_byte(cBuffer.get(), i*fBytesPerColor + 2);
517 uint8_t alpha;
518 switch (alphaType) {
519 case kOpaque_SkAlphaType:
520 colorTable[i] = SkPackARGB32NoCheck(0xFF, red, green,
521 blue);
522 break;
523 case kUnpremul_SkAlphaType:
524 alpha = (fMasks->getAlphaMask() >> 24) &
525 get_byte(cBuffer.get(), i*fBytesPerColor + 3);
526 colorTable[i] = SkPackARGB32NoCheck(alpha, red, green,
527 blue);
528 break;
529 case kPremul_SkAlphaType:
530 alpha = (fMasks->getAlphaMask() >> 24) &
531 get_byte(cBuffer.get(), i*fBytesPerColor + 3);
532 colorTable[i] = SkPreMultiplyARGB(alpha, red, green,
scroggo 2015/03/18 14:59:32 nit: We could handle both premul and unpremul with
msarett 2015/03/18 15:57:00 Maybe this is better?
533 blue);
534 break;
535 default:
536 // This should not be reached because conversion possible
537 // should fail if the alpha type is not one of the above
538 // values.
539 SkASSERT(false);
540 break;
541 }
542 }
543
544 // To avoid segmentation faults on bad pixel data, fill the end of the
545 // color table with black. This is the same the behavior as the
546 // chromium decoder.
547 for (; i < maxColors; i++) {
548 colorTable[i] = SkPackARGB32NoCheck(0xFF, 0, 0, 0);
549 }
550 }
551
552 // Check that we have not read past the pixel array offset
553 if(fOffset < colorBytes) {
554 // This may occur on OS 2.1 and other old versions where the color
555 // table defaults to max size, and the bmp tries to use a smaller color
556 // table. This is invalid, and our decision is to indicate an error,
557 // rather than try to guess the intended size of the color table.
558 SkDebugf("Error: pixel data offset less than color table size.\n");
559 return NULL;
560 }
561
562 // After reading the color table, skip to the start of the pixel array
563 if (stream()->skip(fOffset - colorBytes) != fOffset - colorBytes) {
564 SkDebugf("Error: unable to skip to image data.\n");
565 return false;
566 }
567
568 // Set the color table and return true on success
569 fColorTable.reset(SkNEW_ARGS(SkColorTable, (colorTable, maxColors)));
570 return true;
571 }
572
573 /*
574 *
534 * Performs the bitmap decoding for bit masks input format 575 * Performs the bitmap decoding for bit masks input format
535 * 576 *
536 */ 577 */
537 SkCodec::Result SkBmpCodec::decodeMask(const SkImageInfo& dstInfo, 578 SkCodec::Result SkBmpCodec::decodeMask(const SkImageInfo& dstInfo,
538 void* dst, size_t dstRowBytes) { 579 void* dst, size_t dstRowBytes) {
539 // Set constant values 580 // Set constant values
540 const int width = dstInfo.width(); 581 const int width = dstInfo.width();
541 const int height = dstInfo.height(); 582 const int height = dstInfo.height();
542 const size_t rowBytes = SkAlign4(compute_row_bytes(width, fBitsPerPixel)); 583 const size_t rowBytes = SkAlign4(compute_row_bytes(width, fBitsPerPixel));
543 584
544 // Allocate space for a row buffer and a source for the swizzler 585 // Allocate a buffer large enough to hold the full input stream
scroggo 2015/03/18 14:59:32 nit: this holds the whole image, not the whole str
msarett 2015/03/18 15:57:00 Done.
545 SkAutoTDeleteArray<uint8_t> srcBuffer(SkNEW_ARRAY(uint8_t, rowBytes)); 586 SkAutoTDeleteArray<uint8_t>
587 srcBuffer(SkNEW_ARRAY(uint8_t, height*rowBytes));
588 uint8_t* srcRow = srcBuffer.get();
546 589
547 // Get the destination start row and delta 590 // Get the destination start row and delta
591 SkPMColor* dstStart;
548 SkPMColor* dstRow; 592 SkPMColor* dstRow;
549 int delta; 593 int delta;
550 if (kTopDown_RowOrder == fRowOrder) { 594 if (kTopDown_RowOrder == fRowOrder) {
551 dstRow = (SkPMColor*) dst; 595 dstStart = (SkPMColor*) dst;
596 dstRow = dstStart;
552 delta = (int) dstRowBytes; 597 delta = (int) dstRowBytes;
553 } else { 598 } else {
554 dstRow = (SkPMColor*) SkTAddOffset<void>(dst, (height-1) * dstRowBytes); 599 dstStart = (SkPMColor*) SkTAddOffset<void>(
600 dst, (height - 1) * dstRowBytes);
601 dstRow = dstStart;
555 delta = -((int) dstRowBytes); 602 delta = -((int) dstRowBytes);
556 } 603 }
557 604
558 // Create the swizzler 605 // Create the swizzler
559 SkMaskSwizzler* swizzler = SkMaskSwizzler::CreateMaskSwizzler( 606 SkAutoTDelete<SkMaskSwizzler> maskSwizzler(
560 dstInfo, fMasks, fBitsPerPixel); 607 SkMaskSwizzler::CreateMaskSwizzler(dstInfo, fMasks, fBitsPerPixel));
561 608
562 // Iterate over rows of the image 609 // Iterate over rows of the image
563 bool transparent = true; 610 bool transparent = true;
564 for (int y = 0; y < height; y++) { 611 for (int y = 0; y < height; y++) {
565 // Read a row of the input 612 // Read a row of the input
566 if (stream()->read(srcBuffer.get(), rowBytes) != rowBytes) { 613 if (stream()->read(srcRow, rowBytes) != rowBytes) {
567 SkDebugf("Warning: incomplete input stream.\n"); 614 SkDebugf("Warning: incomplete input stream.\n");
568 return kIncompleteInput; 615 return kIncompleteInput;
569 } 616 }
570 617
571 // Decode the row in destination format 618 // Decode the row in destination format
572 SkSwizzler::ResultAlpha r = swizzler->next(dstRow, srcBuffer.get()); 619 SkSwizzler::ResultAlpha r = maskSwizzler->next(dstRow, srcRow);
scroggo 2015/03/18 14:59:32 This is confusing. The second parameter for SkMask
msarett 2015/03/18 15:57:00 Yes I will unify. And I think this will fix the i
scroggo 2015/03/18 16:02:06 I know I told you that SkSwizzler::next() should t
msarett 2015/03/18 16:08:17 I would agree that src should always be the first
573 transparent &= SkSwizzler::IsTransparent(r); 620 transparent &= SkSwizzler::IsTransparent(r);
574 621
575 // Move to the next row 622 // Move to the next row
576 dstRow = SkTAddOffset<SkPMColor>(dstRow, delta); 623 dstRow = SkTAddOffset<SkPMColor>(dstRow, delta);
scroggo 2015/03/18 14:59:32 This isn't new to this CL, but if delta is negativ
msarett 2015/03/18 15:57:00 It does work. But it seems that this was by luck
624 srcRow = SkTAddOffset<uint8_t>(srcRow, rowBytes);
577 } 625 }
578 626
579 // Some fully transparent bmp images are intended to be opaque. Here, we 627 // Some fully transparent bmp images are intended to be opaque. Here, we
580 // correct for this possibility. 628 // correct for this possibility.
581 dstRow = (SkPMColor*) dst;
582 if (transparent) { 629 if (transparent) {
630 const SkImageInfo& opaqueInfo =
631 dstInfo.makeAlphaType(kOpaque_SkAlphaType);
632 SkAutoTDelete<SkMaskSwizzler> opaqueSwizzler(
633 SkMaskSwizzler::CreateMaskSwizzler(opaqueInfo, fMasks,
634 fBitsPerPixel));
635 srcRow = srcBuffer.get();
636 dstRow = dstStart;
583 for (int y = 0; y < height; y++) { 637 for (int y = 0; y < height; y++) {
584 for (int x = 0; x < width; x++) { 638 // Decode the row in new format
585 dstRow[x] |= 0xFF000000; 639 opaqueSwizzler->next(dstRow, srcRow);
586 } 640
587 dstRow = SkTAddOffset<SkPMColor>(dstRow, dstRowBytes); 641 // Move to the next row
642 dstRow = SkTAddOffset<SkPMColor>(dstRow, delta);
643 srcRow = SkTAddOffset<uint8_t>(srcRow, rowBytes);
588 } 644 }
589 } 645 }
590 646
591 // Finished decoding the entire image 647 // Finished decoding the entire image
592 return kSuccess; 648 return kSuccess;
593 } 649 }
594 650
595 /* 651 /*
596 * 652 *
597 * Set an RLE pixel using the color table 653 * Set an RLE pixel using the color table
598 * 654 *
599 */ 655 */
600 void SkBmpCodec::setRLEPixel(SkPMColor* dst, size_t dstRowBytes, int height, 656 void SkBmpCodec::setRLEPixel(SkPMColor* dst, size_t dstRowBytes,
601 uint32_t x, uint32_t y, uint8_t index) { 657 const SkImageInfo& dstInfo, uint32_t x, uint32_t y,
658 uint8_t index) {
659 // Set the row
660 int height = dstInfo.height();
661 int row;
602 if (kBottomUp_RowOrder == fRowOrder) { 662 if (kBottomUp_RowOrder == fRowOrder) {
603 y = height - y - 1; 663 row = height - y - 1;
664 } else {
665 row = y;
604 } 666 }
605 SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, y * dstRowBytes); 667
606 dstRow[x] = fColorTable.get()[index]; 668 // Set the pixel based on destination color type
669 switch (dstInfo.colorType()) {
670 case kN32_SkColorType: {
671 SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst,
672 row * (int) dstRowBytes);
673 dstRow[x] = fColorTable->operator[](index);
674 break;
675 }
676 case kRGB_565_SkColorType: {
677 uint16_t* dstRow = SkTAddOffset<uint16_t>(dst,
678 row * (int) dstRowBytes);
679 dstRow[x] = SkPixel32ToPixel16(fColorTable->operator[](index));
680 break;
681 }
682 default:
683 // This case should not be reached. We should catch an invalid
684 // color type when we check that the conversion is possible.
685 SkASSERT(false);
686 break;
687 }
607 } 688 }
608 689
609 /* 690 /*
691 *
692 * Set an RLE pixel from R, G, B values
693 *
694 */
695 void SkBmpCodec::setRLE24Pixel(SkPMColor* dst, size_t dstRowBytes,
696 const SkImageInfo& dstInfo, uint32_t x,
697 uint32_t y, uint8_t red, uint8_t green,
698 uint8_t blue) {
699 // Set the row
700 int height = dstInfo.height();
701 int row;
702 if (kBottomUp_RowOrder == fRowOrder) {
703 row = height - y - 1;
704 } else {
705 row = y;
706 }
707
708 // Set the pixel based on destination color type
709 switch (dstInfo.colorType()) {
710 case kN32_SkColorType: {
711 SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst,
712 row * (int) dstRowBytes);
713 dstRow[x] = SkPackARGB32NoCheck(0xFF, red, green, blue);
714 break;
715 }
716 case kRGB_565_SkColorType: {
717 uint16_t* dstRow = SkTAddOffset<uint16_t>(dst,
718 row * (int) dstRowBytes);
719 dstRow[x] = SkPack888ToRGB16(red, green, blue);
720 break;
721 }
722 default:
723 // This case should not be reached. We should catch an invalid
724 // color type when we check that the conversion is possible.
725 SkASSERT(false);
726 break;
727 }
728 }
729
730 /*
610 * 731 *
611 * Performs the bitmap decoding for RLE input format 732 * Performs the bitmap decoding for RLE input format
612 * RLE decoding is performed all at once, rather than a one row at a time 733 * RLE decoding is performed all at once, rather than a one row at a time
613 * 734 *
614 */ 735 */
615 SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, 736 SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo,
616 void* dst, size_t dstRowBytes) { 737 void* dst, size_t dstRowBytes) {
617 // Set RLE flags 738 // Set RLE flags
618 static const uint8_t RLE_ESCAPE = 0; 739 static const uint8_t RLE_ESCAPE = 0;
619 static const uint8_t RLE_EOL = 0; 740 static const uint8_t RLE_EOL = 0;
620 static const uint8_t RLE_EOF = 1; 741 static const uint8_t RLE_EOF = 1;
621 static const uint8_t RLE_DELTA = 2; 742 static const uint8_t RLE_DELTA = 2;
622 743
623 // Set constant values 744 // Set constant values
624 const int width = dstInfo.width(); 745 const int width = dstInfo.width();
625 const int height = dstInfo.height(); 746 const int height = dstInfo.height();
626 747
627 // Input buffer parameters 748 // Input buffer parameters
628 uint32_t currByte = 0; 749 uint32_t currByte = 0;
629 SkAutoTDeleteArray<uint8_t> buffer(SkNEW_ARRAY(uint8_t, fRemainingBytes)); 750 SkAutoTDeleteArray<uint8_t> buffer(SkNEW_ARRAY(uint8_t, fRLEBytes));
630 size_t totalBytes = stream()->read(buffer.get(), fRemainingBytes); 751 size_t totalBytes = stream()->read(buffer.get(), fRLEBytes);
631 if ((uint32_t) totalBytes < fRemainingBytes) { 752 if (totalBytes < fRLEBytes) {
632 SkDebugf("Warning: incomplete RLE file.\n"); 753 SkDebugf("Warning: incomplete RLE file.\n");
633 } else if (totalBytes <= 0) { 754 } else if (totalBytes <= 0) {
634 SkDebugf("Error: could not read RLE image data.\n"); 755 SkDebugf("Error: could not read RLE image data.\n");
635 return kInvalidInput; 756 return kInvalidInput;
636 } 757 }
637 758
638 // Destination parameters 759 // Destination parameters
639 int x = 0; 760 int x = 0;
640 int y = 0; 761 int y = 0;
641 // If the code skips pixels, remaining pixels are transparent or black 762 // If the code skips pixels, remaining pixels are transparent or black
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
700 fBitsPerPixel); 821 fBitsPerPixel);
701 // Abort if setting numPixels moves us off the edge of the 822 // Abort if setting numPixels moves us off the edge of the
702 // image. Also abort if there are not enough bytes 823 // image. Also abort if there are not enough bytes
703 // remaining in the stream to set numPixels. 824 // remaining in the stream to set numPixels.
704 if (x + numPixels > width || 825 if (x + numPixels > width ||
705 (int) totalBytes - currByte < SkAlign2(rowBytes)) { 826 (int) totalBytes - currByte < SkAlign2(rowBytes)) {
706 SkDebugf("Warning: invalid RLE input.\n"); 827 SkDebugf("Warning: invalid RLE input.\n");
707 return kIncompleteInput; 828 return kIncompleteInput;
708 } 829 }
709 // Set numPixels number of pixels 830 // Set numPixels number of pixels
710 SkPMColor* dstRow = SkTAddOffset<SkPMColor>(
711 dstPtr, y * dstRowBytes);
712 while (numPixels > 0) { 831 while (numPixels > 0) {
713 switch(fBitsPerPixel) { 832 switch(fBitsPerPixel) {
714 case 4: { 833 case 4: {
715 SkASSERT(currByte < totalBytes); 834 SkASSERT(currByte < totalBytes);
716 uint8_t val = buffer.get()[currByte++]; 835 uint8_t val = buffer.get()[currByte++];
717 setRLEPixel(dstPtr, dstRowBytes, height, x++, y, 836 setRLEPixel(dstPtr, dstRowBytes, dstInfo, x++,
718 val >> 4); 837 y, val >> 4);
719 numPixels--; 838 numPixels--;
720 if (numPixels != 0) { 839 if (numPixels != 0) {
721 setRLEPixel(dstPtr, dstRowBytes, height, 840 setRLEPixel(dstPtr, dstRowBytes, dstInfo,
722 x++, y, val & 0xF); 841 x++, y, val & 0xF);
723 numPixels--; 842 numPixels--;
724 } 843 }
725 break; 844 break;
726 } 845 }
727 case 8: 846 case 8:
728 SkASSERT(currByte < totalBytes); 847 SkASSERT(currByte < totalBytes);
729 setRLEPixel(dstPtr, dstRowBytes, height, x++, y, 848 setRLEPixel(dstPtr, dstRowBytes, dstInfo, x++,
730 buffer.get()[currByte++]); 849 y, buffer.get()[currByte++]);
731 numPixels--; 850 numPixels--;
732 break; 851 break;
733 case 24: { 852 case 24: {
734 SkASSERT(currByte + 2 < totalBytes); 853 SkASSERT(currByte + 2 < totalBytes);
735 uint8_t blue = buffer.get()[currByte++]; 854 uint8_t blue = buffer.get()[currByte++];
736 uint8_t green = buffer.get()[currByte++]; 855 uint8_t green = buffer.get()[currByte++];
737 uint8_t red = buffer.get()[currByte++]; 856 uint8_t red = buffer.get()[currByte++];
738 SkPMColor color = SkPackARGB32NoCheck( 857 setRLE24Pixel(dstPtr, dstRowBytes, dstInfo,
739 0xFF, red, green, blue); 858 x++, y, red, green, blue);
740 dstRow[x++] = color;
741 numPixels--; 859 numPixels--;
742 } 860 }
743 default: 861 default:
744 SkASSERT(false); 862 SkASSERT(false);
745 return kInvalidInput; 863 return kInvalidInput;
746 } 864 }
747 } 865 }
748 // Skip a byte if necessary to maintain alignment 866 // Skip a byte if necessary to maintain alignment
749 if (!SkIsAlign2(rowBytes)) { 867 if (!SkIsAlign2(rowBytes)) {
750 currByte++; 868 currByte++;
(...skipping 13 matching lines...) Expand all
764 // color. 882 // color.
765 if ((int) totalBytes - currByte < 2) { 883 if ((int) totalBytes - currByte < 2) {
766 SkDebugf("Warning: incomplete RLE input\n"); 884 SkDebugf("Warning: incomplete RLE input\n");
767 return kIncompleteInput; 885 return kIncompleteInput;
768 } 886 }
769 887
770 // Fill the pixels up to endX with the specified color 888 // Fill the pixels up to endX with the specified color
771 uint8_t blue = task; 889 uint8_t blue = task;
772 uint8_t green = buffer.get()[currByte++]; 890 uint8_t green = buffer.get()[currByte++];
773 uint8_t red = buffer.get()[currByte++]; 891 uint8_t red = buffer.get()[currByte++];
774 SkPMColor color = SkPackARGB32NoCheck(0xFF, red, green, blue);
775 SkPMColor* dstRow =
776 SkTAddOffset<SkPMColor>(dstPtr, y * dstRowBytes);
777 while (x < endX) { 892 while (x < endX) {
778 dstRow[x++] = color; 893 setRLE24Pixel(dstPtr, dstRowBytes, dstInfo, x++, y, red,
894 green, blue);
779 } 895 }
780 } else { 896 } else {
781 // In RLE8 or RLE4, the second byte read gives the index in the 897 // In RLE8 or RLE4, the second byte read gives the index in the
782 // color table to look up the pixel color. 898 // color table to look up the pixel color.
783 // RLE8 has one color index that gets repeated 899 // RLE8 has one color index that gets repeated
784 // RLE4 has two color indexes in the upper and lower 4 bits of 900 // RLE4 has two color indexes in the upper and lower 4 bits of
785 // the bytes, which are alternated 901 // the bytes, which are alternated
786 uint8_t indices[2] = { task, task }; 902 uint8_t indices[2] = { task, task };
787 if (4 == fBitsPerPixel) { 903 if (4 == fBitsPerPixel) {
788 indices[0] >>= 4; 904 indices[0] >>= 4;
789 indices[1] &= 0xf; 905 indices[1] &= 0xf;
790 } 906 }
791 907
792 // Set the indicated number of pixels 908 // Set the indicated number of pixels
793 for (int which = 0; x < endX; x++) { 909 for (int which = 0; x < endX; x++) {
794 setRLEPixel(dstPtr, dstRowBytes, height, x, y, 910 setRLEPixel(dstPtr, dstRowBytes, dstInfo, x, y,
795 indices[which]); 911 indices[which]);
796 which = !which; 912 which = !which;
797 } 913 }
798 } 914 }
799 } 915 }
800 } 916 }
801 } 917 }
802 918
803 /* 919 /*
804 * 920 *
805 * Performs the bitmap decoding for standard input format 921 * Performs the bitmap decoding for standard input format
806 * 922 *
807 */ 923 */
808 SkCodec::Result SkBmpCodec::decode(const SkImageInfo& dstInfo, 924 SkCodec::Result SkBmpCodec::decode(const SkImageInfo& dstInfo,
809 void* dst, size_t dstRowBytes) { 925 void* dst, size_t dstRowBytes) {
810 // Set constant values 926 // Set constant values
811 const int width = dstInfo.width(); 927 const int width = dstInfo.width();
812 const int height = dstInfo.height(); 928 const int height = dstInfo.height();
813 const size_t rowBytes = SkAlign4(compute_row_bytes(width, fBitsPerPixel)); 929 const size_t rowBytes = SkAlign4(compute_row_bytes(width, fBitsPerPixel));
814 const uint32_t alphaMask = fMasks->getAlphaMask();
815 930
816 // Get swizzler configuration 931 // Get swizzler configuration
817 SkSwizzler::SrcConfig config; 932 SkSwizzler::SrcConfig config;
818 switch (fBitsPerPixel) { 933 switch (fBitsPerPixel) {
819 case 1: 934 case 1:
820 config = SkSwizzler::kIndex1; 935 config = SkSwizzler::kIndex1;
821 break; 936 break;
822 case 2: 937 case 2:
823 config = SkSwizzler::kIndex2; 938 config = SkSwizzler::kIndex2;
824 break; 939 break;
825 case 4: 940 case 4:
826 config = SkSwizzler::kIndex4; 941 config = SkSwizzler::kIndex4;
827 break; 942 break;
828 case 8: 943 case 8:
829 config = SkSwizzler::kIndex; 944 config = SkSwizzler::kIndex;
830 break; 945 break;
831 case 24: 946 case 24:
832 config = SkSwizzler::kBGR; 947 config = SkSwizzler::kBGR;
833 break; 948 break;
834 case 32: 949 case 32:
835 if (0 == alphaMask) { 950 if (kOpaque_SkAlphaType == dstInfo.alphaType()) {
836 config = SkSwizzler::kBGRX; 951 config = SkSwizzler::kBGRX;
837 } else { 952 } else {
838 config = SkSwizzler::kBGRA; 953 config = SkSwizzler::kBGRA;
839 } 954 }
840 break; 955 break;
841 default: 956 default:
842 SkASSERT(false); 957 SkASSERT(false);
843 return kInvalidInput; 958 return kInvalidInput;
844 } 959 }
845 960
846 // Create swizzler 961 // Create swizzler
847 SkSwizzler* swizzler = SkSwizzler::CreateSwizzler(config, fColorTable.get(), 962 SkAutoTDelete<SkSwizzler> swizzler(SkSwizzler::CreateSwizzler(config,
848 dstInfo, dst, dstRowBytes, SkImageGenerator::kNo_ZeroInitialized); 963 fColorTable->readColors(), dstInfo, dst, dstRowBytes,
964 SkImageGenerator::kNo_ZeroInitialized));
849 965
850 // Allocate space for a row buffer and a source for the swizzler 966 // Allocate space for a row buffer and a source for the swizzler
851 SkAutoTDeleteArray<uint8_t> srcBuffer(SkNEW_ARRAY(uint8_t, rowBytes)); 967 SkAutoTDeleteArray<uint8_t> srcBuffer(SkNEW_ARRAY(uint8_t, rowBytes));
852 968
853 // Iterate over rows of the image 969 // Iterate over rows of the image
854 // FIXME: bool transparent = true; 970 // FIXME: bool transparent = true;
855 for (int y = 0; y < height; y++) { 971 for (int y = 0; y < height; y++) {
856 // Read a row of the input 972 // Read a row of the input
857 if (stream()->read(srcBuffer.get(), rowBytes) != rowBytes) { 973 if (stream()->read(srcBuffer.get(), rowBytes) != rowBytes) {
858 SkDebugf("Warning: incomplete input stream.\n"); 974 SkDebugf("Warning: incomplete input stream.\n");
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
895 } 1011 }
896 dstRow = SkTAddOffset<SkPMColor>(dstRow, dstRowBytes); 1012 dstRow = SkTAddOffset<SkPMColor>(dstRow, dstRowBytes);
897 } 1013 }
898 } 1014 }
899 } 1015 }
900 */ 1016 */
901 1017
902 // Finished decoding the entire image 1018 // Finished decoding the entire image
903 return kSuccess; 1019 return kSuccess;
904 } 1020 }
OLDNEW
« no previous file with comments | « src/codec/SkCodec_libbmp.h ('k') | src/codec/SkCodec_libpng.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698