| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #if defined(USE_SYSTEM_LIBPNG) |
| 6 #include <png.h> |
| 7 #else |
| 8 #include "third_party/libpng/png.h" |
| 9 #endif |
| 10 |
| 5 #include <algorithm> | 11 #include <algorithm> |
| 6 #include <cmath> | 12 #include <cmath> |
| 7 | 13 |
| 14 #include "base/logging.h" |
| 8 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
| 9 #include "third_party/skia/include/core/SkBitmap.h" | 16 #include "third_party/skia/include/core/SkBitmap.h" |
| 17 #include "third_party/skia/include/core/SkColorPriv.h" |
| 10 #include "third_party/skia/include/core/SkUnPreMultiply.h" | 18 #include "third_party/skia/include/core/SkUnPreMultiply.h" |
| 11 #include "third_party/zlib/zlib.h" | 19 #include "third_party/zlib/zlib.h" |
| 12 #include "ui/gfx/codec/png_codec.h" | 20 #include "ui/gfx/codec/png_codec.h" |
| 13 #include "ui/gfx/size.h" | 21 #include "ui/gfx/size.h" |
| 14 | 22 |
| 15 namespace gfx { | 23 namespace gfx { |
| 16 | 24 |
| 17 static void MakeRGBImage(int w, int h, std::vector<unsigned char>* dat) { | 25 namespace { |
| 26 |
| 27 void MakeRGBImage(int w, int h, std::vector<unsigned char>* dat) { |
| 18 dat->resize(w * h * 3); | 28 dat->resize(w * h * 3); |
| 19 for (int y = 0; y < h; y++) { | 29 for (int y = 0; y < h; y++) { |
| 20 for (int x = 0; x < w; x++) { | 30 for (int x = 0; x < w; x++) { |
| 21 unsigned char* org_px = &(*dat)[(y * w + x) * 3]; | 31 unsigned char* org_px = &(*dat)[(y * w + x) * 3]; |
| 22 org_px[0] = x * 3; // r | 32 org_px[0] = x * 3; // r |
| 23 org_px[1] = x * 3 + 1; // g | 33 org_px[1] = x * 3 + 1; // g |
| 24 org_px[2] = x * 3 + 2; // b | 34 org_px[2] = x * 3 + 2; // b |
| 25 } | 35 } |
| 26 } | 36 } |
| 27 } | 37 } |
| 28 | 38 |
| 29 // Set use_transparency to write data into the alpha channel, otherwise it will | 39 // Set use_transparency to write data into the alpha channel, otherwise it will |
| 30 // be filled with 0xff. With the alpha channel stripped, this should yield the | 40 // be filled with 0xff. With the alpha channel stripped, this should yield the |
| 31 // same image as MakeRGBImage above, so the code below can make reference | 41 // same image as MakeRGBImage above, so the code below can make reference |
| 32 // images for conversion testing. | 42 // images for conversion testing. |
| 33 static void MakeRGBAImage(int w, int h, bool use_transparency, | 43 void MakeRGBAImage(int w, int h, bool use_transparency, |
| 34 std::vector<unsigned char>* dat) { | 44 std::vector<unsigned char>* dat) { |
| 35 dat->resize(w * h * 4); | 45 dat->resize(w * h * 4); |
| 36 for (int y = 0; y < h; y++) { | 46 for (int y = 0; y < h; y++) { |
| 37 for (int x = 0; x < w; x++) { | 47 for (int x = 0; x < w; x++) { |
| 38 unsigned char* org_px = &(*dat)[(y * w + x) * 4]; | 48 unsigned char* org_px = &(*dat)[(y * w + x) * 4]; |
| 39 org_px[0] = x * 3; // r | 49 org_px[0] = x * 3; // r |
| 40 org_px[1] = x * 3 + 1; // g | 50 org_px[1] = x * 3 + 1; // g |
| 41 org_px[2] = x * 3 + 2; // b | 51 org_px[2] = x * 3 + 2; // b |
| 42 if (use_transparency) | 52 if (use_transparency) |
| 43 org_px[3] = x*3 + 3; // a | 53 org_px[3] = x*3 + 3; // a |
| 44 else | 54 else |
| 45 org_px[3] = 0xFF; // a (opaque) | 55 org_px[3] = 0xFF; // a (opaque) |
| 46 } | 56 } |
| 47 } | 57 } |
| 48 } | 58 } |
| 49 | 59 |
| 60 // User write function (to be passed to libpng by EncodeImage) which writes |
| 61 // into a buffer instead of to a file. |
| 62 void WriteImageData(png_structp png_ptr, |
| 63 png_bytep data, |
| 64 png_size_t length) { |
| 65 std::vector<unsigned char>& v = |
| 66 *static_cast<std::vector<unsigned char>*>(png_get_io_ptr(png_ptr)); |
| 67 v.resize(v.size() + length); |
| 68 memcpy(&v[v.size() - length], data, length); |
| 69 } |
| 70 |
| 71 // User flush function; goes with WriteImageData, above. |
| 72 void FlushImageData(png_structp /*png_ptr*/) { |
| 73 } |
| 74 |
| 75 // Libpng user error function which allows us to print libpng errors using |
| 76 // Chrome's logging facilities instead of stderr. |
| 77 void LogLibPNGError(png_structp png_ptr, |
| 78 png_const_charp error_msg) { |
| 79 DLOG(ERROR) << "libpng encode error: " << error_msg; |
| 80 longjmp(png_jmpbuf(png_ptr), 1); |
| 81 } |
| 82 |
| 83 // Goes with LogLibPNGError, above. |
| 84 void LogLibPNGWarning(png_structp png_ptr, |
| 85 png_const_charp warning_msg) { |
| 86 DLOG(ERROR) << "libpng encode warning: " << warning_msg; |
| 87 } |
| 88 |
| 89 // Color types supported by EncodeImage. Required because neither libpng nor |
| 90 // PNGCodec::Encode supports all of the required values. |
| 91 enum ColorType { |
| 92 COLOR_TYPE_GRAY = PNG_COLOR_TYPE_GRAY, |
| 93 COLOR_TYPE_GRAY_ALPHA = PNG_COLOR_TYPE_GRAY_ALPHA, |
| 94 COLOR_TYPE_PALETTE = PNG_COLOR_TYPE_PALETTE, |
| 95 COLOR_TYPE_RGB = PNG_COLOR_TYPE_RGB, |
| 96 COLOR_TYPE_RGBA = PNG_COLOR_TYPE_RGBA, |
| 97 COLOR_TYPE_BGR, |
| 98 COLOR_TYPE_BGRA |
| 99 }; |
| 100 |
| 101 // PNG encoder used for testing. Required because PNGCodec::Encode doesn't do |
| 102 // interlaced, palette-based, or grayscale images, but PNGCodec::Decode is |
| 103 // actually asked to decode these types of images by Chrome. |
| 104 bool EncodeImage(const std::vector<unsigned char>& input, |
| 105 const int width, |
| 106 const int height, |
| 107 ColorType output_color_type, |
| 108 std::vector<unsigned char>* output, |
| 109 const int interlace_type = PNG_INTERLACE_NONE, |
| 110 std::vector<png_color>* palette = 0, |
| 111 std::vector<unsigned char>* palette_alpha = 0) { |
| 112 struct ScopedPNGStructs { |
| 113 ScopedPNGStructs(png_struct** s, png_info** i) : s_(s), i_(i) {} |
| 114 ~ScopedPNGStructs() { png_destroy_write_struct(s_, i_); } |
| 115 png_struct** s_; |
| 116 png_info** i_; |
| 117 }; |
| 118 |
| 119 DCHECK(output); |
| 120 png_struct* png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, |
| 121 NULL, NULL, NULL); |
| 122 if (!png_ptr) |
| 123 return false; |
| 124 |
| 125 png_infop info_ptr = png_create_info_struct(png_ptr); |
| 126 if (!info_ptr) { |
| 127 png_destroy_write_struct(&png_ptr, NULL); |
| 128 return false; |
| 129 } |
| 130 |
| 131 ScopedPNGStructs scoped_png_structs(&png_ptr, &info_ptr); |
| 132 |
| 133 if (setjmp(png_jmpbuf(png_ptr))) |
| 134 return false; |
| 135 |
| 136 png_set_error_fn(png_ptr, NULL, LogLibPNGError, LogLibPNGWarning); |
| 137 |
| 138 int input_rowbytes = 0; |
| 139 int transforms = PNG_TRANSFORM_IDENTITY; |
| 140 |
| 141 switch (output_color_type) { |
| 142 case COLOR_TYPE_GRAY: |
| 143 input_rowbytes = width; |
| 144 break; |
| 145 case COLOR_TYPE_GRAY_ALPHA: |
| 146 input_rowbytes = width * 2; |
| 147 break; |
| 148 case COLOR_TYPE_PALETTE: |
| 149 if (!palette) |
| 150 return false; |
| 151 input_rowbytes = width; |
| 152 break; |
| 153 case COLOR_TYPE_RGB: |
| 154 input_rowbytes = width * 3; |
| 155 break; |
| 156 case COLOR_TYPE_RGBA: |
| 157 input_rowbytes = width * 4; |
| 158 break; |
| 159 case COLOR_TYPE_BGR: |
| 160 input_rowbytes = width * 3; |
| 161 output_color_type = static_cast<ColorType>(PNG_COLOR_TYPE_RGB); |
| 162 transforms |= PNG_TRANSFORM_BGR; |
| 163 break; |
| 164 case COLOR_TYPE_BGRA: |
| 165 input_rowbytes = width * 4; |
| 166 output_color_type = static_cast<ColorType>(PNG_COLOR_TYPE_RGBA); |
| 167 transforms |= PNG_TRANSFORM_BGR; |
| 168 break; |
| 169 }; |
| 170 |
| 171 std::vector<png_bytep> row_pointers(height); |
| 172 for (int y = 0 ; y < height; y++) { |
| 173 row_pointers[y] = const_cast<unsigned char*>(&input[y * input_rowbytes]); |
| 174 } |
| 175 png_set_rows(png_ptr, info_ptr, &row_pointers[0]); |
| 176 png_set_write_fn(png_ptr, output, WriteImageData, FlushImageData); |
| 177 png_set_IHDR(png_ptr, info_ptr, width, height, 8, output_color_type, |
| 178 interlace_type, PNG_COMPRESSION_TYPE_DEFAULT, |
| 179 PNG_FILTER_TYPE_DEFAULT); |
| 180 if (output_color_type == COLOR_TYPE_PALETTE) { |
| 181 png_set_PLTE(png_ptr, info_ptr, &palette->front(), palette->size()); |
| 182 if (palette_alpha) { |
| 183 png_set_tRNS(png_ptr, |
| 184 info_ptr, |
| 185 &palette_alpha->front(), |
| 186 palette_alpha->size(), |
| 187 NULL); |
| 188 } |
| 189 } |
| 190 |
| 191 png_write_png(png_ptr, info_ptr, transforms, NULL); |
| 192 |
| 193 return true; |
| 194 } |
| 195 |
| 196 } // namespace |
| 197 |
| 50 // Returns true if each channel of the given two colors are "close." This is | 198 // Returns true if each channel of the given two colors are "close." This is |
| 51 // used for comparing colors where rounding errors may cause off-by-one. | 199 // used for comparing colors where rounding errors may cause off-by-one. |
| 52 bool ColorsClose(uint32_t a, uint32_t b) { | 200 bool ColorsClose(uint32_t a, uint32_t b) { |
| 53 return abs(static_cast<int>(SkColorGetB(a) - SkColorGetB(b))) < 2 && | 201 return abs(static_cast<int>(SkColorGetB(a) - SkColorGetB(b))) < 2 && |
| 54 abs(static_cast<int>(SkColorGetG(a) - SkColorGetG(b))) < 2 && | 202 abs(static_cast<int>(SkColorGetG(a) - SkColorGetG(b))) < 2 && |
| 55 abs(static_cast<int>(SkColorGetR(a) - SkColorGetR(b))) < 2 && | 203 abs(static_cast<int>(SkColorGetR(a) - SkColorGetR(b))) < 2 && |
| 56 abs(static_cast<int>(SkColorGetA(a) - SkColorGetA(b))) < 2; | 204 abs(static_cast<int>(SkColorGetA(a) - SkColorGetA(b))) < 2; |
| 57 } | 205 } |
| 58 | 206 |
| 59 // Returns true if the RGB components are "close." | 207 // Returns true if the RGB components are "close." |
| (...skipping 15 matching lines...) Expand all Loading... |
| 75 | 223 |
| 76 TEST(PNGCodec, EncodeDecodeRGB) { | 224 TEST(PNGCodec, EncodeDecodeRGB) { |
| 77 const int w = 20, h = 20; | 225 const int w = 20, h = 20; |
| 78 | 226 |
| 79 // create an image with known values | 227 // create an image with known values |
| 80 std::vector<unsigned char> original; | 228 std::vector<unsigned char> original; |
| 81 MakeRGBImage(w, h, &original); | 229 MakeRGBImage(w, h, &original); |
| 82 | 230 |
| 83 // encode | 231 // encode |
| 84 std::vector<unsigned char> encoded; | 232 std::vector<unsigned char> encoded; |
| 85 EXPECT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB, | 233 ASSERT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB, |
| 86 Size(w, h), w * 3, false, | 234 Size(w, h), w * 3, false, |
| 87 std::vector<PNGCodec::Comment>(), | 235 std::vector<PNGCodec::Comment>(), |
| 88 &encoded)); | 236 &encoded)); |
| 89 | 237 |
| 90 // decode, it should have the same size as the original | 238 // decode, it should have the same size as the original |
| 91 std::vector<unsigned char> decoded; | 239 std::vector<unsigned char> decoded; |
| 92 int outw, outh; | 240 int outw, outh; |
| 93 EXPECT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), | 241 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| 94 PNGCodec::FORMAT_RGB, &decoded, | 242 PNGCodec::FORMAT_RGB, &decoded, |
| 95 &outw, &outh)); | 243 &outw, &outh)); |
| 96 ASSERT_EQ(w, outw); | 244 ASSERT_EQ(w, outw); |
| 97 ASSERT_EQ(h, outh); | 245 ASSERT_EQ(h, outh); |
| 98 ASSERT_EQ(original.size(), decoded.size()); | 246 ASSERT_EQ(original.size(), decoded.size()); |
| 99 | 247 |
| 100 // Images must be equal | 248 // Images must be equal |
| 101 ASSERT_TRUE(original == decoded); | 249 ASSERT_TRUE(original == decoded); |
| 102 } | 250 } |
| 103 | 251 |
| 104 TEST(PNGCodec, EncodeDecodeRGBA) { | 252 TEST(PNGCodec, EncodeDecodeRGBA) { |
| 105 const int w = 20, h = 20; | 253 const int w = 20, h = 20; |
| 106 | 254 |
| 107 // create an image with known values, a must be opaque because it will be | 255 // create an image with known values, a must be opaque because it will be |
| 108 // lost during encoding | 256 // lost during encoding |
| 109 std::vector<unsigned char> original; | 257 std::vector<unsigned char> original; |
| 110 MakeRGBAImage(w, h, true, &original); | 258 MakeRGBAImage(w, h, true, &original); |
| 111 | 259 |
| 112 // encode | 260 // encode |
| 113 std::vector<unsigned char> encoded; | 261 std::vector<unsigned char> encoded; |
| 114 EXPECT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGBA, | 262 ASSERT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGBA, |
| 115 Size(w, h), w * 4, false, | 263 Size(w, h), w * 4, false, |
| 116 std::vector<PNGCodec::Comment>(), | 264 std::vector<PNGCodec::Comment>(), |
| 117 &encoded)); | 265 &encoded)); |
| 118 | 266 |
| 119 // decode, it should have the same size as the original | 267 // decode, it should have the same size as the original |
| 120 std::vector<unsigned char> decoded; | 268 std::vector<unsigned char> decoded; |
| 121 int outw, outh; | 269 int outw, outh; |
| 122 EXPECT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), | 270 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| 123 PNGCodec::FORMAT_RGBA, &decoded, | 271 PNGCodec::FORMAT_RGBA, &decoded, |
| 124 &outw, &outh)); | 272 &outw, &outh)); |
| 125 ASSERT_EQ(w, outw); | 273 ASSERT_EQ(w, outw); |
| 126 ASSERT_EQ(h, outh); | 274 ASSERT_EQ(h, outh); |
| 127 ASSERT_EQ(original.size(), decoded.size()); | 275 ASSERT_EQ(original.size(), decoded.size()); |
| 128 | 276 |
| 129 // Images must be exactly equal | 277 // Images must be exactly equal |
| 130 ASSERT_TRUE(original == decoded); | 278 ASSERT_TRUE(original == decoded); |
| 131 } | 279 } |
| 132 | 280 |
| 281 TEST(PNGCodec, EncodeDecodeBGRA) { |
| 282 const int w = 20, h = 20; |
| 283 |
| 284 // Create an image with known values, alpha must be opaque because it will be |
| 285 // lost during encoding. |
| 286 std::vector<unsigned char> original; |
| 287 MakeRGBAImage(w, h, true, &original); |
| 288 |
| 289 // Encode. |
| 290 std::vector<unsigned char> encoded; |
| 291 ASSERT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_BGRA, |
| 292 Size(w, h), w * 4, false, |
| 293 std::vector<PNGCodec::Comment>(), |
| 294 &encoded)); |
| 295 |
| 296 // Decode, it should have the same size as the original. |
| 297 std::vector<unsigned char> decoded; |
| 298 int outw, outh; |
| 299 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| 300 PNGCodec::FORMAT_BGRA, &decoded, |
| 301 &outw, &outh)); |
| 302 ASSERT_EQ(w, outw); |
| 303 ASSERT_EQ(h, outh); |
| 304 ASSERT_EQ(original.size(), decoded.size()); |
| 305 |
| 306 // Images must be exactly equal. |
| 307 ASSERT_TRUE(original == decoded); |
| 308 } |
| 309 |
| 310 TEST(PNGCodec, DecodeInterlacedRGB) { |
| 311 const int w = 20, h = 20; |
| 312 |
| 313 // create an image with known values |
| 314 std::vector<unsigned char> original; |
| 315 MakeRGBImage(w, h, &original); |
| 316 |
| 317 // encode |
| 318 std::vector<unsigned char> encoded; |
| 319 ASSERT_TRUE(EncodeImage(original, |
| 320 w, h, |
| 321 COLOR_TYPE_RGB, |
| 322 &encoded, |
| 323 PNG_INTERLACE_ADAM7)); |
| 324 |
| 325 // decode, it should have the same size as the original |
| 326 std::vector<unsigned char> decoded; |
| 327 int outw, outh; |
| 328 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| 329 PNGCodec::FORMAT_RGB, &decoded, |
| 330 &outw, &outh)); |
| 331 ASSERT_EQ(w, outw); |
| 332 ASSERT_EQ(h, outh); |
| 333 ASSERT_EQ(original.size(), decoded.size()); |
| 334 |
| 335 // Images must be equal |
| 336 ASSERT_EQ(original, decoded); |
| 337 } |
| 338 |
| 339 TEST(PNGCodec, DecodeInterlacedRGBA) { |
| 340 const int w = 20, h = 20; |
| 341 |
| 342 // create an image with known values |
| 343 std::vector<unsigned char> original; |
| 344 MakeRGBAImage(w, h, false, &original); |
| 345 |
| 346 // encode |
| 347 std::vector<unsigned char> encoded; |
| 348 ASSERT_TRUE(EncodeImage(original, |
| 349 w, h, |
| 350 COLOR_TYPE_RGBA, |
| 351 &encoded, |
| 352 PNG_INTERLACE_ADAM7)); |
| 353 |
| 354 // decode, it should have the same size as the original |
| 355 std::vector<unsigned char> decoded; |
| 356 int outw, outh; |
| 357 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| 358 PNGCodec::FORMAT_RGBA, &decoded, |
| 359 &outw, &outh)); |
| 360 ASSERT_EQ(w, outw); |
| 361 ASSERT_EQ(h, outh); |
| 362 ASSERT_EQ(original.size(), decoded.size()); |
| 363 |
| 364 // Images must be equal |
| 365 ASSERT_EQ(original, decoded); |
| 366 } |
| 367 |
| 368 TEST(PNGCodec, DecodeInterlacedRGBADiscardAlpha) { |
| 369 const int w = 20, h = 20; |
| 370 |
| 371 // create an image with known values |
| 372 std::vector<unsigned char> original; |
| 373 MakeRGBAImage(w, h, false, &original); |
| 374 |
| 375 // encode |
| 376 std::vector<unsigned char> encoded; |
| 377 ASSERT_TRUE(EncodeImage(original, |
| 378 w, h, |
| 379 COLOR_TYPE_RGBA, |
| 380 &encoded, |
| 381 PNG_INTERLACE_ADAM7)); |
| 382 |
| 383 // decode |
| 384 std::vector<unsigned char> decoded; |
| 385 int outw, outh; |
| 386 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| 387 PNGCodec::FORMAT_RGB, &decoded, |
| 388 &outw, &outh)); |
| 389 ASSERT_EQ(w, outw); |
| 390 ASSERT_EQ(h, outh); |
| 391 ASSERT_EQ(decoded.size(), w * h * 3U); |
| 392 |
| 393 // Images must be equal |
| 394 for (int x = 0; x < w; x++) { |
| 395 for (int y = 0; y < h; y++) { |
| 396 unsigned char* orig_px = &original[(y * w + x) * 4]; |
| 397 unsigned char* dec_px = &decoded[(y * w + x) * 3]; |
| 398 ASSERT_EQ(dec_px[0], orig_px[0]); |
| 399 ASSERT_EQ(dec_px[1], orig_px[1]); |
| 400 ASSERT_EQ(dec_px[2], orig_px[2]); |
| 401 } |
| 402 } |
| 403 } |
| 404 |
| 405 TEST(PNGCodec, DecodeInterlacedBGR) { |
| 406 const int w = 20, h = 20; |
| 407 |
| 408 // create an image with known values |
| 409 std::vector<unsigned char> original; |
| 410 MakeRGBImage(w, h, &original); |
| 411 |
| 412 // encode |
| 413 std::vector<unsigned char> encoded; |
| 414 ASSERT_TRUE(EncodeImage(original, |
| 415 w, h, |
| 416 COLOR_TYPE_BGR, |
| 417 &encoded, |
| 418 PNG_INTERLACE_ADAM7)); |
| 419 |
| 420 // decode, it should have the same size as the original |
| 421 std::vector<unsigned char> decoded; |
| 422 int outw, outh; |
| 423 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| 424 PNGCodec::FORMAT_BGRA, &decoded, |
| 425 &outw, &outh)); |
| 426 ASSERT_EQ(w, outw); |
| 427 ASSERT_EQ(h, outh); |
| 428 ASSERT_EQ(decoded.size(), w * h * 4U); |
| 429 |
| 430 // Images must be equal |
| 431 for (int x = 0; x < w; x++) { |
| 432 for (int y = 0; y < h; y++) { |
| 433 unsigned char* orig_px = &original[(y * w + x) * 3]; |
| 434 unsigned char* dec_px = &decoded[(y * w + x) * 4]; |
| 435 ASSERT_EQ(dec_px[0], orig_px[0]); |
| 436 ASSERT_EQ(dec_px[1], orig_px[1]); |
| 437 ASSERT_EQ(dec_px[2], orig_px[2]); |
| 438 } |
| 439 } |
| 440 } |
| 441 |
| 442 TEST(PNGCodec, DecodeInterlacedBGRA) { |
| 443 const int w = 20, h = 20; |
| 444 |
| 445 // create an image with known values |
| 446 std::vector<unsigned char> original; |
| 447 MakeRGBAImage(w, h, false, &original); |
| 448 |
| 449 // encode |
| 450 std::vector<unsigned char> encoded; |
| 451 ASSERT_TRUE(EncodeImage(original, |
| 452 w, h, |
| 453 COLOR_TYPE_BGRA, |
| 454 &encoded, |
| 455 PNG_INTERLACE_ADAM7)); |
| 456 |
| 457 // decode, it should have the same size as the original |
| 458 std::vector<unsigned char> decoded; |
| 459 int outw, outh; |
| 460 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| 461 PNGCodec::FORMAT_BGRA, &decoded, |
| 462 &outw, &outh)); |
| 463 ASSERT_EQ(w, outw); |
| 464 ASSERT_EQ(h, outh); |
| 465 ASSERT_EQ(original.size(), decoded.size()); |
| 466 |
| 467 // Images must be equal |
| 468 ASSERT_EQ(original, decoded); |
| 469 } |
| 470 |
| 471 // Not encoding an interlaced PNG from SkBitmap because we don't do it |
| 472 // anywhere, and the ability to do that requires more code changes. |
| 473 TEST(PNGCodec, DecodeInterlacedRGBtoSkBitmap) { |
| 474 const int w = 20, h = 20; |
| 475 |
| 476 // create an image with known values |
| 477 std::vector<unsigned char> original; |
| 478 MakeRGBImage(w, h, &original); |
| 479 |
| 480 // encode |
| 481 std::vector<unsigned char> encoded; |
| 482 ASSERT_TRUE(EncodeImage(original, |
| 483 w, h, |
| 484 COLOR_TYPE_RGB, |
| 485 &encoded, |
| 486 PNG_INTERLACE_ADAM7)); |
| 487 |
| 488 // Decode the encoded string. |
| 489 SkBitmap decoded_bitmap; |
| 490 ASSERT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(), |
| 491 &decoded_bitmap)); |
| 492 |
| 493 for (int x = 0; x < w; x++) { |
| 494 for (int y = 0; y < h; y++) { |
| 495 const unsigned char* original_pixel = &original[(y * w + x) * 3]; |
| 496 const uint32_t original_pixel_sk = SkPackARGB32(0xFF, |
| 497 original_pixel[0], |
| 498 original_pixel[1], |
| 499 original_pixel[2]); |
| 500 const uint32_t decoded_pixel = decoded_bitmap.getAddr32(0, y)[x]; |
| 501 ASSERT_EQ(original_pixel_sk, decoded_pixel); |
| 502 } |
| 503 } |
| 504 } |
| 505 |
| 506 TEST(PNGCodec, DecodeInterlacedRGBAtoSkBitmap) { |
| 507 const int w = 20, h = 20; |
| 508 |
| 509 // create an image with known values |
| 510 std::vector<unsigned char> original; |
| 511 MakeRGBAImage(w, h, false, &original); |
| 512 |
| 513 // encode |
| 514 std::vector<unsigned char> encoded; |
| 515 ASSERT_TRUE(EncodeImage(original, |
| 516 w, h, |
| 517 COLOR_TYPE_RGBA, |
| 518 &encoded, |
| 519 PNG_INTERLACE_ADAM7)); |
| 520 |
| 521 // Decode the encoded string. |
| 522 SkBitmap decoded_bitmap; |
| 523 ASSERT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(), |
| 524 &decoded_bitmap)); |
| 525 |
| 526 for (int x = 0; x < w; x++) { |
| 527 for (int y = 0; y < h; y++) { |
| 528 const unsigned char* original_pixel = &original[(y * w + x) * 4]; |
| 529 const uint32_t original_pixel_sk = SkPackARGB32(original_pixel[3], |
| 530 original_pixel[0], |
| 531 original_pixel[1], |
| 532 original_pixel[2]); |
| 533 const uint32_t decoded_pixel = decoded_bitmap.getAddr32(0, y)[x]; |
| 534 ASSERT_EQ(original_pixel_sk, decoded_pixel); |
| 535 } |
| 536 } |
| 537 } |
| 538 |
| 133 // Test that corrupted data decompression causes failures. | 539 // Test that corrupted data decompression causes failures. |
| 134 TEST(PNGCodec, DecodeCorrupted) { | 540 TEST(PNGCodec, DecodeCorrupted) { |
| 135 int w = 20, h = 20; | 541 int w = 20, h = 20; |
| 136 | 542 |
| 137 // Make some random data (an uncompressed image). | 543 // Make some random data (an uncompressed image). |
| 138 std::vector<unsigned char> original; | 544 std::vector<unsigned char> original; |
| 139 MakeRGBImage(w, h, &original); | 545 MakeRGBImage(w, h, &original); |
| 140 | 546 |
| 141 // It should fail when given non-JPEG compressed data. | 547 // It should fail when given non-JPEG compressed data. |
| 142 std::vector<unsigned char> output; | 548 std::vector<unsigned char> output; |
| 143 int outw, outh; | 549 int outw, outh; |
| 144 EXPECT_FALSE(PNGCodec::Decode(&original[0], original.size(), | 550 EXPECT_FALSE(PNGCodec::Decode(&original[0], original.size(), |
| 145 PNGCodec::FORMAT_RGB, &output, | 551 PNGCodec::FORMAT_RGB, &output, |
| 146 &outw, &outh)); | 552 &outw, &outh)); |
| 147 | 553 |
| 148 // Make some compressed data. | 554 // Make some compressed data. |
| 149 std::vector<unsigned char> compressed; | 555 std::vector<unsigned char> compressed; |
| 150 EXPECT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB, | 556 ASSERT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB, |
| 151 Size(w, h), w * 3, false, | 557 Size(w, h), w * 3, false, |
| 152 std::vector<PNGCodec::Comment>(), | 558 std::vector<PNGCodec::Comment>(), |
| 153 &compressed)); | 559 &compressed)); |
| 154 | 560 |
| 155 // Try decompressing a truncated version. | 561 // Try decompressing a truncated version. |
| 156 EXPECT_FALSE(PNGCodec::Decode(&compressed[0], compressed.size() / 2, | 562 EXPECT_FALSE(PNGCodec::Decode(&compressed[0], compressed.size() / 2, |
| 157 PNGCodec::FORMAT_RGB, &output, | 563 PNGCodec::FORMAT_RGB, &output, |
| 158 &outw, &outh)); | 564 &outw, &outh)); |
| 159 | 565 |
| 160 // Corrupt it and try decompressing that. | 566 // Corrupt it and try decompressing that. |
| 161 for (int i = 10; i < 30; i++) | 567 for (int i = 10; i < 30; i++) |
| 162 compressed[i] = i; | 568 compressed[i] = i; |
| 163 EXPECT_FALSE(PNGCodec::Decode(&compressed[0], compressed.size(), | 569 EXPECT_FALSE(PNGCodec::Decode(&compressed[0], compressed.size(), |
| 164 PNGCodec::FORMAT_RGB, &output, | 570 PNGCodec::FORMAT_RGB, &output, |
| 165 &outw, &outh)); | 571 &outw, &outh)); |
| 166 } | 572 } |
| 167 | 573 |
| 168 TEST(PNGCodec, EncodeDecodeBGRA) { | |
| 169 const int w = 20, h = 20; | |
| 170 | |
| 171 // Create an image with known values, alpha must be opaque because it will be | |
| 172 // lost during encoding. | |
| 173 std::vector<unsigned char> original; | |
| 174 MakeRGBAImage(w, h, true, &original); | |
| 175 | |
| 176 // Encode. | |
| 177 std::vector<unsigned char> encoded; | |
| 178 EXPECT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_BGRA, | |
| 179 Size(w, h), w * 4, false, | |
| 180 std::vector<PNGCodec::Comment>(), | |
| 181 &encoded)); | |
| 182 | |
| 183 // Decode, it should have the same size as the original. | |
| 184 std::vector<unsigned char> decoded; | |
| 185 int outw, outh; | |
| 186 EXPECT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), | |
| 187 PNGCodec::FORMAT_BGRA, &decoded, | |
| 188 &outw, &outh)); | |
| 189 ASSERT_EQ(w, outw); | |
| 190 ASSERT_EQ(h, outh); | |
| 191 ASSERT_EQ(original.size(), decoded.size()); | |
| 192 | |
| 193 // Images must be exactly equal. | |
| 194 ASSERT_TRUE(original == decoded); | |
| 195 } | |
| 196 | |
| 197 TEST(PNGCodec, StripAddAlpha) { | 574 TEST(PNGCodec, StripAddAlpha) { |
| 198 const int w = 20, h = 20; | 575 const int w = 20, h = 20; |
| 199 | 576 |
| 200 // These should be the same except one has a 0xff alpha channel. | 577 // These should be the same except one has a 0xff alpha channel. |
| 201 std::vector<unsigned char> original_rgb; | 578 std::vector<unsigned char> original_rgb; |
| 202 MakeRGBImage(w, h, &original_rgb); | 579 MakeRGBImage(w, h, &original_rgb); |
| 203 std::vector<unsigned char> original_rgba; | 580 std::vector<unsigned char> original_rgba; |
| 204 MakeRGBAImage(w, h, false, &original_rgba); | 581 MakeRGBAImage(w, h, false, &original_rgba); |
| 205 | 582 |
| 206 // Encode RGBA data as RGB. | 583 // Encode RGBA data as RGB. |
| 207 std::vector<unsigned char> encoded; | 584 std::vector<unsigned char> encoded; |
| 208 EXPECT_TRUE(PNGCodec::Encode(&original_rgba[0], PNGCodec::FORMAT_RGBA, | 585 EXPECT_TRUE(PNGCodec::Encode(&original_rgba[0], PNGCodec::FORMAT_RGBA, |
| 209 Size(w, h), w * 4, true, | 586 Size(w, h), w * 4, true, |
| 210 std::vector<PNGCodec::Comment>(), | 587 std::vector<PNGCodec::Comment>(), |
| 211 &encoded)); | 588 &encoded)); |
| 212 | 589 |
| 213 // Decode the RGB to RGBA. | 590 // Decode the RGB to RGBA. |
| 214 std::vector<unsigned char> decoded; | 591 std::vector<unsigned char> decoded; |
| 215 int outw, outh; | 592 int outw, outh; |
| 216 EXPECT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), | 593 EXPECT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| 217 PNGCodec::FORMAT_RGBA, &decoded, | 594 PNGCodec::FORMAT_RGBA, &decoded, |
| 218 &outw, &outh)); | 595 &outw, &outh)); |
| 219 | 596 |
| 220 // Decoded and reference should be the same (opaque alpha). | 597 // Decoded and reference should be the same (opaque alpha). |
| 221 ASSERT_EQ(w, outw); | 598 ASSERT_EQ(w, outw); |
| 222 ASSERT_EQ(h, outh); | 599 ASSERT_EQ(h, outh); |
| 223 ASSERT_EQ(original_rgba.size(), decoded.size()); | 600 ASSERT_EQ(original_rgba.size(), decoded.size()); |
| 224 ASSERT_TRUE(original_rgba == decoded); | 601 ASSERT_EQ(original_rgba, decoded); |
| 225 | 602 |
| 226 // Encode RGBA to RGBA. | 603 // Encode RGBA to RGBA. |
| 227 EXPECT_TRUE(PNGCodec::Encode(&original_rgba[0], PNGCodec::FORMAT_RGBA, | 604 EXPECT_TRUE(PNGCodec::Encode(&original_rgba[0], PNGCodec::FORMAT_RGBA, |
| 228 Size(w, h), w * 4, false, | 605 Size(w, h), w * 4, false, |
| 229 std::vector<PNGCodec::Comment>(), | 606 std::vector<PNGCodec::Comment>(), |
| 230 &encoded)); | 607 &encoded)); |
| 231 | 608 |
| 232 // Decode the RGBA to RGB. | 609 // Decode the RGBA to RGB. |
| 233 EXPECT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), | 610 EXPECT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), |
| 234 PNGCodec::FORMAT_RGB, &decoded, | 611 PNGCodec::FORMAT_RGB, &decoded, |
| 235 &outw, &outh)); | 612 &outw, &outh)); |
| 236 | 613 |
| 237 // It should be the same as our non-alpha-channel reference. | 614 // It should be the same as our non-alpha-channel reference. |
| 238 ASSERT_EQ(w, outw); | 615 ASSERT_EQ(w, outw); |
| 239 ASSERT_EQ(h, outh); | 616 ASSERT_EQ(h, outh); |
| 240 ASSERT_EQ(original_rgb.size(), decoded.size()); | 617 ASSERT_EQ(original_rgb.size(), decoded.size()); |
| 241 ASSERT_TRUE(original_rgb == decoded); | 618 ASSERT_EQ(original_rgb, decoded); |
| 242 } | 619 } |
| 243 | 620 |
| 244 TEST(PNGCodec, EncodeBGRASkBitmap) { | 621 TEST(PNGCodec, EncodeBGRASkBitmap) { |
| 245 const int w = 20, h = 20; | 622 const int w = 20, h = 20; |
| 246 | 623 |
| 247 SkBitmap original_bitmap; | 624 SkBitmap original_bitmap; |
| 248 MakeTestSkBitmap(w, h, &original_bitmap); | 625 MakeTestSkBitmap(w, h, &original_bitmap); |
| 249 | 626 |
| 250 // Encode the bitmap. | 627 // Encode the bitmap. |
| 251 std::vector<unsigned char> encoded; | 628 std::vector<unsigned char> encoded; |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 379 ASSERT_EQ(w, outw); | 756 ASSERT_EQ(w, outw); |
| 380 ASSERT_EQ(h, outh); | 757 ASSERT_EQ(h, outh); |
| 381 ASSERT_EQ(original.size(), decoded.size()); | 758 ASSERT_EQ(original.size(), decoded.size()); |
| 382 | 759 |
| 383 // Images must be exactly equal | 760 // Images must be exactly equal |
| 384 ASSERT_TRUE(original == decoded); | 761 ASSERT_TRUE(original == decoded); |
| 385 } | 762 } |
| 386 | 763 |
| 387 | 764 |
| 388 } // namespace gfx | 765 } // namespace gfx |
| OLD | NEW |