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