aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/images
diff options
context:
space:
mode:
authorGravatar msarett <msarett@google.com>2016-03-23 19:19:28 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-03-23 19:19:28 -0700
commitf037fdebda2a2626e6512d7532063f2cd41a264d (patch)
treec9e722006b56c664953a68699a2bafef8f104035 /src/images
parente8f3062a36d3682f4019309a32b5b84dc9eddf8c (diff)
Delete SkImageDecoder
This image decoding implementation has been replaced by SkCodec in Android. Additionally, we have replaced uses of SkImageDecoder in Skia and Google3 with uses of SkCodec. Now we can delete SkImageDecoder :). BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1820503002 CQ_EXTRA_TRYBOTS=client.skia.compile:Build-Ubuntu-GCC-x86_64-Release-CMake-Trybot,Build-Mac-Clang-x86_64-Release-CMake-Trybot Committed: https://skia.googlesource.com/skia/+/f799706656f2581c5bf5510d94df3fa17cce1607 Committed: https://skia.googlesource.com/skia/+/5b6e73e0c8282c4d85accbfbcecc6dee84f8a1eb Review URL: https://codereview.chromium.org/1820503002
Diffstat (limited to 'src/images')
-rw-r--r--src/images/SkForceLinking.cpp26
-rw-r--r--src/images/SkImageDecoder.cpp204
-rw-r--r--src/images/SkImageDecoder_FactoryDefault.cpp9
-rw-r--r--src/images/SkImageDecoder_FactoryRegistrar.cpp63
-rw-r--r--src/images/SkImageDecoder_astc.cpp203
-rw-r--r--src/images/SkImageDecoder_ktx.cpp242
-rw-r--r--src/images/SkImageDecoder_libbmp.cpp166
-rw-r--r--src/images/SkImageDecoder_libgif.cpp541
-rw-r--r--src/images/SkImageDecoder_libico.cpp456
-rw-r--r--src/images/SkImageDecoder_libjpeg.cpp757
-rw-r--r--src/images/SkImageDecoder_libpng.cpp683
-rw-r--r--src/images/SkImageDecoder_libwebp.cpp314
-rw-r--r--src/images/SkImageDecoder_pkm.cpp128
-rw-r--r--src/images/SkImageDecoder_wbmp.cpp173
-rw-r--r--src/images/SkJpegUtility.cpp102
-rw-r--r--src/images/SkJpegUtility.h18
-rw-r--r--src/images/SkScaledBitmapSampler.cpp877
-rw-r--r--src/images/SkScaledBitmapSampler.h107
-rw-r--r--src/images/bmpdecoderhelper.cpp369
-rw-r--r--src/images/bmpdecoderhelper.h116
20 files changed, 20 insertions, 5534 deletions
diff --git a/src/images/SkForceLinking.cpp b/src/images/SkForceLinking.cpp
index 55b7021432..05fc7e08a6 100644
--- a/src/images/SkForceLinking.cpp
+++ b/src/images/SkForceLinking.cpp
@@ -5,8 +5,8 @@
* found in the LICENSE file.
*/
+#include "SkImageEncoder.h"
#include "SkForceLinking.h"
-#include "SkImageDecoder.h"
// This method is required to fool the linker into not discarding the pre-main
// initialization and registration of the decoder classes. Passing true will
@@ -14,26 +14,22 @@
int SkForceLinking(bool doNotPassTrue) {
if (doNotPassTrue) {
SkASSERT(false);
- CreateJPEGImageDecoder();
- CreateWEBPImageDecoder();
- CreateBMPImageDecoder();
- CreateICOImageDecoder();
- CreateWBMPImageDecoder();
+ CreateJPEGImageEncoder();
+ CreateWEBPImageEncoder();
+
// Only link hardware texture codecs on platforms that build them. See images.gyp
#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
- CreatePKMImageDecoder();
- CreateKTXImageDecoder();
- CreateASTCImageDecoder();
+ CreateKTXImageEncoder();
#endif
- // 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_IOS)
- CreateGIFImageDecoder();
+ CreatePNGImageEncoder();
#endif
-#if !defined(SK_BUILD_FOR_MAC) && !defined(SK_BUILD_FOR_WIN) && !defined(SK_BUILD_FOR_IOS)
- CreatePNGImageDecoder();
+#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
+ CreatePNGImageEncoder_CG();
#endif
-#if defined(SK_BUILD_FOR_IOS)
- CreatePNGImageEncoder_IOS();
+#if defined(SK_BUILD_FOR_WIN)
+ CreateImageEncoder_WIC();
#endif
return -1;
}
diff --git a/src/images/SkImageDecoder.cpp b/src/images/SkImageDecoder.cpp
deleted file mode 100644
index 221faf74d5..0000000000
--- a/src/images/SkImageDecoder.cpp
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#include "SkImageDecoder.h"
-#include "SkBitmap.h"
-#include "SkImagePriv.h"
-#include "SkPixelRef.h"
-#include "SkStream.h"
-#include "SkTemplates.h"
-#include "SkCanvas.h"
-
-SkImageDecoder::SkImageDecoder()
- : fPeeker(nullptr)
- , fAllocator(nullptr)
- , fSampleSize(1)
- , fDefaultPref(kUnknown_SkColorType)
- , fPreserveSrcDepth(false)
- , fDitherImage(true)
- , fSkipWritingZeroes(false)
- , fPreferQualityOverSpeed(false)
- , fRequireUnpremultipliedColors(false) {
-}
-
-SkImageDecoder::~SkImageDecoder() {
- SkSafeUnref(fPeeker);
- SkSafeUnref(fAllocator);
-}
-
-void SkImageDecoder::copyFieldsToOther(SkImageDecoder* other) {
- if (nullptr == other) {
- return;
- }
- other->setPeeker(fPeeker);
- other->setAllocator(fAllocator);
- other->setSampleSize(fSampleSize);
- other->setPreserveSrcDepth(fPreserveSrcDepth);
- other->setDitherImage(fDitherImage);
- other->setSkipWritingZeroes(fSkipWritingZeroes);
- other->setPreferQualityOverSpeed(fPreferQualityOverSpeed);
- other->setRequireUnpremultipliedColors(fRequireUnpremultipliedColors);
-}
-
-SkImageDecoder::Format SkImageDecoder::getFormat() const {
- return kUnknown_Format;
-}
-
-const char* SkImageDecoder::getFormatName() const {
- return GetFormatName(this->getFormat());
-}
-
-const char* SkImageDecoder::GetFormatName(Format format) {
- switch (format) {
- case kUnknown_Format:
- return "Unknown Format";
- case kBMP_Format:
- return "BMP";
- case kGIF_Format:
- return "GIF";
- case kICO_Format:
- return "ICO";
- case kPKM_Format:
- return "PKM";
- case kKTX_Format:
- return "KTX";
- case kASTC_Format:
- return "ASTC";
- case kJPEG_Format:
- return "JPEG";
- case kPNG_Format:
- return "PNG";
- case kWBMP_Format:
- return "WBMP";
- case kWEBP_Format:
- return "WEBP";
- default:
- SkDEBUGFAIL("Invalid format type!");
- }
- return "Unknown Format";
-}
-
-SkPngChunkReader* SkImageDecoder::setPeeker(SkPngChunkReader* peeker) {
- SkRefCnt_SafeAssign(fPeeker, peeker);
- return peeker;
-}
-
-SkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator* alloc) {
- SkRefCnt_SafeAssign(fAllocator, alloc);
- return alloc;
-}
-
-void SkImageDecoder::setSampleSize(int size) {
- if (size < 1) {
- size = 1;
- }
- fSampleSize = size;
-}
-
-bool SkImageDecoder::allocPixelRef(SkBitmap* bitmap,
- SkColorTable* ctable) const {
- return bitmap->tryAllocPixels(fAllocator, ctable);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-SkColorType SkImageDecoder::getPrefColorType(SrcDepth srcDepth, bool srcHasAlpha) const {
- SkColorType ct = fDefaultPref;
- if (fPreserveSrcDepth) {
- switch (srcDepth) {
- case kIndex_SrcDepth:
- ct = kIndex_8_SkColorType;
- break;
- case k8BitGray_SrcDepth:
- ct = kN32_SkColorType;
- break;
- case k32Bit_SrcDepth:
- ct = kN32_SkColorType;
- break;
- }
- }
- return ct;
-}
-
-SkImageDecoder::Result SkImageDecoder::decode(SkStream* stream, SkBitmap* bm, SkColorType pref,
- Mode mode) {
- // we reset this to false before calling onDecode
- fShouldCancelDecode = false;
- // assign this, for use by getPrefColorType(), in case fUsePrefTable is false
- fDefaultPref = pref;
-
- // pass a temporary bitmap, so that if we return false, we are assured of
- // leaving the caller's bitmap untouched.
- SkBitmap tmp;
- const Result result = this->onDecode(stream, &tmp, mode);
- if (kFailure != result) {
- bm->swap(tmp);
- }
- return result;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-bool SkImageDecoder::DecodeFile(const char file[], SkBitmap* bm, SkColorType pref, Mode mode,
- Format* format) {
- SkASSERT(file);
- SkASSERT(bm);
-
- SkAutoTDelete<SkStreamRewindable> stream(SkStream::NewFromFile(file));
- if (stream.get()) {
- if (SkImageDecoder::DecodeStream(stream, bm, pref, mode, format)) {
- if (SkPixelRef* pr = bm->pixelRef()) {
- pr->setURI(file);
- }
- return true;
- }
- }
- return false;
-}
-
-bool SkImageDecoder::DecodeMemory(const void* buffer, size_t size, SkBitmap* bm, SkColorType pref,
- Mode mode, Format* format) {
- if (0 == size) {
- return false;
- }
- SkASSERT(buffer);
-
- SkMemoryStream stream(buffer, size);
- return SkImageDecoder::DecodeStream(&stream, bm, pref, mode, format);
-}
-
-bool SkImageDecoder::DecodeStream(SkStreamRewindable* stream, SkBitmap* bm, SkColorType pref,
- Mode mode, Format* format) {
- SkASSERT(stream);
- SkASSERT(bm);
-
- bool success = false;
- SkImageDecoder* codec = SkImageDecoder::Factory(stream);
-
- if (codec) {
- success = codec->decode(stream, bm, pref, mode) != kFailure;
- if (success && format) {
- *format = codec->getFormat();
- if (kUnknown_Format == *format) {
- if (stream->rewind()) {
- *format = GetStreamFormat(stream);
- }
- }
- }
- delete codec;
- }
- return success;
-}
-
-bool SkImageDecoder::decodeYUV8Planes(SkStream* stream, SkISize componentSizes[3], void* planes[3],
- size_t rowBytes[3], SkYUVColorSpace* colorSpace) {
- // we reset this to false before calling onDecodeYUV8Planes
- fShouldCancelDecode = false;
-
- return this->onDecodeYUV8Planes(stream, componentSizes, planes, rowBytes, colorSpace);
-}
diff --git a/src/images/SkImageDecoder_FactoryDefault.cpp b/src/images/SkImageDecoder_FactoryDefault.cpp
index 77c0a0ac57..ef8ddda830 100644
--- a/src/images/SkImageDecoder_FactoryDefault.cpp
+++ b/src/images/SkImageDecoder_FactoryDefault.cpp
@@ -6,18 +6,9 @@
* found in the LICENSE file.
*/
-#include "SkImageDecoder.h"
#include "SkMovie.h"
#include "SkStream.h"
-extern SkImageDecoder* image_decoder_from_stream(SkStreamRewindable*);
-
-SkImageDecoder* SkImageDecoder::Factory(SkStreamRewindable* stream) {
- return image_decoder_from_stream(stream);
-}
-
-/////////////////////////////////////////////////////////////////////////
-
typedef SkTRegistry<SkMovie*(*)(SkStreamRewindable*)> MovieReg;
SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) {
diff --git a/src/images/SkImageDecoder_FactoryRegistrar.cpp b/src/images/SkImageDecoder_FactoryRegistrar.cpp
deleted file mode 100644
index 36034d20ad..0000000000
--- a/src/images/SkImageDecoder_FactoryRegistrar.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkErrorInternals.h"
-#include "SkImageDecoder.h"
-#include "SkStream.h"
-#include "SkTRegistry.h"
-
-// This file is used for registration of SkImageDecoders. It also holds a function
-// for checking all the the registered SkImageDecoders for one that matches an
-// input SkStreamRewindable.
-
-template SkImageDecoder_DecodeReg* SkImageDecoder_DecodeReg::gHead;
-
-SkImageDecoder* image_decoder_from_stream(SkStreamRewindable*);
-
-SkImageDecoder* image_decoder_from_stream(SkStreamRewindable* stream) {
- SkImageDecoder* codec = nullptr;
- const SkImageDecoder_DecodeReg* curr = SkImageDecoder_DecodeReg::Head();
- while (curr) {
- codec = curr->factory()(stream);
- // we rewind here, because we promise later when we call "decode", that
- // the stream will be at its beginning.
- bool rewindSuceeded = stream->rewind();
-
- // our image decoder's require that rewind is supported so we fail early
- // if we are given a stream that does not support rewinding.
- if (!rewindSuceeded) {
- SkDEBUGF(("Unable to rewind the image stream."));
- delete codec;
- return nullptr;
- }
-
- if (codec) {
- return codec;
- }
- curr = curr->next();
- }
- return nullptr;
-}
-
-template SkImageDecoder_FormatReg* SkImageDecoder_FormatReg::gHead;
-
-SkImageDecoder::Format SkImageDecoder::GetStreamFormat(SkStreamRewindable* stream) {
- const SkImageDecoder_FormatReg* curr = SkImageDecoder_FormatReg::Head();
- while (curr != nullptr) {
- Format format = curr->factory()(stream);
- if (!stream->rewind()) {
- SkErrorInternals::SetError(kInvalidOperation_SkError,
- "Unable to rewind the image stream\n");
- return kUnknown_Format;
- }
- if (format != kUnknown_Format) {
- return format;
- }
- curr = curr->next();
- }
- return kUnknown_Format;
-}
diff --git a/src/images/SkImageDecoder_astc.cpp b/src/images/SkImageDecoder_astc.cpp
deleted file mode 100644
index 30d65f1f0f..0000000000
--- a/src/images/SkImageDecoder_astc.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * 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 "SkData.h"
-#include "SkEndian.h"
-#include "SkColorPriv.h"
-#include "SkImageDecoder.h"
-#include "SkScaledBitmapSampler.h"
-#include "SkStream.h"
-#include "SkStreamPriv.h"
-#include "SkTypes.h"
-
-#include "SkTextureCompressor.h"
-
-class SkASTCImageDecoder : public SkImageDecoder {
-public:
- SkASTCImageDecoder() { }
-
- Format getFormat() const override {
- return kASTC_Format;
- }
-
-protected:
- Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override;
-
-private:
- typedef SkImageDecoder INHERITED;
-};
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-static const uint32_t kASTCMagicNumber = 0x5CA1AB13;
-
-static inline int read_24bit(const uint8_t* buf) {
- // Assume everything is little endian...
- return
- static_cast<int>(buf[0]) |
- (static_cast<int>(buf[1]) << 8) |
- (static_cast<int>(buf[2]) << 16);
-}
-
-SkImageDecoder::Result SkASTCImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
- auto data = SkCopyStreamToData(stream);
- if (!data || !data->size()) {
- return kFailure;
- }
-
- unsigned char* buf = (unsigned char*) data->data();
-
- // Make sure that the magic header is there...
- SkASSERT(SkEndian_SwapLE32(*(reinterpret_cast<uint32_t*>(buf))) == kASTCMagicNumber);
-
- // Advance past the magic header
- buf += 4;
-
- const int blockDimX = buf[0];
- const int blockDimY = buf[1];
- const int blockDimZ = buf[2];
-
- if (1 != blockDimZ) {
- // We don't support decoding 3D
- return kFailure;
- }
-
- // Choose the proper ASTC format
- SkTextureCompressor::Format astcFormat;
- if (4 == blockDimX && 4 == blockDimY) {
- astcFormat = SkTextureCompressor::kASTC_4x4_Format;
- } else if (5 == blockDimX && 4 == blockDimY) {
- astcFormat = SkTextureCompressor::kASTC_5x4_Format;
- } else if (5 == blockDimX && 5 == blockDimY) {
- astcFormat = SkTextureCompressor::kASTC_5x5_Format;
- } else if (6 == blockDimX && 5 == blockDimY) {
- astcFormat = SkTextureCompressor::kASTC_6x5_Format;
- } else if (6 == blockDimX && 6 == blockDimY) {
- astcFormat = SkTextureCompressor::kASTC_6x6_Format;
- } else if (8 == blockDimX && 5 == blockDimY) {
- astcFormat = SkTextureCompressor::kASTC_8x5_Format;
- } else if (8 == blockDimX && 6 == blockDimY) {
- astcFormat = SkTextureCompressor::kASTC_8x6_Format;
- } else if (8 == blockDimX && 8 == blockDimY) {
- astcFormat = SkTextureCompressor::kASTC_8x8_Format;
- } else if (10 == blockDimX && 5 == blockDimY) {
- astcFormat = SkTextureCompressor::kASTC_10x5_Format;
- } else if (10 == blockDimX && 6 == blockDimY) {
- astcFormat = SkTextureCompressor::kASTC_10x6_Format;
- } else if (10 == blockDimX && 8 == blockDimY) {
- astcFormat = SkTextureCompressor::kASTC_10x8_Format;
- } else if (10 == blockDimX && 10 == blockDimY) {
- astcFormat = SkTextureCompressor::kASTC_10x10_Format;
- } else if (12 == blockDimX && 10 == blockDimY) {
- astcFormat = SkTextureCompressor::kASTC_12x10_Format;
- } else if (12 == blockDimX && 12 == blockDimY) {
- astcFormat = SkTextureCompressor::kASTC_12x12_Format;
- } else {
- // We don't support any other block dimensions..
- return kFailure;
- }
-
- // Advance buf past the block dimensions
- buf += 3;
-
- // Read the width/height/depth from the buffer...
- const int width = read_24bit(buf);
- const int height = read_24bit(buf + 3);
- const int depth = read_24bit(buf + 6);
-
- if (1 != depth) {
- // We don't support decoding 3D.
- return kFailure;
- }
-
- // Advance the buffer past the image dimensions
- buf += 9;
-
- // Setup the sampler...
- SkScaledBitmapSampler sampler(width, height, this->getSampleSize());
-
- // Determine the alpha of the bitmap...
- SkAlphaType alphaType = kOpaque_SkAlphaType;
- if (this->getRequireUnpremultipliedColors()) {
- alphaType = kUnpremul_SkAlphaType;
- } else {
- alphaType = kPremul_SkAlphaType;
- }
-
- // Set the config...
- bm->setInfo(SkImageInfo::MakeN32(sampler.scaledWidth(), sampler.scaledHeight(), alphaType));
-
- if (SkImageDecoder::kDecodeBounds_Mode == mode) {
- return kSuccess;
- }
-
- if (!this->allocPixelRef(bm, nullptr)) {
- return kFailure;
- }
-
- // Lock the pixels, since we're about to write to them...
- SkAutoLockPixels alp(*bm);
-
- if (!sampler.begin(bm, SkScaledBitmapSampler::kRGBA, *this)) {
- return kFailure;
- }
-
- // ASTC Data is encoded as RGBA pixels, so we should extract it as such
- int nPixels = width * height;
- SkAutoMalloc outRGBAData(nPixels * 4);
- uint8_t *outRGBADataPtr = reinterpret_cast<uint8_t *>(outRGBAData.get());
-
- // Decode ASTC
- if (!SkTextureCompressor::DecompressBufferFromFormat(
- outRGBADataPtr, width*4, buf, width, height, astcFormat)) {
- return kFailure;
- }
-
- // Set each of the pixels...
- const int srcRowBytes = width * 4;
- const int dstHeight = sampler.scaledHeight();
- const uint8_t *srcRow = reinterpret_cast<uint8_t *>(outRGBADataPtr);
- srcRow += sampler.srcY0() * srcRowBytes;
- for (int y = 0; y < dstHeight; ++y) {
- sampler.next(srcRow);
- srcRow += sampler.srcDY() * srcRowBytes;
- }
-
- return kSuccess;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-DEFINE_DECODER_CREATOR(ASTCImageDecoder);
-/////////////////////////////////////////////////////////////////////////////////////////
-
-static bool is_astc(SkStreamRewindable* stream) {
- // Read the ASTC header and make sure it's valid.
- uint32_t magic;
- if (stream->read((void*)&magic, 4) != 4) {
- return false;
- }
-
- return kASTCMagicNumber == SkEndian_SwapLE32(magic);
-}
-
-static SkImageDecoder* sk_libastc_dfactory(SkStreamRewindable* stream) {
- if (is_astc(stream)) {
- return new SkASTCImageDecoder;
- }
- return nullptr;
-}
-
-static SkImageDecoder_DecodeReg gReg(sk_libastc_dfactory);
-
-static SkImageDecoder::Format get_format_astc(SkStreamRewindable* stream) {
- if (is_astc(stream)) {
- return SkImageDecoder::kASTC_Format;
- }
- return SkImageDecoder::kUnknown_Format;
-}
-
-static SkImageDecoder_FormatReg gFormatReg(get_format_astc);
diff --git a/src/images/SkImageDecoder_ktx.cpp b/src/images/SkImageDecoder_ktx.cpp
index 156674565c..79f0293c2a 100644
--- a/src/images/SkImageDecoder_ktx.cpp
+++ b/src/images/SkImageDecoder_ktx.cpp
@@ -6,10 +6,9 @@
*/
#include "SkColorPriv.h"
-#include "SkImageDecoder.h"
+#include "SkImageEncoder.h"
#include "SkImageGenerator.h"
#include "SkPixelRef.h"
-#include "SkScaledBitmapSampler.h"
#include "SkStream.h"
#include "SkStreamPriv.h"
#include "SkTypes.h"
@@ -17,230 +16,14 @@
#include "ktx.h"
#include "etc1.h"
-/////////////////////////////////////////////////////////////////////////////////////////
-
-
-/////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
-// KTX Image decoder
-// ---
+// KTX Image Encoder
+//
// KTX is a general texture data storage file format ratified by the Khronos Group. As an
// overview, a KTX file contains all of the appropriate values needed to fully specify a
// texture in an OpenGL application, including the use of compressed data.
//
-// This decoder is meant to be used with an SkDiscardablePixelRef so that GPU backends
-// can sniff the data before creating a texture. If they encounter a compressed format
-// that they understand, they can then upload the data directly to the GPU. Otherwise,
-// they will decode the data into a format that Skia supports.
-
-class SkKTXImageDecoder : public SkImageDecoder {
-public:
- SkKTXImageDecoder() { }
-
- Format getFormat() const override {
- return kKTX_Format;
- }
-
-protected:
- Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override;
-
-private:
- typedef SkImageDecoder INHERITED;
-};
-
-SkImageDecoder::Result SkKTXImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
- // TODO: Implement SkStream::copyToData() that's cheap for memory and file streams
- auto data = SkCopyStreamToData(stream);
- if (nullptr == data) {
- return kFailure;
- }
-
- SkKTXFile ktxFile(data.get());
- if (!ktxFile.valid()) {
- return kFailure;
- }
-
- const unsigned short width = ktxFile.width();
- const unsigned short height = ktxFile.height();
-
- // Set a flag if our source is premultiplied alpha
- const SkString premulKey("KTXPremultipliedAlpha");
- const bool bSrcIsPremul = ktxFile.getValueForKey(premulKey) == SkString("True");
-
- // Setup the sampler...
- SkScaledBitmapSampler sampler(width, height, this->getSampleSize());
-
- // Determine the alpha of the bitmap...
- SkAlphaType alphaType = kOpaque_SkAlphaType;
- if (ktxFile.isRGBA8()) {
- if (this->getRequireUnpremultipliedColors()) {
- alphaType = kUnpremul_SkAlphaType;
- // If the client wants unpremul colors and we only have
- // premul, then we cannot honor their wish.
- if (bSrcIsPremul) {
- return kFailure;
- }
- } else {
- alphaType = kPremul_SkAlphaType;
- }
- }
-
- // Search through the compressed formats to see if the KTX file is holding
- // compressed data
- bool ktxIsCompressed = false;
- SkTextureCompressor::Format ktxCompressedFormat;
- for (int i = 0; i < SkTextureCompressor::kFormatCnt; ++i) {
- SkTextureCompressor::Format fmt = static_cast<SkTextureCompressor::Format>(i);
- if (ktxFile.isCompressedFormat(fmt)) {
- ktxIsCompressed = true;
- ktxCompressedFormat = fmt;
- break;
- }
- }
-
- // If the compressed format is a grayscale image, then setup the bitmap properly...
- bool isCompressedAlpha = ktxIsCompressed &&
- ((SkTextureCompressor::kLATC_Format == ktxCompressedFormat) ||
- (SkTextureCompressor::kR11_EAC_Format == ktxCompressedFormat));
-
- // Set the image dimensions and underlying pixel type.
- if (isCompressedAlpha) {
- const int w = sampler.scaledWidth();
- const int h = sampler.scaledHeight();
- bm->setInfo(SkImageInfo::MakeA8(w, h));
- } else {
- const int w = sampler.scaledWidth();
- const int h = sampler.scaledHeight();
- bm->setInfo(SkImageInfo::MakeN32(w, h, alphaType));
- }
-
- if (SkImageDecoder::kDecodeBounds_Mode == mode) {
- return kSuccess;
- }
-
- // If we've made it this far, then we know how to grok the data.
- if (!this->allocPixelRef(bm, nullptr)) {
- return kFailure;
- }
-
- // Lock the pixels, since we're about to write to them...
- SkAutoLockPixels alp(*bm);
-
- if (isCompressedAlpha) {
- if (!sampler.begin(bm, SkScaledBitmapSampler::kGray, *this)) {
- return kFailure;
- }
-
- // Alpha data is only a single byte per pixel.
- int nPixels = width * height;
- SkAutoMalloc outRGBData(nPixels);
- uint8_t *outRGBDataPtr = reinterpret_cast<uint8_t *>(outRGBData.get());
-
- // Decode the compressed format
- const uint8_t *buf = reinterpret_cast<const uint8_t *>(ktxFile.pixelData());
- if (!SkTextureCompressor::DecompressBufferFromFormat(
- outRGBDataPtr, width, buf, width, height, ktxCompressedFormat)) {
- return kFailure;
- }
-
- // Set each of the pixels...
- const int srcRowBytes = width;
- const int dstHeight = sampler.scaledHeight();
- const uint8_t *srcRow = reinterpret_cast<uint8_t *>(outRGBDataPtr);
- srcRow += sampler.srcY0() * srcRowBytes;
- for (int y = 0; y < dstHeight; ++y) {
- sampler.next(srcRow);
- srcRow += sampler.srcDY() * srcRowBytes;
- }
-
- return kSuccess;
-
- } else if (ktxFile.isCompressedFormat(SkTextureCompressor::kETC1_Format)) {
- if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) {
- return kFailure;
- }
-
- // ETC1 Data is encoded as RGB pixels, so we should extract it as such
- int nPixels = width * height;
- SkAutoMalloc outRGBData(nPixels * 3);
- uint8_t *outRGBDataPtr = reinterpret_cast<uint8_t *>(outRGBData.get());
-
- // Decode ETC1
- const uint8_t *buf = reinterpret_cast<const uint8_t *>(ktxFile.pixelData());
- if (!SkTextureCompressor::DecompressBufferFromFormat(
- outRGBDataPtr, width*3, buf, width, height, SkTextureCompressor::kETC1_Format)) {
- return kFailure;
- }
-
- // Set each of the pixels...
- const int srcRowBytes = width * 3;
- const int dstHeight = sampler.scaledHeight();
- const uint8_t *srcRow = reinterpret_cast<uint8_t *>(outRGBDataPtr);
- srcRow += sampler.srcY0() * srcRowBytes;
- for (int y = 0; y < dstHeight; ++y) {
- sampler.next(srcRow);
- srcRow += sampler.srcDY() * srcRowBytes;
- }
-
- return kSuccess;
-
- } else if (ktxFile.isRGB8()) {
-
- // Uncompressed RGB data (without alpha)
- if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) {
- return kFailure;
- }
-
- // Just need to read RGB pixels
- const int srcRowBytes = width * 3;
- const int dstHeight = sampler.scaledHeight();
- const uint8_t *srcRow = reinterpret_cast<const uint8_t *>(ktxFile.pixelData());
- srcRow += sampler.srcY0() * srcRowBytes;
- for (int y = 0; y < dstHeight; ++y) {
- sampler.next(srcRow);
- srcRow += sampler.srcDY() * srcRowBytes;
- }
-
- return kSuccess;
-
- } else if (ktxFile.isRGBA8()) {
-
- // Uncompressed RGBA data
-
- // If we know that the image contains premultiplied alpha, then
- // we need to turn off the premultiplier
- SkScaledBitmapSampler::Options opts (*this);
- if (bSrcIsPremul) {
- SkASSERT(bm->alphaType() == kPremul_SkAlphaType);
- SkASSERT(!this->getRequireUnpremultipliedColors());
-
- opts.fPremultiplyAlpha = false;
- }
-
- if (!sampler.begin(bm, SkScaledBitmapSampler::kRGBA, opts)) {
- return kFailure;
- }
-
- // Just need to read RGBA pixels
- const int srcRowBytes = width * 4;
- const int dstHeight = sampler.scaledHeight();
- const uint8_t *srcRow = reinterpret_cast<const uint8_t *>(ktxFile.pixelData());
- srcRow += sampler.srcY0() * srcRowBytes;
- for (int y = 0; y < dstHeight; ++y) {
- sampler.next(srcRow);
- srcRow += sampler.srcDY() * srcRowBytes;
- }
-
- return kSuccess;
- }
-
- return kFailure;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-// 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
@@ -304,28 +87,11 @@ bool SkKTXImageEncoder::encodePKM(SkWStream* stream, const SkData *data) {
}
/////////////////////////////////////////////////////////////////////////////////////////
-DEFINE_DECODER_CREATOR(KTXImageDecoder);
DEFINE_ENCODER_CREATOR(KTXImageEncoder);
/////////////////////////////////////////////////////////////////////////////////////////
-static SkImageDecoder* sk_libktx_dfactory(SkStreamRewindable* stream) {
- if (SkKTXFile::is_ktx(stream)) {
- return new SkKTXImageDecoder;
- }
- return nullptr;
-}
-
-static SkImageDecoder::Format get_format_ktx(SkStreamRewindable* stream) {
- if (SkKTXFile::is_ktx(stream)) {
- return SkImageDecoder::kKTX_Format;
- }
- return SkImageDecoder::kUnknown_Format;
-}
-
SkImageEncoder* sk_libktx_efactory(SkImageEncoder::Type t) {
return (SkImageEncoder::kKTX_Type == t) ? new SkKTXImageEncoder : nullptr;
}
-static SkImageDecoder_DecodeReg gReg(sk_libktx_dfactory);
-static SkImageDecoder_FormatReg gFormatReg(get_format_ktx);
static SkImageEncoder_EncodeReg gEReg(sk_libktx_efactory);
diff --git a/src/images/SkImageDecoder_libbmp.cpp b/src/images/SkImageDecoder_libbmp.cpp
deleted file mode 100644
index b9359bea7a..0000000000
--- a/src/images/SkImageDecoder_libbmp.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#include "bmpdecoderhelper.h"
-#include "SkColorPriv.h"
-#include "SkData.h"
-#include "SkImageDecoder.h"
-#include "SkScaledBitmapSampler.h"
-#include "SkStream.h"
-#include "SkStreamPriv.h"
-#include "SkTDArray.h"
-
-class SkBMPImageDecoder : public SkImageDecoder {
-public:
- SkBMPImageDecoder() {}
-
- Format getFormat() const override {
- return kBMP_Format;
- }
-
-protected:
- Result onDecode(SkStream* stream, SkBitmap* bm, Mode mode) override;
-
-private:
- typedef SkImageDecoder INHERITED;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-DEFINE_DECODER_CREATOR(BMPImageDecoder);
-///////////////////////////////////////////////////////////////////////////////
-
-static bool is_bmp(SkStreamRewindable* stream) {
- static const char kBmpMagic[] = { 'B', 'M' };
-
-
- char buffer[sizeof(kBmpMagic)];
-
- return stream->read(buffer, sizeof(kBmpMagic)) == sizeof(kBmpMagic) &&
- !memcmp(buffer, kBmpMagic, sizeof(kBmpMagic));
-}
-
-static SkImageDecoder* sk_libbmp_dfactory(SkStreamRewindable* stream) {
- if (is_bmp(stream)) {
- return new SkBMPImageDecoder;
- }
- return nullptr;
-}
-
-static SkImageDecoder_DecodeReg gReg(sk_libbmp_dfactory);
-
-static SkImageDecoder::Format get_format_bmp(SkStreamRewindable* stream) {
- if (is_bmp(stream)) {
- return SkImageDecoder::kBMP_Format;
- }
- return SkImageDecoder::kUnknown_Format;
-}
-
-static SkImageDecoder_FormatReg gFormatReg(get_format_bmp);
-
-///////////////////////////////////////////////////////////////////////////////
-
-class SkBmpDecoderCallback : public image_codec::BmpDecoderCallback {
-public:
- // we don't copy the bitmap, just remember the pointer
- SkBmpDecoderCallback(bool justBounds) : fJustBounds(justBounds) {}
-
- // override from BmpDecoderCallback
- virtual uint8* SetSize(int width, int height) {
- fWidth = width;
- fHeight = height;
- if (fJustBounds) {
- return nullptr;
- }
-
- fRGB.setCount(width * height * 3); // 3 == r, g, b
- return fRGB.begin();
- }
-
- int width() const { return fWidth; }
- int height() const { return fHeight; }
- const uint8_t* rgb() const { return fRGB.begin(); }
-
-private:
- SkTDArray<uint8_t> fRGB;
- int fWidth;
- int fHeight;
- bool fJustBounds;
-};
-
-SkImageDecoder::Result SkBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
- // First read the entire stream, so that all of the data can be passed to
- // the BmpDecoderHelper.
-
- auto data = SkCopyStreamToData(stream);
- if (!data) {
- return kFailure;
- }
-
- // Byte length of all of the data.
- const size_t length = data->size();
- if (0 == length) {
- return kFailure;
- }
-
- const bool justBounds = SkImageDecoder::kDecodeBounds_Mode == mode;
- SkBmpDecoderCallback callback(justBounds);
-
- // Now decode the BMP into callback's rgb() array [r,g,b, r,g,b, ...]
- {
- image_codec::BmpDecoderHelper helper;
- const int max_pixels = 16383*16383; // max width*height
- if (!helper.DecodeImage((const char*) data->data(), length,
- max_pixels, &callback)) {
- return kFailure;
- }
- }
-
- // we don't need this anymore, so free it now (before we try to allocate
- // the bitmap's pixels) rather than waiting for its destructor
- data.reset(nullptr);
-
- int width = callback.width();
- int height = callback.height();
- SkColorType colorType = this->getPrefColorType(k32Bit_SrcDepth, false);
-
- // only accept prefConfig if it makes sense for us
- if (kARGB_4444_SkColorType != colorType && kRGB_565_SkColorType != colorType) {
- colorType = kN32_SkColorType;
- }
-
- SkScaledBitmapSampler sampler(width, height, getSampleSize());
-
- bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(),
- colorType, kOpaque_SkAlphaType));
-
- if (justBounds) {
- return kSuccess;
- }
-
- if (!this->allocPixelRef(bm, nullptr)) {
- return kFailure;
- }
-
- SkAutoLockPixels alp(*bm);
-
- if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) {
- return kFailure;
- }
-
- const int srcRowBytes = width * 3;
- const int dstHeight = sampler.scaledHeight();
- const uint8_t* srcRow = callback.rgb();
-
- srcRow += sampler.srcY0() * srcRowBytes;
- for (int y = 0; y < dstHeight; y++) {
- sampler.next(srcRow);
- srcRow += sampler.srcDY() * srcRowBytes;
- }
- return kSuccess;
-}
diff --git a/src/images/SkImageDecoder_libgif.cpp b/src/images/SkImageDecoder_libgif.cpp
deleted file mode 100644
index 2677b13073..0000000000
--- a/src/images/SkImageDecoder_libgif.cpp
+++ /dev/null
@@ -1,541 +0,0 @@
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkColor.h"
-#include "SkColorPriv.h"
-#include "SkColorTable.h"
-#include "SkImageDecoder.h"
-#include "SkRTConf.h"
-#include "SkScaledBitmapSampler.h"
-#include "SkStream.h"
-#include "SkTemplates.h"
-#include "SkUtils.h"
-
-#include "gif_lib.h"
-
-class SkGIFImageDecoder : public SkImageDecoder {
-public:
- Format getFormat() const override {
- return kGIF_Format;
- }
-
-protected:
- Result onDecode(SkStream* stream, SkBitmap* bm, Mode mode) override;
-
-private:
- typedef SkImageDecoder INHERITED;
-};
-
-static const uint8_t gStartingIterlaceYValue[] = {
- 0, 4, 2, 1
-};
-static const uint8_t gDeltaIterlaceYValue[] = {
- 8, 8, 4, 2
-};
-
-SK_CONF_DECLARE(bool, c_suppressGIFImageDecoderWarnings,
- "images.gif.suppressDecoderWarnings", true,
- "Suppress GIF warnings and errors when calling image decode "
- "functions.");
-
-
-/* Implement the GIF interlace algorithm in an iterator.
- 1) grab every 8th line beginning at 0
- 2) grab every 8th line beginning at 4
- 3) grab every 4th line beginning at 2
- 4) grab every 2nd line beginning at 1
-*/
-class GifInterlaceIter {
-public:
- GifInterlaceIter(int height) : fHeight(height) {
- fStartYPtr = gStartingIterlaceYValue;
- fDeltaYPtr = gDeltaIterlaceYValue;
-
- fCurrY = *fStartYPtr++;
- fDeltaY = *fDeltaYPtr++;
- }
-
- int currY() const {
- SkASSERT(fStartYPtr);
- SkASSERT(fDeltaYPtr);
- return fCurrY;
- }
-
- void next() {
- SkASSERT(fStartYPtr);
- SkASSERT(fDeltaYPtr);
-
- int y = fCurrY + fDeltaY;
- // We went from an if statement to a while loop so that we iterate
- // through fStartYPtr until a valid row is found. This is so that images
- // that are smaller than 5x5 will not trash memory.
- while (y >= fHeight) {
- if (gStartingIterlaceYValue +
- SK_ARRAY_COUNT(gStartingIterlaceYValue) == fStartYPtr) {
- // we done
- SkDEBUGCODE(fStartYPtr = nullptr;)
- SkDEBUGCODE(fDeltaYPtr = nullptr;)
- y = 0;
- } else {
- y = *fStartYPtr++;
- fDeltaY = *fDeltaYPtr++;
- }
- }
- fCurrY = y;
- }
-
-private:
- const int fHeight;
- int fCurrY;
- int fDeltaY;
- const uint8_t* fStartYPtr;
- const uint8_t* fDeltaYPtr;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-static int DecodeCallBackProc(GifFileType* fileType, GifByteType* out,
- int size) {
- SkStream* stream = (SkStream*) fileType->UserData;
- return (int) stream->read(out, size);
-}
-
-void CheckFreeExtension(SavedImage* Image) {
- if (Image->ExtensionBlocks) {
-#if GIFLIB_MAJOR < 5
- FreeExtension(Image);
-#else
- GifFreeExtensions(&Image->ExtensionBlockCount, &Image->ExtensionBlocks);
-#endif
- }
-}
-
-// return nullptr on failure
-static const ColorMapObject* find_colormap(const GifFileType* gif) {
- const ColorMapObject* cmap = gif->Image.ColorMap;
- if (nullptr == cmap) {
- cmap = gif->SColorMap;
- }
-
- if (nullptr == cmap) {
- // no colormap found
- return nullptr;
- }
- // some sanity checks
- if (cmap && ((unsigned)cmap->ColorCount > 256 ||
- cmap->ColorCount != (1 << cmap->BitsPerPixel))) {
- cmap = nullptr;
- }
- return cmap;
-}
-
-// return -1 if not found (i.e. we're completely opaque)
-static int find_transpIndex(const SavedImage& image, int colorCount) {
- int transpIndex = -1;
- for (int i = 0; i < image.ExtensionBlockCount; ++i) {
- const ExtensionBlock* eb = image.ExtensionBlocks + i;
- if (eb->Function == 0xF9 && eb->ByteCount == 4) {
- if (eb->Bytes[0] & 1) {
- transpIndex = (unsigned char)eb->Bytes[3];
- // check for valid transpIndex
- if (transpIndex >= colorCount) {
- transpIndex = -1;
- }
- break;
- }
- }
- }
- return transpIndex;
-}
-
-static SkImageDecoder::Result error_return(const SkBitmap& bm, const char msg[]) {
- if (!c_suppressGIFImageDecoderWarnings) {
- SkDebugf("libgif error [%s] bitmap [%d %d] pixels %p colortable %p\n",
- msg, bm.width(), bm.height(), bm.getPixels(),
- bm.getColorTable());
- }
- return SkImageDecoder::kFailure;
-}
-
-static void gif_warning(const SkBitmap& bm, const char msg[]) {
- if (!c_suppressGIFImageDecoderWarnings) {
- SkDebugf("libgif warning [%s] bitmap [%d %d] pixels %p colortable %p\n",
- msg, bm.width(), bm.height(), bm.getPixels(),
- bm.getColorTable());
- }
-}
-
-/**
- * Skip rows in the source gif image.
- * @param gif Source image.
- * @param dst Scratch output needed by gif library call. Must be >= width bytes.
- * @param width Bytes per row in the source image.
- * @param rowsToSkip Number of rows to skip.
- * @return True on success, false on GIF_ERROR.
- */
-static bool skip_src_rows(GifFileType* gif, uint8_t* dst, int width, int rowsToSkip) {
- for (int i = 0; i < rowsToSkip; i++) {
- if (DGifGetLine(gif, dst, width) == GIF_ERROR) {
- return false;
- }
- }
- return true;
-}
-
-/**
- * GIFs with fewer then 256 color entries will sometimes index out of
- * bounds of the color table (this is malformed, but libgif does not
- * check sicne it is rare). This function checks for this error and
- * fixes it. This makes the output image consistantly deterministic.
- */
-static void sanitize_indexed_bitmap(SkBitmap* bm) {
- if ((kIndex_8_SkColorType == bm->colorType()) && !(bm->empty())) {
- SkAutoLockPixels alp(*bm);
- if (bm->getPixels()) {
- SkColorTable* ct = bm->getColorTable(); // Index8 must have it.
- SkASSERT(ct != nullptr);
- uint32_t count = ct->count();
- SkASSERT(count > 0);
- SkASSERT(count <= 0x100);
- if (count != 0x100) { // Full colortables can't go wrong.
- // Count is a power of 2; asserted elsewhere.
- uint8_t byteMask = (~(count - 1));
- bool warning = false;
- uint8_t* addr = static_cast<uint8_t*>(bm->getPixels());
- int height = bm->height();
- int width = bm->width();
- size_t rowBytes = bm->rowBytes();
- while (--height >= 0) {
- uint8_t* ptr = addr;
- int x = width;
- while (--x >= 0) {
- if (0 != ((*ptr) & byteMask)) {
- warning = true;
- *ptr = 0;
- }
- ++ptr;
- }
- addr += rowBytes;
- }
- if (warning) {
- gif_warning(*bm, "Index out of bounds.");
- }
- }
- }
- }
-}
-
-namespace {
-// This function is a template argument, so can't be static.
-int close_gif(GifFileType* gif) {
-#if GIFLIB_MAJOR < 5 || (GIFLIB_MAJOR == 5 && GIFLIB_MINOR == 0)
- return DGifCloseFile(gif);
-#else
- return DGifCloseFile(gif, nullptr);
-#endif
-}
-}//namespace
-
-SkImageDecoder::Result SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) {
-#if GIFLIB_MAJOR < 5
- GifFileType* gif = DGifOpen(sk_stream, DecodeCallBackProc);
-#else
- GifFileType* gif = DGifOpen(sk_stream, DecodeCallBackProc, nullptr);
-#endif
- if (nullptr == gif) {
- return error_return(*bm, "DGifOpen");
- }
-
- SkAutoTCallIProc<GifFileType, close_gif> acp(gif);
-
- SavedImage temp_save;
- temp_save.ExtensionBlocks=nullptr;
- temp_save.ExtensionBlockCount=0;
- SkAutoTCallVProc<SavedImage, CheckFreeExtension> acp2(&temp_save);
-
- int width, height;
- GifRecordType recType;
- GifByteType *extData;
-#if GIFLIB_MAJOR >= 5
- int extFunction;
-#endif
- int transpIndex = -1; // -1 means we don't have it (yet)
- int fillIndex = gif->SBackGroundColor;
-
- do {
- if (DGifGetRecordType(gif, &recType) == GIF_ERROR) {
- return error_return(*bm, "DGifGetRecordType");
- }
-
- switch (recType) {
- case IMAGE_DESC_RECORD_TYPE: {
- if (DGifGetImageDesc(gif) == GIF_ERROR) {
- return error_return(*bm, "IMAGE_DESC_RECORD_TYPE");
- }
-
- if (gif->ImageCount < 1) { // sanity check
- return error_return(*bm, "ImageCount < 1");
- }
-
- width = gif->SWidth;
- height = gif->SHeight;
-
- SavedImage* image = &gif->SavedImages[gif->ImageCount-1];
- const GifImageDesc& desc = image->ImageDesc;
-
- int imageLeft = desc.Left;
- int imageTop = desc.Top;
- const int innerWidth = desc.Width;
- const int innerHeight = desc.Height;
- if (innerWidth <= 0 || innerHeight <= 0) {
- return error_return(*bm, "invalid dimensions");
- }
-
- // check for valid descriptor
- if (innerWidth > width) {
- gif_warning(*bm, "image too wide, expanding output to size");
- width = innerWidth;
- imageLeft = 0;
- } else if (imageLeft + innerWidth > width) {
- gif_warning(*bm, "shifting image left to fit");
- imageLeft = width - innerWidth;
- } else if (imageLeft < 0) {
- gif_warning(*bm, "shifting image right to fit");
- imageLeft = 0;
- }
-
-
- if (innerHeight > height) {
- gif_warning(*bm, "image too tall, expanding output to size");
- height = innerHeight;
- imageTop = 0;
- } else if (imageTop + innerHeight > height) {
- gif_warning(*bm, "shifting image up to fit");
- imageTop = height - innerHeight;
- } else if (imageTop < 0) {
- gif_warning(*bm, "shifting image down to fit");
- imageTop = 0;
- }
-
- SkScaledBitmapSampler sampler(width, height, this->getSampleSize());
-
- bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(),
- kIndex_8_SkColorType, kPremul_SkAlphaType));
-
- if (SkImageDecoder::kDecodeBounds_Mode == mode) {
- return kSuccess;
- }
-
-
- // now we decode the colortable
- int colorCount = 0;
- {
- // Declare colorPtr here for scope.
- SkPMColor colorPtr[256]; // storage for worst-case
- const ColorMapObject* cmap = find_colormap(gif);
- if (cmap != nullptr) {
- SkASSERT(cmap->ColorCount == (1 << (cmap->BitsPerPixel)));
- colorCount = cmap->ColorCount;
- if (colorCount > 256) {
- colorCount = 256; // our kIndex8 can't support more
- }
- for (int index = 0; index < colorCount; index++) {
- colorPtr[index] = SkPackARGB32(0xFF,
- cmap->Colors[index].Red,
- cmap->Colors[index].Green,
- cmap->Colors[index].Blue);
- }
- } else {
- // find_colormap() returned nullptr. Some (rare, broken)
- // GIFs don't have a color table, so we force one.
- gif_warning(*bm, "missing colormap");
- colorCount = 256;
- sk_memset32(colorPtr, SK_ColorWHITE, colorCount);
- }
- transpIndex = find_transpIndex(temp_save, colorCount);
- if (transpIndex >= 0) {
- colorPtr[transpIndex] = SK_ColorTRANSPARENT; // ram in a transparent SkPMColor
- fillIndex = transpIndex;
- } else if (fillIndex >= colorCount) {
- // gif->SBackGroundColor should be less than colorCount.
- fillIndex = 0; // If not, fix it.
- }
-
- SkAutoTUnref<SkColorTable> ctable(new SkColorTable(colorPtr, colorCount));
- if (!this->allocPixelRef(bm, ctable)) {
- return error_return(*bm, "allocPixelRef");
- }
- }
-
- // abort if either inner dimension is <= 0
- if (innerWidth <= 0 || innerHeight <= 0) {
- return error_return(*bm, "non-pos inner width/height");
- }
-
- SkAutoLockPixels alp(*bm);
-
- SkAutoTMalloc<uint8_t> storage(innerWidth);
- uint8_t* scanline = storage.get();
-
- // GIF has an option to store the scanlines of an image, plus a larger background,
- // filled by a fill color. In this case, we will use a subset of the larger bitmap
- // for sampling.
- SkBitmap subset;
- SkBitmap* workingBitmap;
- // are we only a subset of the total bounds?
- if ((imageTop | imageLeft) > 0 ||
- innerWidth < width || innerHeight < height) {
- // Fill the background.
- memset(bm->getPixels(), fillIndex, bm->getSize());
-
- // Create a subset of the bitmap.
- SkIRect subsetRect(SkIRect::MakeXYWH(imageLeft / sampler.srcDX(),
- imageTop / sampler.srcDY(),
- innerWidth / sampler.srcDX(),
- innerHeight / sampler.srcDY()));
- if (!bm->extractSubset(&subset, subsetRect)) {
- return error_return(*bm, "Extract failed.");
- }
- // Update the sampler. We'll now be only sampling into the subset.
- sampler = SkScaledBitmapSampler(innerWidth, innerHeight, this->getSampleSize());
- workingBitmap = &subset;
- } else {
- workingBitmap = bm;
- }
-
- // bm is already locked, but if we had to take a subset, it must be locked also,
- // so that getPixels() will point to its pixels.
- SkAutoLockPixels alpWorking(*workingBitmap);
-
- if (!sampler.begin(workingBitmap, SkScaledBitmapSampler::kIndex, *this)) {
- return error_return(*bm, "Sampler failed to begin.");
- }
-
- // now decode each scanline
- if (gif->Image.Interlace) {
- // Iterate over the height of the source data. The sampler will
- // take care of skipping unneeded rows.
- GifInterlaceIter iter(innerHeight);
- for (int y = 0; y < innerHeight; y++) {
- if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) {
- gif_warning(*bm, "interlace DGifGetLine");
- memset(scanline, fillIndex, innerWidth);
- for (; y < innerHeight; y++) {
- sampler.sampleInterlaced(scanline, iter.currY());
- iter.next();
- }
- return kPartialSuccess;
- }
- sampler.sampleInterlaced(scanline, iter.currY());
- iter.next();
- }
- } else {
- // easy, non-interlace case
- const int outHeight = workingBitmap->height();
- skip_src_rows(gif, scanline, innerWidth, sampler.srcY0());
- for (int y = 0; y < outHeight; y++) {
- if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) {
- gif_warning(*bm, "DGifGetLine");
- memset(scanline, fillIndex, innerWidth);
- for (; y < outHeight; y++) {
- sampler.next(scanline);
- }
- return kPartialSuccess;
- }
- // scanline now contains the raw data. Sample it.
- sampler.next(scanline);
- if (y < outHeight - 1) {
- skip_src_rows(gif, scanline, innerWidth, sampler.srcDY() - 1);
- }
- }
- // skip the rest of the rows (if any)
- int read = (outHeight - 1) * sampler.srcDY() + sampler.srcY0() + 1;
- SkASSERT(read <= innerHeight);
- skip_src_rows(gif, scanline, innerWidth, innerHeight - read);
- }
- sanitize_indexed_bitmap(bm);
- return kSuccess;
- } break;
-
- case EXTENSION_RECORD_TYPE:
-#if GIFLIB_MAJOR < 5
- if (DGifGetExtension(gif, &temp_save.Function,
- &extData) == GIF_ERROR) {
-#else
- if (DGifGetExtension(gif, &extFunction, &extData) == GIF_ERROR) {
-#endif
- return error_return(*bm, "DGifGetExtension");
- }
-
- while (extData != nullptr) {
- /* Create an extension block with our data */
-#if GIFLIB_MAJOR < 5
- if (AddExtensionBlock(&temp_save, extData[0],
- &extData[1]) == GIF_ERROR) {
-#else
- if (GifAddExtensionBlock(&temp_save.ExtensionBlockCount,
- &temp_save.ExtensionBlocks,
- extFunction,
- extData[0],
- &extData[1]) == GIF_ERROR) {
-#endif
- return error_return(*bm, "AddExtensionBlock");
- }
- if (DGifGetExtensionNext(gif, &extData) == GIF_ERROR) {
- return error_return(*bm, "DGifGetExtensionNext");
- }
-#if GIFLIB_MAJOR < 5
- temp_save.Function = 0;
-#endif
- }
- break;
-
- case TERMINATE_RECORD_TYPE:
- break;
-
- default: /* Should be trapped by DGifGetRecordType */
- break;
- }
- } while (recType != TERMINATE_RECORD_TYPE);
-
- sanitize_indexed_bitmap(bm);
- return kSuccess;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-DEFINE_DECODER_CREATOR(GIFImageDecoder);
-///////////////////////////////////////////////////////////////////////////////
-
-static bool is_gif(SkStreamRewindable* stream) {
- char buf[GIF_STAMP_LEN];
- if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN) {
- if (memcmp(GIF_STAMP, buf, GIF_STAMP_LEN) == 0 ||
- memcmp(GIF87_STAMP, buf, GIF_STAMP_LEN) == 0 ||
- memcmp(GIF89_STAMP, buf, GIF_STAMP_LEN) == 0) {
- return true;
- }
- }
- return false;
-}
-
-static SkImageDecoder* sk_libgif_dfactory(SkStreamRewindable* stream) {
- if (is_gif(stream)) {
- return new SkGIFImageDecoder;
- }
- return nullptr;
-}
-
-static SkImageDecoder_DecodeReg gReg(sk_libgif_dfactory);
-
-static SkImageDecoder::Format get_format_gif(SkStreamRewindable* stream) {
- if (is_gif(stream)) {
- return SkImageDecoder::kGIF_Format;
- }
- return SkImageDecoder::kUnknown_Format;
-}
-
-static SkImageDecoder_FormatReg gFormatReg(get_format_gif);
diff --git a/src/images/SkImageDecoder_libico.cpp b/src/images/SkImageDecoder_libico.cpp
deleted file mode 100644
index ff04d74d06..0000000000
--- a/src/images/SkImageDecoder_libico.cpp
+++ /dev/null
@@ -1,456 +0,0 @@
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkColorPriv.h"
-#include "SkData.h"
-#include "SkImageDecoder.h"
-#include "SkStream.h"
-#include "SkStreamPriv.h"
-#include "SkTypes.h"
-
-class SkICOImageDecoder : public SkImageDecoder {
-public:
- SkICOImageDecoder();
-
- Format getFormat() const override {
- return kICO_Format;
- }
-
-protected:
- Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override;
-
-private:
- typedef SkImageDecoder INHERITED;
-};
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-//read bytes starting from the begin-th index in the buffer
-//read in Intel order, and return an integer
-
-#define readByte(buffer,begin) buffer[begin]
-#define read2Bytes(buffer,begin) buffer[begin]+SkLeftShift(buffer[begin+1],8)
-#define read4Bytes(buffer,begin) buffer[begin]+SkLeftShift(buffer[begin+1],8)+SkLeftShift(buffer[begin+2],16)+SkLeftShift(buffer[begin+3],24)
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-SkICOImageDecoder::SkICOImageDecoder()
-{
-}
-
-//helpers - my function pointer will call one of these, depending on the bitCount, each time through the inner loop
-static void editPixelBit1(const int pixelNo, const unsigned char* buf,
- const int xorOffset, int& x, int y, const int w,
- SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors);
-static void editPixelBit4(const int pixelNo, const unsigned char* buf,
- const int xorOffset, int& x, int y, const int w,
- SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors);
-static void editPixelBit8(const int pixelNo, const unsigned char* buf,
- const int xorOffset, int& x, int y, const int w,
- SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors);
-static void editPixelBit24(const int pixelNo, const unsigned char* buf,
- const int xorOffset, int& x, int y, const int w,
- SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors);
-static void editPixelBit32(const int pixelNo, const unsigned char* buf,
- const int xorOffset, int& x, int y, const int w,
- SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors);
-
-
-static int calculateRowBytesFor8888(int w, int bitCount)
-{
- // Default rowBytes is w << 2 for kARGB_8888
- // In the case of a 4 bit image with an odd width, we need to add some
- // so we can go off the end of the drawn bitmap.
- // Add 4 to ensure that it is still a multiple of 4.
- if (4 == bitCount && (w & 0x1)) {
- return (w + 1) << 2;
- }
- // Otherwise return 0, which will allow it to be calculated automatically.
- return 0;
-}
-
-SkImageDecoder::Result SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
- auto data = SkCopyStreamToData(stream);
- if (!data) {
- return kFailure;
- }
-
- const size_t length = data->size();
- // Check that the buffer is large enough to read the directory header
- if (length < 6) {
- return kFailure;
- }
-
- unsigned char* buf = (unsigned char*) data->data();
-
- //these should always be the same - should i use for error checking? - what about files that have some
- //incorrect values, but still decode properly?
- int reserved = read2Bytes(buf, 0); // 0
- int type = read2Bytes(buf, 2); // 1
- if (reserved != 0 || type != 1) {
- return kFailure;
- }
-
- int count = read2Bytes(buf, 4);
- // Check that there are directory entries
- if (count < 1) {
- return kFailure;
- }
-
- // Check that buffer is large enough to read directory entries.
- // We are guaranteed that count is at least 1. We might as well assume
- // count is 1 because this deprecated decoder only looks at the first
- // directory entry.
- if (length < (size_t)(6 + count*16)) {
- return kFailure;
- }
-
- //skip ahead to the correct header
- //commented out lines are not used, but if i switch to other read method, need to know how many to skip
- //otherwise, they could be used for error checking
- int w = readByte(buf, 6);
- int h = readByte(buf, 7);
- SkASSERT(w >= 0 && h >= 0);
- int colorCount = readByte(buf, 8);
- //int reservedToo = readByte(buf, 9 + choice*16); //0
- //int planes = read2Bytes(buf, 10 + choice*16); //1 - but often 0
- //int fakeBitCount = read2Bytes(buf, 12 + choice*16); //should be real - usually 0
- const size_t size = read4Bytes(buf, 14); //matters?
- const size_t offset = read4Bytes(buf, 18);
- // promote the sum to 64-bits to avoid overflow
- // Check that buffer is large enough to read image data
- if (offset > length || size > length || ((uint64_t)offset + size) > length) {
- return kFailure;
- }
-
- // Check to see if this is a PNG image inside the ICO
- {
- SkMemoryStream subStream(buf + offset, size, false);
- SkAutoTDelete<SkImageDecoder> otherDecoder(SkImageDecoder::Factory(&subStream));
- if (otherDecoder.get() != nullptr) {
- // Disallow nesting ICO files within one another
- // FIXME: Can ICO files contain other formats besides PNG?
- if (otherDecoder->getFormat() == SkImageDecoder::kICO_Format) {
- return kFailure;
- }
- // Set fields on the other decoder to be the same as this one.
- this->copyFieldsToOther(otherDecoder.get());
- const Result result = otherDecoder->decode(&subStream, bm, this->getDefaultPref(),
- mode);
- // FIXME: Should we just return result here? Is it possible that data that looked like
- // a subimage was not, but was actually a valid ICO?
- if (result != kFailure) {
- return result;
- }
- }
- }
-
- //int infoSize = read4Bytes(buf, offset); //40
- //int width = read4Bytes(buf, offset+4); //should == w
- //int height = read4Bytes(buf, offset+8); //should == 2*h
- //int planesToo = read2Bytes(buf, offset+12); //should == 1 (does it?)
-
- // For ico images, only a byte is used to store each dimension
- // 0 is used to represent 256
- if (w == 0) {
- w = 256;
- }
- if (h == 0) {
- h = 256;
- }
-
- // Check that buffer is large enough to read the bit depth
- if (length < offset + 16) {
- return kFailure;
- }
- int bitCount = read2Bytes(buf, offset+14);
-
- void (*placePixel)(const int pixelNo, const unsigned char* buf,
- const int xorOffset, int& x, int y, const int w,
- SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors) = nullptr;
- switch (bitCount)
- {
- case 1:
- placePixel = &editPixelBit1;
- colorCount = 2;
- break;
- case 4:
- placePixel = &editPixelBit4;
- colorCount = 16;
- break;
- case 8:
- placePixel = &editPixelBit8;
- colorCount = 256;
- break;
- case 24:
- placePixel = &editPixelBit24;
- colorCount = 0;
- break;
- case 32:
- placePixel = &editPixelBit32;
- colorCount = 0;
- break;
- default:
- SkDEBUGF(("Decoding %ibpp is unimplemented\n", bitCount));
- return kFailure;
- }
-
- //these should all be zero, but perhaps are not - need to check
- //int compression = read4Bytes(buf, offset+16); //0
- //int imageSize = read4Bytes(buf, offset+20); //0 - sometimes has a value
- //int xPixels = read4Bytes(buf, offset+24); //0
- //int yPixels = read4Bytes(buf, offset+28); //0
- //int colorsUsed = read4Bytes(buf, offset+32) //0 - might have an actual value though
- //int colorsImportant = read4Bytes(buf, offset+36); //0
-
- int begin = SkToInt(offset + 40);
- // Check that the buffer is large enough to read the color table
- // For bmp-in-icos, there should be 4 bytes per color
- if (length < (size_t) (begin + 4*colorCount)) {
- return kFailure;
- }
-
- //this array represents the colortable
- //if i allow other types of bitmaps, it may actually be used as a part of the bitmap
- SkPMColor* colors = nullptr;
- int blue, green, red;
- if (colorCount)
- {
- colors = new SkPMColor[colorCount];
- for (int j = 0; j < colorCount; j++)
- {
- //should this be a function - maybe a #define?
- blue = readByte(buf, begin + 4*j);
- green = readByte(buf, begin + 4*j + 1);
- red = readByte(buf, begin + 4*j + 2);
- colors[j] = SkPackARGB32(0xFF, red & 0xFF, green & 0xFF, blue & 0xFF);
- }
- }
- int bitWidth = w*bitCount;
- int test = bitWidth & 0x1F;
- int mask = -(((test >> 4) | (test >> 3) | (test >> 2) | (test >> 1) | test) & 0x1); //either 0xFFFFFFFF or 0
- int lineBitWidth = (bitWidth & 0xFFFFFFE0) + (0x20 & mask);
- int lineWidth = lineBitWidth/bitCount;
-
- int xorOffset = begin + colorCount*4; //beginning of the color bitmap
- //other read method means we will just be here already
- int andOffset = xorOffset + ((lineWidth*h*bitCount) >> 3);
-
- /*int */test = w & 0x1F; //the low 5 bits - we are rounding up to the next 32 (2^5)
- /*int */mask = -(((test >> 4) | (test >> 3) | (test >> 2) | (test >> 1) | test) & 0x1); //either 0xFFFFFFFF or 0
- int andLineWidth = (w & 0xFFFFFFE0) + (0x20 & mask);
- //if we allow different Configs, everything is the same til here
- //change the config, and use different address getter, and place index vs color, and add the color table
- //FIXME: what is the tradeoff in size?
- //if the andbitmap (mask) is all zeroes, then we can easily do an index bitmap
- //however, with small images with large colortables, maybe it's better to still do argb_8888
-
- bm->setInfo(SkImageInfo::MakeN32Premul(w, h), calculateRowBytesFor8888(w, bitCount));
-
- if (SkImageDecoder::kDecodeBounds_Mode == mode) {
- delete[] colors;
- return kSuccess;
- }
-
- if (!this->allocPixelRef(bm, nullptr))
- {
- delete[] colors;
- return kFailure;
- }
-
- // The AND mask is a 1-bit alpha mask for each pixel that comes after the
- // XOR mask in the bmp. If we check that the largest AND offset is safe,
- // it should mean all other buffer accesses will be at smaller indices and
- // will therefore be safe.
- size_t maxAndOffset = andOffset + ((andLineWidth*(h-1)+(w-1)) >> 3);
- if (length <= maxAndOffset) {
- return kFailure;
- }
-
- // Here we assert that all reads from the buffer using the XOR offset are
- // less than the AND offset. This should be guaranteed based on the above
- // calculations.
-#ifdef SK_DEBUG
- int maxPixelNum = lineWidth*(h-1)+w-1;
- int maxByte;
- switch (bitCount) {
- case 1:
- maxByte = maxPixelNum >> 3;
- break;
- case 4:
- maxByte = maxPixelNum >> 1;
- break;
- case 8:
- maxByte = maxPixelNum;
- break;
- case 24:
- maxByte = maxPixelNum * 3 + 2;
- break;
- case 32:
- maxByte = maxPixelNum * 4 + 3;
- break;
- default:
- SkASSERT(false);
- return kFailure;
- }
- int maxXOROffset = xorOffset + maxByte;
- SkASSERT(maxXOROffset < andOffset);
-#endif
-
- SkAutoLockPixels alp(*bm);
-
- for (int y = 0; y < h; y++)
- {
- for (int x = 0; x < w; x++)
- {
- //U32* address = bm->getAddr32(x, y);
-
- //check the alpha bit first, but pass it along to the function to figure out how to deal with it
- int andPixelNo = andLineWidth*(h-y-1)+x;
- //only need to get a new alphaByte when x %8 == 0
- //but that introduces an if and a mod - probably much slower
- //that's ok, it's just a read of an array, not a stream
- int alphaByte = readByte(buf, andOffset + (andPixelNo >> 3));
- int shift = 7 - (andPixelNo & 0x7);
- int m = 1 << shift;
-
- int pixelNo = lineWidth*(h-y-1)+x;
- placePixel(pixelNo, buf, xorOffset, x, y, w, bm, alphaByte, m, shift, colors);
-
- }
- }
-
- delete [] colors;
- //ensure we haven't read off the end?
- //of course this doesn't help us if the andOffset was a lie...
- //return andOffset + (andLineWidth >> 3) <= length;
- return kSuccess;
-} //onDecode
-
-//function to place the pixel, determined by the bitCount
-static void editPixelBit1(const int pixelNo, const unsigned char* buf,
- const int xorOffset, int& x, int y, const int w,
- SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors)
-{
- // note that this should be the same as/similar to the AND bitmap
- SkPMColor* address = bm->getAddr32(x,y);
- int byte = readByte(buf, xorOffset + (pixelNo >> 3));
- int colorBit;
- int alphaBit;
- // Read all of the bits in this byte.
- int i = x + 8;
- // Pin to the width so we do not write outside the bounds of
- // our color table.
- i = i > w ? w : i;
- // While loop to check all 8 bits individually.
- while (x < i)
- {
-
- colorBit = (byte & m) >> shift;
- alphaBit = (alphaByte & m) >> shift;
- *address = (alphaBit-1)&(colors[colorBit]);
- x++;
- // setup for the next pixel
- address = address + 1;
- m = m >> 1;
- shift -= 1;
- }
- x--;
-}
-static void editPixelBit4(const int pixelNo, const unsigned char* buf,
- const int xorOffset, int& x, int y, const int w,
- SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors)
-{
- SkPMColor* address = bm->getAddr32(x, y);
- int byte = readByte(buf, xorOffset + (pixelNo >> 1));
- int pixel = (byte >> 4) & 0xF;
- int alphaBit = (alphaByte & m) >> shift;
- *address = (alphaBit-1)&(colors[pixel]);
- x++;
- //if w is odd, x may be the same as w, which means we are writing to an unused portion of the bitmap
- //but that's okay, since i've added an extra rowByte for just this purpose
- address = address + 1;
- pixel = byte & 0xF;
- m = m >> 1;
- alphaBit = (alphaByte & m) >> (shift-1);
- //speed up trick here
- *address = (alphaBit-1)&(colors[pixel]);
-}
-
-static void editPixelBit8(const int pixelNo, const unsigned char* buf,
- const int xorOffset, int& x, int y, const int w,
- SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors)
-{
- SkPMColor* address = bm->getAddr32(x, y);
- int pixel = readByte(buf, xorOffset + pixelNo);
- int alphaBit = (alphaByte & m) >> shift;
- *address = (alphaBit-1)&(colors[pixel]);
-}
-
-static void editPixelBit24(const int pixelNo, const unsigned char* buf,
- const int xorOffset, int& x, int y, const int w,
- SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors)
-{
- SkPMColor* address = bm->getAddr32(x, y);
- int blue = readByte(buf, xorOffset + 3*pixelNo);
- int green = readByte(buf, xorOffset + 3*pixelNo + 1);
- int red = readByte(buf, xorOffset + 3*pixelNo + 2);
- int alphaBit = (alphaByte & m) >> shift;
- //alphaBit == 1 => alpha = 0
- int alpha = (alphaBit-1) & 0xFF;
- *address = SkPreMultiplyARGB(alpha, red, green, blue);
-}
-
-static void editPixelBit32(const int pixelNo, const unsigned char* buf,
- const int xorOffset, int& x, int y, const int w,
- SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors)
-{
- SkPMColor* address = bm->getAddr32(x, y);
- int blue = readByte(buf, xorOffset + 4*pixelNo);
- int green = readByte(buf, xorOffset + 4*pixelNo + 1);
- int red = readByte(buf, xorOffset + 4*pixelNo + 2);
- int alphaBit = (alphaByte & m) >> shift;
-#if 1 // don't trust the alphaBit for 32bit images <mrr>
- alphaBit = 0;
-#endif
- int alpha = readByte(buf, xorOffset + 4*pixelNo + 3) & ((alphaBit-1)&0xFF);
- *address = SkPreMultiplyARGB(alpha, red, green, blue);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-DEFINE_DECODER_CREATOR(ICOImageDecoder);
-/////////////////////////////////////////////////////////////////////////////////////////
-
-static bool is_ico(SkStreamRewindable* stream) {
- // Check to see if the first four bytes are 0,0,1,0
- // FIXME: Is that required and sufficient?
- char buf[4];
- if (stream->read((void*)buf, 4) != 4) {
- return false;
- }
- int reserved = read2Bytes(buf, 0);
- int type = read2Bytes(buf, 2);
- return 0 == reserved && 1 == type;
-}
-
-static SkImageDecoder* sk_libico_dfactory(SkStreamRewindable* stream) {
- if (is_ico(stream)) {
- return new SkICOImageDecoder;
- }
- return nullptr;
-}
-
-static SkImageDecoder_DecodeReg gReg(sk_libico_dfactory);
-
-static SkImageDecoder::Format get_format_ico(SkStreamRewindable* stream) {
- if (is_ico(stream)) {
- return SkImageDecoder::kICO_Format;
- }
- return SkImageDecoder::kUnknown_Format;
-}
-
-static SkImageDecoder_FormatReg gFormatReg(get_format_ico);
diff --git a/src/images/SkImageDecoder_libjpeg.cpp b/src/images/SkImageDecoder_libjpeg.cpp
index 89bfefcd45..fd10bdbdf6 100644
--- a/src/images/SkImageDecoder_libjpeg.cpp
+++ b/src/images/SkImageDecoder_libjpeg.cpp
@@ -6,13 +6,10 @@
*/
-#include "SkImageDecoder.h"
#include "SkImageEncoder.h"
#include "SkJpegUtility.h"
#include "SkColorPriv.h"
#include "SkDither.h"
-#include "SkMSAN.h"
-#include "SkScaledBitmapSampler.h"
#include "SkStream.h"
#include "SkTemplates.h"
#include "SkTime.h"
@@ -28,730 +25,12 @@ extern "C" {
#include "jerror.h"
}
-// These enable timing code that report milliseconds for an encoding/decoding
+// These enable timing code that report milliseconds for an encoding
//#define TIME_ENCODE
-//#define TIME_DECODE
// this enables our rgb->yuv code, which is faster than libjpeg on ARM
#define WE_CONVERT_TO_YUV
-// If ANDROID_RGB is defined by in the jpeg headers it indicates that jpeg offers
-// support for two additional formats (1) JCS_RGBA_8888 and (2) JCS_RGB_565.
-
-#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS true
-#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS true
-SK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderWarnings,
- "images.jpeg.suppressDecoderWarnings",
- DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS,
- "Suppress most JPG warnings when calling decode functions.");
-SK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderErrors,
- "images.jpeg.suppressDecoderErrors",
- DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS,
- "Suppress most JPG error messages when decode "
- "function fails.");
-
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-
-static void do_nothing_emit_message(jpeg_common_struct*, int) {
- /* do nothing */
-}
-static void do_nothing_output_message(j_common_ptr) {
- /* do nothing */
-}
-
-static void initialize_info(jpeg_decompress_struct* cinfo, skjpeg_source_mgr* src_mgr) {
- SkASSERT(cinfo != nullptr);
- SkASSERT(src_mgr != nullptr);
- jpeg_create_decompress(cinfo);
- cinfo->src = src_mgr;
- /* To suppress warnings with a SK_DEBUG binary, set the
- * environment variable "skia_images_jpeg_suppressDecoderWarnings"
- * to "true". Inside a program that links to skia:
- * SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true); */
- if (c_suppressJPEGImageDecoderWarnings) {
- cinfo->err->emit_message = &do_nothing_emit_message;
- }
- /* To suppress error messages with a SK_DEBUG binary, set the
- * environment variable "skia_images_jpeg_suppressDecoderErrors"
- * to "true". Inside a program that links to skia:
- * SK_CONF_SET("images.jpeg.suppressDecoderErrors", true); */
- if (c_suppressJPEGImageDecoderErrors) {
- cinfo->err->output_message = &do_nothing_output_message;
- }
-}
-
-class SkJPEGImageDecoder : public SkImageDecoder {
-public:
-
- Format getFormat() const override {
- return kJPEG_Format;
- }
-
-protected:
- Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override;
- bool onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3],
- void* planes[3], size_t rowBytes[3],
- SkYUVColorSpace* colorSpace) override;
-
-private:
-
- /**
- * Determine the appropriate bitmap colortype and out_color_space based on
- * both the preference of the caller and the jpeg_color_space on the
- * jpeg_decompress_struct passed in.
- * Must be called after jpeg_read_header.
- */
- SkColorType getBitmapColorType(jpeg_decompress_struct*);
-
- typedef SkImageDecoder INHERITED;
-};
-
-//////////////////////////////////////////////////////////////////////////
-
-/* Automatically clean up after throwing an exception */
-class JPEGAutoClean {
-public:
- JPEGAutoClean(): cinfo_ptr(nullptr) {}
- ~JPEGAutoClean() {
- if (cinfo_ptr) {
- jpeg_destroy_decompress(cinfo_ptr);
- }
- }
- void set(jpeg_decompress_struct* info) {
- cinfo_ptr = info;
- }
-private:
- jpeg_decompress_struct* cinfo_ptr;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-/* If we need to better match the request, we might examine the image and
- output dimensions, and determine if the downsampling jpeg provided is
- not sufficient. If so, we can recompute a modified sampleSize value to
- make up the difference.
-
- To skip this additional scaling, just set sampleSize = 1; below.
- */
-static int recompute_sampleSize(int sampleSize,
- const jpeg_decompress_struct& cinfo) {
- return sampleSize * cinfo.output_width / cinfo.image_width;
-}
-
-static bool valid_output_dimensions(const jpeg_decompress_struct& cinfo) {
- /* These are initialized to 0, so if they have non-zero values, we assume
- they are "valid" (i.e. have been computed by libjpeg)
- */
- return 0 != cinfo.output_width && 0 != cinfo.output_height;
-}
-
-static bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer, int count) {
- for (int i = 0; i < count; i++) {
- JSAMPLE* rowptr = (JSAMPLE*)buffer;
- int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1);
- if (1 != row_count) {
- return false;
- }
- }
- return true;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-// This guy exists just to aid in debugging, as it allows debuggers to just
-// set a break-point in one place to see all error exists.
-static void print_jpeg_decoder_errors(const jpeg_decompress_struct& cinfo,
- int width, int height, const char caller[]) {
- if (!(c_suppressJPEGImageDecoderErrors)) {
- char buffer[JMSG_LENGTH_MAX];
- cinfo.err->format_message((const j_common_ptr)&cinfo, buffer);
- SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n",
- cinfo.err->msg_code, buffer, caller, width, height);
- }
-}
-
-static bool return_false(const jpeg_decompress_struct& cinfo,
- const char caller[]) {
- print_jpeg_decoder_errors(cinfo, 0, 0, caller);
- return false;
-}
-
-static SkImageDecoder::Result return_failure(const jpeg_decompress_struct& cinfo,
- const SkBitmap& bm, const char caller[]) {
- print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller);
- return SkImageDecoder::kFailure;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-// Convert a scanline of CMYK samples to RGBX in place. Note that this
-// method moves the "scanline" pointer in its processing
-static void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) {
- // At this point we've received CMYK pixels from libjpeg. We
- // perform a crude conversion to RGB (based on the formulae
- // from easyrgb.com):
- // CMYK -> CMY
- // C = ( C * (1 - K) + K ) // for each CMY component
- // CMY -> RGB
- // R = ( 1 - C ) * 255 // for each RGB component
- // Unfortunately we are seeing inverted CMYK so all the original terms
- // are 1-. This yields:
- // CMYK -> CMY
- // C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K
- // The conversion from CMY->RGB remains the same
- for (unsigned int x = 0; x < width; ++x, scanline += 4) {
- scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]);
- scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]);
- scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]);
- scanline[3] = 255;
- }
-}
-
-/**
- * Common code for setting the error manager.
- */
-static void set_error_mgr(jpeg_decompress_struct* cinfo, skjpeg_error_mgr* errorManager) {
- SkASSERT(cinfo != nullptr);
- SkASSERT(errorManager != nullptr);
- cinfo->err = jpeg_std_error(errorManager);
- errorManager->error_exit = skjpeg_error_exit;
-}
-
-/**
- * Common code for setting the dct method.
- */
-static void set_dct_method(const SkImageDecoder& decoder, jpeg_decompress_struct* cinfo) {
- SkASSERT(cinfo != nullptr);
- cinfo->dct_method = JDCT_ISLOW;
-}
-
-SkColorType SkJPEGImageDecoder::getBitmapColorType(jpeg_decompress_struct* cinfo) {
- SkASSERT(cinfo != nullptr);
-
- SrcDepth srcDepth = k32Bit_SrcDepth;
- if (JCS_GRAYSCALE == cinfo->jpeg_color_space) {
- srcDepth = k8BitGray_SrcDepth;
- }
-
- SkColorType colorType = this->getPrefColorType(srcDepth, /*hasAlpha*/ false);
- switch (colorType) {
- case kAlpha_8_SkColorType:
- // Only respect A8 colortype if the original is grayscale,
- // in which case we will treat the grayscale as alpha
- // values.
- if (cinfo->jpeg_color_space != JCS_GRAYSCALE) {
- colorType = kN32_SkColorType;
- }
- break;
- case kN32_SkColorType:
- // Fall through.
- case kARGB_4444_SkColorType:
- // Fall through.
- case kRGB_565_SkColorType:
- // These are acceptable destination colortypes.
- break;
- default:
- // Force all other colortypes to 8888.
- colorType = kN32_SkColorType;
- break;
- }
-
- switch (cinfo->jpeg_color_space) {
- case JCS_CMYK:
- // Fall through.
- case JCS_YCCK:
- // libjpeg cannot convert from CMYK or YCCK to RGB - here we set up
- // so libjpeg will give us CMYK samples back and we will later
- // manually convert them to RGB
- cinfo->out_color_space = JCS_CMYK;
- break;
- case JCS_GRAYSCALE:
- if (kAlpha_8_SkColorType == colorType) {
- cinfo->out_color_space = JCS_GRAYSCALE;
- break;
- }
- // The data is JCS_GRAYSCALE, but the caller wants some sort of RGB
- // colortype. Fall through to set to the default.
- default:
- cinfo->out_color_space = JCS_RGB;
- break;
- }
- return colorType;
-}
-
-/**
- * Based on the colortype and dither mode, adjust out_color_space and
- * dither_mode of cinfo. Only does work in ANDROID_RGB
- */
-static void adjust_out_color_space_and_dither(jpeg_decompress_struct* cinfo,
- SkColorType colorType,
- const SkImageDecoder& decoder) {
- SkASSERT(cinfo != nullptr);
-#ifdef ANDROID_RGB
- cinfo->dither_mode = JDITHER_NONE;
- if (JCS_CMYK == cinfo->out_color_space) {
- return;
- }
- switch (colorType) {
- case kN32_SkColorType:
- cinfo->out_color_space = JCS_RGBA_8888;
- break;
- case kRGB_565_SkColorType:
- cinfo->out_color_space = JCS_RGB_565;
- if (decoder.getDitherImage()) {
- cinfo->dither_mode = JDITHER_ORDERED;
- }
- break;
- default:
- break;
- }
-#endif
-}
-
-/**
- Sets all pixels in given bitmap to SK_ColorWHITE for all rows >= y.
- Used when decoding fails partway through reading scanlines to fill
- remaining lines. */
-static void fill_below_level(int y, SkBitmap* bitmap) {
- SkIRect rect = SkIRect::MakeLTRB(0, y, bitmap->width(), bitmap->height());
- SkCanvas canvas(*bitmap);
- canvas.clipRect(SkRect::Make(rect));
- canvas.drawColor(SK_ColorWHITE);
-}
-
-/**
- * Get the config and bytes per pixel of the source data. Return
- * whether the data is supported.
- */
-static bool get_src_config(const jpeg_decompress_struct& cinfo,
- SkScaledBitmapSampler::SrcConfig* sc,
- int* srcBytesPerPixel) {
- SkASSERT(sc != nullptr && srcBytesPerPixel != nullptr);
- if (JCS_CMYK == cinfo.out_color_space) {
- // In this case we will manually convert the CMYK values to RGB
- *sc = SkScaledBitmapSampler::kRGBX;
- // The CMYK work-around relies on 4 components per pixel here
- *srcBytesPerPixel = 4;
- } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) {
- *sc = SkScaledBitmapSampler::kRGB;
- *srcBytesPerPixel = 3;
-#ifdef ANDROID_RGB
- } else if (JCS_RGBA_8888 == cinfo.out_color_space) {
- *sc = SkScaledBitmapSampler::kRGBX;
- *srcBytesPerPixel = 4;
- } else if (JCS_RGB_565 == cinfo.out_color_space) {
- *sc = SkScaledBitmapSampler::kRGB_565;
- *srcBytesPerPixel = 2;
-#endif
- } else if (1 == cinfo.out_color_components &&
- JCS_GRAYSCALE == cinfo.out_color_space) {
- *sc = SkScaledBitmapSampler::kGray;
- *srcBytesPerPixel = 1;
- } else {
- return false;
- }
- return true;
-}
-
-SkImageDecoder::Result SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
-#ifdef TIME_DECODE
- SkAutoTime atm("JPEG Decode");
-#endif
-
- JPEGAutoClean autoClean;
-
- jpeg_decompress_struct cinfo;
- skjpeg_source_mgr srcManager(stream, this);
-
- skjpeg_error_mgr errorManager;
- set_error_mgr(&cinfo, &errorManager);
-
- // All objects need to be instantiated before this setjmp call so that
- // they will be cleaned up properly if an error occurs.
- if (setjmp(errorManager.fJmpBuf)) {
- return return_failure(cinfo, *bm, "setjmp");
- }
-
- initialize_info(&cinfo, &srcManager);
- autoClean.set(&cinfo);
-
- int status = jpeg_read_header(&cinfo, true);
- if (status != JPEG_HEADER_OK) {
- return return_failure(cinfo, *bm, "read_header");
- }
-
- /* Try to fulfill the requested sampleSize. Since jpeg can do it (when it
- can) much faster that we, just use their num/denom api to approximate
- the size.
- */
- int sampleSize = this->getSampleSize();
-
- set_dct_method(*this, &cinfo);
-
- SkASSERT(1 == cinfo.scale_num);
- cinfo.scale_denom = sampleSize;
-
- const SkColorType colorType = this->getBitmapColorType(&cinfo);
- const SkAlphaType alphaType = kAlpha_8_SkColorType == colorType ?
- kPremul_SkAlphaType : kOpaque_SkAlphaType;
-
- adjust_out_color_space_and_dither(&cinfo, colorType, *this);
-
- if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) {
- // Assume an A8 bitmap is not opaque to avoid the check of each
- // individual pixel. It is very unlikely to be opaque, since
- // an opaque A8 bitmap would not be very interesting.
- // Otherwise, a jpeg image is opaque.
- bool success = bm->setInfo(SkImageInfo::Make(cinfo.image_width, cinfo.image_height,
- colorType, alphaType));
- return success ? kSuccess : kFailure;
- }
-
- /* image_width and image_height are the original dimensions, available
- after jpeg_read_header(). To see the scaled dimensions, we have to call
- jpeg_start_decompress(), and then read output_width and output_height.
- */
- if (!jpeg_start_decompress(&cinfo)) {
- /* If we failed here, we may still have enough information to return
- to the caller if they just wanted (subsampled bounds). If sampleSize
- was 1, then we would have already returned. Thus we just check if
- we're in kDecodeBounds_Mode, and that we have valid output sizes.
-
- One reason to fail here is that we have insufficient stream data
- to complete the setup. However, output dimensions seem to get
- computed very early, which is why this special check can pay off.
- */
- if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimensions(cinfo)) {
- SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height,
- recompute_sampleSize(sampleSize, cinfo));
- // Assume an A8 bitmap is not opaque to avoid the check of each
- // individual pixel. It is very unlikely to be opaque, since
- // an opaque A8 bitmap would not be very interesting.
- // Otherwise, a jpeg image is opaque.
- bool success = bm->setInfo(SkImageInfo::Make(smpl.scaledWidth(), smpl.scaledHeight(),
- colorType, alphaType));
- return success ? kSuccess : kFailure;
- } else {
- return return_failure(cinfo, *bm, "start_decompress");
- }
- }
- sampleSize = recompute_sampleSize(sampleSize, cinfo);
-
- SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampleSize);
- // Assume an A8 bitmap is not opaque to avoid the check of each
- // individual pixel. It is very unlikely to be opaque, since
- // an opaque A8 bitmap would not be very interesting.
- // Otherwise, a jpeg image is opaque.
- bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(),
- colorType, alphaType));
- if (SkImageDecoder::kDecodeBounds_Mode == mode) {
- return kSuccess;
- }
- if (!this->allocPixelRef(bm, nullptr)) {
- return return_failure(cinfo, *bm, "allocPixelRef");
- }
-
- SkAutoLockPixels alp(*bm);
-
-#ifdef ANDROID_RGB
- /* short-circuit the SkScaledBitmapSampler when possible, as this gives
- a significant performance boost.
- */
- if (sampleSize == 1 &&
- ((kN32_SkColorType == colorType && cinfo.out_color_space == JCS_RGBA_8888) ||
- (kRGB_565_SkColorType == colorType && cinfo.out_color_space == JCS_RGB_565)))
- {
- JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels();
- INT32 const bpr = bm->rowBytes();
-
- while (cinfo.output_scanline < cinfo.output_height) {
- int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
- if (0 == row_count) {
- // if row_count == 0, then we didn't get a scanline,
- // so return early. We will return a partial image.
- fill_below_level(cinfo.output_scanline, bm);
- cinfo.output_scanline = cinfo.output_height;
- jpeg_finish_decompress(&cinfo);
- return kPartialSuccess;
- }
- if (this->shouldCancelDecode()) {
- return return_failure(cinfo, *bm, "shouldCancelDecode");
- }
- rowptr += bpr;
- }
- jpeg_finish_decompress(&cinfo);
- return kSuccess;
- }
-#endif
-
- // check for supported formats
- SkScaledBitmapSampler::SrcConfig sc;
- int srcBytesPerPixel;
-
- if (!get_src_config(cinfo, &sc, &srcBytesPerPixel)) {
- return return_failure(cinfo, *bm, "jpeg colorspace");
- }
-
- if (!sampler.begin(bm, sc, *this)) {
- return return_failure(cinfo, *bm, "sampler.begin");
- }
-
- SkAutoTMalloc<uint8_t> srcStorage(cinfo.output_width * srcBytesPerPixel);
- uint8_t* srcRow = srcStorage.get();
-
- // Possibly skip initial rows [sampler.srcY0]
- if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) {
- return return_failure(cinfo, *bm, "skip rows");
- }
-
- // now loop through scanlines until y == bm->height() - 1
- for (int y = 0;; y++) {
- JSAMPLE* rowptr = (JSAMPLE*)srcRow;
- int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
- sk_msan_mark_initialized(srcRow, srcRow + cinfo.output_width * srcBytesPerPixel,
- "skbug.com/4550");
- if (0 == row_count) {
- // if row_count == 0, then we didn't get a scanline,
- // so return early. We will return a partial image.
- fill_below_level(y, bm);
- cinfo.output_scanline = cinfo.output_height;
- jpeg_finish_decompress(&cinfo);
- return kPartialSuccess;
- }
- if (this->shouldCancelDecode()) {
- return return_failure(cinfo, *bm, "shouldCancelDecode");
- }
-
- if (JCS_CMYK == cinfo.out_color_space) {
- convert_CMYK_to_RGB(srcRow, cinfo.output_width);
- }
-
-
- sampler.next(srcRow);
- if (bm->height() - 1 == y) {
- // we're done
- break;
- }
-
- if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) {
- return return_failure(cinfo, *bm, "skip rows");
- }
- }
-
- // we formally skip the rest, so we don't get a complaint from libjpeg
- if (!skip_src_rows(&cinfo, srcRow,
- cinfo.output_height - cinfo.output_scanline)) {
- return return_failure(cinfo, *bm, "skip rows");
- }
- jpeg_finish_decompress(&cinfo);
-
- return kSuccess;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-enum SizeType {
- kSizeForMemoryAllocation_SizeType,
- kActualSize_SizeType
-};
-
-static SkISize compute_yuv_size(const jpeg_decompress_struct& info, int component,
- SizeType sizeType) {
- if (sizeType == kSizeForMemoryAllocation_SizeType) {
- return SkISize::Make(info.cur_comp_info[component]->width_in_blocks * DCTSIZE,
- info.cur_comp_info[component]->height_in_blocks * DCTSIZE);
- }
- return SkISize::Make(info.cur_comp_info[component]->downsampled_width,
- info.cur_comp_info[component]->downsampled_height);
-}
-
-static bool appears_to_be_yuv(const jpeg_decompress_struct& info) {
- return (info.jpeg_color_space == JCS_YCbCr)
- && (DCTSIZE == 8)
- && (info.num_components == 3)
- && (info.comps_in_scan >= info.num_components)
- && (info.scale_denom <= 8)
- && (info.cur_comp_info[0])
- && (info.cur_comp_info[1])
- && (info.cur_comp_info[2])
- && (info.cur_comp_info[1]->h_samp_factor == 1)
- && (info.cur_comp_info[1]->v_samp_factor == 1)
- && (info.cur_comp_info[2]->h_samp_factor == 1)
- && (info.cur_comp_info[2]->v_samp_factor == 1);
-}
-
-static void update_components_sizes(const jpeg_decompress_struct& cinfo, SkISize componentSizes[3],
- SizeType sizeType) {
- SkASSERT(appears_to_be_yuv(cinfo));
- for (int i = 0; i < 3; ++i) {
- componentSizes[i] = compute_yuv_size(cinfo, i, sizeType);
- }
-}
-
-static bool output_raw_data(jpeg_decompress_struct& cinfo, void* planes[3], size_t rowBytes[3]) {
- SkASSERT(appears_to_be_yuv(cinfo));
- // U size and V size have to be the same if we're calling output_raw_data()
- SkISize uvSize = compute_yuv_size(cinfo, 1, kSizeForMemoryAllocation_SizeType);
- SkASSERT(uvSize == compute_yuv_size(cinfo, 2, kSizeForMemoryAllocation_SizeType));
-
- JSAMPARRAY bufferraw[3];
- JSAMPROW bufferraw2[32];
- bufferraw[0] = &bufferraw2[0]; // Y channel rows (8 or 16)
- bufferraw[1] = &bufferraw2[16]; // U channel rows (8)
- bufferraw[2] = &bufferraw2[24]; // V channel rows (8)
- int yWidth = cinfo.output_width;
- int yHeight = cinfo.output_height;
- int yMaxH = yHeight - 1;
- int v = cinfo.cur_comp_info[0]->v_samp_factor;
- int uvMaxH = uvSize.height() - 1;
- JSAMPROW outputY = static_cast<JSAMPROW>(planes[0]);
- JSAMPROW outputU = static_cast<JSAMPROW>(planes[1]);
- JSAMPROW outputV = static_cast<JSAMPROW>(planes[2]);
- size_t rowBytesY = rowBytes[0];
- size_t rowBytesU = rowBytes[1];
- size_t rowBytesV = rowBytes[2];
-
- int yScanlinesToRead = DCTSIZE * v;
- SkAutoMalloc lastRowStorage(rowBytesY * 4);
- JSAMPROW yLastRow = (JSAMPROW)lastRowStorage.get();
- JSAMPROW uLastRow = yLastRow + rowBytesY;
- JSAMPROW vLastRow = uLastRow + rowBytesY;
- JSAMPROW dummyRow = vLastRow + rowBytesY;
-
- while (cinfo.output_scanline < cinfo.output_height) {
- // Request 8 or 16 scanlines: returns 0 or more scanlines.
- bool hasYLastRow(false), hasUVLastRow(false);
- // Assign 8 or 16 rows of memory to read the Y channel.
- for (int i = 0; i < yScanlinesToRead; ++i) {
- int scanline = (cinfo.output_scanline + i);
- if (scanline < yMaxH) {
- bufferraw2[i] = &outputY[scanline * rowBytesY];
- } else if (scanline == yMaxH) {
- bufferraw2[i] = yLastRow;
- hasYLastRow = true;
- } else {
- bufferraw2[i] = dummyRow;
- }
- }
- int scaledScanline = cinfo.output_scanline / v;
- // Assign 8 rows of memory to read the U and V channels.
- for (int i = 0; i < 8; ++i) {
- int scanline = (scaledScanline + i);
- if (scanline < uvMaxH) {
- bufferraw2[16 + i] = &outputU[scanline * rowBytesU];
- bufferraw2[24 + i] = &outputV[scanline * rowBytesV];
- } else if (scanline == uvMaxH) {
- bufferraw2[16 + i] = uLastRow;
- bufferraw2[24 + i] = vLastRow;
- hasUVLastRow = true;
- } else {
- bufferraw2[16 + i] = dummyRow;
- bufferraw2[24 + i] = dummyRow;
- }
- }
- JDIMENSION scanlinesRead = jpeg_read_raw_data(&cinfo, bufferraw, yScanlinesToRead);
-
- if (scanlinesRead == 0) {
- return false;
- }
-
- if (hasYLastRow) {
- memcpy(&outputY[yMaxH * rowBytesY], yLastRow, yWidth);
- }
- if (hasUVLastRow) {
- memcpy(&outputU[uvMaxH * rowBytesU], uLastRow, uvSize.width());
- memcpy(&outputV[uvMaxH * rowBytesV], vLastRow, uvSize.width());
- }
- }
-
- cinfo.output_scanline = SkMin32(cinfo.output_scanline, cinfo.output_height);
-
- return true;
-}
-
-bool SkJPEGImageDecoder::onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3],
- void* planes[3], size_t rowBytes[3],
- SkYUVColorSpace* colorSpace) {
-#ifdef TIME_DECODE
- SkAutoTime atm("JPEG YUV8 Decode");
-#endif
- if (this->getSampleSize() != 1) {
- return false; // Resizing not supported
- }
-
- JPEGAutoClean autoClean;
-
- jpeg_decompress_struct cinfo;
- skjpeg_source_mgr srcManager(stream, this);
-
- skjpeg_error_mgr errorManager;
- set_error_mgr(&cinfo, &errorManager);
-
- // All objects need to be instantiated before this setjmp call so that
- // they will be cleaned up properly if an error occurs.
- if (setjmp(errorManager.fJmpBuf)) {
- return return_false(cinfo, "setjmp YUV8");
- }
-
- initialize_info(&cinfo, &srcManager);
- autoClean.set(&cinfo);
-
- int status = jpeg_read_header(&cinfo, true);
- if (status != JPEG_HEADER_OK) {
- return return_false(cinfo, "read_header YUV8");
- }
-
- if (!appears_to_be_yuv(cinfo)) {
- // It's not an error to not be encoded in YUV, so no need to use return_false()
- return false;
- }
-
- cinfo.out_color_space = JCS_YCbCr;
- cinfo.raw_data_out = TRUE;
-
- if (!planes || !planes[0] || !rowBytes || !rowBytes[0]) { // Compute size only
- update_components_sizes(cinfo, componentSizes, kSizeForMemoryAllocation_SizeType);
- return true;
- }
-
- set_dct_method(*this, &cinfo);
-
- SkASSERT(1 == cinfo.scale_num);
- cinfo.scale_denom = 1;
-
-#ifdef ANDROID_RGB
- cinfo.dither_mode = JDITHER_NONE;
-#endif
-
- /* image_width and image_height are the original dimensions, available
- after jpeg_read_header(). To see the scaled dimensions, we have to call
- jpeg_start_decompress(), and then read output_width and output_height.
- */
- if (!jpeg_start_decompress(&cinfo)) {
- return return_false(cinfo, "start_decompress YUV8");
- }
-
- // Seems like jpeg_start_decompress is updating our opinion of whether cinfo represents YUV.
- // Again, not really an error.
- if (!appears_to_be_yuv(cinfo)) {
- return false;
- }
-
- if (!output_raw_data(cinfo, planes, rowBytes)) {
- return return_false(cinfo, "output_raw_data");
- }
-
- update_components_sizes(cinfo, componentSizes, kActualSize_SizeType);
- jpeg_finish_decompress(&cinfo);
-
- if (nullptr != colorSpace) {
- *colorSpace = kJPEG_SkYUVColorSpace;
- }
-
- return true;
-}
-
///////////////////////////////////////////////////////////////////////////////
#include "SkColorPriv.h"
@@ -993,45 +272,11 @@ protected:
};
///////////////////////////////////////////////////////////////////////////////
-DEFINE_DECODER_CREATOR(JPEGImageDecoder);
DEFINE_ENCODER_CREATOR(JPEGImageEncoder);
///////////////////////////////////////////////////////////////////////////////
-static bool is_jpeg(SkStreamRewindable* stream) {
- static const unsigned char gHeader[] = { 0xFF, 0xD8, 0xFF };
- static const size_t HEADER_SIZE = sizeof(gHeader);
-
- char buffer[HEADER_SIZE];
- size_t len = stream->read(buffer, HEADER_SIZE);
-
- if (len != HEADER_SIZE) {
- return false; // can't read enough
- }
- if (memcmp(buffer, gHeader, HEADER_SIZE)) {
- return false;
- }
- return true;
-}
-
-
-static SkImageDecoder* sk_libjpeg_dfactory(SkStreamRewindable* stream) {
- if (is_jpeg(stream)) {
- return new SkJPEGImageDecoder;
- }
- return nullptr;
-}
-
-static SkImageDecoder::Format get_format_jpeg(SkStreamRewindable* stream) {
- if (is_jpeg(stream)) {
- return SkImageDecoder::kJPEG_Format;
- }
- return SkImageDecoder::kUnknown_Format;
-}
-
static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) {
return (SkImageEncoder::kJPEG_Type == t) ? new SkJPEGImageEncoder : nullptr;
}
-static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory);
-static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg);
static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory);
diff --git a/src/images/SkImageDecoder_libpng.cpp b/src/images/SkImageDecoder_libpng.cpp
index cd8152a36b..c3df5d10a8 100644
--- a/src/images/SkImageDecoder_libpng.cpp
+++ b/src/images/SkImageDecoder_libpng.cpp
@@ -5,14 +5,12 @@
* found in the LICENSE file.
*/
-#include "SkImageDecoder.h"
#include "SkImageEncoder.h"
#include "SkColor.h"
#include "SkColorPriv.h"
#include "SkDither.h"
#include "SkMath.h"
#include "SkRTConf.h"
-#include "SkScaledBitmapSampler.h"
#include "SkStream.h"
#include "SkTemplates.h"
#include "SkUtils.h"
@@ -44,88 +42,10 @@ SK_CONF_DECLARE(bool, c_suppressPNGImageDecoderWarnings,
"Suppress most PNG warnings when calling image decode "
"functions.");
-class SkPNGImageIndex {
-public:
- // Takes ownership of stream.
- SkPNGImageIndex(SkStreamRewindable* stream, png_structp png_ptr, png_infop info_ptr)
- : fStream(stream)
- , fPng_ptr(png_ptr)
- , fInfo_ptr(info_ptr)
- , fColorType(kUnknown_SkColorType) {
- SkASSERT(stream != nullptr);
- }
- ~SkPNGImageIndex() {
- if (fPng_ptr) {
- png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL);
- }
- }
-
- SkAutoTDelete<SkStreamRewindable> fStream;
- png_structp fPng_ptr;
- png_infop fInfo_ptr;
- SkColorType fColorType;
-};
-
-class SkPNGImageDecoder : public SkImageDecoder {
-public:
- SkPNGImageDecoder() {
- fImageIndex = nullptr;
- }
- Format getFormat() const override {
- return kPNG_Format;
- }
-
- virtual ~SkPNGImageDecoder() { delete fImageIndex; }
-
-protected:
- Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override;
-
-private:
- SkPNGImageIndex* fImageIndex;
-
- bool onDecodeInit(SkStream* stream, png_structp *png_ptrp, png_infop *info_ptrp);
- bool decodePalette(png_structp png_ptr, png_infop info_ptr, int bitDepth,
- bool * SK_RESTRICT hasAlphap, bool *reallyHasAlphap,
- SkColorTable **colorTablep);
- bool getBitmapColorType(png_structp, png_infop, SkColorType*, bool* hasAlpha,
- SkPMColor* theTranspColor);
-
- typedef SkImageDecoder INHERITED;
-};
-
-#ifndef png_jmpbuf
-# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
-#endif
-
-#define PNG_BYTES_TO_CHECK 4
-
-/* Automatically clean up after throwing an exception */
-struct PNGAutoClean {
- PNGAutoClean(png_structp p, png_infop i): png_ptr(p), info_ptr(i) {}
- ~PNGAutoClean() {
- png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
- }
-private:
- png_structp png_ptr;
- png_infop info_ptr;
-};
-
-static void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) {
- SkStream* sk_stream = (SkStream*) png_get_io_ptr(png_ptr);
- size_t bytes = sk_stream->read(data, length);
- if (bytes != length) {
- png_error(png_ptr, "Read Error!");
- }
-}
+///////////////////////////////////////////////////////////////////////////////
-#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
-static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
- SkPngChunkReader* peeker = (SkPngChunkReader*)png_get_user_chunk_ptr(png_ptr);
- // readChunk() returning true means continue decoding
- return peeker->readChunk((const char*)chunk->name, chunk->data, chunk->size) ?
- 1 : -1;
-}
-#endif
+#include "SkColorPriv.h"
+#include "SkUnPreMultiply.h"
static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
if (!c_suppressPNGImageDecoderWarnings) {
@@ -134,577 +54,6 @@ static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
longjmp(png_jmpbuf(png_ptr), 1);
}
-static void skip_src_rows(png_structp png_ptr, uint8_t storage[], int count) {
- for (int i = 0; i < count; i++) {
- uint8_t* tmp = storage;
- png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
- }
-}
-
-static bool pos_le(int value, int max) {
- return value > 0 && value <= max;
-}
-
-static bool substituteTranspColor(SkBitmap* bm, SkPMColor match) {
- SkASSERT(bm->colorType() == kN32_SkColorType);
-
- bool reallyHasAlpha = false;
-
- for (int y = bm->height() - 1; y >= 0; --y) {
- SkPMColor* p = bm->getAddr32(0, y);
- for (int x = bm->width() - 1; x >= 0; --x) {
- if (match == *p) {
- *p = 0;
- reallyHasAlpha = true;
- }
- p += 1;
- }
- }
- return reallyHasAlpha;
-}
-
-static bool canUpscalePaletteToConfig(SkColorType dstColorType, bool srcHasAlpha) {
- switch (dstColorType) {
- case kN32_SkColorType:
- case kARGB_4444_SkColorType:
- return true;
- case kRGB_565_SkColorType:
- // only return true if the src is opaque (since 565 is opaque)
- return !srcHasAlpha;
- default:
- return false;
- }
-}
-
-// call only if color_type is PALETTE. Returns true if the ctable has alpha
-static bool hasTransparencyInPalette(png_structp png_ptr, png_infop info_ptr) {
- png_bytep trans;
- int num_trans;
-
- if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
- png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, nullptr);
- return num_trans > 0;
- }
- return false;
-}
-
-void do_nothing_warning_fn(png_structp, png_const_charp) {
- /* do nothing */
-}
-
-bool SkPNGImageDecoder::onDecodeInit(SkStream* sk_stream, png_structp *png_ptrp,
- png_infop *info_ptrp) {
- /* Create and initialize the png_struct with the desired error handler
- * functions. If you want to use the default stderr and longjump method,
- * you can supply nullptr for the last three parameters. We also supply the
- * the compiler header file version, so that we know if the application
- * was compiled with a compatible version of the library. */
-
- png_error_ptr user_warning_fn =
- (c_suppressPNGImageDecoderWarnings) ? (&do_nothing_warning_fn) : nullptr;
- /* nullptr means to leave as default library behavior. */
- /* c_suppressPNGImageDecoderWarnings default depends on SK_DEBUG. */
- /* To suppress warnings with a SK_DEBUG binary, set the
- * environment variable "skia_images_png_suppressDecoderWarnings"
- * to "true". Inside a program that links to skia:
- * SK_CONF_SET("images.png.suppressDecoderWarnings", true); */
-
- png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
- nullptr, sk_error_fn, user_warning_fn);
- // png_voidp user_error_ptr, user_error_fn, user_warning_fn);
- if (png_ptr == nullptr) {
- return false;
- }
-
- *png_ptrp = png_ptr;
-
- /* Allocate/initialize the memory for image information. */
- png_infop info_ptr = png_create_info_struct(png_ptr);
- if (info_ptr == nullptr) {
- png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
- return false;
- }
- *info_ptrp = info_ptr;
-
- /* Set error handling if you are using the setjmp/longjmp method (this is
- * the normal method of doing things with libpng). REQUIRED unless you
- * set up your own error handlers in the png_create_read_struct() earlier.
- */
- if (setjmp(png_jmpbuf(png_ptr))) {
- png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
- return false;
- }
-
- /* If you are using replacement read functions, instead of calling
- * png_init_io() here you would call:
- */
- png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn);
- /* where user_io_ptr is a structure you want available to the callbacks */
- /* If we have already read some of the signature */
-// png_set_sig_bytes(png_ptr, 0 /* sig_read */ );
-
-#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
- // hookup our peeker so we can see any user-chunks the caller may be interested in
- png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
- if (this->getPeeker()) {
- png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk);
- }
-#endif
- /* The call to png_read_info() gives us all of the information from the
- * PNG file before the first IDAT (image data chunk). */
- png_read_info(png_ptr, info_ptr);
- png_uint_32 origWidth, origHeight;
- int bitDepth, colorType;
- png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
- &colorType, int_p_NULL, int_p_NULL, int_p_NULL);
-
- /* tell libpng to strip 16 bit/color files down to 8 bits/color */
- if (bitDepth == 16) {
- png_set_strip_16(png_ptr);
- }
-#ifdef PNG_READ_PACK_SUPPORTED
- /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
- * byte into separate bytes (useful for paletted and grayscale images). */
- if (bitDepth < 8) {
- png_set_packing(png_ptr);
- }
-#endif
- /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
- if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) {
- png_set_expand_gray_1_2_4_to_8(png_ptr);
- }
-
- return true;
-}
-
-SkImageDecoder::Result SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
- Mode mode) {
- png_structp png_ptr;
- png_infop info_ptr;
-
- if (!onDecodeInit(sk_stream, &png_ptr, &info_ptr)) {
- return kFailure;
- }
-
- PNGAutoClean autoClean(png_ptr, info_ptr);
-
- if (setjmp(png_jmpbuf(png_ptr))) {
- return kFailure;
- }
-
- png_uint_32 origWidth, origHeight;
- int bitDepth, pngColorType, interlaceType;
- png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
- &pngColorType, &interlaceType, int_p_NULL, int_p_NULL);
-
- SkColorType colorType;
- bool hasAlpha = false;
- SkPMColor theTranspColor = 0; // 0 tells us not to try to match
-
- if (!this->getBitmapColorType(png_ptr, info_ptr, &colorType, &hasAlpha, &theTranspColor)) {
- return kFailure;
- }
-
- SkAlphaType alphaType = this->getRequireUnpremultipliedColors() ?
- kUnpremul_SkAlphaType : kPremul_SkAlphaType;
- const int sampleSize = this->getSampleSize();
- SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);
- decodedBitmap->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(),
- colorType, alphaType));
-
- if (SkImageDecoder::kDecodeBounds_Mode == mode) {
- return kSuccess;
- }
-
- // from here down we are concerned with colortables and pixels
-
- // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype
- // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we
- // draw lots faster if we can flag the bitmap has being opaque
- bool reallyHasAlpha = false;
- SkColorTable* colorTable = nullptr;
-
- if (pngColorType == PNG_COLOR_TYPE_PALETTE) {
- decodePalette(png_ptr, info_ptr, bitDepth, &hasAlpha, &reallyHasAlpha, &colorTable);
- }
-
- SkAutoUnref aur(colorTable);
-
- if (!this->allocPixelRef(decodedBitmap,
- kIndex_8_SkColorType == colorType ? colorTable : nullptr)) {
- return kFailure;
- }
-
- SkAutoLockPixels alp(*decodedBitmap);
-
- // Repeat setjmp, otherwise variables declared since the last call (e.g. alp
- // and aur) won't get their destructors called in case of a failure.
- if (setjmp(png_jmpbuf(png_ptr))) {
- return kFailure;
- }
-
- /* Turn on interlace handling. REQUIRED if you are not using
- * png_read_image(). To see how to handle interlacing passes,
- * see the png_read_row() method below:
- */
- const int number_passes = (interlaceType != PNG_INTERLACE_NONE) ?
- png_set_interlace_handling(png_ptr) : 1;
-
- /* Optional call to gamma correct and add the background to the palette
- * and update info structure. REQUIRED if you are expecting libpng to
- * update the palette for you (ie you selected such a transform above).
- */
- png_read_update_info(png_ptr, info_ptr);
-
- if ((kAlpha_8_SkColorType == colorType || kIndex_8_SkColorType == colorType) &&
- 1 == sampleSize) {
- if (kAlpha_8_SkColorType == colorType) {
- // For an A8 bitmap, we assume there is an alpha for speed. It is
- // possible the bitmap is opaque, but that is an unlikely use case
- // since it would not be very interesting.
- reallyHasAlpha = true;
- // A8 is only allowed if the original was GRAY.
- SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType);
- }
- for (int i = 0; i < number_passes; i++) {
- for (png_uint_32 y = 0; y < origHeight; y++) {
- uint8_t* bmRow = decodedBitmap->getAddr8(0, y);
- png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
- }
- }
- } else {
- SkScaledBitmapSampler::SrcConfig sc;
- int srcBytesPerPixel = 4;
-
- if (colorTable != nullptr) {
- sc = SkScaledBitmapSampler::kIndex;
- srcBytesPerPixel = 1;
- } else if (kAlpha_8_SkColorType == colorType) {
- // A8 is only allowed if the original was GRAY.
- SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType);
- sc = SkScaledBitmapSampler::kGray;
- srcBytesPerPixel = 1;
- } else if (hasAlpha) {
- sc = SkScaledBitmapSampler::kRGBA;
- } else {
- sc = SkScaledBitmapSampler::kRGBX;
- }
-
- /* We have to pass the colortable explicitly, since we may have one
- even if our decodedBitmap doesn't, due to the request that we
- upscale png's palette to a direct model
- */
- const SkPMColor* colors = colorTable ? colorTable->readColors() : nullptr;
- if (!sampler.begin(decodedBitmap, sc, *this, colors)) {
- return kFailure;
- }
- const int height = decodedBitmap->height();
-
- if (number_passes > 1) {
- SkAutoTMalloc<uint8_t> storage(origWidth * origHeight * srcBytesPerPixel);
- uint8_t* base = storage.get();
- size_t rowBytes = origWidth * srcBytesPerPixel;
-
- for (int i = 0; i < number_passes; i++) {
- uint8_t* row = base;
- for (png_uint_32 y = 0; y < origHeight; y++) {
- uint8_t* bmRow = row;
- png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
- row += rowBytes;
- }
- }
- // now sample it
- base += sampler.srcY0() * rowBytes;
- for (int y = 0; y < height; y++) {
- reallyHasAlpha |= sampler.next(base);
- base += sampler.srcDY() * rowBytes;
- }
- } else {
- SkAutoTMalloc<uint8_t> storage(origWidth * srcBytesPerPixel);
- uint8_t* srcRow = storage.get();
- skip_src_rows(png_ptr, srcRow, sampler.srcY0());
-
- for (int y = 0; y < height; y++) {
- uint8_t* tmp = srcRow;
- png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
- reallyHasAlpha |= sampler.next(srcRow);
- if (y < height - 1) {
- skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1);
- }
- }
-
- // skip the rest of the rows (if any)
- png_uint_32 read = (height - 1) * sampler.srcDY() +
- sampler.srcY0() + 1;
- SkASSERT(read <= origHeight);
- skip_src_rows(png_ptr, srcRow, origHeight - read);
- }
- }
-
- /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
- png_read_end(png_ptr, info_ptr);
-
- if (0 != theTranspColor) {
- reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor);
- }
- if (reallyHasAlpha && this->getRequireUnpremultipliedColors()) {
- switch (decodedBitmap->colorType()) {
- case kIndex_8_SkColorType:
- // Fall through.
- case kARGB_4444_SkColorType:
- // We have chosen not to support unpremul for these colortypes.
- return kFailure;
- default: {
- // Fall through to finish the decode. This colortype either
- // supports unpremul or it is irrelevant because it has no
- // alpha (or only alpha).
- // These brackets prevent a warning.
- }
- }
- }
-
- if (!reallyHasAlpha) {
- decodedBitmap->setAlphaType(kOpaque_SkAlphaType);
- }
- return kSuccess;
-}
-
-
-
-bool SkPNGImageDecoder::getBitmapColorType(png_structp png_ptr, png_infop info_ptr,
- SkColorType* colorTypep,
- bool* hasAlphap,
- SkPMColor* SK_RESTRICT theTranspColorp) {
- png_uint_32 origWidth, origHeight;
- int bitDepth, colorType;
- png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
- &colorType, int_p_NULL, int_p_NULL, int_p_NULL);
-
-#ifdef PNG_sBIT_SUPPORTED
- // check for sBIT chunk data, in case we should disable dithering because
- // our data is not truely 8bits per component
- png_color_8p sig_bit;
- if (this->getDitherImage() && png_get_sBIT(png_ptr, info_ptr, &sig_bit)) {
-#if 0
- SkDebugf("----- sBIT %d %d %d %d\n", sig_bit->red, sig_bit->green,
- sig_bit->blue, sig_bit->alpha);
-#endif
- // 0 seems to indicate no information available
- if (pos_le(sig_bit->red, SK_R16_BITS) &&
- pos_le(sig_bit->green, SK_G16_BITS) &&
- pos_le(sig_bit->blue, SK_B16_BITS)) {
- this->setDitherImage(false);
- }
- }
-#endif
-
- if (colorType == PNG_COLOR_TYPE_PALETTE) {
- bool paletteHasAlpha = hasTransparencyInPalette(png_ptr, info_ptr);
- *colorTypep = this->getPrefColorType(kIndex_SrcDepth, paletteHasAlpha);
- // now see if we can upscale to their requested colortype
- if (!canUpscalePaletteToConfig(*colorTypep, paletteHasAlpha)) {
- *colorTypep = kIndex_8_SkColorType;
- }
- } else {
- png_color_16p transpColor = nullptr;
- int numTransp = 0;
-
- png_get_tRNS(png_ptr, info_ptr, nullptr, &numTransp, &transpColor);
-
- bool valid = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS);
-
- if (valid && numTransp == 1 && transpColor != nullptr) {
- /* Compute our transparent color, which we'll match against later.
- We don't really handle 16bit components properly here, since we
- do our compare *after* the values have been knocked down to 8bit
- which means we will find more matches than we should. The real
- fix seems to be to see the actual 16bit components, do the
- compare, and then knock it down to 8bits ourselves.
- */
- if (colorType & PNG_COLOR_MASK_COLOR) {
- if (16 == bitDepth) {
- *theTranspColorp = SkPackARGB32(0xFF, transpColor->red >> 8,
- transpColor->green >> 8,
- transpColor->blue >> 8);
- } else {
- /* We apply the mask because in a very small
- number of corrupt PNGs, (transpColor->red > 255)
- and (bitDepth == 8), for certain versions of libpng. */
- *theTranspColorp = SkPackARGB32(0xFF,
- 0xFF & (transpColor->red),
- 0xFF & (transpColor->green),
- 0xFF & (transpColor->blue));
- }
- } else { // gray
- if (16 == bitDepth) {
- *theTranspColorp = SkPackARGB32(0xFF, transpColor->gray >> 8,
- transpColor->gray >> 8,
- transpColor->gray >> 8);
- } else {
- /* We apply the mask because in a very small
- number of corrupt PNGs, (transpColor->red >
- 255) and (bitDepth == 8), for certain versions
- of libpng. For safety we assume the same could
- happen with a grayscale PNG. */
- *theTranspColorp = SkPackARGB32(0xFF,
- 0xFF & (transpColor->gray),
- 0xFF & (transpColor->gray),
- 0xFF & (transpColor->gray));
- }
- }
- }
-
- if (valid ||
- PNG_COLOR_TYPE_RGB_ALPHA == colorType ||
- PNG_COLOR_TYPE_GRAY_ALPHA == colorType) {
- *hasAlphap = true;
- }
-
- SrcDepth srcDepth = k32Bit_SrcDepth;
- if (PNG_COLOR_TYPE_GRAY == colorType) {
- srcDepth = k8BitGray_SrcDepth;
- // Remove this assert, which fails on desk_pokemonwiki.skp
- //SkASSERT(!*hasAlphap);
- }
-
- *colorTypep = this->getPrefColorType(srcDepth, *hasAlphap);
- // now match the request against our capabilities
- if (*hasAlphap) {
- if (*colorTypep != kARGB_4444_SkColorType) {
- *colorTypep = kN32_SkColorType;
- }
- } else {
- if (kAlpha_8_SkColorType == *colorTypep) {
- if (k8BitGray_SrcDepth != srcDepth) {
- // Converting a non grayscale image to A8 is not currently supported.
- *colorTypep = kN32_SkColorType;
- }
- } else if (*colorTypep != kRGB_565_SkColorType &&
- *colorTypep != kARGB_4444_SkColorType) {
- *colorTypep = kN32_SkColorType;
- }
- }
- }
-
- // sanity check for size
- {
- int64_t size = sk_64_mul(origWidth, origHeight);
- // now check that if we are 4-bytes per pixel, we also don't overflow
- if (size < 0 || size > (0x7FFFFFFF >> 2)) {
- return false;
- }
- }
-
- // If the image has alpha and the decoder wants unpremultiplied
- // colors, the only supported colortype is 8888.
- if (this->getRequireUnpremultipliedColors() && *hasAlphap) {
- *colorTypep = kN32_SkColorType;
- }
-
- if (fImageIndex != nullptr) {
- if (kUnknown_SkColorType == fImageIndex->fColorType) {
- // This is the first time for this subset decode. From now on,
- // all decodes must be in the same colortype.
- fImageIndex->fColorType = *colorTypep;
- } else if (fImageIndex->fColorType != *colorTypep) {
- // Requesting a different colortype for a subsequent decode is not
- // supported. Report failure before we make changes to png_ptr.
- return false;
- }
- }
-
- bool convertGrayToRGB = PNG_COLOR_TYPE_GRAY == colorType && *colorTypep != kAlpha_8_SkColorType;
-
- // Unless the user is requesting A8, convert a grayscale image into RGB.
- // GRAY_ALPHA will always be converted to RGB
- if (convertGrayToRGB || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
- png_set_gray_to_rgb(png_ptr);
- }
-
- // Add filler (or alpha) byte (after each RGB triplet) if necessary.
- if (colorType == PNG_COLOR_TYPE_RGB || convertGrayToRGB) {
- png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
- }
-
- return true;
-}
-
-typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
-
-bool SkPNGImageDecoder::decodePalette(png_structp png_ptr, png_infop info_ptr,
- int bitDepth, bool *hasAlphap,
- bool *reallyHasAlphap,
- SkColorTable **colorTablep) {
- int numPalette;
- png_colorp palette;
- png_bytep trans;
- int numTrans;
-
- png_get_PLTE(png_ptr, info_ptr, &palette, &numPalette);
-
- SkPMColor colorStorage[256]; // worst-case storage
- SkPMColor* colorPtr = colorStorage;
-
- if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
- png_get_tRNS(png_ptr, info_ptr, &trans, &numTrans, nullptr);
- *hasAlphap = (numTrans > 0);
- } else {
- numTrans = 0;
- }
-
- // check for bad images that might make us crash
- if (numTrans > numPalette) {
- numTrans = numPalette;
- }
-
- int index = 0;
- int transLessThanFF = 0;
-
- // Choose which function to use to create the color table. If the final destination's
- // colortype is unpremultiplied, the color table will store unpremultiplied colors.
- PackColorProc proc;
- if (this->getRequireUnpremultipliedColors()) {
- proc = &SkPackARGB32NoCheck;
- } else {
- proc = &SkPreMultiplyARGB;
- }
- for (; index < numTrans; index++) {
- transLessThanFF |= (int)*trans - 0xFF;
- *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue);
- palette++;
- }
- bool reallyHasAlpha = (transLessThanFF < 0);
-
- for (; index < numPalette; index++) {
- *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue);
- palette++;
- }
-
- /* BUGGY IMAGE WORKAROUND
-
- Invalid images could contain pixel values that are greater than the number of palette
- entries. Since we use pixel values as indices into the palette this could result in reading
- beyond the end of the palette which could leak the contents of uninitialized memory. To
- ensure this doesn't happen, we grow the colortable to the maximum size that can be
- addressed by the bitdepth of the image and fill it with the last palette color or black if
- the palette is empty (really broken image).
- */
- int colorCount = SkTMax(numPalette, 1 << SkTMin(bitDepth, 8));
- SkPMColor lastColor = index > 0 ? colorPtr[-1] : SkPackARGB32(0xFF, 0, 0, 0);
- for (; index < colorCount; index++) {
- *colorPtr++ = lastColor;
- }
-
- *colorTablep = new SkColorTable(colorStorage, colorCount);
- *reallyHasAlphap = reallyHasAlpha;
- return true;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-#include "SkColorPriv.h"
-#include "SkUnPreMultiply.h"
-
static void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) {
SkWStream* sk_stream = (SkWStream*)png_get_io_ptr(png_ptr);
if (!sk_stream->write(data, len)) {
@@ -985,37 +334,11 @@ bool SkPNGImageEncoder::doEncode(SkWStream* stream, const SkBitmap& bitmap,
}
///////////////////////////////////////////////////////////////////////////////
-DEFINE_DECODER_CREATOR(PNGImageDecoder);
DEFINE_ENCODER_CREATOR(PNGImageEncoder);
///////////////////////////////////////////////////////////////////////////////
-static bool is_png(SkStreamRewindable* stream) {
- char buf[PNG_BYTES_TO_CHECK];
- if (stream->read(buf, PNG_BYTES_TO_CHECK) == PNG_BYTES_TO_CHECK &&
- !png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) {
- return true;
- }
- return false;
-}
-
-SkImageDecoder* sk_libpng_dfactory(SkStreamRewindable* stream) {
- if (is_png(stream)) {
- return new SkPNGImageDecoder;
- }
- return nullptr;
-}
-
-static SkImageDecoder::Format get_format_png(SkStreamRewindable* stream) {
- if (is_png(stream)) {
- return SkImageDecoder::kPNG_Format;
- }
- return SkImageDecoder::kUnknown_Format;
-}
-
SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) {
return (SkImageEncoder::kPNG_Type == t) ? new SkPNGImageEncoder : nullptr;
}
-static SkImageDecoder_DecodeReg gDReg(sk_libpng_dfactory);
-static SkImageDecoder_FormatReg gFormatReg(get_format_png);
static SkImageEncoder_EncodeReg gEReg(sk_libpng_efactory);
diff --git a/src/images/SkImageDecoder_libwebp.cpp b/src/images/SkImageDecoder_libwebp.cpp
index 2db08cee83..116608a253 100644
--- a/src/images/SkImageDecoder_libwebp.cpp
+++ b/src/images/SkImageDecoder_libwebp.cpp
@@ -14,10 +14,9 @@
* limitations under the License.
*/
-#include "SkImageDecoder.h"
+#include "SkBitmap.h"
#include "SkImageEncoder.h"
#include "SkColorPriv.h"
-#include "SkScaledBitmapSampler.h"
#include "SkStream.h"
#include "SkTemplates.h"
#include "SkUtils.h"
@@ -32,299 +31,9 @@
extern "C" {
// If moving libwebp out of skia source tree, path for webp headers must be
// updated accordingly. Here, we enforce using local copy in webp sub-directory.
-#include "webp/decode.h"
#include "webp/encode.h"
}
-// this enables timing code to report milliseconds for a decode
-//#define TIME_DECODE
-
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-
-// Define VP8 I/O on top of Skia stream
-
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-
-static const size_t WEBP_VP8_HEADER_SIZE = 64;
-static const size_t WEBP_IDECODE_BUFFER_SZ = (1 << 16);
-
-// Parse headers of RIFF container, and check for valid Webp (VP8) content.
-static bool webp_parse_header(SkStream* stream, int* width, int* height, int* alpha) {
- unsigned char buffer[WEBP_VP8_HEADER_SIZE];
- size_t bytesToRead = WEBP_VP8_HEADER_SIZE;
- size_t totalBytesRead = 0;
- do {
- unsigned char* dst = buffer + totalBytesRead;
- const size_t bytesRead = stream->read(dst, bytesToRead);
- if (0 == bytesRead) {
- SkASSERT(stream->isAtEnd());
- break;
- }
- bytesToRead -= bytesRead;
- totalBytesRead += bytesRead;
- SkASSERT(bytesToRead + totalBytesRead == WEBP_VP8_HEADER_SIZE);
- } while (!stream->isAtEnd() && bytesToRead > 0);
-
- WebPBitstreamFeatures features;
- VP8StatusCode status = WebPGetFeatures(buffer, totalBytesRead, &features);
- if (VP8_STATUS_OK != status) {
- return false; // Invalid WebP file.
- }
- *width = features.width;
- *height = features.height;
- *alpha = features.has_alpha;
-
- // sanity check for image size that's about to be decoded.
- {
- int64_t size = sk_64_mul(*width, *height);
- if (!sk_64_isS32(size)) {
- return false;
- }
- // now check that if we are 4-bytes per pixel, we also don't overflow
- if (sk_64_asS32(size) > (0x7FFFFFFF >> 2)) {
- return false;
- }
- }
- return true;
-}
-
-class SkWEBPImageDecoder: public SkImageDecoder {
-public:
- SkWEBPImageDecoder() {
- fOrigWidth = 0;
- fOrigHeight = 0;
- fHasAlpha = 0;
- }
-
- Format getFormat() const override {
- return kWEBP_Format;
- }
-
-protected:
- Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override;
-
-private:
- /**
- * Called when determining the output config to request to webp.
- * If the image does not have alpha, there is no need to premultiply.
- * If the caller wants unpremultiplied colors, that is respected.
- */
- bool shouldPremultiply() const {
- return SkToBool(fHasAlpha) && !this->getRequireUnpremultipliedColors();
- }
-
- bool setDecodeConfig(SkBitmap* decodedBitmap, int width, int height);
-
- SkAutoTDelete<SkStream> fInputStream;
- int fOrigWidth;
- int fOrigHeight;
- int fHasAlpha;
-
- typedef SkImageDecoder INHERITED;
-};
-
-//////////////////////////////////////////////////////////////////////////
-
-#ifdef TIME_DECODE
-
-#include "SkTime.h"
-
-class AutoTimeMillis {
-public:
- AutoTimeMillis(const char label[]) :
- fLabel(label) {
- if (nullptr == fLabel) {
- fLabel = "";
- }
- fNow = SkTime::GetMSecs();
- }
- ~AutoTimeMillis() {
- SkDebugf("---- Time (ms): %s %d\n", fLabel, SkTime::GetMSecs() - fNow);
- }
-private:
- const char* fLabel;
- SkMSec fNow;
-};
-
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-
-// This guy exists just to aid in debugging, as it allows debuggers to just
-// set a break-point in one place to see all error exists.
-static void print_webp_error(const SkBitmap& bm, const char msg[]) {
- SkDEBUGF(("libwebp error %s [%d %d]", msg, bm.width(), bm.height()));
-}
-
-static SkImageDecoder::Result return_failure(const SkBitmap& bm, const char msg[]) {
- print_webp_error(bm, msg);
- return SkImageDecoder::kFailure; // must always return kFailure
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-static WEBP_CSP_MODE webp_decode_mode(const SkBitmap* decodedBitmap, bool premultiply) {
- WEBP_CSP_MODE mode = MODE_LAST;
- const SkColorType ct = decodedBitmap->colorType();
-
- if (ct == kN32_SkColorType) {
- #if SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
- mode = premultiply ? MODE_bgrA : MODE_BGRA;
- #elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A)
- mode = premultiply ? MODE_rgbA : MODE_RGBA;
- #else
- #error "Skia uses BGRA or RGBA byte order"
- #endif
- } else if (ct == kARGB_4444_SkColorType) {
- mode = premultiply ? MODE_rgbA_4444 : MODE_RGBA_4444;
- } else if (ct == kRGB_565_SkColorType) {
- mode = MODE_RGB_565;
- }
- SkASSERT(MODE_LAST != mode);
- return mode;
-}
-
-// Incremental WebP image decoding. Reads input buffer of 64K size iteratively
-// and decodes this block to appropriate color-space as per config object.
-static bool webp_idecode(SkStream* stream, WebPDecoderConfig* config) {
- WebPIDecoder* idec = WebPIDecode(nullptr, 0, config);
- if (nullptr == idec) {
- WebPFreeDecBuffer(&config->output);
- return false;
- }
-
- if (!stream->rewind()) {
- SkDebugf("Failed to rewind webp stream!");
- return false;
- }
- const size_t readBufferSize = stream->hasLength() ?
- SkTMin(stream->getLength(), WEBP_IDECODE_BUFFER_SZ) : WEBP_IDECODE_BUFFER_SZ;
- SkAutoTMalloc<unsigned char> srcStorage(readBufferSize);
- unsigned char* input = srcStorage.get();
- if (nullptr == input) {
- WebPIDelete(idec);
- WebPFreeDecBuffer(&config->output);
- return false;
- }
-
- bool success = true;
- VP8StatusCode status = VP8_STATUS_SUSPENDED;
- do {
- const size_t bytesRead = stream->read(input, readBufferSize);
- if (0 == bytesRead) {
- success = false;
- break;
- }
-
- status = WebPIAppend(idec, input, bytesRead);
- if (VP8_STATUS_OK != status && VP8_STATUS_SUSPENDED != status) {
- success = false;
- break;
- }
- } while (VP8_STATUS_OK != status);
- srcStorage.reset();
- WebPIDelete(idec);
- WebPFreeDecBuffer(&config->output);
-
- return success;
-}
-
-static bool webp_get_config_resize(WebPDecoderConfig* config,
- SkBitmap* decodedBitmap,
- int width, int height, bool premultiply) {
- WEBP_CSP_MODE mode = webp_decode_mode(decodedBitmap, premultiply);
- if (MODE_LAST == mode) {
- return false;
- }
-
- if (0 == WebPInitDecoderConfig(config)) {
- return false;
- }
-
- config->output.colorspace = mode;
- config->output.u.RGBA.rgba = (uint8_t*)decodedBitmap->getPixels();
- config->output.u.RGBA.stride = (int) decodedBitmap->rowBytes();
- config->output.u.RGBA.size = decodedBitmap->getSize();
- config->output.is_external_memory = 1;
-
- if (width != decodedBitmap->width() || height != decodedBitmap->height()) {
- config->options.use_scaling = 1;
- config->options.scaled_width = decodedBitmap->width();
- config->options.scaled_height = decodedBitmap->height();
- }
-
- return true;
-}
-
-bool SkWEBPImageDecoder::setDecodeConfig(SkBitmap* decodedBitmap, int width, int height) {
- SkColorType colorType = this->getPrefColorType(k32Bit_SrcDepth, SkToBool(fHasAlpha));
-
- // YUV converter supports output in RGB565, RGBA4444 and RGBA8888 formats.
- if (fHasAlpha) {
- if (colorType != kARGB_4444_SkColorType) {
- colorType = kN32_SkColorType;
- }
- } else {
- if (colorType != kRGB_565_SkColorType && colorType != kARGB_4444_SkColorType) {
- colorType = kN32_SkColorType;
- }
- }
-
- SkAlphaType alphaType = kOpaque_SkAlphaType;
- if (SkToBool(fHasAlpha)) {
- if (this->getRequireUnpremultipliedColors()) {
- alphaType = kUnpremul_SkAlphaType;
- } else {
- alphaType = kPremul_SkAlphaType;
- }
- }
- return decodedBitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType));
-}
-
-SkImageDecoder::Result SkWEBPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
- Mode mode) {
-#ifdef TIME_DECODE
- AutoTimeMillis atm("WEBP Decode");
-#endif
-
- int origWidth, origHeight, hasAlpha;
- if (!webp_parse_header(stream, &origWidth, &origHeight, &hasAlpha)) {
- return kFailure;
- }
- this->fHasAlpha = hasAlpha;
-
- const int sampleSize = this->getSampleSize();
- SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);
- if (!setDecodeConfig(decodedBitmap, sampler.scaledWidth(),
- sampler.scaledHeight())) {
- return kFailure;
- }
-
- // If only bounds are requested, done
- if (SkImageDecoder::kDecodeBounds_Mode == mode) {
- return kSuccess;
- }
-
- if (!this->allocPixelRef(decodedBitmap, nullptr)) {
- return return_failure(*decodedBitmap, "allocPixelRef");
- }
-
- SkAutoLockPixels alp(*decodedBitmap);
-
- WebPDecoderConfig config;
- if (!webp_get_config_resize(&config, decodedBitmap, origWidth, origHeight,
- this->shouldPremultiply())) {
- return kFailure;
- }
-
- // Decode the WebP image data stream using WebP incremental decoding.
- return webp_idecode(stream, &config) ? kSuccess : kFailure;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
#include "SkUnPreMultiply.h"
typedef void (*ScanlineImporter)(const uint8_t* in, uint8_t* out, int width,
@@ -528,32 +237,11 @@ bool SkWEBPImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bm,
///////////////////////////////////////////////////////////////////////////////
-DEFINE_DECODER_CREATOR(WEBPImageDecoder);
DEFINE_ENCODER_CREATOR(WEBPImageEncoder);
///////////////////////////////////////////////////////////////////////////////
-static SkImageDecoder* sk_libwebp_dfactory(SkStreamRewindable* stream) {
- int width, height, hasAlpha;
- if (!webp_parse_header(stream, &width, &height, &hasAlpha)) {
- return nullptr;
- }
-
- // Magic matches, call decoder
- return new SkWEBPImageDecoder;
-}
-
-static SkImageDecoder::Format get_format_webp(SkStreamRewindable* stream) {
- int width, height, hasAlpha;
- if (webp_parse_header(stream, &width, &height, &hasAlpha)) {
- return SkImageDecoder::kWEBP_Format;
- }
- return SkImageDecoder::kUnknown_Format;
-}
-
static SkImageEncoder* sk_libwebp_efactory(SkImageEncoder::Type t) {
return (SkImageEncoder::kWEBP_Type == t) ? new SkWEBPImageEncoder : nullptr;
}
-static SkImageDecoder_DecodeReg gDReg(sk_libwebp_dfactory);
-static SkImageDecoder_FormatReg gFormatReg(get_format_webp);
static SkImageEncoder_EncodeReg gEReg(sk_libwebp_efactory);
diff --git a/src/images/SkImageDecoder_pkm.cpp b/src/images/SkImageDecoder_pkm.cpp
deleted file mode 100644
index af68f20d97..0000000000
--- a/src/images/SkImageDecoder_pkm.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * 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 "SkData.h"
-#include "SkImageDecoder.h"
-#include "SkScaledBitmapSampler.h"
-#include "SkStream.h"
-#include "SkStreamPriv.h"
-#include "SkTextureCompressor.h"
-#include "SkTypes.h"
-
-#include "etc1.h"
-
-class SkPKMImageDecoder : public SkImageDecoder {
-public:
- SkPKMImageDecoder() { }
-
- Format getFormat() const override {
- return kPKM_Format;
- }
-
-protected:
- Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override;
-
-private:
- typedef SkImageDecoder INHERITED;
-};
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-SkImageDecoder::Result SkPKMImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
- sk_sp<SkData> data(SkCopyStreamToData(stream));
- if (!data || !data->size()) {
- return kFailure;
- }
-
- unsigned char* buf = (unsigned char*) data->data();
-
- // 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);
-
- // Setup the sampler...
- SkScaledBitmapSampler sampler(width, height, this->getSampleSize());
-
- // Set the config...
- bm->setInfo(SkImageInfo::MakeN32(sampler.scaledWidth(), sampler.scaledHeight(),
- kOpaque_SkAlphaType));
- if (SkImageDecoder::kDecodeBounds_Mode == mode) {
- return kSuccess;
- }
-
- if (!this->allocPixelRef(bm, nullptr)) {
- return kFailure;
- }
-
- // Lock the pixels, since we're about to write to them...
- SkAutoLockPixels alp(*bm);
-
- if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) {
- return kFailure;
- }
-
- // 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);
- uint8_t *outRGBDataPtr = reinterpret_cast<uint8_t *>(outRGBData.get());
-
- // Decode ETC1
- if (!SkTextureCompressor::DecompressBufferFromFormat(
- outRGBDataPtr, width*3, buf, width, height, SkTextureCompressor::kETC1_Format)) {
- return kFailure;
- }
-
- // Set each of the pixels...
- const int srcRowBytes = width * 3;
- const int dstHeight = sampler.scaledHeight();
- const uint8_t *srcRow = reinterpret_cast<uint8_t *>(outRGBDataPtr);
- srcRow += sampler.srcY0() * srcRowBytes;
- for (int y = 0; y < dstHeight; ++y) {
- sampler.next(srcRow);
- srcRow += sampler.srcDY() * srcRowBytes;
- }
-
- return kSuccess;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-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 new SkPKMImageDecoder;
- }
- return nullptr;
-}
-
-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);
diff --git a/src/images/SkImageDecoder_wbmp.cpp b/src/images/SkImageDecoder_wbmp.cpp
deleted file mode 100644
index 335966b29a..0000000000
--- a/src/images/SkImageDecoder_wbmp.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-
-/*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#include "SkImageDecoder.h"
-#include "SkColor.h"
-#include "SkColorPriv.h"
-#include "SkMath.h"
-#include "SkStream.h"
-#include "SkTemplates.h"
-#include "SkUtils.h"
-
-class SkWBMPImageDecoder : public SkImageDecoder {
-public:
- Format getFormat() const override {
- return kWBMP_Format;
- }
-
-protected:
- Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override;
-
-private:
- typedef SkImageDecoder INHERITED;
-};
-
-static bool read_byte(SkStream* stream, uint8_t* data)
-{
- return stream->read(data, 1) == 1;
-}
-
-static bool read_mbf(SkStream* stream, int* value)
-{
- int n = 0;
- uint8_t data;
- do {
- if (!read_byte(stream, &data)) {
- return false;
- }
- n = (n << 7) | (data & 0x7F);
- } while (data & 0x80);
-
- *value = n;
- return true;
-}
-
-struct wbmp_head {
- int fWidth;
- int fHeight;
-
- bool init(SkStream* stream)
- {
- uint8_t data;
-
- if (!read_byte(stream, &data) || data != 0) { // unknown type
- return false;
- }
- if (!read_byte(stream, &data) || (data & 0x9F)) { // skip fixed header
- return false;
- }
- if (!read_mbf(stream, &fWidth) || (unsigned)fWidth > 0xFFFF) {
- return false;
- }
- if (!read_mbf(stream, &fHeight) || (unsigned)fHeight > 0xFFFF) {
- return false;
- }
- return fWidth != 0 && fHeight != 0;
- }
-};
-
-static void expand_bits_to_bytes(uint8_t dst[], const uint8_t src[], int bits)
-{
- int bytes = bits >> 3;
-
- for (int i = 0; i < bytes; i++) {
- unsigned mask = *src++;
- dst[0] = (mask >> 7) & 1;
- dst[1] = (mask >> 6) & 1;
- dst[2] = (mask >> 5) & 1;
- dst[3] = (mask >> 4) & 1;
- dst[4] = (mask >> 3) & 1;
- dst[5] = (mask >> 2) & 1;
- dst[6] = (mask >> 1) & 1;
- dst[7] = (mask >> 0) & 1;
- dst += 8;
- }
-
- bits &= 7;
- if (bits > 0) {
- unsigned mask = *src;
- do {
- *dst++ = (mask >> 7) & 1;
- mask <<= 1;
- } while (--bits != 0);
- }
-}
-
-SkImageDecoder::Result SkWBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
- Mode mode)
-{
- wbmp_head head;
-
- if (!head.init(stream)) {
- return kFailure;
- }
-
- int width = head.fWidth;
- int height = head.fHeight;
-
- decodedBitmap->setInfo(SkImageInfo::Make(width, height,
- kIndex_8_SkColorType, kOpaque_SkAlphaType));
-
- if (SkImageDecoder::kDecodeBounds_Mode == mode) {
- return kSuccess;
- }
-
- const SkPMColor colors[] = { SK_ColorBLACK, SK_ColorWHITE };
- SkColorTable* ct = new SkColorTable(colors, 2);
- SkAutoUnref aur(ct);
-
- if (!this->allocPixelRef(decodedBitmap, ct)) {
- return kFailure;
- }
-
- SkAutoLockPixels alp(*decodedBitmap);
-
- uint8_t* dst = decodedBitmap->getAddr8(0, 0);
- // store the 1-bit valuess at the end of our pixels, so we won't stomp
- // on them before we're read them. Just trying to avoid a temp allocation
- size_t srcRB = SkAlign8(width) >> 3;
- size_t srcSize = height * srcRB;
- uint8_t* src = dst + decodedBitmap->getSize() - srcSize;
- if (stream->read(src, srcSize) != srcSize) {
- return kFailure;
- }
-
- for (int y = 0; y < height; y++)
- {
- expand_bits_to_bytes(dst, src, width);
- dst += decodedBitmap->rowBytes();
- src += srcRB;
- }
-
- return kSuccess;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-DEFINE_DECODER_CREATOR(WBMPImageDecoder);
-///////////////////////////////////////////////////////////////////////////////
-
-static SkImageDecoder* sk_wbmp_dfactory(SkStreamRewindable* stream) {
- wbmp_head head;
-
- if (head.init(stream)) {
- return new SkWBMPImageDecoder;
- }
- return nullptr;
-}
-
-static SkImageDecoder::Format get_format_wbmp(SkStreamRewindable* stream) {
- wbmp_head head;
- if (head.init(stream)) {
- return SkImageDecoder::kWBMP_Format;
- }
- return SkImageDecoder::kUnknown_Format;
-}
-
-static SkImageDecoder_DecodeReg gDReg(sk_wbmp_dfactory);
-static SkImageDecoder_FormatReg gFormatReg(get_format_wbmp);
diff --git a/src/images/SkJpegUtility.cpp b/src/images/SkJpegUtility.cpp
index f1a32cae10..ab8486bcf6 100644
--- a/src/images/SkJpegUtility.cpp
+++ b/src/images/SkJpegUtility.cpp
@@ -8,108 +8,6 @@
#include "SkJpegUtility.h"
-/////////////////////////////////////////////////////////////////////
-static void sk_init_source(j_decompress_ptr cinfo) {
- skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src;
- src->next_input_byte = (const JOCTET*)src->fBuffer;
- src->bytes_in_buffer = 0;
-#ifdef SK_JPEG_INDEX_SUPPORTED
- src->current_offset = 0;
-#endif
- if (!src->fStream->rewind()) {
- SkDebugf("xxxxxxxxxxxxxx failure to rewind\n");
- cinfo->err->error_exit((j_common_ptr)cinfo);
- }
-}
-
-#ifdef SK_JPEG_INDEX_SUPPORTED
-static boolean sk_seek_input_data(j_decompress_ptr cinfo, long byte_offset) {
- skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src;
- size_t bo = (size_t) byte_offset;
-
- if (bo > src->current_offset) {
- (void)src->fStream->skip(bo - src->current_offset);
- } else {
- if (!src->fStream->rewind()) {
- SkDebugf("xxxxxxxxxxxxxx failure to rewind\n");
- cinfo->err->error_exit((j_common_ptr)cinfo);
- return false;
- }
- (void)src->fStream->skip(bo);
- }
-
- src->current_offset = bo;
- src->next_input_byte = (const JOCTET*)src->fBuffer;
- src->bytes_in_buffer = 0;
- return true;
-}
-#endif
-
-static boolean sk_fill_input_buffer(j_decompress_ptr cinfo) {
- skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src;
- if (src->fDecoder != nullptr && src->fDecoder->shouldCancelDecode()) {
- return FALSE;
- }
- size_t bytes = src->fStream->read(src->fBuffer, skjpeg_source_mgr::kBufferSize);
- // note that JPEG is happy with less than the full read,
- // as long as the result is non-zero
- if (bytes == 0) {
- return FALSE;
- }
-
-#ifdef SK_JPEG_INDEX_SUPPORTED
- src->current_offset += bytes;
-#endif
- src->next_input_byte = (const JOCTET*)src->fBuffer;
- src->bytes_in_buffer = bytes;
- return TRUE;
-}
-
-static void sk_skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
- skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src;
-
- if (num_bytes > (long)src->bytes_in_buffer) {
- size_t bytesToSkip = num_bytes - src->bytes_in_buffer;
- while (bytesToSkip > 0) {
- size_t bytes = src->fStream->skip(bytesToSkip);
- if (bytes <= 0 || bytes > bytesToSkip) {
-// SkDebugf("xxxxxxxxxxxxxx failure to skip request %d returned %d\n", bytesToSkip, bytes);
- cinfo->err->error_exit((j_common_ptr)cinfo);
- return;
- }
-#ifdef SK_JPEG_INDEX_SUPPORTED
- src->current_offset += bytes;
-#endif
- bytesToSkip -= bytes;
- }
- src->next_input_byte = (const JOCTET*)src->fBuffer;
- src->bytes_in_buffer = 0;
- } else {
- src->next_input_byte += num_bytes;
- src->bytes_in_buffer -= num_bytes;
- }
-}
-
-static void sk_term_source(j_decompress_ptr /*cinfo*/) {}
-
-
-///////////////////////////////////////////////////////////////////////////////
-
-skjpeg_source_mgr::skjpeg_source_mgr(SkStream* stream, SkImageDecoder* decoder)
- : fStream(stream)
- , fDecoder(decoder) {
-
- init_source = sk_init_source;
- fill_input_buffer = sk_fill_input_buffer;
- skip_input_data = sk_skip_input_data;
- resync_to_restart = jpeg_resync_to_restart;
- term_source = sk_term_source;
-#ifdef SK_JPEG_INDEX_SUPPORTED
- seek_input_data = sk_seek_input_data;
-#endif
-// SkDebugf("**************** use memorybase %p %d\n", fMemoryBase, fMemoryBaseSize);
-}
-
///////////////////////////////////////////////////////////////////////////////
static void sk_init_destination(j_compress_ptr cinfo) {
diff --git a/src/images/SkJpegUtility.h b/src/images/SkJpegUtility.h
index 1a763f843c..c84465289c 100644
--- a/src/images/SkJpegUtility.h
+++ b/src/images/SkJpegUtility.h
@@ -10,7 +10,6 @@
#ifndef SkJpegUtility_DEFINED
#define SkJpegUtility_DEFINED
-#include "SkImageDecoder.h"
#include "SkStream.h"
extern "C" {
@@ -30,23 +29,6 @@ struct skjpeg_error_mgr : jpeg_error_mgr {
void skjpeg_error_exit(j_common_ptr cinfo);
-///////////////////////////////////////////////////////////////////////////
-/* Our source struct for directing jpeg to our stream object.
-*/
-struct skjpeg_source_mgr : jpeg_source_mgr {
- skjpeg_source_mgr(SkStream* stream, SkImageDecoder* decoder);
-
- // Unowned.
- SkStream* fStream;
- // Unowned pointer to the decoder, used to check if the decoding process
- // has been cancelled.
- SkImageDecoder* fDecoder;
- enum {
- kBufferSize = 1024
- };
- char fBuffer[kBufferSize];
-};
-
/////////////////////////////////////////////////////////////////////////////
/* Our destination struct for directing decompressed pixels to our stream
* object.
diff --git a/src/images/SkScaledBitmapSampler.cpp b/src/images/SkScaledBitmapSampler.cpp
deleted file mode 100644
index 5ffd648893..0000000000
--- a/src/images/SkScaledBitmapSampler.cpp
+++ /dev/null
@@ -1,877 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#include "SkScaledBitmapSampler.h"
-#include "SkBitmap.h"
-#include "SkColorPriv.h"
-#include "SkDither.h"
-#include "SkTypes.h"
-
-// 8888
-
-static bool Sample_Gray_D8888(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int, const SkPMColor[]) {
- SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
- for (int x = 0; x < width; x++) {
- dst[x] = SkPackARGB32(0xFF, src[0], src[0], src[0]);
- src += deltaSrc;
- }
- return false;
-}
-
-static SkScaledBitmapSampler::RowProc
-get_gray_to_8888_proc(const SkScaledBitmapSampler::Options& opts) {
- // Dither, unpremul, and skipZeroes have no effect
- return Sample_Gray_D8888;
-}
-
-static bool Sample_RGBx_D8888(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int, const SkPMColor[]) {
- SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
- for (int x = 0; x < width; x++) {
- dst[x] = SkPackARGB32(0xFF, src[0], src[1], src[2]);
- src += deltaSrc;
- }
- return false;
-}
-
-static SkScaledBitmapSampler::RowProc
-get_RGBx_to_8888_proc(const SkScaledBitmapSampler::Options& opts) {
- // Dither, unpremul, and skipZeroes have no effect
- return Sample_RGBx_D8888;
-}
-
-static bool Sample_RGBA_D8888(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int, const SkPMColor[]) {
- SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
- unsigned alphaMask = 0xFF;
- for (int x = 0; x < width; x++) {
- unsigned alpha = src[3];
- dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
- src += deltaSrc;
- alphaMask &= alpha;
- }
- return alphaMask != 0xFF;
-}
-
-static bool Sample_RGBA_D8888_Unpremul(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int,
- const SkPMColor[]) {
- uint32_t* SK_RESTRICT dst = reinterpret_cast<uint32_t*>(dstRow);
- unsigned alphaMask = 0xFF;
- for (int x = 0; x < width; x++) {
- unsigned alpha = src[3];
- dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]);
- src += deltaSrc;
- alphaMask &= alpha;
- }
- return alphaMask != 0xFF;
-}
-
-static bool Sample_RGBA_D8888_SkipZ(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int,
- const SkPMColor[]) {
- SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
- unsigned alphaMask = 0xFF;
- for (int x = 0; x < width; x++) {
- unsigned alpha = src[3];
- if (0 != alpha) {
- dst[x] = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
- }
- src += deltaSrc;
- alphaMask &= alpha;
- }
- return alphaMask != 0xFF;
-}
-
-static SkScaledBitmapSampler::RowProc
-get_RGBA_to_8888_proc(const SkScaledBitmapSampler::Options& opts) {
- // Dither has no effect.
- if (!opts.fPremultiplyAlpha) {
- // We could check each component for a zero, at the expense of extra checks.
- // For now, just return unpremul.
- return Sample_RGBA_D8888_Unpremul;
- }
- // Supply the versions that premultiply the colors
- if (opts.fSkipZeros) {
- return Sample_RGBA_D8888_SkipZ;
- }
- return Sample_RGBA_D8888;
-}
-
-// 565
-
-static bool Sample_Gray_D565(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int, const SkPMColor[]) {
- uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
- for (int x = 0; x < width; x++) {
- dst[x] = SkPack888ToRGB16(src[0], src[0], src[0]);
- src += deltaSrc;
- }
- return false;
-}
-
-static bool Sample_Gray_D565_D(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int y, const SkPMColor[]) {
- uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
- DITHER_565_SCAN(y);
- for (int x = 0; x < width; x++) {
- dst[x] = SkDitherRGBTo565(src[0], src[0], src[0], DITHER_VALUE(x));
- src += deltaSrc;
- }
- return false;
-}
-
-static SkScaledBitmapSampler::RowProc
-get_gray_to_565_proc(const SkScaledBitmapSampler::Options& opts) {
- // Unpremul and skip zeroes make no difference
- if (opts.fDither) {
- return Sample_Gray_D565_D;
- }
- return Sample_Gray_D565;
-}
-
-static bool Sample_RGBx_D565(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int, const SkPMColor[]) {
- uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
- for (int x = 0; x < width; x++) {
- dst[x] = SkPack888ToRGB16(src[0], src[1], src[2]);
- src += deltaSrc;
- }
- return false;
-}
-
-static bool Sample_RGBx_D565_D(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int y,
- const SkPMColor[]) {
- uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
- DITHER_565_SCAN(y);
- for (int x = 0; x < width; x++) {
- dst[x] = SkDitherRGBTo565(src[0], src[1], src[2], DITHER_VALUE(x));
- src += deltaSrc;
- }
- return false;
-}
-
-static SkScaledBitmapSampler::RowProc
-get_RGBx_to_565_proc(const SkScaledBitmapSampler::Options& opts) {
- // Unpremul and skip zeroes make no difference
- if (opts.fDither) {
- return Sample_RGBx_D565_D;
- }
- return Sample_RGBx_D565;
-}
-
-
-static bool Sample_D565_D565(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int, const SkPMColor[]) {
- uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
- uint16_t* SK_RESTRICT castedSrc = (uint16_t*) src;
- for (int x = 0; x < width; x++) {
- dst[x] = castedSrc[0];
- castedSrc += deltaSrc >> 1;
- }
- return false;
-}
-
-static SkScaledBitmapSampler::RowProc
-get_565_to_565_proc(const SkScaledBitmapSampler::Options& opts) {
- // Unpremul, dither, and skip zeroes have no effect
- return Sample_D565_D565;
-}
-
-// 4444
-
-static bool Sample_Gray_D4444(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int, const SkPMColor[]) {
- SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
- for (int x = 0; x < width; x++) {
- unsigned gray = src[0] >> 4;
- dst[x] = SkPackARGB4444(0xF, gray, gray, gray);
- src += deltaSrc;
- }
- return false;
-}
-
-static bool Sample_Gray_D4444_D(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int y, const SkPMColor[]) {
- SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
- DITHER_4444_SCAN(y);
- for (int x = 0; x < width; x++) {
- dst[x] = SkDitherARGB32To4444(0xFF, src[0], src[0], src[0],
- DITHER_VALUE(x));
- src += deltaSrc;
- }
- return false;
-}
-
-static SkScaledBitmapSampler::RowProc
-get_gray_to_4444_proc(const SkScaledBitmapSampler::Options& opts) {
- // Skip zeroes and unpremul make no difference
- if (opts.fDither) {
- return Sample_Gray_D4444_D;
- }
- return Sample_Gray_D4444;
-}
-
-static bool Sample_RGBx_D4444(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int, const SkPMColor[]) {
- SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
- for (int x = 0; x < width; x++) {
- dst[x] = SkPackARGB4444(0xF, src[0] >> 4, src[1] >> 4, src[2] >> 4);
- src += deltaSrc;
- }
- return false;
-}
-
-static bool Sample_RGBx_D4444_D(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int y, const SkPMColor[]) {
- SkPMColor16* dst = (SkPMColor16*)dstRow;
- DITHER_4444_SCAN(y);
-
- for (int x = 0; x < width; x++) {
- dst[x] = SkDitherARGB32To4444(0xFF, src[0], src[1], src[2],
- DITHER_VALUE(x));
- src += deltaSrc;
- }
- return false;
-}
-
-static SkScaledBitmapSampler::RowProc
-get_RGBx_to_4444_proc(const SkScaledBitmapSampler::Options& opts) {
- // Skip zeroes and unpremul make no difference
- if (opts.fDither) {
- return Sample_RGBx_D4444_D;
- }
- return Sample_RGBx_D4444;
-}
-
-static bool Sample_RGBA_D4444(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int, const SkPMColor[]) {
- SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
- unsigned alphaMask = 0xFF;
-
- for (int x = 0; x < width; x++) {
- unsigned alpha = src[3];
- SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
- dst[x] = SkPixel32ToPixel4444(c);
- src += deltaSrc;
- alphaMask &= alpha;
- }
- return alphaMask != 0xFF;
-}
-
-static bool Sample_RGBA_D4444_SkipZ(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int,
- const SkPMColor[]) {
- SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
- unsigned alphaMask = 0xFF;
-
- for (int x = 0; x < width; x++) {
- unsigned alpha = src[3];
- if (alpha != 0) {
- SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
- dst[x] = SkPixel32ToPixel4444(c);
- }
- src += deltaSrc;
- alphaMask &= alpha;
- }
- return alphaMask != 0xFF;
-}
-
-
-static bool Sample_RGBA_D4444_D(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int y,
- const SkPMColor[]) {
- SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
- unsigned alphaMask = 0xFF;
- DITHER_4444_SCAN(y);
-
- for (int x = 0; x < width; x++) {
- unsigned alpha = src[3];
- SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
- dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
- src += deltaSrc;
- alphaMask &= alpha;
- }
- return alphaMask != 0xFF;
-}
-
-static bool Sample_RGBA_D4444_D_SkipZ(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int y,
- const SkPMColor[]) {
- SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
- unsigned alphaMask = 0xFF;
- DITHER_4444_SCAN(y);
-
- for (int x = 0; x < width; x++) {
- unsigned alpha = src[3];
- if (alpha != 0) {
- SkPMColor c = SkPreMultiplyARGB(alpha, src[0], src[1], src[2]);
- dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
- }
- src += deltaSrc;
- alphaMask &= alpha;
- }
- return alphaMask != 0xFF;
-}
-
-static SkScaledBitmapSampler::RowProc
-get_RGBA_to_4444_proc(const SkScaledBitmapSampler::Options& opts) {
- if (!opts.fPremultiplyAlpha) {
- // Unpremultiplied is not supported for 4444
- return nullptr;
- }
- if (opts.fSkipZeros) {
- if (opts.fDither) {
- return Sample_RGBA_D4444_D_SkipZ;
- }
- return Sample_RGBA_D4444_SkipZ;
- }
- if (opts.fDither) {
- return Sample_RGBA_D4444_D;
- }
- return Sample_RGBA_D4444;
-}
-
-// Index
-
-#define A32_MASK_IN_PLACE (SkPMColor)(SK_A32_MASK << SK_A32_SHIFT)
-
-static bool Sample_Index_D8888(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int, const SkPMColor ctable[]) {
-
- SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
- SkPMColor cc = A32_MASK_IN_PLACE;
- for (int x = 0; x < width; x++) {
- SkPMColor c = ctable[*src];
- cc &= c;
- dst[x] = c;
- src += deltaSrc;
- }
- return cc != A32_MASK_IN_PLACE;
-}
-
-static bool Sample_Index_D8888_SkipZ(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int,
- const SkPMColor ctable[]) {
-
- SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow;
- SkPMColor cc = A32_MASK_IN_PLACE;
- for (int x = 0; x < width; x++) {
- SkPMColor c = ctable[*src];
- cc &= c;
- if (c != 0) {
- dst[x] = c;
- }
- src += deltaSrc;
- }
- return cc != A32_MASK_IN_PLACE;
-}
-
-static SkScaledBitmapSampler::RowProc
-get_index_to_8888_proc(const SkScaledBitmapSampler::Options& opts) {
- // The caller is expected to have created the source colortable
- // properly with respect to opts.fPremultiplyAlpha, so premul makes
- // no difference here.
- // Dither makes no difference
- if (opts.fSkipZeros) {
- return Sample_Index_D8888_SkipZ;
- }
- return Sample_Index_D8888;
-}
-
-static bool Sample_Index_D565(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int, const SkPMColor ctable[]) {
-
- uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
- for (int x = 0; x < width; x++) {
- dst[x] = SkPixel32ToPixel16(ctable[*src]);
- src += deltaSrc;
- }
- return false;
-}
-
-static bool Sample_Index_D565_D(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src, int width,
- int deltaSrc, int y, const SkPMColor ctable[]) {
-
- uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
- DITHER_565_SCAN(y);
-
- for (int x = 0; x < width; x++) {
- SkPMColor c = ctable[*src];
- dst[x] = SkDitherRGBTo565(SkGetPackedR32(c), SkGetPackedG32(c),
- SkGetPackedB32(c), DITHER_VALUE(x));
- src += deltaSrc;
- }
- return false;
-}
-
-static SkScaledBitmapSampler::RowProc
-get_index_to_565_proc(const SkScaledBitmapSampler::Options& opts) {
- // Unpremultiplied and skip zeroes make no difference
- if (opts.fDither) {
- return Sample_Index_D565_D;
- }
- return Sample_Index_D565;
-}
-
-static bool Sample_Index_D4444(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src, int width,
- int deltaSrc, int y, const SkPMColor ctable[]) {
-
- SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
- SkPMColor cc = A32_MASK_IN_PLACE;
- for (int x = 0; x < width; x++) {
- SkPMColor c = ctable[*src];
- cc &= c;
- dst[x] = SkPixel32ToPixel4444(c);
- src += deltaSrc;
- }
- return cc != A32_MASK_IN_PLACE;
-}
-
-static bool Sample_Index_D4444_D(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src, int width,
- int deltaSrc, int y, const SkPMColor ctable[]) {
-
- SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
- SkPMColor cc = A32_MASK_IN_PLACE;
- DITHER_4444_SCAN(y);
-
- for (int x = 0; x < width; x++) {
- SkPMColor c = ctable[*src];
- cc &= c;
- dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
- src += deltaSrc;
- }
- return cc != A32_MASK_IN_PLACE;
-}
-
-static bool Sample_Index_D4444_SkipZ(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src, int width,
- int deltaSrc, int y, const SkPMColor ctable[]) {
-
- SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
- SkPMColor cc = A32_MASK_IN_PLACE;
- for (int x = 0; x < width; x++) {
- SkPMColor c = ctable[*src];
- cc &= c;
- if (c != 0) {
- dst[x] = SkPixel32ToPixel4444(c);
- }
- src += deltaSrc;
- }
- return cc != A32_MASK_IN_PLACE;
-}
-
-static bool Sample_Index_D4444_D_SkipZ(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src, int width,
- int deltaSrc, int y, const SkPMColor ctable[]) {
-
- SkPMColor16* SK_RESTRICT dst = (SkPMColor16*)dstRow;
- SkPMColor cc = A32_MASK_IN_PLACE;
- DITHER_4444_SCAN(y);
-
- for (int x = 0; x < width; x++) {
- SkPMColor c = ctable[*src];
- cc &= c;
- if (c != 0) {
- dst[x] = SkDitherARGB32To4444(c, DITHER_VALUE(x));
- }
- src += deltaSrc;
- }
- return cc != A32_MASK_IN_PLACE;
-}
-
-static SkScaledBitmapSampler::RowProc
-get_index_to_4444_proc(const SkScaledBitmapSampler::Options& opts) {
- // Unpremul not allowed
- if (!opts.fPremultiplyAlpha) {
- return nullptr;
- }
- if (opts.fSkipZeros) {
- if (opts.fDither) {
- return Sample_Index_D4444_D_SkipZ;
- }
- return Sample_Index_D4444_SkipZ;
- }
- if (opts.fDither) {
- return Sample_Index_D4444_D;
- }
- return Sample_Index_D4444;
-}
-
-static bool Sample_Index_DI(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int, const SkPMColor[]) {
- if (1 == deltaSrc) {
- memcpy(dstRow, src, width);
- } else {
- uint8_t* SK_RESTRICT dst = (uint8_t*)dstRow;
- for (int x = 0; x < width; x++) {
- dst[x] = src[0];
- src += deltaSrc;
- }
- }
- return false;
-}
-
-static SkScaledBitmapSampler::RowProc
-get_index_to_index_proc(const SkScaledBitmapSampler::Options& opts) {
- // Unpremul not allowed
- if (!opts.fPremultiplyAlpha) {
- return nullptr;
- }
- // Ignore dither and skip zeroes
- return Sample_Index_DI;
-}
-
-// A8
-static bool Sample_Gray_DA8(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int,
- const SkPMColor[]) {
- // Sampling Gray to A8 uses the same function as Index to Index8,
- // except we assume that there is alpha for speed, since an A8
- // bitmap with no alpha is not interesting.
- (void) Sample_Index_DI(dstRow, src, width, deltaSrc, /* y unused */ 0,
- /* ctable unused */ nullptr);
- return true;
-}
-
-static SkScaledBitmapSampler::RowProc
-get_gray_to_A8_proc(const SkScaledBitmapSampler::Options& opts) {
- if (!opts.fPremultiplyAlpha) {
- return nullptr;
- }
- // Ignore skip and dither.
- return Sample_Gray_DA8;
-}
-
-typedef SkScaledBitmapSampler::RowProc (*RowProcChooser)(const SkScaledBitmapSampler::Options&);
-///////////////////////////////////////////////////////////////////////////////
-
-#include "SkScaledBitmapSampler.h"
-
-SkScaledBitmapSampler::SkScaledBitmapSampler(int width, int height,
- int sampleSize) {
- fCTable = nullptr;
- fDstRow = nullptr;
- fRowProc = nullptr;
-
- if (width <= 0 || height <= 0) {
- sk_throw();
- }
-
- SkDEBUGCODE(fSampleMode = kUninitialized_SampleMode);
-
- if (sampleSize <= 1) {
- fScaledWidth = width;
- fScaledHeight = height;
- fX0 = fY0 = 0;
- fDX = fDY = 1;
- return;
- }
-
- int dx = SkMin32(sampleSize, width);
- int dy = SkMin32(sampleSize, height);
-
- fScaledWidth = width / dx;
- fScaledHeight = height / dy;
-
- SkASSERT(fScaledWidth > 0);
- SkASSERT(fScaledHeight > 0);
-
- fX0 = dx >> 1;
- fY0 = dy >> 1;
-
- SkASSERT(fX0 >= 0 && fX0 < width);
- SkASSERT(fY0 >= 0 && fY0 < height);
-
- fDX = dx;
- fDY = dy;
-
- SkASSERT(fDX > 0 && (fX0 + fDX * (fScaledWidth - 1)) < width);
- SkASSERT(fDY > 0 && (fY0 + fDY * (fScaledHeight - 1)) < height);
-}
-
-bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc,
- const Options& opts,
- const SkPMColor ctable[]) {
- static const RowProcChooser gProcChoosers[] = {
- get_gray_to_8888_proc,
- get_RGBx_to_8888_proc,
- get_RGBA_to_8888_proc,
- get_index_to_8888_proc,
- nullptr, // 565 to 8888
-
- get_gray_to_565_proc,
- get_RGBx_to_565_proc,
- get_RGBx_to_565_proc, // The source alpha will be ignored.
- get_index_to_565_proc,
- get_565_to_565_proc,
-
- get_gray_to_4444_proc,
- get_RGBx_to_4444_proc,
- get_RGBA_to_4444_proc,
- get_index_to_4444_proc,
- nullptr, // 565 to 4444
-
- nullptr, // gray to index
- nullptr, // rgbx to index
- nullptr, // rgba to index
- get_index_to_index_proc,
- nullptr, // 565 to index
-
- get_gray_to_A8_proc,
- nullptr, // rgbx to a8
- nullptr, // rgba to a8
- nullptr, // index to a8
- nullptr, // 565 to a8
- };
-
- // The jump between dst configs in the table
- static const int gProcDstConfigSpan = 5;
- static_assert(SK_ARRAY_COUNT(gProcChoosers) == 5 * gProcDstConfigSpan,
- "gProcs_has_the_wrong_number_of_entries");
-
- fCTable = ctable;
-
- int index = 0;
- switch (sc) {
- case SkScaledBitmapSampler::kGray:
- fSrcPixelSize = 1;
- index += 0;
- break;
- case SkScaledBitmapSampler::kRGB:
- fSrcPixelSize = 3;
- index += 1;
- break;
- case SkScaledBitmapSampler::kRGBX:
- fSrcPixelSize = 4;
- index += 1;
- break;
- case SkScaledBitmapSampler::kRGBA:
- fSrcPixelSize = 4;
- index += 2;
- break;
- case SkScaledBitmapSampler::kIndex:
- fSrcPixelSize = 1;
- index += 3;
- break;
- case SkScaledBitmapSampler::kRGB_565:
- fSrcPixelSize = 2;
- index += 4;
- break;
- default:
- return false;
- }
-
- switch (dst->colorType()) {
- case kN32_SkColorType:
- index += 0 * gProcDstConfigSpan;
- break;
- case kRGB_565_SkColorType:
- index += 1 * gProcDstConfigSpan;
- break;
- case kARGB_4444_SkColorType:
- index += 2 * gProcDstConfigSpan;
- break;
- case kIndex_8_SkColorType:
- index += 3 * gProcDstConfigSpan;
- break;
- case kAlpha_8_SkColorType:
- index += 4 * gProcDstConfigSpan;
- break;
- default:
- return false;
- }
-
- RowProcChooser chooser = gProcChoosers[index];
- if (nullptr == chooser) {
- fRowProc = nullptr;
- } else {
- fRowProc = chooser(opts);
- }
- fDstRow = (char*)dst->getPixels();
- fDstRowBytes = dst->rowBytes();
- fCurrY = 0;
- return fRowProc != nullptr;
-}
-
-bool SkScaledBitmapSampler::begin(SkBitmap* dst, SrcConfig sc,
- const SkImageDecoder& decoder,
- const SkPMColor ctable[]) {
- return this->begin(dst, sc, Options(decoder), ctable);
-}
-
-bool SkScaledBitmapSampler::next(const uint8_t* SK_RESTRICT src) {
- SkASSERT(kInterlaced_SampleMode != fSampleMode);
- SkDEBUGCODE(fSampleMode = kConsecutive_SampleMode);
- SkASSERT((unsigned)fCurrY < (unsigned)fScaledHeight);
-
- bool hadAlpha = fRowProc(fDstRow, src + fX0 * fSrcPixelSize, fScaledWidth,
- fDX * fSrcPixelSize, fCurrY, fCTable);
- fDstRow += fDstRowBytes;
- fCurrY += 1;
- return hadAlpha;
-}
-
-bool SkScaledBitmapSampler::sampleInterlaced(const uint8_t* SK_RESTRICT src, int srcY) {
- SkASSERT(kConsecutive_SampleMode != fSampleMode);
- SkDEBUGCODE(fSampleMode = kInterlaced_SampleMode);
- // Any line that should be a part of the destination can be created by the formula:
- // fY0 + (some multiplier) * fDY
- // so if srcY - fY0 is not an integer multiple of fDY that srcY will be skipped.
- const int srcYMinusY0 = srcY - fY0;
- if (srcYMinusY0 % fDY != 0) {
- // This line is not part of the output, so return false for alpha, since we have
- // not added an alpha to the output.
- return false;
- }
- // Unlike in next(), where the data is used sequentially, this function skips around,
- // so fDstRow and fCurrY are never updated. fDstRow must always be the starting point
- // of the destination bitmap's pixels, which is used to calculate the destination row
- // each time this function is called.
- const int dstY = srcYMinusY0 / fDY;
- if (dstY >= fScaledHeight) {
- return false;
- }
- char* dstRow = fDstRow + dstY * fDstRowBytes;
- return fRowProc(dstRow, src + fX0 * fSrcPixelSize, fScaledWidth,
- fDX * fSrcPixelSize, dstY, fCTable);
-}
-
-#ifdef SK_DEBUG
-// The following code is for a test to ensure that changing the method to get the right row proc
-// did not change the row proc unintentionally. Tested by ImageDecodingTest.cpp
-
-// friend of SkScaledBitmapSampler solely for the purpose of accessing fRowProc.
-class RowProcTester {
-public:
- static SkScaledBitmapSampler::RowProc getRowProc(const SkScaledBitmapSampler& sampler) {
- return sampler.fRowProc;
- }
-};
-
-
-// Table showing the expected RowProc for each combination of inputs.
-// Table formated as follows:
-// Each group of 5 consecutive rows represents sampling from a single
-// SkScaledBitmapSampler::SrcConfig.
-// Within each set, each row represents a different destination SkBitmap::Config
-// Each column represents a different combination of dither and unpremul.
-// D = dither ~D = no dither
-// U = unpremul ~U = no unpremul
-// ~D~U D~U ~DU DU
-SkScaledBitmapSampler::RowProc gTestProcs[] = {
- // Gray
- Sample_Gray_DA8, Sample_Gray_DA8, nullptr, nullptr, // to A8
- nullptr, nullptr, nullptr, nullptr, // to Index8
- Sample_Gray_D565, Sample_Gray_D565_D, Sample_Gray_D565, Sample_Gray_D565_D, // to 565
- Sample_Gray_D4444, Sample_Gray_D4444_D, Sample_Gray_D4444, Sample_Gray_D4444_D, // to 4444
- Sample_Gray_D8888, Sample_Gray_D8888, Sample_Gray_D8888, Sample_Gray_D8888, // to 8888
- // Index
- nullptr, nullptr, nullptr, nullptr, // to A8
- Sample_Index_DI, Sample_Index_DI, nullptr, nullptr, // to Index8
- Sample_Index_D565, Sample_Index_D565_D, Sample_Index_D565, Sample_Index_D565_D, // to 565
- Sample_Index_D4444, Sample_Index_D4444_D, nullptr, nullptr, // to 4444
- Sample_Index_D8888, Sample_Index_D8888, Sample_Index_D8888, Sample_Index_D8888, // to 8888
- // RGB
- nullptr, nullptr, nullptr, nullptr, // to A8
- nullptr, nullptr, nullptr, nullptr, // to Index8
- Sample_RGBx_D565, Sample_RGBx_D565_D, Sample_RGBx_D565, Sample_RGBx_D565_D, // to 565
- Sample_RGBx_D4444, Sample_RGBx_D4444_D, Sample_RGBx_D4444, Sample_RGBx_D4444_D, // to 4444
- Sample_RGBx_D8888, Sample_RGBx_D8888, Sample_RGBx_D8888, Sample_RGBx_D8888, // to 8888
- // RGBx is the same as RGB
- nullptr, nullptr, nullptr, nullptr, // to A8
- nullptr, nullptr, nullptr, nullptr, // to Index8
- Sample_RGBx_D565, Sample_RGBx_D565_D, Sample_RGBx_D565, Sample_RGBx_D565_D, // to 565
- Sample_RGBx_D4444, Sample_RGBx_D4444_D, Sample_RGBx_D4444, Sample_RGBx_D4444_D, // to 4444
- Sample_RGBx_D8888, Sample_RGBx_D8888, Sample_RGBx_D8888, Sample_RGBx_D8888, // to 8888
- // RGBA
- nullptr, nullptr, nullptr, nullptr, // to A8
- nullptr, nullptr, nullptr, nullptr, // to Index8
- Sample_RGBx_D565, Sample_RGBx_D565_D, Sample_RGBx_D565, Sample_RGBx_D565_D, // to 565
- Sample_RGBA_D4444, Sample_RGBA_D4444_D, nullptr, nullptr, // to 4444
- Sample_RGBA_D8888, Sample_RGBA_D8888, Sample_RGBA_D8888_Unpremul, Sample_RGBA_D8888_Unpremul, // to 8888
- // RGB_565
- nullptr, nullptr, nullptr, nullptr, // to A8
- nullptr, nullptr, nullptr, nullptr, // to Index8
- Sample_D565_D565, Sample_D565_D565, Sample_D565_D565, Sample_D565_D565, // to 565
- nullptr, nullptr, nullptr, nullptr, // to 4444
- nullptr, nullptr, nullptr, nullptr, // to 8888
-};
-
-// Dummy class that allows instantiation of an ImageDecoder, so begin can query its fields.
-class DummyDecoder : public SkImageDecoder {
-public:
- DummyDecoder() {}
-protected:
- Result onDecode(SkStream*, SkBitmap*, SkImageDecoder::Mode) override {
- return kFailure;
- }
-};
-
-void test_row_proc_choice();
-void test_row_proc_choice() {
- const SkColorType colorTypes[] = {
- kAlpha_8_SkColorType, kIndex_8_SkColorType, kRGB_565_SkColorType, kARGB_4444_SkColorType,
- kN32_SkColorType
- };
-
- SkBitmap dummyBitmap;
- DummyDecoder dummyDecoder;
- size_t procCounter = 0;
- for (int sc = SkScaledBitmapSampler::kGray; sc <= SkScaledBitmapSampler::kRGB_565; ++sc) {
- for (size_t c = 0; c < SK_ARRAY_COUNT(colorTypes); ++c) {
- for (int unpremul = 0; unpremul <= 1; ++unpremul) {
- for (int dither = 0; dither <= 1; ++dither) {
- // Arbitrary width/height/sampleSize to allow SkScaledBitmapSampler to
- // be considered valid.
- SkScaledBitmapSampler sampler(10, 10, 1);
- dummyBitmap.setInfo(SkImageInfo::Make(10, 10,
- colorTypes[c], kPremul_SkAlphaType));
- dummyDecoder.setDitherImage(SkToBool(dither));
- dummyDecoder.setRequireUnpremultipliedColors(SkToBool(unpremul));
- sampler.begin(&dummyBitmap, (SkScaledBitmapSampler::SrcConfig) sc,
- dummyDecoder);
- SkScaledBitmapSampler::RowProc expected = gTestProcs[procCounter];
- SkScaledBitmapSampler::RowProc actual = RowProcTester::getRowProc(sampler);
- SkASSERT(expected == actual);
- procCounter++;
- }
- }
- }
- }
- SkASSERT(SK_ARRAY_COUNT(gTestProcs) == procCounter);
-}
-#endif // SK_DEBUG
diff --git a/src/images/SkScaledBitmapSampler.h b/src/images/SkScaledBitmapSampler.h
deleted file mode 100644
index 198dc07572..0000000000
--- a/src/images/SkScaledBitmapSampler.h
+++ /dev/null
@@ -1,107 +0,0 @@
-
-/*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#ifndef SkScaledBitmapSampler_DEFINED
-#define SkScaledBitmapSampler_DEFINED
-
-#include "SkTypes.h"
-#include "SkColor.h"
-#include "SkImageDecoder.h"
-
-class SkBitmap;
-
-class SkScaledBitmapSampler {
-public:
- SkScaledBitmapSampler(int origWidth, int origHeight, int cellSize);
-
- int scaledWidth() const { return fScaledWidth; }
- int scaledHeight() const { return fScaledHeight; }
-
- int srcY0() const { return fY0; }
- int srcDX() const { return fDX; }
- int srcDY() const { return fDY; }
-
- enum SrcConfig {
- kGray, // 1 byte per pixel
- kIndex, // 1 byte per pixel
- kRGB, // 3 bytes per pixel
- kRGBX, // 4 byes per pixel (ignore 4th)
- kRGBA, // 4 bytes per pixel
- kRGB_565 // 2 bytes per pixel
- };
-
- struct Options {
- bool fDither;
- bool fPremultiplyAlpha;
- bool fSkipZeros;
- explicit Options(const SkImageDecoder &dec)
- : fDither(dec.getDitherImage())
- , fPremultiplyAlpha(!dec.getRequireUnpremultipliedColors())
- , fSkipZeros(dec.getSkipWritingZeroes())
- { }
- };
-
- // Given a dst bitmap (with pixels already allocated) and a src-config,
- // prepares iterator to process the src colors and write them into dst.
- // Returns false if the request cannot be fulfulled.
- bool begin(SkBitmap* dst, SrcConfig sc, const SkImageDecoder& decoder,
- const SkPMColor* = nullptr);
- bool begin(SkBitmap* dst, SrcConfig sc, const Options& opts,
- const SkPMColor* = nullptr);
- // call with row of src pixels, for y = 0...scaledHeight-1.
- // returns true if the row had non-opaque alpha in it
- bool next(const uint8_t* SK_RESTRICT src);
-
- // Like next(), but specifies the y value of the source row, so the
- // rows can come in any order. If the row is not part of the output
- // sample, it will be skipped. Only sampleInterlaced OR next should
- // be called for one SkScaledBitmapSampler.
- bool sampleInterlaced(const uint8_t* SK_RESTRICT src, int srcY);
-
- typedef bool (*RowProc)(void* SK_RESTRICT dstRow,
- const uint8_t* SK_RESTRICT src,
- int width, int deltaSrc, int y,
- const SkPMColor[]);
-
-private:
- int fScaledWidth;
- int fScaledHeight;
-
- int fX0; // first X coord to sample
- int fY0; // first Y coord (scanline) to sample
- int fDX; // step between X samples
- int fDY; // step between Y samples
-
-#ifdef SK_DEBUG
- // Keep track of whether the caller is using next or sampleInterlaced.
- // Only one can be used per sampler.
- enum SampleMode {
- kUninitialized_SampleMode,
- kConsecutive_SampleMode,
- kInterlaced_SampleMode,
- };
-
- SampleMode fSampleMode;
-#endif
-
- // setup state
- char* fDstRow; // points into bitmap's pixels
- size_t fDstRowBytes;
- int fCurrY; // used for dithering
- int fSrcPixelSize; // 1, 3, 4
- RowProc fRowProc;
-
- // optional reference to the src colors if the src is a palette model
- const SkPMColor* fCTable;
-
-#ifdef SK_DEBUG
- // Helper class allowing a test to have access to fRowProc.
- friend class RowProcTester;
-#endif
-};
-
-#endif
diff --git a/src/images/bmpdecoderhelper.cpp b/src/images/bmpdecoderhelper.cpp
deleted file mode 100644
index 9171b5d527..0000000000
--- a/src/images/bmpdecoderhelper.cpp
+++ /dev/null
@@ -1,369 +0,0 @@
-
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-// Author: cevans@google.com (Chris Evans)
-
-#include "bmpdecoderhelper.h"
-
-namespace image_codec {
-
-static const int kBmpHeaderSize = 14;
-static const int kBmpInfoSize = 40;
-static const int kBmpOS2InfoSize = 12;
-static const int kMaxDim = SHRT_MAX / 2;
-
-bool BmpDecoderHelper::DecodeImage(const char* p,
- size_t len,
- int max_pixels,
- BmpDecoderCallback* callback) {
- data_ = reinterpret_cast<const uint8*>(p);
- pos_ = 0;
- len_ = len;
- inverted_ = true;
- // Parse the header structure.
- if (len < kBmpHeaderSize + 4) {
- return false;
- }
- GetShort(); // Signature.
- GetInt(); // Size.
- GetInt(); // Reserved.
- int offset = GetInt();
- // Parse the info structure.
- int infoSize = GetInt();
- if (infoSize != kBmpOS2InfoSize && infoSize < kBmpInfoSize) {
- return false;
- }
- int cols = 0;
- int comp = 0;
- int colLen = 4;
- if (infoSize >= kBmpInfoSize) {
- if (len < kBmpHeaderSize + kBmpInfoSize) {
- return false;
- }
- width_ = GetInt();
- height_ = GetInt();
- GetShort(); // Planes.
- bpp_ = GetShort();
- comp = GetInt();
- GetInt(); // Size.
- GetInt(); // XPPM.
- GetInt(); // YPPM.
- cols = GetInt();
- GetInt(); // Important colours.
- } else {
- if (len < kBmpHeaderSize + kBmpOS2InfoSize) {
- return false;
- }
- colLen = 3;
- width_ = GetShort();
- height_ = GetShort();
- GetShort(); // Planes.
- bpp_ = GetShort();
- }
- if (height_ < 0) {
- height_ = -height_;
- inverted_ = false;
- }
- if (width_ <= 0 || width_ > kMaxDim || height_ <= 0 || height_ > kMaxDim) {
- return false;
- }
- if (width_ * height_ > max_pixels) {
- return false;
- }
- if (cols < 0 || cols > 256) {
- return false;
- }
- // Allocate then read in the colour map.
- if (cols == 0 && bpp_ <= 8) {
- cols = 1 << bpp_;
- }
- if (bpp_ <= 8 || cols > 0) {
- uint8* colBuf = new uint8[256 * 3];
- memset(colBuf, '\0', 256 * 3);
- colTab_.reset(colBuf);
- }
- if (cols > 0) {
- if (pos_ + (cols * colLen) > len_) {
- return false;
- }
- for (int i = 0; i < cols; ++i) {
- int base = i * 3;
- colTab_[base + 2] = GetByte();
- colTab_[base + 1] = GetByte();
- colTab_[base] = GetByte();
- if (colLen == 4) {
- GetByte();
- }
- }
- }
- // Read in the compression data if necessary.
- redBits_ = 0x7c00;
- greenBits_ = 0x03e0;
- blueBits_ = 0x001f;
- bool rle = false;
- if (comp == 1 || comp == 2) {
- rle = true;
- } else if (comp == 3) {
- if (pos_ + 12 > len_) {
- return false;
- }
- redBits_ = GetInt() & 0xffff;
- greenBits_ = GetInt() & 0xffff;
- blueBits_ = GetInt() & 0xffff;
- }
- redShiftRight_ = CalcShiftRight(redBits_);
- greenShiftRight_ = CalcShiftRight(greenBits_);
- blueShiftRight_ = CalcShiftRight(blueBits_);
- redShiftLeft_ = CalcShiftLeft(redBits_);
- greenShiftLeft_ = CalcShiftLeft(greenBits_);
- blueShiftLeft_ = CalcShiftLeft(blueBits_);
- rowPad_ = 0;
- pixelPad_ = 0;
- int rowLen;
- if (bpp_ == 32) {
- rowLen = width_ * 4;
- pixelPad_ = 1;
- } else if (bpp_ == 24) {
- rowLen = width_ * 3;
- } else if (bpp_ == 16) {
- rowLen = width_ * 2;
- } else if (bpp_ == 8) {
- rowLen = width_;
- } else if (bpp_ == 4) {
- rowLen = width_ / 2;
- if (width_ & 1) {
- rowLen++;
- }
- } else if (bpp_ == 1) {
- rowLen = width_ / 8;
- if (width_ & 7) {
- rowLen++;
- }
- } else {
- return false;
- }
- // Round the rowLen up to a multiple of 4.
- if (rowLen % 4 != 0) {
- rowPad_ = 4 - (rowLen % 4);
- rowLen += rowPad_;
- }
-
- if (offset > 0 && (size_t)offset > pos_ && (size_t)offset < len_) {
- pos_ = offset;
- }
- // Deliberately off-by-one; a load of BMPs seem to have their last byte
- // missing.
- if (!rle && (pos_ + (rowLen * height_) > len_ + 1)) {
- return false;
- }
-
- output_ = callback->SetSize(width_, height_);
- if (nullptr == output_) {
- return true; // meaning we succeeded, but they want us to stop now
- }
-
- if (rle && (bpp_ == 4 || bpp_ == 8)) {
- DoRLEDecode();
- } else {
- DoStandardDecode();
- }
- return true;
-}
-
-void BmpDecoderHelper::DoRLEDecode() {
- static const uint8 RLE_ESCAPE = 0;
- static const uint8 RLE_EOL = 0;
- static const uint8 RLE_EOF = 1;
- static const uint8 RLE_DELTA = 2;
- int x = 0;
- int y = height_ - 1;
- while (pos_ + 1 < len_) {
- uint8 cmd = GetByte();
- if (cmd != RLE_ESCAPE) {
- uint8 pixels = GetByte();
- int num = 0;
- uint8 col = pixels;
- while (cmd-- && x < width_) {
- if (bpp_ == 4) {
- if (num & 1) {
- col = pixels & 0xf;
- } else {
- col = pixels >> 4;
- }
- }
- PutPixel(x++, y, col);
- num++;
- }
- } else {
- cmd = GetByte();
- if (cmd == RLE_EOF) {
- return;
- } else if (cmd == RLE_EOL) {
- x = 0;
- y--;
- if (y < 0) {
- return;
- }
- } else if (cmd == RLE_DELTA) {
- if (pos_ + 1 < len_) {
- uint8 dx = GetByte();
- uint8 dy = GetByte();
- x += dx;
- if (x > width_) {
- x = width_;
- }
- y -= dy;
- if (y < 0) {
- return;
- }
- }
- } else {
- int num = 0;
- int bytesRead = 0;
- uint8 val = 0;
- while (cmd-- && pos_ < len_) {
- if (bpp_ == 8 || !(num & 1)) {
- val = GetByte();
- bytesRead++;
- }
- uint8 col = val;
- if (bpp_ == 4) {
- if (num & 1) {
- col = col & 0xf;
- } else {
- col >>= 4;
- }
- }
- if (x < width_) {
- PutPixel(x++, y, col);
- }
- num++;
- }
- // All pixel runs must be an even number of bytes - skip a byte if we
- // read an odd number.
- if ((bytesRead & 1) && pos_ < len_) {
- GetByte();
- }
- }
- }
- }
-}
-
-void BmpDecoderHelper::PutPixel(int x, int y, uint8 col) {
- CHECK(x >= 0 && x < width_);
- CHECK(y >= 0 && y < height_);
- if (!inverted_) {
- y = height_ - (y + 1);
- }
-
- int base = ((y * width_) + x) * 3;
- int colBase = col * 3;
- output_[base] = colTab_[colBase];
- output_[base + 1] = colTab_[colBase + 1];
- output_[base + 2] = colTab_[colBase + 2];
-}
-
-void BmpDecoderHelper::DoStandardDecode() {
- int row = 0;
- uint8 currVal = 0;
- for (int h = height_ - 1; h >= 0; h--, row++) {
- int realH = h;
- if (!inverted_) {
- realH = height_ - (h + 1);
- }
- uint8* line = output_ + (3 * width_ * realH);
- for (int w = 0; w < width_; w++) {
- if (bpp_ >= 24) {
- line[2] = GetByte();
- line[1] = GetByte();
- line[0] = GetByte();
- } else if (bpp_ == 16) {
- uint32 val = GetShort();
- line[0] = ((val & redBits_) >> redShiftRight_) << redShiftLeft_;
- line[1] = ((val & greenBits_) >> greenShiftRight_) << greenShiftLeft_;
- line[2] = ((val & blueBits_) >> blueShiftRight_) << blueShiftLeft_;
- } else if (bpp_ <= 8) {
- uint8 col;
- if (bpp_ == 8) {
- col = GetByte();
- } else if (bpp_ == 4) {
- if ((w % 2) == 0) {
- currVal = GetByte();
- col = currVal >> 4;
- } else {
- col = currVal & 0xf;
- }
- } else {
- if ((w % 8) == 0) {
- currVal = GetByte();
- }
- int bit = w & 7;
- col = ((currVal >> (7 - bit)) & 1);
- }
- int base = col * 3;
- line[0] = colTab_[base];
- line[1] = colTab_[base + 1];
- line[2] = colTab_[base + 2];
- }
- line += 3;
- for (int i = 0; i < pixelPad_; ++i) {
- GetByte();
- }
- }
- for (int i = 0; i < rowPad_; ++i) {
- GetByte();
- }
- }
-}
-
-int BmpDecoderHelper::GetInt() {
- uint8 b1 = GetByte();
- uint8 b2 = GetByte();
- uint8 b3 = GetByte();
- uint8 b4 = GetByte();
- return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
-}
-
-int BmpDecoderHelper::GetShort() {
- uint8 b1 = GetByte();
- uint8 b2 = GetByte();
- return b1 | (b2 << 8);
-}
-
-uint8 BmpDecoderHelper::GetByte() {
- CHECK(pos_ <= len_);
- // We deliberately allow this off-by-one access to cater for BMPs with their
- // last byte missing.
- if (pos_ == len_) {
- return 0;
- }
- return data_[pos_++];
-}
-
-int BmpDecoderHelper::CalcShiftRight(uint32 mask) {
- int ret = 0;
- while (mask != 0 && !(mask & 1)) {
- mask >>= 1;
- ret++;
- }
- return ret;
-}
-
-int BmpDecoderHelper::CalcShiftLeft(uint32 mask) {
- int ret = 0;
- while (mask != 0 && !(mask & 1)) {
- mask >>= 1;
- }
- while (mask != 0 && !(mask & 0x80)) {
- mask <<= 1;
- ret++;
- }
- return ret;
-}
-
-} // namespace image_codec
diff --git a/src/images/bmpdecoderhelper.h b/src/images/bmpdecoderhelper.h
deleted file mode 100644
index b448734bbc..0000000000
--- a/src/images/bmpdecoderhelper.h
+++ /dev/null
@@ -1,116 +0,0 @@
-
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-
-#ifndef IMAGE_CODEC_BMPDECODERHELPER_H__
-#define IMAGE_CODEC_BMPDECODERHELPER_H__
-
-///////////////////////////////////////////////////////////////////////////////
-// this section is my current "glue" between google3 code and android.
-// will be fixed soon
-
-#include "SkTypes.h"
-#include <limits.h>
-#define DISALLOW_EVIL_CONSTRUCTORS(name)
-#define CHECK(predicate) SkASSERT(predicate)
-typedef uint8_t uint8;
-typedef uint32_t uint32;
-
-template <typename T> class scoped_array {
-private:
- T* ptr_;
- scoped_array(scoped_array const&);
- scoped_array& operator=(const scoped_array&);
-
-public:
- explicit scoped_array(T* p = 0) : ptr_(p) {}
- ~scoped_array() {
- delete[] ptr_;
- }
-
- void reset(T* p = 0) {
- if (p != ptr_) {
- delete[] ptr_;
- ptr_ = p;
- }
- }
-
- T& operator[](int i) const {
- return ptr_[i];
- }
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-namespace image_codec {
-
-class BmpDecoderCallback {
- public:
- BmpDecoderCallback() { }
- virtual ~BmpDecoderCallback() {}
-
- /**
- * This is called once for an image. It is passed the width and height and
- * should return the address of a buffer that is large enough to store
- * all of the resulting pixels (widht * height * 3 bytes). If it returns nullptr,
- * then the decoder will abort, but return true, as the caller has received
- * valid dimensions.
- */
- virtual uint8* SetSize(int width, int height) = 0;
-
- private:
- DISALLOW_EVIL_CONSTRUCTORS(BmpDecoderCallback);
-};
-
-class BmpDecoderHelper {
- public:
- BmpDecoderHelper() { }
- ~BmpDecoderHelper() { }
- bool DecodeImage(const char* data,
- size_t len,
- int max_pixels,
- BmpDecoderCallback* callback);
-
- private:
- DISALLOW_EVIL_CONSTRUCTORS(BmpDecoderHelper);
-
- void DoRLEDecode();
- void DoStandardDecode();
- void PutPixel(int x, int y, uint8 col);
-
- int GetInt();
- int GetShort();
- uint8 GetByte();
- int CalcShiftRight(uint32 mask);
- int CalcShiftLeft(uint32 mask);
-
- const uint8* data_;
- size_t pos_;
- size_t len_;
- int width_;
- int height_;
- int bpp_;
- int pixelPad_;
- int rowPad_;
- scoped_array<uint8> colTab_;
- uint32 redBits_;
- uint32 greenBits_;
- uint32 blueBits_;
- int redShiftRight_;
- int greenShiftRight_;
- int blueShiftRight_;
- int redShiftLeft_;
- int greenShiftLeft_;
- int blueShiftLeft_;
- uint8* output_;
- bool inverted_;
-};
-
-} // namespace
-
-#endif