aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-04-23 18:06:23 +0000
committerGravatar bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-04-23 18:06:23 +0000
commit8c6a4f24d331503b3eb9a5c918d5876772b9a5ee (patch)
tree15a17ad474d1dbde0a0908eb8ad0cc0295a0381f /src
parentab792828a57b663841dacffda9c2163e5e45d934 (diff)
ARGB image encoder for checksums.
Diffstat (limited to 'src')
-rw-r--r--src/images/SkImageEncoder_argb.cpp119
-rw-r--r--src/utils/SkBitmapHasher.cpp51
-rw-r--r--src/utils/SkBitmapHasher.h5
-rw-r--r--src/utils/SkBitmapTransformer.cpp87
-rw-r--r--src/utils/SkBitmapTransformer.h104
-rw-r--r--src/utils/SkMD5.h2
-rw-r--r--src/utils/SkSHA1.h2
7 files changed, 143 insertions, 227 deletions
diff --git a/src/images/SkImageEncoder_argb.cpp b/src/images/SkImageEncoder_argb.cpp
new file mode 100644
index 0000000000..5abc23ce6f
--- /dev/null
+++ b/src/images/SkImageEncoder_argb.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkImageEncoder.h"
+#include "SkBitmap.h"
+#include "SkColorPriv.h"
+#include "SkStream.h"
+#include "SkTemplates.h"
+
+class SkARGBImageEncoder : public SkImageEncoder {
+protected:
+ virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) SK_OVERRIDE;
+
+private:
+ typedef SkImageEncoder INHERITED;
+};
+
+typedef void (*ScanlineImporter)(const uint8_t* in, uint8_t* argb, int width,
+ const SkPMColor* SK_RESTRICT ctable);
+
+static void ARGB_8888_To_ARGB(const uint8_t* in, uint8_t* argb, int width, const SkPMColor*) {
+ const uint32_t* SK_RESTRICT src = (const uint32_t*)in;
+ for (int i = 0; i < width; ++i) {
+ const uint32_t c = *src++;
+ argb[0] = SkGetPackedA32(c);
+ argb[1] = SkGetPackedR32(c);
+ argb[2] = SkGetPackedG32(c);
+ argb[3] = SkGetPackedB32(c);
+ argb += 4;
+ }
+}
+
+static void RGB_565_To_ARGB(const uint8_t* in, uint8_t* argb, int width, const SkPMColor*) {
+ const uint16_t* SK_RESTRICT src = (const uint16_t*)in;
+ for (int i = 0; i < width; ++i) {
+ const uint16_t c = *src++;
+ argb[0] = 0xFF;
+ argb[1] = SkPacked16ToR32(c);
+ argb[2] = SkPacked16ToG32(c);
+ argb[3] = SkPacked16ToB32(c);
+ argb += 4;
+ }
+}
+
+static void ARGB_4444_To_ARGB(const uint8_t* in, uint8_t* argb, int width, const SkPMColor*) {
+ const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)in;
+ for (int i = 0; i < width; ++i) {
+ const SkPMColor16 c = *src++;
+ argb[0] = SkPacked4444ToA32(c);
+ argb[1] = SkPacked4444ToR32(c);
+ argb[2] = SkPacked4444ToG32(c);
+ argb[3] = SkPacked4444ToB32(c);
+ argb += 4;
+ }
+}
+
+static void Index8_To_ARGB(const uint8_t* in, uint8_t* argb, int width,
+ const SkPMColor* SK_RESTRICT ctable) {
+ const uint8_t* SK_RESTRICT src = (const uint8_t*)in;
+ for (int i = 0; i < width; ++i) {
+ const uint32_t c = ctable[*src++];
+ argb[0] = SkGetPackedA32(c);
+ argb[1] = SkGetPackedR32(c);
+ argb[2] = SkGetPackedG32(c);
+ argb[3] = SkGetPackedB32(c);
+ argb += 4;
+ }
+}
+
+static ScanlineImporter ChooseImporter(const SkBitmap::Config& config) {
+ switch (config) {
+ case SkBitmap::kARGB_8888_Config:
+ return ARGB_8888_To_ARGB;
+ case SkBitmap::kRGB_565_Config:
+ return RGB_565_To_ARGB;
+ case SkBitmap::kARGB_4444_Config:
+ return ARGB_4444_To_ARGB;
+ case SkBitmap::kIndex8_Config:
+ return Index8_To_ARGB;
+ default:
+ return NULL;
+ }
+}
+
+bool SkARGBImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, int) {
+ const SkBitmap::Config config = bitmap.getConfig();
+ const ScanlineImporter scanline_import = ChooseImporter(config);
+ if (NULL == scanline_import) {
+ return false;
+ }
+
+ SkAutoLockPixels alp(bitmap);
+ const uint8_t* src = (uint8_t*)bitmap.getPixels();
+ if (NULL == bitmap.getPixels()) {
+ return false;
+ }
+
+ SkAutoLockColors ctLocker;
+ const SkPMColor* colors = ctLocker.lockColors(bitmap);
+
+ const int argbStride = bitmap.width() * 4;
+ SkAutoTDeleteArray<uint8_t> ada(new uint8_t[argbStride]);
+ uint8_t* argb = ada.get();
+ for (int y = 0; y < bitmap.height(); ++y) {
+ scanline_import(src + y * bitmap.rowBytes(), argb, bitmap.width(), colors);
+ stream->write(argb, argbStride);
+ }
+
+ return true;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+DEFINE_ENCODER_CREATOR(ARGBImageEncoder);
+///////////////////////////////////////////////////////////////////////////////
diff --git a/src/utils/SkBitmapHasher.cpp b/src/utils/SkBitmapHasher.cpp
index 6df3ab9f27..e8352e59b9 100644
--- a/src/utils/SkBitmapHasher.cpp
+++ b/src/utils/SkBitmapHasher.cpp
@@ -1,4 +1,3 @@
-
/*
* Copyright 2012 Google Inc.
*
@@ -8,63 +7,55 @@
#include "SkBitmap.h"
#include "SkBitmapHasher.h"
-#include "SkBitmapTransformer.h"
#include "SkCityHash.h"
#include "SkEndian.h"
+#include "SkImageEncoder.h"
+#include "SkStream.h"
/**
- * Write an integer value into a bytebuffer in little-endian order.
+ * Write an integer value to a stream in little-endian order.
*/
-static void write_int_to_buffer(int val, char* buf) {
+static void write_int_to_buffer(uint32_t val, SkWStream* out) {
val = SkEndian_SwapLE32(val);
- for (int byte=0; byte<4; byte++) {
- *buf++ = (char)(val & 0xff);
+ for (size_t byte = 0; byte < 4; ++byte) {
+ out->write8((uint8_t)(val & 0xff));
val = val >> 8;
}
}
-/*static*/ bool SkBitmapHasher::ComputeDigestInternal(
- const SkBitmap& bitmap, const SkBitmapTransformer& transformer, SkHashDigest *result) {
- size_t pixelBufferSize = transformer.bytesNeededTotal();
- size_t totalBufferSize = pixelBufferSize + 8; // leave room for x/y dimensions
+/*static*/ bool SkBitmapHasher::ComputeDigestInternal(const SkBitmap& bitmap,
+ SkHashDigest *result) {
+ size_t pixelBufferSize = bitmap.width() * bitmap.height() * 4;
+ size_t totalBufferSize = pixelBufferSize + 2 * sizeof(uint32_t);
SkAutoMalloc bufferManager(totalBufferSize);
char *bufferStart = static_cast<char *>(bufferManager.get());
- char *bufPtr = bufferStart;
+ SkMemoryWStream out(bufferStart, totalBufferSize);
+
// start with the x/y dimensions
- write_int_to_buffer(bitmap.width(), bufPtr);
- bufPtr += 4;
- write_int_to_buffer(bitmap.height(), bufPtr);
- bufPtr += 4;
+ write_int_to_buffer(SkToU32(bitmap.width()), &out);
+ write_int_to_buffer(SkToU32(bitmap.height()), &out);
// add all the pixel data
- if (!transformer.copyBitmapToPixelBuffer(bufPtr, pixelBufferSize)) {
+ SkAutoTDelete<SkImageEncoder> enc(CreateARGBImageEncoder());
+ if (!enc->encodeStream(&out, bitmap, SkImageEncoder::kDefaultQuality)) {
return false;
}
+
*result = SkCityHash::Compute64(bufferStart, totalBufferSize);
return true;
}
/*static*/ bool SkBitmapHasher::ComputeDigest(const SkBitmap& bitmap, SkHashDigest *result) {
- 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 ComputeDigestInternal(bitmap, transformer, result);
+ if (ComputeDigestInternal(bitmap, result)) {
+ return true;
}
// 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 ComputeDigestInternal(copyBitmap, copyTransformer, result);
- } else {
+ if (!bitmap.copyTo(&copyBitmap, SkBitmap::kARGB_8888_Config)) {
return false;
}
+ return ComputeDigestInternal(copyBitmap, result);
}
diff --git a/src/utils/SkBitmapHasher.h b/src/utils/SkBitmapHasher.h
index dc8685bddb..165da3dcc8 100644
--- a/src/utils/SkBitmapHasher.h
+++ b/src/utils/SkBitmapHasher.h
@@ -10,7 +10,6 @@
#define SkBitmapHasher_DEFINED
#include "SkBitmap.h"
-#include "SkBitmapTransformer.h"
// TODO(epoger): Soon, SkHashDigest will become a real class of its own,
// and callers won't be able to assume it converts to/from a uint64_t.
@@ -34,9 +33,7 @@ public:
static bool ComputeDigest(const SkBitmap& bitmap, SkHashDigest *result);
private:
- static bool ComputeDigestInternal(const SkBitmap& bitmap,
- const SkBitmapTransformer& transformer,
- SkHashDigest *result);
+ static bool ComputeDigestInternal(const SkBitmap& bitmap, SkHashDigest *result);
};
#endif
diff --git a/src/utils/SkBitmapTransformer.cpp b/src/utils/SkBitmapTransformer.cpp
deleted file mode 100644
index c8356d4238..0000000000
--- a/src/utils/SkBitmapTransformer.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-
-/*
- * 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
deleted file mode 100644
index 70971ac625..0000000000
--- a/src/utils/SkBitmapTransformer.h
+++ /dev/null
@@ -1,104 +0,0 @@
-
-/*
- * 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
diff --git a/src/utils/SkMD5.h b/src/utils/SkMD5.h
index 6fbdb46b44..6b4fc53636 100644
--- a/src/utils/SkMD5.h
+++ b/src/utils/SkMD5.h
@@ -17,7 +17,7 @@
//SK_CPU_LENDIAN allows 32 bit <=> 8 bit conversions without copies (if alligned).
//SK_CPU_FAST_UNALIGNED_ACCESS allows 32 bit <=> 8 bit conversions without copies if SK_CPU_LENDIAN.
-class SkMD5 : SkWStream {
+class SkMD5 : public SkWStream {
public:
SkMD5();
diff --git a/src/utils/SkSHA1.h b/src/utils/SkSHA1.h
index 10bbc43c50..cf2cb8c679 100644
--- a/src/utils/SkSHA1.h
+++ b/src/utils/SkSHA1.h
@@ -17,7 +17,7 @@
//SK_CPU_BENDIAN allows 32 bit <=> 8 bit conversions without copies (if alligned).
//SK_CPU_FAST_UNALIGNED_ACCESS allows 32 bit <=> 8 bit conversions without copies if SK_CPU_BENDIAN.
-class SkSHA1 : SkWStream {
+class SkSHA1 : public SkWStream {
public:
SkSHA1();