Chromium Code Reviews| Index: src/images/SkImageDecoder_ktx.cpp |
| diff --git a/src/images/SkImageDecoder_ktx.cpp b/src/images/SkImageDecoder_ktx.cpp |
| index bf3445e98514d9734589d9f18ee98f588e1a8088..6ff245954008fed7845d651436157240ddc2870d 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); |
|
scroggo
2014/06/09 14:49:45
This is intended as a setting for the client. If t
|
| + 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); |
|
scroggo
2014/06/09 14:49:45
Again, if the client wanted unpremultiplied colors
|
| + } |
| + |
| 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); |