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 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
66 inline J_COLOR_SPACE rgbOutputColorSpace() { return JCS_EXT_RGBA; } | 66 inline J_COLOR_SPACE rgbOutputColorSpace() { return JCS_EXT_RGBA; } |
67 #else // Output little-endian BGRA pixels. | 67 #else // Output little-endian BGRA pixels. |
68 inline J_COLOR_SPACE rgbOutputColorSpace() { return JCS_EXT_BGRA; } | 68 inline J_COLOR_SPACE rgbOutputColorSpace() { return JCS_EXT_BGRA; } |
69 #endif | 69 #endif |
70 inline bool turboSwizzled(J_COLOR_SPACE colorSpace) { return colorSpace == JCS_E XT_RGBA || colorSpace == JCS_EXT_BGRA; } | 70 inline bool turboSwizzled(J_COLOR_SPACE colorSpace) { return colorSpace == JCS_E XT_RGBA || colorSpace == JCS_EXT_BGRA; } |
71 inline bool colorSpaceHasAlpha(J_COLOR_SPACE colorSpace) { return turboSwizzled( colorSpace); } | 71 inline bool colorSpaceHasAlpha(J_COLOR_SPACE colorSpace) { return turboSwizzled( colorSpace); } |
72 #else | 72 #else |
73 inline J_COLOR_SPACE rgbOutputColorSpace() { return JCS_RGB; } | 73 inline J_COLOR_SPACE rgbOutputColorSpace() { return JCS_RGB; } |
74 inline bool colorSpaceHasAlpha(J_COLOR_SPACE) { return false; } | 74 inline bool colorSpaceHasAlpha(J_COLOR_SPACE) { return false; } |
75 #endif | 75 #endif |
76 | 76 |
Noel Gordon
2014/07/25 15:55:01
I think we need to define yuvOutputColorSpace() so
| |
77 #if USE(LOW_QUALITY_IMAGE_NO_JPEG_DITHERING) | 77 #if USE(LOW_QUALITY_IMAGE_NO_JPEG_DITHERING) |
78 inline J_DCT_METHOD dctMethod() { return JDCT_IFAST; } | 78 inline J_DCT_METHOD dctMethod() { return JDCT_IFAST; } |
79 inline J_DITHER_MODE ditherMode() { return JDITHER_NONE; } | 79 inline J_DITHER_MODE ditherMode() { return JDITHER_NONE; } |
80 #else | 80 #else |
81 inline J_DCT_METHOD dctMethod() { return JDCT_ISLOW; } | 81 inline J_DCT_METHOD dctMethod() { return JDCT_ISLOW; } |
82 inline J_DITHER_MODE ditherMode() { return JDITHER_FS; } | 82 inline J_DITHER_MODE ditherMode() { return JDITHER_FS; } |
83 #endif | 83 #endif |
84 | 84 |
85 #if USE(LOW_QUALITY_IMAGE_NO_JPEG_FANCY_UPSAMPLING) | 85 #if USE(LOW_QUALITY_IMAGE_NO_JPEG_FANCY_UPSAMPLING) |
86 inline bool doFancyUpsampling() { return false; } | 86 inline bool doFancyUpsampling() { return false; } |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
235 ignoreProfile = true; | 235 ignoreProfile = true; |
236 | 236 |
237 ASSERT(colorProfile.isEmpty()); | 237 ASSERT(colorProfile.isEmpty()); |
238 if (!ignoreProfile) | 238 if (!ignoreProfile) |
239 colorProfile.append(profileData, profileLength); | 239 colorProfile.append(profileData, profileLength); |
240 free(profile); | 240 free(profile); |
241 #endif | 241 #endif |
242 } | 242 } |
243 #endif | 243 #endif |
244 | 244 |
245 static void computeUVSize(const jpeg_decompress_struct* info, int* width, int* h eight) | |
246 { | |
Noel Gordon
2014/07/25 15:55:01
How about this: make this routine return an IntSiz
sugoi1
2014/07/25 16:56:48
Done.
| |
247 int h = info->cur_comp_info[0]->h_samp_factor; | |
Noel Gordon
2014/07/25 15:55:01
h -> u?
sugoi1
2014/07/25 16:56:48
In this case:
h -> horizontal
v -> vertical
| |
248 int v = info->cur_comp_info[0]->v_samp_factor; | |
249 *width = (info->output_width + h - 1) / h; | |
250 *height = (info->output_height + v - 1) / v; | |
251 } | |
252 | |
245 class JPEGImageReader { | 253 class JPEGImageReader { |
246 WTF_MAKE_FAST_ALLOCATED; | 254 WTF_MAKE_FAST_ALLOCATED; |
247 public: | 255 public: |
248 JPEGImageReader(JPEGImageDecoder* decoder) | 256 JPEGImageReader(JPEGImageDecoder* decoder) |
249 : m_decoder(decoder) | 257 : m_decoder(decoder) |
250 , m_bufferLength(0) | 258 , m_bufferLength(0) |
251 , m_bytesToSkip(0) | 259 , m_bytesToSkip(0) |
252 , m_state(JPEG_HEADER) | 260 , m_state(JPEG_HEADER) |
253 , m_samples(0) | 261 , m_samples(0) |
254 #if USE(QCMSLIB) | 262 #if USE(QCMSLIB) |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
340 if (setjmp(m_err.setjmp_buffer)) | 348 if (setjmp(m_err.setjmp_buffer)) |
341 return m_decoder->setFailed(); | 349 return m_decoder->setFailed(); |
342 | 350 |
343 switch (m_state) { | 351 switch (m_state) { |
344 case JPEG_HEADER: | 352 case JPEG_HEADER: |
345 // Read file parameters with jpeg_read_header(). | 353 // Read file parameters with jpeg_read_header(). |
346 if (jpeg_read_header(&m_info, true) == JPEG_SUSPENDED) | 354 if (jpeg_read_header(&m_info, true) == JPEG_SUSPENDED) |
347 return false; // I/O suspension. | 355 return false; // I/O suspension. |
348 | 356 |
349 switch (m_info.jpeg_color_space) { | 357 switch (m_info.jpeg_color_space) { |
358 case JCS_YCbCr: | |
359 // libjpeg can convert YCbCr image pixels to RGB. | |
360 m_info.out_color_space = rgbOutputColorSpace(); | |
361 if (m_decoder->acceleratedYUVDecoding() | |
Alpha Left Google
2014/07/24 23:30:56
What about by default output RGB and only change o
sugoi1
2014/07/25 02:55:13
Isn't that what's already happening here? RGB is s
Noel Gordon
2014/07/25 15:55:01
The code following here could be moved to it's own
sugoi1
2014/07/25 16:56:48
Already done in current patch
| |
362 && (DCTSIZE == 8) | |
363 && (m_info.num_components == 3) | |
364 && (m_info.scale_denom <= 8) | |
365 && (m_info.cur_comp_info[1]->h_samp_factor == 1) | |
366 && (m_info.cur_comp_info[1]->v_samp_factor == 1) | |
367 && (m_info.cur_comp_info[2]->h_samp_factor == 1) | |
368 && (m_info.cur_comp_info[2]->v_samp_factor == 1)) { | |
369 int h = m_info.cur_comp_info[0]->h_samp_factor; | |
370 int v = m_info.cur_comp_info[0]->v_samp_factor; | |
371 // Only set YUV mode if the format is supported | |
Alpha Left Google
2014/07/24 22:07:27
nit: period at the end of sentence.
sugoi1
2014/07/24 23:16:37
Acknowledged.
| |
372 // 4:4:4 : (h == 1) && (v == 1) | |
373 // 4:4:0 : (h == 1) && (v == 2) | |
374 // 4:2:2 : (h == 2) && (v == 1) | |
375 // 4:2:0 : (h == 2) && (v == 2) | |
376 // 4:1:1 : (h == 4) && (v == 1) | |
377 // 4:1:0 : (h == 4) && (v == 2) | |
378 if (((h == 1) || (h == 2) || (h == 4)) && ((v == 1) || (v == 2))) { | |
379 m_info.out_color_space = JCS_YCbCr; | |
380 m_info.raw_data_out = TRUE; | |
381 } | |
382 } | |
383 break; | |
350 case JCS_GRAYSCALE: | 384 case JCS_GRAYSCALE: |
351 case JCS_RGB: | 385 case JCS_RGB: |
352 case JCS_YCbCr: | 386 // 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(); | 387 m_info.out_color_space = rgbOutputColorSpace(); |
355 #if defined(TURBO_JPEG_RGB_SWIZZLE) | 388 #if defined(TURBO_JPEG_RGB_SWIZZLE) |
356 if (m_info.saw_JFIF_marker) | 389 if (m_info.saw_JFIF_marker) |
357 break; | 390 break; |
358 // FIXME: Swizzle decoding does not support Adobe transform=0 | 391 // FIXME: Swizzle decoding does not support Adobe transform=0 |
359 // images (yet), so revert to using JSC_RGB in that case. | 392 // images (yet), so revert to using JSC_RGB in that case. |
360 if (m_info.saw_Adobe_marker && !m_info.Adobe_transform) | 393 if (m_info.saw_Adobe_marker && !m_info.Adobe_transform) |
361 m_info.out_color_space = JCS_RGB; | 394 m_info.out_color_space = JCS_RGB; |
362 #endif | 395 #endif |
363 break; | 396 break; |
(...skipping 16 matching lines...) Expand all Loading... | |
380 // Calculate and set decoded size. | 413 // Calculate and set decoded size. |
381 m_info.scale_num = m_decoder->desiredScaleNumerator(); | 414 m_info.scale_num = m_decoder->desiredScaleNumerator(); |
382 m_info.scale_denom = scaleDenominator; | 415 m_info.scale_denom = scaleDenominator; |
383 jpeg_calc_output_dimensions(&m_info); | 416 jpeg_calc_output_dimensions(&m_info); |
384 m_decoder->setDecodedSize(m_info.output_width, m_info.output_height) ; | 417 m_decoder->setDecodedSize(m_info.output_width, m_info.output_height) ; |
385 | 418 |
386 m_decoder->setOrientation(readImageOrientation(info())); | 419 m_decoder->setOrientation(readImageOrientation(info())); |
387 | 420 |
388 #if USE(QCMSLIB) | 421 #if USE(QCMSLIB) |
389 // Allow color management of the decoded RGBA pixels if possible. | 422 // Allow color management of the decoded RGBA pixels if possible. |
390 if (!m_decoder->ignoresGammaAndColorProfile()) { | 423 if (!m_decoder->ignoresGammaAndColorProfile()) { |
Noel Gordon
2014/07/25 15:55:01
Most web jpeg images are YCbCr, and many are photo
sugoi1
2014/07/25 17:20:26
Oh yeah, I know about the color profiles, I don't
| |
391 ColorProfile colorProfile; | 424 ColorProfile colorProfile; |
392 readColorProfile(info(), colorProfile); | 425 readColorProfile(info(), colorProfile); |
393 createColorTransform(colorProfile, colorSpaceHasAlpha(m_info.out _color_space)); | 426 createColorTransform(colorProfile, colorSpaceHasAlpha(m_info.out _color_space)); |
394 #if defined(TURBO_JPEG_RGB_SWIZZLE) | 427 #if defined(TURBO_JPEG_RGB_SWIZZLE) |
395 // Input RGBA data to qcms. Note: restored to BGRA on output. | 428 // Input RGBA data to qcms. Note: restored to BGRA on output. |
396 if (m_transform && m_info.out_color_space == JCS_EXT_BGRA) | 429 if (m_transform && m_info.out_color_space == JCS_EXT_BGRA) |
397 m_info.out_color_space = JCS_EXT_RGBA; | 430 m_info.out_color_space = JCS_EXT_RGBA; |
398 #endif | 431 #endif |
399 m_decoder->setHasColorProfile(!!m_transform); | 432 m_decoder->setHasColorProfile(!!m_transform); |
400 } | 433 } |
(...skipping 19 matching lines...) Expand all Loading... | |
420 m_info.do_fancy_upsampling = doFancyUpsampling(); | 453 m_info.do_fancy_upsampling = doFancyUpsampling(); |
421 m_info.enable_2pass_quant = false; | 454 m_info.enable_2pass_quant = false; |
422 m_info.do_block_smoothing = true; | 455 m_info.do_block_smoothing = true; |
423 | 456 |
424 // Make a one-row-high sample array that will go away when done with | 457 // 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 | 458 // 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 | 459 // uses the IJG memory manager, it must be allocated before the call |
427 // to jpeg_start_compress(). | 460 // to jpeg_start_compress(). |
428 // FIXME: note that some output color spaces do not need the samples | 461 // FIXME: note that some output color spaces do not need the samples |
429 // buffer. Remove this allocation for those color spaces. | 462 // 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); | 463 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 | 464 |
432 // Start decompressor. | 465 // Start decompressor. |
433 if (!jpeg_start_decompress(&m_info)) | 466 if (!jpeg_start_decompress(&m_info)) |
434 return false; // I/O suspension. | 467 return false; // I/O suspension. |
435 | 468 |
436 // If this is a progressive JPEG ... | 469 // If this is a progressive JPEG ... |
437 m_state = (m_info.buffered_image) ? JPEG_DECOMPRESS_PROGRESSIVE : JP EG_DECOMPRESS_SEQUENTIAL; | 470 m_state = (m_info.buffered_image) ? JPEG_DECOMPRESS_PROGRESSIVE : JP EG_DECOMPRESS_SEQUENTIAL; |
438 // FALL THROUGH | 471 // FALL THROUGH |
439 | 472 |
440 case JPEG_DECOMPRESS_SEQUENTIAL: | 473 case JPEG_DECOMPRESS_SEQUENTIAL: |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
590 { | 623 { |
591 decoder_source_mgr *src = (decoder_source_mgr *)jd->src; | 624 decoder_source_mgr *src = (decoder_source_mgr *)jd->src; |
592 src->decoder->decoder()->jpegComplete(); | 625 src->decoder->decoder()->jpegComplete(); |
593 } | 626 } |
594 | 627 |
595 JPEGImageDecoder::JPEGImageDecoder(ImageSource::AlphaOption alphaOption, | 628 JPEGImageDecoder::JPEGImageDecoder(ImageSource::AlphaOption alphaOption, |
596 ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption, | 629 ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption, |
597 size_t maxDecodedBytes) | 630 size_t maxDecodedBytes) |
598 : ImageDecoder(alphaOption, gammaAndColorProfileOption, maxDecodedBytes) | 631 : ImageDecoder(alphaOption, gammaAndColorProfileOption, maxDecodedBytes) |
599 , m_hasColorProfile(false) | 632 , m_hasColorProfile(false) |
633 , m_acceleratedYUVDecoding(false) | |
600 { | 634 { |
601 } | 635 } |
602 | 636 |
603 JPEGImageDecoder::~JPEGImageDecoder() | 637 JPEGImageDecoder::~JPEGImageDecoder() |
604 { | 638 { |
605 } | 639 } |
606 | 640 |
607 bool JPEGImageDecoder::isSizeAvailable() | 641 bool JPEGImageDecoder::isSizeAvailable() |
608 { | 642 { |
609 if (!ImageDecoder::isSizeAvailable()) | 643 if (!ImageDecoder::isSizeAvailable()) |
(...skipping 12 matching lines...) Expand all Loading... | |
622 | 656 |
623 setDecodedSize(width, height); | 657 setDecodedSize(width, height); |
624 return true; | 658 return true; |
625 } | 659 } |
626 | 660 |
627 void JPEGImageDecoder::setDecodedSize(unsigned width, unsigned height) | 661 void JPEGImageDecoder::setDecodedSize(unsigned width, unsigned height) |
628 { | 662 { |
629 m_decodedSize = IntSize(width, height); | 663 m_decodedSize = IntSize(width, height); |
630 } | 664 } |
631 | 665 |
666 IntSize JPEGImageDecoder::decodedSize(int component) const | |
667 { | |
Noel Gordon
2014/07/25 15:55:01
Did you consider using a separate function that ex
sugoi1
2014/07/25 16:56:48
Already done in current patch.
| |
668 if (((component == 1) || (component == 2)) && m_reader.get()) { // Asking fo r U or V | |
669 const jpeg_decompress_struct* info = m_reader->info(); | |
670 if (info && (info->out_color_space == JCS_YCbCr)) { | |
671 int w, h; | |
672 computeUVSize(info, &w, &h); | |
673 return IntSize(w, h); | |
674 } | |
675 } | |
676 | |
677 return m_decodedSize; | |
678 } | |
679 | |
632 unsigned JPEGImageDecoder::desiredScaleNumerator() const | 680 unsigned JPEGImageDecoder::desiredScaleNumerator() const |
633 { | 681 { |
634 size_t originalBytes = size().width() * size().height() * 4; | 682 size_t originalBytes = size().width() * size().height() * 4; |
635 if (originalBytes <= m_maxDecodedBytes) { | 683 if (originalBytes <= m_maxDecodedBytes) { |
636 return scaleDenominator; | 684 return scaleDenominator; |
637 } | 685 } |
638 | 686 |
639 // Downsample according to the maximum decoded size. | 687 // Downsample according to the maximum decoded size. |
640 unsigned scaleNumerator = static_cast<unsigned>(floor(sqrt( | 688 unsigned scaleNumerator = static_cast<unsigned>(floor(sqrt( |
641 // MSVC needs explicit parameter type for sqrt(). | 689 // MSVC needs explicit parameter type for sqrt(). |
642 static_cast<float>(m_maxDecodedBytes * scaleDenominator * scaleDenominat or / originalBytes)))); | 690 static_cast<float>(m_maxDecodedBytes * scaleDenominator * scaleDenominat or / originalBytes)))); |
643 | 691 |
644 return scaleNumerator; | 692 return scaleNumerator; |
645 } | 693 } |
646 | 694 |
695 bool JPEGImageDecoder::doAcceleratedYUVDecoding() | |
696 { | |
Noel Gordon
2014/07/25 15:55:01
Would yuvDecode() or decodeToYUV() better describe
sugoi1
2014/07/25 16:56:48
Accelerated has already been removed from the name
| |
697 setAcceleratedYUVDecoding(true); | |
698 PlatformInstrumentation::willDecodeImage("JPEG"); | |
699 decode(false); | |
700 PlatformInstrumentation::didDecodeImage(); | |
701 return !failed(); | |
702 } | |
703 | |
647 ImageFrame* JPEGImageDecoder::frameBufferAtIndex(size_t index) | 704 ImageFrame* JPEGImageDecoder::frameBufferAtIndex(size_t index) |
648 { | 705 { |
649 if (index) | 706 if (index) |
650 return 0; | 707 return 0; |
651 | 708 |
652 if (m_frameBufferCache.isEmpty()) { | 709 if (m_frameBufferCache.isEmpty()) { |
653 m_frameBufferCache.resize(1); | 710 m_frameBufferCache.resize(1); |
654 m_frameBufferCache[0].setPremultiplyAlpha(m_premultiplyAlpha); | 711 m_frameBufferCache[0].setPremultiplyAlpha(m_premultiplyAlpha); |
655 } | 712 } |
656 | 713 |
657 ImageFrame& frame = m_frameBufferCache[0]; | 714 ImageFrame& frame = m_frameBufferCache[0]; |
658 if (frame.status() != ImageFrame::FrameComplete) { | 715 if (frame.status() != ImageFrame::FrameComplete) { |
659 PlatformInstrumentation::willDecodeImage("JPEG"); | 716 PlatformInstrumentation::willDecodeImage("JPEG"); |
660 decode(false); | 717 decode(false); |
661 PlatformInstrumentation::didDecodeImage(); | 718 PlatformInstrumentation::didDecodeImage(); |
662 } | 719 } |
663 | 720 |
664 frame.notifyBitmapIfPixelsChanged(); | 721 frame.notifyBitmapIfPixelsChanged(); |
665 return &frame; | 722 return &frame; |
666 } | 723 } |
667 | 724 |
668 bool JPEGImageDecoder::setFailed() | 725 bool JPEGImageDecoder::setFailed() |
669 { | 726 { |
670 m_reader.clear(); | 727 m_reader.clear(); |
671 return ImageDecoder::setFailed(); | 728 return ImageDecoder::setFailed(); |
672 } | 729 } |
673 | 730 |
731 void JPEGImageDecoder::setDecodingBuffers(OwnPtr<DecodingBuffers>& decodingBuffe rs) | |
732 { | |
733 m_decodingBuffers = decodingBuffers.release(); | |
734 } | |
735 | |
674 template <J_COLOR_SPACE colorSpace> void setPixel(ImageFrame& buffer, ImageFrame ::PixelData* pixel, JSAMPARRAY samples, int column) | 736 template <J_COLOR_SPACE colorSpace> void setPixel(ImageFrame& buffer, ImageFrame ::PixelData* pixel, JSAMPARRAY samples, int column) |
675 { | 737 { |
676 JSAMPLE* jsample = *samples + column * (colorSpace == JCS_RGB ? 3 : 4); | 738 ASSERT_NOT_REACHED(); |
739 } | |
677 | 740 |
678 switch (colorSpace) { | 741 template <> void setPixel<JCS_RGB>(ImageFrame& buffer, ImageFrame::PixelData* pi xel, JSAMPARRAY samples, int column) |
Noel Gordon
2014/07/25 15:55:01
The setPixel() code from lines 736-762 changed, I'
sugoi1
2014/07/25 16:56:48
This is cleanup. Using template arguments in condi
| |
679 case JCS_RGB: | 742 { |
680 buffer.setRGBARaw(pixel, jsample[0], jsample[1], jsample[2], 255); | 743 JSAMPLE* jsample = *samples + column * 3; |
681 break; | 744 buffer.setRGBARaw(pixel, jsample[0], jsample[1], jsample[2], 255); |
682 case JCS_CMYK: | 745 } |
683 // Source is 'Inverted CMYK', output is RGB. | 746 |
684 // See: http://www.easyrgb.com/math.php?MATH=M12#text12 | 747 template <> void setPixel<JCS_CMYK>(ImageFrame& buffer, ImageFrame::PixelData* p ixel, JSAMPARRAY samples, int column) |
685 // Or: http://www.ilkeratalay.com/colorspacesfaq.php#rgb | 748 { |
686 // From CMYK to CMY: | 749 JSAMPLE* jsample = *samples + column * 4; |
687 // X = X * (1 - K ) + K [for X = C, M, or Y] | 750 |
688 // Thus, from Inverted CMYK to CMY is: | 751 // Source is 'Inverted CMYK', output is RGB. |
689 // X = (1-iX) * (1 - (1-iK)) + (1-iK) => 1 - iX*iK | 752 // See: http://www.easyrgb.com/math.php?MATH=M12#text12 |
690 // From CMY (0..1) to RGB (0..1): | 753 // Or: http://www.ilkeratalay.com/colorspacesfaq.php#rgb |
691 // R = 1 - C => 1 - (1 - iC*iK) => iC*iK [G and B similar] | 754 // From CMYK to CMY: |
692 unsigned k = jsample[3]; | 755 // 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); | 756 // Thus, from Inverted CMYK to CMY is: |
694 break; | 757 // X = (1-iX) * (1 - (1-iK)) + (1-iK) => 1 - iX*iK |
695 } | 758 // From CMY (0..1) to RGB (0..1): |
759 // R = 1 - C => 1 - (1 - iC*iK) => iC*iK [G and B similar] | |
760 unsigned k = jsample[3]; | |
761 buffer.setRGBARaw(pixel, jsample[0] * k / 255, jsample[1] * k / 255, jsample [2] * k / 255, 255); | |
696 } | 762 } |
697 | 763 |
698 template <J_COLOR_SPACE colorSpace> bool outputRows(JPEGImageReader* reader, Ima geFrame& buffer) | 764 template <J_COLOR_SPACE colorSpace> bool outputRows(JPEGImageReader* reader, Ima geFrame& buffer) |
699 { | 765 { |
700 JSAMPARRAY samples = reader->samples(); | 766 JSAMPARRAY samples = reader->samples(); |
701 jpeg_decompress_struct* info = reader->info(); | 767 jpeg_decompress_struct* info = reader->info(); |
702 int width = info->output_width; | 768 int width = info->output_width; |
703 | 769 |
704 while (info->output_scanline < info->output_height) { | 770 while (info->output_scanline < info->output_height) { |
705 // jpeg_read_scanlines will increase the scanline counter, so we | 771 // jpeg_read_scanlines will increase the scanline counter, so we |
706 // save the scanline before calling it. | 772 // save the scanline before calling it. |
707 int y = info->output_scanline; | 773 int y = info->output_scanline; |
708 // Request one scanline: returns 0 or 1 scanlines. | 774 // Request one scanline: returns 0 or 1 scanlines. |
709 if (jpeg_read_scanlines(info, samples, 1) != 1) | 775 if (jpeg_read_scanlines(info, samples, 1) != 1) |
710 return false; | 776 return false; |
711 #if USE(QCMSLIB) | 777 #if USE(QCMSLIB) |
712 if (reader->colorTransform() && colorSpace == JCS_RGB) | 778 if (reader->colorTransform() && colorSpace == JCS_RGB) |
713 qcms_transform_data(reader->colorTransform(), *samples, *samples, wi dth); | 779 qcms_transform_data(reader->colorTransform(), *samples, *samples, wi dth); |
714 #endif | 780 #endif |
715 ImageFrame::PixelData* pixel = buffer.getAddr(0, y); | 781 ImageFrame::PixelData* pixel = buffer.getAddr(0, y); |
716 for (int x = 0; x < width; ++pixel, ++x) | 782 for (int x = 0; x < width; ++pixel, ++x) |
717 setPixel<colorSpace>(buffer, pixel, samples, x); | 783 setPixel<colorSpace>(buffer, pixel, samples, x); |
718 } | 784 } |
719 | 785 |
720 buffer.setPixelsChanged(true); | 786 buffer.setPixelsChanged(true); |
721 return true; | 787 return true; |
722 } | 788 } |
723 | 789 |
790 static bool outputRawData(JPEGImageReader* reader, DecodingBuffers* decodingBuff ers) | |
791 { | |
792 JSAMPARRAY samples = reader->samples(); | |
793 jpeg_decompress_struct* info = reader->info(); | |
794 JSAMPARRAY bufferraw[3]; | |
795 JSAMPROW bufferraw2[32]; | |
796 bufferraw[0] = &bufferraw2[0]; | |
Alpha Left Google
2014/07/24 22:07:27
Please document why.
| |
797 bufferraw[1] = &bufferraw2[16]; | |
798 bufferraw[2] = &bufferraw2[24]; | |
799 int yWidth = info->output_width; | |
800 int yHeight = info->output_height; | |
801 int yMaxH = yHeight - 1; | |
802 int v = info->cur_comp_info[0]->v_samp_factor; | |
803 int uvWidth(0), uvHeight(0); | |
804 computeUVSize(info, &uvWidth, &uvHeight); | |
805 int uvMaxH = uvHeight - 1; | |
806 JSAMPROW outputY = static_cast<JSAMPROW>(decodingBuffers->getPlane(0)); | |
807 JSAMPROW outputU = static_cast<JSAMPROW>(decodingBuffers->getPlane(1)); | |
808 JSAMPROW outputV = static_cast<JSAMPROW>(decodingBuffers->getPlane(2)); | |
809 size_t rowBytesY = decodingBuffers->getRowBytes(0); | |
810 size_t rowBytesU = decodingBuffers->getRowBytes(1); | |
811 size_t rowBytesV = decodingBuffers->getRowBytes(2); | |
812 | |
813 int scanlinesToRead = DCTSIZE * v; | |
Alpha Left Google
2014/07/24 22:07:27
nit: This should be yScanlinesToRead.
sugoi1
2014/07/24 23:16:36
Acknowledged.
| |
814 JSAMPROW yLastRow = *samples; | |
815 JSAMPROW uLastRow = yLastRow + 2 * yWidth; | |
816 JSAMPROW vLastRow = uLastRow + 2 * yWidth; | |
817 JSAMPROW dummyRow = vLastRow + 2 * yWidth; | |
818 | |
819 while (info->output_scanline < info->output_height) { | |
820 // Request 8 or 16 scanlines: returns 0 or more scanlines. | |
821 bool hasYLastRow(false), hasUVLastRow(false); | |
822 for (int i = 0; i < scanlinesToRead; ++i) { | |
Alpha Left Google
2014/07/24 22:07:27
nit: Add a comment that this is reading the Y scan
sugoi1
2014/07/24 23:16:37
Acknowledged.
| |
823 int scanline = (info->output_scanline + i); | |
824 if (scanline < yMaxH) { | |
825 bufferraw2[i] = &outputY[scanline * rowBytesY]; | |
826 } else if (scanline == yMaxH) { | |
827 bufferraw2[i] = yLastRow; | |
828 hasYLastRow = true; | |
829 } else { | |
830 bufferraw2[i] = dummyRow; | |
831 } | |
832 } | |
833 int scaledScanline = info->output_scanline / v; | |
834 for (int i = 0; i < 8; ++i) { | |
Alpha Left Google
2014/07/24 22:07:27
Add a comment saying this is reading the UV scanli
sugoi1
2014/07/24 23:16:36
Acknowledged.
| |
835 int scanline = (scaledScanline + i); | |
836 if (scanline < uvMaxH) { | |
837 bufferraw2[16 + i] = &outputU[scanline * rowBytesU]; | |
838 bufferraw2[24 + i] = &outputV[scanline * rowBytesV]; | |
839 } else if (scanline == uvMaxH) { | |
840 bufferraw2[16 + i] = uLastRow; | |
841 bufferraw2[24 + i] = vLastRow; | |
842 hasUVLastRow = true; | |
843 } else { | |
844 bufferraw2[16 + i] = dummyRow; | |
845 bufferraw2[24 + i] = dummyRow; | |
846 } | |
847 } | |
848 JDIMENSION scanlinesRead = jpeg_read_raw_data(info, bufferraw, scanlines ToRead); | |
849 | |
850 if (scanlinesRead == 0) | |
851 return false; | |
852 | |
853 if (hasYLastRow) { | |
854 memcpy(&outputY[yMaxH * rowBytesY], yLastRow, yWidth); | |
Noel Gordon
2014/07/25 15:55:01
memcpy: it's perhaps the best way to kill decoding
sugoi1
2014/07/25 16:56:48
This is only the last row of a jpeg image, if the
| |
855 } | |
856 if (hasUVLastRow) { | |
857 memcpy(&outputU[uvMaxH * rowBytesU], uLastRow, uvWidth); | |
858 memcpy(&outputV[uvMaxH * rowBytesV], vLastRow, uvWidth); | |
859 } | |
860 } | |
861 | |
862 info->output_scanline = std::min(info->output_scanline, info->output_height) ; | |
863 | |
864 return true; | |
865 } | |
866 | |
724 bool JPEGImageDecoder::outputScanlines() | 867 bool JPEGImageDecoder::outputScanlines() |
725 { | 868 { |
726 if (m_frameBufferCache.isEmpty()) | 869 if (m_frameBufferCache.isEmpty()) |
727 return false; | 870 return false; |
Noel Gordon
2014/07/25 15:55:02
If you pass this point and go on to yuv decode, a
| |
728 | 871 |
729 jpeg_decompress_struct* info = m_reader->info(); | 872 jpeg_decompress_struct* info = m_reader->info(); |
730 | 873 |
874 if ((JCS_YCbCr == info->out_color_space) && (m_decodingBuffers.get())) { | |
Alpha Left Google
2014/07/24 22:07:27
If you have set YUV decoding but didn't assign the
sugoi1
2014/07/24 23:16:37
If it fails for any reason, the caller should fall
| |
875 return outputRawData(m_reader.get(), m_decodingBuffers.get()); | |
876 } | |
877 | |
731 // Initialize the framebuffer if needed. | 878 // Initialize the framebuffer if needed. |
732 ImageFrame& buffer = m_frameBufferCache[0]; | 879 ImageFrame& buffer = m_frameBufferCache[0]; |
733 if (buffer.status() == ImageFrame::FrameEmpty) { | 880 if (buffer.status() == ImageFrame::FrameEmpty) { |
734 ASSERT(info->output_width == static_cast<JDIMENSION>(m_decodedSize.width ())); | 881 ASSERT(info->output_width == static_cast<JDIMENSION>(m_decodedSize.width ())); |
735 ASSERT(info->output_height == static_cast<JDIMENSION>(m_decodedSize.heig ht())); | 882 ASSERT(info->output_height == static_cast<JDIMENSION>(m_decodedSize.heig ht())); |
736 | 883 |
737 if (!buffer.setSize(info->output_width, info->output_height)) | 884 if (!buffer.setSize(info->output_width, info->output_height)) |
738 return setFailed(); | 885 return setFailed(); |
739 buffer.setStatus(ImageFrame::FramePartial); | 886 buffer.setStatus(ImageFrame::FramePartial); |
740 // The buffer is transparent outside the decoded area while the image is | 887 // 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. | 945 // has failed. |
799 if (!m_reader->decode(*m_data, onlySize) && isAllDataReceived()) | 946 if (!m_reader->decode(*m_data, onlySize) && isAllDataReceived()) |
800 setFailed(); | 947 setFailed(); |
801 // If we're done decoding the image, we don't need the JPEGImageReader | 948 // If we're done decoding the image, we don't need the JPEGImageReader |
802 // anymore. (If we failed, |m_reader| has already been cleared.) | 949 // anymore. (If we failed, |m_reader| has already been cleared.) |
803 else if (!m_frameBufferCache.isEmpty() && (m_frameBufferCache[0].status() == ImageFrame::FrameComplete)) | 950 else if (!m_frameBufferCache.isEmpty() && (m_frameBufferCache[0].status() == ImageFrame::FrameComplete)) |
804 m_reader.clear(); | 951 m_reader.clear(); |
805 } | 952 } |
806 | 953 |
807 } | 954 } |
OLD | NEW |