ARGB image encoder for checksums.
https://codereview.chromium.org/14267031/


git-svn-id: http://skia.googlecode.com/svn/trunk@8831 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gyp/images.gyp b/gyp/images.gyp
index d062d09..c96ff4d 100644
--- a/gyp/images.gyp
+++ b/gyp/images.gyp
@@ -47,6 +47,7 @@
         '../src/images/SkImageDecoder_wbmp.cpp',
         '../src/images/SkImageEncoder.cpp',
         '../src/images/SkImageEncoder_Factory.cpp',
+        '../src/images/SkImageEncoder_argb.cpp',
         '../src/images/SkImageRef.cpp',
         '../src/images/SkImageRefPool.cpp',
         '../src/images/SkImageRefPool.h',
diff --git a/gyp/tests.gyp b/gyp/tests.gyp
index b95b4a6..ef6994e 100644
--- a/gyp/tests.gyp
+++ b/gyp/tests.gyp
@@ -23,13 +23,13 @@
       'sources': [
         '../tests/AAClipTest.cpp',
         '../tests/AnnotationTest.cpp',
+        '../tests/ARGBImageEncoderTest.cpp',
         '../tests/AtomicTest.cpp',
         '../tests/BitmapCopyTest.cpp',
         '../tests/BitmapFactoryTest.cpp',
         '../tests/BitmapGetColorTest.cpp',
         '../tests/BitmapHasherTest.cpp',
         '../tests/BitmapHeapTest.cpp',
-        '../tests/BitmapTransformerTest.cpp',
         '../tests/BitSetTest.cpp',
         '../tests/BlitRowTest.cpp',
         '../tests/BlurTest.cpp',
diff --git a/gyp/utils.gyp b/gyp/utils.gyp
index a14f585..169bfbf 100644
--- a/gyp/utils.gyp
+++ b/gyp/utils.gyp
@@ -12,6 +12,7 @@
         '../include/config',
         '../include/core',
         '../include/effects',
+        '../include/images',
         '../include/pipe',
         '../include/utils',
         '../include/utils/mac',
@@ -59,8 +60,6 @@
         '../src/utils/SkBase64.h',
         '../src/utils/SkBitmapHasher.cpp',
         '../src/utils/SkBitmapHasher.h',
-        '../src/utils/SkBitmapTransformer.cpp',
-        '../src/utils/SkBitmapTransformer.h',
         '../src/utils/SkBitSet.cpp',
         '../src/utils/SkBitSet.h',
         '../src/utils/SkBoundaryPatch.cpp',
diff --git a/include/images/SkImageEncoder.h b/include/images/SkImageEncoder.h
index 5db32c3..0f7d18a 100644
--- a/include/images/SkImageEncoder.h
+++ b/include/images/SkImageEncoder.h
@@ -83,6 +83,11 @@
 
 // All the encoders known by Skia. Note that, depending on the compiler settings,
 // not all of these will be available
+/** An ARGBImageEncoder will always write out
+ *  bitmap.width() * bitmap.height() * 4
+ *  bytes.
+ */
+DECLARE_ENCODER_CREATOR(ARGBImageEncoder);
 DECLARE_ENCODER_CREATOR(JPEGImageEncoder);
 DECLARE_ENCODER_CREATOR(PNGImageEncoder);
 DECLARE_ENCODER_CREATOR(WEBPImageEncoder);
diff --git a/src/images/SkImageEncoder_argb.cpp b/src/images/SkImageEncoder_argb.cpp
new file mode 100644
index 0000000..5abc23c
--- /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 6df3ab9..e8352e5 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 dc8685b..165da3d 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 @@
     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 c8356d4..0000000
--- 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 70971ac..0000000
--- 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 6fbdb46..6b4fc53 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 10bbc43..cf2cb8c 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();
 
diff --git a/tests/ARGBImageEncoderTest.cpp b/tests/ARGBImageEncoderTest.cpp
new file mode 100644
index 0000000..05ad58c
--- /dev/null
+++ b/tests/ARGBImageEncoderTest.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/** Tests for ARGBImageEncoder. */
+
+#include "Test.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkImageEncoder.h"
+#include "SkStream.h"
+
+namespace skiatest {
+
+class BitmapTransformerTestClass : public Test {
+public:
+    static Test* Factory(void*) { return SkNEW(BitmapTransformerTestClass); }
+protected:
+    virtual void onGetName(SkString* name) SK_OVERRIDE { name->set("ARGBImageEncoder"); }
+    virtual void onRun(Reporter* reporter) SK_OVERRIDE;
+};
+
+static SkBitmap::Config configs[] = {
+        SkBitmap::kRGB_565_Config,
+        SkBitmap::kARGB_4444_Config,
+        SkBitmap::kARGB_8888_Config,
+};
+
+void BitmapTransformerTestClass::onRun(Reporter* reporter) {
+    // Bytes we expect to get:
+    const int kWidth = 3;
+    const int kHeight = 5;
+    const unsigned char comparisonBuffer[] = {
+        // kHeight rows, each with kWidth pixels, premultiplied ARGB for each pixel
+        0xff,0xff,0x00,0x00, 0xff,0xff,0x00,0x00, 0xff,0xff,0x00,0x00, // red
+        0xff,0x00,0xff,0x00, 0xff,0x00,0xff,0x00, 0xff,0x00,0xff,0x00, // green
+        0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, // blue
+        0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, // blue
+        0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, // blue
+    };
+
+    SkAutoTDelete<SkImageEncoder> enc(CreateARGBImageEncoder());
+    for (size_t configIndex = 0; configIndex < SK_ARRAY_COUNT(configs); ++configIndex) {
+        // A bitmap that should generate the above bytes:
+        SkBitmap bitmap;
+        {
+            bitmap.setConfig(configs[configIndex], kWidth, kHeight);
+            REPORTER_ASSERT(reporter, bitmap.allocPixels());
+            bitmap.setIsOpaque(true);
+            bitmap.eraseColor(SK_ColorBLUE);
+            // Change rows [0,1] from blue to [red,green].
+            SkCanvas canvas(bitmap);
+            SkPaint paint;
+            paint.setColor(SK_ColorRED);
+            canvas.drawIRect(SkIRect::MakeLTRB(0, 0, kWidth, 1), paint);
+            paint.setColor(SK_ColorGREEN);
+            canvas.drawIRect(SkIRect::MakeLTRB(0, 1, kWidth, 2), paint);
+        }
+
+        // Transform the bitmap.
+        int bufferSize = bitmap.width() * bitmap.height() * 4;
+        SkAutoMalloc pixelBufferManager(bufferSize);
+        char *pixelBuffer = static_cast<char *>(pixelBufferManager.get());
+        SkMemoryWStream out(pixelBuffer, bufferSize);
+        REPORTER_ASSERT(reporter, enc->encodeStream(&out, bitmap, SkImageEncoder::kDefaultQuality));
+
+        // Confirm we got the expected results.
+        REPORTER_ASSERT(reporter, bufferSize == sizeof(comparisonBuffer));
+        REPORTER_ASSERT(reporter, memcmp(pixelBuffer, comparisonBuffer, bufferSize) == 0);
+    }
+}
+
+static TestRegistry gReg(BitmapTransformerTestClass::Factory);
+
+}
diff --git a/tests/BitmapTransformerTest.cpp b/tests/BitmapTransformerTest.cpp
deleted file mode 100644
index d9ce696..0000000
--- a/tests/BitmapTransformerTest.cpp
+++ /dev/null
@@ -1,97 +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.
- */
-
-/**
- * Tests for SkBitmapTransformer.h and SkBitmapTransformer.cpp
- */
-
-#include "Test.h"
-#include "SkBitmap.h"
-#include "SkBitmapTransformer.h"
-
-namespace skiatest {
-    class BitmapTransformerTestClass : public Test {
-    public:
-        static Test* Factory(void*) {return SkNEW(BitmapTransformerTestClass); }
-    protected:
-        virtual void onGetName(SkString* name) { name->set("BitmapTransformer"); }
-        virtual void onRun(Reporter* reporter) {
-            this->fReporter = reporter;
-            RunTest();
-        }
-    private:
-        void RunTest() {
-            SkBitmap bitmap;
-            SkBitmap::Config supportedConfig = SkBitmap::kARGB_8888_Config;
-            SkBitmap::Config unsupportedConfig = SkBitmap::kARGB_4444_Config;
-            SkBitmapTransformer::PixelFormat supportedPixelFormat =
-                SkBitmapTransformer::kARGB_8888_Premul_PixelFormat;
-            const int kWidth = 55;
-            const int kHeight = 333;
-
-            // Transformations that we know are unsupported:
-            {
-                bitmap.setConfig(unsupportedConfig, kWidth, kHeight);
-                SkBitmapTransformer transformer = SkBitmapTransformer(bitmap, supportedPixelFormat);
-                REPORTER_ASSERT(fReporter, !transformer.isValid());
-            }
-
-            // Valid transformations:
-            {
-                // Bytes we expect to get:
-                const int kWidth = 3;
-                const int kHeight = 5;
-                const unsigned char comparisonBuffer[] = {
-                    // kHeight rows, each with kWidth pixels, premultiplied ARGB for each pixel
-                    0xff,0xff,0x00,0x00, 0xff,0xff,0x00,0x00, 0xff,0xff,0x00,0x00, // red
-                    0xff,0x00,0xff,0x00, 0xff,0x00,0xff,0x00, 0xff,0x00,0xff,0x00, // green
-                    0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, // blue
-                    0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, // blue
-                    0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, // blue
-                };
-
-                // A bitmap that should generate the above bytes:
-                bitmap.setConfig(supportedConfig, kWidth, kHeight);
-                REPORTER_ASSERT(fReporter, bitmap.allocPixels());
-                bitmap.setIsOpaque(true);
-                bitmap.eraseColor(SK_ColorBLUE);
-                bitmap.lockPixels();
-                // Change rows [0,1] from blue to [red,green].
-                SkColor oldColor = SK_ColorBLUE;
-                SkColor newColors[] = {SK_ColorRED, SK_ColorGREEN};
-                for (int y = 0; y <= 1; y++) {
-                    for (int x = 0; x < kWidth; x++) {
-                        REPORTER_ASSERT(fReporter, bitmap.getColor(x, y) == oldColor);
-                        SkPMColor* pixel = static_cast<SkPMColor *>(bitmap.getAddr(x, y));
-                        *pixel = SkPreMultiplyColor(newColors[y]);
-                        REPORTER_ASSERT(fReporter, bitmap.getColor(x, y) == newColors[y]);
-                    }
-                }
-                bitmap.unlockPixels();
-
-                // Transform the bitmap and confirm we got the expected results.
-                SkBitmapTransformer transformer = SkBitmapTransformer(bitmap, supportedPixelFormat);
-                REPORTER_ASSERT(fReporter, transformer.isValid());
-                REPORTER_ASSERT(fReporter, transformer.bytesNeededPerRow() == kWidth * 4);
-                REPORTER_ASSERT(fReporter, transformer.bytesNeededTotal() == kWidth * kHeight * 4);
-                int bufferSize = transformer.bytesNeededTotal();
-                SkAutoMalloc pixelBufferManager(bufferSize);
-                char *pixelBuffer = static_cast<char *>(pixelBufferManager.get());
-                REPORTER_ASSERT(fReporter,
-                                transformer.copyBitmapToPixelBuffer(pixelBuffer, bufferSize));
-                REPORTER_ASSERT(fReporter, bufferSize == sizeof(comparisonBuffer));
-                REPORTER_ASSERT(fReporter, memcmp(pixelBuffer, comparisonBuffer, bufferSize) == 0);
-            }
-
-        }
-
-        Reporter* fReporter;
-    };
-
-    static TestRegistry gReg(BitmapTransformerTestClass::Factory);
-}