Chromium Code Reviews| Index: ui/gfx/codec/png_codec_unittest.cc |
| =================================================================== |
| --- ui/gfx/codec/png_codec_unittest.cc (revision 123937) |
| +++ ui/gfx/codec/png_codec_unittest.cc (working copy) |
| @@ -2,11 +2,19 @@ |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| +#if defined(USE_SYSTEM_LIBPNG) |
| +#include <png.h> |
| +#else |
| +#include "third_party/libpng/png.h" |
| +#endif |
|
Francois
2012/02/28 15:00:36
Required in order to encode interlaced, palette-ba
|
| + |
| #include <algorithm> |
| #include <cmath> |
| +#include "base/logging.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| +#include "third_party/skia/include/core/SkColorPriv.h" |
| #include "third_party/skia/include/core/SkUnPreMultiply.h" |
| #include "third_party/zlib/zlib.h" |
| #include "ui/gfx/codec/png_codec.h" |
| @@ -14,7 +22,9 @@ |
| namespace gfx { |
| -static void MakeRGBImage(int w, int h, std::vector<unsigned char>* dat) { |
| +namespace { |
| + |
| +void MakeRGBImage(int w, int h, std::vector<unsigned char>* dat) { |
| dat->resize(w * h * 3); |
| for (int y = 0; y < h; y++) { |
| for (int x = 0; x < w; x++) { |
| @@ -30,8 +40,8 @@ |
| // be filled with 0xff. With the alpha channel stripped, this should yield the |
| // same image as MakeRGBImage above, so the code below can make reference |
| // images for conversion testing. |
| -static void MakeRGBAImage(int w, int h, bool use_transparency, |
| - std::vector<unsigned char>* dat) { |
| +void MakeRGBAImage(int w, int h, bool use_transparency, |
| + std::vector<unsigned char>* dat) { |
| dat->resize(w * h * 4); |
| for (int y = 0; y < h; y++) { |
| for (int x = 0; x < w; x++) { |
| @@ -47,6 +57,188 @@ |
| } |
| } |
| +// Creates a palette-based image. |
| +void MakePaletteImage(int w, int h, |
| + std::vector<unsigned char>* dat, |
| + std::vector<png_color>* palette, |
| + std::vector<unsigned char>* trans_chunk = 0) { |
| + dat->resize(w * h); |
| + palette->resize(w); |
| + for (int i = 0; i < w; ++i) { |
| + png_color& color = (*palette)[i]; |
| + color.red = i * 3; |
| + color.green = color.red + 1; |
| + color.blue = color.red + 2; |
| + } |
| + for (int y = 0; y < h; y++) { |
| + for (int x = 0; x < w; x++) { |
| + (*dat)[y * w + x] = x; // palette index |
| + } |
| + } |
| + if (trans_chunk) { |
| + trans_chunk->resize(palette->size()); |
| + for (std::size_t i = 0; i < trans_chunk->size(); ++i) { |
| + (*trans_chunk)[i] = i % 256; |
| + } |
| + } |
| +} |
| + |
| +// Creates a grayscale image without an alpha channel. |
| +void MakeGrayscaleImage(int w, int h, |
| + std::vector<unsigned char>* dat) { |
| + dat->resize(w * h); |
| + for (int y = 0; y < h; y++) { |
| + for (int x = 0; x < w; x++) { |
| + (*dat)[y * w + x] = x; // gray value |
| + } |
| + } |
| +} |
| + |
| +// Creates a grayscale image with an alpha channel. |
| +void MakeGrayscaleAlphaImage(int w, int h, |
| + std::vector<unsigned char>* dat) { |
| + dat->resize(w * h * 2); |
| + for (int y = 0; y < h; y++) { |
| + for (int x = 0; x < w; x++) { |
| + unsigned char* px = &(*dat)[(y * w + x) * 2]; |
| + px[0] = x; // gray value |
| + px[1] = x % 256; // alpha |
| + } |
| + } |
| +} |
| + |
| +// User write function (to be passed to libpng by EncodeImage) which writes |
| +// into a buffer instead of to a file. |
| +void WriteImageData(png_structp png_ptr, |
| + png_bytep data, |
| + png_size_t length) { |
| + std::vector<unsigned char>& v = |
| + *static_cast<std::vector<unsigned char>*>(png_get_io_ptr(png_ptr)); |
| + v.resize(v.size() + length); |
| + memcpy(&v[v.size() - length], data, length); |
| +} |
| + |
| +// User flush function; goes with WriteImageData, above. |
| +void FlushImageData(png_structp) {} |
|
Francois
2012/02/28 15:00:36
Will change this to void FlushImageData(png_struct
Francois
2012/02/29 09:12:29
Done.
|
| + |
| +// Libpng user error function which allows us to print libpng errors using |
| +// Chrome's logging facilities instead of stderr. |
| +void LogLibPNGError(png_structp png_ptr, |
| + png_const_charp error_msg) { |
| + DLOG(ERROR) << "libpng encode error: " << error_msg; |
| + longjmp(png_jmpbuf(png_ptr), 1); |
| +} |
| + |
| +// Goes with LogLibPNGError, above. |
| +void LogLibPNGWarning(png_structp png_ptr, |
| + png_const_charp warning_msg) { |
| + DLOG(ERROR) << "libpng encode warning: " << warning_msg; |
| +} |
| + |
| +// Color types supported by EncodeImage. Required because neither libpng nor |
| +// PNGCodec::Encode supports all of the required values. |
| +enum ColorType { |
| + COLOR_TYPE_GRAY = PNG_COLOR_TYPE_GRAY, |
| + COLOR_TYPE_GRAY_ALPHA = PNG_COLOR_TYPE_GRAY_ALPHA, |
| + COLOR_TYPE_PALETTE = PNG_COLOR_TYPE_PALETTE, |
| + COLOR_TYPE_RGB = PNG_COLOR_TYPE_RGB, |
| + COLOR_TYPE_RGBA = PNG_COLOR_TYPE_RGBA, |
| + COLOR_TYPE_BGR, |
| + COLOR_TYPE_BGRA |
| +}; |
| + |
| +// PNG encoder used for testing. Required because PNGCodec::Encode doesn't do |
| +// interlaced, palette-based, or grayscale images, but PNGCodec::Decode is |
| +// actually asked to decode these types of images by Chrome. |
| +bool EncodeImage(const std::vector<unsigned char>& input, |
| + const int width, |
| + const int height, |
| + ColorType output_color_type, |
| + std::vector<unsigned char>* output, |
| + const int interlace_type = PNG_INTERLACE_NONE, |
| + std::vector<png_color>* palette = 0, |
| + std::vector<unsigned char>* palette_alpha = 0) { |
| + struct ScopedPNGStructs { |
| + ScopedPNGStructs(png_struct** s, png_info** i) : s_(s), i_(i) {} |
| + ~ScopedPNGStructs() { png_destroy_write_struct(s_, i_); } |
| + png_struct** s_; |
| + png_info** i_; |
| + }; |
| + |
| + DCHECK(output); |
| + png_struct* png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, |
| + NULL, NULL, NULL); |
| + if (!png_ptr) return false; |
| + |
| + png_infop info_ptr = png_create_info_struct(png_ptr); |
| + if (!info_ptr) { |
| + png_destroy_write_struct(&png_ptr, NULL); |
| + return false; |
| + } |
| + |
| + ScopedPNGStructs scoped_png_structs(&png_ptr, &info_ptr); |
| + |
| + if (setjmp(png_jmpbuf(png_ptr))) |
| + return false; |
| + |
| + png_set_error_fn(png_ptr, NULL, LogLibPNGError, LogLibPNGWarning); |
| + |
| + int input_rowbytes = 0; |
| + int transforms = PNG_TRANSFORM_IDENTITY; |
| + |
| + switch (output_color_type) { |
| + case COLOR_TYPE_GRAY: |
| + input_rowbytes = width; |
| + break; |
| + case COLOR_TYPE_GRAY_ALPHA: |
| + input_rowbytes = width * 2; |
| + break; |
| + case COLOR_TYPE_PALETTE: |
| + if (!palette) return false; |
| + input_rowbytes = width; |
| + break; |
| + case COLOR_TYPE_RGB: |
| + input_rowbytes = width * 3; |
| + break; |
| + case COLOR_TYPE_RGBA: |
| + input_rowbytes = width * 4; |
| + break; |
| + case COLOR_TYPE_BGRA: |
| + input_rowbytes = width * 4; |
| + output_color_type = static_cast<ColorType>(PNG_COLOR_TYPE_RGBA); |
| + transforms |= PNG_TRANSFORM_BGR; |
| + break; |
| + default: |
| + return false; |
| + break; |
| + }; |
| + |
| + std::vector<png_bytep> row_pointers(height); |
| + for (int y = 0 ; y < height; y++) { |
| + row_pointers[y] = const_cast<unsigned char*>(&input[y * input_rowbytes]); |
| + } |
| + png_set_rows(png_ptr, info_ptr, &row_pointers[0]); |
| + png_set_write_fn(png_ptr, output, WriteImageData, FlushImageData); |
| + png_set_IHDR(png_ptr, info_ptr, width, height, 8, output_color_type, |
| + interlace_type, PNG_COMPRESSION_TYPE_DEFAULT, |
| + PNG_FILTER_TYPE_DEFAULT); |
| + if (output_color_type == COLOR_TYPE_PALETTE) { |
| + png_set_PLTE(png_ptr, info_ptr, &palette->front(), palette->size()); |
| + if (palette_alpha) |
| + png_set_tRNS(png_ptr, |
| + info_ptr, |
| + &palette_alpha->front(), |
| + palette_alpha->size(), |
| + NULL); |
| + } |
| + |
| + png_write_png(png_ptr, info_ptr, transforms, NULL); |
| + |
| + return true; |
| +} |
| + |
| +} // namespace |
| + |
| // Returns true if each channel of the given two colors are "close." This is |
| // used for comparing colors where rounding errors may cause off-by-one. |
| bool ColorsClose(uint32_t a, uint32_t b) { |
| @@ -82,7 +274,7 @@ |
| // encode |
| std::vector<unsigned char> encoded; |
| - EXPECT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB, |
| + ASSERT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB, |
| Size(w, h), w * 3, false, |
| std::vector<PNGCodec::Comment>(), |
| &encoded)); |
| @@ -90,7 +282,7 @@ |
| // decode, it should have the same size as the original |
| std::vector<unsigned char> decoded; |
| int outw, outh; |
| - EXPECT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| + ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| PNGCodec::FORMAT_RGB, &decoded, |
| &outw, &outh)); |
| ASSERT_EQ(w, outw); |
| @@ -111,7 +303,7 @@ |
| // encode |
| std::vector<unsigned char> encoded; |
| - EXPECT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGBA, |
| + ASSERT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGBA, |
| Size(w, h), w * 4, false, |
| std::vector<PNGCodec::Comment>(), |
| &encoded)); |
| @@ -119,7 +311,7 @@ |
| // decode, it should have the same size as the original |
| std::vector<unsigned char> decoded; |
| int outw, outh; |
| - EXPECT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| + ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| PNGCodec::FORMAT_RGBA, &decoded, |
| &outw, &outh)); |
| ASSERT_EQ(w, outw); |
| @@ -130,6 +322,505 @@ |
| ASSERT_TRUE(original == decoded); |
| } |
| +TEST(PNGCodec, EncodeDecodeBGRA) { |
| + const int w = 20, h = 20; |
| + |
| + // Create an image with known values, alpha must be opaque because it will be |
| + // lost during encoding. |
| + std::vector<unsigned char> original; |
| + MakeRGBAImage(w, h, true, &original); |
| + |
| + // Encode. |
| + std::vector<unsigned char> encoded; |
| + ASSERT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_BGRA, |
| + Size(w, h), w * 4, false, |
| + std::vector<PNGCodec::Comment>(), |
| + &encoded)); |
| + |
| + // Decode, it should have the same size as the original. |
| + std::vector<unsigned char> decoded; |
| + int outw, outh; |
| + ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| + PNGCodec::FORMAT_BGRA, &decoded, |
| + &outw, &outh)); |
| + ASSERT_EQ(w, outw); |
| + ASSERT_EQ(h, outh); |
| + ASSERT_EQ(original.size(), decoded.size()); |
| + |
| + // Images must be exactly equal. |
| + ASSERT_TRUE(original == decoded); |
| +} |
|
Francois
2012/02/28 15:00:36
Old code moved from further down.
|
| + |
| +TEST(PNGCodec, DecodePalette) { |
| + const int w = 20, h = 20; |
| + |
| + // create an image with known values |
| + std::vector<unsigned char> original; |
| + std::vector<png_color> original_palette; |
| + std::vector<unsigned char> original_trans_chunk; |
| + MakePaletteImage(w, h, &original, &original_palette, &original_trans_chunk); |
| + |
| + // encode |
| + std::vector<unsigned char> encoded; |
| + ASSERT_TRUE(EncodeImage(original, |
| + w, h, |
| + COLOR_TYPE_PALETTE, |
| + &encoded, |
| + PNG_INTERLACE_NONE, |
| + &original_palette, |
| + &original_trans_chunk)); |
| + |
| + // decode |
| + std::vector<unsigned char> decoded; |
| + int outw, outh; |
| + ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| + PNGCodec::FORMAT_RGBA, &decoded, |
| + &outw, &outh)); |
| + ASSERT_EQ(w, outw); |
| + ASSERT_EQ(h, outh); |
| + ASSERT_EQ(decoded.size(), w * h * 4U); |
| + |
| + // Images must be equal |
| + for (int y = 0; y < h; ++y) { |
| + for (int x = 0; x < w; ++x) { |
| + unsigned char palette_pixel = original[y * w + x]; |
| + png_color& palette_color = original_palette[palette_pixel]; |
| + int alpha = original_trans_chunk[palette_pixel]; |
| + unsigned char* rgba_pixel = &decoded[(y * w + x) * 4]; |
| + |
| + ASSERT_EQ(palette_color.red, rgba_pixel[0]); |
| + ASSERT_EQ(palette_color.green, rgba_pixel[1]); |
| + ASSERT_EQ(palette_color.blue, rgba_pixel[2]); |
| + ASSERT_EQ(alpha, rgba_pixel[3]); |
| + } |
| + } |
| +} |
| + |
| +TEST(PNGCodec, DecodePaletteDiscardAlpha) { |
| + const int w = 20, h = 20; |
| + |
| + // create an image with known values |
| + std::vector<unsigned char> original; |
| + std::vector<png_color> original_palette; |
| + std::vector<unsigned char> original_trans_chunk; |
| + MakePaletteImage(w, h, &original, &original_palette, &original_trans_chunk); |
| + |
| + // encode |
| + std::vector<unsigned char> encoded; |
| + ASSERT_TRUE(EncodeImage(original, |
| + w, h, |
| + COLOR_TYPE_PALETTE, |
| + &encoded, |
| + PNG_INTERLACE_NONE, |
| + &original_palette, |
| + &original_trans_chunk)); |
| + |
| + // decode |
| + std::vector<unsigned char> decoded; |
| + int outw, outh; |
| + ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| + PNGCodec::FORMAT_RGB, &decoded, |
| + &outw, &outh)); |
| + ASSERT_EQ(w, outw); |
| + ASSERT_EQ(h, outh); |
| + ASSERT_EQ(decoded.size(), w * h * 3U); |
| + |
| + // Images must be equal |
| + for (int y = 0; y < h; ++y) { |
| + for (int x = 0; x < w; ++x) { |
| + unsigned char palette_pixel = original[y * w + x]; |
| + png_color& palette_color = original_palette[palette_pixel]; |
| + unsigned char* rgba_pixel = &decoded[(y * w + x) * 3]; |
| + |
| + ASSERT_EQ(palette_color.red, rgba_pixel[0]); |
| + ASSERT_EQ(palette_color.green, rgba_pixel[1]); |
| + ASSERT_EQ(palette_color.blue, rgba_pixel[2]); |
| + } |
| + } |
| +} |
| + |
| +TEST(PNGCodec, DecodeInterlacedPalette) { |
| + const int w = 20, h = 20; |
| + |
| + // create an image with known values |
| + std::vector<unsigned char> original; |
| + std::vector<png_color> original_palette; |
| + std::vector<unsigned char> original_trans_chunk; |
| + MakePaletteImage(w, h, &original, &original_palette, &original_trans_chunk); |
| + |
| + // encode |
| + std::vector<unsigned char> encoded; |
| + ASSERT_TRUE(EncodeImage(original, |
| + w, h, |
| + COLOR_TYPE_PALETTE, |
| + &encoded, |
| + PNG_INTERLACE_ADAM7, |
| + &original_palette, |
| + &original_trans_chunk)); |
| + |
| + // decode |
| + std::vector<unsigned char> decoded; |
| + int outw, outh; |
| + ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| + PNGCodec::FORMAT_RGBA, &decoded, |
| + &outw, &outh)); |
| + ASSERT_EQ(w, outw); |
| + ASSERT_EQ(h, outh); |
| + ASSERT_EQ(decoded.size(), w * h * 4U); |
| + |
| + // Images must be equal |
| + for (int y = 0; y < h; ++y) { |
| + for (int x = 0; x < w; ++x) { |
| + unsigned char palette_pixel = original[y * w + x]; |
| + png_color& palette_color = original_palette[palette_pixel]; |
| + int alpha = original_trans_chunk[palette_pixel]; |
| + unsigned char* rgba_pixel = &decoded[(y * w + x) * 4]; |
| + |
| + ASSERT_EQ(palette_color.red, rgba_pixel[0]); |
| + ASSERT_EQ(palette_color.green, rgba_pixel[1]); |
| + ASSERT_EQ(palette_color.blue, rgba_pixel[2]); |
| + ASSERT_EQ(alpha, rgba_pixel[3]); |
| + } |
| + } |
| +} |
| + |
| +TEST(PNGCodec, DecodeGrayscale) { |
| + const int w = 20, h = 20; |
| + |
| + // create an image with known values |
| + std::vector<unsigned char> original; |
| + MakeGrayscaleImage(w, h, &original); |
| + |
| + // encode |
| + std::vector<unsigned char> encoded; |
| + ASSERT_TRUE(EncodeImage(original, w, h, COLOR_TYPE_GRAY, &encoded)); |
| + |
| + // decode |
| + std::vector<unsigned char> decoded; |
| + int outw, outh; |
| + ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| + PNGCodec::FORMAT_RGB, &decoded, |
| + &outw, &outh)); |
| + ASSERT_EQ(w, outw); |
| + ASSERT_EQ(h, outh); |
| + ASSERT_EQ(decoded.size(), original.size() * 3); |
| + |
| + // Images must be equal |
| + for (int y = 0; y < h; ++y) { |
| + for (int x = 0; x < w; ++x) { |
| + unsigned char gray_pixel = original[(y * w + x)]; |
| + unsigned char* rgba_pixel = &decoded[(y * w + x) * 3]; |
| + ASSERT_EQ(rgba_pixel[0], gray_pixel); |
| + ASSERT_EQ(rgba_pixel[1], gray_pixel); |
| + ASSERT_EQ(rgba_pixel[2], gray_pixel); |
| + } |
| + } |
| +} |
| + |
| +TEST(PNGCodec, DecodeGrayscaleWithAlpha) { |
| + const int w = 20, h = 20; |
| + |
| + // create an image with known values |
| + std::vector<unsigned char> original; |
| + MakeGrayscaleAlphaImage(w, h, &original); |
| + |
| + // encode |
| + std::vector<unsigned char> encoded; |
| + ASSERT_TRUE(EncodeImage(original, |
| + w, h, |
| + COLOR_TYPE_GRAY_ALPHA, |
| + &encoded)); |
| + |
| + // decode |
| + std::vector<unsigned char> decoded; |
| + int outw, outh; |
| + ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| + PNGCodec::FORMAT_RGBA, &decoded, |
| + &outw, &outh)); |
| + ASSERT_EQ(w, outw); |
| + ASSERT_EQ(h, outh); |
| + ASSERT_EQ(decoded.size(), original.size() * 2); |
| + |
| + // Images must be equal |
| + for (int y = 0; y < h; ++y) { |
| + for (int x = 0; x < w; ++x) { |
| + unsigned char* gray_pixel = &original[(y * w + x) * 2]; |
| + unsigned char* rgba_pixel = &decoded[(y * w + x) * 4]; |
| + ASSERT_EQ(rgba_pixel[0], gray_pixel[0]); |
| + ASSERT_EQ(rgba_pixel[1], gray_pixel[0]); |
| + ASSERT_EQ(rgba_pixel[2], gray_pixel[0]); |
| + ASSERT_EQ(rgba_pixel[3], gray_pixel[1]); |
| + } |
| + } |
| +} |
| + |
| +TEST(PNGCodec, DecodeGrayscaleWithAlphaDiscardAlpha) { |
| + const int w = 20, h = 20; |
| + |
| + // create an image with known values |
| + std::vector<unsigned char> original; |
| + MakeGrayscaleAlphaImage(w, h, &original); |
| + |
| + // encode |
| + std::vector<unsigned char> encoded; |
| + ASSERT_TRUE(EncodeImage(original, |
| + w, h, |
| + COLOR_TYPE_GRAY_ALPHA, |
| + &encoded)); |
| + |
| + // decode |
| + std::vector<unsigned char> decoded; |
| + int outw, outh; |
| + ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| + PNGCodec::FORMAT_RGB, &decoded, |
| + &outw, &outh)); |
| + ASSERT_EQ(w, outw); |
| + ASSERT_EQ(h, outh); |
| + ASSERT_EQ(decoded.size(), w * h * 3U); |
| + |
| + // Images must be equal |
| + for (int y = 0; y < h; ++y) { |
| + for (int x = 0; x < w; ++x) { |
| + unsigned char* gray_pixel = &original[(y * w + x) * 2]; |
| + unsigned char* rgba_pixel = &decoded[(y * w + x) * 3]; |
| + ASSERT_EQ(rgba_pixel[0], gray_pixel[0]); |
| + ASSERT_EQ(rgba_pixel[1], gray_pixel[0]); |
| + ASSERT_EQ(rgba_pixel[2], gray_pixel[0]); |
| + } |
| + } |
| +} |
| + |
| +TEST(PNGCodec, DecodeInterlacedGrayscale) { |
| + const int w = 20, h = 20; |
| + |
| + // create an image with known values |
| + std::vector<unsigned char> original; |
| + MakeGrayscaleImage(w, h, &original); |
| + |
| + // encode |
| + std::vector<unsigned char> encoded; |
| + ASSERT_TRUE(EncodeImage(original, |
| + w, h, |
| + COLOR_TYPE_GRAY, |
| + &encoded, |
| + PNG_INTERLACE_ADAM7)); |
| + |
| + // decode |
| + std::vector<unsigned char> decoded; |
| + int outw, outh; |
| + ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| + PNGCodec::FORMAT_RGBA, &decoded, |
| + &outw, &outh)); |
| + ASSERT_EQ(w, outw); |
| + ASSERT_EQ(h, outh); |
| + ASSERT_EQ(decoded.size(), original.size() * 4); |
| + |
| + // Images must be equal |
| + for (int y = 0; y < h; ++y) { |
| + for (int x = 0; x < w; ++x) { |
| + unsigned char gray_pixel = original[(y * w + x)]; |
| + unsigned char* rgba_pixel = &decoded[(y * w + x) * 4]; |
| + ASSERT_EQ(rgba_pixel[0], gray_pixel); |
| + ASSERT_EQ(rgba_pixel[1], gray_pixel); |
| + ASSERT_EQ(rgba_pixel[2], gray_pixel); |
| + ASSERT_EQ(rgba_pixel[3], 0xFF); |
| + } |
| + } |
| +} |
| + |
| +TEST(PNGCodec, DecodeInterlacedGrayscaleWithAlpha) { |
| + const int w = 20, h = 20; |
| + |
| + // create an image with known values |
| + std::vector<unsigned char> original; |
| + MakeGrayscaleAlphaImage(w, h, &original); |
| + |
| + // encode |
| + std::vector<unsigned char> encoded; |
| + ASSERT_TRUE(EncodeImage(original, |
| + w, h, |
| + COLOR_TYPE_GRAY_ALPHA, |
| + &encoded, |
| + PNG_INTERLACE_ADAM7)); |
| + |
| + // decode |
| + std::vector<unsigned char> decoded; |
| + int outw, outh; |
| + ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| + PNGCodec::FORMAT_RGBA, &decoded, |
| + &outw, &outh)); |
| + ASSERT_EQ(w, outw); |
| + ASSERT_EQ(h, outh); |
| + ASSERT_EQ(decoded.size(), original.size() * 2); |
| + |
| + // Images must be equal |
| + for (int y = 0; y < h; ++y) { |
| + for (int x = 0; x < w; ++x) { |
| + unsigned char* gray_pixel = &original[(y * w + x) * 2]; |
| + unsigned char* rgba_pixel = &decoded[(y * w + x) * 4]; |
| + ASSERT_EQ(rgba_pixel[0], gray_pixel[0]); |
| + ASSERT_EQ(rgba_pixel[1], gray_pixel[0]); |
| + ASSERT_EQ(rgba_pixel[2], gray_pixel[0]); |
| + ASSERT_EQ(rgba_pixel[3], gray_pixel[1]); |
| + } |
| + } |
| +} |
| + |
| +TEST(PNGCodec, DecodeInterlacedRGB) { |
| + const int w = 20, h = 20; |
| + |
| + // create an image with known values |
| + std::vector<unsigned char> original; |
| + MakeRGBImage(w, h, &original); |
| + |
| + // encode |
| + std::vector<unsigned char> encoded; |
| + ASSERT_TRUE(EncodeImage(original, |
| + w, h, |
| + COLOR_TYPE_RGB, |
| + &encoded, |
| + PNG_INTERLACE_ADAM7)); |
| + |
| + // decode, it should have the same size as the original |
| + std::vector<unsigned char> decoded; |
| + int outw, outh; |
| + ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| + PNGCodec::FORMAT_RGB, &decoded, |
| + &outw, &outh)); |
| + ASSERT_EQ(w, outw); |
| + ASSERT_EQ(h, outh); |
| + ASSERT_EQ(original.size(), decoded.size()); |
| + |
| + // Images must be equal |
| + ASSERT_EQ(original, decoded); |
| +} |
| + |
| +TEST(PNGCodec, DecodeInterlacedRGBA) { |
| + const int w = 20, h = 20; |
| + |
| + // create an image with known values |
| + std::vector<unsigned char> original; |
| + MakeRGBAImage(w, h, false, &original); |
| + |
| + // encode |
| + std::vector<unsigned char> encoded; |
| + ASSERT_TRUE(EncodeImage(original, |
| + w, h, |
| + COLOR_TYPE_RGBA, |
| + &encoded, |
| + PNG_INTERLACE_ADAM7)); |
| + |
| + // decode, it should have the same size as the original |
| + std::vector<unsigned char> decoded; |
| + int outw, outh; |
| + ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| + PNGCodec::FORMAT_RGBA, &decoded, |
| + &outw, &outh)); |
| + ASSERT_EQ(w, outw); |
| + ASSERT_EQ(h, outh); |
| + ASSERT_EQ(original.size(), decoded.size()); |
| + |
| + // Images must be equal |
| + ASSERT_EQ(original, decoded); |
| +} |
| + |
| +TEST(PNGCodec, DecodeInterlacedBGRA) { |
| + const int w = 20, h = 20; |
| + |
| + // create an image with known values |
| + std::vector<unsigned char> original; |
| + MakeRGBAImage(w, h, false, &original); |
| + |
| + // encode |
| + std::vector<unsigned char> encoded; |
| + ASSERT_TRUE(EncodeImage(original, |
| + w, h, |
| + COLOR_TYPE_BGRA, |
| + &encoded, |
| + PNG_INTERLACE_ADAM7)); |
| + |
| + // decode, it should have the same size as the original |
| + std::vector<unsigned char> decoded; |
| + int outw, outh; |
| + ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| + PNGCodec::FORMAT_BGRA, &decoded, |
| + &outw, &outh)); |
| + ASSERT_EQ(w, outw); |
| + ASSERT_EQ(h, outh); |
| + ASSERT_EQ(original.size(), decoded.size()); |
| + |
| + // Images must be equal |
| + ASSERT_EQ(original, decoded); |
| +} |
| + |
| +// Not encoding an interlaced PNG from SkBitmap because we don't do it |
| +// anywhere, and the ability to do that requires more code changes. |
| +TEST(PNGCodec, DecodeInterlacedRGBtoSkBitmap) { |
| + const int w = 20, h = 20; |
| + |
| + // create an image with known values |
| + std::vector<unsigned char> original; |
| + MakeRGBImage(w, h, &original); |
| + |
| + // encode |
| + std::vector<unsigned char> encoded; |
| + ASSERT_TRUE(EncodeImage(original, |
| + w, h, |
| + COLOR_TYPE_RGB, |
| + &encoded, |
| + PNG_INTERLACE_ADAM7)); |
| + |
| + // Decode the encoded string. |
| + SkBitmap decoded_bitmap; |
| + ASSERT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(), |
| + &decoded_bitmap)); |
| + |
| + for (int x = 0; x < w; x++) { |
| + for (int y = 0; y < h; y++) { |
| + const unsigned char* original_pixel = &original[(y * w + x) * 3]; |
| + const uint32_t original_pixel_sk = SkPackARGB32(0xFF, |
| + original_pixel[0], |
| + original_pixel[1], |
| + original_pixel[2]); |
| + const uint32_t decoded_pixel = decoded_bitmap.getAddr32(0, y)[x]; |
| + ASSERT_EQ(original_pixel_sk, decoded_pixel); |
| + } |
| + } |
| +} |
| + |
| +TEST(PNGCodec, DecodeInterlacedRGBAtoSkBitmap) { |
| + const int w = 20, h = 20; |
| + |
| + // create an image with known values |
| + std::vector<unsigned char> original; |
| + MakeRGBAImage(w, h, false, &original); |
| + |
| + // encode |
| + std::vector<unsigned char> encoded; |
| + ASSERT_TRUE(EncodeImage(original, |
| + w, h, |
| + COLOR_TYPE_RGBA, |
| + &encoded, |
| + PNG_INTERLACE_ADAM7)); |
| + |
| + // Decode the encoded string. |
| + SkBitmap decoded_bitmap; |
| + ASSERT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(), |
| + &decoded_bitmap)); |
| + |
| + for (int x = 0; x < w; x++) { |
| + for (int y = 0; y < h; y++) { |
| + const unsigned char* original_pixel = &original[(y * w + x) * 4]; |
| + const uint32_t original_pixel_sk = SkPackARGB32(original_pixel[3], |
| + original_pixel[0], |
| + original_pixel[1], |
| + original_pixel[2]); |
| + const uint32_t decoded_pixel = decoded_bitmap.getAddr32(0, y)[x]; |
| + ASSERT_EQ(original_pixel_sk, decoded_pixel); |
| + } |
| + } |
| +} |
| + |
| // Test that corrupted data decompression causes failures. |
| TEST(PNGCodec, DecodeCorrupted) { |
| int w = 20, h = 20; |
| @@ -147,7 +838,7 @@ |
| // Make some compressed data. |
| std::vector<unsigned char> compressed; |
| - EXPECT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB, |
| + ASSERT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB, |
| Size(w, h), w * 3, false, |
| std::vector<PNGCodec::Comment>(), |
| &compressed)); |
| @@ -165,35 +856,6 @@ |
| &outw, &outh)); |
| } |
| -TEST(PNGCodec, EncodeDecodeBGRA) { |
| - const int w = 20, h = 20; |
| - |
| - // Create an image with known values, alpha must be opaque because it will be |
| - // lost during encoding. |
| - std::vector<unsigned char> original; |
| - MakeRGBAImage(w, h, true, &original); |
| - |
| - // Encode. |
| - std::vector<unsigned char> encoded; |
| - EXPECT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_BGRA, |
| - Size(w, h), w * 4, false, |
| - std::vector<PNGCodec::Comment>(), |
| - &encoded)); |
| - |
| - // Decode, it should have the same size as the original. |
| - std::vector<unsigned char> decoded; |
| - int outw, outh; |
| - EXPECT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| - PNGCodec::FORMAT_BGRA, &decoded, |
| - &outw, &outh)); |
| - ASSERT_EQ(w, outw); |
| - ASSERT_EQ(h, outh); |
| - ASSERT_EQ(original.size(), decoded.size()); |
| - |
| - // Images must be exactly equal. |
| - ASSERT_TRUE(original == decoded); |
|
Francois
2012/02/28 15:00:36
This function was moved further up.
|
| -} |
| - |
| TEST(PNGCodec, StripAddAlpha) { |
| const int w = 20, h = 20; |
| @@ -221,7 +883,7 @@ |
| ASSERT_EQ(w, outw); |
| ASSERT_EQ(h, outh); |
| ASSERT_EQ(original_rgba.size(), decoded.size()); |
| - ASSERT_TRUE(original_rgba == decoded); |
| + ASSERT_EQ(original_rgba, decoded); |
| // Encode RGBA to RGBA. |
| EXPECT_TRUE(PNGCodec::Encode(&original_rgba[0], PNGCodec::FORMAT_RGBA, |
| @@ -238,7 +900,7 @@ |
| ASSERT_EQ(w, outw); |
| ASSERT_EQ(h, outh); |
| ASSERT_EQ(original_rgb.size(), decoded.size()); |
| - ASSERT_TRUE(original_rgb == decoded); |
| + ASSERT_EQ(original_rgb, decoded); |
| } |
| TEST(PNGCodec, EncodeBGRASkBitmap) { |