From 9f686f3639ff87e6d28b4ffcc42feebeca90f8d8 Mon Sep 17 00:00:00 2001 From: "scroggo@google.com" Date: Thu, 29 Nov 2012 21:05:37 +0000 Subject: [PATCH] Create a factory to decode an SkBitmap from an SkData. Add a test and a GM for the factory, and a PNG file for it to decode. The PNG file is copyright-free, obtained from http://openclipart.org/detail/29213/paper-plane-by-ddoo In cmykjpeg, do not attempt to decode in the constructor, since it currently crashes on Mac (if you provide the correct resource path). Even when we fix this crash there is no need to do it in the constructor, since we create all of the gms in order to get their names (to determine whether to run them). Review URL: https://codereview.appspot.com/6847122 git-svn-id: http://skia.googlecode.com/svn/trunk@6618 2bbb7eff-a529-9590-31e7-b0007b416f81 --- gm/cmykjpeg.cpp | 6 ++- gm/factory.cpp | 67 +++++++++++++++++++++++++++ gm/resources/plane.png | Bin 0 -> 5718 bytes gyp/gmslides.gypi | 1 + gyp/images.gyp | 2 + gyp/tests.gyp | 1 + include/images/SkBitmapFactory.h | 46 +++++++++++++++++++ src/images/SkBitmapFactory.cpp | 41 +++++++++++++++++ tests/BitmapFactoryTest.cpp | 76 +++++++++++++++++++++++++++++++ 9 files changed, 238 insertions(+), 2 deletions(-) create mode 100644 gm/factory.cpp create mode 100644 gm/resources/plane.png create mode 100644 include/images/SkBitmapFactory.h create mode 100644 src/images/SkBitmapFactory.cpp create mode 100644 tests/BitmapFactoryTest.cpp diff --git a/gm/cmykjpeg.cpp b/gm/cmykjpeg.cpp index 94cf98f92d..692bc3e760 100644 --- a/gm/cmykjpeg.cpp +++ b/gm/cmykjpeg.cpp @@ -17,7 +17,10 @@ namespace skiagm { */ class CMYKJpegGM : public GM { public: - CMYKJpegGM() { + CMYKJpegGM() {} + +protected: + virtual void onOnceBeforeDraw() SK_OVERRIDE { // parameters to the "decode" call bool dither = false; @@ -41,7 +44,6 @@ public: } } -protected: virtual SkString onShortName() { return SkString("cmykjpeg"); } diff --git a/gm/factory.cpp b/gm/factory.cpp new file mode 100644 index 0000000000..88931584d8 --- /dev/null +++ b/gm/factory.cpp @@ -0,0 +1,67 @@ +/* + * 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 "gm.h" +#include "SkBitmapFactory.h" +#include "SkCanvas.h" +#include "SkData.h" +#include "SkStream.h" + +namespace skiagm { + +/** + * Draw a PNG created by SkBitmapFactory. + */ +class FactoryGM : public GM { +public: + FactoryGM() {} + +protected: + virtual void onOnceBeforeDraw() SK_OVERRIDE { + SkString filename(INHERITED::gResourcePath); + if (!filename.endsWith("/") && !filename.endsWith("\\")) { + filename.append("/"); + } + + // Copyright-free file from http://openclipart.org/detail/29213/paper-plane-by-ddoo + filename.append("plane.png"); + + SkFILEStream stream(filename.c_str()); + if (stream.isValid()) { + stream.rewind(); + size_t length = stream.getLength(); + void* buffer = sk_malloc_throw(length); + stream.read(buffer, length); + SkAutoDataUnref data(SkData::NewFromMalloc(buffer, length)); + SkBitmapFactory::DecodeBitmap(&fBitmap, data); + } + } + + virtual SkString onShortName() { + return SkString("factory"); + } + + virtual SkISize onISize() { + return make_isize(640, 480); + } + + virtual void onDraw(SkCanvas* canvas) { + canvas->drawBitmap(fBitmap, 0, 0); + } + +private: + SkBitmap fBitmap; + + typedef GM INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static GM* MyFactory(void*) { return new FactoryGM; } +static GMRegistry reg(MyFactory); + +} diff --git a/gm/resources/plane.png b/gm/resources/plane.png new file mode 100644 index 0000000000000000000000000000000000000000..03585b5cb498006d683bb93b92feae317d11919d GIT binary patch literal 5718 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 literal 0 HcmV?d00001 diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi index bff8391761..6a8b5a6bd1 100644 --- a/gyp/gmslides.gypi +++ b/gyp/gmslides.gypi @@ -31,6 +31,7 @@ '../gm/extractbitmap.cpp', '../gm/emptypath.cpp', '../gm/fatpathfill.cpp', + '../gm/factory.cpp', '../gm/filltypes.cpp', '../gm/filltypespersp.cpp', '../gm/fontscaler.cpp', diff --git a/gyp/images.gyp b/gyp/images.gyp index daf4c5f6c8..1441359e9b 100644 --- a/gyp/images.gyp +++ b/gyp/images.gyp @@ -18,6 +18,7 @@ '../include/images', ], 'sources': [ + '../include/images/SkBitmapFactory.h', '../include/images/SkFlipPixelRef.h', '../include/images/SkImageDecoder.h', '../include/images/SkImageEncoder.h', @@ -29,6 +30,7 @@ '../src/images/bmpdecoderhelper.cpp', '../src/images/bmpdecoderhelper.h', + '../src/images/SkBitmapFactory.cpp', '../src/images/SkFDStream.cpp', '../src/images/SkFlipPixelRef.cpp', '../src/images/SkImageDecoder.cpp', diff --git a/gyp/tests.gyp b/gyp/tests.gyp index 7e8a19e8ab..1c649336dc 100644 --- a/gyp/tests.gyp +++ b/gyp/tests.gyp @@ -20,6 +20,7 @@ '../tests/AnnotationTest.cpp', '../tests/AtomicTest.cpp', '../tests/BitmapCopyTest.cpp', + '../tests/BitmapFactoryTest.cpp', '../tests/BitmapGetColorTest.cpp', '../tests/BitmapHeapTest.cpp', '../tests/BitSetTest.cpp', diff --git a/include/images/SkBitmapFactory.h b/include/images/SkBitmapFactory.h new file mode 100644 index 0000000000..6779dc24c3 --- /dev/null +++ b/include/images/SkBitmapFactory.h @@ -0,0 +1,46 @@ +/* + * 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 SkBitmapFactory_DEFINED +#define SkBitmapFactory_DEFINED + +class SkBitmap; +class SkData; + +/** + * General purpose factory for decoding bitmaps. + * + * Currently only provides a way to decode a bitmap or its dimensions from an SkData. Future plans + * include options to provide a bitmap which caches the pixel data. + */ +class SkBitmapFactory { + +public: + enum Constraints { + /** + * Only decode the bounds of the bitmap. No pixels will be allocated. + */ + kDecodeBoundsOnly_Constraint, + + /** + * Decode the bounds and pixels of the bitmap. + */ + kDecodePixels_Constraint, + }; + + /** + * Decodes an SkData into an SkBitmap. + * @param SkBitmap Already created bitmap to encode into. + * @param SkData Encoded SkBitmap data. + * @param constraint Specifications for how to do the decoding. + * @return True on success. If false, passed in SkBitmap is unmodified. + */ + static bool DecodeBitmap(SkBitmap*, const SkData*, + Constraints constraint = kDecodePixels_Constraint); +}; + +#endif // SkBitmapFactory_DEFINED diff --git a/src/images/SkBitmapFactory.cpp b/src/images/SkBitmapFactory.cpp new file mode 100644 index 0000000000..4e5d90bd60 --- /dev/null +++ b/src/images/SkBitmapFactory.cpp @@ -0,0 +1,41 @@ +/* + * 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 "SkBitmapFactory.h" + +#include "SkBitmap.h" +#include "SkData.h" +#include "SkImageDecoder.h" +#include "SkStream.h" +#include "SkTemplates.h" + +bool SkBitmapFactory::DecodeBitmap(SkBitmap* dst, const SkData* data, Constraints constraint) { + if (NULL == data || data->size() == 0 || dst == NULL) { + return false; + } + + SkMemoryStream stream(data->data(), data->size()); + SkAutoTDelete decoder (SkImageDecoder::Factory(&stream)); + if (decoder.get() == NULL) { + return false; + } + + SkBitmap tmp; + SkImageDecoder::Mode mode; + if (kDecodeBoundsOnly_Constraint == constraint) { + mode = SkImageDecoder::kDecodeBounds_Mode; + } else { + mode = SkImageDecoder::kDecodePixels_Mode; + } + + if (decoder->decode(&stream, &tmp, mode)) { + tmp.swap(*dst); + return true; + } else { + return false; + } +} diff --git a/tests/BitmapFactoryTest.cpp b/tests/BitmapFactoryTest.cpp new file mode 100644 index 0000000000..b24fd258ca --- /dev/null +++ b/tests/BitmapFactoryTest.cpp @@ -0,0 +1,76 @@ + +/* + * 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 "SkBitmap.h" +#include "SkBitmapFactory.h" +#include "SkCanvas.h" +#include "SkColor.h" +#include "SkData.h" +#include "SkImageEncoder.h" +#include "SkPaint.h" +#include "SkStream.h" +#include "SkTemplates.h" +#include "Test.h" + +static SkBitmap* create_bitmap() { + SkBitmap* bm = SkNEW(SkBitmap); + const int W = 100, H = 100; + bm->setConfig(SkBitmap::kARGB_8888_Config, W, H); + bm->allocPixels(); + bm->eraseColor(SK_ColorBLACK); + SkCanvas canvas(*bm); + SkPaint paint; + paint.setColor(SK_ColorBLUE); + canvas.drawRectCoords(0, 0, SkIntToScalar(W/2), SkIntToScalar(H/2), paint); + return bm; +} + +static SkData* create_data_from_bitmap(const SkBitmap& bm) { + SkDynamicMemoryWStream stream; + if (SkImageEncoder::EncodeStream(&stream, bm, SkImageEncoder::kPNG_Type, 100)) { + return stream.copyToData(); + } + return NULL; +} + +static void assert_bounds_equal(skiatest::Reporter* reporter, const SkBitmap& bm1, + const SkBitmap& bm2) { + REPORTER_ASSERT(reporter, bm1.width() == bm2.width()); + REPORTER_ASSERT(reporter, bm1.height() == bm2.height()); +} + +static void TestBitmapFactory(skiatest::Reporter* reporter) { + SkAutoTDelete bitmap(create_bitmap()); + SkASSERT(bitmap.get() != NULL); + + SkAutoDataUnref encodedBitmap(create_data_from_bitmap(*bitmap.get())); + if (encodedBitmap.get() == NULL) { + // Encoding failed. + return; + } + + SkBitmap bitmapFromFactory; + bool success = SkBitmapFactory::DecodeBitmap(&bitmapFromFactory, encodedBitmap); + // This assumes that if the encoder worked, the decoder should also work, so the above call + // should not fail. + REPORTER_ASSERT(reporter, success); + assert_bounds_equal(reporter, *bitmap.get(), bitmapFromFactory); + REPORTER_ASSERT(reporter, bitmapFromFactory.pixelRef() != NULL); + + // When only requesting that the bounds be decoded, the bounds should be set properly while + // the pixels should be empty. + SkBitmap boundedBitmap; + success = SkBitmapFactory::DecodeBitmap(&boundedBitmap, encodedBitmap, + SkBitmapFactory::kDecodeBoundsOnly_Constraint); + REPORTER_ASSERT(reporter, success); + assert_bounds_equal(reporter, *bitmap.get(), boundedBitmap); + REPORTER_ASSERT(reporter, boundedBitmap.pixelRef() == NULL); +} + +#include "TestClassDef.h" +DEFINE_TESTCLASS("BitmapFactory", TestBitmapFactoryClass, TestBitmapFactory)