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
This commit is contained in:
scroggo@google.com 2012-11-29 21:05:37 +00:00
parent 8a98e3bd18
commit 9f686f3639
9 changed files with 238 additions and 2 deletions

View File

@ -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");
}

67
gm/factory.cpp Normal file
View File

@ -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);
}

BIN
gm/resources/plane.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@ -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',

View File

@ -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',

View File

@ -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',

View File

@ -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

View File

@ -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<SkImageDecoder> 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;
}
}

View File

@ -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<SkBitmap> 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)