diff options
author | 2015-08-31 06:55:13 -0700 | |
---|---|---|
committer | 2015-08-31 06:55:13 -0700 | |
commit | 5406d6f39ad042e7a0a0d4ea16beca4fe2b66492 (patch) | |
tree | af812bd6efebdd5dfec260883ee9047426011652 /src/codec/SkBmpCodec.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/SkBmpCodec.cpp')
-rw-r--r-- | src/codec/SkBmpCodec.cpp | 87 |
1 files changed, 83 insertions, 4 deletions
diff --git a/src/codec/SkBmpCodec.cpp b/src/codec/SkBmpCodec.cpp index f2f6a8e771..8d21e1dd8e 100644 --- a/src/codec/SkBmpCodec.cpp +++ b/src/codec/SkBmpCodec.cpp @@ -11,6 +11,7 @@ #include "SkBmpStandardCodec.h" #include "SkCodecPriv.h" #include "SkColorPriv.h" +#include "SkScaledCodec.h" #include "SkStream.h" /* @@ -261,10 +262,10 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { } // Check for valid dimensions from header - RowOrder rowOrder = kBottomUp_RowOrder; + SkScanlineDecoder::SkScanlineOrder rowOrder = SkScanlineDecoder::kBottomUp_SkScanlineOrder; if (height < 0) { height = -height; - rowOrder = kTopDown_RowOrder; + rowOrder = SkScanlineDecoder::kTopDown_SkScanlineOrder; } // The height field for bmp in ico is double the actual height because they // contain an XOR mask followed by an AND mask @@ -526,7 +527,7 @@ SkCodec* SkBmpCodec::NewFromStream(SkStream* stream, bool inIco) { } SkBmpCodec::SkBmpCodec(const SkImageInfo& info, SkStream* stream, - uint16_t bitsPerPixel, RowOrder rowOrder) + uint16_t bitsPerPixel, SkScanlineDecoder::SkScanlineOrder rowOrder) : INHERITED(info, stream) , fBitsPerPixel(bitsPerPixel) , fRowOrder(rowOrder) @@ -536,6 +537,14 @@ bool SkBmpCodec::onRewind() { return SkBmpCodec::ReadHeader(this->stream(), this->inIco(), nullptr); } +int32_t SkBmpCodec::getDstRow(int32_t y, int32_t height) { + if (SkScanlineDecoder::kTopDown_SkScanlineOrder == fRowOrder) { + return y; + } + SkASSERT(SkScanlineDecoder::kBottomUp_SkScanlineOrder == fRowOrder); + return height - y - 1; +} + /* * Get the destination row to start filling from * Used to fill the remainder of the image on incomplete input for bmps @@ -544,7 +553,8 @@ bool SkBmpCodec::onRewind() { * filling at the top of the image. */ void* SkBmpCodec::getDstStartRow(void* dst, size_t dstRowBytes, int32_t y) const { - return (kTopDown_RowOrder == fRowOrder) ? SkTAddOffset<void*>(dst, y * dstRowBytes) : dst; + return (SkScanlineDecoder::kTopDown_SkScanlineOrder == fRowOrder) ? + SkTAddOffset<void*>(dst, y * dstRowBytes) : dst; } /* @@ -559,3 +569,72 @@ uint32_t SkBmpCodec::computeNumColors(uint32_t numColors) { } return numColors; } + +/* + * Scanline decoder for bmps + */ +class SkBmpScanlineDecoder : public SkScanlineDecoder { +public: + SkBmpScanlineDecoder(SkBmpCodec* codec) + : INHERITED(codec->getInfo()) + , fCodec(codec) + {} + + SkEncodedFormat onGetEncodedFormat() const override { + return kBMP_SkEncodedFormat; + } + + SkCodec::Result onStart(const SkImageInfo& dstInfo, const SkCodec::Options& options, + SkPMColor inputColorPtr[], int* inputColorCount) override { + if (!fCodec->rewindIfNeeded()) { + return SkCodec::kCouldNotRewind; + } + if (options.fSubset) { + // Subsets are not supported. + return SkCodec::kUnimplemented; + } + if (dstInfo.dimensions() != this->getInfo().dimensions()) { + if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) { + return SkCodec::kInvalidScale; + } + } + if (!conversion_possible(dstInfo, this->getInfo())) { + SkCodecPrintf("Error: cannot convert input type to output type.\n"); + return SkCodec::kInvalidConversion; + } + + return fCodec->prepareToDecode(dstInfo, options, inputColorPtr, inputColorCount); + } + + SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) override { + // Create a new image info representing the portion of the image to decode + SkImageInfo rowInfo = this->dstInfo().makeWH(this->dstInfo().width(), count); + + // Decode the requested rows + return fCodec->decodeRows(rowInfo, dst, rowBytes, this->options()); + } + + SkScanlineOrder onGetScanlineOrder() const override { + return fCodec->fRowOrder; + } + + int onGetY() const override { + return fCodec->getDstRow(this->INHERITED::onGetY(), this->dstInfo().height()); + } + + // TODO(msarett): Override default skipping with something more clever. + +private: + SkAutoTDelete<SkBmpCodec> fCodec; + + typedef SkScanlineDecoder INHERITED; +}; + +SkScanlineDecoder* SkBmpCodec::NewSDFromStream(SkStream* stream) { + SkAutoTDelete<SkBmpCodec> codec(static_cast<SkBmpCodec*>(SkBmpCodec::NewFromStream(stream))); + if (!codec) { + return NULL; + } + + return SkNEW_ARGS(SkBmpScanlineDecoder, (codec.detach())); +} |