From 5a7c6be72b940dde8ff6ad2485a09aecd56a2660 Mon Sep 17 00:00:00 2001 From: "scroggo@google.com" Date: Thu, 4 Oct 2012 21:46:08 +0000 Subject: [PATCH] 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 --- gm/gmmain.cpp | 41 +++++++---- gyp/images.gyp | 1 + include/core/SkFlattenableBuffers.h | 9 --- include/core/SkPicture.h | 11 ++- include/core/SkSerializationHelpers.h | 35 +++++++++ include/core/SkWriter32.h | 9 +++ include/images/SkImages.h | 14 ++++ src/core/SkOrderedReadBuffer.cpp | 32 ++++++-- src/core/SkOrderedReadBuffer.h | 14 +++- src/core/SkOrderedWriteBuffer.cpp | 42 +++++++++-- src/core/SkOrderedWriteBuffer.h | 13 ++++ src/core/SkPicture.cpp | 11 +-- src/core/SkPicturePlayback.cpp | 12 ++- src/core/SkPicturePlayback.h | 9 ++- src/core/SkWriter32.cpp | 13 +++- src/images/SkImages.cpp | 16 ++++ src/ports/SkGlobalInitialization_default.cpp | 7 +- src/ports/SkImageDecoder_CG.cpp | 15 +++- src/ports/SkImageDecoder_empty.cpp | 106 ++++++++++----------------- tools/bench_pictures_main.cpp | 3 +- tools/render_pictures_main.cpp | 3 +- 21 files changed, 289 insertions(+), 127 deletions(-) create mode 100644 include/core/SkSerializationHelpers.h create mode 100644 include/images/SkImages.h create mode 100644 src/images/SkImages.cpp 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 void compute_diff(const SkBitmap& target, const SkBitmap& base, 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 @@ static ErrorBitfield compare(const SkBitmap& target, const SkBitmap& base, 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 @@ static ErrorBitfield compare_to_reference_image(const SkString& name, 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 @@ static ErrorBitfield handle_test_results(GM* gm, 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 @@ static ErrorBitfield handle_test_results(GM* gm, if (comparisonBitmap) { retval |= compare_to_reference_image(name, bitmap, *comparisonBitmap, diffPath, - renderModeDescriptor); + renderModeDescriptor, tolerance); } return retval; } @@ -513,6 +519,10 @@ static SkPicture* generate_new_picture(GM* gm) { 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 @@ static SkPicture* stream_to_new_picture(const SkPicture& src) { // ?!?! SkDynamicMemoryWStream storage; - src.serialize(&storage); + src.serialize(&storage, &EncodeBitmap); int streamSize = storage.getOffset(); SkAutoMalloc dstStorage(streamSize); @@ -531,7 +541,7 @@ static SkPicture* stream_to_new_picture(const SkPicture& src) { //@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 @@ static ErrorBitfield test_picture_serialization(GM* gm, 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 @@ public: 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 @@ public: 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 @@ public: /** * 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 @@ public: */ 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 @@ public: 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 @@ SkOrderedReadBuffer::SkOrderedReadBuffer() : INHERITED() { fFactoryTDArray = NULL; fFactoryArray = NULL; fFactoryCount = 0; + fBitmapDecoder = NULL; } SkOrderedReadBuffer::SkOrderedReadBuffer(const void* data, size_t size) : INHERITED() { @@ -33,6 +34,7 @@ SkOrderedReadBuffer::SkOrderedReadBuffer(const void* data, size_t size) : INHERI fFactoryTDArray = NULL; fFactoryArray = NULL; fFactoryCount = 0; + fBitmapDecoder = NULL; } SkOrderedReadBuffer::SkOrderedReadBuffer(SkStream* stream) { @@ -48,6 +50,7 @@ SkOrderedReadBuffer::SkOrderedReadBuffer(SkStream* stream) { fFactoryTDArray = NULL; fFactoryArray = NULL; fFactoryCount = 0; + fBitmapDecoder = NULL; } SkOrderedReadBuffer::~SkOrderedReadBuffer() { @@ -164,12 +167,31 @@ uint32_t SkOrderedReadBuffer::getArrayCount() { } 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(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 @@ public: 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 @@ private: 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 @@ SkOrderedWriteBuffer::SkOrderedWriteBuffer(size_t minSize) , 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 @@ SkOrderedWriteBuffer::SkOrderedWriteBuffer(size_t minSize, void* storage, size_t , fNamedFactorySet(NULL) , fWriter(minSize, storage, storageSize) , fBitmapHeap(NULL) - , fTFSet(NULL) { + , fTFSet(NULL) + , fBitmapEncoder(NULL) { } SkOrderedWriteBuffer::~SkOrderedWriteBuffer() { @@ -134,10 +137,37 @@ bool SkOrderedWriteBuffer::writeToStream(SkWStream* stream) { } 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 @@ public: 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 @@ private: 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 @@ void SkPicture::draw(SkCanvas* surface) { // 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 @@ SkPicture::SkPicture(SkStream* stream, bool* success) : SkRefCnt() { 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 @@ SkPicture::SkPicture(SkStream* stream, bool* success) : SkRefCnt() { } } -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 @@ void SkPicture::serialize(SkWStream* stream) const { 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::flattenToBuffer(SkOrderedWriteBuffer& buffer) const { } } -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 @@ void SkPicturePlayback::serialize(SkWStream* stream) const { buffer.setFlags(SkFlattenableWriteBuffer::kCrossProcess_Flag); buffer.setTypefaceRecorder(&typefaceSet); buffer.setFactoryRecorder(&factSet); + buffer.setBitmapEncoder(encoder); this->flattenToBuffer(buffer); @@ -428,7 +430,8 @@ static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) { } 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 @@ bool SkPicturePlayback::parseStreamTag(SkStream* stream, const SkPictInfo& info, fFactoryPlayback->setupBuffer(buffer); fTFPlayback.setupBuffer(buffer); + buffer.setBitmapDecoder(decoder); while (!buffer.eof()) { tag = buffer.readUInt(); @@ -532,7 +536,7 @@ bool SkPicturePlayback::parseBufferTag(SkOrderedReadBuffer& buffer, } 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 @@ SkPicturePlayback::SkPicturePlayback(SkStream* stream, const SkPictInfo& info, } 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 @@ public: 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 @@ public: #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 @@ void SkWriter32::flatten(void* dst) const { 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 @@ void SkFlattenable::InitializeFlattenables() { 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 @@ private: */ 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: + // : CGImageDestinationAddImage image could not be converted to destination + // format. + // : 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 @@ bool SkImageEncoder_CG::onEncode(SkWStream* stream, const SkBitmap& bm, } SkAutoTCallVProc 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; +} -typedef SkMovie* (*SkMovieFactoryProc)(SkStream*); +bool SkImageDecoder::DecodeStream(SkStream*, SkBitmap*, SkBitmap::Config, SkImageDecoder::Mode, + SkImageDecoder::Format*) { + return false; +} -extern SkMovie* SkMovie_GIF_Factory(SkStream*); +bool SkImageDecoder::DecodeMemory(const void*, size_t, SkBitmap*, SkBitmap::Config, + SkImageDecoder::Mode, SkImageDecoder::Format*) { + return false; +} -static const SkMovieFactoryProc gMovieProcs[] = { -#if 0 - SkMovie_GIF_Factory -#endif -}; +SkImageDecoder* CreateJPEGImageDecoder() { + return NULL; +} +///////////////////////////////////////////////////////////////////////// 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; - } + 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; +} + +///////////////////////////////////////////////////////////////////////// + +#include "SkImages.h" + +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 @@ static bool run_single_benchmark(const SkString& inputPath, } 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 @@ static bool render_picture(const SkString& inputPath, const SkString& outputDir, } 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; -- 2.7.4