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