aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar epoger@google.com <epoger@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-12-12 17:22:23 +0000
committerGravatar epoger@google.com <epoger@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-12-12 17:22:23 +0000
commit31114c69f39befd50d2b755b7d0dd1cda2c6d2ab (patch)
treebf8479ad3a372b64f34f719622290b4afbd9312b /src
parentca47aae7ecfdafb5e88baee13737908b79a4c716 (diff)
Create SkBitmapChecksummer and associated SkBitmapTransformer
As needed to start capturing gm image checksums. Review URL: https://codereview.appspot.com/6920050 git-svn-id: http://skia.googlecode.com/svn/trunk@6759 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src')
-rw-r--r--src/utils/SkBitmapChecksummer.cpp69
-rw-r--r--src/utils/SkBitmapChecksummer.h37
-rw-r--r--src/utils/SkBitmapTransformer.cpp87
-rw-r--r--src/utils/SkBitmapTransformer.h104
4 files changed, 297 insertions, 0 deletions
diff --git a/src/utils/SkBitmapChecksummer.cpp b/src/utils/SkBitmapChecksummer.cpp
new file mode 100644
index 0000000000..bb9fc8d974
--- /dev/null
+++ b/src/utils/SkBitmapChecksummer.cpp
@@ -0,0 +1,69 @@
+
+/*
+ * 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 "SkBitmapChecksummer.h"
+#include "SkBitmapTransformer.h"
+#include "SkCityHash.h"
+#include "SkEndian.h"
+
+/**
+ * Write an integer value into a bytebuffer in little-endian order.
+ */
+static void write_int_to_buffer(int val, char* buf) {
+ val = SkEndian_SwapLE32(val);
+ for (int byte=0; byte<4; byte++) {
+ *buf++ = (char)(val & 0xff);
+ val = val >> 8;
+ }
+}
+
+/*static*/ uint64_t SkBitmapChecksummer::Compute64Internal(
+ const SkBitmap& bitmap, const SkBitmapTransformer& transformer) {
+ int pixelBufferSize = transformer.bytesNeededTotal();
+ int totalBufferSize = pixelBufferSize + 8; // leave room for x/y dimensions
+
+ SkAutoMalloc bufferManager(totalBufferSize);
+ char *bufferStart = static_cast<char *>(bufferManager.get());
+ char *bufPtr = bufferStart;
+ // start with the x/y dimensions
+ write_int_to_buffer(bitmap.width(), bufPtr);
+ bufPtr += 4;
+ write_int_to_buffer(bitmap.height(), bufPtr);
+ bufPtr += 4;
+
+ // add all the pixel data
+ if (!transformer.copyBitmapToPixelBuffer(bufPtr, pixelBufferSize)) {
+ return 0;
+ }
+ return SkCityHash::Compute64(bufferStart, totalBufferSize);
+}
+
+/*static*/ uint64_t SkBitmapChecksummer::Compute64(const SkBitmap& bitmap) {
+ const SkBitmapTransformer::PixelFormat kPixelFormat =
+ SkBitmapTransformer::kARGB_8888_Premul_PixelFormat;
+
+ // First, try to transform the existing bitmap.
+ const SkBitmapTransformer transformer =
+ SkBitmapTransformer(bitmap, kPixelFormat);
+ if (transformer.isValid(false)) {
+ return Compute64Internal(bitmap, transformer);
+ }
+
+ // Hmm, that didn't work. Maybe if we create a new
+ // kARGB_8888_Config version of the bitmap it will work better?
+ SkBitmap copyBitmap;
+ bitmap.copyTo(&copyBitmap, SkBitmap::kARGB_8888_Config);
+ const SkBitmapTransformer copyTransformer =
+ SkBitmapTransformer(copyBitmap, kPixelFormat);
+ if (copyTransformer.isValid(true)) {
+ return Compute64Internal(copyBitmap, copyTransformer);
+ } else {
+ return 0;
+ }
+}
diff --git a/src/utils/SkBitmapChecksummer.h b/src/utils/SkBitmapChecksummer.h
new file mode 100644
index 0000000000..63ac726c2e
--- /dev/null
+++ b/src/utils/SkBitmapChecksummer.h
@@ -0,0 +1,37 @@
+
+/*
+ * 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 SkBitmapChecksummer_DEFINED
+#define SkBitmapChecksummer_DEFINED
+
+#include "SkBitmap.h"
+#include "SkBitmapTransformer.h"
+
+/**
+ * Static class that can generate checksums from SkBitmaps.
+ */
+class SkBitmapChecksummer {
+public:
+ /**
+ * Returns a 64-bit checksum of the pixels in this bitmap.
+ *
+ * If this is unable to compute the checksum for some reason,
+ * it returns 0.
+ *
+ * Note: depending on the bitmap config, we may need to create an
+ * intermediate SkBitmap and copy the pixels over to it... so in some
+ * cases, performance and memory usage can suffer.
+ */
+ static uint64_t Compute64(const SkBitmap& bitmap);
+
+private:
+ static uint64_t Compute64Internal(const SkBitmap& bitmap,
+ const SkBitmapTransformer& transformer);
+};
+
+#endif
diff --git a/src/utils/SkBitmapTransformer.cpp b/src/utils/SkBitmapTransformer.cpp
new file mode 100644
index 0000000000..c8356d4238
--- /dev/null
+++ b/src/utils/SkBitmapTransformer.cpp
@@ -0,0 +1,87 @@
+
+/*
+ * 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 "SkBitmapTransformer.h"
+#include "SkColorPriv.h"
+#include "SkTypes.h"
+
+bool SkBitmapTransformer::isValid(bool logReason) const {
+ bool retval = true;
+
+ switch(fPixelFormat) {
+ case kARGB_8888_Premul_PixelFormat:
+ break;
+ default:
+ if (logReason) {
+ SkDEBUGF(("PixelFormat %d not supported\n", fPixelFormat));
+ }
+ retval = false;
+ }
+
+ SkBitmap::Config bitmapConfig = fBitmap.config();
+ switch(bitmapConfig) {
+ case SkBitmap::kARGB_8888_Config:
+ break;
+ default:
+ if (logReason) {
+ SkDEBUGF(("SkBitmap::Config %d not supported\n", bitmapConfig));
+ }
+ retval = false;
+ }
+
+ return retval;
+}
+
+/**
+ * Transform from kARGB_8888_Config to kARGB_8888_Premul_PixelFormat.
+ *
+ * Similar to the various scanline transformers in
+ * src/images/transform_scanline.h .
+ */
+static void transform_scanline(const char* SK_RESTRICT src, int width,
+ char* SK_RESTRICT dst) {
+ const SkPMColor* SK_RESTRICT srcP = reinterpret_cast<const SkPMColor*>(src);
+ for (int i = 0; i < width; i++) {
+ SkPMColor c = *srcP++;
+ unsigned a = SkGetPackedA32(c);
+ unsigned r = SkGetPackedR32(c);
+ unsigned g = SkGetPackedG32(c);
+ unsigned b = SkGetPackedB32(c);
+ *dst++ = a;
+ *dst++ = r;
+ *dst++ = g;
+ *dst++ = b;
+ }
+}
+
+bool SkBitmapTransformer::copyBitmapToPixelBuffer(void *dstBuffer,
+ size_t dstBufferSize) const {
+ if (!this->isValid(true)) {
+ return false;
+ }
+ size_t bytesNeeded = this->bytesNeededTotal();
+ if (dstBufferSize < bytesNeeded) {
+ SkDEBUGF(("dstBufferSize %d must be >= %d\n", dstBufferSize, bytesNeeded));
+ return false;
+ }
+
+ fBitmap.lockPixels();
+ int width = fBitmap.width();
+ size_t srcRowBytes = fBitmap.rowBytes();
+ size_t dstRowBytes = this->bytesNeededPerRow();
+ const char *srcBytes = const_cast<const char *>(static_cast<char*>(fBitmap.getPixels()));
+ char *dstBytes = static_cast<char *>(dstBuffer);
+ for (int y = 0; y < fBitmap.height(); y++) {
+ transform_scanline(srcBytes, width, dstBytes);
+ srcBytes += srcRowBytes;
+ dstBytes += dstRowBytes;
+ }
+ fBitmap.unlockPixels();
+ return true;
+}
diff --git a/src/utils/SkBitmapTransformer.h b/src/utils/SkBitmapTransformer.h
new file mode 100644
index 0000000000..70971ac625
--- /dev/null
+++ b/src/utils/SkBitmapTransformer.h
@@ -0,0 +1,104 @@
+
+/*
+ * 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 SkBitmapTransformer_DEFINED
+#define SkBitmapTransformer_DEFINED
+
+#include "SkBitmap.h"
+
+/**
+ * Class that can copy pixel data out of an SkBitmap, transforming it
+ * into the appropriate PixelFormat.
+ *
+ * As noted in https://codereview.appspot.com/6849119/#msg6 and
+ * https://codereview.appspot.com/6900047 , at some point we might want
+ * to make this more general purpose:
+ * - support more PixelFormats
+ * - use existing SkCanvas::Config8888 enum instead of new PixelFormat enum
+ * - add method to copy pixel data for a single row, instead of the whole bitmap
+ * - add methods to copy pixel data INTO an SkBitmap
+ *
+ * That would allow us to replace SkCopyConfig8888ToBitmap() in
+ * src/core/SkConfig8888.h , as well as the transformations used by
+ * src/images/SkImageDecoder_libpng.cpp , with this common code.
+ *
+ * But for now, we want something more narrowly targeted, just
+ * supplying what is needed by SkBitmapChecksummer.
+ */
+class SkBitmapTransformer {
+public:
+ enum PixelFormat {
+ // 32 bits per pixel, ARGB byte order, with the alpha-channel
+ // value premultiplied into the R/G/B channel values.
+ kARGB_8888_Premul_PixelFormat,
+
+ // marks the end of the list
+ kLast_PixelFormat = kARGB_8888_Premul_PixelFormat,
+ };
+
+ /**
+ * Creates an SkBitmapTransformer instance that can transform between
+ * the given bitmap and a pixel buffer with given pixelFormat.
+ *
+ * Call IsValid() before using, to confirm that this particular
+ * bitmap/pixelFormat combination is supported!
+ */
+ SkBitmapTransformer(const SkBitmap& bitmap, PixelFormat pixelFormat) :
+ fBitmap(bitmap), fPixelFormat(pixelFormat) {}
+
+ /**
+ * Returns true iff we can convert between fBitmap and fPixelFormat.
+ * If this returns false, the return values of any other methods will
+ * be meaningless!
+ *
+ * @param logReason whether to log the reason why this combination
+ * is unsupported (only applies in debug mode)
+ */
+ bool isValid(bool logReason=false) const;
+
+ /**
+ * Returns the number of bytes needed to store a single row of the
+ * bitmap's pixels if converted to pixelFormat.
+ */
+ size_t bytesNeededPerRow() const {
+ // This is hard-coded for the single supported PixelFormat.
+ return fBitmap.width() * 4;
+ }
+
+ /**
+ * Returns the number of bytes needed to store the entire bitmap
+ * if converted to pixelFormat, ASSUMING that it is written
+ * out as a single contiguous blob of pixels (no leftover bytes
+ * at the end of each row).
+ */
+ size_t bytesNeededTotal() const {
+ return this->bytesNeededPerRow() * fBitmap.height();
+ }
+
+ /**
+ * Writes the entire bitmap into dstBuffer, using the already-specified
+ * pixelFormat. Returns true if successful.
+ *
+ * dstBufferSize is the maximum allowable bytes to write into dstBuffer;
+ * if that is not large enough to hold the entire bitmap, then this
+ * will fail immediately and return false.
+ * We force the caller to pass this in to avoid buffer overruns in
+ * unanticipated cases.
+ *
+ * All pixels for all rows will be written into dstBuffer as a
+ * single contiguous blob (no skipped pixels at the end of each
+ * row).
+ */
+ bool copyBitmapToPixelBuffer (void *dstBuffer, size_t dstBufferSize) const;
+
+private:
+ const SkBitmap& fBitmap;
+ const PixelFormat fPixelFormat;
+};
+
+#endif