Home | History | Annotate | Download | only in image_diff
      1 // Copyright 2013 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 // This is a duplicate of chromium's src/tools/imagediff/image_diff_png.cc
      6 // that has been modified to build in a pdfium environment, which itself
      7 // was duplicated as follows:
      8 
      9 // This is a duplicate of ui/gfx/codec/png_codec.cc, after removing code related
     10 // to Skia, that we can use when running layout tests with minimal dependencies.
     11 
     12 #include "testing/image_diff/image_diff_png.h"
     13 
     14 #include <stdlib.h>
     15 #include <string.h>
     16 
     17 #include <string>
     18 
     19 #include "third_party/base/logging.h"
     20 #include "third_party/zlib/zlib.h"
     21 
     22 #ifdef USE_SYSTEM_LIBPNG
     23 #include <png.h>
     24 #else
     25 #include "third_party/libpng16/png.h"
     26 #endif
     27 
     28 namespace image_diff_png {
     29 
     30 namespace {
     31 
     32 enum ColorFormat {
     33   // 3 bytes per pixel (packed), in RGB order regardless of endianness.
     34   // This is the native JPEG format.
     35   FORMAT_RGB,
     36 
     37   // 3 bytes per pixel, in BGR order regardless of endianness.
     38   FORMAT_BGR,
     39 
     40   // 4 bytes per pixel, in RGBA order in memory regardless of endianness.
     41   FORMAT_RGBA,
     42 
     43   // 4 bytes per pixel, in BGRA order in memory regardless of endianness.
     44   // This is the default Windows DIB order.
     45   FORMAT_BGRA,
     46 
     47   // 1 byte per pixel.
     48   FORMAT_GRAY,
     49 };
     50 
     51 // Represents a comment in the tEXt ancillary chunk of the png.
     52 struct Comment {
     53   std::string key;
     54   std::string text;
     55 };
     56 
     57 // Converts BGRA->RGBA and RGBA->BGRA.
     58 void ConvertBetweenBGRAandRGBA(const unsigned char* input,
     59                                int pixel_width,
     60                                unsigned char* output,
     61                                bool* is_opaque) {
     62   for (int x = 0; x < pixel_width; x++) {
     63     const unsigned char* pixel_in = &input[x * 4];
     64     unsigned char* pixel_out = &output[x * 4];
     65     pixel_out[0] = pixel_in[2];
     66     pixel_out[1] = pixel_in[1];
     67     pixel_out[2] = pixel_in[0];
     68     pixel_out[3] = pixel_in[3];
     69   }
     70 }
     71 
     72 void ConvertBGRtoRGB(const unsigned char* bgr,
     73                      int pixel_width,
     74                      unsigned char* rgb,
     75                      bool* is_opaque) {
     76   for (int x = 0; x < pixel_width; x++) {
     77     const unsigned char* pixel_in = &bgr[x * 3];
     78     unsigned char* pixel_out = &rgb[x * 3];
     79     pixel_out[0] = pixel_in[2];
     80     pixel_out[1] = pixel_in[1];
     81     pixel_out[2] = pixel_in[0];
     82   }
     83 }
     84 
     85 void ConvertRGBAtoRGB(const unsigned char* rgba,
     86                       int pixel_width,
     87                       unsigned char* rgb,
     88                       bool* is_opaque) {
     89   for (int x = 0; x < pixel_width; x++) {
     90     const unsigned char* pixel_in = &rgba[x * 4];
     91     unsigned char* pixel_out = &rgb[x * 3];
     92     pixel_out[0] = pixel_in[0];
     93     pixel_out[1] = pixel_in[1];
     94     pixel_out[2] = pixel_in[2];
     95   }
     96 }
     97 
     98 }  // namespace
     99 
    100 // Decoder
    101 //
    102 // This code is based on WebKit libpng interface (PNGImageDecoder), which is
    103 // in turn based on the Mozilla png decoder.
    104 
    105 namespace {
    106 
    107 // Gamma constants: We assume we're on Windows which uses a gamma of 2.2.
    108 const double kMaxGamma = 21474.83;  // Maximum gamma accepted by png library.
    109 const double kDefaultGamma = 2.2;
    110 const double kInverseGamma = 1.0 / kDefaultGamma;
    111 
    112 class PngDecoderState {
    113  public:
    114   // Output is a vector<unsigned char>.
    115   PngDecoderState(ColorFormat ofmt, std::vector<unsigned char>* o)
    116       : output_format(ofmt),
    117         output_channels(0),
    118         is_opaque(true),
    119         output(o),
    120         row_converter(nullptr),
    121         width(0),
    122         height(0),
    123         done(false) {}
    124 
    125   ColorFormat output_format;
    126   int output_channels;
    127 
    128   // Used during the reading of an SkBitmap. Defaults to true until we see a
    129   // pixel with anything other than an alpha of 255.
    130   bool is_opaque;
    131 
    132   // An intermediary buffer for decode output.
    133   std::vector<unsigned char>* output;
    134 
    135   // Called to convert a row from the library to the correct output format.
    136   // When NULL, no conversion is necessary.
    137   void (*row_converter)(const unsigned char* in,
    138                         int w,
    139                         unsigned char* out,
    140                         bool* is_opaque);
    141 
    142   // Size of the image, set in the info callback.
    143   int width;
    144   int height;
    145 
    146   // Set to true when we've found the end of the data.
    147   bool done;
    148 };
    149 
    150 void ConvertRGBtoRGBA(const unsigned char* rgb,
    151                       int pixel_width,
    152                       unsigned char* rgba,
    153                       bool* is_opaque) {
    154   for (int x = 0; x < pixel_width; x++) {
    155     const unsigned char* pixel_in = &rgb[x * 3];
    156     unsigned char* pixel_out = &rgba[x * 4];
    157     pixel_out[0] = pixel_in[0];
    158     pixel_out[1] = pixel_in[1];
    159     pixel_out[2] = pixel_in[2];
    160     pixel_out[3] = 0xff;
    161   }
    162 }
    163 
    164 void ConvertRGBtoBGRA(const unsigned char* rgb,
    165                       int pixel_width,
    166                       unsigned char* bgra,
    167                       bool* is_opaque) {
    168   for (int x = 0; x < pixel_width; x++) {
    169     const unsigned char* pixel_in = &rgb[x * 3];
    170     unsigned char* pixel_out = &bgra[x * 4];
    171     pixel_out[0] = pixel_in[2];
    172     pixel_out[1] = pixel_in[1];
    173     pixel_out[2] = pixel_in[0];
    174     pixel_out[3] = 0xff;
    175   }
    176 }
    177 
    178 // Called when the png header has been read. This code is based on the WebKit
    179 // PNGImageDecoder
    180 void DecodeInfoCallback(png_struct* png_ptr, png_info* info_ptr) {
    181   PngDecoderState* state =
    182       static_cast<PngDecoderState*>(png_get_progressive_ptr(png_ptr));
    183 
    184   int bit_depth, color_type, interlace_type, compression_type;
    185   int filter_type, channels;
    186   png_uint_32 w, h;
    187   png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type,
    188                &interlace_type, &compression_type, &filter_type);
    189 
    190   // Bounds check. When the image is unreasonably big, we'll error out and
    191   // end up back at the setjmp call when we set up decoding.  "Unreasonably big"
    192   // means "big enough that w * h * 32bpp might overflow an int"; we choose this
    193   // threshold to match WebKit and because a number of places in code assume
    194   // that an image's size (in bytes) fits in a (signed) int.
    195   unsigned long long total_size =
    196       static_cast<unsigned long long>(w) * static_cast<unsigned long long>(h);
    197   if (total_size > ((1 << 29) - 1))
    198     longjmp(png_jmpbuf(png_ptr), 1);
    199   state->width = static_cast<int>(w);
    200   state->height = static_cast<int>(h);
    201 
    202   // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA.
    203   if (color_type == PNG_COLOR_TYPE_PALETTE ||
    204       (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8))
    205     png_set_expand(png_ptr);
    206 
    207   // Transparency for paletted images.
    208   if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
    209     png_set_expand(png_ptr);
    210 
    211   // Convert 16-bit to 8-bit.
    212   if (bit_depth == 16)
    213     png_set_strip_16(png_ptr);
    214 
    215   // Expand grayscale to RGB.
    216   if (color_type == PNG_COLOR_TYPE_GRAY ||
    217       color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
    218     png_set_gray_to_rgb(png_ptr);
    219 
    220   // Deal with gamma and keep it under our control.
    221   double gamma;
    222   if (png_get_gAMA(png_ptr, info_ptr, &gamma)) {
    223     if (gamma <= 0.0 || gamma > kMaxGamma) {
    224       gamma = kInverseGamma;
    225       png_set_gAMA(png_ptr, info_ptr, gamma);
    226     }
    227     png_set_gamma(png_ptr, kDefaultGamma, gamma);
    228   } else {
    229     png_set_gamma(png_ptr, kDefaultGamma, kInverseGamma);
    230   }
    231 
    232   // Tell libpng to send us rows for interlaced pngs.
    233   if (interlace_type == PNG_INTERLACE_ADAM7)
    234     png_set_interlace_handling(png_ptr);
    235 
    236   // Update our info now
    237   png_read_update_info(png_ptr, info_ptr);
    238   channels = png_get_channels(png_ptr, info_ptr);
    239 
    240   // Pick our row format converter necessary for this data.
    241   if (channels == 3) {
    242     switch (state->output_format) {
    243       case FORMAT_RGB:
    244         state->row_converter = nullptr;  // no conversion necessary
    245         state->output_channels = 3;
    246         break;
    247       case FORMAT_RGBA:
    248         state->row_converter = &ConvertRGBtoRGBA;
    249         state->output_channels = 4;
    250         break;
    251       case FORMAT_BGRA:
    252         state->row_converter = &ConvertRGBtoBGRA;
    253         state->output_channels = 4;
    254         break;
    255       case FORMAT_GRAY:
    256         state->row_converter = nullptr;
    257         state->output_channels = 1;
    258         break;
    259       default:
    260         NOTREACHED();
    261         break;
    262     }
    263   } else if (channels == 4) {
    264     switch (state->output_format) {
    265       case FORMAT_RGB:
    266         state->row_converter = &ConvertRGBAtoRGB;
    267         state->output_channels = 3;
    268         break;
    269       case FORMAT_RGBA:
    270         state->row_converter = nullptr;  // no conversion necessary
    271         state->output_channels = 4;
    272         break;
    273       case FORMAT_BGRA:
    274         state->row_converter = &ConvertBetweenBGRAandRGBA;
    275         state->output_channels = 4;
    276         break;
    277       default:
    278         NOTREACHED();
    279         break;
    280     }
    281   } else {
    282     NOTREACHED();
    283     longjmp(png_jmpbuf(png_ptr), 1);
    284   }
    285 
    286   state->output->resize(state->width * state->output_channels * state->height);
    287 }
    288 
    289 void DecodeRowCallback(png_struct* png_ptr,
    290                        png_byte* new_row,
    291                        png_uint_32 row_num,
    292                        int pass) {
    293   PngDecoderState* state =
    294       static_cast<PngDecoderState*>(png_get_progressive_ptr(png_ptr));
    295 
    296   if (static_cast<int>(row_num) > state->height) {
    297     NOTREACHED();
    298     return;
    299   }
    300 
    301   unsigned char* base = NULL;
    302   base = &state->output->front();
    303 
    304   unsigned char* dest = &base[state->width * state->output_channels * row_num];
    305   if (state->row_converter)
    306     state->row_converter(new_row, state->width, dest, &state->is_opaque);
    307   else
    308     memcpy(dest, new_row, state->width * state->output_channels);
    309 }
    310 
    311 void DecodeEndCallback(png_struct* png_ptr, png_info* info) {
    312   PngDecoderState* state =
    313       static_cast<PngDecoderState*>(png_get_progressive_ptr(png_ptr));
    314 
    315   // Mark the image as complete, this will tell the Decode function that we
    316   // have successfully found the end of the data.
    317   state->done = true;
    318 }
    319 
    320 // Automatically destroys the given read structs on destruction to make
    321 // cleanup and error handling code cleaner.
    322 class PngReadStructDestroyer {
    323  public:
    324   PngReadStructDestroyer(png_struct** ps, png_info** pi) : ps_(ps), pi_(pi) {}
    325   ~PngReadStructDestroyer() { png_destroy_read_struct(ps_, pi_, NULL); }
    326 
    327  private:
    328   png_struct** ps_;
    329   png_info** pi_;
    330 };
    331 
    332 bool BuildPNGStruct(const unsigned char* input,
    333                     size_t input_size,
    334                     png_struct** png_ptr,
    335                     png_info** info_ptr) {
    336   if (input_size < 8)
    337     return false;  // Input data too small to be a png
    338 
    339   // Have libpng check the signature, it likes the first 8 bytes.
    340   if (png_sig_cmp(const_cast<unsigned char*>(input), 0, 8) != 0)
    341     return false;
    342 
    343   *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    344   if (!*png_ptr)
    345     return false;
    346 
    347   *info_ptr = png_create_info_struct(*png_ptr);
    348   if (!*info_ptr) {
    349     png_destroy_read_struct(png_ptr, NULL, NULL);
    350     return false;
    351   }
    352 
    353   return true;
    354 }
    355 
    356 }  // namespace
    357 
    358 // static
    359 bool Decode(const unsigned char* input,
    360             size_t input_size,
    361             ColorFormat format,
    362             std::vector<unsigned char>* output,
    363             int* w,
    364             int* h) {
    365   png_struct* png_ptr = NULL;
    366   png_info* info_ptr = NULL;
    367   if (!BuildPNGStruct(input, input_size, &png_ptr, &info_ptr))
    368     return false;
    369 
    370   PngReadStructDestroyer destroyer(&png_ptr, &info_ptr);
    371   if (setjmp(png_jmpbuf(png_ptr))) {
    372     // The destroyer will ensure that the structures are cleaned up in this
    373     // case, even though we may get here as a jump from random parts of the
    374     // PNG library called below.
    375     return false;
    376   }
    377 
    378   PngDecoderState state(format, output);
    379 
    380   png_set_progressive_read_fn(png_ptr, &state, &DecodeInfoCallback,
    381                               &DecodeRowCallback, &DecodeEndCallback);
    382   png_process_data(png_ptr, info_ptr, const_cast<unsigned char*>(input),
    383                    input_size);
    384 
    385   if (!state.done) {
    386     // Fed it all the data but the library didn't think we got all the data, so
    387     // this file must be truncated.
    388     output->clear();
    389     return false;
    390   }
    391 
    392   *w = state.width;
    393   *h = state.height;
    394   return true;
    395 }
    396 
    397 // Encoder
    398 //
    399 // This section of the code is based on nsPNGEncoder.cpp in Mozilla
    400 // (Copyright 2005 Google Inc.)
    401 
    402 namespace {
    403 
    404 // Passed around as the io_ptr in the png structs so our callbacks know where
    405 // to write data.
    406 struct PngEncoderState {
    407   explicit PngEncoderState(std::vector<unsigned char>* o) : out(o) {}
    408   std::vector<unsigned char>* out;
    409 };
    410 
    411 // Called by libpng to flush its internal buffer to ours.
    412 void EncoderWriteCallback(png_structp png, png_bytep data, png_size_t size) {
    413   PngEncoderState* state = static_cast<PngEncoderState*>(png_get_io_ptr(png));
    414   size_t old_size = state->out->size();
    415   state->out->resize(old_size + size);
    416   memcpy(&(*state->out)[old_size], data, size);
    417 }
    418 
    419 void FakeFlushCallback(png_structp png) {
    420   // We don't need to perform any flushing since we aren't doing real IO, but
    421   // we're required to provide this function by libpng.
    422 }
    423 
    424 void ConvertBGRAtoRGB(const unsigned char* bgra,
    425                       int pixel_width,
    426                       unsigned char* rgb,
    427                       bool* is_opaque) {
    428   for (int x = 0; x < pixel_width; x++) {
    429     const unsigned char* pixel_in = &bgra[x * 4];
    430     unsigned char* pixel_out = &rgb[x * 3];
    431     pixel_out[0] = pixel_in[2];
    432     pixel_out[1] = pixel_in[1];
    433     pixel_out[2] = pixel_in[0];
    434   }
    435 }
    436 
    437 #ifdef PNG_TEXT_SUPPORTED
    438 
    439 inline char* strdup(const char* str) {
    440 #if defined(OS_WIN)
    441   return _strdup(str);
    442 #else
    443   return ::strdup(str);
    444 #endif
    445 }
    446 
    447 class CommentWriter {
    448  public:
    449   explicit CommentWriter(const std::vector<Comment>& comments)
    450       : comments_(comments), png_text_(new png_text[comments.size()]) {
    451     for (size_t i = 0; i < comments.size(); ++i)
    452       AddComment(i, comments[i]);
    453   }
    454 
    455   ~CommentWriter() {
    456     for (size_t i = 0; i < comments_.size(); ++i) {
    457       free(png_text_[i].key);
    458       free(png_text_[i].text);
    459     }
    460     delete[] png_text_;
    461   }
    462 
    463   bool HasComments() { return !comments_.empty(); }
    464 
    465   png_text* get_png_text() { return png_text_; }
    466 
    467   int size() { return static_cast<int>(comments_.size()); }
    468 
    469  private:
    470   void AddComment(size_t pos, const Comment& comment) {
    471     png_text_[pos].compression = PNG_TEXT_COMPRESSION_NONE;
    472     // A PNG comment's key can only be 79 characters long.
    473     if (comment.key.length() > 79)
    474       return;
    475     png_text_[pos].key = strdup(comment.key.substr(0, 78).c_str());
    476     png_text_[pos].text = strdup(comment.text.c_str());
    477     png_text_[pos].text_length = comment.text.length();
    478 #ifdef PNG_iTXt_SUPPORTED
    479     png_text_[pos].itxt_length = 0;
    480     png_text_[pos].lang = 0;
    481     png_text_[pos].lang_key = 0;
    482 #endif
    483   }
    484 
    485   const std::vector<Comment> comments_;
    486   png_text* png_text_;
    487 };
    488 #endif  // PNG_TEXT_SUPPORTED
    489 
    490 // The type of functions usable for converting between pixel formats.
    491 typedef void (*FormatConverter)(const unsigned char* in,
    492                                 int w,
    493                                 unsigned char* out,
    494                                 bool* is_opaque);
    495 
    496 // libpng uses a wacky setjmp-based API, which makes the compiler nervous.
    497 // We constrain all of the calls we make to libpng where the setjmp() is in
    498 // place to this function.
    499 // Returns true on success.
    500 bool DoLibpngWrite(png_struct* png_ptr,
    501                    png_info* info_ptr,
    502                    PngEncoderState* state,
    503                    int width,
    504                    int height,
    505                    int row_byte_width,
    506                    const unsigned char* input,
    507                    int compression_level,
    508                    int png_output_color_type,
    509                    int output_color_components,
    510                    FormatConverter converter,
    511                    const std::vector<Comment>& comments) {
    512 #ifdef PNG_TEXT_SUPPORTED
    513   CommentWriter comment_writer(comments);
    514 #endif
    515   unsigned char* row_buffer = NULL;
    516 
    517   // Make sure to not declare any locals here -- locals in the presence
    518   // of setjmp() in C++ code makes gcc complain.
    519 
    520   if (setjmp(png_jmpbuf(png_ptr))) {
    521     delete[] row_buffer;
    522     return false;
    523   }
    524 
    525   png_set_compression_level(png_ptr, compression_level);
    526 
    527   // Set our callback for libpng to give us the data.
    528   png_set_write_fn(png_ptr, state, EncoderWriteCallback, FakeFlushCallback);
    529 
    530   png_set_IHDR(png_ptr, info_ptr, width, height, 8, png_output_color_type,
    531                PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
    532                PNG_FILTER_TYPE_DEFAULT);
    533 
    534 #ifdef PNG_TEXT_SUPPORTED
    535   if (comment_writer.HasComments()) {
    536     png_set_text(png_ptr, info_ptr, comment_writer.get_png_text(),
    537                  comment_writer.size());
    538   }
    539 #endif
    540 
    541   png_write_info(png_ptr, info_ptr);
    542 
    543   if (!converter) {
    544     // No conversion needed, give the data directly to libpng.
    545     for (int y = 0; y < height; y++) {
    546       png_write_row(png_ptr,
    547                     const_cast<unsigned char*>(&input[y * row_byte_width]));
    548     }
    549   } else {
    550     // Needs conversion using a separate buffer.
    551     row_buffer = new unsigned char[width * output_color_components];
    552     for (int y = 0; y < height; y++) {
    553       converter(&input[y * row_byte_width], width, row_buffer, NULL);
    554       png_write_row(png_ptr, row_buffer);
    555     }
    556     delete[] row_buffer;
    557   }
    558 
    559   png_write_end(png_ptr, info_ptr);
    560   return true;
    561 }
    562 
    563 }  // namespace
    564 
    565 // static
    566 bool EncodeWithCompressionLevel(const unsigned char* input,
    567                                 ColorFormat format,
    568                                 const int width,
    569                                 const int height,
    570                                 int row_byte_width,
    571                                 bool discard_transparency,
    572                                 const std::vector<Comment>& comments,
    573                                 int compression_level,
    574                                 std::vector<unsigned char>* output) {
    575   // Run to convert an input row into the output row format, NULL means no
    576   // conversion is necessary.
    577   FormatConverter converter = nullptr;
    578 
    579   int input_color_components, output_color_components;
    580   int png_output_color_type;
    581   switch (format) {
    582     case FORMAT_BGR:
    583       converter = ConvertBGRtoRGB;
    584 
    585     case FORMAT_RGB:
    586       input_color_components = 3;
    587       output_color_components = 3;
    588       png_output_color_type = PNG_COLOR_TYPE_RGB;
    589       discard_transparency = false;
    590       break;
    591 
    592     case FORMAT_RGBA:
    593       input_color_components = 4;
    594       if (discard_transparency) {
    595         output_color_components = 3;
    596         png_output_color_type = PNG_COLOR_TYPE_RGB;
    597         converter = ConvertRGBAtoRGB;
    598       } else {
    599         output_color_components = 4;
    600         png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
    601         converter = nullptr;
    602       }
    603       break;
    604 
    605     case FORMAT_BGRA:
    606       input_color_components = 4;
    607       if (discard_transparency) {
    608         output_color_components = 3;
    609         png_output_color_type = PNG_COLOR_TYPE_RGB;
    610         converter = ConvertBGRAtoRGB;
    611       } else {
    612         output_color_components = 4;
    613         png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
    614         converter = ConvertBetweenBGRAandRGBA;
    615       }
    616       break;
    617 
    618     case FORMAT_GRAY:
    619       input_color_components = 1;
    620       output_color_components = 1;
    621       png_output_color_type = PNG_COLOR_TYPE_GRAY;
    622       discard_transparency = false;
    623       break;
    624 
    625     default:
    626       NOTREACHED();
    627       return false;
    628   }
    629 
    630   // Row stride should be at least as long as the length of the data.
    631   if (row_byte_width < input_color_components * width)
    632     return false;
    633 
    634   png_struct* png_ptr =
    635       png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    636   if (!png_ptr)
    637     return false;
    638   png_info* info_ptr = png_create_info_struct(png_ptr);
    639   if (!info_ptr) {
    640     png_destroy_write_struct(&png_ptr, NULL);
    641     return false;
    642   }
    643 
    644   PngEncoderState state(output);
    645   bool success =
    646       DoLibpngWrite(png_ptr, info_ptr, &state, width, height, row_byte_width,
    647                     input, compression_level, png_output_color_type,
    648                     output_color_components, converter, comments);
    649   png_destroy_write_struct(&png_ptr, &info_ptr);
    650 
    651   return success;
    652 }
    653 
    654 // static
    655 bool Encode(const unsigned char* input,
    656             ColorFormat format,
    657             const int width,
    658             const int height,
    659             int row_byte_width,
    660             bool discard_transparency,
    661             const std::vector<Comment>& comments,
    662             std::vector<unsigned char>* output) {
    663   return EncodeWithCompressionLevel(input, format, width, height,
    664                                     row_byte_width, discard_transparency,
    665                                     comments, Z_DEFAULT_COMPRESSION, output);
    666 }
    667 
    668 // Decode a PNG into an RGBA pixel array.
    669 bool DecodePNG(const unsigned char* input,
    670                size_t input_size,
    671                std::vector<unsigned char>* output,
    672                int* width,
    673                int* height) {
    674   return Decode(input, input_size, FORMAT_RGBA, output, width, height);
    675 }
    676 
    677 // Encode a BGR pixel array into a PNG.
    678 bool EncodeBGRPNG(const unsigned char* input,
    679                   int width,
    680                   int height,
    681                   int row_byte_width,
    682                   std::vector<unsigned char>* output) {
    683   return Encode(input, FORMAT_BGR, width, height, row_byte_width, false,
    684                 std::vector<Comment>(), output);
    685 }
    686 
    687 // Encode an RGBA pixel array into a PNG.
    688 bool EncodeRGBAPNG(const unsigned char* input,
    689                    int width,
    690                    int height,
    691                    int row_byte_width,
    692                    std::vector<unsigned char>* output) {
    693   return Encode(input, FORMAT_RGBA, width, height, row_byte_width, false,
    694                 std::vector<Comment>(), output);
    695 }
    696 
    697 // Encode an BGRA pixel array into a PNG.
    698 bool EncodeBGRAPNG(const unsigned char* input,
    699                    int width,
    700                    int height,
    701                    int row_byte_width,
    702                    bool discard_transparency,
    703                    std::vector<unsigned char>* output) {
    704   return Encode(input, FORMAT_BGRA, width, height, row_byte_width,
    705                 discard_transparency, std::vector<Comment>(), output);
    706 }
    707 
    708 // Encode a grayscale pixel array into a PNG.
    709 bool EncodeGrayPNG(const unsigned char* input,
    710                    int width,
    711                    int height,
    712                    int row_byte_width,
    713                    std::vector<unsigned char>* output) {
    714   return Encode(input, FORMAT_GRAY, width, height, row_byte_width, false,
    715                 std::vector<Comment>(), output);
    716 }
    717 
    718 }  // namespace image_diff_png
    719