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

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: . 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 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
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
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
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
OLDNEW
« ui/base/resource/resource_bundle.cc ('K') | « ui/gfx/codec/png_codec.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698