Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2006 Apple Computer, Inc. | 2 * Copyright (C) 2006 Apple Computer, Inc. |
| 3 * | 3 * |
| 4 * Portions are Copyright (C) 2001-6 mozilla.org | 4 * Portions are Copyright (C) 2001-6 mozilla.org |
| 5 * | 5 * |
| 6 * Other contributors: | 6 * Other contributors: |
| 7 * Stuart Parmenter <stuart@mozilla.com> | 7 * Stuart Parmenter <stuart@mozilla.com> |
| 8 * | 8 * |
| 9 * Copyright (C) 2007-2009 Torch Mobile, Inc. | 9 * Copyright (C) 2007-2009 Torch Mobile, Inc. |
| 10 * | 10 * |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 106 | 106 |
| 107 enum jstate { | 107 enum jstate { |
| 108 JPEG_HEADER, // Reading JFIF headers | 108 JPEG_HEADER, // Reading JFIF headers |
| 109 JPEG_START_DECOMPRESS, | 109 JPEG_START_DECOMPRESS, |
| 110 JPEG_DECOMPRESS_PROGRESSIVE, // Output progressive pixels | 110 JPEG_DECOMPRESS_PROGRESSIVE, // Output progressive pixels |
| 111 JPEG_DECOMPRESS_SEQUENTIAL, // Output sequential pixels | 111 JPEG_DECOMPRESS_SEQUENTIAL, // Output sequential pixels |
| 112 JPEG_DONE, | 112 JPEG_DONE, |
| 113 JPEG_ERROR | 113 JPEG_ERROR |
| 114 }; | 114 }; |
| 115 | 115 |
| 116 enum yuv_subsampling { | |
| 117 YUV_UNKNOWN, | |
| 118 YUV_410, | |
| 119 YUV_411, | |
| 120 YUV_420, | |
| 121 YUV_422, | |
| 122 YUV_440, | |
| 123 YUV_444 | |
| 124 }; | |
| 125 | |
| 116 void init_source(j_decompress_ptr jd); | 126 void init_source(j_decompress_ptr jd); |
| 117 boolean fill_input_buffer(j_decompress_ptr jd); | 127 boolean fill_input_buffer(j_decompress_ptr jd); |
| 118 void skip_input_data(j_decompress_ptr jd, long num_bytes); | 128 void skip_input_data(j_decompress_ptr jd, long num_bytes); |
| 119 void term_source(j_decompress_ptr jd); | 129 void term_source(j_decompress_ptr jd); |
| 120 void error_exit(j_common_ptr cinfo); | 130 void error_exit(j_common_ptr cinfo); |
| 121 | 131 |
| 122 // Implementation of a JPEG src object that understands our state machine | 132 // Implementation of a JPEG src object that understands our state machine |
| 123 struct decoder_source_mgr { | 133 struct decoder_source_mgr { |
| 124 // public fields; must be first in this struct! | 134 // public fields; must be first in this struct! |
| 125 struct jpeg_source_mgr pub; | 135 struct jpeg_source_mgr pub; |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 235 ignoreProfile = true; | 245 ignoreProfile = true; |
| 236 | 246 |
| 237 ASSERT(colorProfile.isEmpty()); | 247 ASSERT(colorProfile.isEmpty()); |
| 238 if (!ignoreProfile) | 248 if (!ignoreProfile) |
| 239 colorProfile.append(profileData, profileLength); | 249 colorProfile.append(profileData, profileLength); |
| 240 free(profile); | 250 free(profile); |
| 241 #endif | 251 #endif |
| 242 } | 252 } |
| 243 #endif | 253 #endif |
| 244 | 254 |
| 255 static IntSize computeUVSize(const jpeg_decompress_struct* info) | |
| 256 { | |
| 257 int h = info->cur_comp_info[0]->h_samp_factor; | |
| 258 int v = info->cur_comp_info[0]->v_samp_factor; | |
| 259 return IntSize((info->output_width + h - 1) / h, (info->output_height + v - 1) / v); | |
| 260 } | |
| 261 | |
| 262 static yuv_subsampling getYUVSubsampling(const jpeg_decompress_struct& info) | |
| 263 { | |
|
Noel Gordon
2014/07/28 07:29:07
yuvSubsampling(...)
sugoi1
2014/08/19 20:28:47
Done.
| |
| 264 if ((DCTSIZE == 8) | |
| 265 && (info.num_components == 3) | |
| 266 && (info.scale_denom <= 8) | |
| 267 && (info.cur_comp_info[1]->h_samp_factor == 1) | |
| 268 && (info.cur_comp_info[1]->v_samp_factor == 1) | |
| 269 && (info.cur_comp_info[2]->h_samp_factor == 1) | |
| 270 && (info.cur_comp_info[2]->v_samp_factor == 1)) { | |
| 271 int h = info.cur_comp_info[0]->h_samp_factor; | |
| 272 int v = info.cur_comp_info[0]->v_samp_factor; | |
| 273 // 4:4:4 : (h == 1) && (v == 1) | |
| 274 // 4:4:0 : (h == 1) && (v == 2) | |
| 275 // 4:2:2 : (h == 2) && (v == 1) | |
| 276 // 4:2:0 : (h == 2) && (v == 2) | |
| 277 // 4:1:1 : (h == 4) && (v == 1) | |
| 278 // 4:1:0 : (h == 4) && (v == 2) | |
| 279 if (v == 1) { | |
| 280 switch (h) { | |
| 281 case 1: | |
| 282 return YUV_444; | |
| 283 case 2: | |
| 284 return YUV_422; | |
| 285 case 4: | |
| 286 return YUV_411; | |
| 287 default: | |
| 288 break; | |
| 289 } | |
| 290 } else if (v == 2) { | |
| 291 switch (h) { | |
| 292 case 1: | |
| 293 return YUV_440; | |
| 294 case 2: | |
| 295 return YUV_420; | |
| 296 case 4: | |
| 297 return YUV_410; | |
| 298 default: | |
| 299 break; | |
| 300 } | |
| 301 } | |
| 302 } | |
| 303 | |
| 304 return YUV_UNKNOWN; | |
| 305 } | |
| 306 | |
| 245 class JPEGImageReader { | 307 class JPEGImageReader { |
| 246 WTF_MAKE_FAST_ALLOCATED; | 308 WTF_MAKE_FAST_ALLOCATED; |
| 247 public: | 309 public: |
| 248 JPEGImageReader(JPEGImageDecoder* decoder) | 310 JPEGImageReader(JPEGImageDecoder* decoder) |
| 249 : m_decoder(decoder) | 311 : m_decoder(decoder) |
| 250 , m_bufferLength(0) | 312 , m_bufferLength(0) |
| 251 , m_bytesToSkip(0) | 313 , m_bytesToSkip(0) |
| 252 , m_state(JPEG_HEADER) | 314 , m_state(JPEG_HEADER) |
| 253 , m_samples(0) | 315 , m_samples(0) |
| 254 #if USE(QCMSLIB) | 316 #if USE(QCMSLIB) |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 340 if (setjmp(m_err.setjmp_buffer)) | 402 if (setjmp(m_err.setjmp_buffer)) |
| 341 return m_decoder->setFailed(); | 403 return m_decoder->setFailed(); |
| 342 | 404 |
| 343 switch (m_state) { | 405 switch (m_state) { |
| 344 case JPEG_HEADER: | 406 case JPEG_HEADER: |
| 345 // Read file parameters with jpeg_read_header(). | 407 // Read file parameters with jpeg_read_header(). |
| 346 if (jpeg_read_header(&m_info, true) == JPEG_SUSPENDED) | 408 if (jpeg_read_header(&m_info, true) == JPEG_SUSPENDED) |
| 347 return false; // I/O suspension. | 409 return false; // I/O suspension. |
| 348 | 410 |
| 349 switch (m_info.jpeg_color_space) { | 411 switch (m_info.jpeg_color_space) { |
| 412 case JCS_YCbCr: | |
| 413 // libjpeg can convert YCbCr image pixels to RGB. | |
| 414 m_info.out_color_space = rgbOutputColorSpace(); | |
| 415 if (m_decoder->YUVDecoding() && (getYUVSubsampling(m_info) != YU V_UNKNOWN)) { | |
| 416 m_info.out_color_space = JCS_YCbCr; | |
|
Noel Gordon
2014/07/28 07:29:07
You should somehow record that YCbCr decoding is a
sugoi1
2014/08/19 20:28:47
Done.
| |
| 417 m_info.raw_data_out = TRUE; | |
| 418 } | |
| 419 break; | |
| 350 case JCS_GRAYSCALE: | 420 case JCS_GRAYSCALE: |
| 351 case JCS_RGB: | 421 case JCS_RGB: |
| 352 case JCS_YCbCr: | 422 // libjpeg can convert GRAYSCALE image pixels to RGB. |
| 353 // libjpeg can convert GRAYSCALE and YCbCr image pixels to RGB. | |
| 354 m_info.out_color_space = rgbOutputColorSpace(); | 423 m_info.out_color_space = rgbOutputColorSpace(); |
| 355 #if defined(TURBO_JPEG_RGB_SWIZZLE) | 424 #if defined(TURBO_JPEG_RGB_SWIZZLE) |
| 356 if (m_info.saw_JFIF_marker) | 425 if (m_info.saw_JFIF_marker) |
| 357 break; | 426 break; |
| 358 // FIXME: Swizzle decoding does not support Adobe transform=0 | 427 // FIXME: Swizzle decoding does not support Adobe transform=0 |
| 359 // images (yet), so revert to using JSC_RGB in that case. | 428 // images (yet), so revert to using JSC_RGB in that case. |
| 360 if (m_info.saw_Adobe_marker && !m_info.Adobe_transform) | 429 if (m_info.saw_Adobe_marker && !m_info.Adobe_transform) |
| 361 m_info.out_color_space = JCS_RGB; | 430 m_info.out_color_space = JCS_RGB; |
| 362 #endif | 431 #endif |
| 363 break; | 432 break; |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 384 m_decoder->setDecodedSize(m_info.output_width, m_info.output_height) ; | 453 m_decoder->setDecodedSize(m_info.output_width, m_info.output_height) ; |
| 385 | 454 |
| 386 m_decoder->setOrientation(readImageOrientation(info())); | 455 m_decoder->setOrientation(readImageOrientation(info())); |
| 387 | 456 |
| 388 #if USE(QCMSLIB) | 457 #if USE(QCMSLIB) |
| 389 // Allow color management of the decoded RGBA pixels if possible. | 458 // Allow color management of the decoded RGBA pixels if possible. |
| 390 if (!m_decoder->ignoresGammaAndColorProfile()) { | 459 if (!m_decoder->ignoresGammaAndColorProfile()) { |
| 391 ColorProfile colorProfile; | 460 ColorProfile colorProfile; |
| 392 readColorProfile(info(), colorProfile); | 461 readColorProfile(info(), colorProfile); |
| 393 createColorTransform(colorProfile, colorSpaceHasAlpha(m_info.out _color_space)); | 462 createColorTransform(colorProfile, colorSpaceHasAlpha(m_info.out _color_space)); |
| 463 if (m_transform && m_info.out_color_space == JCS_YCbCr) { | |
|
Noel Gordon
2014/07/28 07:29:07
... because this code in this block is broken by a
sugoi1
2014/08/19 20:28:47
Done.
| |
| 464 m_info.out_color_space = rgbOutputColorSpace(); | |
| 465 m_info.raw_data_out = FALSE; | |
| 466 } | |
| 394 #if defined(TURBO_JPEG_RGB_SWIZZLE) | 467 #if defined(TURBO_JPEG_RGB_SWIZZLE) |
| 395 // Input RGBA data to qcms. Note: restored to BGRA on output. | 468 // Input RGBA data to qcms. Note: restored to BGRA on output. |
| 396 if (m_transform && m_info.out_color_space == JCS_EXT_BGRA) | 469 if (m_transform && m_info.out_color_space == JCS_EXT_BGRA) |
| 397 m_info.out_color_space = JCS_EXT_RGBA; | 470 m_info.out_color_space = JCS_EXT_RGBA; |
| 398 #endif | 471 #endif |
| 399 m_decoder->setHasColorProfile(!!m_transform); | 472 m_decoder->setHasColorProfile(!!m_transform); |
| 400 } | 473 } |
| 401 #endif | 474 #endif |
| 402 // Don't allocate a giant and superfluous memory buffer when the | 475 // Don't allocate a giant and superfluous memory buffer when the |
|
Noel Gordon
2014/07/28 07:29:07
... and make a deferred yuv test around here
if
sugoi1
2014/08/19 20:28:47
Done.
In that case, the planes wouldn't be used. T
| |
| 403 // image is a sequential JPEG. | 476 // image is a sequential JPEG. |
| 404 m_info.buffered_image = jpeg_has_multiple_scans(&m_info); | 477 m_info.buffered_image = jpeg_has_multiple_scans(&m_info); |
| 405 | 478 |
| 406 if (onlySize) { | 479 if (onlySize) { |
| 407 // We can stop here. Reduce our buffer length and available data . | 480 // We can stop here. Reduce our buffer length and available data . |
| 408 m_bufferLength -= m_info.src->bytes_in_buffer; | 481 m_bufferLength -= m_info.src->bytes_in_buffer; |
| 409 m_info.src->bytes_in_buffer = 0; | 482 m_info.src->bytes_in_buffer = 0; |
| 410 return true; | 483 return true; |
| 411 } | 484 } |
| 412 // FALL THROUGH | 485 // FALL THROUGH |
| 413 | 486 |
| 414 case JPEG_START_DECOMPRESS: | 487 case JPEG_START_DECOMPRESS: |
| 415 // Set parameters for decompression. | 488 // Set parameters for decompression. |
| 416 // FIXME -- Should reset dct_method and dither mode for final pass | 489 // FIXME -- Should reset dct_method and dither mode for final pass |
| 417 // of progressive JPEG. | 490 // of progressive JPEG. |
| 418 m_info.dct_method = dctMethod(); | 491 m_info.dct_method = dctMethod(); |
| 419 m_info.dither_mode = ditherMode(); | 492 m_info.dither_mode = ditherMode(); |
| 420 m_info.do_fancy_upsampling = doFancyUpsampling(); | 493 m_info.do_fancy_upsampling = doFancyUpsampling(); |
| 421 m_info.enable_2pass_quant = false; | 494 m_info.enable_2pass_quant = false; |
| 422 m_info.do_block_smoothing = true; | 495 m_info.do_block_smoothing = true; |
| 423 | 496 |
| 424 // Make a one-row-high sample array that will go away when done with | 497 // Make a one-row-high sample array that will go away when done with |
| 425 // image. Always make it big enough to hold an RGB row. Since this | 498 // image. Always make it big enough to hold an RGB row. Since this |
| 426 // uses the IJG memory manager, it must be allocated before the call | 499 // uses the IJG memory manager, it must be allocated before the call |
| 427 // to jpeg_start_compress(). | 500 // to jpeg_start_compress(). |
| 428 // FIXME: note that some output color spaces do not need the samples | 501 // FIXME: note that some output color spaces do not need the samples |
| 429 // buffer. Remove this allocation for those color spaces. | 502 // buffer. Remove this allocation for those color spaces. |
| 430 m_samples = (*m_info.mem->alloc_sarray)(reinterpret_cast<j_common_pt r>(&m_info), JPOOL_IMAGE, m_info.output_width * 4, 1); | 503 m_samples = (*m_info.mem->alloc_sarray)(reinterpret_cast<j_common_pt r>(&m_info), JPOOL_IMAGE, m_info.output_width * 4, m_info.out_color_space == JCS _YCbCr ? 2 : 1); |
| 431 | 504 |
| 432 // Start decompressor. | 505 // Start decompressor. |
| 433 if (!jpeg_start_decompress(&m_info)) | 506 if (!jpeg_start_decompress(&m_info)) |
| 434 return false; // I/O suspension. | 507 return false; // I/O suspension. |
| 435 | 508 |
| 436 // If this is a progressive JPEG ... | 509 // If this is a progressive JPEG ... |
| 437 m_state = (m_info.buffered_image) ? JPEG_DECOMPRESS_PROGRESSIVE : JP EG_DECOMPRESS_SEQUENTIAL; | 510 m_state = (m_info.buffered_image) ? JPEG_DECOMPRESS_PROGRESSIVE : JP EG_DECOMPRESS_SEQUENTIAL; |
| 438 // FALL THROUGH | 511 // FALL THROUGH |
| 439 | 512 |
| 440 case JPEG_DECOMPRESS_SEQUENTIAL: | 513 case JPEG_DECOMPRESS_SEQUENTIAL: |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 622 | 695 |
| 623 setDecodedSize(width, height); | 696 setDecodedSize(width, height); |
| 624 return true; | 697 return true; |
| 625 } | 698 } |
| 626 | 699 |
| 627 void JPEGImageDecoder::setDecodedSize(unsigned width, unsigned height) | 700 void JPEGImageDecoder::setDecodedSize(unsigned width, unsigned height) |
| 628 { | 701 { |
| 629 m_decodedSize = IntSize(width, height); | 702 m_decodedSize = IntSize(width, height); |
| 630 } | 703 } |
| 631 | 704 |
| 705 IntSize JPEGImageDecoder::decodedYUVSize(int component) const | |
| 706 { | |
| 707 if (((component == 1) || (component == 2)) && m_reader.get()) { // Asking fo r U or V | |
| 708 const jpeg_decompress_struct* info = m_reader->info(); | |
| 709 if (info && (info->out_color_space == JCS_YCbCr)) { | |
| 710 return computeUVSize(info); | |
| 711 } | |
| 712 } | |
| 713 | |
| 714 return m_decodedSize; | |
| 715 } | |
| 716 | |
| 632 unsigned JPEGImageDecoder::desiredScaleNumerator() const | 717 unsigned JPEGImageDecoder::desiredScaleNumerator() const |
| 633 { | 718 { |
| 634 size_t originalBytes = size().width() * size().height() * 4; | 719 size_t originalBytes = size().width() * size().height() * 4; |
| 635 if (originalBytes <= m_maxDecodedBytes) { | 720 if (originalBytes <= m_maxDecodedBytes) { |
| 636 return scaleDenominator; | 721 return scaleDenominator; |
| 637 } | 722 } |
| 638 | 723 |
| 639 // Downsample according to the maximum decoded size. | 724 // Downsample according to the maximum decoded size. |
| 640 unsigned scaleNumerator = static_cast<unsigned>(floor(sqrt( | 725 unsigned scaleNumerator = static_cast<unsigned>(floor(sqrt( |
| 641 // MSVC needs explicit parameter type for sqrt(). | 726 // MSVC needs explicit parameter type for sqrt(). |
| 642 static_cast<float>(m_maxDecodedBytes * scaleDenominator * scaleDenominat or / originalBytes)))); | 727 static_cast<float>(m_maxDecodedBytes * scaleDenominator * scaleDenominat or / originalBytes)))); |
| 643 | 728 |
| 644 return scaleNumerator; | 729 return scaleNumerator; |
| 645 } | 730 } |
| 646 | 731 |
| 732 bool JPEGImageDecoder::decodeToYUV() | |
| 733 { | |
| 734 PlatformInstrumentation::willDecodeImage("JPEG"); | |
| 735 decode(false); | |
| 736 PlatformInstrumentation::didDecodeImage(); | |
| 737 return !failed(); | |
| 738 } | |
| 739 | |
| 647 ImageFrame* JPEGImageDecoder::frameBufferAtIndex(size_t index) | 740 ImageFrame* JPEGImageDecoder::frameBufferAtIndex(size_t index) |
| 648 { | 741 { |
| 649 if (index) | 742 if (index) |
| 650 return 0; | 743 return 0; |
| 651 | 744 |
| 652 if (m_frameBufferCache.isEmpty()) { | 745 if (m_frameBufferCache.isEmpty()) { |
| 653 m_frameBufferCache.resize(1); | 746 m_frameBufferCache.resize(1); |
| 654 m_frameBufferCache[0].setPremultiplyAlpha(m_premultiplyAlpha); | 747 m_frameBufferCache[0].setPremultiplyAlpha(m_premultiplyAlpha); |
| 655 } | 748 } |
| 656 | 749 |
| 657 ImageFrame& frame = m_frameBufferCache[0]; | 750 ImageFrame& frame = m_frameBufferCache[0]; |
| 658 if (frame.status() != ImageFrame::FrameComplete) { | 751 if (frame.status() != ImageFrame::FrameComplete) { |
| 659 PlatformInstrumentation::willDecodeImage("JPEG"); | 752 PlatformInstrumentation::willDecodeImage("JPEG"); |
| 660 decode(false); | 753 decode(false); |
| 661 PlatformInstrumentation::didDecodeImage(); | 754 PlatformInstrumentation::didDecodeImage(); |
| 662 } | 755 } |
| 663 | 756 |
| 664 frame.notifyBitmapIfPixelsChanged(); | 757 frame.notifyBitmapIfPixelsChanged(); |
| 665 return &frame; | 758 return &frame; |
| 666 } | 759 } |
| 667 | 760 |
| 668 bool JPEGImageDecoder::setFailed() | 761 bool JPEGImageDecoder::setFailed() |
| 669 { | 762 { |
| 670 m_reader.clear(); | 763 m_reader.clear(); |
| 671 return ImageDecoder::setFailed(); | 764 return ImageDecoder::setFailed(); |
| 672 } | 765 } |
| 673 | 766 |
| 767 void JPEGImageDecoder::setImagePlanes(OwnPtr<ImagePlanes>& imagePlanes) | |
| 768 { | |
| 769 m_imagePlanes = imagePlanes.release(); | |
| 770 } | |
| 771 | |
| 674 template <J_COLOR_SPACE colorSpace> void setPixel(ImageFrame& buffer, ImageFrame ::PixelData* pixel, JSAMPARRAY samples, int column) | 772 template <J_COLOR_SPACE colorSpace> void setPixel(ImageFrame& buffer, ImageFrame ::PixelData* pixel, JSAMPARRAY samples, int column) |
| 675 { | 773 { |
| 676 JSAMPLE* jsample = *samples + column * (colorSpace == JCS_RGB ? 3 : 4); | 774 ASSERT_NOT_REACHED(); |
| 775 } | |
| 677 | 776 |
| 678 switch (colorSpace) { | 777 template <> void setPixel<JCS_RGB>(ImageFrame& buffer, ImageFrame::PixelData* pi xel, JSAMPARRAY samples, int column) |
| 679 case JCS_RGB: | 778 { |
| 680 buffer.setRGBARaw(pixel, jsample[0], jsample[1], jsample[2], 255); | 779 JSAMPLE* jsample = *samples + column * 3; |
| 681 break; | 780 buffer.setRGBARaw(pixel, jsample[0], jsample[1], jsample[2], 255); |
| 682 case JCS_CMYK: | 781 } |
| 683 // Source is 'Inverted CMYK', output is RGB. | 782 |
| 684 // See: http://www.easyrgb.com/math.php?MATH=M12#text12 | 783 template <> void setPixel<JCS_CMYK>(ImageFrame& buffer, ImageFrame::PixelData* p ixel, JSAMPARRAY samples, int column) |
| 685 // Or: http://www.ilkeratalay.com/colorspacesfaq.php#rgb | 784 { |
| 686 // From CMYK to CMY: | 785 JSAMPLE* jsample = *samples + column * 4; |
| 687 // X = X * (1 - K ) + K [for X = C, M, or Y] | 786 |
| 688 // Thus, from Inverted CMYK to CMY is: | 787 // Source is 'Inverted CMYK', output is RGB. |
| 689 // X = (1-iX) * (1 - (1-iK)) + (1-iK) => 1 - iX*iK | 788 // See: http://www.easyrgb.com/math.php?MATH=M12#text12 |
| 690 // From CMY (0..1) to RGB (0..1): | 789 // Or: http://www.ilkeratalay.com/colorspacesfaq.php#rgb |
| 691 // R = 1 - C => 1 - (1 - iC*iK) => iC*iK [G and B similar] | 790 // From CMYK to CMY: |
| 692 unsigned k = jsample[3]; | 791 // X = X * (1 - K ) + K [for X = C, M, or Y] |
| 693 buffer.setRGBARaw(pixel, jsample[0] * k / 255, jsample[1] * k / 255, jsa mple[2] * k / 255, 255); | 792 // Thus, from Inverted CMYK to CMY is: |
| 694 break; | 793 // X = (1-iX) * (1 - (1-iK)) + (1-iK) => 1 - iX*iK |
| 695 } | 794 // From CMY (0..1) to RGB (0..1): |
| 795 // R = 1 - C => 1 - (1 - iC*iK) => iC*iK [G and B similar] | |
| 796 unsigned k = jsample[3]; | |
| 797 buffer.setRGBARaw(pixel, jsample[0] * k / 255, jsample[1] * k / 255, jsample [2] * k / 255, 255); | |
| 696 } | 798 } |
| 697 | 799 |
| 698 template <J_COLOR_SPACE colorSpace> bool outputRows(JPEGImageReader* reader, Ima geFrame& buffer) | 800 template <J_COLOR_SPACE colorSpace> bool outputRows(JPEGImageReader* reader, Ima geFrame& buffer) |
| 699 { | 801 { |
| 700 JSAMPARRAY samples = reader->samples(); | 802 JSAMPARRAY samples = reader->samples(); |
| 701 jpeg_decompress_struct* info = reader->info(); | 803 jpeg_decompress_struct* info = reader->info(); |
| 702 int width = info->output_width; | 804 int width = info->output_width; |
| 703 | 805 |
| 704 while (info->output_scanline < info->output_height) { | 806 while (info->output_scanline < info->output_height) { |
| 705 // jpeg_read_scanlines will increase the scanline counter, so we | 807 // jpeg_read_scanlines will increase the scanline counter, so we |
| 706 // save the scanline before calling it. | 808 // save the scanline before calling it. |
| 707 int y = info->output_scanline; | 809 int y = info->output_scanline; |
| 708 // Request one scanline: returns 0 or 1 scanlines. | 810 // Request one scanline: returns 0 or 1 scanlines. |
| 709 if (jpeg_read_scanlines(info, samples, 1) != 1) | 811 if (jpeg_read_scanlines(info, samples, 1) != 1) |
| 710 return false; | 812 return false; |
| 711 #if USE(QCMSLIB) | 813 #if USE(QCMSLIB) |
| 712 if (reader->colorTransform() && colorSpace == JCS_RGB) | 814 if (reader->colorTransform() && colorSpace == JCS_RGB) |
| 713 qcms_transform_data(reader->colorTransform(), *samples, *samples, wi dth); | 815 qcms_transform_data(reader->colorTransform(), *samples, *samples, wi dth); |
| 714 #endif | 816 #endif |
| 715 ImageFrame::PixelData* pixel = buffer.getAddr(0, y); | 817 ImageFrame::PixelData* pixel = buffer.getAddr(0, y); |
| 716 for (int x = 0; x < width; ++pixel, ++x) | 818 for (int x = 0; x < width; ++pixel, ++x) |
| 717 setPixel<colorSpace>(buffer, pixel, samples, x); | 819 setPixel<colorSpace>(buffer, pixel, samples, x); |
| 718 } | 820 } |
| 719 | 821 |
| 720 buffer.setPixelsChanged(true); | 822 buffer.setPixelsChanged(true); |
| 721 return true; | 823 return true; |
| 722 } | 824 } |
| 723 | 825 |
| 826 static bool outputRawData(JPEGImageReader* reader, ImagePlanes* imagePlanes) | |
| 827 { | |
| 828 JSAMPARRAY samples = reader->samples(); | |
| 829 jpeg_decompress_struct* info = reader->info(); | |
| 830 JSAMPARRAY bufferraw[3]; | |
| 831 JSAMPROW bufferraw2[32]; | |
| 832 bufferraw[0] = &bufferraw2[0]; // Y channel rows (8 or 16) | |
| 833 bufferraw[1] = &bufferraw2[16]; // U channel rows (8) | |
| 834 bufferraw[2] = &bufferraw2[24]; // V channel rows (8) | |
| 835 int yWidth = info->output_width; | |
| 836 int yHeight = info->output_height; | |
| 837 int yMaxH = yHeight - 1; | |
| 838 int v = info->cur_comp_info[0]->v_samp_factor; | |
| 839 IntSize uvSize = computeUVSize(info); | |
| 840 int uvMaxH = uvSize.height() - 1; | |
| 841 JSAMPROW outputY = static_cast<JSAMPROW>(imagePlanes->plane(0)); | |
| 842 JSAMPROW outputU = static_cast<JSAMPROW>(imagePlanes->plane(1)); | |
| 843 JSAMPROW outputV = static_cast<JSAMPROW>(imagePlanes->plane(2)); | |
| 844 size_t rowBytesY = imagePlanes->rowBytes(0); | |
| 845 size_t rowBytesU = imagePlanes->rowBytes(1); | |
| 846 size_t rowBytesV = imagePlanes->rowBytes(2); | |
| 847 | |
| 848 int yScanlinesToRead = DCTSIZE * v; | |
| 849 JSAMPROW yLastRow = *samples; | |
| 850 JSAMPROW uLastRow = yLastRow + 2 * yWidth; | |
| 851 JSAMPROW vLastRow = uLastRow + 2 * yWidth; | |
| 852 JSAMPROW dummyRow = vLastRow + 2 * yWidth; | |
| 853 | |
| 854 while (info->output_scanline < info->output_height) { | |
| 855 // Request 8 or 16 scanlines: returns 0 or more scanlines. | |
| 856 bool hasYLastRow(false), hasUVLastRow(false); | |
| 857 // Assign 8 or 16 rows of memory to read the Y channel. | |
| 858 for (int i = 0; i < yScanlinesToRead; ++i) { | |
| 859 int scanline = (info->output_scanline + i); | |
| 860 if (scanline < yMaxH) { | |
| 861 bufferraw2[i] = &outputY[scanline * rowBytesY]; | |
| 862 } else if (scanline == yMaxH) { | |
| 863 bufferraw2[i] = yLastRow; | |
| 864 hasYLastRow = true; | |
| 865 } else { | |
| 866 bufferraw2[i] = dummyRow; | |
| 867 } | |
| 868 } | |
| 869 int scaledScanline = info->output_scanline / v; | |
| 870 // Assign 8 rows of memory to read the U and V channels. | |
| 871 for (int i = 0; i < 8; ++i) { | |
| 872 int scanline = (scaledScanline + i); | |
| 873 if (scanline < uvMaxH) { | |
| 874 bufferraw2[16 + i] = &outputU[scanline * rowBytesU]; | |
| 875 bufferraw2[24 + i] = &outputV[scanline * rowBytesV]; | |
| 876 } else if (scanline == uvMaxH) { | |
| 877 bufferraw2[16 + i] = uLastRow; | |
| 878 bufferraw2[24 + i] = vLastRow; | |
| 879 hasUVLastRow = true; | |
| 880 } else { | |
| 881 bufferraw2[16 + i] = dummyRow; | |
| 882 bufferraw2[24 + i] = dummyRow; | |
| 883 } | |
| 884 } | |
| 885 JDIMENSION scanlinesRead = jpeg_read_raw_data(info, bufferraw, yScanline sToRead); | |
| 886 | |
| 887 if (scanlinesRead == 0) | |
| 888 return false; | |
| 889 | |
| 890 if (hasYLastRow) { | |
| 891 memcpy(&outputY[yMaxH * rowBytesY], yLastRow, yWidth); | |
| 892 } | |
| 893 if (hasUVLastRow) { | |
| 894 memcpy(&outputU[uvMaxH * rowBytesU], uLastRow, uvSize.width()); | |
| 895 memcpy(&outputV[uvMaxH * rowBytesV], vLastRow, uvSize.width()); | |
| 896 } | |
| 897 } | |
| 898 | |
| 899 info->output_scanline = std::min(info->output_scanline, info->output_height) ; | |
| 900 | |
| 901 return true; | |
| 902 } | |
| 903 | |
| 724 bool JPEGImageDecoder::outputScanlines() | 904 bool JPEGImageDecoder::outputScanlines() |
| 725 { | 905 { |
| 726 if (m_frameBufferCache.isEmpty()) | 906 if (m_frameBufferCache.isEmpty()) |
| 727 return false; | 907 return false; |
| 728 | 908 |
| 729 jpeg_decompress_struct* info = m_reader->info(); | 909 jpeg_decompress_struct* info = m_reader->info(); |
| 730 | 910 |
| 911 if (m_imagePlanes.get()) { | |
|
Noel Gordon
2014/07/28 07:29:07
Can you have imagePlanes but be decoding into RGBA
sugoi1
2014/08/19 20:28:47
This shouldn't happen. Once the header is read (us
| |
| 912 return outputRawData(m_reader.get(), m_imagePlanes.get()); | |
| 913 } | |
| 914 | |
| 731 // Initialize the framebuffer if needed. | 915 // Initialize the framebuffer if needed. |
| 732 ImageFrame& buffer = m_frameBufferCache[0]; | 916 ImageFrame& buffer = m_frameBufferCache[0]; |
| 733 if (buffer.status() == ImageFrame::FrameEmpty) { | 917 if (buffer.status() == ImageFrame::FrameEmpty) { |
| 734 ASSERT(info->output_width == static_cast<JDIMENSION>(m_decodedSize.width ())); | 918 ASSERT(info->output_width == static_cast<JDIMENSION>(m_decodedSize.width ())); |
| 735 ASSERT(info->output_height == static_cast<JDIMENSION>(m_decodedSize.heig ht())); | 919 ASSERT(info->output_height == static_cast<JDIMENSION>(m_decodedSize.heig ht())); |
| 736 | 920 |
| 737 if (!buffer.setSize(info->output_width, info->output_height)) | 921 if (!buffer.setSize(info->output_width, info->output_height)) |
| 738 return setFailed(); | 922 return setFailed(); |
| 739 buffer.setStatus(ImageFrame::FramePartial); | 923 buffer.setStatus(ImageFrame::FramePartial); |
| 740 // The buffer is transparent outside the decoded area while the image is | 924 // The buffer is transparent outside the decoded area while the image is |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 798 // has failed. | 982 // has failed. |
| 799 if (!m_reader->decode(*m_data, onlySize) && isAllDataReceived()) | 983 if (!m_reader->decode(*m_data, onlySize) && isAllDataReceived()) |
| 800 setFailed(); | 984 setFailed(); |
| 801 // If we're done decoding the image, we don't need the JPEGImageReader | 985 // If we're done decoding the image, we don't need the JPEGImageReader |
| 802 // anymore. (If we failed, |m_reader| has already been cleared.) | 986 // anymore. (If we failed, |m_reader| has already been cleared.) |
| 803 else if (!m_frameBufferCache.isEmpty() && (m_frameBufferCache[0].status() == ImageFrame::FrameComplete)) | 987 else if (!m_frameBufferCache.isEmpty() && (m_frameBufferCache[0].status() == ImageFrame::FrameComplete)) |
| 804 m_reader.clear(); | 988 m_reader.clear(); |
| 805 } | 989 } |
| 806 | 990 |
| 807 } | 991 } |
| OLD | NEW |