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 3// found in the LICENSE file. 4 5#include <algorithm> 6#include <cmath> 7 8#include "base/logging.h" 9#include "testing/gtest/include/gtest/gtest.h" 10#include "third_party/libpng/png.h" 11#include "third_party/skia/include/core/SkBitmap.h" 12#include "third_party/skia/include/core/SkColorPriv.h" 13#include "third_party/skia/include/core/SkUnPreMultiply.h" 14#include "third_party/zlib/zlib.h" 15#include "ui/gfx/codec/png_codec.h" 16#include "ui/gfx/size.h" 17#include "ui/gfx/skia_util.h" 18 19namespace gfx { 20 21namespace { 22 23void MakeRGBImage(int w, int h, std::vector<unsigned char>* data) { 24 data->resize(w * h * 3); 25 for (int y = 0; y < h; y++) { 26 for (int x = 0; x < w; x++) { 27 unsigned char* org_px = &(*data)[(y * w + x) * 3]; 28 org_px[0] = x * 3; // r 29 org_px[1] = x * 3 + 1; // g 30 org_px[2] = x * 3 + 2; // b 31 } 32 } 33} 34 35// Set use_transparency to write data into the alpha channel, otherwise it will 36// be filled with 0xff. With the alpha channel stripped, this should yield the 37// same image as MakeRGBImage above, so the code below can make reference 38// images for conversion testing. 39void MakeRGBAImage(int w, int h, bool use_transparency, 40 std::vector<unsigned char>* data) { 41 data->resize(w * h * 4); 42 for (int y = 0; y < h; y++) { 43 for (int x = 0; x < w; x++) { 44 unsigned char* org_px = &(*data)[(y * w + x) * 4]; 45 org_px[0] = x * 3; // r 46 org_px[1] = x * 3 + 1; // g 47 org_px[2] = x * 3 + 2; // b 48 if (use_transparency) 49 org_px[3] = x*3 + 3; // a 50 else 51 org_px[3] = 0xFF; // a (opaque) 52 } 53 } 54} 55 56// Creates a palette-based image. 57void MakePaletteImage(int w, int h, 58 std::vector<unsigned char>* data, 59 std::vector<png_color>* palette, 60 std::vector<unsigned char>* trans_chunk = 0) { 61 data->resize(w * h); 62 palette->resize(w); 63 for (int i = 0; i < w; ++i) { 64 png_color& color = (*palette)[i]; 65 color.red = i * 3; 66 color.green = color.red + 1; 67 color.blue = color.red + 2; 68 } 69 for (int y = 0; y < h; y++) { 70 for (int x = 0; x < w; x++) { 71 (*data)[y * w + x] = x; // palette index 72 } 73 } 74 if (trans_chunk) { 75 trans_chunk->resize(palette->size()); 76 for (std::size_t i = 0; i < trans_chunk->size(); ++i) { 77 (*trans_chunk)[i] = i % 256; 78 } 79 } 80} 81 82// Creates a grayscale image without an alpha channel. 83void MakeGrayscaleImage(int w, int h, 84 std::vector<unsigned char>* data) { 85 data->resize(w * h); 86 for (int y = 0; y < h; y++) { 87 for (int x = 0; x < w; x++) { 88 (*data)[y * w + x] = x; // gray value 89 } 90 } 91} 92 93// Creates a grayscale image with an alpha channel. 94void MakeGrayscaleAlphaImage(int w, int h, 95 std::vector<unsigned char>* data) { 96 data->resize(w * h * 2); 97 for (int y = 0; y < h; y++) { 98 for (int x = 0; x < w; x++) { 99 unsigned char* px = &(*data)[(y * w + x) * 2]; 100 px[0] = x; // gray value 101 px[1] = x % 256; // alpha 102 } 103 } 104} 105 106// User write function (to be passed to libpng by EncodeImage) which writes 107// into a buffer instead of to a file. 108void WriteImageData(png_structp png_ptr, 109 png_bytep data, 110 png_size_t length) { 111 std::vector<unsigned char>& v = 112 *static_cast<std::vector<unsigned char>*>(png_get_io_ptr(png_ptr)); 113 v.resize(v.size() + length); 114 memcpy(&v[v.size() - length], data, length); 115} 116 117// User flush function; goes with WriteImageData, above. 118void FlushImageData(png_structp /*png_ptr*/) { 119} 120 121// Libpng user error function which allows us to print libpng errors using 122// Chrome's logging facilities instead of stderr. 123void LogLibPNGError(png_structp png_ptr, 124 png_const_charp error_msg) { 125 DLOG(ERROR) << "libpng encode error: " << error_msg; 126 longjmp(png_jmpbuf(png_ptr), 1); 127} 128 129// Goes with LogLibPNGError, above. 130void LogLibPNGWarning(png_structp png_ptr, 131 png_const_charp warning_msg) { 132 DLOG(ERROR) << "libpng encode warning: " << warning_msg; 133} 134 135// Color types supported by EncodeImage. Required because neither libpng nor 136// PNGCodec::Encode supports all of the required values. 137enum ColorType { 138 COLOR_TYPE_GRAY = PNG_COLOR_TYPE_GRAY, 139 COLOR_TYPE_GRAY_ALPHA = PNG_COLOR_TYPE_GRAY_ALPHA, 140 COLOR_TYPE_PALETTE = PNG_COLOR_TYPE_PALETTE, 141 COLOR_TYPE_RGB = PNG_COLOR_TYPE_RGB, 142 COLOR_TYPE_RGBA = PNG_COLOR_TYPE_RGBA, 143 COLOR_TYPE_BGR, 144 COLOR_TYPE_BGRA 145}; 146 147// PNG encoder used for testing. Required because PNGCodec::Encode doesn't do 148// interlaced, palette-based, or grayscale images, but PNGCodec::Decode is 149// actually asked to decode these types of images by Chrome. 150bool EncodeImage(const std::vector<unsigned char>& input, 151 const int width, 152 const int height, 153 ColorType output_color_type, 154 std::vector<unsigned char>* output, 155 const int interlace_type = PNG_INTERLACE_NONE, 156 std::vector<png_color>* palette = 0, 157 std::vector<unsigned char>* palette_alpha = 0) { 158 DCHECK(output); 159 160 int input_rowbytes = 0; 161 int transforms = PNG_TRANSFORM_IDENTITY; 162 163 switch (output_color_type) { 164 case COLOR_TYPE_GRAY: 165 input_rowbytes = width; 166 break; 167 case COLOR_TYPE_GRAY_ALPHA: 168 input_rowbytes = width * 2; 169 break; 170 case COLOR_TYPE_PALETTE: 171 if (!palette) 172 return false; 173 input_rowbytes = width; 174 break; 175 case COLOR_TYPE_RGB: 176 input_rowbytes = width * 3; 177 break; 178 case COLOR_TYPE_RGBA: 179 input_rowbytes = width * 4; 180 break; 181 case COLOR_TYPE_BGR: 182 input_rowbytes = width * 3; 183 output_color_type = static_cast<ColorType>(PNG_COLOR_TYPE_RGB); 184 transforms |= PNG_TRANSFORM_BGR; 185 break; 186 case COLOR_TYPE_BGRA: 187 input_rowbytes = width * 4; 188 output_color_type = static_cast<ColorType>(PNG_COLOR_TYPE_RGBA); 189 transforms |= PNG_TRANSFORM_BGR; 190 break; 191 }; 192 193 png_struct* png_ptr = 194 png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 195 if (!png_ptr) 196 return false; 197 png_infop info_ptr = png_create_info_struct(png_ptr); 198 if (!info_ptr) { 199 png_destroy_write_struct(&png_ptr, NULL); 200 return false; 201 } 202 203 std::vector<png_bytep> row_pointers(height); 204 for (int y = 0 ; y < height; ++y) { 205 row_pointers[y] = const_cast<unsigned char*>(&input[y * input_rowbytes]); 206 } 207 208 if (setjmp(png_jmpbuf(png_ptr))) { 209 png_destroy_write_struct(&png_ptr, &info_ptr); 210 return false; 211 } 212 213 png_set_error_fn(png_ptr, NULL, LogLibPNGError, LogLibPNGWarning); 214 png_set_rows(png_ptr, info_ptr, &row_pointers[0]); 215 png_set_write_fn(png_ptr, output, WriteImageData, FlushImageData); 216 png_set_IHDR(png_ptr, info_ptr, width, height, 8, output_color_type, 217 interlace_type, PNG_COMPRESSION_TYPE_DEFAULT, 218 PNG_FILTER_TYPE_DEFAULT); 219 if (output_color_type == COLOR_TYPE_PALETTE) { 220 png_set_PLTE(png_ptr, info_ptr, &palette->front(), palette->size()); 221 if (palette_alpha) { 222 unsigned char* alpha_data = &palette_alpha->front(); 223 size_t alpha_size = palette_alpha->size(); 224 png_set_tRNS(png_ptr, info_ptr, alpha_data, alpha_size, NULL); 225 } 226 } 227 228 png_write_png(png_ptr, info_ptr, transforms, NULL); 229 230 png_destroy_write_struct(&png_ptr, &info_ptr); 231 return true; 232} 233 234} // namespace 235 236// Returns true if each channel of the given two colors are "close." This is 237// used for comparing colors where rounding errors may cause off-by-one. 238bool ColorsClose(uint32_t a, uint32_t b) { 239 return abs(static_cast<int>(SkColorGetB(a) - SkColorGetB(b))) < 2 && 240 abs(static_cast<int>(SkColorGetG(a) - SkColorGetG(b))) < 2 && 241 abs(static_cast<int>(SkColorGetR(a) - SkColorGetR(b))) < 2 && 242 abs(static_cast<int>(SkColorGetA(a) - SkColorGetA(b))) < 2; 243} 244 245// Returns true if the RGB components are "close." 246bool NonAlphaColorsClose(uint32_t a, uint32_t b) { 247 return abs(static_cast<int>(SkColorGetB(a) - SkColorGetB(b))) < 2 && 248 abs(static_cast<int>(SkColorGetG(a) - SkColorGetG(b))) < 2 && 249 abs(static_cast<int>(SkColorGetR(a) - SkColorGetR(b))) < 2; 250} 251 252void MakeTestSkBitmap(int w, int h, SkBitmap* bmp) { 253 bmp->setConfig(SkBitmap::kARGB_8888_Config, w, h); 254 bmp->allocPixels(); 255 256 uint32_t* src_data = bmp->getAddr32(0, 0); 257 for (int i = 0; i < w * h; i++) { 258 src_data[i] = SkPreMultiplyARGB(i % 255, i % 250, i % 245, i % 240); 259 } 260} 261 262TEST(PNGCodec, EncodeDecodeRGB) { 263 const int w = 20, h = 20; 264 265 // create an image with known values 266 std::vector<unsigned char> original; 267 MakeRGBImage(w, h, &original); 268 269 // encode 270 std::vector<unsigned char> encoded; 271 ASSERT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB, 272 Size(w, h), w * 3, false, 273 std::vector<PNGCodec::Comment>(), 274 &encoded)); 275 276 // decode, it should have the same size as the original 277 std::vector<unsigned char> decoded; 278 int outw, outh; 279 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), 280 PNGCodec::FORMAT_RGB, &decoded, 281 &outw, &outh)); 282 ASSERT_EQ(w, outw); 283 ASSERT_EQ(h, outh); 284 ASSERT_EQ(original.size(), decoded.size()); 285 286 // Images must be equal 287 ASSERT_TRUE(original == decoded); 288} 289 290TEST(PNGCodec, EncodeDecodeRGBA) { 291 const int w = 20, h = 20; 292 293 // create an image with known values, a must be opaque because it will be 294 // lost during encoding 295 std::vector<unsigned char> original; 296 MakeRGBAImage(w, h, true, &original); 297 298 // encode 299 std::vector<unsigned char> encoded; 300 ASSERT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGBA, 301 Size(w, h), w * 4, false, 302 std::vector<PNGCodec::Comment>(), 303 &encoded)); 304 305 // decode, it should have the same size as the original 306 std::vector<unsigned char> decoded; 307 int outw, outh; 308 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), 309 PNGCodec::FORMAT_RGBA, &decoded, 310 &outw, &outh)); 311 ASSERT_EQ(w, outw); 312 ASSERT_EQ(h, outh); 313 ASSERT_EQ(original.size(), decoded.size()); 314 315 // Images must be exactly equal 316 ASSERT_TRUE(original == decoded); 317} 318 319TEST(PNGCodec, EncodeDecodeBGRA) { 320 const int w = 20, h = 20; 321 322 // Create an image with known values, alpha must be opaque because it will be 323 // lost during encoding. 324 std::vector<unsigned char> original; 325 MakeRGBAImage(w, h, true, &original); 326 327 // Encode. 328 std::vector<unsigned char> encoded; 329 ASSERT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_BGRA, 330 Size(w, h), w * 4, false, 331 std::vector<PNGCodec::Comment>(), 332 &encoded)); 333 334 // Decode, it should have the same size as the original. 335 std::vector<unsigned char> decoded; 336 int outw, outh; 337 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), 338 PNGCodec::FORMAT_BGRA, &decoded, 339 &outw, &outh)); 340 ASSERT_EQ(w, outw); 341 ASSERT_EQ(h, outh); 342 ASSERT_EQ(original.size(), decoded.size()); 343 344 // Images must be exactly equal. 345 ASSERT_TRUE(original == decoded); 346} 347 348TEST(PNGCodec, DecodePalette) { 349 const int w = 20, h = 20; 350 351 // create an image with known values 352 std::vector<unsigned char> original; 353 std::vector<png_color> original_palette; 354 std::vector<unsigned char> original_trans_chunk; 355 MakePaletteImage(w, h, &original, &original_palette, &original_trans_chunk); 356 357 // encode 358 std::vector<unsigned char> encoded; 359 ASSERT_TRUE(EncodeImage(original, 360 w, h, 361 COLOR_TYPE_PALETTE, 362 &encoded, 363 PNG_INTERLACE_NONE, 364 &original_palette, 365 &original_trans_chunk)); 366 367 // decode 368 std::vector<unsigned char> decoded; 369 int outw, outh; 370 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), 371 PNGCodec::FORMAT_RGBA, &decoded, 372 &outw, &outh)); 373 ASSERT_EQ(w, outw); 374 ASSERT_EQ(h, outh); 375 ASSERT_EQ(decoded.size(), w * h * 4U); 376 377 // Images must be equal 378 for (int y = 0; y < h; ++y) { 379 for (int x = 0; x < w; ++x) { 380 unsigned char palette_pixel = original[y * w + x]; 381 png_color& palette_color = original_palette[palette_pixel]; 382 int alpha = original_trans_chunk[palette_pixel]; 383 unsigned char* rgba_pixel = &decoded[(y * w + x) * 4]; 384 385 EXPECT_EQ(palette_color.red, rgba_pixel[0]); 386 EXPECT_EQ(palette_color.green, rgba_pixel[1]); 387 EXPECT_EQ(palette_color.blue, rgba_pixel[2]); 388 EXPECT_EQ(alpha, rgba_pixel[3]); 389 } 390 } 391} 392 393TEST(PNGCodec, DecodePaletteDiscardAlpha) { 394 const int w = 20, h = 20; 395 396 // create an image with known values 397 std::vector<unsigned char> original; 398 std::vector<png_color> original_palette; 399 std::vector<unsigned char> original_trans_chunk; 400 MakePaletteImage(w, h, &original, &original_palette, &original_trans_chunk); 401 402 // encode 403 std::vector<unsigned char> encoded; 404 ASSERT_TRUE(EncodeImage(original, 405 w, h, 406 COLOR_TYPE_PALETTE, 407 &encoded, 408 PNG_INTERLACE_NONE, 409 &original_palette, 410 &original_trans_chunk)); 411 412 // decode 413 std::vector<unsigned char> decoded; 414 int outw, outh; 415 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), 416 PNGCodec::FORMAT_RGB, &decoded, 417 &outw, &outh)); 418 ASSERT_EQ(w, outw); 419 ASSERT_EQ(h, outh); 420 ASSERT_EQ(decoded.size(), w * h * 3U); 421 422 // Images must be equal 423 for (int y = 0; y < h; ++y) { 424 for (int x = 0; x < w; ++x) { 425 unsigned char palette_pixel = original[y * w + x]; 426 png_color& palette_color = original_palette[palette_pixel]; 427 unsigned char* rgba_pixel = &decoded[(y * w + x) * 3]; 428 429 EXPECT_EQ(palette_color.red, rgba_pixel[0]); 430 EXPECT_EQ(palette_color.green, rgba_pixel[1]); 431 EXPECT_EQ(palette_color.blue, rgba_pixel[2]); 432 } 433 } 434} 435 436TEST(PNGCodec, DecodeInterlacedPalette) { 437 const int w = 20, h = 20; 438 439 // create an image with known values 440 std::vector<unsigned char> original; 441 std::vector<png_color> original_palette; 442 std::vector<unsigned char> original_trans_chunk; 443 MakePaletteImage(w, h, &original, &original_palette, &original_trans_chunk); 444 445 // encode 446 std::vector<unsigned char> encoded; 447 ASSERT_TRUE(EncodeImage(original, 448 w, h, 449 COLOR_TYPE_PALETTE, 450 &encoded, 451 PNG_INTERLACE_ADAM7, 452 &original_palette, 453 &original_trans_chunk)); 454 455 // decode 456 std::vector<unsigned char> decoded; 457 int outw, outh; 458 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), 459 PNGCodec::FORMAT_RGBA, &decoded, 460 &outw, &outh)); 461 ASSERT_EQ(w, outw); 462 ASSERT_EQ(h, outh); 463 ASSERT_EQ(decoded.size(), w * h * 4U); 464 465 // Images must be equal 466 for (int y = 0; y < h; ++y) { 467 for (int x = 0; x < w; ++x) { 468 unsigned char palette_pixel = original[y * w + x]; 469 png_color& palette_color = original_palette[palette_pixel]; 470 int alpha = original_trans_chunk[palette_pixel]; 471 unsigned char* rgba_pixel = &decoded[(y * w + x) * 4]; 472 473 EXPECT_EQ(palette_color.red, rgba_pixel[0]); 474 EXPECT_EQ(palette_color.green, rgba_pixel[1]); 475 EXPECT_EQ(palette_color.blue, rgba_pixel[2]); 476 EXPECT_EQ(alpha, rgba_pixel[3]); 477 } 478 } 479} 480 481TEST(PNGCodec, DecodeGrayscale) { 482 const int w = 20, h = 20; 483 484 // create an image with known values 485 std::vector<unsigned char> original; 486 MakeGrayscaleImage(w, h, &original); 487 488 // encode 489 std::vector<unsigned char> encoded; 490 ASSERT_TRUE(EncodeImage(original, w, h, COLOR_TYPE_GRAY, &encoded)); 491 492 // decode 493 std::vector<unsigned char> decoded; 494 int outw, outh; 495 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), 496 PNGCodec::FORMAT_RGB, &decoded, 497 &outw, &outh)); 498 ASSERT_EQ(w, outw); 499 ASSERT_EQ(h, outh); 500 ASSERT_EQ(decoded.size(), original.size() * 3); 501 502 // Images must be equal 503 for (int y = 0; y < h; ++y) { 504 for (int x = 0; x < w; ++x) { 505 unsigned char gray_pixel = original[(y * w + x)]; 506 unsigned char* rgba_pixel = &decoded[(y * w + x) * 3]; 507 EXPECT_EQ(rgba_pixel[0], gray_pixel); 508 EXPECT_EQ(rgba_pixel[1], gray_pixel); 509 EXPECT_EQ(rgba_pixel[2], gray_pixel); 510 } 511 } 512} 513 514TEST(PNGCodec, DecodeGrayscaleWithAlpha) { 515 const int w = 20, h = 20; 516 517 // create an image with known values 518 std::vector<unsigned char> original; 519 MakeGrayscaleAlphaImage(w, h, &original); 520 521 // encode 522 std::vector<unsigned char> encoded; 523 ASSERT_TRUE(EncodeImage(original, 524 w, h, 525 COLOR_TYPE_GRAY_ALPHA, 526 &encoded)); 527 528 // decode 529 std::vector<unsigned char> decoded; 530 int outw, outh; 531 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), 532 PNGCodec::FORMAT_RGBA, &decoded, 533 &outw, &outh)); 534 ASSERT_EQ(w, outw); 535 ASSERT_EQ(h, outh); 536 ASSERT_EQ(decoded.size(), original.size() * 2); 537 538 // Images must be equal 539 for (int y = 0; y < h; ++y) { 540 for (int x = 0; x < w; ++x) { 541 unsigned char* gray_pixel = &original[(y * w + x) * 2]; 542 unsigned char* rgba_pixel = &decoded[(y * w + x) * 4]; 543 EXPECT_EQ(rgba_pixel[0], gray_pixel[0]); 544 EXPECT_EQ(rgba_pixel[1], gray_pixel[0]); 545 EXPECT_EQ(rgba_pixel[2], gray_pixel[0]); 546 EXPECT_EQ(rgba_pixel[3], gray_pixel[1]); 547 } 548 } 549} 550 551TEST(PNGCodec, DecodeGrayscaleWithAlphaDiscardAlpha) { 552 const int w = 20, h = 20; 553 554 // create an image with known values 555 std::vector<unsigned char> original; 556 MakeGrayscaleAlphaImage(w, h, &original); 557 558 // encode 559 std::vector<unsigned char> encoded; 560 ASSERT_TRUE(EncodeImage(original, 561 w, h, 562 COLOR_TYPE_GRAY_ALPHA, 563 &encoded)); 564 565 // decode 566 std::vector<unsigned char> decoded; 567 int outw, outh; 568 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), 569 PNGCodec::FORMAT_RGB, &decoded, 570 &outw, &outh)); 571 ASSERT_EQ(w, outw); 572 ASSERT_EQ(h, outh); 573 ASSERT_EQ(decoded.size(), w * h * 3U); 574 575 // Images must be equal 576 for (int y = 0; y < h; ++y) { 577 for (int x = 0; x < w; ++x) { 578 unsigned char* gray_pixel = &original[(y * w + x) * 2]; 579 unsigned char* rgba_pixel = &decoded[(y * w + x) * 3]; 580 EXPECT_EQ(rgba_pixel[0], gray_pixel[0]); 581 EXPECT_EQ(rgba_pixel[1], gray_pixel[0]); 582 EXPECT_EQ(rgba_pixel[2], gray_pixel[0]); 583 } 584 } 585} 586 587TEST(PNGCodec, DecodeInterlacedGrayscale) { 588 const int w = 20, h = 20; 589 590 // create an image with known values 591 std::vector<unsigned char> original; 592 MakeGrayscaleImage(w, h, &original); 593 594 // encode 595 std::vector<unsigned char> encoded; 596 ASSERT_TRUE(EncodeImage(original, 597 w, h, 598 COLOR_TYPE_GRAY, 599 &encoded, 600 PNG_INTERLACE_ADAM7)); 601 602 // decode 603 std::vector<unsigned char> decoded; 604 int outw, outh; 605 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), 606 PNGCodec::FORMAT_RGBA, &decoded, 607 &outw, &outh)); 608 ASSERT_EQ(w, outw); 609 ASSERT_EQ(h, outh); 610 ASSERT_EQ(decoded.size(), original.size() * 4); 611 612 // Images must be equal 613 for (int y = 0; y < h; ++y) { 614 for (int x = 0; x < w; ++x) { 615 unsigned char gray_pixel = original[(y * w + x)]; 616 unsigned char* rgba_pixel = &decoded[(y * w + x) * 4]; 617 EXPECT_EQ(rgba_pixel[0], gray_pixel); 618 EXPECT_EQ(rgba_pixel[1], gray_pixel); 619 EXPECT_EQ(rgba_pixel[2], gray_pixel); 620 EXPECT_EQ(rgba_pixel[3], 0xFF); 621 } 622 } 623} 624 625TEST(PNGCodec, DecodeInterlacedGrayscaleWithAlpha) { 626 const int w = 20, h = 20; 627 628 // create an image with known values 629 std::vector<unsigned char> original; 630 MakeGrayscaleAlphaImage(w, h, &original); 631 632 // encode 633 std::vector<unsigned char> encoded; 634 ASSERT_TRUE(EncodeImage(original, 635 w, h, 636 COLOR_TYPE_GRAY_ALPHA, 637 &encoded, 638 PNG_INTERLACE_ADAM7)); 639 640 // decode 641 std::vector<unsigned char> decoded; 642 int outw, outh; 643 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), 644 PNGCodec::FORMAT_RGBA, &decoded, 645 &outw, &outh)); 646 ASSERT_EQ(w, outw); 647 ASSERT_EQ(h, outh); 648 ASSERT_EQ(decoded.size(), original.size() * 2); 649 650 // Images must be equal 651 for (int y = 0; y < h; ++y) { 652 for (int x = 0; x < w; ++x) { 653 unsigned char* gray_pixel = &original[(y * w + x) * 2]; 654 unsigned char* rgba_pixel = &decoded[(y * w + x) * 4]; 655 EXPECT_EQ(rgba_pixel[0], gray_pixel[0]); 656 EXPECT_EQ(rgba_pixel[1], gray_pixel[0]); 657 EXPECT_EQ(rgba_pixel[2], gray_pixel[0]); 658 EXPECT_EQ(rgba_pixel[3], gray_pixel[1]); 659 } 660 } 661} 662 663TEST(PNGCodec, DecodeInterlacedRGB) { 664 const int w = 20, h = 20; 665 666 // create an image with known values 667 std::vector<unsigned char> original; 668 MakeRGBImage(w, h, &original); 669 670 // encode 671 std::vector<unsigned char> encoded; 672 ASSERT_TRUE(EncodeImage(original, 673 w, h, 674 COLOR_TYPE_RGB, 675 &encoded, 676 PNG_INTERLACE_ADAM7)); 677 678 // decode, it should have the same size as the original 679 std::vector<unsigned char> decoded; 680 int outw, outh; 681 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), 682 PNGCodec::FORMAT_RGB, &decoded, 683 &outw, &outh)); 684 ASSERT_EQ(w, outw); 685 ASSERT_EQ(h, outh); 686 ASSERT_EQ(original.size(), decoded.size()); 687 688 // Images must be equal 689 ASSERT_EQ(original, decoded); 690} 691 692TEST(PNGCodec, DecodeInterlacedRGBA) { 693 const int w = 20, h = 20; 694 695 // create an image with known values 696 std::vector<unsigned char> original; 697 MakeRGBAImage(w, h, false, &original); 698 699 // encode 700 std::vector<unsigned char> encoded; 701 ASSERT_TRUE(EncodeImage(original, 702 w, h, 703 COLOR_TYPE_RGBA, 704 &encoded, 705 PNG_INTERLACE_ADAM7)); 706 707 // decode, it should have the same size as the original 708 std::vector<unsigned char> decoded; 709 int outw, outh; 710 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), 711 PNGCodec::FORMAT_RGBA, &decoded, 712 &outw, &outh)); 713 ASSERT_EQ(w, outw); 714 ASSERT_EQ(h, outh); 715 ASSERT_EQ(original.size(), decoded.size()); 716 717 // Images must be equal 718 ASSERT_EQ(original, decoded); 719} 720 721TEST(PNGCodec, DecodeInterlacedRGBADiscardAlpha) { 722 const int w = 20, h = 20; 723 724 // create an image with known values 725 std::vector<unsigned char> original; 726 MakeRGBAImage(w, h, false, &original); 727 728 // encode 729 std::vector<unsigned char> encoded; 730 ASSERT_TRUE(EncodeImage(original, 731 w, h, 732 COLOR_TYPE_RGBA, 733 &encoded, 734 PNG_INTERLACE_ADAM7)); 735 736 // decode 737 std::vector<unsigned char> decoded; 738 int outw, outh; 739 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), 740 PNGCodec::FORMAT_RGB, &decoded, 741 &outw, &outh)); 742 ASSERT_EQ(w, outw); 743 ASSERT_EQ(h, outh); 744 ASSERT_EQ(decoded.size(), w * h * 3U); 745 746 // Images must be equal 747 for (int x = 0; x < w; x++) { 748 for (int y = 0; y < h; y++) { 749 unsigned char* orig_px = &original[(y * w + x) * 4]; 750 unsigned char* dec_px = &decoded[(y * w + x) * 3]; 751 EXPECT_EQ(dec_px[0], orig_px[0]); 752 EXPECT_EQ(dec_px[1], orig_px[1]); 753 EXPECT_EQ(dec_px[2], orig_px[2]); 754 } 755 } 756} 757 758TEST(PNGCodec, DecodeInterlacedBGR) { 759 const int w = 20, h = 20; 760 761 // create an image with known values 762 std::vector<unsigned char> original; 763 MakeRGBImage(w, h, &original); 764 765 // encode 766 std::vector<unsigned char> encoded; 767 ASSERT_TRUE(EncodeImage(original, 768 w, h, 769 COLOR_TYPE_BGR, 770 &encoded, 771 PNG_INTERLACE_ADAM7)); 772 773 // decode, it should have the same size as the original 774 std::vector<unsigned char> decoded; 775 int outw, outh; 776 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), 777 PNGCodec::FORMAT_BGRA, &decoded, 778 &outw, &outh)); 779 ASSERT_EQ(w, outw); 780 ASSERT_EQ(h, outh); 781 ASSERT_EQ(decoded.size(), w * h * 4U); 782 783 // Images must be equal 784 for (int x = 0; x < w; x++) { 785 for (int y = 0; y < h; y++) { 786 unsigned char* orig_px = &original[(y * w + x) * 3]; 787 unsigned char* dec_px = &decoded[(y * w + x) * 4]; 788 EXPECT_EQ(dec_px[0], orig_px[0]); 789 EXPECT_EQ(dec_px[1], orig_px[1]); 790 EXPECT_EQ(dec_px[2], orig_px[2]); 791 } 792 } 793} 794 795TEST(PNGCodec, DecodeInterlacedBGRA) { 796 const int w = 20, h = 20; 797 798 // create an image with known values 799 std::vector<unsigned char> original; 800 MakeRGBAImage(w, h, false, &original); 801 802 // encode 803 std::vector<unsigned char> encoded; 804 ASSERT_TRUE(EncodeImage(original, 805 w, h, 806 COLOR_TYPE_BGRA, 807 &encoded, 808 PNG_INTERLACE_ADAM7)); 809 810 // decode, it should have the same size as the original 811 std::vector<unsigned char> decoded; 812 int outw, outh; 813 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), 814 PNGCodec::FORMAT_BGRA, &decoded, 815 &outw, &outh)); 816 ASSERT_EQ(w, outw); 817 ASSERT_EQ(h, outh); 818 ASSERT_EQ(original.size(), decoded.size()); 819 820 // Images must be equal 821 ASSERT_EQ(original, decoded); 822} 823 824// Not encoding an interlaced PNG from SkBitmap because we don't do it 825// anywhere, and the ability to do that requires more code changes. 826TEST(PNGCodec, DecodeInterlacedRGBtoSkBitmap) { 827 const int w = 20, h = 20; 828 829 // create an image with known values 830 std::vector<unsigned char> original; 831 MakeRGBImage(w, h, &original); 832 833 // encode 834 std::vector<unsigned char> encoded; 835 ASSERT_TRUE(EncodeImage(original, 836 w, h, 837 COLOR_TYPE_RGB, 838 &encoded, 839 PNG_INTERLACE_ADAM7)); 840 841 // Decode the encoded string. 842 SkBitmap decoded_bitmap; 843 ASSERT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(), 844 &decoded_bitmap)); 845 846 for (int x = 0; x < w; x++) { 847 for (int y = 0; y < h; y++) { 848 const unsigned char* original_pixel = &original[(y * w + x) * 3]; 849 const uint32_t original_pixel_sk = SkPackARGB32(0xFF, 850 original_pixel[0], 851 original_pixel[1], 852 original_pixel[2]); 853 const uint32_t decoded_pixel = decoded_bitmap.getAddr32(0, y)[x]; 854 EXPECT_EQ(original_pixel_sk, decoded_pixel); 855 } 856 } 857} 858 859TEST(PNGCodec, DecodeInterlacedRGBAtoSkBitmap) { 860 const int w = 20, h = 20; 861 862 // create an image with known values 863 std::vector<unsigned char> original; 864 MakeRGBAImage(w, h, false, &original); 865 866 // encode 867 std::vector<unsigned char> encoded; 868 ASSERT_TRUE(EncodeImage(original, 869 w, h, 870 COLOR_TYPE_RGBA, 871 &encoded, 872 PNG_INTERLACE_ADAM7)); 873 874 // Decode the encoded string. 875 SkBitmap decoded_bitmap; 876 ASSERT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(), 877 &decoded_bitmap)); 878 879 for (int x = 0; x < w; x++) { 880 for (int y = 0; y < h; y++) { 881 const unsigned char* original_pixel = &original[(y * w + x) * 4]; 882 const uint32_t original_pixel_sk = SkPackARGB32(original_pixel[3], 883 original_pixel[0], 884 original_pixel[1], 885 original_pixel[2]); 886 const uint32_t decoded_pixel = decoded_bitmap.getAddr32(0, y)[x]; 887 EXPECT_EQ(original_pixel_sk, decoded_pixel); 888 } 889 } 890} 891 892// Test that corrupted data decompression causes failures. 893TEST(PNGCodec, DecodeCorrupted) { 894 int w = 20, h = 20; 895 896 // Make some random data (an uncompressed image). 897 std::vector<unsigned char> original; 898 MakeRGBImage(w, h, &original); 899 900 // It should fail when given non-JPEG compressed data. 901 std::vector<unsigned char> output; 902 int outw, outh; 903 EXPECT_FALSE(PNGCodec::Decode(&original[0], original.size(), 904 PNGCodec::FORMAT_RGB, &output, 905 &outw, &outh)); 906 907 // Make some compressed data. 908 std::vector<unsigned char> compressed; 909 ASSERT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB, 910 Size(w, h), w * 3, false, 911 std::vector<PNGCodec::Comment>(), 912 &compressed)); 913 914 // Try decompressing a truncated version. 915 EXPECT_FALSE(PNGCodec::Decode(&compressed[0], compressed.size() / 2, 916 PNGCodec::FORMAT_RGB, &output, 917 &outw, &outh)); 918 919 // Corrupt it and try decompressing that. 920 for (int i = 10; i < 30; i++) 921 compressed[i] = i; 922 EXPECT_FALSE(PNGCodec::Decode(&compressed[0], compressed.size(), 923 PNGCodec::FORMAT_RGB, &output, 924 &outw, &outh)); 925} 926 927TEST(PNGCodec, StripAddAlpha) { 928 const int w = 20, h = 20; 929 930 // These should be the same except one has a 0xff alpha channel. 931 std::vector<unsigned char> original_rgb; 932 MakeRGBImage(w, h, &original_rgb); 933 std::vector<unsigned char> original_rgba; 934 MakeRGBAImage(w, h, false, &original_rgba); 935 936 // Encode RGBA data as RGB. 937 std::vector<unsigned char> encoded; 938 EXPECT_TRUE(PNGCodec::Encode(&original_rgba[0], PNGCodec::FORMAT_RGBA, 939 Size(w, h), w * 4, true, 940 std::vector<PNGCodec::Comment>(), 941 &encoded)); 942 943 // Decode the RGB to RGBA. 944 std::vector<unsigned char> decoded; 945 int outw, outh; 946 EXPECT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), 947 PNGCodec::FORMAT_RGBA, &decoded, 948 &outw, &outh)); 949 950 // Decoded and reference should be the same (opaque alpha). 951 ASSERT_EQ(w, outw); 952 ASSERT_EQ(h, outh); 953 ASSERT_EQ(original_rgba.size(), decoded.size()); 954 ASSERT_EQ(original_rgba, decoded); 955 956 // Encode RGBA to RGBA. 957 EXPECT_TRUE(PNGCodec::Encode(&original_rgba[0], PNGCodec::FORMAT_RGBA, 958 Size(w, h), w * 4, false, 959 std::vector<PNGCodec::Comment>(), 960 &encoded)); 961 962 // Decode the RGBA to RGB. 963 EXPECT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(), 964 PNGCodec::FORMAT_RGB, &decoded, 965 &outw, &outh)); 966 967 // It should be the same as our non-alpha-channel reference. 968 ASSERT_EQ(w, outw); 969 ASSERT_EQ(h, outh); 970 ASSERT_EQ(original_rgb.size(), decoded.size()); 971 ASSERT_EQ(original_rgb, decoded); 972} 973 974TEST(PNGCodec, EncodeBGRASkBitmapStridePadded) { 975 const int kWidth = 20; 976 const int kHeight = 20; 977 const int kPaddedWidth = 32; 978 const int kBytesPerPixel = 4; 979 const int kPaddedSize = kPaddedWidth * kHeight; 980 const int kRowBytes = kPaddedWidth * kBytesPerPixel; 981 982 SkBitmap original_bitmap; 983 original_bitmap.setConfig(SkBitmap::kARGB_8888_Config, 984 kWidth, kHeight, kRowBytes); 985 original_bitmap.allocPixels(); 986 987 // Write data over the source bitmap. 988 // We write on the pad area here too. 989 // The encoder should ignore the pad area. 990 uint32_t* src_data = original_bitmap.getAddr32(0, 0); 991 for (int i = 0; i < kPaddedSize; i++) { 992 src_data[i] = SkPreMultiplyARGB(i % 255, i % 250, i % 245, i % 240); 993 } 994 995 // Encode the bitmap. 996 std::vector<unsigned char> encoded; 997 PNGCodec::EncodeBGRASkBitmap(original_bitmap, false, &encoded); 998 999 // Decode the encoded string. 1000 SkBitmap decoded_bitmap; 1001 EXPECT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(), 1002 &decoded_bitmap)); 1003 1004 // Compare the original bitmap and the output bitmap. We use ColorsClose 1005 // as SkBitmaps are considered to be pre-multiplied, the unpremultiplication 1006 // (in Encode) and repremultiplication (in Decode) can be lossy. 1007 for (int x = 0; x < kWidth; x++) { 1008 for (int y = 0; y < kHeight; y++) { 1009 uint32_t original_pixel = original_bitmap.getAddr32(0, y)[x]; 1010 uint32_t decoded_pixel = decoded_bitmap.getAddr32(0, y)[x]; 1011 EXPECT_TRUE(ColorsClose(original_pixel, decoded_pixel)); 1012 } 1013 } 1014} 1015 1016TEST(PNGCodec, EncodeBGRASkBitmap) { 1017 const int w = 20, h = 20; 1018 1019 SkBitmap original_bitmap; 1020 MakeTestSkBitmap(w, h, &original_bitmap); 1021 1022 // Encode the bitmap. 1023 std::vector<unsigned char> encoded; 1024 PNGCodec::EncodeBGRASkBitmap(original_bitmap, false, &encoded); 1025 1026 // Decode the encoded string. 1027 SkBitmap decoded_bitmap; 1028 EXPECT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(), 1029 &decoded_bitmap)); 1030 1031 // Compare the original bitmap and the output bitmap. We use ColorsClose 1032 // as SkBitmaps are considered to be pre-multiplied, the unpremultiplication 1033 // (in Encode) and repremultiplication (in Decode) can be lossy. 1034 for (int x = 0; x < w; x++) { 1035 for (int y = 0; y < h; y++) { 1036 uint32_t original_pixel = original_bitmap.getAddr32(0, y)[x]; 1037 uint32_t decoded_pixel = decoded_bitmap.getAddr32(0, y)[x]; 1038 EXPECT_TRUE(ColorsClose(original_pixel, decoded_pixel)); 1039 } 1040 } 1041} 1042 1043TEST(PNGCodec, EncodeBGRASkBitmapDiscardTransparency) { 1044 const int w = 20, h = 20; 1045 1046 SkBitmap original_bitmap; 1047 MakeTestSkBitmap(w, h, &original_bitmap); 1048 1049 // Encode the bitmap. 1050 std::vector<unsigned char> encoded; 1051 PNGCodec::EncodeBGRASkBitmap(original_bitmap, true, &encoded); 1052 1053 // Decode the encoded string. 1054 SkBitmap decoded_bitmap; 1055 EXPECT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(), 1056 &decoded_bitmap)); 1057 1058 // Compare the original bitmap and the output bitmap. We need to 1059 // unpremultiply original_pixel, as the decoded bitmap doesn't have an alpha 1060 // channel. 1061 for (int x = 0; x < w; x++) { 1062 for (int y = 0; y < h; y++) { 1063 uint32_t original_pixel = original_bitmap.getAddr32(0, y)[x]; 1064 uint32_t unpremultiplied = 1065 SkUnPreMultiply::PMColorToColor(original_pixel); 1066 uint32_t decoded_pixel = decoded_bitmap.getAddr32(0, y)[x]; 1067 uint32_t unpremultiplied_decoded = 1068 SkUnPreMultiply::PMColorToColor(decoded_pixel); 1069 1070 EXPECT_TRUE(NonAlphaColorsClose(unpremultiplied, unpremultiplied_decoded)) 1071 << "Original_pixel: (" 1072 << SkColorGetR(unpremultiplied) << ", " 1073 << SkColorGetG(unpremultiplied) << ", " 1074 << SkColorGetB(unpremultiplied) << "), " 1075 << "Decoded pixel: (" 1076 << SkColorGetR(unpremultiplied_decoded) << ", " 1077 << SkColorGetG(unpremultiplied_decoded) << ", " 1078 << SkColorGetB(unpremultiplied_decoded) << ")"; 1079 } 1080 } 1081} 1082 1083TEST(PNGCodec, EncodeWithComment) { 1084 const int w = 10, h = 10; 1085 1086 std::vector<unsigned char> original; 1087 MakeRGBImage(w, h, &original); 1088 1089 std::vector<unsigned char> encoded; 1090 std::vector<PNGCodec::Comment> comments; 1091 comments.push_back(PNGCodec::Comment("key", "text")); 1092 comments.push_back(PNGCodec::Comment("test", "something")); 1093 comments.push_back(PNGCodec::Comment("have some", "spaces in both")); 1094 EXPECT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB, 1095 Size(w, h), w * 3, false, comments, &encoded)); 1096 1097 // Each chunk is of the form length (4 bytes), chunk type (tEXt), data, 1098 // checksum (4 bytes). Make sure we find all of them in the encoded 1099 // results. 1100 const unsigned char kExpected1[] = 1101 "\x00\x00\x00\x08tEXtkey\x00text\x9e\xe7\x66\x51"; 1102 const unsigned char kExpected2[] = 1103 "\x00\x00\x00\x0etEXttest\x00something\x29\xba\xef\xac"; 1104 const unsigned char kExpected3[] = 1105 "\x00\x00\x00\x18tEXthave some\x00spaces in both\x8d\x69\x34\x2d"; 1106 1107 EXPECT_NE(std::search(encoded.begin(), encoded.end(), kExpected1, 1108 kExpected1 + arraysize(kExpected1)), 1109 encoded.end()); 1110 EXPECT_NE(std::search(encoded.begin(), encoded.end(), kExpected2, 1111 kExpected2 + arraysize(kExpected2)), 1112 encoded.end()); 1113 EXPECT_NE(std::search(encoded.begin(), encoded.end(), kExpected3, 1114 kExpected3 + arraysize(kExpected3)), 1115 encoded.end()); 1116} 1117 1118TEST(PNGCodec, EncodeDecodeWithVaryingCompressionLevels) { 1119 const int w = 20, h = 20; 1120 1121 // create an image with known values, a must be opaque because it will be 1122 // lost during encoding 1123 SkBitmap original_bitmap; 1124 MakeTestSkBitmap(w, h, &original_bitmap); 1125 1126 // encode 1127 std::vector<unsigned char> encoded_normal; 1128 EXPECT_TRUE( 1129 PNGCodec::EncodeBGRASkBitmap(original_bitmap, false, &encoded_normal)); 1130 1131 std::vector<unsigned char> encoded_fast; 1132 EXPECT_TRUE( 1133 PNGCodec::FastEncodeBGRASkBitmap(original_bitmap, false, &encoded_fast)); 1134 1135 // Make sure the different compression settings actually do something; the 1136 // sizes should be different. 1137 EXPECT_NE(encoded_normal.size(), encoded_fast.size()); 1138 1139 // decode, they should be identical to the original. 1140 SkBitmap decoded; 1141 EXPECT_TRUE( 1142 PNGCodec::Decode(&encoded_normal[0], encoded_normal.size(), &decoded)); 1143 EXPECT_TRUE(BitmapsAreEqual(decoded, original_bitmap)); 1144 1145 EXPECT_TRUE( 1146 PNGCodec::Decode(&encoded_fast[0], encoded_fast.size(), &decoded)); 1147 EXPECT_TRUE(BitmapsAreEqual(decoded, original_bitmap)); 1148} 1149 1150 1151} // namespace gfx 1152