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