12385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "tools/imagediff/image_diff_png.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
102385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "base/logging.h"
112385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "build/build_config.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/libpng/png.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/zlib/zlib.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
152385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdochnamespace image_diff_png {
162385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch
172385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch// This is a duplicate of ui/gfx/codec/png_codec.cc, after removing code related
182385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch// to Skia, that we can use when running layout tests with minimal dependencies.
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum ColorFormat {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 3 bytes per pixel (packed), in RGB order regardless of endianness.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is the native JPEG format.
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FORMAT_RGB,
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 4 bytes per pixel, in RGBA order in memory regardless of endianness.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FORMAT_RGBA,
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 4 bytes per pixel, in BGRA order in memory regardless of endianness.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is the default Windows DIB order.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FORMAT_BGRA,
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 4 bytes per pixel, in pre-multiplied kARGB_8888_Config format. For use
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with directly writing to a skia bitmap.
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FORMAT_SkBitmap
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Represents a comment in the tEXt ancillary chunk of the png.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct Comment {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string key;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string text;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Converts BGRA->RGBA and RGBA->BGRA.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ConvertBetweenBGRAandRGBA(const unsigned char* input, int pixel_width,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               unsigned char* output, bool* is_opaque) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int x = 0; x < pixel_width; x++) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const unsigned char* pixel_in = &input[x * 4];
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* pixel_out = &output[x * 4];
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pixel_out[0] = pixel_in[2];
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pixel_out[1] = pixel_in[1];
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pixel_out[2] = pixel_in[0];
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pixel_out[3] = pixel_in[3];
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ConvertRGBAtoRGB(const unsigned char* rgba, int pixel_width,
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      unsigned char* rgb, bool* is_opaque) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int x = 0; x < pixel_width; x++) {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const unsigned char* pixel_in = &rgba[x * 4];
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* pixel_out = &rgb[x * 3];
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pixel_out[0] = pixel_in[0];
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pixel_out[1] = pixel_in[1];
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pixel_out[2] = pixel_in[2];
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Decoder --------------------------------------------------------------------
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This code is based on WebKit libpng interface (PNGImageDecoder), which is
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in turn based on the Mozilla png decoder.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Gamma constants: We assume we're on Windows which uses a gamma of 2.2.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const double kMaxGamma = 21474.83;  // Maximum gamma accepted by png library.
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const double kDefaultGamma = 2.2;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const double kInverseGamma = 1.0 / kDefaultGamma;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PngDecoderState {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Output is a vector<unsigned char>.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PngDecoderState(ColorFormat ofmt, std::vector<unsigned char>* o)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : output_format(ofmt),
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        output_channels(0),
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        is_opaque(true),
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        output(o),
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        row_converter(NULL),
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        width(0),
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        height(0),
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        done(false) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ColorFormat output_format;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int output_channels;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Used during the reading of an SkBitmap. Defaults to true until we see a
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // pixel with anything other than an alpha of 255.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_opaque;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // An intermediary buffer for decode output.
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<unsigned char>* output;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called to convert a row from the library to the correct output format.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // When NULL, no conversion is necessary.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void (*row_converter)(const unsigned char* in, int w, unsigned char* out,
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        bool* is_opaque);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Size of the image, set in the info callback.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int width;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int height;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set to true when we've found the end of the data.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool done;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ConvertRGBtoRGBA(const unsigned char* rgb, int pixel_width,
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      unsigned char* rgba, bool* is_opaque) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int x = 0; x < pixel_width; x++) {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const unsigned char* pixel_in = &rgb[x * 3];
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* pixel_out = &rgba[x * 4];
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pixel_out[0] = pixel_in[0];
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pixel_out[1] = pixel_in[1];
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pixel_out[2] = pixel_in[2];
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pixel_out[3] = 0xff;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ConvertRGBtoBGRA(const unsigned char* rgb, int pixel_width,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      unsigned char* bgra, bool* is_opaque) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int x = 0; x < pixel_width; x++) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const unsigned char* pixel_in = &rgb[x * 3];
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* pixel_out = &bgra[x * 4];
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pixel_out[0] = pixel_in[2];
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pixel_out[1] = pixel_in[1];
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pixel_out[2] = pixel_in[0];
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pixel_out[3] = 0xff;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Called when the png header has been read. This code is based on the WebKit
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PNGImageDecoder
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DecodeInfoCallback(png_struct* png_ptr, png_info* info_ptr) {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PngDecoderState* state = static_cast<PngDecoderState*>(
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      png_get_progressive_ptr(png_ptr));
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int bit_depth, color_type, interlace_type, compression_type;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int filter_type, channels;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  png_uint_32 w, h;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               &interlace_type, &compression_type, &filter_type);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Bounds check. When the image is unreasonably big, we'll error out and
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // end up back at the setjmp call when we set up decoding.  "Unreasonably big"
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // means "big enough that w * h * 32bpp might overflow an int"; we choose this
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // threshold to match WebKit and because a number of places in code assume
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that an image's size (in bytes) fits in a (signed) int.
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned long long total_size =
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<unsigned long long>(w) * static_cast<unsigned long long>(h);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (total_size > ((1 << 29) - 1))
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    longjmp(png_jmpbuf(png_ptr), 1);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state->width = static_cast<int>(w);
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state->height = static_cast<int>(h);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA.
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (color_type == PNG_COLOR_TYPE_PALETTE ||
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8))
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    png_set_expand(png_ptr);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Transparency for paletted images.
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    png_set_expand(png_ptr);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Convert 16-bit to 8-bit.
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bit_depth == 16)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    png_set_strip_16(png_ptr);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Expand grayscale to RGB.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (color_type == PNG_COLOR_TYPE_GRAY ||
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    png_set_gray_to_rgb(png_ptr);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Deal with gamma and keep it under our control.
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double gamma;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (png_get_gAMA(png_ptr, info_ptr, &gamma)) {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (gamma <= 0.0 || gamma > kMaxGamma) {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gamma = kInverseGamma;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      png_set_gAMA(png_ptr, info_ptr, gamma);
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    png_set_gamma(png_ptr, kDefaultGamma, gamma);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    png_set_gamma(png_ptr, kDefaultGamma, kInverseGamma);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Tell libpng to send us rows for interlaced pngs.
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (interlace_type == PNG_INTERLACE_ADAM7)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    png_set_interlace_handling(png_ptr);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update our info now
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  png_read_update_info(png_ptr, info_ptr);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  channels = png_get_channels(png_ptr, info_ptr);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Pick our row format converter necessary for this data.
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (channels == 3) {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (state->output_format) {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case FORMAT_RGB:
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state->row_converter = NULL;  // no conversion necessary
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state->output_channels = 3;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case FORMAT_RGBA:
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state->row_converter = &ConvertRGBtoRGBA;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state->output_channels = 4;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case FORMAT_BGRA:
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state->row_converter = &ConvertRGBtoBGRA;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state->output_channels = 4;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
2212385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        NOTREACHED() << "Unknown output format";
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (channels == 4) {
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (state->output_format) {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case FORMAT_RGB:
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state->row_converter = &ConvertRGBAtoRGB;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state->output_channels = 3;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case FORMAT_RGBA:
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state->row_converter = NULL;  // no conversion necessary
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state->output_channels = 4;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case FORMAT_BGRA:
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state->row_converter = &ConvertBetweenBGRAandRGBA;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state->output_channels = 4;
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
2392385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        NOTREACHED() << "Unknown output format";
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2432385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    NOTREACHED() << "Unknown input channels";
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    longjmp(png_jmpbuf(png_ptr), 1);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state->output->resize(
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      state->width * state->output_channels * state->height);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DecodeRowCallback(png_struct* png_ptr, png_byte* new_row,
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       png_uint_32 row_num, int pass) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PngDecoderState* state = static_cast<PngDecoderState*>(
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      png_get_progressive_ptr(png_ptr));
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(pass == 0);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (static_cast<int>(row_num) > state->height) {
2582385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    NOTREACHED() << "Invalid row";
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* base = NULL;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base = &state->output->front();
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char* dest = &base[state->width * state->output_channels * row_num];
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state->row_converter)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state->row_converter(new_row, state->width, dest, &state->is_opaque);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(dest, new_row, state->width * state->output_channels);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DecodeEndCallback(png_struct* png_ptr, png_info* info) {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PngDecoderState* state = static_cast<PngDecoderState*>(
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      png_get_progressive_ptr(png_ptr));
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mark the image as complete, this will tell the Decode function that we
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // have successfully found the end of the data.
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state->done = true;
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Automatically destroys the given read structs on destruction to make
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// cleanup and error handling code cleaner.
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PngReadStructDestroyer {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PngReadStructDestroyer(png_struct** ps, png_info** pi) : ps_(ps), pi_(pi) {
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~PngReadStructDestroyer() {
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    png_destroy_read_struct(ps_, pi_, NULL);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  png_struct** ps_;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  png_info** pi_;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BuildPNGStruct(const unsigned char* input, size_t input_size,
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    png_struct** png_ptr, png_info** info_ptr) {
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (input_size < 8)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // Input data too small to be a png
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Have libpng check the signature, it likes the first 8 bytes.
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (png_sig_cmp(const_cast<unsigned char*>(input), 0, 8) != 0)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!*png_ptr)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *info_ptr = png_create_info_struct(*png_ptr);
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!*info_ptr) {
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    png_destroy_read_struct(png_ptr, NULL, NULL);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Decode(const unsigned char* input, size_t input_size,
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      ColorFormat format, std::vector<unsigned char>* output,
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      int* w, int* h) {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  png_struct* png_ptr = NULL;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  png_info* info_ptr = NULL;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!BuildPNGStruct(input, input_size, &png_ptr, &info_ptr))
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PngReadStructDestroyer destroyer(&png_ptr, &info_ptr);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (setjmp(png_jmpbuf(png_ptr))) {
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The destroyer will ensure that the structures are cleaned up in this
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // case, even though we may get here as a jump from random parts of the
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // PNG library called below.
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PngDecoderState state(format, output);
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  png_set_progressive_read_fn(png_ptr, &state, &DecodeInfoCallback,
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &DecodeRowCallback, &DecodeEndCallback);
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  png_process_data(png_ptr,
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   info_ptr,
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   const_cast<unsigned char*>(input),
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   input_size);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!state.done) {
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Fed it all the data but the library didn't think we got all the data, so
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // this file must be truncated.
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output->clear();
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *w = state.width;
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *h = state.height;
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Encoder --------------------------------------------------------------------
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This section of the code is based on nsPNGEncoder.cpp in Mozilla
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (Copyright 2005 Google Inc.)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Passed around as the io_ptr in the png structs so our callbacks know where
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to write data.
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct PngEncoderState {
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit PngEncoderState(std::vector<unsigned char>* o) : out(o) {}
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<unsigned char>* out;
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Called by libpng to flush its internal buffer to ours.
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EncoderWriteCallback(png_structp png, png_bytep data, png_size_t size) {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PngEncoderState* state = static_cast<PngEncoderState*>(png_get_io_ptr(png));
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(state->out);
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t old_size = state->out->size();
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state->out->resize(old_size + size);
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(&(*state->out)[old_size], data, size);
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FakeFlushCallback(png_structp png) {
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't need to perform any flushing since we aren't doing real IO, but
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we're required to provide this function by libpng.
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ConvertBGRAtoRGB(const unsigned char* bgra, int pixel_width,
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      unsigned char* rgb, bool* is_opaque) {
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int x = 0; x < pixel_width; x++) {
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const unsigned char* pixel_in = &bgra[x * 4];
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned char* pixel_out = &rgb[x * 3];
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pixel_out[0] = pixel_in[2];
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pixel_out[1] = pixel_in[1];
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pixel_out[2] = pixel_in[0];
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef PNG_TEXT_SUPPORTED
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline char* strdup(const char* str) {
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return _strdup(str);
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ::strdup(str);
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CommentWriter {
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit CommentWriter(const std::vector<Comment>& comments)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : comments_(comments),
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        png_text_(new png_text[comments.size()]) {
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < comments.size(); ++i)
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AddComment(i, comments[i]);
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~CommentWriter() {
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < comments_.size(); ++i) {
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      free(png_text_[i].key);
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      free(png_text_[i].text);
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete [] png_text_;
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool HasComments() {
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return !comments_.empty();
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  png_text* get_png_text() {
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return png_text_;
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int size() {
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return static_cast<int>(comments_.size());
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void AddComment(size_t pos, const Comment& comment) {
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    png_text_[pos].compression = PNG_TEXT_COMPRESSION_NONE;
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // A PNG comment's key can only be 79 characters long.
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(comment.key.length() < 79);
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    png_text_[pos].key = strdup(comment.key.substr(0, 78).c_str());
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    png_text_[pos].text = strdup(comment.text.c_str());
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    png_text_[pos].text_length = comment.text.length();
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef PNG_iTXt_SUPPORTED
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    png_text_[pos].itxt_length = 0;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    png_text_[pos].lang = 0;
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    png_text_[pos].lang_key = 0;
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::vector<Comment> comments_;
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  png_text* png_text_;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // PNG_TEXT_SUPPORTED
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The type of functions usable for converting between pixel formats.
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef void (*FormatConverter)(const unsigned char* in, int w,
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                unsigned char* out, bool* is_opaque);
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// libpng uses a wacky setjmp-based API, which makes the compiler nervous.
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We constrain all of the calls we make to libpng where the setjmp() is in
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// place to this function.
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true on success.
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DoLibpngWrite(png_struct* png_ptr, png_info* info_ptr,
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   PngEncoderState* state,
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   int width, int height, int row_byte_width,
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   const unsigned char* input, int compression_level,
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   int png_output_color_type, int output_color_components,
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   FormatConverter converter,
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   const std::vector<Comment>& comments) {
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#ifdef PNG_TEXT_SUPPORTED
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CommentWriter comment_writer(comments);
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  unsigned char* row_buffer = NULL;
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure to not declare any locals here -- locals in the presence
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of setjmp() in C++ code makes gcc complain.
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (setjmp(png_jmpbuf(png_ptr))) {
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delete[] row_buffer;
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  png_set_compression_level(png_ptr, compression_level);
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set our callback for libpng to give us the data.
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  png_set_write_fn(png_ptr, state, EncoderWriteCallback, FakeFlushCallback);
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  png_set_IHDR(png_ptr, info_ptr, width, height, 8, png_output_color_type,
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               PNG_FILTER_TYPE_DEFAULT);
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef PNG_TEXT_SUPPORTED
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (comment_writer.HasComments()) {
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    png_set_text(png_ptr, info_ptr, comment_writer.get_png_text(),
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 comment_writer.size());
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  png_write_info(png_ptr, info_ptr);
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!converter) {
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No conversion needed, give the data directly to libpng.
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int y = 0; y < height; y ++) {
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      png_write_row(png_ptr,
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const_cast<unsigned char*>(&input[y * row_byte_width]));
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Needs conversion using a separate buffer.
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    row_buffer = new unsigned char[width * output_color_components];
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int y = 0; y < height; y ++) {
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      converter(&input[y * row_byte_width], width, row_buffer, NULL);
5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      png_write_row(png_ptr, row_buffer);
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delete[] row_buffer;
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  png_write_end(png_ptr, info_ptr);
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool EncodeWithCompressionLevel(const unsigned char* input, ColorFormat format,
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const int width, const int height,
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                int row_byte_width,
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                bool discard_transparency,
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const std::vector<Comment>& comments,
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                int compression_level,
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                std::vector<unsigned char>* output) {
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Run to convert an input row into the output row format, NULL means no
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // conversion is necessary.
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FormatConverter converter = NULL;
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int input_color_components, output_color_components;
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int png_output_color_type;
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (format) {
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FORMAT_RGB:
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      input_color_components = 3;
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      output_color_components = 3;
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      png_output_color_type = PNG_COLOR_TYPE_RGB;
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      discard_transparency = false;
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FORMAT_RGBA:
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      input_color_components = 4;
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (discard_transparency) {
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        output_color_components = 3;
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        png_output_color_type = PNG_COLOR_TYPE_RGB;
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        converter = ConvertRGBAtoRGB;
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        output_color_components = 4;
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        converter = NULL;
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case FORMAT_BGRA:
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      input_color_components = 4;
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (discard_transparency) {
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        output_color_components = 3;
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        png_output_color_type = PNG_COLOR_TYPE_RGB;
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        converter = ConvertBGRAtoRGB;
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        output_color_components = 4;
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        converter = ConvertBetweenBGRAandRGBA;
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
5732385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      NOTREACHED() << "Unknown pixel format";
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Row stride should be at least as long as the length of the data.
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(input_color_components * width <= row_byte_width);
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  png_struct* png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                NULL, NULL, NULL);
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!png_ptr)
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  png_info* info_ptr = png_create_info_struct(png_ptr);
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!info_ptr) {
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    png_destroy_write_struct(&png_ptr, NULL);
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PngEncoderState state(output);
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = DoLibpngWrite(png_ptr, info_ptr, &state,
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               width, height, row_byte_width,
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               input, compression_level, png_output_color_type,
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               output_color_components, converter, comments);
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  png_destroy_write_struct(&png_ptr, &info_ptr);
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return success;
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Encode(const unsigned char* input, ColorFormat format,
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            const int width, const int height, int row_byte_width,
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            bool discard_transparency,
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            const std::vector<Comment>& comments,
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            std::vector<unsigned char>* output) {
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return EncodeWithCompressionLevel(input, format, width, height,
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    row_byte_width,
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    discard_transparency,
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    comments, Z_DEFAULT_COMPRESSION,
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    output);
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Decode a PNG into an RGBA pixel array.
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DecodePNG(const unsigned char* input, size_t input_size,
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               std::vector<unsigned char>* output,
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               int* width, int* height) {
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Decode(input, input_size, FORMAT_RGBA, output, width, height);
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Encode an RGBA pixel array into a PNG.
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool EncodeRGBAPNG(const unsigned char* input,
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   int width,
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   int height,
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   int row_byte_width,
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   std::vector<unsigned char>* output) {
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Encode(input, FORMAT_RGBA,
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      width, height, row_byte_width, false,
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::vector<Comment>(), output);
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Encode an BGRA pixel array into a PNG.
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool EncodeBGRAPNG(const unsigned char* input,
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   int width,
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   int height,
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   int row_byte_width,
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   bool discard_transparency,
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   std::vector<unsigned char>* output) {
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Encode(input, FORMAT_BGRA,
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      width, height, row_byte_width, discard_transparency,
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::vector<Comment>(), output);
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6432385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch}  // image_diff_png
644