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