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 |