| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/gfx/codec/png_codec.h" | 5 #include "ui/gfx/codec/png_codec.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/macros.h" | 10 #include "base/macros.h" |
| (...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 306 | 306 |
| 307 void DecodeEndCallback(png_struct* png_ptr, png_info* info) { | 307 void DecodeEndCallback(png_struct* png_ptr, png_info* info) { |
| 308 PngDecoderState* state = static_cast<PngDecoderState*>( | 308 PngDecoderState* state = static_cast<PngDecoderState*>( |
| 309 png_get_progressive_ptr(png_ptr)); | 309 png_get_progressive_ptr(png_ptr)); |
| 310 | 310 |
| 311 // Mark the image as complete, this will tell the Decode function that we | 311 // Mark the image as complete, this will tell the Decode function that we |
| 312 // have successfully found the end of the data. | 312 // have successfully found the end of the data. |
| 313 state->done = true; | 313 state->done = true; |
| 314 } | 314 } |
| 315 | 315 |
| 316 // Automatically destroys the given read structs on destruction to make | 316 // Holds png struct and info ensuring the proper destruction. |
| 317 // cleanup and error handling code cleaner. | 317 class PngReadStructInfo { |
| 318 class PngReadStructDestroyer { | |
| 319 public: | 318 public: |
| 320 PngReadStructDestroyer(png_struct** ps, png_info** pi) : ps_(ps), pi_(pi) { | 319 PngReadStructInfo(): png_ptr_(nullptr), info_ptr_(nullptr) { |
| 321 } | 320 } |
| 322 ~PngReadStructDestroyer() { | 321 ~PngReadStructInfo() { |
| 323 png_destroy_read_struct(ps_, pi_, NULL); | 322 png_destroy_read_struct(&png_ptr_, &info_ptr_, NULL); |
| 324 } | 323 } |
| 324 |
| 325 bool Build(const unsigned char* input, size_t input_size) { |
| 326 if (input_size < 8) |
| 327 return false; // Input data too small to be a png |
| 328 |
| 329 // Have libpng check the signature, it likes the first 8 bytes. |
| 330 if (png_sig_cmp(const_cast<unsigned char*>(input), 0, 8) != 0) |
| 331 return false; |
| 332 |
| 333 png_ptr_ = png_create_read_struct( |
| 334 PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); |
| 335 if (!png_ptr_) |
| 336 return false; |
| 337 |
| 338 info_ptr_ = png_create_info_struct(png_ptr_); |
| 339 if (!info_ptr_) { |
| 340 return false; |
| 341 } |
| 342 return true; |
| 343 } |
| 344 |
| 345 png_struct* png_ptr_; |
| 346 png_info* info_ptr_; |
| 325 private: | 347 private: |
| 326 png_struct** ps_; | 348 DISALLOW_COPY_AND_ASSIGN(PngReadStructInfo); |
| 327 png_info** pi_; | |
| 328 DISALLOW_COPY_AND_ASSIGN(PngReadStructDestroyer); | |
| 329 }; | 349 }; |
| 330 | 350 |
| 331 // Automatically destroys the given write structs on destruction to make | 351 // Holds png struct and info ensuring the proper destruction. |
| 332 // cleanup and error handling code cleaner. | 352 class PngWriteStructInfo { |
| 333 class PngWriteStructDestroyer { | |
| 334 public: | 353 public: |
| 335 explicit PngWriteStructDestroyer(png_struct** ps) : ps_(ps), pi_(0) { | 354 PngWriteStructInfo() : png_ptr_(nullptr), info_ptr_(nullptr) { |
| 336 } | |
| 337 ~PngWriteStructDestroyer() { | |
| 338 png_destroy_write_struct(ps_, pi_); | |
| 339 } | |
| 340 void SetInfoStruct(png_info** pi) { | |
| 341 pi_ = pi; | |
| 342 } | |
| 343 private: | |
| 344 png_struct** ps_; | |
| 345 png_info** pi_; | |
| 346 DISALLOW_COPY_AND_ASSIGN(PngWriteStructDestroyer); | |
| 347 }; | |
| 348 | |
| 349 bool BuildPNGStruct(const unsigned char* input, size_t input_size, | |
| 350 png_struct** png_ptr, png_info** info_ptr) { | |
| 351 if (input_size < 8) | |
| 352 return false; // Input data too small to be a png | |
| 353 | |
| 354 // Have libpng check the signature, it likes the first 8 bytes. | |
| 355 if (png_sig_cmp(const_cast<unsigned char*>(input), 0, 8) != 0) | |
| 356 return false; | |
| 357 | |
| 358 *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |
| 359 if (!*png_ptr) | |
| 360 return false; | |
| 361 | |
| 362 *info_ptr = png_create_info_struct(*png_ptr); | |
| 363 if (!*info_ptr) { | |
| 364 png_destroy_read_struct(png_ptr, NULL, NULL); | |
| 365 return false; | |
| 366 } | 355 } |
| 367 | 356 |
| 368 return true; | 357 ~PngWriteStructInfo() { |
| 369 } | 358 png_destroy_write_struct(&png_ptr_, &info_ptr_); |
| 359 } |
| 360 |
| 361 png_struct* png_ptr_; |
| 362 png_info* info_ptr_; |
| 363 private: |
| 364 DISALLOW_COPY_AND_ASSIGN(PngWriteStructInfo); |
| 365 }; |
| 370 | 366 |
| 371 // Libpng user error and warning functions which allows us to print libpng | 367 // Libpng user error and warning functions which allows us to print libpng |
| 372 // errors and warnings using Chrome's logging facilities instead of stderr. | 368 // errors and warnings using Chrome's logging facilities instead of stderr. |
| 373 | 369 |
| 374 void LogLibPNGDecodeError(png_structp png_ptr, png_const_charp error_msg) { | 370 void LogLibPNGDecodeError(png_structp png_ptr, png_const_charp error_msg) { |
| 375 DLOG(ERROR) << "libpng decode error: " << error_msg; | 371 DLOG(ERROR) << "libpng decode error: " << error_msg; |
| 376 longjmp(png_jmpbuf(png_ptr), 1); | 372 longjmp(png_jmpbuf(png_ptr), 1); |
| 377 } | 373 } |
| 378 | 374 |
| 379 void LogLibPNGDecodeWarning(png_structp png_ptr, png_const_charp warning_msg) { | 375 void LogLibPNGDecodeWarning(png_structp png_ptr, png_const_charp warning_msg) { |
| 380 DLOG(ERROR) << "libpng decode warning: " << warning_msg; | 376 DLOG(ERROR) << "libpng decode warning: " << warning_msg; |
| 381 } | 377 } |
| 382 | 378 |
| 383 void LogLibPNGEncodeError(png_structp png_ptr, png_const_charp error_msg) { | 379 void LogLibPNGEncodeError(png_structp png_ptr, png_const_charp error_msg) { |
| 384 DLOG(ERROR) << "libpng encode error: " << error_msg; | 380 DLOG(ERROR) << "libpng encode error: " << error_msg; |
| 385 longjmp(png_jmpbuf(png_ptr), 1); | 381 longjmp(png_jmpbuf(png_ptr), 1); |
| 386 } | 382 } |
| 387 | 383 |
| 388 void LogLibPNGEncodeWarning(png_structp png_ptr, png_const_charp warning_msg) { | 384 void LogLibPNGEncodeWarning(png_structp png_ptr, png_const_charp warning_msg) { |
| 389 DLOG(ERROR) << "libpng encode warning: " << warning_msg; | 385 DLOG(ERROR) << "libpng encode warning: " << warning_msg; |
| 390 } | 386 } |
| 391 | 387 |
| 392 } // namespace | 388 } // namespace |
| 393 | 389 |
| 394 // static | 390 // static |
| 395 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, | 391 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, |
| 396 ColorFormat format, std::vector<unsigned char>* output, | 392 ColorFormat format, std::vector<unsigned char>* output, |
| 397 int* w, int* h) { | 393 int* w, int* h) { |
| 398 png_struct* png_ptr = NULL; | 394 PngReadStructInfo si; |
| 399 png_info* info_ptr = NULL; | 395 if (!si.Build(input, input_size)) |
| 400 if (!BuildPNGStruct(input, input_size, &png_ptr, &info_ptr)) | |
| 401 return false; | 396 return false; |
| 402 | 397 |
| 403 PngReadStructDestroyer destroyer(&png_ptr, &info_ptr); | 398 if (setjmp(png_jmpbuf(si.png_ptr_))) { |
| 404 if (setjmp(png_jmpbuf(png_ptr))) { | |
| 405 // The destroyer will ensure that the structures are cleaned up in this | 399 // The destroyer will ensure that the structures are cleaned up in this |
| 406 // case, even though we may get here as a jump from random parts of the | 400 // case, even though we may get here as a jump from random parts of the |
| 407 // PNG library called below. | 401 // PNG library called below. |
| 408 return false; | 402 return false; |
| 409 } | 403 } |
| 410 | 404 |
| 411 PngDecoderState state(format, output); | 405 PngDecoderState state(format, output); |
| 412 | 406 |
| 413 png_set_error_fn(png_ptr, NULL, LogLibPNGDecodeError, LogLibPNGDecodeWarning); | 407 png_set_error_fn(si.png_ptr_, NULL, |
| 414 png_set_progressive_read_fn(png_ptr, &state, &DecodeInfoCallback, | 408 LogLibPNGDecodeError, LogLibPNGDecodeWarning); |
| 409 png_set_progressive_read_fn(si.png_ptr_, &state, &DecodeInfoCallback, |
| 415 &DecodeRowCallback, &DecodeEndCallback); | 410 &DecodeRowCallback, &DecodeEndCallback); |
| 416 png_process_data(png_ptr, | 411 png_process_data(si.png_ptr_, |
| 417 info_ptr, | 412 si.info_ptr_, |
| 418 const_cast<unsigned char*>(input), | 413 const_cast<unsigned char*>(input), |
| 419 input_size); | 414 input_size); |
| 420 | 415 |
| 421 if (!state.done) { | 416 if (!state.done) { |
| 422 // Fed it all the data but the library didn't think we got all the data, so | 417 // Fed it all the data but the library didn't think we got all the data, so |
| 423 // this file must be truncated. | 418 // this file must be truncated. |
| 424 output->clear(); | 419 output->clear(); |
| 425 return false; | 420 return false; |
| 426 } | 421 } |
| 427 | 422 |
| 428 *w = state.width; | 423 *w = state.width; |
| 429 *h = state.height; | 424 *h = state.height; |
| 430 return true; | 425 return true; |
| 431 } | 426 } |
| 432 | 427 |
| 433 // static | 428 // static |
| 434 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, | 429 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, |
| 435 SkBitmap* bitmap) { | 430 SkBitmap* bitmap) { |
| 436 DCHECK(bitmap); | 431 DCHECK(bitmap); |
| 437 png_struct* png_ptr = NULL; | 432 PngReadStructInfo si; |
| 438 png_info* info_ptr = NULL; | 433 if (!si.Build(input, input_size)) |
| 439 if (!BuildPNGStruct(input, input_size, &png_ptr, &info_ptr)) | |
| 440 return false; | 434 return false; |
| 441 | 435 |
| 442 PngReadStructDestroyer destroyer(&png_ptr, &info_ptr); | 436 if (setjmp(png_jmpbuf(si.png_ptr_))) { |
| 443 if (setjmp(png_jmpbuf(png_ptr))) { | |
| 444 // The destroyer will ensure that the structures are cleaned up in this | 437 // The destroyer will ensure that the structures are cleaned up in this |
| 445 // case, even though we may get here as a jump from random parts of the | 438 // case, even though we may get here as a jump from random parts of the |
| 446 // PNG library called below. | 439 // PNG library called below. |
| 447 return false; | 440 return false; |
| 448 } | 441 } |
| 449 | 442 |
| 450 PngDecoderState state(bitmap); | 443 PngDecoderState state(bitmap); |
| 451 | 444 |
| 452 png_set_progressive_read_fn(png_ptr, &state, &DecodeInfoCallback, | 445 png_set_progressive_read_fn(si.png_ptr_, &state, &DecodeInfoCallback, |
| 453 &DecodeRowCallback, &DecodeEndCallback); | 446 &DecodeRowCallback, &DecodeEndCallback); |
| 454 png_process_data(png_ptr, | 447 png_process_data(si.png_ptr_, |
| 455 info_ptr, | 448 si.info_ptr_, |
| 456 const_cast<unsigned char*>(input), | 449 const_cast<unsigned char*>(input), |
| 457 input_size); | 450 input_size); |
| 458 | 451 |
| 459 if (!state.done) { | 452 if (!state.done) { |
| 460 return false; | 453 return false; |
| 461 } | 454 } |
| 462 | 455 |
| 463 // Set the bitmap's opaqueness based on what we saw. | 456 // Set the bitmap's opaqueness based on what we saw. |
| 464 bitmap->setAlphaType(state.is_opaque ? | 457 bitmap->setAlphaType(state.is_opaque ? |
| 465 kOpaque_SkAlphaType : kPremul_SkAlphaType); | 458 kOpaque_SkAlphaType : kPremul_SkAlphaType); |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 701 break; | 694 break; |
| 702 | 695 |
| 703 default: | 696 default: |
| 704 NOTREACHED() << "Unknown pixel format"; | 697 NOTREACHED() << "Unknown pixel format"; |
| 705 return false; | 698 return false; |
| 706 } | 699 } |
| 707 | 700 |
| 708 // Row stride should be at least as long as the length of the data. | 701 // Row stride should be at least as long as the length of the data. |
| 709 DCHECK(input_color_components * size.width() <= row_byte_width); | 702 DCHECK(input_color_components * size.width() <= row_byte_width); |
| 710 | 703 |
| 711 png_struct* png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, | 704 PngWriteStructInfo si; |
| 712 NULL, NULL, NULL); | 705 si.png_ptr_ = png_create_write_struct(PNG_LIBPNG_VER_STRING, |
| 713 if (!png_ptr) | 706 NULL, NULL, NULL); |
| 707 if (!si.png_ptr_) |
| 714 return false; | 708 return false; |
| 715 PngWriteStructDestroyer destroyer(&png_ptr); | 709 |
| 716 png_info* info_ptr = png_create_info_struct(png_ptr); | 710 si.info_ptr_ = png_create_info_struct(si.png_ptr_); |
| 717 if (!info_ptr) | 711 if (!si.info_ptr_) |
| 718 return false; | 712 return false; |
| 719 destroyer.SetInfoStruct(&info_ptr); | |
| 720 | 713 |
| 721 output->clear(); | 714 output->clear(); |
| 722 | 715 |
| 723 PngEncoderState state(output); | 716 PngEncoderState state(output); |
| 724 bool success = DoLibpngWrite(png_ptr, info_ptr, &state, | 717 bool success = DoLibpngWrite(si.png_ptr_, si.info_ptr_, &state, |
| 725 size.width(), size.height(), row_byte_width, | 718 size.width(), size.height(), row_byte_width, |
| 726 input, compression_level, png_output_color_type, | 719 input, compression_level, png_output_color_type, |
| 727 output_color_components, converter, comments); | 720 output_color_components, converter, comments); |
| 728 | 721 |
| 729 return success; | 722 return success; |
| 730 } | 723 } |
| 731 | 724 |
| 732 bool InternalEncodeSkBitmap(const SkBitmap& input, | 725 bool InternalEncodeSkBitmap(const SkBitmap& input, |
| 733 bool discard_transparency, | 726 bool discard_transparency, |
| 734 int compression_level, | 727 int compression_level, |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 804 } | 797 } |
| 805 | 798 |
| 806 PNGCodec::Comment::Comment(const std::string& k, const std::string& t) | 799 PNGCodec::Comment::Comment(const std::string& k, const std::string& t) |
| 807 : key(k), text(t) { | 800 : key(k), text(t) { |
| 808 } | 801 } |
| 809 | 802 |
| 810 PNGCodec::Comment::~Comment() { | 803 PNGCodec::Comment::~Comment() { |
| 811 } | 804 } |
| 812 | 805 |
| 813 } // namespace gfx | 806 } // namespace gfx |
| OLD | NEW |