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