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 |
| 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 |