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 "SkBmpCodec.h" | 8 #include "SkBmpCodec.h" |
9 #include "SkBmpMaskCodec.h" | 9 #include "SkBmpMaskCodec.h" |
10 #include "SkBmpRLECodec.h" | 10 #include "SkBmpRLECodec.h" |
(...skipping 26 matching lines...) Expand all Loading... | |
37 kBitMasks_BmpCompressionMethod = 3, | 37 kBitMasks_BmpCompressionMethod = 3, |
38 kJpeg_BmpCompressionMethod = 4, | 38 kJpeg_BmpCompressionMethod = 4, |
39 kPng_BmpCompressionMethod = 5, | 39 kPng_BmpCompressionMethod = 5, |
40 kAlphaBitMasks_BmpCompressionMethod = 6, | 40 kAlphaBitMasks_BmpCompressionMethod = 6, |
41 kCMYK_BmpCompressionMethod = 11, | 41 kCMYK_BmpCompressionMethod = 11, |
42 kCMYK8BitRLE_BmpCompressionMethod = 12, | 42 kCMYK8BitRLE_BmpCompressionMethod = 12, |
43 kCMYK4BitRLE_BmpCompressionMethod = 13 | 43 kCMYK4BitRLE_BmpCompressionMethod = 13 |
44 }; | 44 }; |
45 | 45 |
46 /* | 46 /* |
47 * Used to define the input format of the bmp | |
48 */ | |
49 enum BmpInputFormat { | |
50 kStandard_BmpInputFormat, | |
51 kRLE_BmpInputFormat, | |
52 kBitMask_BmpInputFormat, | |
53 kUnknown_BmpInputFormat | |
54 }; | |
55 | |
56 /* | |
57 * Checks the start of the stream to see if the image is a bitmap | 47 * Checks the start of the stream to see if the image is a bitmap |
58 */ | 48 */ |
59 bool SkBmpCodec::IsBmp(SkStream* stream) { | 49 bool SkBmpCodec::IsBmp(SkStream* stream) { |
60 // TODO: Support "IC", "PT", "CI", "CP", "BA" | 50 // TODO: Support "IC", "PT", "CI", "CP", "BA" |
61 const char bmpSig[] = { 'B', 'M' }; | 51 const char bmpSig[] = { 'B', 'M' }; |
62 char buffer[sizeof(bmpSig)]; | 52 char buffer[sizeof(bmpSig)]; |
63 return stream->read(buffer, sizeof(bmpSig)) == sizeof(bmpSig) && | 53 return stream->read(buffer, sizeof(bmpSig)) == sizeof(bmpSig) && |
64 !memcmp(buffer, bmpSig, sizeof(bmpSig)); | 54 !memcmp(buffer, bmpSig, sizeof(bmpSig)); |
65 } | 55 } |
66 | 56 |
(...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
465 | 455 |
466 if (codecOut) { | 456 if (codecOut) { |
467 // Set the image info | 457 // Set the image info |
468 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height, | 458 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height, |
469 colorType, alphaType); | 459 colorType, alphaType); |
470 | 460 |
471 // Return the codec | 461 // Return the codec |
472 switch (inputFormat) { | 462 switch (inputFormat) { |
473 case kStandard_BmpInputFormat: | 463 case kStandard_BmpInputFormat: |
474 *codecOut = SkNEW_ARGS(SkBmpStandardCodec, (imageInfo, stream, | 464 *codecOut = SkNEW_ARGS(SkBmpStandardCodec, (imageInfo, stream, |
475 bitsPerPixel, numColors, bytesPerColor, | 465 inputFormat, bitsPerPixel, numColors, bytesPerColor, |
476 offset - bytesRead, rowOrder, inIco)); | 466 offset - bytesRead, rowOrder, inIco)); |
477 return true; | 467 return true; |
478 case kBitMask_BmpInputFormat: | 468 case kBitMask_BmpInputFormat: |
479 // Bmp-in-Ico must be standard mode | 469 // Bmp-in-Ico must be standard mode |
480 if (inIco) { | 470 if (inIco) { |
481 SkCodecPrintf("Error: Icos may not use bit mask format.\n"); | 471 SkCodecPrintf("Error: Icos may not use bit mask format.\n"); |
482 return false; | 472 return false; |
483 } | 473 } |
484 // Skip to the start of the pixel array. | 474 // Skip to the start of the pixel array. |
485 // We can do this here because there is no color table to read | 475 // We can do this here because there is no color table to read |
486 // in bit mask mode. | 476 // in bit mask mode. |
487 if (stream->skip(offset - bytesRead) != offset - bytesRead) { | 477 if (stream->skip(offset - bytesRead) != offset - bytesRead) { |
488 SkCodecPrintf("Error: unable to skip to image data.\n"); | 478 SkCodecPrintf("Error: unable to skip to image data.\n"); |
489 return false; | 479 return false; |
490 } | 480 } |
491 | 481 |
492 *codecOut = SkNEW_ARGS(SkBmpMaskCodec, (imageInfo, stream, | 482 *codecOut = SkNEW_ARGS(SkBmpMaskCodec, (imageInfo, stream, |
493 bitsPerPixel, masks.detach(), rowOrder)); | 483 inputFormat, bitsPerPixel, masks.detach(), rowOrder)); |
494 return true; | 484 return true; |
495 case kRLE_BmpInputFormat: | 485 case kRLE_BmpInputFormat: |
496 // Bmp-in-Ico must be standard mode | 486 // Bmp-in-Ico must be standard mode |
497 // When inIco is true, this line cannot be reached, since we | 487 // When inIco is true, this line cannot be reached, since we |
498 // require that RLE Bmps have a valid number of totalBytes, and | 488 // require that RLE Bmps have a valid number of totalBytes, and |
499 // Icos skip the header that contains totalBytes. | 489 // Icos skip the header that contains totalBytes. |
500 SkASSERT(!inIco); | 490 SkASSERT(!inIco); |
501 *codecOut = SkNEW_ARGS(SkBmpRLECodec, ( | 491 *codecOut = SkNEW_ARGS(SkBmpRLECodec, ( |
502 imageInfo, stream, bitsPerPixel, numColors, | 492 imageInfo, stream, inputFormat, bitsPerPixel, numColors, |
503 bytesPerColor, offset - bytesRead, rowOrder, RLEBytes)); | 493 bytesPerColor, offset - bytesRead, rowOrder, RLEBytes)); |
504 return true; | 494 return true; |
505 default: | 495 default: |
506 SkASSERT(false); | 496 SkASSERT(false); |
507 return false; | 497 return false; |
508 } | 498 } |
509 } | 499 } |
510 | 500 |
511 return true; | 501 return true; |
512 } | 502 } |
513 | 503 |
514 /* | 504 /* |
515 * Creates a bmp decoder | 505 * Creates a bmp decoder |
516 * Reads enough of the stream to determine the image format | 506 * Reads enough of the stream to determine the image format |
517 */ | 507 */ |
518 SkCodec* SkBmpCodec::NewFromStream(SkStream* stream, bool inIco) { | 508 SkCodec* SkBmpCodec::NewFromStream(SkStream* stream, bool inIco) { |
519 SkAutoTDelete<SkStream> streamDeleter(stream); | 509 SkAutoTDelete<SkStream> streamDeleter(stream); |
520 SkCodec* codec = NULL; | 510 SkCodec* codec = NULL; |
521 if (ReadHeader(stream, inIco, &codec)) { | 511 if (ReadHeader(stream, inIco, &codec)) { |
522 // codec has taken ownership of stream, so we do not need to | 512 // codec has taken ownership of stream, so we do not need to |
523 // delete it. | 513 // delete it. |
524 SkASSERT(codec); | 514 SkASSERT(codec); |
525 streamDeleter.detach(); | 515 streamDeleter.detach(); |
526 return codec; | 516 return codec; |
527 } | 517 } |
528 return NULL; | 518 return NULL; |
529 } | 519 } |
530 | 520 |
531 SkBmpCodec::SkBmpCodec(const SkImageInfo& info, SkStream* stream, | 521 SkBmpCodec::SkBmpCodec(const SkImageInfo& info, SkStream* stream, |
532 uint16_t bitsPerPixel, RowOrder rowOrder) | 522 BmpInputFormat inputFormat, uint16_t bitsPerPixel, RowOrder rowOrder) |
533 : INHERITED(info, stream) | 523 : INHERITED(info, stream) |
524 , fInputFormat(inputFormat) | |
534 , fBitsPerPixel(bitsPerPixel) | 525 , fBitsPerPixel(bitsPerPixel) |
535 , fRowOrder(rowOrder) | 526 , fRowOrder(rowOrder) |
536 {} | 527 {} |
537 | 528 |
538 bool SkBmpCodec::onRewind() { | 529 bool SkBmpCodec::onRewind() { |
539 return SkBmpCodec::ReadHeader(this->stream(), this->inIco(), NULL); | 530 return SkBmpCodec::ReadHeader(this->stream(), this->inIco(), NULL); |
540 } | 531 } |
541 | 532 |
542 /* | 533 /* |
543 * Get the destination row to start filling from | 534 * Get the destination row to start filling from |
(...skipping 11 matching lines...) Expand all Loading... | |
555 */ | 546 */ |
556 uint32_t SkBmpCodec::computeNumColors(uint32_t numColors) { | 547 uint32_t SkBmpCodec::computeNumColors(uint32_t numColors) { |
557 // Zero is a default for maxColors | 548 // Zero is a default for maxColors |
558 // Also set numColors to maxColors when it is too large | 549 // Also set numColors to maxColors when it is too large |
559 uint32_t maxColors = 1 << fBitsPerPixel; | 550 uint32_t maxColors = 1 << fBitsPerPixel; |
560 if (numColors == 0 || numColors >= maxColors) { | 551 if (numColors == 0 || numColors >= maxColors) { |
561 return maxColors; | 552 return maxColors; |
562 } | 553 } |
563 return numColors; | 554 return numColors; |
564 } | 555 } |
556 | |
557 /* | |
558 * Scanline decoder for bmps | |
559 */ | |
560 class SkBmpScanlineDecoder : public SkScanlineDecoder { | |
561 public: | |
562 SkBmpScanlineDecoder(SkBmpCodec* codec) | |
563 : INHERITED(codec->getInfo()) | |
564 , fCodec(codec) | |
565 {} | |
566 | |
567 SkCodec::Result onStart(const SkImageInfo& dstInfo, const SkCodec::Options& options, | |
568 SkPMColor inputColorPtr[], int* inputColorCount) ove rride { | |
569 if (!fCodec->rewindIfNeeded()) { | |
570 return SkCodec::kCouldNotRewind; | |
571 } | |
572 if (options.fSubset) { | |
573 // Subsets are not supported. | |
574 return SkCodec::kUnimplemented; | |
575 } | |
576 if (dstInfo.dimensions() != fCodec->getInfo().dimensions()) { | |
577 SkCodecPrintf("Error: scaling not supported.\n"); | |
578 return SkCodec::kInvalidScale; | |
579 } | |
580 if (!conversion_possible(dstInfo, fCodec->getInfo())) { | |
581 SkCodecPrintf("Error: cannot convert input type to output type.\n"); | |
582 return SkCodec::kInvalidConversion; | |
583 } | |
584 | |
585 return fCodec->onStart(dstInfo, options, inputColorPtr, inputColorCount) ; | |
586 } | |
587 | |
588 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) { | |
589 // Create a new image info representing the portion of the image to deco de | |
590 SkImageInfo rowInfo = this->dstInfo().makeWH(this->dstInfo().width(), co unt); | |
591 | |
592 // Decode the requested rows | |
593 return fCodec->decode(rowInfo, dst, rowBytes, this->options()); | |
594 } | |
595 | |
596 // TODO(msarett): Override default skipping with something more clever. | |
597 // TODO(msarett): Consider other optimizations for this codec. | |
scroggo
2015/08/14 21:53:00
Do you have any optimizations in mind?
msarett
2015/08/17 19:16:13
Not in particular. I just don't think I've analyz
scroggo
2015/08/26 22:40:09
Great. These would be good candidates to specifica
| |
598 | |
599 private: | |
600 SkAutoTDelete<SkBmpCodec> fCodec; | |
601 | |
602 typedef SkScanlineDecoder INHERITED; | |
603 }; | |
604 | |
605 SkScanlineDecoder* SkBmpCodec::NewSDFromStream(SkStream* stream) { | |
606 SkAutoTDelete<SkBmpCodec> codec(static_cast<SkBmpCodec*>(SkBmpCodec::NewFrom Stream(stream))); | |
607 if (!codec) { | |
608 return NULL; | |
609 } | |
610 | |
611 return SkNEW_ARGS(SkBmpScanlineDecoder, (codec)); | |
612 } | |
OLD | NEW |