OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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/jpeg_codec.h" | 5 #include "ui/gfx/codec/jpeg_codec.h" |
6 | 6 |
7 #include <setjmp.h> | 7 #include <setjmp.h> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/scoped_ptr.h" | 10 #include "base/scoped_ptr.h" |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
209 destroyer.DestroyManagedObject(); | 209 destroyer.DestroyManagedObject(); |
210 return false; | 210 return false; |
211 } | 211 } |
212 | 212 |
213 // The destroyer will destroy() cinfo on exit. | 213 // The destroyer will destroy() cinfo on exit. |
214 jpeg_create_compress(&cinfo); | 214 jpeg_create_compress(&cinfo); |
215 | 215 |
216 cinfo.image_width = w; | 216 cinfo.image_width = w; |
217 cinfo.image_height = h; | 217 cinfo.image_height = h; |
218 cinfo.input_components = 3; | 218 cinfo.input_components = 3; |
| 219 #ifdef JCS_EXTENSIONS |
| 220 // Choose an input colorspace and return if it is an unsupported one. Since |
| 221 // libjpeg-turbo supports all input formats used by Chromium (i.e. RGB, RGBA, |
| 222 // and BGRA), we just map the input parameters to a colorspace used by |
| 223 // libjpeg-turbo. |
| 224 if (format == FORMAT_RGB) { |
| 225 cinfo.input_components = 3; |
| 226 cinfo.in_color_space = JCS_RGB; |
| 227 } else if (format == FORMAT_RGBA || |
| 228 format == FORMAT_SkBitmap && SK_R32_SHIFT == 0) { |
| 229 cinfo.input_components = 4; |
| 230 cinfo.in_color_space = JCS_EXT_RGBX; |
| 231 } else if (format == FORMAT_BGRA || |
| 232 format == FORMAT_SkBitmap && SK_B32_SHIFT == 0) { |
| 233 cinfo.input_components = 4; |
| 234 cinfo.in_color_space = JCS_EXT_BGRX; |
| 235 } else { |
| 236 // We can exit this function without calling jpeg_destroy_compress() because |
| 237 // CompressDestroyer automaticaly calls it. |
| 238 NOTREACHED() << "Invalid pixel format"; |
| 239 return false; |
| 240 } |
| 241 #else |
219 cinfo.in_color_space = JCS_RGB; | 242 cinfo.in_color_space = JCS_RGB; |
| 243 #endif |
220 cinfo.data_precision = 8; | 244 cinfo.data_precision = 8; |
221 | 245 |
222 jpeg_set_defaults(&cinfo); | 246 jpeg_set_defaults(&cinfo); |
223 jpeg_set_quality(&cinfo, quality, 1); // quality here is 0-100 | 247 jpeg_set_quality(&cinfo, quality, 1); // quality here is 0-100 |
224 | 248 |
225 // set up the destination manager | 249 // set up the destination manager |
226 jpeg_destination_mgr destmgr; | 250 jpeg_destination_mgr destmgr; |
227 destmgr.init_destination = InitDestination; | 251 destmgr.init_destination = InitDestination; |
228 destmgr.empty_output_buffer = EmptyOutputBuffer; | 252 destmgr.empty_output_buffer = EmptyOutputBuffer; |
229 destmgr.term_destination = TermDestination; | 253 destmgr.term_destination = TermDestination; |
230 cinfo.dest = &destmgr; | 254 cinfo.dest = &destmgr; |
231 | 255 |
232 JpegEncoderState state(output); | 256 JpegEncoderState state(output); |
233 cinfo.client_data = &state; | 257 cinfo.client_data = &state; |
234 | 258 |
235 jpeg_start_compress(&cinfo, 1); | 259 jpeg_start_compress(&cinfo, 1); |
236 | 260 |
237 // feed it the rows, doing necessary conversions for the color format | 261 // feed it the rows, doing necessary conversions for the color format |
| 262 #ifdef JCS_EXTENSIONS |
| 263 // This function already returns when the input format is not supported by |
| 264 // libjpeg-turbo and needs conversion. Therefore, we just encode lines without |
| 265 // conversions. |
| 266 while (cinfo.next_scanline < cinfo.image_height) { |
| 267 const unsigned char* row = &input[cinfo.next_scanline * row_byte_width]; |
| 268 jpeg_write_scanlines(&cinfo, const_cast<unsigned char**>(&row), 1); |
| 269 } |
| 270 #else |
238 if (format == FORMAT_RGB) { | 271 if (format == FORMAT_RGB) { |
239 // no conversion necessary | 272 // no conversion necessary |
240 while (cinfo.next_scanline < cinfo.image_height) { | 273 while (cinfo.next_scanline < cinfo.image_height) { |
241 const unsigned char* row = &input[cinfo.next_scanline * row_byte_width]; | 274 const unsigned char* row = &input[cinfo.next_scanline * row_byte_width]; |
242 jpeg_write_scanlines(&cinfo, const_cast<unsigned char**>(&row), 1); | 275 jpeg_write_scanlines(&cinfo, const_cast<unsigned char**>(&row), 1); |
243 } | 276 } |
244 } else { | 277 } else { |
245 // get the correct format converter | 278 // get the correct format converter |
246 void (*converter)(const unsigned char* in, int w, unsigned char* rgb); | 279 void (*converter)(const unsigned char* in, int w, unsigned char* rgb); |
247 if (format == FORMAT_RGBA || | 280 if (format == FORMAT_RGBA || |
248 (format == FORMAT_SkBitmap && SK_R32_SHIFT == 0)) { | 281 (format == FORMAT_SkBitmap && SK_R32_SHIFT == 0)) { |
249 converter = StripAlpha; | 282 converter = StripAlpha; |
250 } else if (format == FORMAT_BGRA || | 283 } else if (format == FORMAT_BGRA || |
251 (format == FORMAT_SkBitmap && SK_B32_SHIFT == 0)) { | 284 (format == FORMAT_SkBitmap && SK_B32_SHIFT == 0)) { |
252 converter = BGRAtoRGB; | 285 converter = BGRAtoRGB; |
253 } else { | 286 } else { |
254 NOTREACHED() << "Invalid pixel format"; | 287 NOTREACHED() << "Invalid pixel format"; |
255 return false; | 288 return false; |
256 } | 289 } |
257 | 290 |
258 // output row after converting | 291 // output row after converting |
259 unsigned char* row = new unsigned char[w * 3]; | 292 unsigned char* row = new unsigned char[w * 3]; |
260 | 293 |
261 while (cinfo.next_scanline < cinfo.image_height) { | 294 while (cinfo.next_scanline < cinfo.image_height) { |
262 converter(&input[cinfo.next_scanline * row_byte_width], w, row); | 295 converter(&input[cinfo.next_scanline * row_byte_width], w, row); |
263 jpeg_write_scanlines(&cinfo, &row, 1); | 296 jpeg_write_scanlines(&cinfo, &row, 1); |
264 } | 297 } |
265 delete[] row; | 298 delete[] row; |
266 } | 299 } |
| 300 #endif |
267 | 301 |
268 jpeg_finish_compress(&cinfo); | 302 jpeg_finish_compress(&cinfo); |
269 return true; | 303 return true; |
270 } | 304 } |
271 | 305 |
272 // Decoder -------------------------------------------------------------------- | 306 // Decoder -------------------------------------------------------------------- |
273 | 307 |
274 namespace { | 308 namespace { |
275 | 309 |
276 struct JpegDecoderState { | 310 struct JpegDecoderState { |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
439 | 473 |
440 // fill the file metadata into our buffer | 474 // fill the file metadata into our buffer |
441 if (jpeg_read_header(&cinfo, true) != JPEG_HEADER_OK) | 475 if (jpeg_read_header(&cinfo, true) != JPEG_HEADER_OK) |
442 return false; | 476 return false; |
443 | 477 |
444 // we want to always get RGB data out | 478 // we want to always get RGB data out |
445 switch (cinfo.jpeg_color_space) { | 479 switch (cinfo.jpeg_color_space) { |
446 case JCS_GRAYSCALE: | 480 case JCS_GRAYSCALE: |
447 case JCS_RGB: | 481 case JCS_RGB: |
448 case JCS_YCbCr: | 482 case JCS_YCbCr: |
| 483 #ifdef JCS_EXTENSIONS |
| 484 // Choose an output colorspace and return if it is an unsupported one. |
| 485 // Same as JPEGCodec::Encode(), libjpeg-turbo supports all input formats |
| 486 // used by Chromium (i.e. RGB, RGBA, and BGRA) and we just map the input |
| 487 // parameters to a colorspace. |
| 488 if (format == FORMAT_RGB) { |
| 489 cinfo.out_color_space = JCS_RGB; |
| 490 cinfo.output_components = 3; |
| 491 } else if (format == FORMAT_RGBA || |
| 492 format == FORMAT_SkBitmap && SK_R32_SHIFT == 0) { |
| 493 cinfo.out_color_space = JCS_EXT_RGBX; |
| 494 cinfo.output_components = 4; |
| 495 } else if (format == FORMAT_BGRA || |
| 496 format == FORMAT_SkBitmap && SK_B32_SHIFT == 0) { |
| 497 cinfo.out_color_space = JCS_EXT_BGRX; |
| 498 cinfo.output_components = 4; |
| 499 } else { |
| 500 // We can exit this function without calling jpeg_destroy_decompress() |
| 501 // because DecompressDestroyer automaticaly calls it. |
| 502 NOTREACHED() << "Invalid pixel format"; |
| 503 return false; |
| 504 } |
| 505 #else |
449 cinfo.out_color_space = JCS_RGB; | 506 cinfo.out_color_space = JCS_RGB; |
| 507 #endif |
450 break; | 508 break; |
451 case JCS_CMYK: | 509 case JCS_CMYK: |
452 case JCS_YCCK: | 510 case JCS_YCCK: |
453 default: | 511 default: |
454 // Mozilla errors out on these color spaces, so I presume that the jpeg | 512 // Mozilla errors out on these color spaces, so I presume that the jpeg |
455 // library can't do automatic color space conversion for them. We don't | 513 // library can't do automatic color space conversion for them. We don't |
456 // care about these anyway. | 514 // care about these anyway. |
457 return false; | 515 return false; |
458 } | 516 } |
| 517 #ifndef JCS_EXTENSIONS |
459 cinfo.output_components = 3; | 518 cinfo.output_components = 3; |
| 519 #endif |
460 | 520 |
461 jpeg_calc_output_dimensions(&cinfo); | 521 jpeg_calc_output_dimensions(&cinfo); |
462 *w = cinfo.output_width; | 522 *w = cinfo.output_width; |
463 *h = cinfo.output_height; | 523 *h = cinfo.output_height; |
464 | 524 |
465 jpeg_start_decompress(&cinfo); | 525 jpeg_start_decompress(&cinfo); |
466 | 526 |
467 // FIXME(brettw) we may want to allow the capability for callers to request | 527 // FIXME(brettw) we may want to allow the capability for callers to request |
468 // how to align row lengths as we do for the compressor. | 528 // how to align row lengths as we do for the compressor. |
469 int row_read_stride = cinfo.output_width * cinfo.output_components; | 529 int row_read_stride = cinfo.output_width * cinfo.output_components; |
470 | 530 |
| 531 #ifdef JCS_EXTENSIONS |
| 532 // Create memory for a decoded image and write decoded lines to the memory |
| 533 // without conversions same as JPEGCodec::Encode(). |
| 534 int row_write_stride = row_read_stride; |
| 535 output->resize(row_write_stride * cinfo.output_height); |
| 536 |
| 537 for (int row = 0; row < static_cast<int>(cinfo.output_height); row++) { |
| 538 unsigned char* rowptr = &(*output)[row * row_write_stride]; |
| 539 if (!jpeg_read_scanlines(&cinfo, &rowptr, 1)) |
| 540 return false; |
| 541 } |
| 542 #else |
471 if (format == FORMAT_RGB) { | 543 if (format == FORMAT_RGB) { |
472 // easy case, row needs no conversion | 544 // easy case, row needs no conversion |
473 int row_write_stride = row_read_stride; | 545 int row_write_stride = row_read_stride; |
474 output->resize(row_write_stride * cinfo.output_height); | 546 output->resize(row_write_stride * cinfo.output_height); |
475 | 547 |
476 for (int row = 0; row < static_cast<int>(cinfo.output_height); row++) { | 548 for (int row = 0; row < static_cast<int>(cinfo.output_height); row++) { |
477 unsigned char* rowptr = &(*output)[row * row_write_stride]; | 549 unsigned char* rowptr = &(*output)[row * row_write_stride]; |
478 if (!jpeg_read_scanlines(&cinfo, &rowptr, 1)) | 550 if (!jpeg_read_scanlines(&cinfo, &rowptr, 1)) |
479 return false; | 551 return false; |
480 } | 552 } |
(...skipping 20 matching lines...) Expand all Loading... |
501 output->resize(row_write_stride * cinfo.output_height); | 573 output->resize(row_write_stride * cinfo.output_height); |
502 | 574 |
503 scoped_array<unsigned char> row_data(new unsigned char[row_read_stride]); | 575 scoped_array<unsigned char> row_data(new unsigned char[row_read_stride]); |
504 unsigned char* rowptr = row_data.get(); | 576 unsigned char* rowptr = row_data.get(); |
505 for (int row = 0; row < static_cast<int>(cinfo.output_height); row++) { | 577 for (int row = 0; row < static_cast<int>(cinfo.output_height); row++) { |
506 if (!jpeg_read_scanlines(&cinfo, &rowptr, 1)) | 578 if (!jpeg_read_scanlines(&cinfo, &rowptr, 1)) |
507 return false; | 579 return false; |
508 converter(rowptr, *w, &(*output)[row * row_write_stride]); | 580 converter(rowptr, *w, &(*output)[row * row_write_stride]); |
509 } | 581 } |
510 } | 582 } |
| 583 #endif |
511 | 584 |
512 jpeg_finish_decompress(&cinfo); | 585 jpeg_finish_decompress(&cinfo); |
513 jpeg_destroy_decompress(&cinfo); | 586 jpeg_destroy_decompress(&cinfo); |
514 return true; | 587 return true; |
515 } | 588 } |
516 | 589 |
517 // static | 590 // static |
518 SkBitmap* JPEGCodec::Decode(const unsigned char* input, size_t input_size) { | 591 SkBitmap* JPEGCodec::Decode(const unsigned char* input, size_t input_size) { |
519 int w, h; | 592 int w, h; |
520 std::vector<unsigned char> data_vector; | 593 std::vector<unsigned char> data_vector; |
521 if (!Decode(input, input_size, FORMAT_SkBitmap, &data_vector, &w, &h)) | 594 if (!Decode(input, input_size, FORMAT_SkBitmap, &data_vector, &w, &h)) |
522 return NULL; | 595 return NULL; |
523 | 596 |
524 // Skia only handles 32 bit images. | 597 // Skia only handles 32 bit images. |
525 int data_length = w * h * 4; | 598 int data_length = w * h * 4; |
526 | 599 |
527 SkBitmap* bitmap = new SkBitmap(); | 600 SkBitmap* bitmap = new SkBitmap(); |
528 bitmap->setConfig(SkBitmap::kARGB_8888_Config, w, h); | 601 bitmap->setConfig(SkBitmap::kARGB_8888_Config, w, h); |
529 bitmap->allocPixels(); | 602 bitmap->allocPixels(); |
530 memcpy(bitmap->getAddr32(0, 0), &data_vector[0], data_length); | 603 memcpy(bitmap->getAddr32(0, 0), &data_vector[0], data_length); |
531 | 604 |
532 return bitmap; | 605 return bitmap; |
533 } | 606 } |
534 | 607 |
535 } // namespace gfx | 608 } // namespace gfx |
OLD | NEW |