diff options
author | 2012-12-12 17:22:23 +0000 | |
---|---|---|
committer | 2012-12-12 17:22:23 +0000 | |
commit | 31114c69f39befd50d2b755b7d0dd1cda2c6d2ab (patch) | |
tree | bf8479ad3a372b64f34f719622290b4afbd9312b /src | |
parent | ca47aae7ecfdafb5e88baee13737908b79a4c716 (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.cpp | 69 | ||||
-rw-r--r-- | src/utils/SkBitmapChecksummer.h | 37 | ||||
-rw-r--r-- | src/utils/SkBitmapTransformer.cpp | 87 | ||||
-rw-r--r-- | src/utils/SkBitmapTransformer.h | 104 |
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(©Bitmap, 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 |