Delete dead SkImageDecoder::buildTileIndex and decodeSubset code
This approach to subset decoding is no longer supported. We have replaced it with an implementation that does not depend on forked libraries. https://codereview.chromium.org/1406153015/ BUG=skia: Review URL: https://codereview.chromium.org/1426943009
This commit is contained in:
parent
5c9e34a350
commit
5c351f38fa
@ -237,26 +237,6 @@ public:
|
||||
return this->decode(stream, bitmap, kUnknown_SkColorType, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a stream, build an index for doing tile-based decode.
|
||||
* The built index will be saved in the decoder, and the image size will
|
||||
* be returned in width and height.
|
||||
*
|
||||
* Takes ownership of the SkStreamRewindable, on success or failure.
|
||||
*
|
||||
* Return true for success or false on failure.
|
||||
*/
|
||||
bool buildTileIndex(SkStreamRewindable*, int *width, int *height);
|
||||
|
||||
/**
|
||||
* Decode a rectangle subset in the image.
|
||||
* The method can only be called after buildTileIndex().
|
||||
*
|
||||
* Return true for success.
|
||||
* Return false if the index is never built or failing in decoding.
|
||||
*/
|
||||
bool decodeSubset(SkBitmap* bm, const SkIRect& subset, SkColorType pref);
|
||||
|
||||
/** Given a stream, this will try to find an appropriate decoder object.
|
||||
If none is found, the method returns NULL.
|
||||
*/
|
||||
@ -308,16 +288,6 @@ protected:
|
||||
// must be overridden in subclasses. This guy is called by decode(...)
|
||||
virtual Result onDecode(SkStream*, SkBitmap* bitmap, Mode) = 0;
|
||||
|
||||
// If the decoder wants to support tiled based decoding, this method must be overridden.
|
||||
// This is called by buildTileIndex(...)
|
||||
virtual bool onBuildTileIndex(SkStreamRewindable*, int* /*width*/, int* /*height*/);
|
||||
|
||||
// If the decoder wants to support tiled based decoding,
|
||||
// this method must be overridden. This guy is called by decodeRegion(...)
|
||||
virtual bool onDecodeSubset(SkBitmap*, const SkIRect&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** If planes or rowBytes is NULL, decodes the header and computes componentSizes
|
||||
for memory allocation.
|
||||
Otherwise, decodes the YUV planes into the provided image planes and
|
||||
@ -330,25 +300,6 @@ protected:
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Crop a rectangle from the src Bitmap to the dest Bitmap. src and dst are
|
||||
* both sampled by sampleSize from an original Bitmap.
|
||||
*
|
||||
* @param dst the destination bitmap.
|
||||
* @param src the source bitmap that is sampled by sampleSize from the
|
||||
* original bitmap.
|
||||
* @param sampleSize the sample size that src is sampled from the original bitmap.
|
||||
* @param (dstX, dstY) the upper-left point of the dest bitmap in terms of
|
||||
* the coordinate in the original bitmap.
|
||||
* @param (width, height) the width and height of the unsampled dst.
|
||||
* @param (srcX, srcY) the upper-left point of the src bitmap in terms of
|
||||
* the coordinate in the original bitmap.
|
||||
* @return bool Whether or not it succeeded.
|
||||
*/
|
||||
bool cropBitmap(SkBitmap *dst, SkBitmap *src, int sampleSize,
|
||||
int dstX, int dstY, int width, int height,
|
||||
int srcX, int srcY);
|
||||
|
||||
/**
|
||||
* Copy all fields on this decoder to the other decoder. Used by subclasses
|
||||
* to decode a subimage using a different decoder, but with the same settings.
|
||||
|
@ -142,76 +142,6 @@ SkImageDecoder::Result SkImageDecoder::decode(SkStream* stream, SkBitmap* bm, Sk
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SkImageDecoder::decodeSubset(SkBitmap* bm, const SkIRect& rect, SkColorType pref) {
|
||||
// we reset this to false before calling onDecodeSubset
|
||||
fShouldCancelDecode = false;
|
||||
// assign this, for use by getPrefColorType(), in case fUsePrefTable is false
|
||||
fDefaultPref = pref;
|
||||
|
||||
return this->onDecodeSubset(bm, rect);
|
||||
}
|
||||
|
||||
bool SkImageDecoder::buildTileIndex(SkStreamRewindable* stream, int *width, int *height) {
|
||||
// we reset this to false before calling onBuildTileIndex
|
||||
fShouldCancelDecode = false;
|
||||
|
||||
return this->onBuildTileIndex(stream, width, height);
|
||||
}
|
||||
|
||||
bool SkImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int* /*width*/,
|
||||
int* /*height*/) {
|
||||
delete stream;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SkImageDecoder::cropBitmap(SkBitmap *dst, SkBitmap *src, int sampleSize,
|
||||
int dstX, int dstY, int width, int height,
|
||||
int srcX, int srcY) {
|
||||
int w = width / sampleSize;
|
||||
int h = height / sampleSize;
|
||||
if (src->colorType() == kIndex_8_SkColorType) {
|
||||
// kIndex8 does not allow drawing via an SkCanvas, as is done below.
|
||||
// Instead, use extractSubset. Note that this shares the SkPixelRef and
|
||||
// SkColorTable.
|
||||
// FIXME: Since src is discarded in practice, this holds on to more
|
||||
// pixels than is strictly necessary. Switch to a copy if memory
|
||||
// savings are more important than speed here. This also means
|
||||
// that the pixels in dst can not be reused (though there is no
|
||||
// allocation, which was already done on src).
|
||||
int x = (dstX - srcX) / sampleSize;
|
||||
int y = (dstY - srcY) / sampleSize;
|
||||
SkIRect subset = SkIRect::MakeXYWH(x, y, w, h);
|
||||
return src->extractSubset(dst, subset);
|
||||
}
|
||||
// if the destination has no pixels then we must allocate them.
|
||||
if (dst->isNull()) {
|
||||
dst->setInfo(src->info().makeWH(w, h));
|
||||
|
||||
if (!this->allocPixelRef(dst, nullptr)) {
|
||||
SkDEBUGF(("failed to allocate pixels needed to crop the bitmap"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// check to see if the destination is large enough to decode the desired
|
||||
// region. If this assert fails we will just draw as much of the source
|
||||
// into the destination that we can.
|
||||
if (dst->width() < w || dst->height() < h) {
|
||||
SkDEBUGF(("SkImageDecoder::cropBitmap does not have a large enough bitmap.\n"));
|
||||
}
|
||||
|
||||
// Set the Src_Mode for the paint to prevent transparency issue in the
|
||||
// dest in the event that the dest was being re-used.
|
||||
SkPaint paint;
|
||||
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
|
||||
|
||||
SkCanvas canvas(*dst);
|
||||
canvas.drawBitmap(*src, SkIntToScalar((srcX - dstX) / sampleSize),
|
||||
SkIntToScalar((srcY - dstY) / sampleSize),
|
||||
&paint);
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SkImageDecoder::DecodeFile(const char file[], SkBitmap* bm, SkColorType pref, Mode mode,
|
||||
|
@ -85,154 +85,20 @@ static void initialize_info(jpeg_decompress_struct* cinfo, skjpeg_source_mgr* sr
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SK_JPEG_INDEX_SUPPORTED
|
||||
class SkJPEGImageIndex {
|
||||
public:
|
||||
// Takes ownership of stream.
|
||||
SkJPEGImageIndex(SkStreamRewindable* stream, SkImageDecoder* decoder)
|
||||
: fSrcMgr(stream, decoder)
|
||||
, fStream(stream)
|
||||
, fInfoInitialized(false)
|
||||
, fHuffmanCreated(false)
|
||||
, fDecompressStarted(false)
|
||||
{
|
||||
SkDEBUGCODE(fReadHeaderSucceeded = false;)
|
||||
}
|
||||
|
||||
~SkJPEGImageIndex() {
|
||||
if (fHuffmanCreated) {
|
||||
// Set to false before calling the libjpeg function, in case
|
||||
// the libjpeg function calls longjmp. Our setjmp handler may
|
||||
// attempt to delete this SkJPEGImageIndex, thus entering this
|
||||
// destructor again. Setting fHuffmanCreated to false first
|
||||
// prevents an infinite loop.
|
||||
fHuffmanCreated = false;
|
||||
jpeg_destroy_huffman_index(&fHuffmanIndex);
|
||||
}
|
||||
if (fDecompressStarted) {
|
||||
// Like fHuffmanCreated, set to false before calling libjpeg
|
||||
// function to prevent potential infinite loop.
|
||||
fDecompressStarted = false;
|
||||
jpeg_finish_decompress(&fCInfo);
|
||||
}
|
||||
if (fInfoInitialized) {
|
||||
this->destroyInfo();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the cinfo struct.
|
||||
* After this call, if a huffman index was already built, it
|
||||
* can be used after calling initializeInfoAndReadHeader
|
||||
* again. Must not be called after startTileDecompress except
|
||||
* in the destructor.
|
||||
*/
|
||||
void destroyInfo() {
|
||||
SkASSERT(fInfoInitialized);
|
||||
SkASSERT(!fDecompressStarted);
|
||||
// Like fHuffmanCreated, set to false before calling libjpeg
|
||||
// function to prevent potential infinite loop.
|
||||
fInfoInitialized = false;
|
||||
jpeg_destroy_decompress(&fCInfo);
|
||||
SkDEBUGCODE(fReadHeaderSucceeded = false;)
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the cinfo struct.
|
||||
* Calls jpeg_create_decompress, makes customizations, and
|
||||
* finally calls jpeg_read_header. Returns true if jpeg_read_header
|
||||
* returns JPEG_HEADER_OK.
|
||||
* If cinfo was already initialized, destroyInfo must be called to
|
||||
* destroy the old one. Must not be called after startTileDecompress.
|
||||
*/
|
||||
bool initializeInfoAndReadHeader() {
|
||||
SkASSERT(!fInfoInitialized && !fDecompressStarted);
|
||||
initialize_info(&fCInfo, &fSrcMgr);
|
||||
fInfoInitialized = true;
|
||||
const bool success = (JPEG_HEADER_OK == jpeg_read_header(&fCInfo, true));
|
||||
SkDEBUGCODE(fReadHeaderSucceeded = success;)
|
||||
return success;
|
||||
}
|
||||
|
||||
jpeg_decompress_struct* cinfo() { return &fCInfo; }
|
||||
|
||||
huffman_index* huffmanIndex() { return &fHuffmanIndex; }
|
||||
|
||||
/**
|
||||
* Build the index to be used for tile based decoding.
|
||||
* Must only be called after a successful call to
|
||||
* initializeInfoAndReadHeader and must not be called more
|
||||
* than once.
|
||||
*/
|
||||
bool buildHuffmanIndex() {
|
||||
SkASSERT(fReadHeaderSucceeded);
|
||||
SkASSERT(!fHuffmanCreated);
|
||||
jpeg_create_huffman_index(&fCInfo, &fHuffmanIndex);
|
||||
SkASSERT(1 == fCInfo.scale_num && 1 == fCInfo.scale_denom);
|
||||
fHuffmanCreated = jpeg_build_huffman_index(&fCInfo, &fHuffmanIndex);
|
||||
return fHuffmanCreated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start tile based decoding. Must only be called after a
|
||||
* successful call to buildHuffmanIndex, and must only be
|
||||
* called once.
|
||||
*/
|
||||
bool startTileDecompress() {
|
||||
SkASSERT(fHuffmanCreated);
|
||||
SkASSERT(fReadHeaderSucceeded);
|
||||
SkASSERT(!fDecompressStarted);
|
||||
if (jpeg_start_tile_decompress(&fCInfo)) {
|
||||
fDecompressStarted = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
skjpeg_source_mgr fSrcMgr;
|
||||
SkAutoTDelete<SkStream> fStream;
|
||||
jpeg_decompress_struct fCInfo;
|
||||
huffman_index fHuffmanIndex;
|
||||
bool fInfoInitialized;
|
||||
bool fHuffmanCreated;
|
||||
bool fDecompressStarted;
|
||||
SkDEBUGCODE(bool fReadHeaderSucceeded;)
|
||||
};
|
||||
#endif
|
||||
|
||||
class SkJPEGImageDecoder : public SkImageDecoder {
|
||||
public:
|
||||
#ifdef SK_JPEG_INDEX_SUPPORTED
|
||||
SkJPEGImageDecoder() {
|
||||
fImageIndex = nullptr;
|
||||
fImageWidth = 0;
|
||||
fImageHeight = 0;
|
||||
}
|
||||
|
||||
virtual ~SkJPEGImageDecoder() { delete fImageIndex; }
|
||||
#endif
|
||||
|
||||
Format getFormat() const override {
|
||||
return kJPEG_Format;
|
||||
}
|
||||
|
||||
protected:
|
||||
#ifdef SK_JPEG_INDEX_SUPPORTED
|
||||
bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) override;
|
||||
bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) override;
|
||||
#endif
|
||||
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:
|
||||
#ifdef SK_JPEG_INDEX_SUPPORTED
|
||||
SkJPEGImageIndex* fImageIndex;
|
||||
int fImageWidth;
|
||||
int fImageHeight;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Determine the appropriate bitmap colortype and out_color_space based on
|
||||
@ -295,20 +161,6 @@ static bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer, int count
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef SK_JPEG_INDEX_SUPPORTED
|
||||
static bool skip_src_rows_tile(jpeg_decompress_struct* cinfo,
|
||||
huffman_index *index, void* buffer, int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
JSAMPLE* rowptr = (JSAMPLE*)buffer;
|
||||
int row_count = jpeg_read_tile_scanline(cinfo, index, &rowptr);
|
||||
if (1 != row_count) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This guy exists just to aid in debugging, as it allows debuggers to just
|
||||
@ -329,14 +181,6 @@ static bool return_false(const jpeg_decompress_struct& cinfo,
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef SK_JPEG_INDEX_SUPPORTED
|
||||
static bool return_false(const jpeg_decompress_struct& cinfo,
|
||||
const SkBitmap& bm, const char caller[]) {
|
||||
print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
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);
|
||||
@ -939,240 +783,6 @@ bool SkJPEGImageDecoder::onDecodeYUV8Planes(SkStream* stream, SkISize componentS
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef SK_JPEG_INDEX_SUPPORTED
|
||||
bool SkJPEGImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int *width, int *height) {
|
||||
SkAutoTDelete<SkJPEGImageIndex> imageIndex(new SkJPEGImageIndex(stream, this));
|
||||
|
||||
skjpeg_error_mgr sk_err;
|
||||
set_error_mgr(imageIndex->cinfo(), &sk_err);
|
||||
|
||||
// All objects need to be instantiated before this setjmp call so that
|
||||
// they will be cleaned up properly if an error occurs.
|
||||
if (setjmp(sk_err.fJmpBuf)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// create the cinfo used to create/build the huffmanIndex
|
||||
if (!imageIndex->initializeInfoAndReadHeader()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!imageIndex->buildHuffmanIndex()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// destroy the cinfo used to create/build the huffman index
|
||||
imageIndex->destroyInfo();
|
||||
|
||||
// Init decoder to image decode mode
|
||||
if (!imageIndex->initializeInfoAndReadHeader()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
jpeg_decompress_struct* cinfo = imageIndex->cinfo();
|
||||
// We have a new cinfo, so set the error mgr again.
|
||||
set_error_mgr(cinfo, &sk_err);
|
||||
|
||||
// FIXME: This sets cinfo->out_color_space, which we may change later
|
||||
// based on the config in onDecodeSubset. This should be fine, since
|
||||
// jpeg_init_read_tile_scanline will check out_color_space again after
|
||||
// that change (when it calls jinit_color_deconverter).
|
||||
(void) this->getBitmapColorType(cinfo);
|
||||
|
||||
turn_off_visual_optimizations(cinfo);
|
||||
|
||||
// instead of jpeg_start_decompress() we start a tiled decompress
|
||||
if (!imageIndex->startTileDecompress()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkASSERT(1 == cinfo->scale_num);
|
||||
fImageWidth = cinfo->output_width;
|
||||
fImageHeight = cinfo->output_height;
|
||||
|
||||
if (width) {
|
||||
*width = fImageWidth;
|
||||
}
|
||||
if (height) {
|
||||
*height = fImageHeight;
|
||||
}
|
||||
|
||||
delete fImageIndex;
|
||||
fImageIndex = imageIndex.detach();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) {
|
||||
if (nullptr == fImageIndex) {
|
||||
return false;
|
||||
}
|
||||
jpeg_decompress_struct* cinfo = fImageIndex->cinfo();
|
||||
|
||||
SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight);
|
||||
if (!rect.intersect(region)) {
|
||||
// If the requested region is entirely outside the image return false
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
skjpeg_error_mgr errorManager;
|
||||
set_error_mgr(cinfo, &errorManager);
|
||||
|
||||
if (setjmp(errorManager.fJmpBuf)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int requestedSampleSize = this->getSampleSize();
|
||||
cinfo->scale_denom = requestedSampleSize;
|
||||
|
||||
set_dct_method(*this, cinfo);
|
||||
|
||||
const SkColorType colorType = this->getBitmapColorType(cinfo);
|
||||
adjust_out_color_space_and_dither(cinfo, colorType, *this);
|
||||
|
||||
int startX = rect.fLeft;
|
||||
int startY = rect.fTop;
|
||||
int width = rect.width();
|
||||
int height = rect.height();
|
||||
|
||||
jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(),
|
||||
&startX, &startY, &width, &height);
|
||||
int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo);
|
||||
int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_size);
|
||||
|
||||
SkScaledBitmapSampler sampler(width, height, skiaSampleSize);
|
||||
|
||||
SkBitmap bitmap;
|
||||
// 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.
|
||||
bitmap.setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(), colorType,
|
||||
kAlpha_8_SkColorType == colorType ?
|
||||
kPremul_SkAlphaType : kOpaque_SkAlphaType));
|
||||
|
||||
// Check ahead of time if the swap(dest, src) is possible or not.
|
||||
// If yes, then we will stick to AllocPixelRef since it's cheaper with the
|
||||
// swap happening. If no, then we will use alloc to allocate pixels to
|
||||
// prevent garbage collection.
|
||||
int w = rect.width() / actualSampleSize;
|
||||
int h = rect.height() / actualSampleSize;
|
||||
bool swapOnly = (rect == region) && bm->isNull() &&
|
||||
(w == bitmap.width()) && (h == bitmap.height()) &&
|
||||
((startX - rect.x()) / actualSampleSize == 0) &&
|
||||
((startY - rect.y()) / actualSampleSize == 0);
|
||||
if (swapOnly) {
|
||||
if (!this->allocPixelRef(&bitmap, nullptr)) {
|
||||
return return_false(*cinfo, bitmap, "allocPixelRef");
|
||||
}
|
||||
} else {
|
||||
if (!bitmap.tryAllocPixels()) {
|
||||
return return_false(*cinfo, bitmap, "allocPixels");
|
||||
}
|
||||
}
|
||||
|
||||
SkAutoLockPixels alp(bitmap);
|
||||
|
||||
#ifdef ANDROID_RGB
|
||||
/* short-circuit the SkScaledBitmapSampler when possible, as this gives
|
||||
a significant performance boost.
|
||||
*/
|
||||
if (skiaSampleSize == 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*)bitmap.getPixels();
|
||||
INT32 const bpr = bitmap.rowBytes();
|
||||
int rowTotalCount = 0;
|
||||
|
||||
while (rowTotalCount < height) {
|
||||
int rowCount = jpeg_read_tile_scanline(cinfo,
|
||||
fImageIndex->huffmanIndex(),
|
||||
&rowptr);
|
||||
// if rowCount == 0, then we didn't get a scanline, so abort.
|
||||
// onDecodeSubset() relies on onBuildTileIndex(), which
|
||||
// needs a complete image to succeed.
|
||||
if (0 == rowCount) {
|
||||
return return_false(*cinfo, bitmap, "read_scanlines");
|
||||
}
|
||||
if (this->shouldCancelDecode()) {
|
||||
return return_false(*cinfo, bitmap, "shouldCancelDecode");
|
||||
}
|
||||
rowTotalCount += rowCount;
|
||||
rowptr += bpr;
|
||||
}
|
||||
|
||||
if (swapOnly) {
|
||||
bm->swap(bitmap);
|
||||
return true;
|
||||
}
|
||||
|
||||
return cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(),
|
||||
region.width(), region.height(), startX, startY);
|
||||
}
|
||||
#endif
|
||||
|
||||
// check for supported formats
|
||||
SkScaledBitmapSampler::SrcConfig sc;
|
||||
int srcBytesPerPixel;
|
||||
|
||||
if (!get_src_config(*cinfo, &sc, &srcBytesPerPixel)) {
|
||||
return return_false(*cinfo, *bm, "jpeg colorspace");
|
||||
}
|
||||
|
||||
if (!sampler.begin(&bitmap, sc, *this)) {
|
||||
return return_false(*cinfo, bitmap, "sampler.begin");
|
||||
}
|
||||
|
||||
SkAutoMalloc srcStorage(width * srcBytesPerPixel);
|
||||
uint8_t* srcRow = (uint8_t*)srcStorage.get();
|
||||
|
||||
// Possibly skip initial rows [sampler.srcY0]
|
||||
if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.srcY0())) {
|
||||
return return_false(*cinfo, bitmap, "skip rows");
|
||||
}
|
||||
|
||||
// now loop through scanlines until y == bitmap->height() - 1
|
||||
for (int y = 0;; y++) {
|
||||
JSAMPLE* rowptr = (JSAMPLE*)srcRow;
|
||||
int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), &rowptr);
|
||||
// if row_count == 0, then we didn't get a scanline, so abort.
|
||||
// onDecodeSubset() relies on onBuildTileIndex(), which
|
||||
// needs a complete image to succeed.
|
||||
if (0 == row_count) {
|
||||
return return_false(*cinfo, bitmap, "read_scanlines");
|
||||
}
|
||||
if (this->shouldCancelDecode()) {
|
||||
return return_false(*cinfo, bitmap, "shouldCancelDecode");
|
||||
}
|
||||
|
||||
if (JCS_CMYK == cinfo->out_color_space) {
|
||||
convert_CMYK_to_RGB(srcRow, width);
|
||||
}
|
||||
|
||||
sampler.next(srcRow);
|
||||
if (bitmap.height() - 1 == y) {
|
||||
// we're done
|
||||
break;
|
||||
}
|
||||
|
||||
if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow,
|
||||
sampler.srcDY() - 1)) {
|
||||
return return_false(*cinfo, bitmap, "skip rows");
|
||||
}
|
||||
}
|
||||
if (swapOnly) {
|
||||
bm->swap(bitmap);
|
||||
return true;
|
||||
}
|
||||
return cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(),
|
||||
region.width(), region.height(), startX, startY);
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SkColorPriv.h"
|
||||
|
||||
// taken from jcolor.c in libjpeg
|
||||
|
@ -82,10 +82,6 @@ public:
|
||||
virtual ~SkPNGImageDecoder() { delete fImageIndex; }
|
||||
|
||||
protected:
|
||||
#ifdef SK_PNG_INDEX_SUPPORTED
|
||||
bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) override;
|
||||
bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& region) override;
|
||||
#endif
|
||||
Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override;
|
||||
|
||||
private:
|
||||
@ -126,16 +122,6 @@ static void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SK_PNG_INDEX_SUPPORTED
|
||||
static void sk_seek_fn(png_structp png_ptr, png_uint_32 offset) {
|
||||
SkStreamRewindable* sk_stream = (SkStreamRewindable*) png_get_io_ptr(png_ptr);
|
||||
if (!sk_stream->rewind()) {
|
||||
png_error(png_ptr, "Failed to rewind stream!");
|
||||
}
|
||||
(void)sk_stream->skip(offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
|
||||
static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
|
||||
SkImageDecoder::Peeker* peeker =
|
||||
@ -256,9 +242,6 @@ bool SkPNGImageDecoder::onDecodeInit(SkStream* sk_stream, png_structp *png_ptrp,
|
||||
* png_init_io() here you would call:
|
||||
*/
|
||||
png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn);
|
||||
#ifdef SK_PNG_INDEX_SUPPORTED
|
||||
png_set_seek_fn(png_ptr, sk_seek_fn);
|
||||
#endif
|
||||
/* 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 */ );
|
||||
@ -720,267 +703,6 @@ bool SkPNGImageDecoder::decodePalette(png_structp png_ptr, png_infop info_ptr,
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef SK_PNG_INDEX_SUPPORTED
|
||||
|
||||
bool SkPNGImageDecoder::onBuildTileIndex(SkStreamRewindable* sk_stream, int *width, int *height) {
|
||||
SkAutoTDelete<SkStreamRewindable> streamDeleter(sk_stream);
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
|
||||
if (!onDecodeInit(sk_stream, &png_ptr, &info_ptr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr)) != 0) {
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
*width = origWidth;
|
||||
*height = origHeight;
|
||||
|
||||
png_build_index(png_ptr);
|
||||
|
||||
if (fImageIndex) {
|
||||
delete fImageIndex;
|
||||
}
|
||||
fImageIndex = new SkPNGImageIndex(streamDeleter.detach(), png_ptr, info_ptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkPNGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) {
|
||||
if (nullptr == fImageIndex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
png_structp png_ptr = fImageIndex->fPng_ptr;
|
||||
png_infop info_ptr = fImageIndex->fInfo_ptr;
|
||||
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
SkIRect rect = SkIRect::MakeWH(origWidth, origHeight);
|
||||
|
||||
if (!rect.intersect(region)) {
|
||||
// If the requested region is entirely outside the image, just
|
||||
// returns false
|
||||
return false;
|
||||
}
|
||||
|
||||
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 false;
|
||||
}
|
||||
|
||||
const int sampleSize = this->getSampleSize();
|
||||
SkScaledBitmapSampler sampler(origWidth, rect.height(), sampleSize);
|
||||
|
||||
SkBitmap decodedBitmap;
|
||||
decodedBitmap.setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(),
|
||||
colorType, kPremul_SkAlphaType));
|
||||
|
||||
// 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);
|
||||
|
||||
// Check ahead of time if the swap(dest, src) is possible.
|
||||
// If yes, then we will stick to AllocPixelRef since it's cheaper with the swap happening.
|
||||
// If no, then we will use alloc to allocate pixels to prevent garbage collection.
|
||||
int w = rect.width() / sampleSize;
|
||||
int h = rect.height() / sampleSize;
|
||||
const bool swapOnly = (rect == region) && (w == decodedBitmap.width()) &&
|
||||
(h == decodedBitmap.height()) && bm->isNull();
|
||||
const bool needColorTable = kIndex_8_SkColorType == colorType;
|
||||
if (swapOnly) {
|
||||
if (!this->allocPixelRef(&decodedBitmap, needColorTable ? colorTable : nullptr)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!decodedBitmap.tryAllocPixels(nullptr, needColorTable ? colorTable : nullptr)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
SkAutoLockPixels alp(decodedBitmap);
|
||||
|
||||
/* 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).
|
||||
*/
|
||||
|
||||
// Direct access to png_ptr fields is deprecated in libpng > 1.2.
|
||||
#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
|
||||
png_ptr->pass = 0;
|
||||
#else
|
||||
// FIXME: This sets pass as desired, but also sets iwidth. Is that ok?
|
||||
png_set_interlaced_pass(png_ptr, 0);
|
||||
#endif
|
||||
png_read_update_info(png_ptr, info_ptr);
|
||||
|
||||
int actualTop = rect.fTop;
|
||||
|
||||
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++) {
|
||||
png_configure_decoder(png_ptr, &actualTop, i);
|
||||
for (int j = 0; j < rect.fTop - actualTop; j++) {
|
||||
uint8_t* bmRow = decodedBitmap.getAddr8(0, 0);
|
||||
png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
|
||||
}
|
||||
png_uint_32 bitmapHeight = (png_uint_32) decodedBitmap.height();
|
||||
for (png_uint_32 y = 0; y < bitmapHeight; 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 false;
|
||||
}
|
||||
const int height = decodedBitmap.height();
|
||||
|
||||
if (number_passes > 1) {
|
||||
SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel);
|
||||
uint8_t* base = (uint8_t*)storage.get();
|
||||
size_t rb = origWidth * srcBytesPerPixel;
|
||||
|
||||
for (int i = 0; i < number_passes; i++) {
|
||||
png_configure_decoder(png_ptr, &actualTop, i);
|
||||
for (int j = 0; j < rect.fTop - actualTop; j++) {
|
||||
png_read_rows(png_ptr, &base, png_bytepp_NULL, 1);
|
||||
}
|
||||
uint8_t* row = base;
|
||||
for (int32_t y = 0; y < rect.height(); y++) {
|
||||
uint8_t* bmRow = row;
|
||||
png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
|
||||
row += rb;
|
||||
}
|
||||
}
|
||||
// now sample it
|
||||
base += sampler.srcY0() * rb;
|
||||
for (int y = 0; y < height; y++) {
|
||||
reallyHasAlpha |= sampler.next(base);
|
||||
base += sampler.srcDY() * rb;
|
||||
}
|
||||
} else {
|
||||
SkAutoMalloc storage(origWidth * srcBytesPerPixel);
|
||||
uint8_t* srcRow = (uint8_t*)storage.get();
|
||||
|
||||
png_configure_decoder(png_ptr, &actualTop, 0);
|
||||
skip_src_rows(png_ptr, srcRow, sampler.srcY0());
|
||||
|
||||
for (int i = 0; i < rect.fTop - actualTop; i++) {
|
||||
png_read_rows(png_ptr, &srcRow, png_bytepp_NULL, 1);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 colortypess.
|
||||
return false;
|
||||
default: {
|
||||
// Fall through to finish the decode. This config either
|
||||
// supports unpremul or it is irrelevant because it has no
|
||||
// alpha (or only alpha).
|
||||
// These brackets prevent a warning.
|
||||
}
|
||||
}
|
||||
}
|
||||
SkAlphaType alphaType = kOpaque_SkAlphaType;
|
||||
if (reallyHasAlpha) {
|
||||
if (this->getRequireUnpremultipliedColors()) {
|
||||
alphaType = kUnpremul_SkAlphaType;
|
||||
} else {
|
||||
alphaType = kPremul_SkAlphaType;
|
||||
}
|
||||
}
|
||||
decodedBitmap.setAlphaType(alphaType);
|
||||
|
||||
if (swapOnly) {
|
||||
bm->swap(decodedBitmap);
|
||||
return true;
|
||||
}
|
||||
return this->cropBitmap(bm, &decodedBitmap, sampleSize, region.x(), region.y(),
|
||||
region.width(), region.height(), 0, rect.y());
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SkColorPriv.h"
|
||||
|
@ -103,8 +103,6 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) override;
|
||||
bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) override;
|
||||
Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override;
|
||||
|
||||
private:
|
||||
@ -160,11 +158,6 @@ static void print_webp_error(const SkBitmap& bm, const char msg[]) {
|
||||
SkDEBUGF(("libwebp error %s [%d %d]", msg, bm.width(), bm.height()));
|
||||
}
|
||||
|
||||
static bool return_false(const SkBitmap& bm, const char msg[]) {
|
||||
print_webp_error(bm, msg);
|
||||
return false; // must always return false
|
||||
}
|
||||
|
||||
static SkImageDecoder::Result return_failure(const SkBitmap& bm, const char msg[]) {
|
||||
print_webp_error(bm, msg);
|
||||
return SkImageDecoder::kFailure; // must always return kFailure
|
||||
@ -265,24 +258,6 @@ static bool webp_get_config_resize(WebPDecoderConfig* config,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool webp_get_config_resize_crop(WebPDecoderConfig* config,
|
||||
SkBitmap* decodedBitmap,
|
||||
const SkIRect& region, bool premultiply) {
|
||||
|
||||
if (!webp_get_config_resize(config, decodedBitmap, region.width(),
|
||||
region.height(), premultiply)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config->options.use_cropping = 1;
|
||||
config->options.crop_left = region.fLeft;
|
||||
config->options.crop_top = region.fTop;
|
||||
config->options.crop_width = region.width();
|
||||
config->options.crop_height = region.height();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkWEBPImageDecoder::setDecodeConfig(SkBitmap* decodedBitmap, int width, int height) {
|
||||
SkColorType colorType = this->getPrefColorType(k32Bit_SrcDepth, SkToBool(fHasAlpha));
|
||||
|
||||
@ -308,99 +283,6 @@ bool SkWEBPImageDecoder::setDecodeConfig(SkBitmap* decodedBitmap, int width, int
|
||||
return decodedBitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType));
|
||||
}
|
||||
|
||||
bool SkWEBPImageDecoder::onBuildTileIndex(SkStreamRewindable* stream,
|
||||
int *width, int *height) {
|
||||
SkAutoTDelete<SkStreamRewindable> streamDeleter(stream);
|
||||
int origWidth, origHeight, hasAlpha;
|
||||
if (!webp_parse_header(stream, &origWidth, &origHeight, &hasAlpha)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!stream->rewind()) {
|
||||
SkDebugf("Failed to rewind webp stream!");
|
||||
return false;
|
||||
}
|
||||
|
||||
*width = origWidth;
|
||||
*height = origHeight;
|
||||
|
||||
this->fInputStream.reset(streamDeleter.detach());
|
||||
this->fOrigWidth = origWidth;
|
||||
this->fOrigHeight = origHeight;
|
||||
this->fHasAlpha = hasAlpha;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool is_config_compatible(const SkBitmap& bitmap) {
|
||||
const SkColorType ct = bitmap.colorType();
|
||||
return ct == kARGB_4444_SkColorType || ct == kRGB_565_SkColorType || ct == kN32_SkColorType;
|
||||
}
|
||||
|
||||
bool SkWEBPImageDecoder::onDecodeSubset(SkBitmap* decodedBitmap,
|
||||
const SkIRect& region) {
|
||||
SkIRect rect = SkIRect::MakeWH(fOrigWidth, fOrigHeight);
|
||||
|
||||
if (!rect.intersect(region)) {
|
||||
// If the requested region is entirely outsides the image, return false
|
||||
return false;
|
||||
}
|
||||
|
||||
const int sampleSize = this->getSampleSize();
|
||||
SkScaledBitmapSampler sampler(rect.width(), rect.height(), sampleSize);
|
||||
const int width = sampler.scaledWidth();
|
||||
const int height = sampler.scaledHeight();
|
||||
|
||||
// The image can be decoded directly to decodedBitmap if
|
||||
// 1. the region is within the image range
|
||||
// 2. bitmap's config is compatible
|
||||
// 3. bitmap's size is same as the required region (after sampled)
|
||||
bool directDecode = (rect == region) &&
|
||||
(decodedBitmap->isNull() ||
|
||||
(is_config_compatible(*decodedBitmap) &&
|
||||
(decodedBitmap->width() == width) &&
|
||||
(decodedBitmap->height() == height)));
|
||||
|
||||
SkBitmap tmpBitmap;
|
||||
SkBitmap *bitmap = decodedBitmap;
|
||||
|
||||
if (!directDecode) {
|
||||
bitmap = &tmpBitmap;
|
||||
}
|
||||
|
||||
if (bitmap->isNull()) {
|
||||
if (!setDecodeConfig(bitmap, width, height)) {
|
||||
return false;
|
||||
}
|
||||
// alloc from native heap if it is a temp bitmap. (prevent GC)
|
||||
bool allocResult = (bitmap == decodedBitmap)
|
||||
? allocPixelRef(bitmap, nullptr)
|
||||
: bitmap->tryAllocPixels();
|
||||
if (!allocResult) {
|
||||
return return_false(*decodedBitmap, "allocPixelRef");
|
||||
}
|
||||
}
|
||||
|
||||
SkAutoLockPixels alp(*bitmap);
|
||||
WebPDecoderConfig config;
|
||||
if (!webp_get_config_resize_crop(&config, bitmap, rect,
|
||||
this->shouldPremultiply())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Decode the WebP image data stream using WebP incremental decoding for
|
||||
// the specified cropped image-region.
|
||||
if (!webp_idecode(this->fInputStream, &config)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!directDecode) {
|
||||
return cropBitmap(decodedBitmap, bitmap, sampleSize, region.x(), region.y(),
|
||||
region.width(), region.height(), rect.x(), rect.y());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SkImageDecoder::Result SkWEBPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
|
||||
Mode mode) {
|
||||
#ifdef TIME_DECODE
|
||||
|
@ -43,21 +43,6 @@ bool SkImageDecoder::DecodeMemory(const void*, size_t, SkBitmap*, SkColorType, M
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkImageDecoder::buildTileIndex(SkStreamRewindable*, int *width, int *height) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkImageDecoder::onBuildTileIndex(SkStreamRewindable* stream,
|
||||
int* /*width*/, int* /*height*/) {
|
||||
delete stream;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SkImageDecoder::decodeSubset(SkBitmap*, const SkIRect&, SkColorType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkImageDecoder::Format SkImageDecoder::getFormat() const {
|
||||
return kUnknown_Format;
|
||||
}
|
||||
@ -80,11 +65,6 @@ SkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator*) {
|
||||
|
||||
void SkImageDecoder::setSampleSize(int) {}
|
||||
|
||||
bool SkImageDecoder::cropBitmap(SkBitmap*, SkBitmap*, int, int, int, int, int,
|
||||
int, int) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkImageDecoder::allocPixelRef(SkBitmap*, SkColorTable*) const {
|
||||
return false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user