Add the ability to provide function pointers to SkPicture serialization
and deserialization for encoding and decoding bitmaps.
Remove kForceFlattenBitmapPixels_Flag, which is no longer used.
When an SkOrderedReadBuffer needs to read a bitmap, if it does not
have an image decoder, use a dummy bitmap.
In GM, add a tolerance option for color differences, used when
testing picture serialization, so it can assume two images are the
same even though PNG encoding/decoding may have resulted in small
differences.
Create dummy implementations for SkImageDecoder and SkImageEncoder
functions in SkImageDecoder_empty so that a project that does not
want to include the images project it can still build.
Allow ports to build without images project.
In Mac's image encoder, copy 4444 to 8888 before encoding.
Add SkWriter32::reservePad, to provide a pointer to write non 4 byte
aligned data, padded with zeroes.
In bench_ and render_ pictures, pass decode function to SkPicture
creation from a stream.
BUG=https://code.google.com/p/skia/issues/detail?id=842
Review URL: https://codereview.appspot.com/6551071
git-svn-id: http://skia.googlecode.com/svn/trunk@5818 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp
index f0de5bd..2d341e9 100644
--- a/gm/gmmain.cpp
+++ b/gm/gmmain.cpp
@@ -171,7 +171,7 @@
static ErrorBitfield compare(const SkBitmap& target, const SkBitmap& base,
const SkString& name,
const char* renderModeDescriptor,
- SkBitmap* diff) {
+ SkBitmap* diff, uint32_t tolerance) {
SkBitmap copy;
const SkBitmap* bm = ⌖
if (target.config() != SkBitmap::kARGB_8888_Config) {
@@ -206,16 +206,20 @@
SkPMColor c0 = *bp->getAddr32(x, y);
SkPMColor c1 = *bm->getAddr32(x, y);
if (c0 != c1) {
- SkDebugf(
+ SkPMColor trueDiff = compute_diff_pmcolor(c0, c1);
+ if (SkGetPackedR32(trueDiff) > tolerance || SkGetPackedG32(trueDiff) > tolerance
+ || SkGetPackedB32(trueDiff) > tolerance) {
+ SkDebugf(
"----- %s pixel mismatch for %s at [%d %d] base 0x%08X current 0x%08X\n",
renderModeDescriptor, name.c_str(), x, y, c0, c1);
- if (diff) {
- diff->setConfig(SkBitmap::kARGB_8888_Config, w, h);
- diff->allocPixels();
- compute_diff(*bm, *bp, diff);
+ if (diff) {
+ diff->setConfig(SkBitmap::kARGB_8888_Config, w, h);
+ diff->allocPixels();
+ compute_diff(*bm, *bp, diff);
+ }
+ return ERROR_PIXEL_MISMATCH;
}
- return ERROR_PIXEL_MISMATCH;
}
}
}
@@ -438,11 +442,12 @@
SkBitmap &bitmap,
const SkBitmap& comparisonBitmap,
const char diffPath [],
- const char renderModeDescriptor []) {
+ const char renderModeDescriptor [],
+ uint32_t tolerance = 0) {
ErrorBitfield errors;
SkBitmap diffBitmap;
errors = compare(bitmap, comparisonBitmap, name, renderModeDescriptor,
- diffPath ? &diffBitmap : NULL);
+ diffPath ? &diffBitmap : NULL, tolerance);
if ((ERROR_NONE != errors) && diffPath) {
// write out the generated image
SkString genName = make_filename(diffPath, "", name, "png");
@@ -482,7 +487,8 @@
const char renderModeDescriptor [],
SkBitmap& bitmap,
SkDynamicMemoryWStream* pdf,
- const SkBitmap* comparisonBitmap) {
+ const SkBitmap* comparisonBitmap,
+ uint32_t tolerance = 0) {
SkString name = make_name(gm->shortName(), gRec.fName);
ErrorBitfield retval = ERROR_NONE;
@@ -497,7 +503,7 @@
if (comparisonBitmap) {
retval |= compare_to_reference_image(name, bitmap,
*comparisonBitmap, diffPath,
- renderModeDescriptor);
+ renderModeDescriptor, tolerance);
}
return retval;
}
@@ -513,6 +519,10 @@
return pict;
}
+static bool EncodeBitmap(SkWStream* wStream, const SkBitmap& bitmap) {
+ return SkImageEncoder::EncodeStream(wStream, bitmap, SkImageEncoder::kPNG_Type, 100);
+}
+
static SkPicture* stream_to_new_picture(const SkPicture& src) {
// To do in-memory commiunications with a stream, we need to:
@@ -522,7 +532,7 @@
// ?!?!
SkDynamicMemoryWStream storage;
- src.serialize(&storage);
+ src.serialize(&storage, &EncodeBitmap);
int streamSize = storage.getOffset();
SkAutoMalloc dstStorage(streamSize);
@@ -531,7 +541,7 @@
//@todo thudson 22 April 2011 when can we safely delete [] dst?
storage.copyTo(dst);
SkMemoryStream pictReadback(dst, streamSize);
- SkPicture* retval = new SkPicture (&pictReadback);
+ SkPicture* retval = SkNEW_ARGS(SkPicture, (&pictReadback, NULL, &SkImageDecoder::DecodeStream));
return retval;
}
@@ -623,8 +633,11 @@
if (kRaster_Backend == gRec.fBackend) {
SkBitmap bitmap;
generate_image_from_picture(gm, gRec, repict, &bitmap);
+ // Allow for slight differences in color due to PNG encoding bitmaps, which does not restore
+ // our premultiplied alpha properly.
+ static const uint32_t tolerance = 50;
return handle_test_results(gm, gRec, NULL, NULL, diffPath,
- "-serialize", bitmap, NULL, &comparisonBitmap);
+ "-serialize", bitmap, NULL, &comparisonBitmap, tolerance);
} else {
return ERROR_NONE;
}
diff --git a/gyp/images.gyp b/gyp/images.gyp
index 00c8377..7824cf9 100644
--- a/gyp/images.gyp
+++ b/gyp/images.gyp
@@ -43,6 +43,7 @@
'../src/images/SkImageRefPool.cpp',
'../src/images/SkImageRefPool.h',
'../src/images/SkImageRef_GlobalPool.cpp',
+ '../src/images/SkImages.cpp',
'../src/images/SkJpegUtility.cpp',
'../src/images/SkMovie.cpp',
'../src/images/SkMovie_gif.cpp',
diff --git a/include/core/SkFlattenableBuffers.h b/include/core/SkFlattenableBuffers.h
index 763460b..f5b853c 100644
--- a/include/core/SkFlattenableBuffers.h
+++ b/include/core/SkFlattenableBuffers.h
@@ -154,11 +154,6 @@
enum Flags {
kCrossProcess_Flag = 0x01,
-
- /**
- * Instructs the writer to always serialize bitmap pixel data.
- */
- kForceFlattenBitmapPixels_Flag = 0x04,
};
uint32_t getFlags() const { return fFlags; }
@@ -168,10 +163,6 @@
return SkToBool(fFlags & kCrossProcess_Flag);
}
- bool persistBitmapPixels() const {
- return (fFlags & (kCrossProcess_Flag | kForceFlattenBitmapPixels_Flag)) != 0;
- }
-
bool persistTypeface() const { return (fFlags & kCrossProcess_Flag) != 0; }
protected:
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index 00eadb8..203efde 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -11,6 +11,7 @@
#define SkPicture_DEFINED
#include "SkRefCnt.h"
+#include "SkSerializationHelpers.h"
class SkBitmap;
class SkCanvas;
@@ -40,8 +41,10 @@
/**
* Recreate a picture that was serialized into a stream. *success is set to
* true if the picture was deserialized successfully and false otherwise.
+ * decoder is used to decode any SkBitmaps that were encoded into the stream.
*/
- explicit SkPicture(SkStream*, bool* success = NULL);
+ explicit SkPicture(SkStream*, bool* success = NULL,
+ SkSerializationHelpers::DecodeBitmap decoder = NULL);
virtual ~SkPicture();
/**
@@ -132,7 +135,11 @@
*/
int height() const { return fHeight; }
- void serialize(SkWStream*) const;
+ /**
+ * Serialize to a stream. If non NULL, encoder will be used to encode
+ * any bitmaps in the picture.
+ */
+ void serialize(SkWStream*, SkSerializationHelpers::EncodeBitmap encoder = NULL) const;
/** Signals that the caller is prematurely done replaying the drawing
commands. This can be called from a canvas virtual while the picture
diff --git a/include/core/SkSerializationHelpers.h b/include/core/SkSerializationHelpers.h
new file mode 100644
index 0000000..8bb2a41
--- /dev/null
+++ b/include/core/SkSerializationHelpers.h
@@ -0,0 +1,35 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkSerializationHelpers_DEFINED
+#define SkSerializationHelpers_DEFINED
+
+class SkBitmap;
+class SkStream;
+class SkWStream;
+
+namespace SkSerializationHelpers {
+ /**
+ * Function to encode an SkBitmap to an SkWStream. A function with this signature can be passed
+ * to SkPicture::serialize() and SkOrderedWriteBuffer. The function should return true if it
+ * succeeds. Otherwise it should return false so that SkOrderedWriteBuffer can switch to
+ * another method of storing SkBitmaps.
+ */
+ typedef bool (*EncodeBitmap)(SkWStream*, const SkBitmap&);
+
+ /**
+ * Function to decode an SkBitmap from an SkStream. A function with this signature can be
+ * passed to the SkStream constructor for SkPicture and SkOrderedReadBuffer to decode SkBitmaps
+ * which were previously encoded. The function should return true if it succeeds. Otherwise it
+ * should return false so that SkOrderedReadBuffer can skip the data and provide a dummy
+ * SkBitmap.
+ */
+ typedef bool (*DecodeBitmap)(SkStream*, SkBitmap*);
+}
+
+#endif // SkSerializationHelpers_DEFINED
diff --git a/include/core/SkWriter32.h b/include/core/SkWriter32.h
index fa30f0f..9354d6d 100644
--- a/include/core/SkWriter32.h
+++ b/include/core/SkWriter32.h
@@ -143,6 +143,15 @@
memcpy(this->reserve(size), values, size);
}
+ /**
+ * Reserve size bytes. Does not need to be 4 byte aligned. The remaining space (if any) will be
+ * filled in with zeroes.
+ */
+ uint32_t* reservePad(size_t size);
+
+ /**
+ * Write size bytes from src, and pad to 4 byte alignment with zeroes.
+ */
void writePad(const void* src, size_t size);
/**
diff --git a/include/images/SkImages.h b/include/images/SkImages.h
new file mode 100644
index 0000000..abe10da
--- /dev/null
+++ b/include/images/SkImages.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+class SkImages {
+public:
+ /**
+ * Initializes flattenables in the images project.
+ */
+ static void InitializeFlattenables();
+};
diff --git a/src/core/SkOrderedReadBuffer.cpp b/src/core/SkOrderedReadBuffer.cpp
index 5835c34..0a7bd90 100644
--- a/src/core/SkOrderedReadBuffer.cpp
+++ b/src/core/SkOrderedReadBuffer.cpp
@@ -20,6 +20,7 @@
fFactoryTDArray = NULL;
fFactoryArray = NULL;
fFactoryCount = 0;
+ fBitmapDecoder = NULL;
}
SkOrderedReadBuffer::SkOrderedReadBuffer(const void* data, size_t size) : INHERITED() {
@@ -33,6 +34,7 @@
fFactoryTDArray = NULL;
fFactoryArray = NULL;
fFactoryCount = 0;
+ fBitmapDecoder = NULL;
}
SkOrderedReadBuffer::SkOrderedReadBuffer(SkStream* stream) {
@@ -48,6 +50,7 @@
fFactoryTDArray = NULL;
fFactoryArray = NULL;
fFactoryCount = 0;
+ fBitmapDecoder = NULL;
}
SkOrderedReadBuffer::~SkOrderedReadBuffer() {
@@ -164,12 +167,31 @@
}
void SkOrderedReadBuffer::readBitmap(SkBitmap* bitmap) {
- if (fBitmapStorage) {
- const uint32_t index = fReader.readU32();
- *bitmap = *fBitmapStorage->getBitmap(index);
- fBitmapStorage->releaseRef(index);
+ size_t length = this->readUInt();
+ if (length > 0) {
+ // Bitmap was encoded.
+ SkMemoryStream stream(const_cast<void*>(this->skip(length)), length, false);
+ if (fBitmapDecoder != NULL && fBitmapDecoder(&stream, bitmap)) {
+ // Skip the width and height, which were written in case of failure.
+ fReader.skip(2 * sizeof(int));
+ } else {
+ // This bitmap was encoded when written, but we are unable to decode, possibly due to
+ // not having a decoder. Use a placeholder bitmap.
+ SkDebugf("Could not decode bitmap. Resulting bitmap will be red.\n");
+ int width = this->readInt();
+ int height = this->readInt();
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height);
+ bitmap->allocPixels();
+ bitmap->eraseColor(SK_ColorRED);
+ }
} else {
- bitmap->unflatten(*this);
+ if (fBitmapStorage) {
+ const uint32_t index = fReader.readU32();
+ *bitmap = *fBitmapStorage->getBitmap(index);
+ fBitmapStorage->releaseRef(index);
+ } else {
+ bitmap->unflatten(*this);
+ }
}
}
diff --git a/src/core/SkOrderedReadBuffer.h b/src/core/SkOrderedReadBuffer.h
index 9b69ff3..b3fde17 100644
--- a/src/core/SkOrderedReadBuffer.h
+++ b/src/core/SkOrderedReadBuffer.h
@@ -13,8 +13,9 @@
#include "SkBitmap.h"
#include "SkBitmapHeap.h"
#include "SkFlattenableBuffers.h"
-#include "SkReader32.h"
#include "SkPath.h"
+#include "SkReader32.h"
+#include "SkSerializationHelpers.h"
class SkOrderedReadBuffer : public SkFlattenableReadBuffer {
public:
@@ -97,6 +98,15 @@
fFactoryCount = 0;
}
+ /**
+ * Provide a function to decode an SkBitmap from an SkStream. Only used if the writer encoded
+ * the SkBitmap. If the proper decoder cannot be used, a red bitmap with the appropriate size
+ * will be used.
+ */
+ void setBitmapDecoder(SkSerializationHelpers::DecodeBitmap bitmapDecoder) {
+ fBitmapDecoder = bitmapDecoder;
+ }
+
private:
SkReader32 fReader;
void* fMemoryPtr;
@@ -109,6 +119,8 @@
SkFlattenable::Factory* fFactoryArray;
int fFactoryCount;
+ SkSerializationHelpers::DecodeBitmap fBitmapDecoder;
+
typedef SkFlattenableReadBuffer INHERITED;
};
diff --git a/src/core/SkOrderedWriteBuffer.cpp b/src/core/SkOrderedWriteBuffer.cpp
index daba06a..bdd9516 100644
--- a/src/core/SkOrderedWriteBuffer.cpp
+++ b/src/core/SkOrderedWriteBuffer.cpp
@@ -8,6 +8,7 @@
#include "SkOrderedWriteBuffer.h"
#include "SkPtrRecorder.h"
+#include "SkStream.h"
#include "SkTypeface.h"
SkOrderedWriteBuffer::SkOrderedWriteBuffer(size_t minSize)
@@ -16,7 +17,8 @@
, fNamedFactorySet(NULL)
, fWriter(minSize)
, fBitmapHeap(NULL)
- , fTFSet(NULL) {
+ , fTFSet(NULL)
+ , fBitmapEncoder(NULL) {
}
SkOrderedWriteBuffer::SkOrderedWriteBuffer(size_t minSize, void* storage, size_t storageSize)
@@ -25,7 +27,8 @@
, fNamedFactorySet(NULL)
, fWriter(minSize, storage, storageSize)
, fBitmapHeap(NULL)
- , fTFSet(NULL) {
+ , fTFSet(NULL)
+ , fBitmapEncoder(NULL) {
}
SkOrderedWriteBuffer::~SkOrderedWriteBuffer() {
@@ -134,10 +137,37 @@
}
void SkOrderedWriteBuffer::writeBitmap(const SkBitmap& bitmap) {
- if (fBitmapHeap) {
- fWriter.write32(fBitmapHeap->insert(bitmap));
- } else {
- bitmap.flatten(*this);
+ bool encoded = false;
+ if (fBitmapEncoder != NULL) {
+ SkDynamicMemoryWStream pngStream;
+ if (fBitmapEncoder(&pngStream, bitmap)) {
+ encoded = true;
+ if (encoded) {
+ uint32_t offset = fWriter.bytesWritten();
+ // Write the length to indicate that the bitmap was encoded successfully.
+ size_t length = pngStream.getOffset();
+ this->writeUInt(length);
+ // Now write the stream.
+ if (pngStream.read(fWriter.reservePad(length), 0, length)) {
+ // Write the width and height in case the reader does not have a decoder.
+ this->writeInt(bitmap.width());
+ this->writeInt(bitmap.height());
+ } else {
+ // Writing the stream failed, so go back to original state to store another way.
+ fWriter.rewindToOffset(offset);
+ encoded = false;
+ }
+ }
+ }
+ }
+ if (!encoded) {
+ // Bitmap was not encoded. Record a zero, implying that the reader need not decode.
+ this->writeUInt(0);
+ if (fBitmapHeap) {
+ fWriter.write32(fBitmapHeap->insert(bitmap));
+ } else {
+ bitmap.flatten(*this);
+ }
}
}
diff --git a/src/core/SkOrderedWriteBuffer.h b/src/core/SkOrderedWriteBuffer.h
index 18d8665..681efed 100644
--- a/src/core/SkOrderedWriteBuffer.h
+++ b/src/core/SkOrderedWriteBuffer.h
@@ -15,6 +15,7 @@
#include "SkBitmap.h"
#include "SkBitmapHeap.h"
#include "SkPath.h"
+#include "SkSerializationHelpers.h"
#include "SkWriter32.h"
class SkFlattenable;
@@ -78,6 +79,16 @@
SkRefCnt_SafeAssign(fBitmapHeap, bitmapHeap);
}
+ /**
+ * Provide a function to encode an SkBitmap to an SkStream. writeBitmap will attempt to use
+ * bitmapEncoder to store the SkBitmap. Takes priority over the SkBitmapHeap. If the reader does
+ * not provide a function to decode, it will not be able to restore SkBitmaps, but will still be
+ * able to read the rest of the stream.
+ */
+ void setBitmapEncoder(SkSerializationHelpers::EncodeBitmap bitmapEncoder) {
+ fBitmapEncoder = bitmapEncoder;
+ }
+
private:
SkFactorySet* fFactorySet;
SkNamedFactorySet* fNamedFactorySet;
@@ -86,6 +97,8 @@
SkBitmapHeap* fBitmapHeap;
SkRefCntSet* fTFSet;
+ SkSerializationHelpers::EncodeBitmap fBitmapEncoder;
+
typedef SkFlattenableWriteBuffer INHERITED;
};
diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp
index b3d3751..3e356ce 100644
--- a/src/core/SkPicture.cpp
+++ b/src/core/SkPicture.cpp
@@ -243,9 +243,10 @@
// V5 : don't read/write FunctionPtr on cross-process (we can detect that)
// V6 : added serialization of SkPath's bounds (and packed its flags tighter)
// V7 : changed drawBitmapRect(IRect) to drawBitmapRectToRect(Rect)
-#define PICTURE_VERSION 7
+// V8 : PNG encode bitmaps
+#define PICTURE_VERSION 8
-SkPicture::SkPicture(SkStream* stream, bool* success) : SkRefCnt() {
+SkPicture::SkPicture(SkStream* stream, bool* success, SkSerializationHelpers::DecodeBitmap decoder) : SkRefCnt() {
if (success) {
*success = false;
}
@@ -264,7 +265,7 @@
if (stream->readBool()) {
bool isValid = false;
- fPlayback = SkNEW_ARGS(SkPicturePlayback, (stream, info, &isValid));
+ fPlayback = SkNEW_ARGS(SkPicturePlayback, (stream, info, &isValid, decoder));
if (!isValid) {
SkDELETE(fPlayback);
fPlayback = NULL;
@@ -280,7 +281,7 @@
}
}
-void SkPicture::serialize(SkWStream* stream) const {
+void SkPicture::serialize(SkWStream* stream, SkSerializationHelpers::EncodeBitmap encoder) const {
SkPicturePlayback* playback = fPlayback;
if (NULL == playback && fRecord) {
@@ -303,7 +304,7 @@
stream->write(&info, sizeof(info));
if (playback) {
stream->writeBool(true);
- playback->serialize(stream);
+ playback->serialize(stream, encoder);
// delete playback if it is a local version (i.e. cons'd up just now)
if (playback != fPlayback) {
SkDELETE(playback);
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index 3bff5ea..5d4098a 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -364,7 +364,8 @@
}
}
-void SkPicturePlayback::serialize(SkWStream* stream) const {
+void SkPicturePlayback::serialize(SkWStream* stream,
+ SkSerializationHelpers::EncodeBitmap encoder) const {
writeTagSize(stream, PICT_READER_TAG, fOpData->size());
stream->write(fOpData->bytes(), fOpData->size());
@@ -386,6 +387,7 @@
buffer.setFlags(SkFlattenableWriteBuffer::kCrossProcess_Flag);
buffer.setTypefaceRecorder(&typefaceSet);
buffer.setFactoryRecorder(&factSet);
+ buffer.setBitmapEncoder(encoder);
this->flattenToBuffer(buffer);
@@ -428,7 +430,8 @@
}
bool SkPicturePlayback::parseStreamTag(SkStream* stream, const SkPictInfo& info,
- uint32_t tag, size_t size) {
+ uint32_t tag, size_t size,
+ SkSerializationHelpers::DecodeBitmap decoder) {
/*
* By the time we encounter BUFFER_SIZE_TAG, we need to have already seen
* its dependents: FACTORY_TAG and TYPEFACE_TAG. These two are not required
@@ -481,6 +484,7 @@
fFactoryPlayback->setupBuffer(buffer);
fTFPlayback.setupBuffer(buffer);
+ buffer.setBitmapDecoder(decoder);
while (!buffer.eof()) {
tag = buffer.readUInt();
@@ -532,7 +536,7 @@
}
SkPicturePlayback::SkPicturePlayback(SkStream* stream, const SkPictInfo& info,
- bool* isValid) {
+ bool* isValid, SkSerializationHelpers::DecodeBitmap decoder) {
this->init();
*isValid = false; // wait until we're done parsing to mark as true
@@ -543,7 +547,7 @@
}
uint32_t size = stream->readU32();
- if (!this->parseStreamTag(stream, info, tag, size)) {
+ if (!this->parseStreamTag(stream, info, tag, size, decoder)) {
return; // we're invalid
}
}
diff --git a/src/core/SkPicturePlayback.h b/src/core/SkPicturePlayback.h
index dc46e68..24bce4e 100644
--- a/src/core/SkPicturePlayback.h
+++ b/src/core/SkPicturePlayback.h
@@ -20,6 +20,7 @@
#include "SkPathHeap.h"
#include "SkRegion.h"
#include "SkPictureFlat.h"
+#include "SkSerializationHelpers.h"
#ifdef SK_BUILD_FOR_ANDROID
#include "SkThread.h"
@@ -61,13 +62,14 @@
SkPicturePlayback();
SkPicturePlayback(const SkPicturePlayback& src, SkPictCopyInfo* deepCopyInfo = NULL);
explicit SkPicturePlayback(const SkPictureRecord& record, bool deepCopy = false);
- SkPicturePlayback(SkStream*, const SkPictInfo&, bool* isValid);
+ SkPicturePlayback(SkStream*, const SkPictInfo&, bool* isValid,
+ SkSerializationHelpers::DecodeBitmap decoder);
virtual ~SkPicturePlayback();
void draw(SkCanvas& canvas);
- void serialize(SkWStream*) const;
+ void serialize(SkWStream*, SkSerializationHelpers::EncodeBitmap) const;
void dumpSize() const;
@@ -176,7 +178,8 @@
#endif
private: // these help us with reading/writing
- bool parseStreamTag(SkStream*, const SkPictInfo&, uint32_t tag, size_t size);
+ bool parseStreamTag(SkStream*, const SkPictInfo&, uint32_t tag, size_t size,
+ SkSerializationHelpers::DecodeBitmap decoder);
bool parseBufferTag(SkOrderedReadBuffer&, uint32_t tag, size_t size);
void flattenToBuffer(SkOrderedWriteBuffer&) const;
diff --git a/src/core/SkWriter32.cpp b/src/core/SkWriter32.cpp
index 3ae6a07..6a84927 100644
--- a/src/core/SkWriter32.cpp
+++ b/src/core/SkWriter32.cpp
@@ -226,14 +226,21 @@
SkASSERT(total == fSize);
}
-void SkWriter32::writePad(const void* src, size_t size) {
+uint32_t* SkWriter32::reservePad(size_t size) {
if (size > 0) {
size_t alignedSize = SkAlign4(size);
char* dst = (char*)this->reserve(alignedSize);
- // Pad the last four bytes with zeroes in one step. Some (or all) will
- // be overwritten by the memcpy.
+ // Pad the last four bytes with zeroes in one step.
uint32_t* padding = (uint32_t*)(dst + (alignedSize - 4));
*padding = 0;
+ return (uint32_t*) dst;
+ }
+ return this->reserve(0);
+}
+
+void SkWriter32::writePad(const void* src, size_t size) {
+ if (size > 0) {
+ char* dst = (char*)this->reservePad(size);
// Copy the actual data.
memcpy(dst, src, size);
}
diff --git a/src/images/SkImages.cpp b/src/images/SkImages.cpp
new file mode 100644
index 0000000..28dfd7f
--- /dev/null
+++ b/src/images/SkImages.cpp
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkFlattenable.h"
+#include "SkFlipPixelRef.h"
+#include "SkImageRef_GlobalPool.h"
+#include "SkImages.h"
+
+void SkImages::InitializeFlattenables() {
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkFlipPixelRef)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageRef_GlobalPool)
+}
diff --git a/src/ports/SkGlobalInitialization_default.cpp b/src/ports/SkGlobalInitialization_default.cpp
index fc454b4..a764dd1 100644
--- a/src/ports/SkGlobalInitialization_default.cpp
+++ b/src/ports/SkGlobalInitialization_default.cpp
@@ -8,9 +8,7 @@
#include "SkTypes.h"
#include "SkBitmapProcShader.h"
-#include "SkFlipPixelRef.h"
#include "SkImageRef_ashmem.h"
-#include "SkImageRef_GlobalPool.h"
#include "SkMallocPixelRef.h"
#include "SkPathEffect.h"
#include "SkPixelRef.h"
@@ -37,6 +35,7 @@
#include "SkEmbossMaskFilter.h"
#include "SkFlattenable.h"
#include "SkGradientShader.h"
+#include "SkImages.h"
#include "SkLayerDrawLooper.h"
#include "SkLayerRasterizer.h"
#include "SkLightingImageFilter.h"
@@ -85,14 +84,12 @@
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkMergeImageFilter)
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkColorFilterImageFilter)
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDownSampleImageFilter)
-
- SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkFlipPixelRef)
- SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageRef_GlobalPool)
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkMallocPixelRef)
SkBlurMaskFilter::InitializeFlattenables();
SkColorFilter::InitializeFlattenables();
SkGradientShader::InitializeFlattenables();
+ SkImages::InitializeFlattenables();
SkLightingImageFilter::InitializeFlattenables();
SkTableColorFilter::InitializeFlattenables();
SkXfermode::InitializeFlattenables();
diff --git a/src/ports/SkImageDecoder_CG.cpp b/src/ports/SkImageDecoder_CG.cpp
index 3930c72..bcd3e37 100644
--- a/src/ports/SkImageDecoder_CG.cpp
+++ b/src/ports/SkImageDecoder_CG.cpp
@@ -150,12 +150,25 @@
*/
bool SkImageEncoder_CG::onEncode(SkWStream* stream, const SkBitmap& bm,
int quality) {
+ // Used for converting a bitmap to 8888.
+ const SkBitmap* bmPtr = &bm;
+ SkBitmap bitmap8888;
+
CFStringRef type;
switch (fType) {
case kJPEG_Type:
type = kUTTypeJPEG;
break;
case kPNG_Type:
+ // PNG encoding an ARGB_4444 bitmap gives the following errors in GM:
+ // <Error>: CGImageDestinationAddImage image could not be converted to destination
+ // format.
+ // <Error>: CGImageDestinationFinalize image destination does not have enough images
+ // So instead we copy to 8888.
+ if (bm.getConfig() == SkBitmap::kARGB_4444_Config) {
+ bm.copyTo(&bitmap8888, SkBitmap::kARGB_8888_Config);
+ bmPtr = &bitmap8888;
+ }
type = kUTTypePNG;
break;
default:
@@ -168,7 +181,7 @@
}
SkAutoTCallVProc<const void, CFRelease> ardst(dst);
- CGImageRef image = SkCreateCGImageRef(bm);
+ CGImageRef image = SkCreateCGImageRef(*bmPtr);
if (NULL == image) {
return false;
}
diff --git a/src/ports/SkImageDecoder_empty.cpp b/src/ports/SkImageDecoder_empty.cpp
index e4079d0..410eef1 100644
--- a/src/ports/SkImageDecoder_empty.cpp
+++ b/src/ports/SkImageDecoder_empty.cpp
@@ -8,92 +8,64 @@
#include "SkImageDecoder.h"
+#include "SkImageEncoder.h"
#include "SkMovie.h"
-#include "SkStream.h"
-extern SkImageDecoder* SkImageDecoder_GIF_Factory(SkStream*);
-extern SkImageDecoder* SkImageDecoder_BMP_Factory(SkStream*);
-extern SkImageDecoder* SkImageDecoder_ICO_Factory(SkStream*);
-extern SkImageDecoder* SkImageDecoder_PNG_Factory(SkStream*);
-extern SkImageDecoder* SkImageDecoder_WBMP_Factory(SkStream*);
-extern SkImageDecoder* SkImageDecoder_JPEG_Factory(SkStream*);
-
-typedef SkImageDecoder* (*SkImageDecoderFactoryProc)(SkStream*);
-
-struct CodecFormat {
- SkImageDecoderFactoryProc fProc;
- SkImageDecoder::Format fFormat;
-};
-
-static const CodecFormat gPairs[] = {
-#if 0
- { SkImageDecoder_GIF_Factory, SkImageDecoder::kGIF_Format },
- { SkImageDecoder_PNG_Factory, SkImageDecoder::kPNG_Format },
- { SkImageDecoder_ICO_Factory, SkImageDecoder::kICO_Format },
- { SkImageDecoder_WBMP_Factory, SkImageDecoder::kWBMP_Format },
- { SkImageDecoder_BMP_Factory, SkImageDecoder::kBMP_Format },
- { SkImageDecoder_JPEG_Factory, SkImageDecoder::kJPEG_Format }
-#endif
-};
+class SkBitmap;
+class SkStream;
SkImageDecoder* SkImageDecoder::Factory(SkStream* stream) {
- for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
- SkImageDecoder* codec = gPairs[i].fProc(stream);
- stream->rewind();
- if (NULL != codec) {
- return codec;
- }
- }
return NULL;
}
-bool SkImageDecoder::SupportsFormat(Format format) {
- for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
- if (gPairs[i].fFormat == format) {
- return true;
- }
- }
+bool SkImageDecoder::DecodeFile(const char file[], SkBitmap*, SkBitmap::Config,
+ SkImageDecoder::Mode, SkImageDecoder::Format*) {
+ return false;
+}
+
+bool SkImageDecoder::decode(SkStream*, SkBitmap* bitmap, SkBitmap::Config pref, Mode) {
+ return false;
+}
+
+bool SkImageDecoder::DecodeStream(SkStream*, SkBitmap*, SkBitmap::Config, SkImageDecoder::Mode,
+ SkImageDecoder::Format*) {
+ return false;
+}
+
+bool SkImageDecoder::DecodeMemory(const void*, size_t, SkBitmap*, SkBitmap::Config,
+ SkImageDecoder::Mode, SkImageDecoder::Format*) {
+ return false;
+}
+
+SkImageDecoder* CreateJPEGImageDecoder() {
+ return NULL;
+}
+/////////////////////////////////////////////////////////////////////////
+
+SkMovie* SkMovie::DecodeStream(SkStream* stream) {
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+SkImageEncoder* SkImageEncoder::Create(Type t) {
+ return NULL;
+}
+
+bool SkImageEncoder::EncodeFile(const char file[], const SkBitmap&, Type, int quality) {
+ return false;
+}
+
+bool SkImageEncoder::EncodeStream(SkWStream*, const SkBitmap&, SkImageEncoder::Type, int) {
+ return false;
+}
+
+bool SkImageEncoder::encodeStream(SkWStream*, const SkBitmap&, int) {
return false;
}
/////////////////////////////////////////////////////////////////////////
-typedef SkMovie* (*SkMovieFactoryProc)(SkStream*);
+#include "SkImages.h"
-extern SkMovie* SkMovie_GIF_Factory(SkStream*);
-
-static const SkMovieFactoryProc gMovieProcs[] = {
-#if 0
- SkMovie_GIF_Factory
-#endif
-};
-
-SkMovie* SkMovie::DecodeStream(SkStream* stream) {
- for (unsigned i = 0; i < SK_ARRAY_COUNT(gMovieProcs); i++) {
- SkMovie* movie = gMovieProcs[i](stream);
- if (NULL != movie) {
- return movie;
- }
- stream->rewind();
- }
- return NULL;
-}
-
-/////////////////////////////////////////////////////////////////////////
-
-extern SkImageEncoder* SkImageEncoder_JPEG_Factory();
-extern SkImageEncoder* SkImageEncoder_PNG_Factory();
-
-SkImageEncoder* SkImageEncoder::Create(Type t) {
- switch (t) {
-#if 0
- case kJPEG_Type:
- return SkImageEncoder_JPEG_Factory();
- case kPNG_Type:
- return SkImageEncoder_PNG_Factory();
-#endif
- default:
- return NULL;
- }
-}
-
+void SkImages::InitializeFlattenables() {}
diff --git a/tools/bench_pictures_main.cpp b/tools/bench_pictures_main.cpp
index 26943d9..e602bd9 100644
--- a/tools/bench_pictures_main.cpp
+++ b/tools/bench_pictures_main.cpp
@@ -10,6 +10,7 @@
#include "SkBenchLogger.h"
#include "SkCanvas.h"
#include "SkGraphics.h"
+#include "SkImageDecoder.h"
#include "SkMath.h"
#include "SkOSFile.h"
#include "SkPicture.h"
@@ -109,7 +110,7 @@
}
bool success = false;
- SkPicture picture(&inputStream, &success);
+ SkPicture picture(&inputStream, &success, &SkImageDecoder::DecodeStream);
if (!success) {
SkString err;
err.printf("Could not read an SkPicture from %s\n", inputPath.c_str());
diff --git a/tools/render_pictures_main.cpp b/tools/render_pictures_main.cpp
index 477272d..6d6e8db 100644
--- a/tools/render_pictures_main.cpp
+++ b/tools/render_pictures_main.cpp
@@ -9,6 +9,7 @@
#include "SkCanvas.h"
#include "SkDevice.h"
#include "SkGraphics.h"
+#include "SkImageDecoder.h"
#include "SkMath.h"
#include "SkOSFile.h"
#include "SkPicture.h"
@@ -96,7 +97,7 @@
}
bool success = false;
- SkPicture picture(&inputStream, &success);
+ SkPicture picture(&inputStream, &success, &SkImageDecoder::DecodeStream);
if (!success) {
SkDebugf("Could not read an SkPicture from %s\n", inputPath.c_str());
return false;