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