diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/images/SkForceLinking.cpp | 1 | ||||
-rw-r--r-- | src/images/SkImageDecoder.cpp | 2 | ||||
-rw-r--r-- | src/images/SkImageDecoder_pkm.cpp | 122 |
3 files changed, 125 insertions, 0 deletions
diff --git a/src/images/SkForceLinking.cpp b/src/images/SkForceLinking.cpp index e4dc60a448..dfe2d8aa12 100644 --- a/src/images/SkForceLinking.cpp +++ b/src/images/SkForceLinking.cpp @@ -18,6 +18,7 @@ int SkForceLinking(bool doNotPassTrue) { CreateWEBPImageDecoder(); CreateBMPImageDecoder(); CreateICOImageDecoder(); + CreatePKMImageDecoder(); CreateWBMPImageDecoder(); // Only link GIF and PNG on platforms that build them. See images.gyp #if !defined(SK_BUILD_FOR_MAC) && !defined(SK_BUILD_FOR_WIN) && !defined(SK_BUILD_FOR_NACL) \ diff --git a/src/images/SkImageDecoder.cpp b/src/images/SkImageDecoder.cpp index 32cf087ed8..47523117f5 100644 --- a/src/images/SkImageDecoder.cpp +++ b/src/images/SkImageDecoder.cpp @@ -84,6 +84,8 @@ const char* SkImageDecoder::GetFormatName(Format format) { return "GIF"; case kICO_Format: return "ICO"; + case kPKM_Format: + return "PKM"; case kJPEG_Format: return "JPEG"; case kPNG_Format: diff --git a/src/images/SkImageDecoder_pkm.cpp b/src/images/SkImageDecoder_pkm.cpp new file mode 100644 index 0000000000..07f162b4e9 --- /dev/null +++ b/src/images/SkImageDecoder_pkm.cpp @@ -0,0 +1,122 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkColorPriv.h" +#include "SkImageDecoder.h" +#include "SkStream.h" +#include "SkStreamHelpers.h" +#include "SkTypes.h" + +#include "etc1.h" + +class SkPKMImageDecoder : public SkImageDecoder { +public: + SkPKMImageDecoder() { } + + virtual Format getFormat() const SK_OVERRIDE { + return kPKM_Format; + } + +protected: + virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; + +private: + typedef SkImageDecoder INHERITED; +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +bool SkPKMImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { + SkAutoMalloc autoMal; + const size_t length = CopyStreamToStorage(&autoMal, stream); + if (0 == length) { + return false; + } + + unsigned char* buf = (unsigned char*)autoMal.get(); + + // Make sure original PKM header is there... + SkASSERT(etc1_pkm_is_valid(buf)); + + const unsigned short width = etc1_pkm_get_width(buf); + const unsigned short height = etc1_pkm_get_height(buf); + + // should we allow the Chooser (if present) to pick a config for us??? + if (!this->chooseFromOneChoice(SkBitmap::kARGB_8888_Config, width, height)) { + return false; + } + + bm->setConfig(SkBitmap::kARGB_8888_Config, width, height, 0, kOpaque_SkAlphaType); + if (SkImageDecoder::kDecodeBounds_Mode == mode) { + return true; + } + + if (!this->allocPixelRef(bm, NULL)) { + return false; + } + + // Lock the pixels, since we're about to write to them... + SkAutoLockPixels alp(*bm); + + // Advance buffer past the header + buf += ETC_PKM_HEADER_SIZE; + + // ETC1 Data is encoded as RGB pixels, so we should extract it as such + int nPixels = width * height; + SkAutoMalloc outRGBData(nPixels * 3); + etc1_byte *outRGBDataPtr = reinterpret_cast<etc1_byte *>(outRGBData.get()); + + // Decode ETC1 + if (etc1_decode_image(buf, outRGBDataPtr, width, height, 3, width*3)) { + return false; + } + + // Set each of the pixels... + const uint8_t *src = reinterpret_cast<uint8_t *>(outRGBDataPtr); + uint8_t *dst = reinterpret_cast<uint8_t *>(bm->getPixels()); + for (int i = 0; i < width*height; ++i) { + *dst++ = src[2]; // B + *dst++ = src[1]; // G + *dst++ = src[0]; // R + *dst++ = 0xFF; // Opaque alpha... + src += 3; + } + + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////// +DEFINE_DECODER_CREATOR(PKMImageDecoder); +///////////////////////////////////////////////////////////////////////////////////////// + +static bool is_pkm(SkStreamRewindable* stream) { + // Read the PKM header and make sure it's valid. + unsigned char buf[ETC_PKM_HEADER_SIZE]; + if (stream->read((void*)buf, ETC_PKM_HEADER_SIZE) != ETC_PKM_HEADER_SIZE) { + return false; + } + + return SkToBool(etc1_pkm_is_valid(buf)); +} + +static SkImageDecoder* sk_libpkm_dfactory(SkStreamRewindable* stream) { + if (is_pkm(stream)) { + return SkNEW(SkPKMImageDecoder); + } + return NULL; +} + +static SkImageDecoder_DecodeReg gReg(sk_libpkm_dfactory); + +static SkImageDecoder::Format get_format_pkm(SkStreamRewindable* stream) { + if (is_pkm(stream)) { + return SkImageDecoder::kPKM_Format; + } + return SkImageDecoder::kUnknown_Format; +} + +static SkImageDecoder_FormatReg gFormatReg(get_format_pkm); |