Chromium Code Reviews| 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 |