Do JPEG tile-based decoding.
Change-Id: I795129d55a0a7da90b4d604a902066868933d2a9
diff --git a/Android.mk b/Android.mk
index a63a0f1..6f8162c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -78,6 +78,7 @@
src/images/SkImageRef_GlobalPool.cpp \
src/images/SkImageRefPool.cpp \
src/images/SkJpegUtility.cpp \
+ src/images/SkLargeBitmap.cpp \
src/images/SkMovie.cpp \
src/images/SkMovie_gif.cpp \
src/images/SkPageFlipper.cpp \
diff --git a/include/images/SkImageDecoder.h b/include/images/SkImageDecoder.h
index f8a941f..be1046b 100644
--- a/include/images/SkImageDecoder.h
+++ b/include/images/SkImageDecoder.h
@@ -18,10 +18,17 @@
#define SkImageDecoder_DEFINED
#include "SkBitmap.h"
+#include "SkRect.h"
#include "SkRefCnt.h"
class SkStream;
+class SkVMMemoryReporter : public SkRefCnt {
+public:
+ virtual ~SkVMMemoryReporter() {}
+ virtual bool reportMemory(size_t memorySize);
+};
+
/** \class SkImageDecoder
Base class for decoding compressed images into a SkBitmap
@@ -30,6 +37,7 @@
public:
virtual ~SkImageDecoder();
+ // Should be consistent with kFormatName
enum Format {
kUnknown_Format,
kBMP_Format,
@@ -42,10 +50,21 @@
kLastKnownFormat = kWBMP_Format
};
+ /** Contains the image format name.
+ * This should be consistent with Format.
+ *
+ * The format name gives a more meaningful error message than enum.
+ */
+ static const char *kFormatName[7];
+
/** Return the compressed data's format (see Format enum)
*/
virtual Format getFormat() const;
+ /** Return the compressed data's format name.
+ */
+ const char* getFormatName() const { return kFormatName[getFormat()]; }
+
/** Returns true if the decoder should try to dither the resulting image.
The default setting is true.
*/
@@ -118,6 +137,7 @@
SkBitmap::Allocator* getAllocator() const { return fAllocator; }
SkBitmap::Allocator* setAllocator(SkBitmap::Allocator*);
+ SkVMMemoryReporter* setReporter(SkVMMemoryReporter*);
// sample-size, if set to > 1, tells the decoder to return a smaller than
// original bitmap, sampling 1 pixel for every size pixels. e.g. if sample
@@ -176,6 +196,29 @@
return this->decode(stream, bitmap, SkBitmap::kNo_Config, 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.
+ *
+ * Return true for success or false on failure.
+ */
+ virtual bool buildTileIndex(SkStream*,
+ int *width, int *height, bool isShareable) {
+ return false;
+ }
+
+ /**
+ * Decode a rectangle region in the image specified by rect.
+ * The method can only be called after buildTileIndex().
+ *
+ * Return true for success.
+ * Return false if the index is never built or failing in decoding.
+ */
+ virtual bool decodeRegion(SkBitmap* bitmap, SkIRect rect,
+ SkBitmap::Config pref);
+
+
/** Given a stream, this will try to find an appropriate decoder object.
If none is found, the method returns NULL.
*/
@@ -264,6 +307,11 @@
// must be overridden in subclasses. This guy is called by decode(...)
virtual bool onDecode(SkStream*, SkBitmap* bitmap, Mode) = 0;
+ // must be overridden in subclasses. This guy is called by decodeRegion(...)
+ virtual bool onDecodeRegion(SkBitmap* bitmap, SkIRect rect) {
+ return false;
+ }
+
/** Can be queried from within onDecode, to see if the user (possibly in
a different thread) has requested the decode to cancel. If this returns
true, your onDecode() should stop and return false.
@@ -304,6 +352,8 @@
*/
SkBitmap::Config getPrefConfig(SrcDepth, bool hasAlpha) const;
+ SkVMMemoryReporter* fReporter;
+
private:
Peeker* fPeeker;
Chooser* fChooser;
diff --git a/include/images/SkJpegUtility.h b/include/images/SkJpegUtility.h
index cc9d246..5dd789c9 100644
--- a/include/images/SkJpegUtility.h
+++ b/include/images/SkJpegUtility.h
@@ -41,11 +41,13 @@
/* Our source struct for directing jpeg to our stream object.
*/
struct skjpeg_source_mgr : jpeg_source_mgr {
- skjpeg_source_mgr(SkStream* stream, SkImageDecoder* decoder);
+ skjpeg_source_mgr(SkStream* stream, SkImageDecoder* decoder, bool copyStream, bool ownStream);
+ ~skjpeg_source_mgr();
SkStream* fStream;
- const void* fMemoryBase;
+ void* fMemoryBase;
size_t fMemoryBaseSize;
+ bool fUnrefStream;
SkImageDecoder* fDecoder;
enum {
kBufferSize = 1024
diff --git a/include/images/SkLargeBitmap.h b/include/images/SkLargeBitmap.h
new file mode 100644
index 0000000..0d19f32
--- /dev/null
+++ b/include/images/SkLargeBitmap.h
@@ -0,0 +1,33 @@
+#ifndef SkLargeBitmap_DEFINED
+#define SkLargeBitmap_DEFINED
+
+#include "SkBitmap.h"
+#include "SkRect.h"
+#include "SkImageDecoder.h"
+
+class SkLargeBitmap {
+public:
+ SkLargeBitmap(SkImageDecoder *decoder, int width, int height) {
+ fDecoder = decoder;
+ fWidth = width;
+ fHeight = height;
+ }
+ virtual ~SkLargeBitmap() {
+ delete fDecoder;
+ }
+
+ virtual bool decodeRegion(SkBitmap* bitmap, SkIRect rect,
+ SkBitmap::Config pref, int sampleSize);
+
+ virtual int getWidth() { return fWidth; }
+ virtual int getHeight() { return fHeight; }
+
+ virtual SkImageDecoder* getDecoder() { return fDecoder; }
+
+private:
+ SkImageDecoder *fDecoder;
+ int fWidth;
+ int fHeight;
+};
+
+#endif
diff --git a/src/images/SkImageDecoder.cpp b/src/images/SkImageDecoder.cpp
index 768d671..5191117 100644
--- a/src/images/SkImageDecoder.cpp
+++ b/src/images/SkImageDecoder.cpp
@@ -20,6 +20,17 @@
#include "SkPixelRef.h"
#include "SkStream.h"
#include "SkTemplates.h"
+#include "SkCanvas.h"
+
+const char *SkImageDecoder::kFormatName[] = {
+ "Unknown Format",
+ "BMP",
+ "GIF",
+ "ICO",
+ "JPEG",
+ "PNG",
+ "WBMP",
+};
static SkBitmap::Config gDeviceConfig = SkBitmap::kNo_Config;
@@ -36,8 +47,8 @@
///////////////////////////////////////////////////////////////////////////////
SkImageDecoder::SkImageDecoder()
- : fPeeker(NULL), fChooser(NULL), fAllocator(NULL), fSampleSize(1),
- fDefaultPref(SkBitmap::kNo_Config), fDitherImage(true),
+ : fReporter(NULL), fPeeker(NULL), fChooser(NULL), fAllocator(NULL),
+ fSampleSize(1), fDefaultPref(SkBitmap::kNo_Config), fDitherImage(true),
fUsePrefTable(false) {
}
@@ -45,6 +56,7 @@
fPeeker->safeUnref();
fChooser->safeUnref();
fAllocator->safeUnref();
+ fReporter->safeUnref();
}
SkImageDecoder::Format SkImageDecoder::getFormat() const {
@@ -66,6 +78,11 @@
return alloc;
}
+SkVMMemoryReporter* SkImageDecoder::setReporter(SkVMMemoryReporter* reporter) {
+ SkRefCnt_SafeAssign(fReporter, reporter);
+ return reporter;
+}
+
void SkImageDecoder::setSampleSize(int size) {
if (size < 1) {
size = 1;
@@ -150,6 +167,24 @@
return true;
}
+bool SkImageDecoder::decodeRegion(SkBitmap* bm, SkIRect rect,
+ SkBitmap::Config pref) {
+ // pass a temporary bitmap, so that if we return false, we are assured of
+ // leaving the caller's bitmap untouched.
+ SkBitmap tmp;
+
+ // we reset this to false before calling onDecodeRegion
+ fShouldCancelDecode = false;
+ // assign this, for use by getPrefConfig(), in case fUsePrefTable is false
+ fDefaultPref = pref;
+
+ if (!this->onDecodeRegion(&tmp, rect)) {
+ return false;
+ }
+ bm->swap(tmp);
+ return true;
+}
+
///////////////////////////////////////////////////////////////////////////////
bool SkImageDecoder::DecodeFile(const char file[], SkBitmap* bm,
diff --git a/src/images/SkImageDecoder_libjpeg.cpp b/src/images/SkImageDecoder_libjpeg.cpp
index ed523bb..2318a37 100644
--- a/src/images/SkImageDecoder_libjpeg.cpp
+++ b/src/images/SkImageDecoder_libjpeg.cpp
@@ -23,6 +23,8 @@
#include "SkStream.h"
#include "SkTemplates.h"
#include "SkUtils.h"
+#include "SkRect.h"
+#include "SkCanvas.h"
#include <stdio.h>
extern "C" {
@@ -48,14 +50,44 @@
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
+class SkJPEGImageIndex {
+public:
+ SkJPEGImageIndex() {}
+ virtual ~SkJPEGImageIndex() {
+ jpeg_destroy_huffman_index(index);
+ delete cinfo->src;
+ jpeg_finish_decompress(cinfo);
+ jpeg_destroy_decompress(cinfo);
+ free(cinfo);
+ }
+ jpeg_decompress_struct *cinfo;
+ huffman_index *index;
+};
+
+
class SkJPEGImageDecoder : public SkImageDecoder {
public:
+ SkJPEGImageDecoder() {
+ index = NULL;
+ }
+ ~SkJPEGImageDecoder() {
+ if (index)
+ delete index;
+ }
virtual Format getFormat() const {
return kJPEG_Format;
}
+ virtual bool buildTileIndex(SkStream *stream,
+ int *width, int *height, bool isShareable);
protected:
+ virtual bool onDecodeRegion(SkBitmap* bitmap, SkIRect rect);
virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
+ virtual void cropBitmap(SkBitmap *dest, SkBitmap *src, int sampleSize,
+ int srcX, int srcY, int width, int height,
+ int destX, int destY);
+private:
+ SkJPEGImageIndex *index;
};
//////////////////////////////////////////////////////////////////////////
@@ -141,6 +173,21 @@
return true;
}
+static bool skip_src_rows_tile(jpeg_decompress_struct* cinfo,
+ huffman_index *index, void* buffer,
+ int startX, int startY, int width, int height,
+ int count) {
+ for (int i = 0; i < count; i++) {
+ JSAMPLE* rowptr = (JSAMPLE*)buffer;
+ int row_count = jpeg_read_tile_scanline(cinfo, index, &rowptr,
+ startX, startY, width, height);
+ if (row_count != 1) {
+ 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 bool return_false(const jpeg_decompress_struct& cinfo,
@@ -163,7 +210,7 @@
jpeg_decompress_struct cinfo;
skjpeg_error_mgr sk_err;
- skjpeg_source_mgr sk_stream(stream, this);
+ skjpeg_source_mgr sk_stream(stream, this, false, false);
cinfo.err = jpeg_std_error(&sk_err);
sk_err.error_exit = skjpeg_error_exit;
@@ -388,6 +435,278 @@
return true;
}
+bool SkJPEGImageDecoder::buildTileIndex(SkStream* stream,
+ int *width, int *height,
+ bool isShareable) {
+ SkAutoMalloc srcStorage;
+ SkJPEGImageIndex *index = new SkJPEGImageIndex;
+
+ jpeg_decompress_struct *cinfo = (jpeg_decompress_struct*)
+ malloc(sizeof(jpeg_decompress_struct));
+ skjpeg_error_mgr sk_err;
+ skjpeg_source_mgr *sk_stream =
+ new skjpeg_source_mgr(stream, this, !isShareable, true);
+ if (cinfo == NULL || sk_stream == NULL) {
+ return false;
+ }
+
+ cinfo->err = jpeg_std_error(&sk_err);
+ sk_err.error_exit = skjpeg_error_exit;
+
+ // 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;
+ }
+
+ jpeg_create_decompress(cinfo);
+ cinfo->do_fancy_upsampling = 0;
+ cinfo->do_block_smoothing = 0;
+
+#ifdef ANDROID
+ overwrite_mem_buffer_size(cinfo);
+#endif
+
+ cinfo->src = sk_stream;
+ int status = jpeg_read_header(cinfo, true);
+ if (status != JPEG_HEADER_OK) {
+ return false;
+ }
+ index->index = (huffman_index*)malloc(sizeof(huffman_index));
+ jpeg_create_huffman_index(cinfo, index->index);
+
+ cinfo->dct_method = JDCT_IFAST;
+ cinfo->scale_num = 1;
+ cinfo->scale_denom = 1;
+ if (!jpeg_build_huffman_index(cinfo, index->index)) {
+ return false;
+ }
+ if (fReporter)
+ fReporter->reportMemory(index->index->mem_used);
+ jpeg_destroy_decompress(cinfo);
+
+
+ // Init decoder to image decode mode
+ jpeg_create_decompress(cinfo);
+
+#ifdef ANDROID
+ overwrite_mem_buffer_size(cinfo);
+#endif
+
+ cinfo->src = sk_stream;
+ status = jpeg_read_header(cinfo,true);
+ if (status != JPEG_HEADER_OK) {
+ return false;
+ }
+ cinfo->out_color_space = JCS_RGBA_8888;
+ cinfo->do_fancy_upsampling = 0;
+ cinfo->do_block_smoothing = 0;
+ //jpeg_start_decompress(cinfo);
+ jpeg_start_tile_decompress(cinfo);
+
+ cinfo->dct_method = JDCT_IFAST;
+ cinfo->scale_num = 1;
+ index->cinfo = cinfo;
+ *height = cinfo->output_height;
+ *width = cinfo->output_width;
+
+ this->index = index;
+ return true;
+}
+
+/*
+ * Crop a rectangle from the src Bitmap to the dest Bitmap. src and dest are
+ * both sampled by sampleSize from an original Bitmap.
+ *
+ * @param dest 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 (srcX, srcY) the upper-left point of the src Btimap in terms of
+ * the coordinate in the original Bitmap.
+ * @param (width, height) the width and height of the unsampled dest.
+ * @param (destX, destY) the upper-left point of the dest Bitmap in terms of
+ * the coordinate in the original Bitmap.
+ */
+void SkJPEGImageDecoder::cropBitmap(SkBitmap *dest, SkBitmap *src,
+ int sampleSize, int srcX, int srcY,
+ int width, int height, int destX, int destY)
+{
+ int w = width / sampleSize;
+ int h = height / sampleSize;
+ if (w == src->width() && h == src->height() &&
+ (destX - srcX) / sampleSize == 0 && (destY - srcY) / sampleSize == 0) {
+ // The output rect is the same as the decode result
+ dest->swap( *src );
+ return;
+ }
+ dest->setConfig(src->getConfig(), w, h);
+ dest->setIsOpaque(true);
+ this->allocPixelRef(dest, NULL);
+
+ SkCanvas canvas(*dest);
+ canvas.drawBitmap(*src, (destX - srcX) / sampleSize,
+ (destY - srcY) / sampleSize);
+}
+
+bool SkJPEGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect region) {
+ if (index == NULL) {
+ return false;
+ }
+ int startX = region.fLeft;
+ int startY = region.fTop;
+ int width = region.width();
+ int height = region.height();
+ jpeg_decompress_struct *cinfo = index->cinfo;
+ SkAutoMalloc srcStorage;
+ skjpeg_error_mgr sk_err;
+ cinfo->err = jpeg_std_error(&sk_err);
+ sk_err.error_exit = skjpeg_error_exit;
+ if (setjmp(sk_err.fJmpBuf)) {
+ return false;
+ }
+ int requestedSampleSize = this->getSampleSize();
+ cinfo->scale_denom = requestedSampleSize;
+
+ SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false);
+ if (config != SkBitmap::kARGB_8888_Config &&
+ config != SkBitmap::kARGB_4444_Config &&
+ config != SkBitmap::kRGB_565_Config) {
+ config = SkBitmap::kARGB_8888_Config;
+ }
+#ifdef ANDROID_RGB
+ cinfo->dither_mode = JDITHER_NONE;
+ if (config == SkBitmap::kARGB_8888_Config) {
+ cinfo->out_color_space = JCS_RGBA_8888;
+ } else if (config == SkBitmap::kRGB_565_Config) {
+ if (requestedSampleSize == 1) {
+ // SkScaledBitmapSampler can't handle RGB_565 yet,
+ // so don't even try.
+ cinfo->out_color_space = JCS_RGB_565;
+ if (this->getDitherImage()) {
+ cinfo->dither_mode = JDITHER_ORDERED;
+ }
+ }
+ }
+#endif
+
+ int oriStartX = startX;
+ int oriStartY = startY;
+ int oriWidth = width;
+ int oriHeight = height;
+ jpeg_init_read_tile_scanline(cinfo, index->index,
+ &startX, &startY, &width, &height);
+ int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo);
+ SkBitmap *bitmap = new SkBitmap;
+ SkAutoTDelete<SkBitmap> adb(bitmap);
+
+ int actualSampleSize = skiaSampleSize * cinfo->image_width / cinfo->output_width;
+
+#ifdef ANDROID_RGB
+ /* short-circuit the SkScaledBitmapSampler when possible, as this gives
+ a significant performance boost.
+ */
+ if (skiaSampleSize == 1 &&
+ ((config == SkBitmap::kARGB_8888_Config &&
+ cinfo->out_color_space == JCS_RGBA_8888) ||
+ (config == SkBitmap::kRGB_565_Config &&
+ cinfo->out_color_space == JCS_RGB_565)))
+ {
+ bitmap->setConfig(config, cinfo->output_width, height);
+ bitmap->setIsOpaque(true);
+ if (!this->allocPixelRef(bitmap, NULL)) {
+ return return_false(*cinfo, *bitmap, "allocPixelRef");
+ }
+ SkAutoLockPixels alp(*bitmap);
+ JSAMPLE* rowptr = (JSAMPLE*)bitmap->getPixels();
+ INT32 const bpr = bitmap->rowBytes();
+ int row_total_count = 0;
+
+ while (row_total_count < height) {
+ int row_count = jpeg_read_tile_scanline(cinfo,
+ index->index, &rowptr, startX, startY, width, height);
+ // if row_count == 0, then we didn't get a scanline, so abort.
+ // if we supported partial images, we might return true in this case
+ if (0 == row_count) {
+ return return_false(*cinfo, *bitmap, "read_scanlines");
+ }
+ if (this->shouldCancelDecode()) {
+ return return_false(*cinfo, *bitmap, "shouldCancelDecode");
+ }
+ row_total_count += row_count;
+ rowptr += bpr;
+ }
+ cropBitmap(bm, bitmap, actualSampleSize, oriStartX, oriStartY,
+ oriWidth, oriHeight, startX, startY);
+ return true;
+ }
+#endif
+ // check for supported formats
+ SkScaledBitmapSampler::SrcConfig sc;
+ if (3 == cinfo->out_color_components && JCS_RGB == cinfo->out_color_space) {
+ sc = SkScaledBitmapSampler::kRGB;
+#ifdef ANDROID_RGB
+ } else if (JCS_RGBA_8888 == cinfo->out_color_space) {
+ sc = SkScaledBitmapSampler::kRGBX;
+#endif
+ } else if (1 == cinfo->out_color_components &&
+ JCS_GRAYSCALE == cinfo->out_color_space) {
+ sc = SkScaledBitmapSampler::kGray;
+ } else {
+ return return_false(*cinfo, *bm, "jpeg colorspace");
+ }
+
+ SkScaledBitmapSampler sampler(width, height, skiaSampleSize);
+
+ bitmap->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
+ bitmap->setIsOpaque(true);
+
+ if (!this->allocPixelRef(bitmap, NULL)) {
+ return return_false(*cinfo, *bitmap, "allocPixelRef");
+ }
+
+ SkAutoLockPixels alp(*bitmap);
+ if (!sampler.begin(bitmap, sc, this->getDitherImage())) {
+ return return_false(*cinfo, *bitmap, "sampler.begin");
+ }
+
+ uint8_t* srcRow = (uint8_t*)srcStorage.alloc(width * 4);
+
+ // Possibly skip initial rows [sampler.srcY0]
+ if (!skip_src_rows_tile(cinfo, index->index, srcRow,
+ startX, startY, width, height, 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, index->index, &rowptr,
+ startX, startY, width, height);
+ if (0 == row_count) {
+ return return_false(*cinfo, *bitmap, "read_scanlines");
+ }
+ if (this->shouldCancelDecode()) {
+ return return_false(*cinfo, *bitmap, "shouldCancelDecode");
+ }
+
+ sampler.next(srcRow);
+ if (bitmap->height() - 1 == y) {
+ // we're done
+ break;
+ }
+
+ if (!skip_src_rows_tile(cinfo, index->index, srcRow,
+ startX, startY, width, height,
+ sampler.srcDY() - 1)) {
+ return return_false(*cinfo, *bitmap, "skip rows");
+ }
+ }
+ cropBitmap(bm, bitmap, actualSampleSize, oriStartX, oriStartY,
+ oriWidth, oriHeight, startX, startY);
+ return true;
+}
+
///////////////////////////////////////////////////////////////////////////////
#include "SkColorPriv.h"
diff --git a/src/images/SkJpegUtility.cpp b/src/images/SkJpegUtility.cpp
index e207592..aaf87db 100644
--- a/src/images/SkJpegUtility.cpp
+++ b/src/images/SkJpegUtility.cpp
@@ -21,6 +21,24 @@
skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src;
src->next_input_byte = (const JOCTET*)src->fBuffer;
src->bytes_in_buffer = 0;
+ src->current_offset = 0;
+ src->fStream->rewind();
+}
+
+static boolean sk_seek_input_data(j_decompress_ptr cinfo, long byte_offset) {
+ skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src;
+
+ if (byte_offset > src->current_offset) {
+ (void)src->fStream->skip(byte_offset - src->current_offset);
+ } else {
+ src->fStream->rewind();
+ (void)src->fStream->skip(byte_offset);
+ }
+
+ src->current_offset = byte_offset;
+ src->next_input_byte = (const JOCTET*)src->fBuffer;
+ src->bytes_in_buffer = 0;
+ return TRUE;
}
static boolean sk_fill_input_buffer(j_decompress_ptr cinfo) {
@@ -35,6 +53,7 @@
return FALSE;
}
+ src->current_offset += bytes;
src->next_input_byte = (const JOCTET*)src->fBuffer;
src->bytes_in_buffer = bytes;
return TRUE;
@@ -52,6 +71,7 @@
cinfo->err->error_exit((j_common_ptr)cinfo);
return;
}
+ src->current_offset += bytes;
bytesToSkip -= bytes;
}
src->next_input_byte = (const JOCTET*)src->fBuffer;
@@ -83,7 +103,9 @@
static void skmem_init_source(j_decompress_ptr cinfo) {
skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src;
src->next_input_byte = (const JOCTET*)src->fMemoryBase;
+ src->start_input_byte = (const JOCTET*)src->fMemoryBase;
src->bytes_in_buffer = src->fMemoryBaseSize;
+ src->current_offset = src->fMemoryBaseSize;
}
static boolean skmem_fill_input_buffer(j_decompress_ptr cinfo) {
@@ -108,18 +130,23 @@
///////////////////////////////////////////////////////////////////////////////
-skjpeg_source_mgr::skjpeg_source_mgr(SkStream* stream, SkImageDecoder* decoder) : fStream(stream) {
+skjpeg_source_mgr::skjpeg_source_mgr(SkStream* stream, SkImageDecoder* decoder,
+ bool copyStream, bool ownStream) : fStream(stream) {
fDecoder = decoder;
const void* baseAddr = stream->getMemoryBase();
- if (baseAddr && false) {
- fMemoryBase = baseAddr;
+ fMemoryBase = NULL;
+ fUnrefStream = ownStream;
+ if (copyStream) {
fMemoryBaseSize = stream->getLength();
+ fMemoryBase = sk_malloc_throw(fMemoryBaseSize);
+ stream->read(fMemoryBase, fMemoryBaseSize);
init_source = skmem_init_source;
fill_input_buffer = skmem_fill_input_buffer;
skip_input_data = skmem_skip_input_data;
resync_to_restart = skmem_resync_to_restart;
term_source = skmem_term_source;
+ seek_input_data = NULL;
} else {
fMemoryBase = NULL;
fMemoryBaseSize = 0;
@@ -129,10 +156,20 @@
skip_input_data = sk_skip_input_data;
resync_to_restart = sk_resync_to_restart;
term_source = sk_term_source;
+ seek_input_data = sk_seek_input_data;
}
// SkDebugf("**************** use memorybase %p %d\n", fMemoryBase, fMemoryBaseSize);
}
+skjpeg_source_mgr::~skjpeg_source_mgr() {
+ if (fMemoryBase) {
+ sk_free(fMemoryBase);
+ }
+ if (fUnrefStream) {
+ fStream->unref();
+ }
+}
+
///////////////////////////////////////////////////////////////////////////////
static void sk_init_destination(j_compress_ptr cinfo) {
diff --git a/src/images/SkLargeBitmap.cpp b/src/images/SkLargeBitmap.cpp
new file mode 100644
index 0000000..18fb36f
--- /dev/null
+++ b/src/images/SkLargeBitmap.cpp
@@ -0,0 +1,7 @@
+#include "SkLargeBitmap.h"
+
+bool SkLargeBitmap::decodeRegion(SkBitmap* bitmap, SkIRect rect,
+ SkBitmap::Config pref, int sampleSize) {
+ fDecoder->setSampleSize(sampleSize);
+ return fDecoder->decodeRegion(bitmap, rect, pref);
+}