Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ui / gfx / codec / png_codec_unittest.cc
blob610421a22d74fb10a0059d146ae6aed63d3fc0ce
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/geometry/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->allocN32Pixels(w, h);
262 uint32_t* src_data = bmp->getAddr32(0, 0);
263 for (int i = 0; i < w * h; i++)
264 src_data[i] = SkPreMultiplyARGB(i % 255, i % 250, i % 245, i % 240);
267 void MakeTestA8SkBitmap(int w, int h, SkBitmap* bmp) {
268 bmp->allocPixels(SkImageInfo::MakeA8(w, h));
270 uint8_t* src_data = bmp->getAddr8(0, 0);
271 for (int i = 0; i < w * h; i++)
272 src_data[i] = i % 255;
275 TEST(PNGCodec, EncodeDecodeRGB) {
276 const int w = 20, h = 20;
278 // create an image with known values
279 std::vector<unsigned char> original;
280 MakeRGBImage(w, h, &original);
282 // encode
283 std::vector<unsigned char> encoded;
284 ASSERT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB,
285 Size(w, h), w * 3, false,
286 std::vector<PNGCodec::Comment>(),
287 &encoded));
289 // decode, it should have the same size as the original
290 std::vector<unsigned char> decoded;
291 int outw, outh;
292 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
293 PNGCodec::FORMAT_RGB, &decoded,
294 &outw, &outh));
295 ASSERT_EQ(w, outw);
296 ASSERT_EQ(h, outh);
297 ASSERT_EQ(original.size(), decoded.size());
299 // Images must be equal
300 ASSERT_TRUE(original == decoded);
303 TEST(PNGCodec, EncodeDecodeRGBA) {
304 const int w = 20, h = 20;
306 // create an image with known values, a must be opaque because it will be
307 // lost during encoding
308 std::vector<unsigned char> original;
309 MakeRGBAImage(w, h, true, &original);
311 // encode
312 std::vector<unsigned char> encoded;
313 ASSERT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGBA,
314 Size(w, h), w * 4, false,
315 std::vector<PNGCodec::Comment>(),
316 &encoded));
318 // decode, it should have the same size as the original
319 std::vector<unsigned char> decoded;
320 int outw, outh;
321 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
322 PNGCodec::FORMAT_RGBA, &decoded,
323 &outw, &outh));
324 ASSERT_EQ(w, outw);
325 ASSERT_EQ(h, outh);
326 ASSERT_EQ(original.size(), decoded.size());
328 // Images must be exactly equal
329 ASSERT_TRUE(original == decoded);
332 TEST(PNGCodec, EncodeDecodeBGRA) {
333 const int w = 20, h = 20;
335 // Create an image with known values, alpha must be opaque because it will be
336 // lost during encoding.
337 std::vector<unsigned char> original;
338 MakeRGBAImage(w, h, true, &original);
340 // Encode.
341 std::vector<unsigned char> encoded;
342 ASSERT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_BGRA,
343 Size(w, h), w * 4, false,
344 std::vector<PNGCodec::Comment>(),
345 &encoded));
347 // Decode, it should have the same size as the original.
348 std::vector<unsigned char> decoded;
349 int outw, outh;
350 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
351 PNGCodec::FORMAT_BGRA, &decoded,
352 &outw, &outh));
353 ASSERT_EQ(w, outw);
354 ASSERT_EQ(h, outh);
355 ASSERT_EQ(original.size(), decoded.size());
357 // Images must be exactly equal.
358 ASSERT_TRUE(original == decoded);
361 TEST(PNGCodec, DecodePalette) {
362 const int w = 20, h = 20;
364 // create an image with known values
365 std::vector<unsigned char> original;
366 std::vector<png_color> original_palette;
367 std::vector<unsigned char> original_trans_chunk;
368 MakePaletteImage(w, h, &original, &original_palette, &original_trans_chunk);
370 // encode
371 std::vector<unsigned char> encoded;
372 ASSERT_TRUE(EncodeImage(original,
373 w, h,
374 COLOR_TYPE_PALETTE,
375 &encoded,
376 PNG_INTERLACE_NONE,
377 &original_palette,
378 &original_trans_chunk));
380 // decode
381 std::vector<unsigned char> decoded;
382 int outw, outh;
383 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
384 PNGCodec::FORMAT_RGBA, &decoded,
385 &outw, &outh));
386 ASSERT_EQ(w, outw);
387 ASSERT_EQ(h, outh);
388 ASSERT_EQ(decoded.size(), w * h * 4U);
390 // Images must be equal
391 for (int y = 0; y < h; ++y) {
392 for (int x = 0; x < w; ++x) {
393 unsigned char palette_pixel = original[y * w + x];
394 png_color& palette_color = original_palette[palette_pixel];
395 int alpha = original_trans_chunk[palette_pixel];
396 unsigned char* rgba_pixel = &decoded[(y * w + x) * 4];
398 EXPECT_EQ(palette_color.red, rgba_pixel[0]);
399 EXPECT_EQ(palette_color.green, rgba_pixel[1]);
400 EXPECT_EQ(palette_color.blue, rgba_pixel[2]);
401 EXPECT_EQ(alpha, rgba_pixel[3]);
406 TEST(PNGCodec, DecodePaletteDiscardAlpha) {
407 const int w = 20, h = 20;
409 // create an image with known values
410 std::vector<unsigned char> original;
411 std::vector<png_color> original_palette;
412 std::vector<unsigned char> original_trans_chunk;
413 MakePaletteImage(w, h, &original, &original_palette, &original_trans_chunk);
415 // encode
416 std::vector<unsigned char> encoded;
417 ASSERT_TRUE(EncodeImage(original,
418 w, h,
419 COLOR_TYPE_PALETTE,
420 &encoded,
421 PNG_INTERLACE_NONE,
422 &original_palette,
423 &original_trans_chunk));
425 // decode
426 std::vector<unsigned char> decoded;
427 int outw, outh;
428 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
429 PNGCodec::FORMAT_RGB, &decoded,
430 &outw, &outh));
431 ASSERT_EQ(w, outw);
432 ASSERT_EQ(h, outh);
433 ASSERT_EQ(decoded.size(), w * h * 3U);
435 // Images must be equal
436 for (int y = 0; y < h; ++y) {
437 for (int x = 0; x < w; ++x) {
438 unsigned char palette_pixel = original[y * w + x];
439 png_color& palette_color = original_palette[palette_pixel];
440 unsigned char* rgba_pixel = &decoded[(y * w + x) * 3];
442 EXPECT_EQ(palette_color.red, rgba_pixel[0]);
443 EXPECT_EQ(palette_color.green, rgba_pixel[1]);
444 EXPECT_EQ(palette_color.blue, rgba_pixel[2]);
449 TEST(PNGCodec, DecodeInterlacedPalette) {
450 const int w = 20, h = 20;
452 // create an image with known values
453 std::vector<unsigned char> original;
454 std::vector<png_color> original_palette;
455 std::vector<unsigned char> original_trans_chunk;
456 MakePaletteImage(w, h, &original, &original_palette, &original_trans_chunk);
458 // encode
459 std::vector<unsigned char> encoded;
460 ASSERT_TRUE(EncodeImage(original,
461 w, h,
462 COLOR_TYPE_PALETTE,
463 &encoded,
464 PNG_INTERLACE_ADAM7,
465 &original_palette,
466 &original_trans_chunk));
468 // decode
469 std::vector<unsigned char> decoded;
470 int outw, outh;
471 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
472 PNGCodec::FORMAT_RGBA, &decoded,
473 &outw, &outh));
474 ASSERT_EQ(w, outw);
475 ASSERT_EQ(h, outh);
476 ASSERT_EQ(decoded.size(), w * h * 4U);
478 // Images must be equal
479 for (int y = 0; y < h; ++y) {
480 for (int x = 0; x < w; ++x) {
481 unsigned char palette_pixel = original[y * w + x];
482 png_color& palette_color = original_palette[palette_pixel];
483 int alpha = original_trans_chunk[palette_pixel];
484 unsigned char* rgba_pixel = &decoded[(y * w + x) * 4];
486 EXPECT_EQ(palette_color.red, rgba_pixel[0]);
487 EXPECT_EQ(palette_color.green, rgba_pixel[1]);
488 EXPECT_EQ(palette_color.blue, rgba_pixel[2]);
489 EXPECT_EQ(alpha, rgba_pixel[3]);
494 TEST(PNGCodec, DecodeGrayscale) {
495 const int w = 20, h = 20;
497 // create an image with known values
498 std::vector<unsigned char> original;
499 MakeGrayscaleImage(w, h, &original);
501 // encode
502 std::vector<unsigned char> encoded;
503 ASSERT_TRUE(EncodeImage(original, w, h, COLOR_TYPE_GRAY, &encoded));
505 // decode
506 std::vector<unsigned char> decoded;
507 int outw, outh;
508 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
509 PNGCodec::FORMAT_RGB, &decoded,
510 &outw, &outh));
511 ASSERT_EQ(w, outw);
512 ASSERT_EQ(h, outh);
513 ASSERT_EQ(decoded.size(), original.size() * 3);
515 // Images must be equal
516 for (int y = 0; y < h; ++y) {
517 for (int x = 0; x < w; ++x) {
518 unsigned char gray_pixel = original[(y * w + x)];
519 unsigned char* rgba_pixel = &decoded[(y * w + x) * 3];
520 EXPECT_EQ(rgba_pixel[0], gray_pixel);
521 EXPECT_EQ(rgba_pixel[1], gray_pixel);
522 EXPECT_EQ(rgba_pixel[2], gray_pixel);
527 TEST(PNGCodec, DecodeGrayscaleWithAlpha) {
528 const int w = 20, h = 20;
530 // create an image with known values
531 std::vector<unsigned char> original;
532 MakeGrayscaleAlphaImage(w, h, &original);
534 // encode
535 std::vector<unsigned char> encoded;
536 ASSERT_TRUE(EncodeImage(original,
537 w, h,
538 COLOR_TYPE_GRAY_ALPHA,
539 &encoded));
541 // decode
542 std::vector<unsigned char> decoded;
543 int outw, outh;
544 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
545 PNGCodec::FORMAT_RGBA, &decoded,
546 &outw, &outh));
547 ASSERT_EQ(w, outw);
548 ASSERT_EQ(h, outh);
549 ASSERT_EQ(decoded.size(), original.size() * 2);
551 // Images must be equal
552 for (int y = 0; y < h; ++y) {
553 for (int x = 0; x < w; ++x) {
554 unsigned char* gray_pixel = &original[(y * w + x) * 2];
555 unsigned char* rgba_pixel = &decoded[(y * w + x) * 4];
556 EXPECT_EQ(rgba_pixel[0], gray_pixel[0]);
557 EXPECT_EQ(rgba_pixel[1], gray_pixel[0]);
558 EXPECT_EQ(rgba_pixel[2], gray_pixel[0]);
559 EXPECT_EQ(rgba_pixel[3], gray_pixel[1]);
564 TEST(PNGCodec, DecodeGrayscaleWithAlphaDiscardAlpha) {
565 const int w = 20, h = 20;
567 // create an image with known values
568 std::vector<unsigned char> original;
569 MakeGrayscaleAlphaImage(w, h, &original);
571 // encode
572 std::vector<unsigned char> encoded;
573 ASSERT_TRUE(EncodeImage(original,
574 w, h,
575 COLOR_TYPE_GRAY_ALPHA,
576 &encoded));
578 // decode
579 std::vector<unsigned char> decoded;
580 int outw, outh;
581 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
582 PNGCodec::FORMAT_RGB, &decoded,
583 &outw, &outh));
584 ASSERT_EQ(w, outw);
585 ASSERT_EQ(h, outh);
586 ASSERT_EQ(decoded.size(), w * h * 3U);
588 // Images must be equal
589 for (int y = 0; y < h; ++y) {
590 for (int x = 0; x < w; ++x) {
591 unsigned char* gray_pixel = &original[(y * w + x) * 2];
592 unsigned char* rgba_pixel = &decoded[(y * w + x) * 3];
593 EXPECT_EQ(rgba_pixel[0], gray_pixel[0]);
594 EXPECT_EQ(rgba_pixel[1], gray_pixel[0]);
595 EXPECT_EQ(rgba_pixel[2], gray_pixel[0]);
600 TEST(PNGCodec, DecodeInterlacedGrayscale) {
601 const int w = 20, h = 20;
603 // create an image with known values
604 std::vector<unsigned char> original;
605 MakeGrayscaleImage(w, h, &original);
607 // encode
608 std::vector<unsigned char> encoded;
609 ASSERT_TRUE(EncodeImage(original,
610 w, h,
611 COLOR_TYPE_GRAY,
612 &encoded,
613 PNG_INTERLACE_ADAM7));
615 // decode
616 std::vector<unsigned char> decoded;
617 int outw, outh;
618 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
619 PNGCodec::FORMAT_RGBA, &decoded,
620 &outw, &outh));
621 ASSERT_EQ(w, outw);
622 ASSERT_EQ(h, outh);
623 ASSERT_EQ(decoded.size(), original.size() * 4);
625 // Images must be equal
626 for (int y = 0; y < h; ++y) {
627 for (int x = 0; x < w; ++x) {
628 unsigned char gray_pixel = original[(y * w + x)];
629 unsigned char* rgba_pixel = &decoded[(y * w + x) * 4];
630 EXPECT_EQ(rgba_pixel[0], gray_pixel);
631 EXPECT_EQ(rgba_pixel[1], gray_pixel);
632 EXPECT_EQ(rgba_pixel[2], gray_pixel);
633 EXPECT_EQ(rgba_pixel[3], 0xFF);
638 TEST(PNGCodec, DecodeInterlacedGrayscaleWithAlpha) {
639 const int w = 20, h = 20;
641 // create an image with known values
642 std::vector<unsigned char> original;
643 MakeGrayscaleAlphaImage(w, h, &original);
645 // encode
646 std::vector<unsigned char> encoded;
647 ASSERT_TRUE(EncodeImage(original,
648 w, h,
649 COLOR_TYPE_GRAY_ALPHA,
650 &encoded,
651 PNG_INTERLACE_ADAM7));
653 // decode
654 std::vector<unsigned char> decoded;
655 int outw, outh;
656 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
657 PNGCodec::FORMAT_RGBA, &decoded,
658 &outw, &outh));
659 ASSERT_EQ(w, outw);
660 ASSERT_EQ(h, outh);
661 ASSERT_EQ(decoded.size(), original.size() * 2);
663 // Images must be equal
664 for (int y = 0; y < h; ++y) {
665 for (int x = 0; x < w; ++x) {
666 unsigned char* gray_pixel = &original[(y * w + x) * 2];
667 unsigned char* rgba_pixel = &decoded[(y * w + x) * 4];
668 EXPECT_EQ(rgba_pixel[0], gray_pixel[0]);
669 EXPECT_EQ(rgba_pixel[1], gray_pixel[0]);
670 EXPECT_EQ(rgba_pixel[2], gray_pixel[0]);
671 EXPECT_EQ(rgba_pixel[3], gray_pixel[1]);
676 TEST(PNGCodec, DecodeInterlacedRGB) {
677 const int w = 20, h = 20;
679 // create an image with known values
680 std::vector<unsigned char> original;
681 MakeRGBImage(w, h, &original);
683 // encode
684 std::vector<unsigned char> encoded;
685 ASSERT_TRUE(EncodeImage(original,
686 w, h,
687 COLOR_TYPE_RGB,
688 &encoded,
689 PNG_INTERLACE_ADAM7));
691 // decode, it should have the same size as the original
692 std::vector<unsigned char> decoded;
693 int outw, outh;
694 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
695 PNGCodec::FORMAT_RGB, &decoded,
696 &outw, &outh));
697 ASSERT_EQ(w, outw);
698 ASSERT_EQ(h, outh);
699 ASSERT_EQ(original.size(), decoded.size());
701 // Images must be equal
702 ASSERT_EQ(original, decoded);
705 TEST(PNGCodec, DecodeInterlacedRGBA) {
706 const int w = 20, h = 20;
708 // create an image with known values
709 std::vector<unsigned char> original;
710 MakeRGBAImage(w, h, false, &original);
712 // encode
713 std::vector<unsigned char> encoded;
714 ASSERT_TRUE(EncodeImage(original,
715 w, h,
716 COLOR_TYPE_RGBA,
717 &encoded,
718 PNG_INTERLACE_ADAM7));
720 // decode, it should have the same size as the original
721 std::vector<unsigned char> decoded;
722 int outw, outh;
723 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
724 PNGCodec::FORMAT_RGBA, &decoded,
725 &outw, &outh));
726 ASSERT_EQ(w, outw);
727 ASSERT_EQ(h, outh);
728 ASSERT_EQ(original.size(), decoded.size());
730 // Images must be equal
731 ASSERT_EQ(original, decoded);
734 TEST(PNGCodec, DecodeInterlacedRGBADiscardAlpha) {
735 const int w = 20, h = 20;
737 // create an image with known values
738 std::vector<unsigned char> original;
739 MakeRGBAImage(w, h, false, &original);
741 // encode
742 std::vector<unsigned char> encoded;
743 ASSERT_TRUE(EncodeImage(original,
744 w, h,
745 COLOR_TYPE_RGBA,
746 &encoded,
747 PNG_INTERLACE_ADAM7));
749 // decode
750 std::vector<unsigned char> decoded;
751 int outw, outh;
752 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
753 PNGCodec::FORMAT_RGB, &decoded,
754 &outw, &outh));
755 ASSERT_EQ(w, outw);
756 ASSERT_EQ(h, outh);
757 ASSERT_EQ(decoded.size(), w * h * 3U);
759 // Images must be equal
760 for (int x = 0; x < w; x++) {
761 for (int y = 0; y < h; y++) {
762 unsigned char* orig_px = &original[(y * w + x) * 4];
763 unsigned char* dec_px = &decoded[(y * w + x) * 3];
764 EXPECT_EQ(dec_px[0], orig_px[0]);
765 EXPECT_EQ(dec_px[1], orig_px[1]);
766 EXPECT_EQ(dec_px[2], orig_px[2]);
771 TEST(PNGCodec, DecodeInterlacedBGR) {
772 const int w = 20, h = 20;
774 // create an image with known values
775 std::vector<unsigned char> original;
776 MakeRGBImage(w, h, &original);
778 // encode
779 std::vector<unsigned char> encoded;
780 ASSERT_TRUE(EncodeImage(original,
781 w, h,
782 COLOR_TYPE_BGR,
783 &encoded,
784 PNG_INTERLACE_ADAM7));
786 // decode, it should have the same size as the original
787 std::vector<unsigned char> decoded;
788 int outw, outh;
789 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
790 PNGCodec::FORMAT_BGRA, &decoded,
791 &outw, &outh));
792 ASSERT_EQ(w, outw);
793 ASSERT_EQ(h, outh);
794 ASSERT_EQ(decoded.size(), w * h * 4U);
796 // Images must be equal
797 for (int x = 0; x < w; x++) {
798 for (int y = 0; y < h; y++) {
799 unsigned char* orig_px = &original[(y * w + x) * 3];
800 unsigned char* dec_px = &decoded[(y * w + x) * 4];
801 EXPECT_EQ(dec_px[0], orig_px[0]);
802 EXPECT_EQ(dec_px[1], orig_px[1]);
803 EXPECT_EQ(dec_px[2], orig_px[2]);
808 TEST(PNGCodec, DecodeInterlacedBGRA) {
809 const int w = 20, h = 20;
811 // create an image with known values
812 std::vector<unsigned char> original;
813 MakeRGBAImage(w, h, false, &original);
815 // encode
816 std::vector<unsigned char> encoded;
817 ASSERT_TRUE(EncodeImage(original,
818 w, h,
819 COLOR_TYPE_BGRA,
820 &encoded,
821 PNG_INTERLACE_ADAM7));
823 // decode, it should have the same size as the original
824 std::vector<unsigned char> decoded;
825 int outw, outh;
826 ASSERT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
827 PNGCodec::FORMAT_BGRA, &decoded,
828 &outw, &outh));
829 ASSERT_EQ(w, outw);
830 ASSERT_EQ(h, outh);
831 ASSERT_EQ(original.size(), decoded.size());
833 // Images must be equal
834 ASSERT_EQ(original, decoded);
837 // Not encoding an interlaced PNG from SkBitmap because we don't do it
838 // anywhere, and the ability to do that requires more code changes.
839 TEST(PNGCodec, DecodeInterlacedRGBtoSkBitmap) {
840 const int w = 20, h = 20;
842 // create an image with known values
843 std::vector<unsigned char> original;
844 MakeRGBImage(w, h, &original);
846 // encode
847 std::vector<unsigned char> encoded;
848 ASSERT_TRUE(EncodeImage(original,
849 w, h,
850 COLOR_TYPE_RGB,
851 &encoded,
852 PNG_INTERLACE_ADAM7));
854 // Decode the encoded string.
855 SkBitmap decoded_bitmap;
856 ASSERT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(),
857 &decoded_bitmap));
859 for (int x = 0; x < w; x++) {
860 for (int y = 0; y < h; y++) {
861 const unsigned char* original_pixel = &original[(y * w + x) * 3];
862 const uint32_t original_pixel_sk = SkPackARGB32(0xFF,
863 original_pixel[0],
864 original_pixel[1],
865 original_pixel[2]);
866 const uint32_t decoded_pixel = decoded_bitmap.getAddr32(0, y)[x];
867 EXPECT_EQ(original_pixel_sk, decoded_pixel);
872 TEST(PNGCodec, DecodeInterlacedRGBAtoSkBitmap) {
873 const int w = 20, h = 20;
875 // create an image with known values
876 std::vector<unsigned char> original;
877 MakeRGBAImage(w, h, false, &original);
879 // encode
880 std::vector<unsigned char> encoded;
881 ASSERT_TRUE(EncodeImage(original,
882 w, h,
883 COLOR_TYPE_RGBA,
884 &encoded,
885 PNG_INTERLACE_ADAM7));
887 // Decode the encoded string.
888 SkBitmap decoded_bitmap;
889 ASSERT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(),
890 &decoded_bitmap));
892 for (int x = 0; x < w; x++) {
893 for (int y = 0; y < h; y++) {
894 const unsigned char* original_pixel = &original[(y * w + x) * 4];
895 const uint32_t original_pixel_sk = SkPackARGB32(original_pixel[3],
896 original_pixel[0],
897 original_pixel[1],
898 original_pixel[2]);
899 const uint32_t decoded_pixel = decoded_bitmap.getAddr32(0, y)[x];
900 EXPECT_EQ(original_pixel_sk, decoded_pixel);
905 // Test that corrupted data decompression causes failures.
906 TEST(PNGCodec, DecodeCorrupted) {
907 int w = 20, h = 20;
909 // Make some random data (an uncompressed image).
910 std::vector<unsigned char> original;
911 MakeRGBImage(w, h, &original);
913 // It should fail when given non-JPEG compressed data.
914 std::vector<unsigned char> output;
915 int outw, outh;
916 EXPECT_FALSE(PNGCodec::Decode(&original[0], original.size(),
917 PNGCodec::FORMAT_RGB, &output,
918 &outw, &outh));
920 // Make some compressed data.
921 std::vector<unsigned char> compressed;
922 ASSERT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB,
923 Size(w, h), w * 3, false,
924 std::vector<PNGCodec::Comment>(),
925 &compressed));
927 // Try decompressing a truncated version.
928 EXPECT_FALSE(PNGCodec::Decode(&compressed[0], compressed.size() / 2,
929 PNGCodec::FORMAT_RGB, &output,
930 &outw, &outh));
932 // Corrupt it and try decompressing that.
933 for (int i = 10; i < 30; i++)
934 compressed[i] = i;
935 EXPECT_FALSE(PNGCodec::Decode(&compressed[0], compressed.size(),
936 PNGCodec::FORMAT_RGB, &output,
937 &outw, &outh));
940 TEST(PNGCodec, StripAddAlpha) {
941 const int w = 20, h = 20;
943 // These should be the same except one has a 0xff alpha channel.
944 std::vector<unsigned char> original_rgb;
945 MakeRGBImage(w, h, &original_rgb);
946 std::vector<unsigned char> original_rgba;
947 MakeRGBAImage(w, h, false, &original_rgba);
949 // Encode RGBA data as RGB.
950 std::vector<unsigned char> encoded;
951 EXPECT_TRUE(PNGCodec::Encode(&original_rgba[0], PNGCodec::FORMAT_RGBA,
952 Size(w, h), w * 4, true,
953 std::vector<PNGCodec::Comment>(),
954 &encoded));
956 // Decode the RGB to RGBA.
957 std::vector<unsigned char> decoded;
958 int outw, outh;
959 EXPECT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
960 PNGCodec::FORMAT_RGBA, &decoded,
961 &outw, &outh));
963 // Decoded and reference should be the same (opaque alpha).
964 ASSERT_EQ(w, outw);
965 ASSERT_EQ(h, outh);
966 ASSERT_EQ(original_rgba.size(), decoded.size());
967 ASSERT_EQ(original_rgba, decoded);
969 // Encode RGBA to RGBA.
970 EXPECT_TRUE(PNGCodec::Encode(&original_rgba[0], PNGCodec::FORMAT_RGBA,
971 Size(w, h), w * 4, false,
972 std::vector<PNGCodec::Comment>(),
973 &encoded));
975 // Decode the RGBA to RGB.
976 EXPECT_TRUE(PNGCodec::Decode(&encoded[0], encoded.size(),
977 PNGCodec::FORMAT_RGB, &decoded,
978 &outw, &outh));
980 // It should be the same as our non-alpha-channel reference.
981 ASSERT_EQ(w, outw);
982 ASSERT_EQ(h, outh);
983 ASSERT_EQ(original_rgb.size(), decoded.size());
984 ASSERT_EQ(original_rgb, decoded);
987 TEST(PNGCodec, EncodeBGRASkBitmapStridePadded) {
988 const int kWidth = 20;
989 const int kHeight = 20;
990 const int kPaddedWidth = 32;
991 const int kBytesPerPixel = 4;
992 const int kPaddedSize = kPaddedWidth * kHeight;
993 const int kRowBytes = kPaddedWidth * kBytesPerPixel;
995 SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
996 SkBitmap original_bitmap;
997 original_bitmap.setInfo(info, kRowBytes);
998 original_bitmap.allocPixels();
1000 // Write data over the source bitmap.
1001 // We write on the pad area here too.
1002 // The encoder should ignore the pad area.
1003 uint32_t* src_data = original_bitmap.getAddr32(0, 0);
1004 for (int i = 0; i < kPaddedSize; i++) {
1005 src_data[i] = SkPreMultiplyARGB(i % 255, i % 250, i % 245, i % 240);
1008 // Encode the bitmap.
1009 std::vector<unsigned char> encoded;
1010 PNGCodec::EncodeBGRASkBitmap(original_bitmap, false, &encoded);
1012 // Decode the encoded string.
1013 SkBitmap decoded_bitmap;
1014 EXPECT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(),
1015 &decoded_bitmap));
1017 // Compare the original bitmap and the output bitmap. We use ColorsClose
1018 // as SkBitmaps are considered to be pre-multiplied, the unpremultiplication
1019 // (in Encode) and repremultiplication (in Decode) can be lossy.
1020 for (int x = 0; x < kWidth; x++) {
1021 for (int y = 0; y < kHeight; y++) {
1022 uint32_t original_pixel = original_bitmap.getAddr32(0, y)[x];
1023 uint32_t decoded_pixel = decoded_bitmap.getAddr32(0, y)[x];
1024 EXPECT_TRUE(ColorsClose(original_pixel, decoded_pixel));
1029 TEST(PNGCodec, EncodeBGRASkBitmap) {
1030 const int w = 20, h = 20;
1032 SkBitmap original_bitmap;
1033 MakeTestBGRASkBitmap(w, h, &original_bitmap);
1035 // Encode the bitmap.
1036 std::vector<unsigned char> encoded;
1037 PNGCodec::EncodeBGRASkBitmap(original_bitmap, false, &encoded);
1039 // Decode the encoded string.
1040 SkBitmap decoded_bitmap;
1041 EXPECT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(),
1042 &decoded_bitmap));
1044 // Compare the original bitmap and the output bitmap. We use ColorsClose
1045 // as SkBitmaps are considered to be pre-multiplied, the unpremultiplication
1046 // (in Encode) and repremultiplication (in Decode) can be lossy.
1047 for (int x = 0; x < w; x++) {
1048 for (int y = 0; y < h; y++) {
1049 uint32_t original_pixel = original_bitmap.getAddr32(0, y)[x];
1050 uint32_t decoded_pixel = decoded_bitmap.getAddr32(0, y)[x];
1051 EXPECT_TRUE(ColorsClose(original_pixel, decoded_pixel));
1056 TEST(PNGCodec, EncodeA8SkBitmap) {
1057 const int w = 20, h = 20;
1059 SkBitmap original_bitmap;
1060 MakeTestA8SkBitmap(w, h, &original_bitmap);
1062 // Encode the bitmap.
1063 std::vector<unsigned char> encoded;
1064 EXPECT_TRUE(PNGCodec::EncodeA8SkBitmap(original_bitmap, &encoded));
1066 // Decode the encoded string.
1067 SkBitmap decoded_bitmap;
1068 EXPECT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(),
1069 &decoded_bitmap));
1071 for (int x = 0; x < w; x++) {
1072 for (int y = 0; y < h; y++) {
1073 uint8_t original_pixel = *original_bitmap.getAddr8(x, y);
1074 uint32_t decoded_pixel = *decoded_bitmap.getAddr32(x, y);
1075 EXPECT_TRUE(BGRAGrayEqualsA8Gray(decoded_pixel, original_pixel));
1080 TEST(PNGCodec, EncodeBGRASkBitmapDiscardTransparency) {
1081 const int w = 20, h = 20;
1083 SkBitmap original_bitmap;
1084 MakeTestBGRASkBitmap(w, h, &original_bitmap);
1086 // Encode the bitmap.
1087 std::vector<unsigned char> encoded;
1088 PNGCodec::EncodeBGRASkBitmap(original_bitmap, true, &encoded);
1090 // Decode the encoded string.
1091 SkBitmap decoded_bitmap;
1092 EXPECT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(),
1093 &decoded_bitmap));
1095 // Compare the original bitmap and the output bitmap. We need to
1096 // unpremultiply original_pixel, as the decoded bitmap doesn't have an alpha
1097 // channel.
1098 for (int x = 0; x < w; x++) {
1099 for (int y = 0; y < h; y++) {
1100 uint32_t original_pixel = original_bitmap.getAddr32(0, y)[x];
1101 uint32_t unpremultiplied =
1102 SkUnPreMultiply::PMColorToColor(original_pixel);
1103 uint32_t decoded_pixel = decoded_bitmap.getAddr32(0, y)[x];
1104 uint32_t unpremultiplied_decoded =
1105 SkUnPreMultiply::PMColorToColor(decoded_pixel);
1107 EXPECT_TRUE(NonAlphaColorsClose(unpremultiplied, unpremultiplied_decoded))
1108 << "Original_pixel: ("
1109 << SkColorGetR(unpremultiplied) << ", "
1110 << SkColorGetG(unpremultiplied) << ", "
1111 << SkColorGetB(unpremultiplied) << "), "
1112 << "Decoded pixel: ("
1113 << SkColorGetR(unpremultiplied_decoded) << ", "
1114 << SkColorGetG(unpremultiplied_decoded) << ", "
1115 << SkColorGetB(unpremultiplied_decoded) << ")";
1120 TEST(PNGCodec, EncodeWithComment) {
1121 const int w = 10, h = 10;
1123 std::vector<unsigned char> original;
1124 MakeRGBImage(w, h, &original);
1126 std::vector<unsigned char> encoded;
1127 std::vector<PNGCodec::Comment> comments;
1128 comments.push_back(PNGCodec::Comment("key", "text"));
1129 comments.push_back(PNGCodec::Comment("test", "something"));
1130 comments.push_back(PNGCodec::Comment("have some", "spaces in both"));
1131 EXPECT_TRUE(PNGCodec::Encode(&original[0], PNGCodec::FORMAT_RGB,
1132 Size(w, h), w * 3, false, comments, &encoded));
1134 // Each chunk is of the form length (4 bytes), chunk type (tEXt), data,
1135 // checksum (4 bytes). Make sure we find all of them in the encoded
1136 // results.
1137 const unsigned char kExpected1[] =
1138 "\x00\x00\x00\x08tEXtkey\x00text\x9e\xe7\x66\x51";
1139 const unsigned char kExpected2[] =
1140 "\x00\x00\x00\x0etEXttest\x00something\x29\xba\xef\xac";
1141 const unsigned char kExpected3[] =
1142 "\x00\x00\x00\x18tEXthave some\x00spaces in both\x8d\x69\x34\x2d";
1144 EXPECT_NE(std::search(encoded.begin(), encoded.end(), kExpected1,
1145 kExpected1 + arraysize(kExpected1)),
1146 encoded.end());
1147 EXPECT_NE(std::search(encoded.begin(), encoded.end(), kExpected2,
1148 kExpected2 + arraysize(kExpected2)),
1149 encoded.end());
1150 EXPECT_NE(std::search(encoded.begin(), encoded.end(), kExpected3,
1151 kExpected3 + arraysize(kExpected3)),
1152 encoded.end());
1155 TEST(PNGCodec, EncodeDecodeWithVaryingCompressionLevels) {
1156 const int w = 20, h = 20;
1158 // create an image with known values, a must be opaque because it will be
1159 // lost during encoding
1160 SkBitmap original_bitmap;
1161 MakeTestBGRASkBitmap(w, h, &original_bitmap);
1163 // encode
1164 std::vector<unsigned char> encoded_normal;
1165 EXPECT_TRUE(
1166 PNGCodec::EncodeBGRASkBitmap(original_bitmap, false, &encoded_normal));
1168 std::vector<unsigned char> encoded_fast;
1169 EXPECT_TRUE(
1170 PNGCodec::FastEncodeBGRASkBitmap(original_bitmap, false, &encoded_fast));
1172 // Make sure the different compression settings actually do something; the
1173 // sizes should be different.
1174 EXPECT_NE(encoded_normal.size(), encoded_fast.size());
1176 // decode, they should be identical to the original.
1177 SkBitmap decoded;
1178 EXPECT_TRUE(
1179 PNGCodec::Decode(&encoded_normal[0], encoded_normal.size(), &decoded));
1180 EXPECT_TRUE(BitmapsAreEqual(decoded, original_bitmap));
1182 EXPECT_TRUE(
1183 PNGCodec::Decode(&encoded_fast[0], encoded_fast.size(), &decoded));
1184 EXPECT_TRUE(BitmapsAreEqual(decoded, original_bitmap));
1188 } // namespace gfx