Performance histograms for extension content verification
[chromium-blink-merge.git] / ui / gfx / codec / png_codec_unittest.cc
blob37816807ba991962eb7f2a24c7b5004240b6b0ee
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.
5 #include <algorithm>
6 #include <cmath>
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"
19 namespace gfx {
21 namespace {
23 void 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
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.
39 void 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)
56 // Creates a palette-based image.
57 void 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;
69 for (int y = 0; y < h; y++) {
70 for (int x = 0; x < w; x++) {
71 (*data)[y * w + x] = x; // palette index
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;
82 // Creates a grayscale image without an alpha channel.
83 void 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
93 // Creates a grayscale image with an alpha channel.
94 void 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
106 // User write function (to be passed to libpng by EncodeImage) which writes
107 // into a buffer instead of to a file.
108 void 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);
117 // User flush function; goes with WriteImageData, above.
118 void FlushImageData(png_structp /*png_ptr*/) {
121 // Libpng user error function which allows us to print libpng errors using
122 // Chrome's logging facilities instead of stderr.
123 void 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);
129 // Goes with LogLibPNGError, above.
130 void LogLibPNGWarning(png_structp png_ptr,
131 png_const_charp warning_msg) {
132 DLOG(ERROR) << "libpng encode warning: " << warning_msg;
135 // Color types supported by EncodeImage. Required because neither libpng nor
136 // PNGCodec::Encode supports all of the required values.
137 enum 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
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.
150 bool 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);
160 int input_rowbytes = 0;
161 int transforms = PNG_TRANSFORM_IDENTITY;
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;
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;
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]);
208 if (setjmp(png_jmpbuf(png_ptr))) {
209 png_destroy_write_struct(&png_ptr, &info_ptr);
210 return false;
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);
228 png_write_png(png_ptr, info_ptr, transforms, NULL);
230 png_destroy_write_struct(&png_ptr, &info_ptr);
231 return true;
234 } // namespace
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.
238 bool 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;
245 // Returns true if the RGB components are "close."
246 bool 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;
252 // Returns true if the BGRA 32-bit SkColor specified by |a| is equivalent to the
253 // 8-bit Gray color specified by |b|.
254 bool BGRAGrayEqualsA8Gray(uint32_t a, uint8_t b) {
255 return SkColorGetB(a) == b && SkColorGetG(a) == b &&
256 SkColorGetR(a) == b && SkColorGetA(a) == 255;
259 void MakeTestBGRASkBitmap(int w, int h, SkBitmap* bmp) {
260 bmp->setConfig(SkBitmap::kARGB_8888_Config, w, h);
261 bmp->allocPixels();
263 uint32_t* src_data = bmp->getAddr32(0, 0);
264 for (int i = 0; i < w * h; i++)
265 src_data[i] = SkPreMultiplyARGB(i % 255, i % 250, i % 245, i % 240);
268 void MakeTestA8SkBitmap(int w, int h, SkBitmap* bmp) {
269 bmp->setConfig(SkBitmap::kA8_Config, w, h);
270 bmp->allocPixels();
272 uint8_t* src_data = bmp->getAddr8(0, 0);
273 for (int i = 0; i < w * h; i++)
274 src_data[i] = i % 255;
277 TEST(PNGCodec, EncodeDecodeRGB) {
278 const int w = 20, h = 20;
280 // create an image with known values
281 std::vector<unsigned char> original;
282 MakeRGBImage(w, h, &original);
284 // encode
285 std::vector<unsigned char> encoded;
286 ASSERT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB,
287 Size(w, h), w * 3, false,
288 std::vector<PNGCodec::Comment>(),
289 &encoded));
291 // decode, it should have the same size as the original
292 std::vector<unsigned char> decoded;
293 int outw, outh;
294 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
295 PNGCodec::FORMAT_RGB, &decoded,
296 &outw, &outh));
297 ASSERT_EQ(w, outw);
298 ASSERT_EQ(h, outh);
299 ASSERT_EQ(original.size(), decoded.size());
301 // Images must be equal
302 ASSERT_TRUE(original == decoded);
305 TEST(PNGCodec, EncodeDecodeRGBA) {
306 const int w = 20, h = 20;
308 // create an image with known values, a must be opaque because it will be
309 // lost during encoding
310 std::vector<unsigned char> original;
311 MakeRGBAImage(w, h, true, &original);
313 // encode
314 std::vector<unsigned char> encoded;
315 ASSERT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGBA,
316 Size(w, h), w * 4, false,
317 std::vector<PNGCodec::Comment>(),
318 &encoded));
320 // decode, it should have the same size as the original
321 std::vector<unsigned char> decoded;
322 int outw, outh;
323 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
324 PNGCodec::FORMAT_RGBA, &decoded,
325 &outw, &outh));
326 ASSERT_EQ(w, outw);
327 ASSERT_EQ(h, outh);
328 ASSERT_EQ(original.size(), decoded.size());
330 // Images must be exactly equal
331 ASSERT_TRUE(original == decoded);
334 TEST(PNGCodec, EncodeDecodeBGRA) {
335 const int w = 20, h = 20;
337 // Create an image with known values, alpha must be opaque because it will be
338 // lost during encoding.
339 std::vector<unsigned char> original;
340 MakeRGBAImage(w, h, true, &original);
342 // Encode.
343 std::vector<unsigned char> encoded;
344 ASSERT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_BGRA,
345 Size(w, h), w * 4, false,
346 std::vector<PNGCodec::Comment>(),
347 &encoded));
349 // Decode, it should have the same size as the original.
350 std::vector<unsigned char> decoded;
351 int outw, outh;
352 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
353 PNGCodec::FORMAT_BGRA, &decoded,
354 &outw, &outh));
355 ASSERT_EQ(w, outw);
356 ASSERT_EQ(h, outh);
357 ASSERT_EQ(original.size(), decoded.size());
359 // Images must be exactly equal.
360 ASSERT_TRUE(original == decoded);
363 TEST(PNGCodec, DecodePalette) {
364 const int w = 20, h = 20;
366 // create an image with known values
367 std::vector<unsigned char> original;
368 std::vector<png_color> original_palette;
369 std::vector<unsigned char> original_trans_chunk;
370 MakePaletteImage(w, h, &original, &original_palette, &original_trans_chunk);
372 // encode
373 std::vector<unsigned char> encoded;
374 ASSERT_TRUE(EncodeImage(original,
375 w, h,
376 COLOR_TYPE_PALETTE,
377 &encoded,
378 PNG_INTERLACE_NONE,
379 &original_palette,
380 &original_trans_chunk));
382 // decode
383 std::vector<unsigned char> decoded;
384 int outw, outh;
385 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
386 PNGCodec::FORMAT_RGBA, &decoded,
387 &outw, &outh));
388 ASSERT_EQ(w, outw);
389 ASSERT_EQ(h, outh);
390 ASSERT_EQ(decoded.size(), w * h * 4U);
392 // Images must be equal
393 for (int y = 0; y < h; ++y) {
394 for (int x = 0; x < w; ++x) {
395 unsigned char palette_pixel = original[y * w + x];
396 png_color& palette_color = original_palette[palette_pixel];
397 int alpha = original_trans_chunk[palette_pixel];
398 unsigned char* rgba_pixel = &decoded[(y * w + x) * 4];
400 EXPECT_EQ(palette_color.red, rgba_pixel[0]);
401 EXPECT_EQ(palette_color.green, rgba_pixel[1]);
402 EXPECT_EQ(palette_color.blue, rgba_pixel[2]);
403 EXPECT_EQ(alpha, rgba_pixel[3]);
408 TEST(PNGCodec, DecodePaletteDiscardAlpha) {
409 const int w = 20, h = 20;
411 // create an image with known values
412 std::vector<unsigned char> original;
413 std::vector<png_color> original_palette;
414 std::vector<unsigned char> original_trans_chunk;
415 MakePaletteImage(w, h, &original, &original_palette, &original_trans_chunk);
417 // encode
418 std::vector<unsigned char> encoded;
419 ASSERT_TRUE(EncodeImage(original,
420 w, h,
421 COLOR_TYPE_PALETTE,
422 &encoded,
423 PNG_INTERLACE_NONE,
424 &original_palette,
425 &original_trans_chunk));
427 // decode
428 std::vector<unsigned char> decoded;
429 int outw, outh;
430 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
431 PNGCodec::FORMAT_RGB, &decoded,
432 &outw, &outh));
433 ASSERT_EQ(w, outw);
434 ASSERT_EQ(h, outh);
435 ASSERT_EQ(decoded.size(), w * h * 3U);
437 // Images must be equal
438 for (int y = 0; y < h; ++y) {
439 for (int x = 0; x < w; ++x) {
440 unsigned char palette_pixel = original[y * w + x];
441 png_color& palette_color = original_palette[palette_pixel];
442 unsigned char* rgba_pixel = &decoded[(y * w + x) * 3];
444 EXPECT_EQ(palette_color.red, rgba_pixel[0]);
445 EXPECT_EQ(palette_color.green, rgba_pixel[1]);
446 EXPECT_EQ(palette_color.blue, rgba_pixel[2]);
451 TEST(PNGCodec, DecodeInterlacedPalette) {
452 const int w = 20, h = 20;
454 // create an image with known values
455 std::vector<unsigned char> original;
456 std::vector<png_color> original_palette;
457 std::vector<unsigned char> original_trans_chunk;
458 MakePaletteImage(w, h, &original, &original_palette, &original_trans_chunk);
460 // encode
461 std::vector<unsigned char> encoded;
462 ASSERT_TRUE(EncodeImage(original,
463 w, h,
464 COLOR_TYPE_PALETTE,
465 &encoded,
466 PNG_INTERLACE_ADAM7,
467 &original_palette,
468 &original_trans_chunk));
470 // decode
471 std::vector<unsigned char> decoded;
472 int outw, outh;
473 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
474 PNGCodec::FORMAT_RGBA, &decoded,
475 &outw, &outh));
476 ASSERT_EQ(w, outw);
477 ASSERT_EQ(h, outh);
478 ASSERT_EQ(decoded.size(), w * h * 4U);
480 // Images must be equal
481 for (int y = 0; y < h; ++y) {
482 for (int x = 0; x < w; ++x) {
483 unsigned char palette_pixel = original[y * w + x];
484 png_color& palette_color = original_palette[palette_pixel];
485 int alpha = original_trans_chunk[palette_pixel];
486 unsigned char* rgba_pixel = &decoded[(y * w + x) * 4];
488 EXPECT_EQ(palette_color.red, rgba_pixel[0]);
489 EXPECT_EQ(palette_color.green, rgba_pixel[1]);
490 EXPECT_EQ(palette_color.blue, rgba_pixel[2]);
491 EXPECT_EQ(alpha, rgba_pixel[3]);
496 TEST(PNGCodec, DecodeGrayscale) {
497 const int w = 20, h = 20;
499 // create an image with known values
500 std::vector<unsigned char> original;
501 MakeGrayscaleImage(w, h, &original);
503 // encode
504 std::vector<unsigned char> encoded;
505 ASSERT_TRUE(EncodeImage(original, w, h, COLOR_TYPE_GRAY, &encoded));
507 // decode
508 std::vector<unsigned char> decoded;
509 int outw, outh;
510 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
511 PNGCodec::FORMAT_RGB, &decoded,
512 &outw, &outh));
513 ASSERT_EQ(w, outw);
514 ASSERT_EQ(h, outh);
515 ASSERT_EQ(decoded.size(), original.size() * 3);
517 // Images must be equal
518 for (int y = 0; y < h; ++y) {
519 for (int x = 0; x < w; ++x) {
520 unsigned char gray_pixel = original[(y * w + x)];
521 unsigned char* rgba_pixel = &decoded[(y * w + x) * 3];
522 EXPECT_EQ(rgba_pixel[0], gray_pixel);
523 EXPECT_EQ(rgba_pixel[1], gray_pixel);
524 EXPECT_EQ(rgba_pixel[2], gray_pixel);
529 TEST(PNGCodec, DecodeGrayscaleWithAlpha) {
530 const int w = 20, h = 20;
532 // create an image with known values
533 std::vector<unsigned char> original;
534 MakeGrayscaleAlphaImage(w, h, &original);
536 // encode
537 std::vector<unsigned char> encoded;
538 ASSERT_TRUE(EncodeImage(original,
539 w, h,
540 COLOR_TYPE_GRAY_ALPHA,
541 &encoded));
543 // decode
544 std::vector<unsigned char> decoded;
545 int outw, outh;
546 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
547 PNGCodec::FORMAT_RGBA, &decoded,
548 &outw, &outh));
549 ASSERT_EQ(w, outw);
550 ASSERT_EQ(h, outh);
551 ASSERT_EQ(decoded.size(), original.size() * 2);
553 // Images must be equal
554 for (int y = 0; y < h; ++y) {
555 for (int x = 0; x < w; ++x) {
556 unsigned char* gray_pixel = &original[(y * w + x) * 2];
557 unsigned char* rgba_pixel = &decoded[(y * w + x) * 4];
558 EXPECT_EQ(rgba_pixel[0], gray_pixel[0]);
559 EXPECT_EQ(rgba_pixel[1], gray_pixel[0]);
560 EXPECT_EQ(rgba_pixel[2], gray_pixel[0]);
561 EXPECT_EQ(rgba_pixel[3], gray_pixel[1]);
566 TEST(PNGCodec, DecodeGrayscaleWithAlphaDiscardAlpha) {
567 const int w = 20, h = 20;
569 // create an image with known values
570 std::vector<unsigned char> original;
571 MakeGrayscaleAlphaImage(w, h, &original);
573 // encode
574 std::vector<unsigned char> encoded;
575 ASSERT_TRUE(EncodeImage(original,
576 w, h,
577 COLOR_TYPE_GRAY_ALPHA,
578 &encoded));
580 // decode
581 std::vector<unsigned char> decoded;
582 int outw, outh;
583 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
584 PNGCodec::FORMAT_RGB, &decoded,
585 &outw, &outh));
586 ASSERT_EQ(w, outw);
587 ASSERT_EQ(h, outh);
588 ASSERT_EQ(decoded.size(), w * h * 3U);
590 // Images must be equal
591 for (int y = 0; y < h; ++y) {
592 for (int x = 0; x < w; ++x) {
593 unsigned char* gray_pixel = &original[(y * w + x) * 2];
594 unsigned char* rgba_pixel = &decoded[(y * w + x) * 3];
595 EXPECT_EQ(rgba_pixel[0], gray_pixel[0]);
596 EXPECT_EQ(rgba_pixel[1], gray_pixel[0]);
597 EXPECT_EQ(rgba_pixel[2], gray_pixel[0]);
602 TEST(PNGCodec, DecodeInterlacedGrayscale) {
603 const int w = 20, h = 20;
605 // create an image with known values
606 std::vector<unsigned char> original;
607 MakeGrayscaleImage(w, h, &original);
609 // encode
610 std::vector<unsigned char> encoded;
611 ASSERT_TRUE(EncodeImage(original,
612 w, h,
613 COLOR_TYPE_GRAY,
614 &encoded,
615 PNG_INTERLACE_ADAM7));
617 // decode
618 std::vector<unsigned char> decoded;
619 int outw, outh;
620 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
621 PNGCodec::FORMAT_RGBA, &decoded,
622 &outw, &outh));
623 ASSERT_EQ(w, outw);
624 ASSERT_EQ(h, outh);
625 ASSERT_EQ(decoded.size(), original.size() * 4);
627 // Images must be equal
628 for (int y = 0; y < h; ++y) {
629 for (int x = 0; x < w; ++x) {
630 unsigned char gray_pixel = original[(y * w + x)];
631 unsigned char* rgba_pixel = &decoded[(y * w + x) * 4];
632 EXPECT_EQ(rgba_pixel[0], gray_pixel);
633 EXPECT_EQ(rgba_pixel[1], gray_pixel);
634 EXPECT_EQ(rgba_pixel[2], gray_pixel);
635 EXPECT_EQ(rgba_pixel[3], 0xFF);
640 TEST(PNGCodec, DecodeInterlacedGrayscaleWithAlpha) {
641 const int w = 20, h = 20;
643 // create an image with known values
644 std::vector<unsigned char> original;
645 MakeGrayscaleAlphaImage(w, h, &original);
647 // encode
648 std::vector<unsigned char> encoded;
649 ASSERT_TRUE(EncodeImage(original,
650 w, h,
651 COLOR_TYPE_GRAY_ALPHA,
652 &encoded,
653 PNG_INTERLACE_ADAM7));
655 // decode
656 std::vector<unsigned char> decoded;
657 int outw, outh;
658 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
659 PNGCodec::FORMAT_RGBA, &decoded,
660 &outw, &outh));
661 ASSERT_EQ(w, outw);
662 ASSERT_EQ(h, outh);
663 ASSERT_EQ(decoded.size(), original.size() * 2);
665 // Images must be equal
666 for (int y = 0; y < h; ++y) {
667 for (int x = 0; x < w; ++x) {
668 unsigned char* gray_pixel = &original[(y * w + x) * 2];
669 unsigned char* rgba_pixel = &decoded[(y * w + x) * 4];
670 EXPECT_EQ(rgba_pixel[0], gray_pixel[0]);
671 EXPECT_EQ(rgba_pixel[1], gray_pixel[0]);
672 EXPECT_EQ(rgba_pixel[2], gray_pixel[0]);
673 EXPECT_EQ(rgba_pixel[3], gray_pixel[1]);
678 TEST(PNGCodec, DecodeInterlacedRGB) {
679 const int w = 20, h = 20;
681 // create an image with known values
682 std::vector<unsigned char> original;
683 MakeRGBImage(w, h, &original);
685 // encode
686 std::vector<unsigned char> encoded;
687 ASSERT_TRUE(EncodeImage(original,
688 w, h,
689 COLOR_TYPE_RGB,
690 &encoded,
691 PNG_INTERLACE_ADAM7));
693 // decode, it should have the same size as the original
694 std::vector<unsigned char> decoded;
695 int outw, outh;
696 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
697 PNGCodec::FORMAT_RGB, &decoded,
698 &outw, &outh));
699 ASSERT_EQ(w, outw);
700 ASSERT_EQ(h, outh);
701 ASSERT_EQ(original.size(), decoded.size());
703 // Images must be equal
704 ASSERT_EQ(original, decoded);
707 TEST(PNGCodec, DecodeInterlacedRGBA) {
708 const int w = 20, h = 20;
710 // create an image with known values
711 std::vector<unsigned char> original;
712 MakeRGBAImage(w, h, false, &original);
714 // encode
715 std::vector<unsigned char> encoded;
716 ASSERT_TRUE(EncodeImage(original,
717 w, h,
718 COLOR_TYPE_RGBA,
719 &encoded,
720 PNG_INTERLACE_ADAM7));
722 // decode, it should have the same size as the original
723 std::vector<unsigned char> decoded;
724 int outw, outh;
725 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
726 PNGCodec::FORMAT_RGBA, &decoded,
727 &outw, &outh));
728 ASSERT_EQ(w, outw);
729 ASSERT_EQ(h, outh);
730 ASSERT_EQ(original.size(), decoded.size());
732 // Images must be equal
733 ASSERT_EQ(original, decoded);
736 TEST(PNGCodec, DecodeInterlacedRGBADiscardAlpha) {
737 const int w = 20, h = 20;
739 // create an image with known values
740 std::vector<unsigned char> original;
741 MakeRGBAImage(w, h, false, &original);
743 // encode
744 std::vector<unsigned char> encoded;
745 ASSERT_TRUE(EncodeImage(original,
746 w, h,
747 COLOR_TYPE_RGBA,
748 &encoded,
749 PNG_INTERLACE_ADAM7));
751 // decode
752 std::vector<unsigned char> decoded;
753 int outw, outh;
754 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
755 PNGCodec::FORMAT_RGB, &decoded,
756 &outw, &outh));
757 ASSERT_EQ(w, outw);
758 ASSERT_EQ(h, outh);
759 ASSERT_EQ(decoded.size(), w * h * 3U);
761 // Images must be equal
762 for (int x = 0; x < w; x++) {
763 for (int y = 0; y < h; y++) {
764 unsigned char* orig_px = &original[(y * w + x) * 4];
765 unsigned char* dec_px = &decoded[(y * w + x) * 3];
766 EXPECT_EQ(dec_px[0], orig_px[0]);
767 EXPECT_EQ(dec_px[1], orig_px[1]);
768 EXPECT_EQ(dec_px[2], orig_px[2]);
773 TEST(PNGCodec, DecodeInterlacedBGR) {
774 const int w = 20, h = 20;
776 // create an image with known values
777 std::vector<unsigned char> original;
778 MakeRGBImage(w, h, &original);
780 // encode
781 std::vector<unsigned char> encoded;
782 ASSERT_TRUE(EncodeImage(original,
783 w, h,
784 COLOR_TYPE_BGR,
785 &encoded,
786 PNG_INTERLACE_ADAM7));
788 // decode, it should have the same size as the original
789 std::vector<unsigned char> decoded;
790 int outw, outh;
791 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
792 PNGCodec::FORMAT_BGRA, &decoded,
793 &outw, &outh));
794 ASSERT_EQ(w, outw);
795 ASSERT_EQ(h, outh);
796 ASSERT_EQ(decoded.size(), w * h * 4U);
798 // Images must be equal
799 for (int x = 0; x < w; x++) {
800 for (int y = 0; y < h; y++) {
801 unsigned char* orig_px = &original[(y * w + x) * 3];
802 unsigned char* dec_px = &decoded[(y * w + x) * 4];
803 EXPECT_EQ(dec_px[0], orig_px[0]);
804 EXPECT_EQ(dec_px[1], orig_px[1]);
805 EXPECT_EQ(dec_px[2], orig_px[2]);
810 TEST(PNGCodec, DecodeInterlacedBGRA) {
811 const int w = 20, h = 20;
813 // create an image with known values
814 std::vector<unsigned char> original;
815 MakeRGBAImage(w, h, false, &original);
817 // encode
818 std::vector<unsigned char> encoded;
819 ASSERT_TRUE(EncodeImage(original,
820 w, h,
821 COLOR_TYPE_BGRA,
822 &encoded,
823 PNG_INTERLACE_ADAM7));
825 // decode, it should have the same size as the original
826 std::vector<unsigned char> decoded;
827 int outw, outh;
828 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
829 PNGCodec::FORMAT_BGRA, &decoded,
830 &outw, &outh));
831 ASSERT_EQ(w, outw);
832 ASSERT_EQ(h, outh);
833 ASSERT_EQ(original.size(), decoded.size());
835 // Images must be equal
836 ASSERT_EQ(original, decoded);
839 // Not encoding an interlaced PNG from SkBitmap because we don't do it
840 // anywhere, and the ability to do that requires more code changes.
841 TEST(PNGCodec, DecodeInterlacedRGBtoSkBitmap) {
842 const int w = 20, h = 20;
844 // create an image with known values
845 std::vector<unsigned char> original;
846 MakeRGBImage(w, h, &original);
848 // encode
849 std::vector<unsigned char> encoded;
850 ASSERT_TRUE(EncodeImage(original,
851 w, h,
852 COLOR_TYPE_RGB,
853 &encoded,
854 PNG_INTERLACE_ADAM7));
856 // Decode the encoded string.
857 SkBitmap decoded_bitmap;
858 ASSERT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(),
859 &decoded_bitmap));
861 for (int x = 0; x < w; x++) {
862 for (int y = 0; y < h; y++) {
863 const unsigned char* original_pixel = &original[(y * w + x) * 3];
864 const uint32_t original_pixel_sk = SkPackARGB32(0xFF,
865 original_pixel[0],
866 original_pixel[1],
867 original_pixel[2]);
868 const uint32_t decoded_pixel = decoded_bitmap.getAddr32(0, y)[x];
869 EXPECT_EQ(original_pixel_sk, decoded_pixel);
874 TEST(PNGCodec, DecodeInterlacedRGBAtoSkBitmap) {
875 const int w = 20, h = 20;
877 // create an image with known values
878 std::vector<unsigned char> original;
879 MakeRGBAImage(w, h, false, &original);
881 // encode
882 std::vector<unsigned char> encoded;
883 ASSERT_TRUE(EncodeImage(original,
884 w, h,
885 COLOR_TYPE_RGBA,
886 &encoded,
887 PNG_INTERLACE_ADAM7));
889 // Decode the encoded string.
890 SkBitmap decoded_bitmap;
891 ASSERT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(),
892 &decoded_bitmap));
894 for (int x = 0; x < w; x++) {
895 for (int y = 0; y < h; y++) {
896 const unsigned char* original_pixel = &original[(y * w + x) * 4];
897 const uint32_t original_pixel_sk = SkPackARGB32(original_pixel[3],
898 original_pixel[0],
899 original_pixel[1],
900 original_pixel[2]);
901 const uint32_t decoded_pixel = decoded_bitmap.getAddr32(0, y)[x];
902 EXPECT_EQ(original_pixel_sk, decoded_pixel);
907 // Test that corrupted data decompression causes failures.
908 TEST(PNGCodec, DecodeCorrupted) {
909 int w = 20, h = 20;
911 // Make some random data (an uncompressed image).
912 std::vector<unsigned char> original;
913 MakeRGBImage(w, h, &original);
915 // It should fail when given non-JPEG compressed data.
916 std::vector<unsigned char> output;
917 int outw, outh;
918 EXPECT_FALSE(PNGCodec::Decode(&original[0], original.size(),
919 PNGCodec::FORMAT_RGB, &output,
920 &outw, &outh));
922 // Make some compressed data.
923 std::vector<unsigned char> compressed;
924 ASSERT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB,
925 Size(w, h), w * 3, false,
926 std::vector<PNGCodec::Comment>(),
927 &compressed));
929 // Try decompressing a truncated version.
930 EXPECT_FALSE(PNGCodec::Decode(&compressed[0], compressed.size() / 2,
931 PNGCodec::FORMAT_RGB, &output,
932 &outw, &outh));
934 // Corrupt it and try decompressing that.
935 for (int i = 10; i < 30; i++)
936 compressed[i] = i;
937 EXPECT_FALSE(PNGCodec::Decode(&compressed[0], compressed.size(),
938 PNGCodec::FORMAT_RGB, &output,
939 &outw, &outh));
942 TEST(PNGCodec, StripAddAlpha) {
943 const int w = 20, h = 20;
945 // These should be the same except one has a 0xff alpha channel.
946 std::vector<unsigned char> original_rgb;
947 MakeRGBImage(w, h, &original_rgb);
948 std::vector<unsigned char> original_rgba;
949 MakeRGBAImage(w, h, false, &original_rgba);
951 // Encode RGBA data as RGB.
952 std::vector<unsigned char> encoded;
953 EXPECT_TRUE(PNGCodec::Encode(&original_rgba[0], PNGCodec::FORMAT_RGBA,
954 Size(w, h), w * 4, true,
955 std::vector<PNGCodec::Comment>(),
956 &encoded));
958 // Decode the RGB to RGBA.
959 std::vector<unsigned char> decoded;
960 int outw, outh;
961 EXPECT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
962 PNGCodec::FORMAT_RGBA, &decoded,
963 &outw, &outh));
965 // Decoded and reference should be the same (opaque alpha).
966 ASSERT_EQ(w, outw);
967 ASSERT_EQ(h, outh);
968 ASSERT_EQ(original_rgba.size(), decoded.size());
969 ASSERT_EQ(original_rgba, decoded);
971 // Encode RGBA to RGBA.
972 EXPECT_TRUE(PNGCodec::Encode(&original_rgba[0], PNGCodec::FORMAT_RGBA,
973 Size(w, h), w * 4, false,
974 std::vector<PNGCodec::Comment>(),
975 &encoded));
977 // Decode the RGBA to RGB.
978 EXPECT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
979 PNGCodec::FORMAT_RGB, &decoded,
980 &outw, &outh));
982 // It should be the same as our non-alpha-channel reference.
983 ASSERT_EQ(w, outw);
984 ASSERT_EQ(h, outh);
985 ASSERT_EQ(original_rgb.size(), decoded.size());
986 ASSERT_EQ(original_rgb, decoded);
989 TEST(PNGCodec, EncodeBGRASkBitmapStridePadded) {
990 const int kWidth = 20;
991 const int kHeight = 20;
992 const int kPaddedWidth = 32;
993 const int kBytesPerPixel = 4;
994 const int kPaddedSize = kPaddedWidth * kHeight;
995 const int kRowBytes = kPaddedWidth * kBytesPerPixel;
997 SkBitmap original_bitmap;
998 original_bitmap.setConfig(SkBitmap::kARGB_8888_Config,
999 kWidth, kHeight, kRowBytes);
1000 original_bitmap.allocPixels();
1002 // Write data over the source bitmap.
1003 // We write on the pad area here too.
1004 // The encoder should ignore the pad area.
1005 uint32_t* src_data = original_bitmap.getAddr32(0, 0);
1006 for (int i = 0; i < kPaddedSize; i++) {
1007 src_data[i] = SkPreMultiplyARGB(i % 255, i % 250, i % 245, i % 240);
1010 // Encode the bitmap.
1011 std::vector<unsigned char> encoded;
1012 PNGCodec::EncodeBGRASkBitmap(original_bitmap, false, &encoded);
1014 // Decode the encoded string.
1015 SkBitmap decoded_bitmap;
1016 EXPECT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(),
1017 &decoded_bitmap));
1019 // Compare the original bitmap and the output bitmap. We use ColorsClose
1020 // as SkBitmaps are considered to be pre-multiplied, the unpremultiplication
1021 // (in Encode) and repremultiplication (in Decode) can be lossy.
1022 for (int x = 0; x < kWidth; x++) {
1023 for (int y = 0; y < kHeight; y++) {
1024 uint32_t original_pixel = original_bitmap.getAddr32(0, y)[x];
1025 uint32_t decoded_pixel = decoded_bitmap.getAddr32(0, y)[x];
1026 EXPECT_TRUE(ColorsClose(original_pixel, decoded_pixel));
1031 TEST(PNGCodec, EncodeBGRASkBitmap) {
1032 const int w = 20, h = 20;
1034 SkBitmap original_bitmap;
1035 MakeTestBGRASkBitmap(w, h, &original_bitmap);
1037 // Encode the bitmap.
1038 std::vector<unsigned char> encoded;
1039 PNGCodec::EncodeBGRASkBitmap(original_bitmap, false, &encoded);
1041 // Decode the encoded string.
1042 SkBitmap decoded_bitmap;
1043 EXPECT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(),
1044 &decoded_bitmap));
1046 // Compare the original bitmap and the output bitmap. We use ColorsClose
1047 // as SkBitmaps are considered to be pre-multiplied, the unpremultiplication
1048 // (in Encode) and repremultiplication (in Decode) can be lossy.
1049 for (int x = 0; x < w; x++) {
1050 for (int y = 0; y < h; y++) {
1051 uint32_t original_pixel = original_bitmap.getAddr32(0, y)[x];
1052 uint32_t decoded_pixel = decoded_bitmap.getAddr32(0, y)[x];
1053 EXPECT_TRUE(ColorsClose(original_pixel, decoded_pixel));
1058 TEST(PNGCodec, EncodeA8SkBitmap) {
1059 const int w = 20, h = 20;
1061 SkBitmap original_bitmap;
1062 MakeTestA8SkBitmap(w, h, &original_bitmap);
1064 // Encode the bitmap.
1065 std::vector<unsigned char> encoded;
1066 EXPECT_TRUE(PNGCodec::EncodeA8SkBitmap(original_bitmap, &encoded));
1068 // Decode the encoded string.
1069 SkBitmap decoded_bitmap;
1070 EXPECT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(),
1071 &decoded_bitmap));
1073 for (int x = 0; x < w; x++) {
1074 for (int y = 0; y < h; y++) {
1075 uint8_t original_pixel = *original_bitmap.getAddr8(x, y);
1076 uint32_t decoded_pixel = *decoded_bitmap.getAddr32(x, y);
1077 EXPECT_TRUE(BGRAGrayEqualsA8Gray(decoded_pixel, original_pixel));
1082 TEST(PNGCodec, EncodeBGRASkBitmapDiscardTransparency) {
1083 const int w = 20, h = 20;
1085 SkBitmap original_bitmap;
1086 MakeTestBGRASkBitmap(w, h, &original_bitmap);
1088 // Encode the bitmap.
1089 std::vector<unsigned char> encoded;
1090 PNGCodec::EncodeBGRASkBitmap(original_bitmap, true, &encoded);
1092 // Decode the encoded string.
1093 SkBitmap decoded_bitmap;
1094 EXPECT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(),
1095 &decoded_bitmap));
1097 // Compare the original bitmap and the output bitmap. We need to
1098 // unpremultiply original_pixel, as the decoded bitmap doesn't have an alpha
1099 // channel.
1100 for (int x = 0; x < w; x++) {
1101 for (int y = 0; y < h; y++) {
1102 uint32_t original_pixel = original_bitmap.getAddr32(0, y)[x];
1103 uint32_t unpremultiplied =
1104 SkUnPreMultiply::PMColorToColor(original_pixel);
1105 uint32_t decoded_pixel = decoded_bitmap.getAddr32(0, y)[x];
1106 uint32_t unpremultiplied_decoded =
1107 SkUnPreMultiply::PMColorToColor(decoded_pixel);
1109 EXPECT_TRUE(NonAlphaColorsClose(unpremultiplied, unpremultiplied_decoded))
1110 << "Original_pixel: ("
1111 << SkColorGetR(unpremultiplied) << ", "
1112 << SkColorGetG(unpremultiplied) << ", "
1113 << SkColorGetB(unpremultiplied) << "), "
1114 << "Decoded pixel: ("
1115 << SkColorGetR(unpremultiplied_decoded) << ", "
1116 << SkColorGetG(unpremultiplied_decoded) << ", "
1117 << SkColorGetB(unpremultiplied_decoded) << ")";
1122 TEST(PNGCodec, EncodeWithComment) {
1123 const int w = 10, h = 10;
1125 std::vector<unsigned char> original;
1126 MakeRGBImage(w, h, &original);
1128 std::vector<unsigned char> encoded;
1129 std::vector<PNGCodec::Comment> comments;
1130 comments.push_back(PNGCodec::Comment("key", "text"));
1131 comments.push_back(PNGCodec::Comment("test", "something"));
1132 comments.push_back(PNGCodec::Comment("have some", "spaces in both"));
1133 EXPECT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB,
1134 Size(w, h), w * 3, false, comments, &encoded));
1136 // Each chunk is of the form length (4 bytes), chunk type (tEXt), data,
1137 // checksum (4 bytes). Make sure we find all of them in the encoded
1138 // results.
1139 const unsigned char kExpected1[] =
1140 "\x00\x00\x00\x08tEXtkey\x00text\x9e\xe7\x66\x51";
1141 const unsigned char kExpected2[] =
1142 "\x00\x00\x00\x0etEXttest\x00something\x29\xba\xef\xac";
1143 const unsigned char kExpected3[] =
1144 "\x00\x00\x00\x18tEXthave some\x00spaces in both\x8d\x69\x34\x2d";
1146 EXPECT_NE(std::search(encoded.begin(), encoded.end(), kExpected1,
1147 kExpected1 + arraysize(kExpected1)),
1148 encoded.end());
1149 EXPECT_NE(std::search(encoded.begin(), encoded.end(), kExpected2,
1150 kExpected2 + arraysize(kExpected2)),
1151 encoded.end());
1152 EXPECT_NE(std::search(encoded.begin(), encoded.end(), kExpected3,
1153 kExpected3 + arraysize(kExpected3)),
1154 encoded.end());
1157 TEST(PNGCodec, EncodeDecodeWithVaryingCompressionLevels) {
1158 const int w = 20, h = 20;
1160 // create an image with known values, a must be opaque because it will be
1161 // lost during encoding
1162 SkBitmap original_bitmap;
1163 MakeTestBGRASkBitmap(w, h, &original_bitmap);
1165 // encode
1166 std::vector<unsigned char> encoded_normal;
1167 EXPECT_TRUE(
1168 PNGCodec::EncodeBGRASkBitmap(original_bitmap, false, &encoded_normal));
1170 std::vector<unsigned char> encoded_fast;
1171 EXPECT_TRUE(
1172 PNGCodec::FastEncodeBGRASkBitmap(original_bitmap, false, &encoded_fast));
1174 // Make sure the different compression settings actually do something; the
1175 // sizes should be different.
1176 EXPECT_NE(encoded_normal.size(), encoded_fast.size());
1178 // decode, they should be identical to the original.
1179 SkBitmap decoded;
1180 EXPECT_TRUE(
1181 PNGCodec::Decode(&encoded_normal[0], encoded_normal.size(), &decoded));
1182 EXPECT_TRUE(BitmapsAreEqual(decoded, original_bitmap));
1184 EXPECT_TRUE(
1185 PNGCodec::Decode(&encoded_fast[0], encoded_fast.size(), &decoded));
1186 EXPECT_TRUE(BitmapsAreEqual(decoded, original_bitmap));
1190 } // namespace gfx