Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(114)

Side by Side Diff: ui/gfx/codec/png_codec.cc

Issue 11028064: Resize images for hi-dpi based on a custom PNG chunk added by GRIT r78, and roll GRIT r78 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: comments Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698