diff options
author | msarett <msarett@google.com> | 2015-08-31 06:55:13 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-08-31 06:55:13 -0700 |
commit | 5406d6f39ad042e7a0a0d4ea16beca4fe2b66492 (patch) | |
tree | af812bd6efebdd5dfec260883ee9047426011652 /src/codec/SkBmpRLECodec.cpp | |
parent | 8db52b6367956c22e0cb1be8a9b77b154d21bbf9 (diff) |
Scanline decoding for bmp
Redesigns SkScanlineDecoder.h to indicate the ordering
in which the scanlines are provided
Refactors SkSwizzler::Fill() to include the zeroInit check
and to actually be correct.
BUG=skia:3257
BUG=skia:4198
Review URL: https://codereview.chromium.org/1287423002
Diffstat (limited to 'src/codec/SkBmpRLECodec.cpp')
-rw-r--r-- | src/codec/SkBmpRLECodec.cpp | 181 |
1 files changed, 98 insertions, 83 deletions
diff --git a/src/codec/SkBmpRLECodec.cpp b/src/codec/SkBmpRLECodec.cpp index 1bd14094f9..58c060531e 100644 --- a/src/codec/SkBmpRLECodec.cpp +++ b/src/codec/SkBmpRLECodec.cpp @@ -8,6 +8,7 @@ #include "SkBmpRLECodec.h" #include "SkCodecPriv.h" #include "SkColorPriv.h" +#include "SkScaledCodec.h" #include "SkScanlineDecoder.h" #include "SkStream.h" @@ -15,13 +16,10 @@ * Creates an instance of the decoder * Called only by NewFromStream */ -SkBmpRLECodec::SkBmpRLECodec(const SkImageInfo& info, - SkStream* stream, - uint16_t bitsPerPixel, - uint32_t numColors, - uint32_t bytesPerColor, - uint32_t offset, - SkBmpCodec::RowOrder rowOrder, +SkBmpRLECodec::SkBmpRLECodec(const SkImageInfo& info, SkStream* stream, + uint16_t bitsPerPixel, uint32_t numColors, + uint32_t bytesPerColor, uint32_t offset, + SkScanlineDecoder::SkScanlineOrder rowOrder, size_t RLEBytes) : INHERITED(info, stream, bitsPerPixel, rowOrder) , fColorTable(nullptr) @@ -30,16 +28,18 @@ SkBmpRLECodec::SkBmpRLECodec(const SkImageInfo& info, , fOffset(offset) , fStreamBuffer(new uint8_t[RLEBytes]) , fRLEBytes(RLEBytes) - , fCurrRLEByte(0) {} + , fCurrRLEByte(0) + , fSampleX(1) +{} /* * Initiates the bitmap decode */ SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, - void* dst, size_t dstRowBytes, - const Options& opts, - SkPMColor* inputColorPtr, - int* inputColorCount) { + void* dst, size_t dstRowBytes, + const Options& opts, + SkPMColor* inputColorPtr, + int* inputColorCount) { if (!this->rewindIfNeeded()) { return kCouldNotRewind; } @@ -56,24 +56,13 @@ SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, return kInvalidConversion; } - // Create the color table if necessary and prepare the stream for decode - // Note that if it is non-nullptr, inputColorCount will be modified - if (!this->createColorTable(inputColorCount)) { - SkCodecPrintf("Error: could not create color table.\n"); - return kInvalidInput; - } - - // Copy the color table to the client if necessary - copy_color_table(dstInfo, fColorTable, inputColorPtr, inputColorCount); - - // Initialize a swizzler if necessary - if (!this->initializeStreamBuffer()) { - SkCodecPrintf("Error: cannot initialize swizzler.\n"); - return kInvalidConversion; + Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputColorCount); + if (kSuccess != result) { + return result; } // Perform the decode - return decode(dstInfo, dst, dstRowBytes, opts); + return this->decodeRows(dstInfo, dst, dstRowBytes, opts); } /* @@ -144,6 +133,15 @@ SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, bool SkBmpRLECodec::initializeStreamBuffer() { // Setup a buffer to contain the full input stream + // TODO (msarett): I'm not sure it is smart or optimal to trust fRLEBytes (read from header) + // as the size of our buffer. First of all, the decode fails if fRLEBytes is + // corrupt (negative, zero, or small) when we might be able to decode + // successfully with a fixed size buffer. Additionally, we would save memory + // using a fixed size buffer if the RLE encoding is large. On the other hand, + // we may also waste memory with a fixed size buffer. And determining a + // minimum size for our buffer would depend on the image width (so it's not + // really "fixed" size), and we may end up allocating a buffer that is + // generally larger than the average encoded size anyway. size_t totalBytes = this->stream()->read(fStreamBuffer.get(), fRLEBytes); if (totalBytes < fRLEBytes) { fRLEBytes = totalBytes; @@ -153,6 +151,7 @@ bool SkBmpRLECodec::initializeStreamBuffer() { SkCodecPrintf("Error: could not read RLE image data.\n"); return false; } + fCurrRLEByte = 0; return true; } @@ -197,32 +196,29 @@ size_t SkBmpRLECodec::checkForMoreData() { void SkBmpRLECodec::setPixel(void* dst, size_t dstRowBytes, const SkImageInfo& dstInfo, uint32_t x, uint32_t y, uint8_t index) { - // Set the row - int height = dstInfo.height(); - int row; - if (SkBmpCodec::kBottomUp_RowOrder == this->rowOrder()) { - row = height - y - 1; - } else { - row = y; - } - - // Set the pixel based on destination color type - switch (dstInfo.colorType()) { - case kN32_SkColorType: { - SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes); - dstRow[x] = fColorTable->operator[](index); - break; - } - case kRGB_565_SkColorType: { - uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, row * (int) dstRowBytes); - dstRow[x] = SkPixel32ToPixel16(fColorTable->operator[](index)); - break; + if (is_coord_necessary(x, fSampleX, dstInfo.width())) { + // Set the row + uint32_t row = this->getDstRow(y, dstInfo.height()); + + // Set the pixel based on destination color type + const int dstX = get_dst_coord(x, fSampleX); + switch (dstInfo.colorType()) { + case kN32_SkColorType: { + SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes); + dstRow[dstX] = fColorTable->operator[](index); + break; + } + case kRGB_565_SkColorType: { + uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, row * (int) dstRowBytes); + dstRow[dstX] = SkPixel32ToPixel16(fColorTable->operator[](index)); + break; + } + default: + // This case should not be reached. We should catch an invalid + // color type when we check that the conversion is possible. + SkASSERT(false); + break; } - default: - // This case should not be reached. We should catch an invalid - // color type when we check that the conversion is possible. - SkASSERT(false); - break; } } @@ -233,42 +229,62 @@ void SkBmpRLECodec::setRGBPixel(void* dst, size_t dstRowBytes, const SkImageInfo& dstInfo, uint32_t x, uint32_t y, uint8_t red, uint8_t green, uint8_t blue) { - // Set the row - int height = dstInfo.height(); - int row; - if (SkBmpCodec::kBottomUp_RowOrder == this->rowOrder()) { - row = height - y - 1; - } else { - row = y; + if (is_coord_necessary(x, fSampleX, dstInfo.width())) { + // Set the row + uint32_t row = this->getDstRow(y, dstInfo.height()); + + // Set the pixel based on destination color type + const int dstX = get_dst_coord(x, fSampleX); + switch (dstInfo.colorType()) { + case kN32_SkColorType: { + SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes); + dstRow[dstX] = SkPackARGB32NoCheck(0xFF, red, green, blue); + break; + } + case kRGB_565_SkColorType: { + uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, row * (int) dstRowBytes); + dstRow[dstX] = SkPack888ToRGB16(red, green, blue); + break; + } + default: + // This case should not be reached. We should catch an invalid + // color type when we check that the conversion is possible. + SkASSERT(false); + break; + } } +} - // Set the pixel based on destination color type - switch (dstInfo.colorType()) { - case kN32_SkColorType: { - SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes); - dstRow[x] = SkPackARGB32NoCheck(0xFF, red, green, blue); - break; - } - case kRGB_565_SkColorType: { - uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, row * (int) dstRowBytes); - dstRow[x] = SkPack888ToRGB16(red, green, blue); - break; - } - default: - // This case should not be reached. We should catch an invalid - // color type when we check that the conversion is possible. - SkASSERT(false); - break; +SkCodec::Result SkBmpRLECodec::prepareToDecode(const SkImageInfo& dstInfo, + const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { + // Create the color table if necessary and prepare the stream for decode + // Note that if it is non-NULL, inputColorCount will be modified + if (!this->createColorTable(inputColorCount)) { + SkCodecPrintf("Error: could not create color table.\n"); + return SkCodec::kInvalidInput; } + + // Copy the color table to the client if necessary + copy_color_table(dstInfo, this->fColorTable, inputColorPtr, inputColorCount); + + // Initialize a buffer for encoded RLE data + if (!this->initializeStreamBuffer()) { + SkCodecPrintf("Error: cannot initialize stream buffer.\n"); + return SkCodec::kInvalidConversion; + } + + SkScaledCodec::ComputeSampleSize(dstInfo, this->getInfo(), &fSampleX, NULL); + + return SkCodec::kSuccess; } /* * Performs the bitmap decoding for RLE input format * RLE decoding is performed all at once, rather than a one row at a time */ -SkCodec::Result SkBmpRLECodec::decode(const SkImageInfo& dstInfo, - void* dst, size_t dstRowBytes, - const Options& opts) { +SkCodec::Result SkBmpRLECodec::decodeRows(const SkImageInfo& dstInfo, + void* dst, size_t dstRowBytes, + const Options& opts) { // Set RLE flags static const uint8_t RLE_ESCAPE = 0; static const uint8_t RLE_EOL = 0; @@ -276,7 +292,7 @@ SkCodec::Result SkBmpRLECodec::decode(const SkImageInfo& dstInfo, static const uint8_t RLE_DELTA = 2; // Set constant values - const int width = dstInfo.width(); + const int width = this->getInfo().width(); const int height = dstInfo.height(); // Destination parameters @@ -288,9 +304,8 @@ SkCodec::Result SkBmpRLECodec::decode(const SkImageInfo& dstInfo, // Because of the need for transparent pixels, kN32 is the only color // type that makes sense for the destination format. SkASSERT(kN32_SkColorType == dstInfo.colorType()); - if (kNo_ZeroInitialized == opts.fZeroInitialized) { - SkSwizzler::Fill(dst, dstInfo, dstRowBytes, height, SK_ColorTRANSPARENT, nullptr); - } + SkSwizzler::Fill(dst, dstInfo, dstRowBytes, height, SK_ColorTRANSPARENT, + NULL, opts.fZeroInitialized); while (true) { // If we have reached a row that is beyond the requested height, we have |