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