diff options
-rw-r--r-- | Android.mk | 9 | ||||
-rw-r--r-- | include/images/SkImageEncoder.h | 3 | ||||
-rw-r--r-- | src/images/SkImageDecoder_libwebp.cpp | 139 |
3 files changed, 145 insertions, 6 deletions
@@ -2,7 +2,7 @@ BASE_PATH := $(call my-dir) LOCAL_PATH:= $(call my-dir) ############################################################# -# build the skia+fretype+png+jpeg+zlib+gif library +# build the skia+fretype+png+jpeg+zlib+gif+webp library # include $(CLEAR_VARS) @@ -73,9 +73,9 @@ LOCAL_SRC_FILES:= \ src/images/SkImageDecoder_libgif.cpp \ src/images/SkImageDecoder_libjpeg.cpp \ src/images/SkImageDecoder_libpng.cpp \ + src/images/SkImageDecoder_libwebp.cpp \ src/images/SkImageDecoder_libico.cpp \ src/images/SkImageDecoder_wbmp.cpp \ - src/images/SkImageDecoder_libwebp.cpp \ src/images/SkImageEncoder.cpp \ src/images/SkImageRef.cpp \ src/images/SkImageRef_GlobalPool.cpp \ @@ -218,7 +218,7 @@ LOCAL_SRC_FILES += \ LOCAL_SHARED_LIBRARIES := \ libcutils \ - libemoji \ + libemoji \ libjpeg \ libutils \ libz @@ -227,7 +227,8 @@ LOCAL_STATIC_LIBRARIES := \ libft2 \ libpng \ libgif \ - libwebp-decode + libwebp-decode \ + libwebp-encode LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/src/core \ diff --git a/include/images/SkImageEncoder.h b/include/images/SkImageEncoder.h index 94989c0..c56e080 100644 --- a/include/images/SkImageEncoder.h +++ b/include/images/SkImageEncoder.h @@ -10,7 +10,8 @@ class SkImageEncoder { public: enum Type { kJPEG_Type, - kPNG_Type + kPNG_Type, + kWEBP_Type }; static SkImageEncoder* Create(Type); diff --git a/src/images/SkImageDecoder_libwebp.cpp b/src/images/SkImageDecoder_libwebp.cpp index 4d79213..efbb696 100644 --- a/src/images/SkImageDecoder_libwebp.cpp +++ b/src/images/SkImageDecoder_libwebp.cpp @@ -35,6 +35,7 @@ extern "C" { // Here, we enforce using local copy in webp sub-directory. #include "webp/decode.h" #include "webp/decode_vp8.h" +#include "webp/encode.h" } /* If defined, work around missing padding byte in content generated by webpconv */ @@ -637,6 +638,133 @@ bool SkWEBPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap, Mod /////////////////////////////////////////////////////////////////////////////// +typedef void (*ScanlineImporter)(const uint8_t* in, uint8_t* out, int width, + const SkPMColor* SK_RESTRICT ctable); + +static void ARGB_8888_To_RGB(const uint8_t* in, uint8_t* rgb, int width, + const SkPMColor*) { + const uint32_t* SK_RESTRICT src = (const uint32_t*)in; + for (int i = 0; i < width; ++i) { + const uint32_t c = *src++; + rgb[0] = SkGetPackedR32(c); + rgb[1] = SkGetPackedG32(c); + rgb[2] = SkGetPackedB32(c); + rgb += 3; + } +} + +static void RGB_565_To_RGB(const uint8_t* in, uint8_t* rgb, int width, + const SkPMColor*) { + const uint16_t* SK_RESTRICT src = (const uint16_t*)in; + for (int i = 0; i < width; ++i) { + const uint16_t c = *src++; + rgb[0] = SkPacked16ToR32(c); + rgb[1] = SkPacked16ToG32(c); + rgb[2] = SkPacked16ToB32(c); + rgb += 3; + } +} + +static void ARGB_4444_To_RGB(const uint8_t* in, uint8_t* rgb, int width, + const SkPMColor*) { + const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)in; + for (int i = 0; i < width; ++i) { + const SkPMColor16 c = *src++; + rgb[0] = SkPacked4444ToR32(c); + rgb[1] = SkPacked4444ToG32(c); + rgb[2] = SkPacked4444ToB32(c); + rgb += 3; + } +} + +static void Index8_To_RGB(const uint8_t* in, uint8_t* rgb, int width, + const SkPMColor* SK_RESTRICT ctable) { + const uint8_t* SK_RESTRICT src = (const uint8_t*)in; + for (int i = 0; i < width; ++i) { + const uint32_t c = ctable[*src++]; + rgb[0] = SkGetPackedR32(c); + rgb[1] = SkGetPackedG32(c); + rgb[2] = SkGetPackedB32(c); + rgb += 3; + } +} + +static ScanlineImporter ChooseImporter(const SkBitmap::Config& config) { + switch (config) { + case SkBitmap::kARGB_8888_Config: + return ARGB_8888_To_RGB; + case SkBitmap::kRGB_565_Config: + return RGB_565_To_RGB; + case SkBitmap::kARGB_4444_Config: + return ARGB_4444_To_RGB; + case SkBitmap::kIndex8_Config: + return Index8_To_RGB; + default: + return NULL; + } +} + +static int StreamWriter(const uint8_t* data, size_t data_size, + const WebPPicture* const picture) { + SkWStream* const stream = (SkWStream*)picture->custom_ptr; + return stream->write(data, data_size) ? 1 : 0; +} + +class SkWEBPImageEncoder : public SkImageEncoder { +protected: + virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality); +}; + +bool SkWEBPImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bm, + int quality) { + const SkBitmap::Config config = bm.getConfig(); + const ScanlineImporter scanline_import = ChooseImporter(config); + if (NULL == scanline_import) { + return false; + } + + SkAutoLockPixels alp(bm); + SkAutoLockColors ctLocker; + if (NULL == bm.getPixels()) { + return false; + } + + WebPConfig webp_config; + if (!WebPConfigPreset(&webp_config, WEBP_PRESET_DEFAULT, quality)) { + return false; + } + + WebPPicture pic; + WebPPictureInit(&pic); + pic.width = bm.width(); + pic.height = bm.height(); + pic.writer = StreamWriter; + pic.custom_ptr = (void*)stream; + + const SkPMColor* colors = ctLocker.lockColors(bm); + const uint8_t* src = (uint8_t*)bm.getPixels(); + const int rgb_stride = pic.width * 3; + + // Import (for each scanline) the bit-map image (in appropriate color-space) + // to RGB color space. + uint8_t* rgb = new uint8_t[rgb_stride * pic.height]; + for (int y = 0; y < pic.height; ++y) { + scanline_import(src + y * bm.rowBytes(), rgb + y * rgb_stride, + pic.width, colors); + } + + bool ok = WebPPictureImportRGB(&pic, rgb, rgb_stride); + delete[] rgb; + + ok = ok && WebPEncode(&webp_config, &pic); + WebPPictureFree(&pic); + + return ok; +} + + +/////////////////////////////////////////////////////////////////////////////// + #include "SkTRegistry.h" static SkImageDecoder* DFactory(SkStream* stream) { @@ -652,4 +780,13 @@ SkImageDecoder* sk_libwebp_dfactory(SkStream* stream) { return DFactory(stream); } -static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(DFactory); +static SkImageEncoder* EFactory(SkImageEncoder::Type t) { + return (SkImageEncoder::kWEBP_Type == t) ? SkNEW(SkWEBPImageEncoder) : NULL; +} + +SkImageEncoder* sk_libwebp_efactory(SkImageEncoder::Type t) { + return EFactory(t); +} + +static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libwebp_dfactory); +static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libwebp_efactory); |