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 percent(-1), | |
| 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 percent(-1), | |
| 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 // Image percentage scale (normally 100) from the csCl chunk. | |
| 146 int percent; | |
| 147 | |
| 141 // Set to true when we've found the end of the data. | 148 // Set to true when we've found the end of the data. |
| 142 bool done; | 149 bool done; |
| 143 | 150 |
| 144 private: | 151 private: |
| 145 DISALLOW_COPY_AND_ASSIGN(PngDecoderState); | 152 DISALLOW_COPY_AND_ASSIGN(PngDecoderState); |
| 146 }; | 153 }; |
| 147 | 154 |
| 148 // User transform (passed to libpng) which converts a row decoded by libpng to | 155 // 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 | 156 // Skia format. Expects the row to have 4 channels, otherwise there won't be |
| 150 // enough room in |data|. | 157 // enough room in |data|. |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 323 | 330 |
| 324 void DecodeEndCallback(png_struct* png_ptr, png_info* info) { | 331 void DecodeEndCallback(png_struct* png_ptr, png_info* info) { |
| 325 PngDecoderState* state = static_cast<PngDecoderState*>( | 332 PngDecoderState* state = static_cast<PngDecoderState*>( |
| 326 png_get_progressive_ptr(png_ptr)); | 333 png_get_progressive_ptr(png_ptr)); |
| 327 | 334 |
| 328 // Mark the image as complete, this will tell the Decode function that we | 335 // Mark the image as complete, this will tell the Decode function that we |
| 329 // have successfully found the end of the data. | 336 // have successfully found the end of the data. |
| 330 state->done = true; | 337 state->done = true; |
| 331 } | 338 } |
| 332 | 339 |
| 340 int DecodeUserChunkCallback(png_struct* png_ptr, png_unknown_chunk* chunk) { | |
| 341 PngDecoderState* state = static_cast<PngDecoderState*>( | |
| 342 png_get_user_chunk_ptr(png_ptr)); | |
| 343 DCHECK(memcmp(chunk->name, kPngScaleChunk, 5) == 0); // guaranteed by libpng | |
| 344 if (chunk->size == 2) { | |
| 345 state->percent = chunk->data[0] * 0x100 + chunk->data[1]; | |
| 346 return 1; // processed | |
| 347 } else { | |
| 348 return 0; // unrecognized | |
| 349 } | |
| 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); | |
|
benrg
2012/10/05 18:21:41
This call wasn't in the 4-argument version of PNGC
| |
| 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); |
| 462 bool ok = DecodeInternal(input, input_size, &state); | |
| 463 if (ok) { | |
|
oshima
2012/10/05 20:33:11
I think
if (Decode...) {
return true;
}
...
ret
| |
| 464 *w = state.width; | |
| 465 *h = state.height; | |
| 466 } else { | |
| 467 output->clear(); | |
|
benrg
2012/10/05 18:21:41
Before the refactoring the output was cleared only
| |
| 468 } | |
| 469 return ok; | |
| 470 } | |
| 429 | 471 |
| 430 png_set_error_fn(png_ptr, NULL, LogLibPNGDecodeError, LogLibPNGDecodeWarning); | 472 // static |
| 431 png_set_progressive_read_fn(png_ptr, &state, &DecodeInfoCallback, | 473 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, |
| 432 &DecodeRowCallback, &DecodeEndCallback); | 474 SkBitmap* bitmap, int* percent) { |
| 433 png_process_data(png_ptr, | 475 DCHECK(bitmap); |
| 434 info_ptr, | 476 PngDecoderState state(bitmap); |
| 435 const_cast<unsigned char*>(input), | 477 bool ok = DecodeInternal(input, input_size, &state); |
|
oshima
2012/10/05 20:33:11
ditto.
| |
| 436 input_size); | 478 if (ok) { |
| 437 | 479 bitmap->setIsOpaque(state.is_opaque); |
| 438 if (!state.done) { | 480 if (percent) |
| 439 // Fed it all the data but the library didn't think we got all the data, so | 481 *percent = state.percent; |
| 440 // this file must be truncated. | |
| 441 output->clear(); | |
| 442 return false; | |
| 443 } | 482 } |
| 444 | 483 return ok; |
| 445 *w = state.width; | |
| 446 *h = state.height; | |
| 447 return true; | |
| 448 } | 484 } |
| 449 | 485 |
| 450 // static | 486 // static |
| 451 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, | 487 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, |
| 452 SkBitmap* bitmap) { | 488 SkBitmap* bitmap) { |
| 453 DCHECK(bitmap); | 489 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 } | 490 } |
| 485 | 491 |
| 486 // static | 492 // static |
| 487 SkBitmap* PNGCodec::CreateSkBitmapFromBGRAFormat( | 493 SkBitmap* PNGCodec::CreateSkBitmapFromBGRAFormat( |
| 488 std::vector<unsigned char>& bgra, int width, int height) { | 494 std::vector<unsigned char>& bgra, int width, int height) { |
| 489 SkBitmap* bitmap = new SkBitmap(); | 495 SkBitmap* bitmap = new SkBitmap(); |
| 490 bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); | 496 bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); |
| 491 bitmap->allocPixels(); | 497 bitmap->allocPixels(); |
| 492 | 498 |
| 493 bool opaque = false; | 499 bool opaque = false; |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 783 } | 789 } |
| 784 | 790 |
| 785 PNGCodec::Comment::Comment(const std::string& k, const std::string& t) | 791 PNGCodec::Comment::Comment(const std::string& k, const std::string& t) |
| 786 : key(k), text(t) { | 792 : key(k), text(t) { |
| 787 } | 793 } |
| 788 | 794 |
| 789 PNGCodec::Comment::~Comment() { | 795 PNGCodec::Comment::~Comment() { |
| 790 } | 796 } |
| 791 | 797 |
| 792 } // namespace gfx | 798 } // namespace gfx |
| OLD | NEW |