Chromium Code Reviews| 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 "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
| 9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
| 10 #include "ui/gfx/size.h" | 10 #include "ui/gfx/size.h" |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 87 // This code is based on WebKit libpng interface (PNGImageDecoder), which is | 87 // This code is based on WebKit libpng interface (PNGImageDecoder), which is |
| 88 // in turn based on the Mozilla png decoder. | 88 // in turn based on the Mozilla png decoder. |
| 89 | 89 |
| 90 namespace { | 90 namespace { |
| 91 | 91 |
| 92 // Gamma constants: We assume we're on Windows which uses a gamma of 2.2. | 92 // Gamma constants: We assume we're on Windows which uses a gamma of 2.2. |
| 93 const double kMaxGamma = 21474.83; // Maximum gamma accepted by png library. | 93 const double kMaxGamma = 21474.83; // Maximum gamma accepted by png library. |
| 94 const double kDefaultGamma = 2.2; | 94 const double kDefaultGamma = 2.2; |
| 95 const double kInverseGamma = 1.0 / kDefaultGamma; | 95 const double kInverseGamma = 1.0 / kDefaultGamma; |
| 96 | 96 |
| 97 const png_byte kPngScaleChunk[5] = { 'c', 's', 'C', 'l', 0 }; | |
| 98 | |
| 97 class PngDecoderState { | 99 class PngDecoderState { |
| 98 public: | 100 public: |
| 99 // Output is a vector<unsigned char>. | 101 // Output is a vector<unsigned char>. |
| 100 PngDecoderState(PNGCodec::ColorFormat ofmt, std::vector<unsigned char>* o) | 102 PngDecoderState(PNGCodec::ColorFormat ofmt, std::vector<unsigned char>* o) |
| 101 : output_format(ofmt), | 103 : output_format(ofmt), |
| 102 output_channels(0), | 104 output_channels(0), |
| 103 bitmap(NULL), | 105 bitmap(NULL), |
| 104 is_opaque(true), | 106 is_opaque(true), |
| 105 output(o), | 107 output(o), |
| 106 width(0), | 108 width(0), |
| 107 height(0), | 109 height(0), |
| 110 scale_fallback(false), | |
| 108 done(false) { | 111 done(false) { |
| 109 } | 112 } |
| 110 | 113 |
| 111 // Output is an SkBitmap. | 114 // Output is an SkBitmap. |
| 112 explicit PngDecoderState(SkBitmap* skbitmap) | 115 explicit PngDecoderState(SkBitmap* skbitmap) |
| 113 : output_format(PNGCodec::FORMAT_SkBitmap), | 116 : output_format(PNGCodec::FORMAT_SkBitmap), |
| 114 output_channels(0), | 117 output_channels(0), |
| 115 bitmap(skbitmap), | 118 bitmap(skbitmap), |
| 116 is_opaque(true), | 119 is_opaque(true), |
| 117 output(NULL), | 120 output(NULL), |
| 118 width(0), | 121 width(0), |
| 119 height(0), | 122 height(0), |
| 123 scale_fallback(false), | |
| 120 done(false) { | 124 done(false) { |
| 121 } | 125 } |
| 122 | 126 |
| 123 PNGCodec::ColorFormat output_format; | 127 PNGCodec::ColorFormat output_format; |
| 124 int output_channels; | 128 int output_channels; |
| 125 | 129 |
| 126 // An incoming SkBitmap to write to. If NULL, we write to output instead. | 130 // An incoming SkBitmap to write to. If NULL, we write to output instead. |
| 127 SkBitmap* bitmap; | 131 SkBitmap* bitmap; |
| 128 | 132 |
| 129 // Used during the reading of an SkBitmap. Defaults to true until we see a | 133 // Used during the reading of an SkBitmap. Defaults to true until we see a |
| 130 // pixel with anything other than an alpha of 255. | 134 // pixel with anything other than an alpha of 255. |
| 131 bool is_opaque; | 135 bool is_opaque; |
| 132 | 136 |
| 133 // The other way to decode output, where we write into an intermediary buffer | 137 // The other way to decode output, where we write into an intermediary buffer |
| 134 // instead of directly to an SkBitmap. | 138 // instead of directly to an SkBitmap. |
| 135 std::vector<unsigned char>* output; | 139 std::vector<unsigned char>* output; |
| 136 | 140 |
| 137 // Size of the image, set in the info callback. | 141 // Size of the image, set in the info callback. |
| 138 int width; | 142 int width; |
| 139 int height; | 143 int height; |
| 140 | 144 |
| 145 // True if a csCl chunk is present, indicating that GRIT didn't find an image | |
| 146 // at the proper scale and fell back to 100%. | |
| 147 bool scale_fallback; | |
| 148 | |
| 141 // Set to true when we've found the end of the data. | 149 // Set to true when we've found the end of the data. |
| 142 bool done; | 150 bool done; |
| 143 | 151 |
| 144 private: | 152 private: |
| 145 DISALLOW_COPY_AND_ASSIGN(PngDecoderState); | 153 DISALLOW_COPY_AND_ASSIGN(PngDecoderState); |
| 146 }; | 154 }; |
| 147 | 155 |
| 148 // User transform (passed to libpng) which converts a row decoded by libpng to | 156 // User transform (passed to libpng) which converts a row decoded by libpng to |
| 149 // Skia format. Expects the row to have 4 channels, otherwise there won't be | 157 // Skia format. Expects the row to have 4 channels, otherwise there won't be |
| 150 // enough room in |data|. | 158 // enough room in |data|. |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 323 | 331 |
| 324 void DecodeEndCallback(png_struct* png_ptr, png_info* info) { | 332 void DecodeEndCallback(png_struct* png_ptr, png_info* info) { |
| 325 PngDecoderState* state = static_cast<PngDecoderState*>( | 333 PngDecoderState* state = static_cast<PngDecoderState*>( |
| 326 png_get_progressive_ptr(png_ptr)); | 334 png_get_progressive_ptr(png_ptr)); |
| 327 | 335 |
| 328 // Mark the image as complete, this will tell the Decode function that we | 336 // Mark the image as complete, this will tell the Decode function that we |
| 329 // have successfully found the end of the data. | 337 // have successfully found the end of the data. |
| 330 state->done = true; | 338 state->done = true; |
| 331 } | 339 } |
| 332 | 340 |
| 341 int DecodeUserChunkCallback(png_struct* png_ptr, png_unknown_chunk* chunk) { | |
| 342 PngDecoderState* state = static_cast<PngDecoderState*>( | |
| 343 png_get_user_chunk_ptr(png_ptr)); | |
| 344 DCHECK(memcmp(chunk->name, kPngScaleChunk, 5) == 0); // guaranteed by libpng | |
|
sail
2012/10/09 22:01:37
sentence fragment
benrg
2012/10/10 02:18:13
Done.
| |
| 345 if (chunk->size == 0) { | |
| 346 state->scale_fallback = true; | |
| 347 return 1; // processed | |
| 348 } | |
| 349 return 0; // unrecognized | |
| 350 } | |
| 351 | |
| 333 // Automatically destroys the given read structs on destruction to make | 352 // Automatically destroys the given read structs on destruction to make |
| 334 // cleanup and error handling code cleaner. | 353 // cleanup and error handling code cleaner. |
| 335 class PngReadStructDestroyer { | 354 class PngReadStructDestroyer { |
| 336 public: | 355 public: |
| 337 PngReadStructDestroyer(png_struct** ps, png_info** pi) : ps_(ps), pi_(pi) { | 356 PngReadStructDestroyer(png_struct** ps, png_info** pi) : ps_(ps), pi_(pi) { |
| 338 } | 357 } |
| 339 ~PngReadStructDestroyer() { | 358 ~PngReadStructDestroyer() { |
| 340 png_destroy_read_struct(ps_, pi_, NULL); | 359 png_destroy_read_struct(ps_, pi_, NULL); |
| 341 } | 360 } |
| 342 private: | 361 private: |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 399 | 418 |
| 400 void LogLibPNGEncodeError(png_structp png_ptr, png_const_charp error_msg) { | 419 void LogLibPNGEncodeError(png_structp png_ptr, png_const_charp error_msg) { |
| 401 DLOG(ERROR) << "libpng encode error: " << error_msg; | 420 DLOG(ERROR) << "libpng encode error: " << error_msg; |
| 402 longjmp(png_jmpbuf(png_ptr), 1); | 421 longjmp(png_jmpbuf(png_ptr), 1); |
| 403 } | 422 } |
| 404 | 423 |
| 405 void LogLibPNGEncodeWarning(png_structp png_ptr, png_const_charp warning_msg) { | 424 void LogLibPNGEncodeWarning(png_structp png_ptr, png_const_charp warning_msg) { |
| 406 DLOG(ERROR) << "libpng encode warning: " << warning_msg; | 425 DLOG(ERROR) << "libpng encode warning: " << warning_msg; |
| 407 } | 426 } |
| 408 | 427 |
| 409 } // namespace | 428 bool DecodeInternal(const unsigned char* input, size_t input_size, |
| 410 | 429 PngDecoderState* state) { |
| 411 // static | |
| 412 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, | |
| 413 ColorFormat format, std::vector<unsigned char>* output, | |
| 414 int* w, int* h) { | |
| 415 png_struct* png_ptr = NULL; | 430 png_struct* png_ptr = NULL; |
| 416 png_info* info_ptr = NULL; | 431 png_info* info_ptr = NULL; |
| 417 if (!BuildPNGStruct(input, input_size, &png_ptr, &info_ptr)) | 432 if (!BuildPNGStruct(input, input_size, &png_ptr, &info_ptr)) |
| 418 return false; | 433 return false; |
| 419 | 434 |
| 420 PngReadStructDestroyer destroyer(&png_ptr, &info_ptr); | 435 PngReadStructDestroyer destroyer(&png_ptr, &info_ptr); |
| 421 if (setjmp(png_jmpbuf(png_ptr))) { | 436 if (setjmp(png_jmpbuf(png_ptr))) { |
| 422 // 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 |
| 423 // 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 |
| 424 // PNG library called below. | 439 // PNG library called below. |
| 425 return false; | 440 return false; |
| 426 } | 441 } |
| 427 | 442 |
| 443 png_set_error_fn(png_ptr, NULL, LogLibPNGDecodeError, LogLibPNGDecodeWarning); | |
| 444 png_set_progressive_read_fn(png_ptr, state, DecodeInfoCallback, | |
| 445 DecodeRowCallback, DecodeEndCallback); | |
| 446 png_set_keep_unknown_chunks(png_ptr, 3, const_cast<png_byte*>(kPngScaleChunk), | |
| 447 1); // keep only csCl | |
| 448 png_set_read_user_chunk_fn(png_ptr, state, DecodeUserChunkCallback); | |
| 449 png_process_data(png_ptr, info_ptr, | |
| 450 const_cast<unsigned char*>(input), input_size); | |
| 451 return state->done; | |
| 452 } | |
| 453 | |
| 454 } // namespace | |
| 455 | |
| 456 | |
| 457 // static | |
| 458 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, | |
| 459 ColorFormat format, std::vector<unsigned char>* output, | |
| 460 int* w, int* h) { | |
| 428 PngDecoderState state(format, output); | 461 PngDecoderState state(format, output); |
| 429 | 462 if (!DecodeInternal(input, input_size, &state)) { |
| 430 png_set_error_fn(png_ptr, NULL, LogLibPNGDecodeError, LogLibPNGDecodeWarning); | |
| 431 png_set_progressive_read_fn(png_ptr, &state, &DecodeInfoCallback, | |
| 432 &DecodeRowCallback, &DecodeEndCallback); | |
| 433 png_process_data(png_ptr, | |
| 434 info_ptr, | |
| 435 const_cast<unsigned char*>(input), | |
| 436 input_size); | |
| 437 | |
| 438 if (!state.done) { | |
| 439 // Fed it all the data but the library didn't think we got all the data, so | |
| 440 // this file must be truncated. | |
| 441 output->clear(); | 463 output->clear(); |
| 442 return false; | 464 return false; |
| 443 } | 465 } |
| 444 | |
| 445 *w = state.width; | 466 *w = state.width; |
| 446 *h = state.height; | 467 *h = state.height; |
| 447 return true; | 468 return true; |
| 448 } | 469 } |
| 449 | 470 |
| 450 // static | 471 // static |
| 451 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, | 472 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, |
| 473 SkBitmap* bitmap, bool* scale_fallback) { | |
| 474 DCHECK(bitmap); | |
| 475 PngDecoderState state(bitmap); | |
| 476 if (!DecodeInternal(input, input_size, &state)) | |
| 477 return false; | |
| 478 bitmap->setIsOpaque(state.is_opaque); | |
| 479 if (scale_fallback) | |
| 480 *scale_fallback = state.scale_fallback; | |
| 481 return true; | |
| 482 } | |
| 483 | |
| 484 // static | |
| 485 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, | |
| 452 SkBitmap* bitmap) { | 486 SkBitmap* bitmap) { |
| 453 DCHECK(bitmap); | 487 return Decode(input, input_size, bitmap, NULL); |
| 454 png_struct* png_ptr = NULL; | |
| 455 png_info* info_ptr = NULL; | |
| 456 if (!BuildPNGStruct(input, input_size, &png_ptr, &info_ptr)) | |
| 457 return false; | |
| 458 | |
| 459 PngReadStructDestroyer destroyer(&png_ptr, &info_ptr); | |
| 460 if (setjmp(png_jmpbuf(png_ptr))) { | |
| 461 // The destroyer will ensure that the structures are cleaned up in this | |
| 462 // case, even though we may get here as a jump from random parts of the | |
| 463 // PNG library called below. | |
| 464 return false; | |
| 465 } | |
| 466 | |
| 467 PngDecoderState state(bitmap); | |
| 468 | |
| 469 png_set_progressive_read_fn(png_ptr, &state, &DecodeInfoCallback, | |
| 470 &DecodeRowCallback, &DecodeEndCallback); | |
| 471 png_process_data(png_ptr, | |
| 472 info_ptr, | |
| 473 const_cast<unsigned char*>(input), | |
| 474 input_size); | |
| 475 | |
| 476 if (!state.done) { | |
| 477 return false; | |
| 478 } | |
| 479 | |
| 480 // Set the bitmap's opaqueness based on what we saw. | |
| 481 bitmap->setIsOpaque(state.is_opaque); | |
| 482 | |
| 483 return true; | |
| 484 } | 488 } |
| 485 | 489 |
| 486 // static | 490 // static |
| 487 SkBitmap* PNGCodec::CreateSkBitmapFromBGRAFormat( | 491 SkBitmap* PNGCodec::CreateSkBitmapFromBGRAFormat( |
| 488 std::vector<unsigned char>& bgra, int width, int height) { | 492 std::vector<unsigned char>& bgra, int width, int height) { |
| 489 SkBitmap* bitmap = new SkBitmap(); | 493 SkBitmap* bitmap = new SkBitmap(); |
| 490 bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); | 494 bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); |
| 491 bitmap->allocPixels(); | 495 bitmap->allocPixels(); |
| 492 | 496 |
| 493 bool opaque = false; | 497 bool opaque = false; |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 783 } | 787 } |
| 784 | 788 |
| 785 PNGCodec::Comment::Comment(const std::string& k, const std::string& t) | 789 PNGCodec::Comment::Comment(const std::string& k, const std::string& t) |
| 786 : key(k), text(t) { | 790 : key(k), text(t) { |
| 787 } | 791 } |
| 788 | 792 |
| 789 PNGCodec::Comment::~Comment() { | 793 PNGCodec::Comment::~Comment() { |
| 790 } | 794 } |
| 791 | 795 |
| 792 } // namespace gfx | 796 } // namespace gfx |
| OLD | NEW |