Support RGBA/BGRA Premul/Unpremul from SkPNGImageEncoder

BUG=skia:5616
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2325223002

Review-Url: https://codereview.chromium.org/2325223002
diff --git a/src/images/SkPNGImageEncoder.cpp b/src/images/SkPNGImageEncoder.cpp
index a9c8b3d..b30cd25 100644
--- a/src/images/SkPNGImageEncoder.cpp
+++ b/src/images/SkPNGImageEncoder.cpp
@@ -58,30 +58,30 @@
     }
 }
 
-static transform_scanline_proc choose_proc(SkColorType ct, bool hasAlpha) {
-    // we don't care about search on alpha if we're kIndex8, since only the
-    // colortable packing cares about that distinction, not the pixels
-    if (kIndex_8_SkColorType == ct) {
-        hasAlpha = false;   // we store false in the table entries for kIndex8
-    }
-
+static transform_scanline_proc choose_proc(SkColorType ct, SkAlphaType alphaType) {
     static const struct {
         SkColorType             fColorType;
-        bool                    fHasAlpha;
+        SkAlphaType             fAlphaType;
         transform_scanline_proc fProc;
     } gMap[] = {
-        { kRGB_565_SkColorType,     false,  transform_scanline_565 },
-        { kN32_SkColorType,         false,  transform_scanline_888 },
-        { kN32_SkColorType,         true,   transform_scanline_8888 },
-        { kARGB_4444_SkColorType,   false,  transform_scanline_444 },
-        { kARGB_4444_SkColorType,   true,   transform_scanline_4444 },
-        { kIndex_8_SkColorType,     false,  transform_scanline_memcpy },
-        { kGray_8_SkColorType,      false,  transform_scanline_memcpy },
+        { kRGB_565_SkColorType,   kOpaque_SkAlphaType,   transform_scanline_565    },
+        { kRGBA_8888_SkColorType, kOpaque_SkAlphaType,   transform_scanline_RGBX   },
+        { kBGRA_8888_SkColorType, kOpaque_SkAlphaType,   transform_scanline_BGRX   },
+        { kRGBA_8888_SkColorType, kPremul_SkAlphaType,   transform_scanline_rgbA   },
+        { kBGRA_8888_SkColorType, kPremul_SkAlphaType,   transform_scanline_bgrA   },
+        { kRGBA_8888_SkColorType, kUnpremul_SkAlphaType, transform_scanline_memcpy },
+        { kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, transform_scanline_BGRA   },
+        { kARGB_4444_SkColorType, kOpaque_SkAlphaType,   transform_scanline_444    },
+        { kARGB_4444_SkColorType, kPremul_SkAlphaType,   transform_scanline_4444   },
+        { kIndex_8_SkColorType,   kOpaque_SkAlphaType,   transform_scanline_memcpy },
+        { kIndex_8_SkColorType,   kPremul_SkAlphaType,   transform_scanline_memcpy },
+        { kIndex_8_SkColorType,   kUnpremul_SkAlphaType, transform_scanline_memcpy },
+        { kGray_8_SkColorType,    kOpaque_SkAlphaType,   transform_scanline_memcpy },
     };
 
-    for (int i = SK_ARRAY_COUNT(gMap) - 1; i >= 0; --i) {
-        if (gMap[i].fColorType == ct && gMap[i].fHasAlpha == hasAlpha) {
-            return gMap[i].fProc;
+    for (auto entry : gMap) {
+        if (entry.fColorType == ct && entry.fAlphaType == alphaType) {
+            return entry.fProc;
         }
     }
     sk_throw();
@@ -112,12 +112,12 @@
 */
 static inline int pack_palette(SkColorTable* ctable,
                                png_color* SK_RESTRICT palette,
-                               png_byte* SK_RESTRICT trans, bool hasAlpha) {
+                               png_byte* SK_RESTRICT trans, SkAlphaType alphaType) {
     const SkPMColor* SK_RESTRICT colors = ctable ? ctable->readColors() : nullptr;
     const int ctCount = ctable->count();
     int i, num_trans = 0;
 
-    if (hasAlpha) {
+    if (kOpaque_SkAlphaType != alphaType) {
         /*  first see if we have some number of fully opaque at the end of the
             ctable. PNG allows num_trans < num_palette, but all of the trans
             entries must come first in the palette. If I was smarter, I'd
@@ -134,18 +134,27 @@
             num_trans -= 1;
         }
 
-        const SkUnPreMultiply::Scale* SK_RESTRICT table =
-                                            SkUnPreMultiply::GetScaleTable();
-
-        for (i = 0; i < num_trans; i++) {
-            const SkPMColor c = *colors++;
-            const unsigned a = SkGetPackedA32(c);
-            const SkUnPreMultiply::Scale s = table[a];
-            trans[i] = a;
-            palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c));
-            palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32(c));
-            palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c));
+        if (kPremul_SkAlphaType == alphaType) {
+            const SkUnPreMultiply::Scale* SK_RESTRICT table = SkUnPreMultiply::GetScaleTable();
+            for (i = 0; i < num_trans; i++) {
+                const SkPMColor c = *colors++;
+                const unsigned a = SkGetPackedA32(c);
+                const SkUnPreMultiply::Scale s = table[a];
+                trans[i] = a;
+                palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c));
+                palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32(c));
+                palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c));
+            }
+        } else {
+            for (i = 0; i < num_trans; i++) {
+                const SkPMColor c = *colors++;
+                trans[i] = SkGetPackedA32(c);
+                palette[i].red = SkGetPackedR32(c);
+                palette[i].green = SkGetPackedG32(c);
+                palette[i].blue = SkGetPackedB32(c);
+            }
         }
+
         // now fall out of this if-block to use common code for the trailing
         // opaque entries
     }
@@ -165,7 +174,7 @@
     bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override;
 private:
     bool doEncode(SkWStream* stream, const SkBitmap& bm,
-                  const bool& hasAlpha, int colorType,
+                  SkAlphaType alphaType, int colorType,
                   int bitDepth, SkColorType ct,
                   png_color_8& sig_bit);
 
@@ -180,12 +189,12 @@
     switch (originalBitmap.colorType()) {
         case kIndex_8_SkColorType:
         case kGray_8_SkColorType:
-        case kN32_SkColorType:
+        case kRGBA_8888_SkColorType:
+        case kBGRA_8888_SkColorType:
         case kARGB_4444_SkColorType:
         case kRGB_565_SkColorType:
             break;
         default:
-            // TODO(scroggo): support 8888-but-not-N32 natively.
             // TODO(scroggo): support Alpha_8 as Grayscale(black)+Alpha
             if (originalBitmap.copyTo(&copy, kN32_SkColorType)) {
                 bitmap = &copy;
@@ -193,7 +202,22 @@
     }
     SkColorType ct = bitmap->colorType();
 
-    const bool hasAlpha = !bitmap->isOpaque();
+    const SkAlphaType alphaType = bitmap->alphaType();
+    switch (alphaType) {
+        case kUnpremul_SkAlphaType:
+            if (kARGB_4444_SkColorType == ct) {
+                return false;
+            }
+
+            break;
+        case kOpaque_SkAlphaType:
+        case kPremul_SkAlphaType:
+            break;
+        default:
+            return false;
+    }
+
+    const bool isOpaque = (kOpaque_SkAlphaType == alphaType);
     int bitDepth = 8;   // default for color
     png_color_8 sig_bit;
     sk_bzero(&sig_bit, sizeof(png_color_8));
@@ -210,28 +234,29 @@
         case kGray_8_SkColorType:
             sig_bit.gray = 8;
             colorType = PNG_COLOR_TYPE_GRAY;
-            SkASSERT(!hasAlpha);
+            SkASSERT(isOpaque);
             break;
-        case kN32_SkColorType:
+        case kRGBA_8888_SkColorType:
+        case kBGRA_8888_SkColorType:
             sig_bit.red = 8;
             sig_bit.green = 8;
             sig_bit.blue = 8;
             sig_bit.alpha = 8;
-            colorType = hasAlpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB;
+            colorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA;
             break;
         case kARGB_4444_SkColorType:
             sig_bit.red = 4;
             sig_bit.green = 4;
             sig_bit.blue = 4;
             sig_bit.alpha = 4;
-            colorType = hasAlpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB;
+            colorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA;
             break;
         case kRGB_565_SkColorType:
             sig_bit.red = 5;
             sig_bit.green = 6;
             sig_bit.blue = 5;
             colorType = PNG_COLOR_TYPE_RGB;
-            SkASSERT(!hasAlpha);
+            SkASSERT(isOpaque);
             break;
         default:
             return false;
@@ -253,11 +278,11 @@
         bitDepth = computeBitDepth(ctable->count());
     }
 
-    return doEncode(stream, *bitmap, hasAlpha, colorType, bitDepth, ct, sig_bit);
+    return doEncode(stream, *bitmap, alphaType, colorType, bitDepth, ct, sig_bit);
 }
 
 bool SkPNGImageEncoder::doEncode(SkWStream* stream, const SkBitmap& bitmap,
-                  const bool& hasAlpha, int colorType,
+                  SkAlphaType alphaType, int colorType,
                   int bitDepth, SkColorType ct,
                   png_color_8& sig_bit) {
 
@@ -304,9 +329,9 @@
     png_color paletteColors[256];
     png_byte trans[256];
     if (kIndex_8_SkColorType == ct) {
-        SkColorTable* ct = bitmap.getColorTable();
-        int numTrans = pack_palette(ct, paletteColors, trans, hasAlpha);
-        png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count());
+        SkColorTable* colorTable = bitmap.getColorTable();
+        int numTrans = pack_palette(colorTable, paletteColors, trans, alphaType);
+        png_set_PLTE(png_ptr, info_ptr, paletteColors, colorTable->count());
         if (numTrans > 0) {
             png_set_tRNS(png_ptr, info_ptr, trans, numTrans, nullptr);
         }
@@ -318,11 +343,11 @@
     const char* srcImage = (const char*)bitmap.getPixels();
     SkAutoSTMalloc<1024, char> rowStorage(bitmap.width() << 2);
     char* storage = rowStorage.get();
-    transform_scanline_proc proc = choose_proc(ct, hasAlpha);
+    transform_scanline_proc proc = choose_proc(ct, alphaType);
 
     for (int y = 0; y < bitmap.height(); y++) {
         png_bytep row_ptr = (png_bytep)storage;
-        proc(srcImage, bitmap.width(), storage);
+        proc(storage, srcImage, bitmap.width(), SkColorTypeBytesPerPixel(ct));
         png_write_rows(png_ptr, &row_ptr, 1);
         srcImage += bitmap.rowBytes();
     }
diff --git a/src/images/transform_scanline.h b/src/images/transform_scanline.h
index 4baf6b6..a02e98a 100644
--- a/src/images/transform_scanline.h
+++ b/src/images/transform_scanline.h
@@ -19,16 +19,17 @@
  * Function template for transforming scanlines.
  * Transform 'width' pixels from 'src' buffer into 'dst' buffer,
  * repacking color channel data as appropriate for the given transformation.
+ * 'bpp' is bytes per pixel in the 'src' buffer.
  */
-typedef void (*transform_scanline_proc)(const char* SK_RESTRICT src,
-                                        int width, char* SK_RESTRICT dst);
+typedef void (*transform_scanline_proc)(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
+                                        int width, int bpp);
 
 /**
  * Identity transformation: just copy bytes from src to dst.
  */
-static void transform_scanline_memcpy(const char* SK_RESTRICT src, int width,
-                                      char* SK_RESTRICT dst) {
-    memcpy(dst, src, width);
+static void transform_scanline_memcpy(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
+                                      int width, int bpp) {
+    memcpy(dst, src, width * bpp);
 }
 
 /**
@@ -36,9 +37,9 @@
  * Alpha channel data is not present in kRGB_565_Config format, so there is no
  * alpha channel data to preserve.
  */
-static void transform_scanline_565(const char* SK_RESTRICT src, int width,
-                                   char* SK_RESTRICT dst) {
-    const uint16_t* SK_RESTRICT srcP = (const uint16_t*)src;
+static void transform_scanline_565(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
+                                   int width, int) {
+    const uint16_t* srcP = (const uint16_t*)src;
     for (int i = 0; i < width; i++) {
         unsigned c = *srcP++;
         *dst++ = SkPacked16ToR32(c);
@@ -48,17 +49,32 @@
 }
 
 /**
- * Transform from kARGB_8888_Config to 3-bytes-per-pixel RGB.
- * Alpha channel data, if any, is abandoned.
+ * Transform from kRGBA_8888_SkColorType to 3-bytes-per-pixel RGB.
+ * Alpha channel data is abandoned.
  */
-static void transform_scanline_888(const char* SK_RESTRICT src, int width,
-                                   char* SK_RESTRICT dst) {
-    const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src;
+static void transform_scanline_RGBX(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
+                                    int width, int) {
+    const uint32_t* srcP = (const SkPMColor*)src;
     for (int i = 0; i < width; i++) {
-        SkPMColor c = *srcP++;
-        *dst++ = SkGetPackedR32(c);
-        *dst++ = SkGetPackedG32(c);
-        *dst++ = SkGetPackedB32(c);
+        uint32_t c = *srcP++;
+        *dst++ = (c >>  0) & 0xFF;
+        *dst++ = (c >>  8) & 0xFF;
+        *dst++ = (c >> 16) & 0xFF;
+    }
+}
+
+/**
+ * Transform from kBGRA_8888_SkColorType to 3-bytes-per-pixel RGB.
+ * Alpha channel data is abandoned.
+ */
+static void transform_scanline_BGRX(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
+                                    int width, int) {
+    const uint32_t* srcP = (const SkPMColor*)src;
+    for (int i = 0; i < width; i++) {
+        uint32_t c = *srcP++;
+        *dst++ = (c >> 16) & 0xFF;
+        *dst++ = (c >>  8) & 0xFF;
+        *dst++ = (c >>  0) & 0xFF;
     }
 }
 
@@ -66,9 +82,9 @@
  * Transform from kARGB_4444_Config to 3-bytes-per-pixel RGB.
  * Alpha channel data, if any, is abandoned.
  */
-static void transform_scanline_444(const char* SK_RESTRICT src, int width,
-                                   char* SK_RESTRICT dst) {
-    const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src;
+static void transform_scanline_444(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
+                                   int width, int) {
+    const SkPMColor16* srcP = (const SkPMColor16*)src;
     for (int i = 0; i < width; i++) {
         SkPMColor16 c = *srcP++;
         *dst++ = SkPacked4444ToR32(c);
@@ -77,23 +93,26 @@
     }
 }
 
-/**
- * Transform from kARGB_8888_Config to 4-bytes-per-pixel RGBA.
- * (This would be the identity transformation, except for byte-order and
- * scaling of RGB based on alpha channel).
- */
-static void transform_scanline_8888(const char* SK_RESTRICT src, int width,
-                                    char* SK_RESTRICT dst) {
-    const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src;
-    const SkUnPreMultiply::Scale* SK_RESTRICT table =
-                                              SkUnPreMultiply::GetScaleTable();
+template <bool kIsRGBA>
+static inline void transform_scanline_unpremultiply(char* SK_RESTRICT dst,
+                                                    const char* SK_RESTRICT src, int width, int) {
+    const uint32_t* srcP = (const SkPMColor*)src;
+    const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
 
     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);
+        uint32_t c = *srcP++;
+        unsigned r, g, b, a;
+        if (kIsRGBA) {
+            r = (c >>  0) & 0xFF;
+            g = (c >>  8) & 0xFF;
+            b = (c >> 16) & 0xFF;
+            a = (c >> 24) & 0xFF;
+        } else {
+            r = (c >> 16) & 0xFF;
+            g = (c >>  8) & 0xFF;
+            b = (c >>  0) & 0xFF;
+            a = (c >> 24) & 0xFF;
+        }
 
         if (0 != a && 255 != a) {
             SkUnPreMultiply::Scale scale = table[a];
@@ -109,14 +128,44 @@
 }
 
 /**
+ * Transform from kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
+ */
+static void transform_scanline_rgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
+                                    int width, int bpp) {
+    transform_scanline_unpremultiply<true>(dst, src, width, bpp);
+}
+
+/**
+ * Transform from kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
+ */
+static void transform_scanline_bgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
+                                    int width, int bpp) {
+    transform_scanline_unpremultiply<false>(dst, src, width, bpp);
+}
+
+/**
+ * Transform from kUnpremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
+ */
+static void transform_scanline_BGRA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
+                                    int width, int) {
+    const uint32_t* srcP = (const SkPMColor*)src;
+    for (int i = 0; i < width; i++) {
+        uint32_t c = *srcP++;
+        *dst++ = (c >> 16) & 0xFF;
+        *dst++ = (c >>  8) & 0xFF;
+        *dst++ = (c >>  0) & 0xFF;
+        *dst++ = (c >> 24) & 0xFF;
+    }
+}
+
+/**
  * Transform from kARGB_8888_Config to 4-bytes-per-pixel RGBA,
  * with scaling of RGB based on alpha channel.
  */
-static void transform_scanline_4444(const char* SK_RESTRICT src, int width,
-                                    char* SK_RESTRICT dst) {
-    const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src;
-    const SkUnPreMultiply::Scale* SK_RESTRICT table =
-                                              SkUnPreMultiply::GetScaleTable();
+static void transform_scanline_4444(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
+                                    int width, int) {
+    const SkPMColor16* srcP = (const SkPMColor16*)src;
+    const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
 
     for (int i = 0; i < width; i++) {
         SkPMColor16 c = *srcP++;
diff --git a/tests/CodecTest.cpp b/tests/CodecTest.cpp
index 348bc64..044c2fd 100644
--- a/tests/CodecTest.cpp
+++ b/tests/CodecTest.cpp
@@ -1073,22 +1073,53 @@
     check_color_xform(r, "mandrill_512.png");
 }
 
-static void check_round_trip(skiatest::Reporter* r, const SkBitmap& bm1) {
-    SkColorType origColorType = bm1.colorType();
-    SkAlphaType origAlphaType = bm1.alphaType();
+static bool color_type_match(SkColorType origColorType, SkColorType codecColorType) {
+    switch (origColorType) {
+        case kRGBA_8888_SkColorType:
+        case kBGRA_8888_SkColorType:
+            return kRGBA_8888_SkColorType == codecColorType ||
+                   kBGRA_8888_SkColorType == codecColorType;
+        default:
+            return origColorType == codecColorType;
+    }
+}
+
+static bool alpha_type_match(SkAlphaType origAlphaType, SkAlphaType codecAlphaType) {
+    switch (origAlphaType) {
+        case kUnpremul_SkAlphaType:
+        case kPremul_SkAlphaType:
+            return kUnpremul_SkAlphaType == codecAlphaType ||
+                    kPremul_SkAlphaType == codecAlphaType;
+        default:
+            return origAlphaType == codecAlphaType;
+    }
+}
+
+static void check_round_trip(skiatest::Reporter* r, SkCodec* origCodec, const SkImageInfo& info) {
+    SkBitmap bm1;
+    SkPMColor colors[256];
+    SkAutoTUnref<SkColorTable> colorTable1(new SkColorTable(colors, 256));
+    bm1.allocPixels(info, nullptr, colorTable1.get());
+    int numColors;
+    SkCodec::Result result = origCodec->getPixels(info, bm1.getPixels(), bm1.rowBytes(), nullptr,
+                                                  const_cast<SkPMColor*>(colorTable1->readColors()),
+                                                  &numColors);
+    // This will fail to update colorTable1->count() but is fine for the purpose of this test.
+    REPORTER_ASSERT(r, SkCodec::kSuccess == result);
 
     // Encode the image to png.
     sk_sp<SkData> data =
             sk_sp<SkData>(SkImageEncoder::EncodeData(bm1, SkImageEncoder::kPNG_Type, 100));
 
-    // Prepare to decode.  The codec should recognize that the PNG is 565.
     SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(data));
-    REPORTER_ASSERT(r, origColorType == codec->getInfo().colorType());
-    REPORTER_ASSERT(r, origAlphaType == codec->getInfo().alphaType());
+    REPORTER_ASSERT(r, color_type_match(info.colorType(), codec->getInfo().colorType()));
+    REPORTER_ASSERT(r, alpha_type_match(info.alphaType(), codec->getInfo().alphaType()));
 
     SkBitmap bm2;
-    bm2.allocPixels(codec->getInfo());
-    SkCodec::Result result = codec->getPixels(codec->getInfo(), bm2.getPixels(), bm2.rowBytes());
+    SkAutoTUnref<SkColorTable> colorTable2(new SkColorTable(colors, 256));
+    bm2.allocPixels(info, nullptr, colorTable2.get());
+    result = codec->getPixels(info, bm2.getPixels(), bm2.rowBytes(), nullptr,
+                              const_cast<SkPMColor*>(colorTable2->readColors()), &numColors);
     REPORTER_ASSERT(r, SkCodec::kSuccess == result);
 
     SkMD5::Digest d1, d2;
@@ -1098,26 +1129,52 @@
 }
 
 DEF_TEST(Codec_PngRoundTrip, r) {
-    // Create an arbitrary 565 bitmap.
     const char* path = "mandrill_512_q075.jpg";
     SkAutoTDelete<SkStream> stream(resource(path));
     SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release()));
-    SkImageInfo info565 = codec->getInfo().makeColorType(kRGB_565_SkColorType);
-    SkBitmap bm1;
-    bm1.allocPixels(info565);
-    SkCodec::Result result = codec->getPixels(info565, bm1.getPixels(), bm1.rowBytes());
-    REPORTER_ASSERT(r, SkCodec::kSuccess == result);
-    check_round_trip(r, bm1);
 
-    // Create an arbitrary gray bitmap.
+    SkColorType colorTypesOpaque[] = {
+            kRGB_565_SkColorType, kRGBA_8888_SkColorType, kBGRA_8888_SkColorType
+    };
+    for (SkColorType colorType : colorTypesOpaque) {
+        SkImageInfo newInfo = codec->getInfo().makeColorType(colorType);
+        check_round_trip(r, codec.get(), newInfo);
+    }
+
     path = "grayscale.jpg";
     stream.reset(resource(path));
     codec.reset(SkCodec::NewFromStream(stream.release()));
-    SkBitmap bm2;
-    bm2.allocPixels(codec->getInfo());
-    result = codec->getPixels(codec->getInfo(), bm2.getPixels(), bm2.rowBytes());
-    REPORTER_ASSERT(r, SkCodec::kSuccess == result);
-    check_round_trip(r, bm2);
+    check_round_trip(r, codec.get(), codec->getInfo());
+
+    path = "yellow_rose.png";
+    stream.reset(resource(path));
+    codec.reset(SkCodec::NewFromStream(stream.release()));
+
+    SkColorType colorTypesWithAlpha[] = {
+            kRGBA_8888_SkColorType, kBGRA_8888_SkColorType
+    };
+    SkAlphaType alphaTypes[] = {
+            kUnpremul_SkAlphaType, kPremul_SkAlphaType
+    };
+    for (SkColorType colorType : colorTypesWithAlpha) {
+        for (SkAlphaType alphaType : alphaTypes) {
+            // Set color space to nullptr because color correct premultiplies do not round trip.
+            SkImageInfo newInfo = codec->getInfo().makeColorType(colorType)
+                                                  .makeAlphaType(alphaType)
+                                                  .makeColorSpace(nullptr);
+            check_round_trip(r, codec.get(), newInfo);
+        }
+    }
+
+    path = "index8.png";
+    stream.reset(resource(path));
+    codec.reset(SkCodec::NewFromStream(stream.release()));
+
+    for (SkAlphaType alphaType : alphaTypes) {
+        SkImageInfo newInfo = codec->getInfo().makeAlphaType(alphaType)
+                                              .makeColorSpace(nullptr);
+        check_round_trip(r, codec.get(), newInfo);
+    }
 }
 
 static void test_conversion_possible(skiatest::Reporter* r, const char* path,