diff options
author | 2014-06-06 06:16:28 -0700 | |
---|---|---|
committer | 2014-06-06 06:16:28 -0700 | |
commit | c250d2e4abdbe8193357696518592af8a0b4555a (patch) | |
tree | ec333c67dd8a8fa3690ac4a2bbbcc8aab4e9120f /src/images/SkImageDecoder_ktx.cpp | |
parent | b0b0feb71f0841497c041aa4aca2b10e032224e0 (diff) |
Initial KTX encoder
The encoder comes with tests to check that the encoding/decoding
operations between ETC encoded bitmaps and ARGB bitmaps are sane.
R=bsalomon@google.com, robertphillips@google.com
Author: krajcevski@google.com
Review URL: https://codereview.chromium.org/312353003
Diffstat (limited to 'src/images/SkImageDecoder_ktx.cpp')
-rw-r--r-- | src/images/SkImageDecoder_ktx.cpp | 89 |
1 files changed, 86 insertions, 3 deletions
diff --git a/src/images/SkImageDecoder_ktx.cpp b/src/images/SkImageDecoder_ktx.cpp index bf3445e985..6ff2459540 100644 --- a/src/images/SkImageDecoder_ktx.cpp +++ b/src/images/SkImageDecoder_ktx.cpp @@ -7,6 +7,7 @@ #include "SkColorPriv.h" #include "SkImageDecoder.h" +#include "SkPixelRef.h" #include "SkScaledBitmapSampler.h" #include "SkStream.h" #include "SkStreamHelpers.h" @@ -73,7 +74,7 @@ bool SkKTXImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { bm->setConfig(SkBitmap::kARGB_8888_Config, sampler.scaledWidth(), sampler.scaledHeight(), 0, - ktxFile.isRGBA8()? kUnpremul_SkAlphaType : kOpaque_SkAlphaType); + ktxFile.isRGBA8()? kPremul_SkAlphaType : kOpaque_SkAlphaType); if (SkImageDecoder::kDecodeBounds_Mode == mode) { return true; } @@ -135,6 +136,15 @@ bool SkKTXImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { } else if (ktxFile.isRGBA8()) { + // If we know that the image contains premultiplied alpha, then + // don't premultiply it upon decoding. + bool setRequireUnpremul = false; + const SkString premulKey("KTXPremultipliedAlpha"); + if (ktxFile.getValueForKey(premulKey) == SkString("True")) { + this->setRequireUnpremultipliedColors(true); + setRequireUnpremul = true; + } + // Uncompressed RGBA data if (!sampler.begin(bm, SkScaledBitmapSampler::kRGBA, *this)) { return false; @@ -150,14 +160,83 @@ bool SkKTXImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { srcRow += sampler.srcDY() * srcRowBytes; } + // Reset this in case the decoder needs to be used again. + if (setRequireUnpremul) { + this->setRequireUnpremultipliedColors(false); + } + return true; } return false; } +/////////////////////////////////////////////////////////////////////////////// + +// KTX Image Encoder +// +// This encoder takes a best guess at how to encode the bitmap passed to it. If +// there is an installed discardable pixel ref with existing PKM data, then we +// will repurpose the existing ETC1 data into a KTX file. If the data contains +// KTX data, then we simply return a copy of the same data. For all other files, +// the underlying KTX library tries to do its best to encode the appropriate +// data specified by the bitmap based on the config. (i.e. kAlpha8_Config will +// be represented as a full resolution 8-bit image dump with the appropriate +// OpenGL defines in the header). + +class SkKTXImageEncoder : public SkImageEncoder { +protected: + virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) SK_OVERRIDE; + +private: + virtual bool encodePKM(SkWStream* stream, const SkData *data); + typedef SkImageEncoder INHERITED; +}; + +bool SkKTXImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, int) { + SkAutoDataUnref data(bitmap.pixelRef()->refEncodedData()); + + // Is this even encoded data? + if (NULL != data) { + const uint8_t *bytes = data->bytes(); + if (etc1_pkm_is_valid(bytes)) { + return this->encodePKM(stream, data); + } + + // Is it a KTX file?? + if (SkKTXFile::is_ktx(bytes)) { + return stream->write(bytes, data->size()); + } + + // If it's neither a KTX nor a PKM, then we need to + // get at the actual pixels, so fall through and decompress... + } + + return SkKTXFile::WriteBitmapToKTX(stream, bitmap); +} + +bool SkKTXImageEncoder::encodePKM(SkWStream* stream, const SkData *data) { + const uint8_t* bytes = data->bytes(); + SkASSERT(etc1_pkm_is_valid(bytes)); + + etc1_uint32 width = etc1_pkm_get_width(bytes); + etc1_uint32 height = etc1_pkm_get_height(bytes); + + // ETC1 Data is stored as compressed 4x4 pixel blocks, so we must make sure + // that our dimensions are valid. + if (width == 0 || (width & 3) != 0 || height == 0 || (height & 3) != 0) { + return false; + } + + // Advance pointer to etc1 data. + bytes += ETC_PKM_HEADER_SIZE; + + return SkKTXFile::WriteETC1ToKTX(stream, bytes, width, height); +} + ///////////////////////////////////////////////////////////////////////////////////////// DEFINE_DECODER_CREATOR(KTXImageDecoder); +DEFINE_ENCODER_CREATOR(KTXImageEncoder); ///////////////////////////////////////////////////////////////////////////////////////// static SkImageDecoder* sk_libktx_dfactory(SkStreamRewindable* stream) { @@ -167,8 +246,6 @@ static SkImageDecoder* sk_libktx_dfactory(SkStreamRewindable* stream) { return NULL; } -static SkImageDecoder_DecodeReg gReg(sk_libktx_dfactory); - static SkImageDecoder::Format get_format_ktx(SkStreamRewindable* stream) { if (SkKTXFile::is_ktx(stream)) { return SkImageDecoder::kKTX_Format; @@ -176,4 +253,10 @@ static SkImageDecoder::Format get_format_ktx(SkStreamRewindable* stream) { return SkImageDecoder::kUnknown_Format; } +SkImageEncoder* sk_libktx_efactory(SkImageEncoder::Type t) { + return (SkImageEncoder::kKTX_Type == t) ? SkNEW(SkKTXImageEncoder) : NULL; +} + +static SkImageDecoder_DecodeReg gReg(sk_libktx_dfactory); static SkImageDecoder_FormatReg gFormatReg(get_format_ktx); +static SkImageEncoder_EncodeReg gEReg(sk_libktx_efactory); |