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 |