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

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

Issue 243076: Move the JPEG and PNG codecs from base/gfx to app/gfx/codec. Move the classes... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 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
Property Changes:
Added: svn:mergeinfo
Merged /branches/chrome_webkit_merge_branch/base/gfx/png_decoder.cc:r69-2775
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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 "base/gfx/png_decoder.h" 5 #include "app/gfx/codec/png_codec.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/scoped_ptr.h"
8 #include "third_party/skia/include/core/SkBitmap.h" 9 #include "third_party/skia/include/core/SkBitmap.h"
10 #include "third_party/skia/include/core/SkUnPreMultiply.h"
9 11
10 extern "C" { 12 extern "C" {
11 #if defined(USE_SYSTEM_LIBPNG) 13 #if defined(USE_SYSTEM_LIBPNG)
12 #include <png.h> 14 #include <png.h>
13 #else 15 #else
14 #include "third_party/libpng/png.h" 16 #include "third_party/libpng/png.h"
15 #endif 17 #endif
16 } 18 }
17 19
20 namespace gfx {
21
18 namespace { 22 namespace {
19 23
20 // Converts BGRA->RGBA and RGBA->BGRA. 24 // Converts BGRA->RGBA and RGBA->BGRA.
21 void ConvertBetweenBGRAandRGBA(const unsigned char* input, int pixel_width, 25 void ConvertBetweenBGRAandRGBA(const unsigned char* input, int pixel_width,
22 unsigned char* output) { 26 unsigned char* output) {
23 for (int x = 0; x < pixel_width; x++) { 27 for (int x = 0; x < pixel_width; x++) {
24 const unsigned char* pixel_in = &input[x * 4]; 28 const unsigned char* pixel_in = &input[x * 4];
25 unsigned char* pixel_out = &output[x * 4]; 29 unsigned char* pixel_out = &output[x * 4];
26 pixel_out[0] = pixel_in[2]; 30 pixel_out[0] = pixel_in[2];
27 pixel_out[1] = pixel_in[1]; 31 pixel_out[1] = pixel_in[1];
(...skipping 22 matching lines...) Expand all
50 54
51 namespace { 55 namespace {
52 56
53 // Gamma constants: We assume we're on Windows which uses a gamma of 2.2. 57 // Gamma constants: We assume we're on Windows which uses a gamma of 2.2.
54 const double kMaxGamma = 21474.83; // Maximum gamma accepted by png library. 58 const double kMaxGamma = 21474.83; // Maximum gamma accepted by png library.
55 const double kDefaultGamma = 2.2; 59 const double kDefaultGamma = 2.2;
56 const double kInverseGamma = 1.0 / kDefaultGamma; 60 const double kInverseGamma = 1.0 / kDefaultGamma;
57 61
58 class PngDecoderState { 62 class PngDecoderState {
59 public: 63 public:
60 PngDecoderState(PNGDecoder::ColorFormat ofmt, std::vector<unsigned char>* o) 64 PngDecoderState(PNGCodec::ColorFormat ofmt, std::vector<unsigned char>* o)
61 : output_format(ofmt), 65 : output_format(ofmt),
62 output_channels(0), 66 output_channels(0),
63 output(o), 67 output(o),
64 row_converter(NULL), 68 row_converter(NULL),
65 width(0), 69 width(0),
66 height(0), 70 height(0),
67 done(false) { 71 done(false) {
68 } 72 }
69 73
70 PNGDecoder::ColorFormat output_format; 74 PNGCodec::ColorFormat output_format;
71 int output_channels; 75 int output_channels;
72 76
73 std::vector<unsigned char>* output; 77 std::vector<unsigned char>* output;
74 78
75 // Called to convert a row from the library to the correct output format. 79 // Called to convert a row from the library to the correct output format.
76 // When NULL, no conversion is necessary. 80 // When NULL, no conversion is necessary.
77 void (*row_converter)(const unsigned char* in, int w, unsigned char* out); 81 void (*row_converter)(const unsigned char* in, int w, unsigned char* out);
78 82
79 // Size of the image, set in the info callback. 83 // Size of the image, set in the info callback.
80 int width; 84 int width;
81 int height; 85 int height;
82 86
83 // Set to true when we've found the end of the data. 87 // Set to true when we've found the end of the data.
84 bool done; 88 bool done;
85 89
86 private: 90 private:
87 DISALLOW_EVIL_CONSTRUCTORS(PngDecoderState); 91 DISALLOW_COPY_AND_ASSIGN(PngDecoderState);
88 }; 92 };
89 93
90 void ConvertRGBtoRGBA(const unsigned char* rgb, int pixel_width, 94 void ConvertRGBtoRGBA(const unsigned char* rgb, int pixel_width,
91 unsigned char* rgba) { 95 unsigned char* rgba) {
92 for (int x = 0; x < pixel_width; x++) { 96 for (int x = 0; x < pixel_width; x++) {
93 const unsigned char* pixel_in = &rgb[x * 3]; 97 const unsigned char* pixel_in = &rgb[x * 3];
94 unsigned char* pixel_out = &rgba[x * 4]; 98 unsigned char* pixel_out = &rgba[x * 4];
95 pixel_out[0] = pixel_in[0]; 99 pixel_out[0] = pixel_in[0];
96 pixel_out[1] = pixel_in[1]; 100 pixel_out[1] = pixel_in[1];
97 pixel_out[2] = pixel_in[2]; 101 pixel_out[2] = pixel_in[2];
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 if (interlace_type == PNG_INTERLACE_ADAM7) 173 if (interlace_type == PNG_INTERLACE_ADAM7)
170 png_set_interlace_handling(png_ptr); 174 png_set_interlace_handling(png_ptr);
171 175
172 // Update our info now 176 // Update our info now
173 png_read_update_info(png_ptr, info_ptr); 177 png_read_update_info(png_ptr, info_ptr);
174 channels = png_get_channels(png_ptr, info_ptr); 178 channels = png_get_channels(png_ptr, info_ptr);
175 179
176 // Pick our row format converter necessary for this data. 180 // Pick our row format converter necessary for this data.
177 if (channels == 3) { 181 if (channels == 3) {
178 switch (state->output_format) { 182 switch (state->output_format) {
179 case PNGDecoder::FORMAT_RGB: 183 case PNGCodec::FORMAT_RGB:
180 state->row_converter = NULL; // no conversion necessary 184 state->row_converter = NULL; // no conversion necessary
181 state->output_channels = 3; 185 state->output_channels = 3;
182 break; 186 break;
183 case PNGDecoder::FORMAT_RGBA: 187 case PNGCodec::FORMAT_RGBA:
184 state->row_converter = &ConvertRGBtoRGBA; 188 state->row_converter = &ConvertRGBtoRGBA;
185 state->output_channels = 4; 189 state->output_channels = 4;
186 break; 190 break;
187 case PNGDecoder::FORMAT_BGRA: 191 case PNGCodec::FORMAT_BGRA:
188 state->row_converter = &ConvertRGBtoBGRA; 192 state->row_converter = &ConvertRGBtoBGRA;
189 state->output_channels = 4; 193 state->output_channels = 4;
190 break; 194 break;
191 default: 195 default:
192 NOTREACHED() << "Unknown output format"; 196 NOTREACHED() << "Unknown output format";
193 break; 197 break;
194 } 198 }
195 } else if (channels == 4) { 199 } else if (channels == 4) {
196 switch (state->output_format) { 200 switch (state->output_format) {
197 case PNGDecoder::FORMAT_RGB: 201 case PNGCodec::FORMAT_RGB:
198 state->row_converter = &ConvertRGBAtoRGB; 202 state->row_converter = &ConvertRGBAtoRGB;
199 state->output_channels = 3; 203 state->output_channels = 3;
200 break; 204 break;
201 case PNGDecoder::FORMAT_RGBA: 205 case PNGCodec::FORMAT_RGBA:
202 state->row_converter = NULL; // no conversion necessary 206 state->row_converter = NULL; // no conversion necessary
203 state->output_channels = 4; 207 state->output_channels = 4;
204 break; 208 break;
205 case PNGDecoder::FORMAT_BGRA: 209 case PNGCodec::FORMAT_BGRA:
206 state->row_converter = &ConvertBetweenBGRAandRGBA; 210 state->row_converter = &ConvertBetweenBGRAandRGBA;
207 state->output_channels = 4; 211 state->output_channels = 4;
208 break; 212 break;
209 default: 213 default:
210 NOTREACHED() << "Unknown output format"; 214 NOTREACHED() << "Unknown output format";
211 break; 215 break;
212 } 216 }
213 } else { 217 } else {
214 NOTREACHED() << "Unknown input channels"; 218 NOTREACHED() << "Unknown input channels";
215 longjmp(png_ptr->jmpbuf, 1); 219 longjmp(png_ptr->jmpbuf, 1);
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 png_destroy_read_struct(ps_, pi_, NULL); 261 png_destroy_read_struct(ps_, pi_, NULL);
258 } 262 }
259 private: 263 private:
260 png_struct** ps_; 264 png_struct** ps_;
261 png_info** pi_; 265 png_info** pi_;
262 }; 266 };
263 267
264 } // namespace 268 } // namespace
265 269
266 // static 270 // static
267 bool PNGDecoder::Decode(const unsigned char* input, size_t input_size, 271 bool PNGCodec::Decode(const unsigned char* input, size_t input_size,
268 ColorFormat format, std::vector<unsigned char>* output, 272 ColorFormat format, std::vector<unsigned char>* output,
269 int* w, int* h) { 273 int* w, int* h) {
270 if (input_size < 8) 274 if (input_size < 8)
271 return false; // Input data too small to be a png 275 return false; // Input data too small to be a png
272 276
273 // Have libpng check the signature, it likes the first 8 bytes. 277 // Have libpng check the signature, it likes the first 8 bytes.
274 if (png_sig_cmp(const_cast<unsigned char*>(input), 0, 8) != 0) 278 if (png_sig_cmp(const_cast<unsigned char*>(input), 0, 8) != 0)
275 return false; 279 return false;
276 280
277 png_struct* png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 281 png_struct* png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
278 png_voidp_NULL, 282 png_voidp_NULL,
279 png_error_ptr_NULL, 283 png_error_ptr_NULL,
(...skipping 30 matching lines...) Expand all
310 output->clear(); 314 output->clear();
311 return false; 315 return false;
312 } 316 }
313 317
314 *w = state.width; 318 *w = state.width;
315 *h = state.height; 319 *h = state.height;
316 return true; 320 return true;
317 } 321 }
318 322
319 // static 323 // static
320 bool PNGDecoder::Decode(const std::vector<unsigned char>* data, 324 bool PNGCodec::Decode(const std::vector<unsigned char>* data,
321 SkBitmap* bitmap) { 325 SkBitmap* bitmap) {
322 DCHECK(bitmap); 326 DCHECK(bitmap);
323 if (!data || data->empty()) 327 if (!data || data->empty())
324 return false; 328 return false;
325 int width, height; 329 int width, height;
326 std::vector<unsigned char> decoded_data; 330 std::vector<unsigned char> decoded_data;
327 if (PNGDecoder::Decode(&data->front(), data->size(), PNGDecoder::FORMAT_BGRA, 331 if (PNGCodec::Decode(&data->front(), data->size(), PNGCodec::FORMAT_BGRA,
328 &decoded_data, &width, &height)) { 332 &decoded_data, &width, &height)) {
329 bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); 333 bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height);
330 bitmap->allocPixels(); 334 bitmap->allocPixels();
331 unsigned char* bitmap_data = 335 unsigned char* bitmap_data =
332 reinterpret_cast<unsigned char*>(bitmap->getAddr32(0, 0)); 336 reinterpret_cast<unsigned char*>(bitmap->getAddr32(0, 0));
333 for (int i = width * height * 4 - 4; i >= 0; i -= 4) { 337 for (int i = width * height * 4 - 4; i >= 0; i -= 4) {
334 unsigned char alpha = decoded_data[i + 3]; 338 unsigned char alpha = decoded_data[i + 3];
335 if (alpha != 0 && alpha != 255) { 339 if (alpha != 0 && alpha != 255) {
336 SkColor premultiplied = SkPreMultiplyARGB(alpha, 340 SkColor premultiplied = SkPreMultiplyARGB(alpha,
337 decoded_data[i], decoded_data[i + 1], decoded_data[i + 2]); 341 decoded_data[i], decoded_data[i + 1], decoded_data[i + 2]);
338 bitmap_data[i + 3] = alpha; 342 bitmap_data[i + 3] = alpha;
339 bitmap_data[i] = SkColorGetR(premultiplied); 343 bitmap_data[i] = SkColorGetR(premultiplied);
340 bitmap_data[i + 1] = SkColorGetG(premultiplied); 344 bitmap_data[i + 1] = SkColorGetG(premultiplied);
341 bitmap_data[i + 2] = SkColorGetB(premultiplied); 345 bitmap_data[i + 2] = SkColorGetB(premultiplied);
342 } else { 346 } else {
343 bitmap_data[i + 3] = alpha; 347 bitmap_data[i + 3] = alpha;
344 bitmap_data[i] = decoded_data[i]; 348 bitmap_data[i] = decoded_data[i];
345 bitmap_data[i + 1] = decoded_data[i + 1]; 349 bitmap_data[i + 1] = decoded_data[i + 1];
346 bitmap_data[i + 2] = decoded_data[i + 2]; 350 bitmap_data[i + 2] = decoded_data[i + 2];
347 } 351 }
348 } 352 }
349 return true; 353 return true;
350 } 354 }
351 return false; 355 return false;
352 } 356 }
353 357
354 //static 358 // static
355 SkBitmap* PNGDecoder::CreateSkBitmapFromBGRAFormat( 359 SkBitmap* PNGCodec::CreateSkBitmapFromBGRAFormat(
356 std::vector<unsigned char>& bgra, int width, int height) { 360 std::vector<unsigned char>& bgra, int width, int height) {
357 SkBitmap* bitmap = new SkBitmap(); 361 SkBitmap* bitmap = new SkBitmap();
358 bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); 362 bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height);
359 bitmap->allocPixels(); 363 bitmap->allocPixels();
360 364
361 bool opaque = false; 365 bool opaque = false;
362 unsigned char* bitmap_data = 366 unsigned char* bitmap_data =
363 reinterpret_cast<unsigned char*>(bitmap->getAddr32(0, 0)); 367 reinterpret_cast<unsigned char*>(bitmap->getAddr32(0, 0));
364 for (int i = width * height * 4 - 4; i >= 0; i -= 4) { 368 for (int i = width * height * 4 - 4; i >= 0; i -= 4) {
365 unsigned char alpha = bgra[i + 3]; 369 unsigned char alpha = bgra[i + 3];
366 if (!opaque && alpha != 255) { 370 if (!opaque && alpha != 255) {
367 opaque = false; 371 opaque = false;
368 } 372 }
369 bitmap_data[i + 3] = alpha; 373 bitmap_data[i + 3] = alpha;
370 bitmap_data[i] = (bgra[i] * alpha) >> 8; 374 bitmap_data[i] = (bgra[i] * alpha) >> 8;
371 bitmap_data[i + 1] = (bgra[i + 1] * alpha) >> 8; 375 bitmap_data[i + 1] = (bgra[i + 1] * alpha) >> 8;
372 bitmap_data[i + 2] = (bgra[i + 2] * alpha) >> 8; 376 bitmap_data[i + 2] = (bgra[i + 2] * alpha) >> 8;
373 } 377 }
374 378
375 bitmap->setIsOpaque(opaque); 379 bitmap->setIsOpaque(opaque);
376 return bitmap; 380 return bitmap;
377 } 381 }
382
383 // Encoder --------------------------------------------------------------------
384 //
385 // This section of the code is based on nsPNGEncoder.cpp in Mozilla
386 // (Copyright 2005 Google Inc.)
387
388 namespace {
389
390 // Passed around as the io_ptr in the png structs so our callbacks know where
391 // to write data.
392 struct PngEncoderState {
393 PngEncoderState(std::vector<unsigned char>* o) : out(o) {}
394 std::vector<unsigned char>* out;
395 };
396
397 // Called by libpng to flush its internal buffer to ours.
398 void EncoderWriteCallback(png_structp png, png_bytep data, png_size_t size) {
399 PngEncoderState* state = static_cast<PngEncoderState*>(png_get_io_ptr(png));
400 DCHECK(state->out);
401
402 size_t old_size = state->out->size();
403 state->out->resize(old_size + size);
404 memcpy(&(*state->out)[old_size], data, size);
405 }
406
407 void ConvertBGRAtoRGB(const unsigned char* bgra, int pixel_width,
408 unsigned char* rgb) {
409 for (int x = 0; x < pixel_width; x++) {
410 const unsigned char* pixel_in = &bgra[x * 4];
411 unsigned char* pixel_out = &rgb[x * 3];
412 pixel_out[0] = pixel_in[2];
413 pixel_out[1] = pixel_in[1];
414 pixel_out[2] = pixel_in[0];
415 }
416 }
417
418 // Automatically destroys the given write structs on destruction to make
419 // cleanup and error handling code cleaner.
420 class PngWriteStructDestroyer {
421 public:
422 PngWriteStructDestroyer(png_struct** ps, png_info** pi) : ps_(ps), pi_(pi) {
423 }
424 ~PngWriteStructDestroyer() {
425 png_destroy_write_struct(ps_, pi_);
426 }
427 private:
428 png_struct** ps_;
429 png_info** pi_;
430
431 DISALLOW_EVIL_CONSTRUCTORS(PngWriteStructDestroyer);
432 };
433
434 } // namespace
435
436 // static
437 bool PNGCodec::Encode(const unsigned char* input, ColorFormat format,
438 int w, int h, int row_byte_width,
439 bool discard_transparency,
440 std::vector<unsigned char>* output) {
441 // Run to convert an input row into the output row format, NULL means no
442 // conversion is necessary.
443 void (*converter)(const unsigned char* in, int w, unsigned char* out) = NULL;
444
445 int input_color_components, output_color_components;
446 int png_output_color_type;
447 switch (format) {
448 case FORMAT_RGB:
449 input_color_components = 3;
450 output_color_components = 3;
451 png_output_color_type = PNG_COLOR_TYPE_RGB;
452 discard_transparency = false;
453 break;
454
455 case FORMAT_RGBA:
456 input_color_components = 4;
457 if (discard_transparency) {
458 output_color_components = 3;
459 png_output_color_type = PNG_COLOR_TYPE_RGB;
460 converter = ConvertRGBAtoRGB;
461 } else {
462 output_color_components = 4;
463 png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
464 converter = NULL;
465 }
466 break;
467
468 case FORMAT_BGRA:
469 input_color_components = 4;
470 if (discard_transparency) {
471 output_color_components = 3;
472 png_output_color_type = PNG_COLOR_TYPE_RGB;
473 converter = ConvertBGRAtoRGB;
474 } else {
475 output_color_components = 4;
476 png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
477 converter = ConvertBetweenBGRAandRGBA;
478 }
479 break;
480
481 default:
482 NOTREACHED() << "Unknown pixel format";
483 return false;
484 }
485
486 // Row stride should be at least as long as the length of the data.
487 DCHECK(input_color_components * w <= row_byte_width);
488
489 png_struct* png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
490 png_voidp_NULL,
491 png_error_ptr_NULL,
492 png_error_ptr_NULL);
493 if (!png_ptr)
494 return false;
495 png_info* info_ptr = png_create_info_struct(png_ptr);
496 if (!info_ptr) {
497 png_destroy_write_struct(&png_ptr, NULL);
498 return false;
499 }
500 PngWriteStructDestroyer destroyer(&png_ptr, &info_ptr);
501
502 if (setjmp(png_jmpbuf(png_ptr))) {
503 // The destroyer will ensure that the structures are cleaned up in this
504 // case, even though we may get here as a jump from random parts of the
505 // PNG library called below.
506 return false;
507 }
508
509 // Set our callback for libpng to give us the data.
510 PngEncoderState state(output);
511 png_set_write_fn(png_ptr, &state, EncoderWriteCallback, NULL);
512
513 png_set_IHDR(png_ptr, info_ptr, w, h, 8, png_output_color_type,
514 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
515 PNG_FILTER_TYPE_DEFAULT);
516 png_write_info(png_ptr, info_ptr);
517
518 if (!converter) {
519 // No conversion needed, give the data directly to libpng.
520 for (int y = 0; y < h; y ++)
521 png_write_row(png_ptr,
522 const_cast<unsigned char*>(&input[y * row_byte_width]));
523 } else {
524 // Needs conversion using a separate buffer.
525 unsigned char* row = new unsigned char[w * output_color_components];
526 for (int y = 0; y < h; y ++) {
527 converter(&input[y * row_byte_width], w, row);
528 png_write_row(png_ptr, row);
529 }
530 delete[] row;
531 }
532
533 png_write_end(png_ptr, info_ptr);
534 return true;
535 }
536
537 // static
538 bool PNGCodec::EncodeBGRASkBitmap(const SkBitmap& input,
539 bool discard_transparency,
540 std::vector<unsigned char>* output) {
541 static const int bbp = 4;
542
543 SkAutoLockPixels lock_input(input);
544 DCHECK(input.empty() || input.bytesPerPixel() == bbp);
545
546 // SkBitmaps are premultiplied, we need to unpremultiply them.
547 scoped_array<unsigned char> divided(
548 new unsigned char[input.width() * input.height() * bbp]);
549
550 int i = 0;
551 for (int y = 0; y < input.height(); y++) {
552 for (int x = 0; x < input.width(); x++) {
553 uint32 pixel = input.getAddr32(0, y)[x];
554
555 int alpha = SkColorGetA(pixel);
556 if (alpha != 0 && alpha != 255) {
557 SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel);
558 divided[i + 0] = SkColorGetR(unmultiplied);
559 divided[i + 1] = SkColorGetG(unmultiplied);
560 divided[i + 2] = SkColorGetB(unmultiplied);
561 divided[i + 3] = alpha;
562 } else {
563 divided[i + 0] = SkColorGetR(pixel);
564 divided[i + 1] = SkColorGetG(pixel);
565 divided[i + 2] = SkColorGetB(pixel);
566 divided[i + 3] = alpha;
567 }
568 i += bbp;
569 }
570 }
571
572 return Encode(divided.get(),
573 PNGCodec::FORMAT_RGBA, input.width(), input.height(),
574 input.width() * bbp, discard_transparency, output);
575 }
576
577 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698