| 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 fell_back_to_1x(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 fell_back_to_1x(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 fell_back_to_1x; |
| 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 // We instructed libpng to call us only for csCl chunks. |
| 345 DCHECK(memcmp(chunk->name, kPngScaleChunk, 5) == 0); |
| 346 if (chunk->size == 0) { |
| 347 state->fell_back_to_1x = true; |
| 348 return 1; // processed |
| 349 } |
| 350 return 0; // unrecognized |
| 351 } |
| 352 |
| 333 // Automatically destroys the given read structs on destruction to make | 353 // Automatically destroys the given read structs on destruction to make |
| 334 // cleanup and error handling code cleaner. | 354 // cleanup and error handling code cleaner. |
| 335 class PngReadStructDestroyer { | 355 class PngReadStructDestroyer { |
| 336 public: | 356 public: |
| 337 PngReadStructDestroyer(png_struct** ps, png_info** pi) : ps_(ps), pi_(pi) { | 357 PngReadStructDestroyer(png_struct** ps, png_info** pi) : ps_(ps), pi_(pi) { |
| 338 } | 358 } |
| 339 ~PngReadStructDestroyer() { | 359 ~PngReadStructDestroyer() { |
| 340 png_destroy_read_struct(ps_, pi_, NULL); | 360 png_destroy_read_struct(ps_, pi_, NULL); |
| 341 } | 361 } |
| 342 private: | 362 private: |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 399 | 419 |
| 400 void LogLibPNGEncodeError(png_structp png_ptr, png_const_charp error_msg) { | 420 void LogLibPNGEncodeError(png_structp png_ptr, png_const_charp error_msg) { |
| 401 DLOG(ERROR) << "libpng encode error: " << error_msg; | 421 DLOG(ERROR) << "libpng encode error: " << error_msg; |
| 402 longjmp(png_jmpbuf(png_ptr), 1); | 422 longjmp(png_jmpbuf(png_ptr), 1); |
| 403 } | 423 } |
| 404 | 424 |
| 405 void LogLibPNGEncodeWarning(png_structp png_ptr, png_const_charp warning_msg) { | 425 void LogLibPNGEncodeWarning(png_structp png_ptr, png_const_charp warning_msg) { |
| 406 DLOG(ERROR) << "libpng encode warning: " << warning_msg; | 426 DLOG(ERROR) << "libpng encode warning: " << warning_msg; |
| 407 } | 427 } |
| 408 | 428 |
| 409 } // namespace | 429 bool DecodeInternal(const unsigned char* input, size_t input_size, |
| 410 | 430 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; | 431 png_struct* png_ptr = NULL; |
| 416 png_info* info_ptr = NULL; | 432 png_info* info_ptr = NULL; |
| 417 if (!BuildPNGStruct(input, input_size, &png_ptr, &info_ptr)) | 433 if (!BuildPNGStruct(input, input_size, &png_ptr, &info_ptr)) |
| 418 return false; | 434 return false; |
| 419 | 435 |
| 420 PngReadStructDestroyer destroyer(&png_ptr, &info_ptr); | 436 PngReadStructDestroyer destroyer(&png_ptr, &info_ptr); |
| 421 if (setjmp(png_jmpbuf(png_ptr))) { | 437 if (setjmp(png_jmpbuf(png_ptr))) { |
| 422 // The destroyer will ensure that the structures are cleaned up in this | 438 // 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 | 439 // case, even though we may get here as a jump from random parts of the |
| 424 // PNG library called below. | 440 // PNG library called below. |
| 425 return false; | 441 return false; |
| 426 } | 442 } |
| 427 | 443 |
| 444 png_set_error_fn(png_ptr, NULL, LogLibPNGDecodeError, LogLibPNGDecodeWarning); |
| 445 png_set_progressive_read_fn(png_ptr, state, DecodeInfoCallback, |
| 446 DecodeRowCallback, DecodeEndCallback); |
| 447 png_set_keep_unknown_chunks(png_ptr, 3, const_cast<png_byte*>(kPngScaleChunk), |
| 448 1); // keep only csCl |
| 449 png_set_read_user_chunk_fn(png_ptr, state, DecodeUserChunkCallback); |
| 450 png_process_data(png_ptr, info_ptr, |
| 451 const_cast<unsigned char*>(input), input_size); |
| 452 return state->done; |
| 453 } |
| 454 |
| 455 } // namespace |
| 456 |
| 457 |
| 458 // static |
| 459 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, |
| 460 ColorFormat format, std::vector<unsigned char>* output, |
| 461 int* w, int* h) { |
| 428 PngDecoderState state(format, output); | 462 PngDecoderState state(format, output); |
| 429 | 463 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(); | 464 output->clear(); |
| 442 return false; | 465 return false; |
| 443 } | 466 } |
| 444 | |
| 445 *w = state.width; | 467 *w = state.width; |
| 446 *h = state.height; | 468 *h = state.height; |
| 447 return true; | 469 return true; |
| 448 } | 470 } |
| 449 | 471 |
| 450 // static | 472 // static |
| 451 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, | 473 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, |
| 474 SkBitmap* bitmap, bool* fell_back_to_1x) { |
| 475 DCHECK(bitmap); |
| 476 PngDecoderState state(bitmap); |
| 477 if (!DecodeInternal(input, input_size, &state)) |
| 478 return false; |
| 479 bitmap->setIsOpaque(state.is_opaque); |
| 480 if (fell_back_to_1x) |
| 481 *fell_back_to_1x = state.fell_back_to_1x; |
| 482 return true; |
| 483 } |
| 484 |
| 485 // static |
| 486 bool PNGCodec::Decode(const unsigned char* input, size_t input_size, |
| 452 SkBitmap* bitmap) { | 487 SkBitmap* bitmap) { |
| 453 DCHECK(bitmap); | 488 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 } | 489 } |
| 485 | 490 |
| 486 // static | 491 // static |
| 487 SkBitmap* PNGCodec::CreateSkBitmapFromBGRAFormat( | 492 SkBitmap* PNGCodec::CreateSkBitmapFromBGRAFormat( |
| 488 std::vector<unsigned char>& bgra, int width, int height) { | 493 std::vector<unsigned char>& bgra, int width, int height) { |
| 489 SkBitmap* bitmap = new SkBitmap(); | 494 SkBitmap* bitmap = new SkBitmap(); |
| 490 bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); | 495 bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); |
| 491 bitmap->allocPixels(); | 496 bitmap->allocPixels(); |
| 492 | 497 |
| 493 bool opaque = false; | 498 bool opaque = false; |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 783 } | 788 } |
| 784 | 789 |
| 785 PNGCodec::Comment::Comment(const std::string& k, const std::string& t) | 790 PNGCodec::Comment::Comment(const std::string& k, const std::string& t) |
| 786 : key(k), text(t) { | 791 : key(k), text(t) { |
| 787 } | 792 } |
| 788 | 793 |
| 789 PNGCodec::Comment::~Comment() { | 794 PNGCodec::Comment::~Comment() { |
| 790 } | 795 } |
| 791 | 796 |
| 792 } // namespace gfx | 797 } // namespace gfx |
| OLD | NEW |