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 * This library is free software; you can redistribute it and/or | 9 * This library is free software; you can redistribute it and/or |
10 * modify it under the terms of the GNU Lesser General Public | 10 * modify it under the terms of the GNU Lesser General Public |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
42 #include "wtf/PtrUtil.h" | 42 #include "wtf/PtrUtil.h" |
43 #include "wtf/Threading.h" | 43 #include "wtf/Threading.h" |
44 #include <memory> | 44 #include <memory> |
45 | 45 |
46 extern "C" { | 46 extern "C" { |
47 #include <stdio.h> // jpeglib.h needs stdio FILE. | 47 #include <stdio.h> // jpeglib.h needs stdio FILE. |
48 #include "jpeglib.h" | 48 #include "jpeglib.h" |
49 #if USE(ICCJPEG) | 49 #if USE(ICCJPEG) |
50 #include "iccjpeg.h" | 50 #include "iccjpeg.h" |
51 #endif | 51 #endif |
| 52 #if USE(QCMSLIB) |
| 53 #include "qcms.h" |
| 54 #endif |
52 #include <setjmp.h> | 55 #include <setjmp.h> |
53 } | 56 } |
54 | 57 |
55 #if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN) | 58 #if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN) |
56 #error Blink assumes a little-endian target. | 59 #error Blink assumes a little-endian target. |
57 #endif | 60 #endif |
58 | 61 |
59 #if defined(JCS_ALPHA_EXTENSIONS) | 62 #if defined(JCS_ALPHA_EXTENSIONS) |
60 #define TURBO_JPEG_RGB_SWIZZLE | 63 #define TURBO_JPEG_RGB_SWIZZLE |
61 #if SK_B32_SHIFT // Output little-endian RGBA pixels (Android). | 64 #if SK_B32_SHIFT // Output little-endian RGBA pixels (Android). |
62 inline J_COLOR_SPACE rgbOutputColorSpace() { | 65 inline J_COLOR_SPACE rgbOutputColorSpace() { |
63 return JCS_EXT_RGBA; | 66 return JCS_EXT_RGBA; |
64 } | 67 } |
65 #else // Output little-endian BGRA pixels. | 68 #else // Output little-endian BGRA pixels. |
66 inline J_COLOR_SPACE rgbOutputColorSpace() { | 69 inline J_COLOR_SPACE rgbOutputColorSpace() { |
67 return JCS_EXT_BGRA; | 70 return JCS_EXT_BGRA; |
68 } | 71 } |
69 #endif | 72 #endif |
70 inline bool turboSwizzled(J_COLOR_SPACE colorSpace) { | 73 inline bool turboSwizzled(J_COLOR_SPACE colorSpace) { |
71 return colorSpace == JCS_EXT_RGBA || colorSpace == JCS_EXT_BGRA; | 74 return colorSpace == JCS_EXT_RGBA || colorSpace == JCS_EXT_BGRA; |
72 } | 75 } |
| 76 inline bool colorSpaceHasAlpha(J_COLOR_SPACE colorSpace) { |
| 77 return turboSwizzled(colorSpace); |
| 78 } |
73 #else | 79 #else |
74 inline J_COLOR_SPACE rgbOutputColorSpace() { | 80 inline J_COLOR_SPACE rgbOutputColorSpace() { |
75 return JCS_RGB; | 81 return JCS_RGB; |
76 } | 82 } |
| 83 inline bool colorSpaceHasAlpha(J_COLOR_SPACE) { |
| 84 return false; |
| 85 } |
77 #endif | 86 #endif |
78 | 87 |
79 namespace { | 88 namespace { |
80 | 89 |
81 const int exifMarker = JPEG_APP0 + 1; | 90 const int exifMarker = JPEG_APP0 + 1; |
82 | 91 |
83 // JPEG only supports a denominator of 8. | 92 // JPEG only supports a denominator of 8. |
84 const unsigned scaleDenominator = 8; | 93 const unsigned scaleDenominator = 8; |
85 | 94 |
86 } // namespace | 95 } // namespace |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
299 m_src.pub.fill_input_buffer = fill_input_buffer; | 308 m_src.pub.fill_input_buffer = fill_input_buffer; |
300 m_src.pub.skip_input_data = skip_input_data; | 309 m_src.pub.skip_input_data = skip_input_data; |
301 m_src.pub.resync_to_restart = jpeg_resync_to_restart; | 310 m_src.pub.resync_to_restart = jpeg_resync_to_restart; |
302 m_src.pub.term_source = term_source; | 311 m_src.pub.term_source = term_source; |
303 m_src.reader = this; | 312 m_src.reader = this; |
304 | 313 |
305 #if USE(ICCJPEG) | 314 #if USE(ICCJPEG) |
306 // Retain ICC color profile markers for color management. | 315 // Retain ICC color profile markers for color management. |
307 setup_read_icc_profile(&m_info); | 316 setup_read_icc_profile(&m_info); |
308 #endif | 317 #endif |
309 | |
310 // Keep APP1 blocks, for obtaining exif data. | 318 // Keep APP1 blocks, for obtaining exif data. |
311 jpeg_save_markers(&m_info, exifMarker, 0xFFFF); | 319 jpeg_save_markers(&m_info, exifMarker, 0xFFFF); |
312 } | 320 } |
313 | 321 |
314 ~JPEGImageReader() { jpeg_destroy_decompress(&m_info); } | 322 ~JPEGImageReader() { jpeg_destroy_decompress(&m_info); } |
315 | 323 |
316 void skipBytes(long numBytes) { | 324 void skipBytes(long numBytes) { |
317 if (numBytes <= 0) | 325 if (numBytes <= 0) |
318 return; | 326 return; |
319 | 327 |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
446 m_decoder->setDecodedSize(m_info.output_width, m_info.output_height); | 454 m_decoder->setDecodedSize(m_info.output_width, m_info.output_height); |
447 | 455 |
448 m_decoder->setOrientation(readImageOrientation(info())); | 456 m_decoder->setOrientation(readImageOrientation(info())); |
449 | 457 |
450 // Allow color management of the decoded RGBA pixels if possible. | 458 // Allow color management of the decoded RGBA pixels if possible. |
451 if (!m_decoder->ignoresGammaAndColorProfile()) { | 459 if (!m_decoder->ignoresGammaAndColorProfile()) { |
452 #if USE(ICCJPEG) | 460 #if USE(ICCJPEG) |
453 JOCTET* profile = nullptr; | 461 JOCTET* profile = nullptr; |
454 unsigned profileLength = 0; | 462 unsigned profileLength = 0; |
455 if (read_icc_profile(info(), &profile, &profileLength)) { | 463 if (read_icc_profile(info(), &profile, &profileLength)) { |
456 decoder()->setColorSpaceAndComputeTransform( | 464 decoder()->setColorProfileAndComputeTransform( |
457 reinterpret_cast<char*>(profile), profileLength, | 465 reinterpret_cast<char*>(profile), profileLength, |
| 466 colorSpaceHasAlpha(info()->out_color_space), |
458 false /* useSRGB */); | 467 false /* useSRGB */); |
459 free(profile); | 468 free(profile); |
460 } | 469 } |
461 #endif // USE(ICCJPEG) | 470 #endif // USE(ICCJPEG) |
462 #if USE(SKCOLORXFORM) | 471 #if USE(QCMSLIB) |
463 if (decoder()->colorTransform()) { | 472 if (decoder()->colorTransform()) { |
464 overrideColorSpace = JCS_UNKNOWN; | 473 overrideColorSpace = JCS_UNKNOWN; |
| 474 #if defined(TURBO_JPEG_RGB_SWIZZLE) |
| 475 // Input RGBA data to qcms. Note: restored to BGRA on output. |
| 476 if (m_info.out_color_space == JCS_EXT_BGRA) |
| 477 m_info.out_color_space = JCS_EXT_RGBA; |
| 478 #endif // defined(TURBO_JPEG_RGB_SWIZZLE) |
465 } | 479 } |
466 #endif // USE(SKCOLORXFORM) | 480 #endif // USE(QCMSLIB) |
467 } | 481 } |
468 if (overrideColorSpace == JCS_YCbCr) { | 482 if (overrideColorSpace == JCS_YCbCr) { |
469 m_info.out_color_space = JCS_YCbCr; | 483 m_info.out_color_space = JCS_YCbCr; |
470 m_info.raw_data_out = TRUE; | 484 m_info.raw_data_out = TRUE; |
471 m_uvSize = computeYUVSize( | 485 m_uvSize = computeYUVSize( |
472 &m_info, | 486 &m_info, |
473 1); // U size and V size have to be the same if we got here | 487 1); // U size and V size have to be the same if we got here |
474 } | 488 } |
475 | 489 |
476 // Don't allocate a giant and superfluous memory buffer when the | 490 // Don't allocate a giant and superfluous memory buffer when the |
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
793 } | 807 } |
794 | 808 |
795 template <J_COLOR_SPACE colorSpace> | 809 template <J_COLOR_SPACE colorSpace> |
796 void setPixel(ImageFrame& buffer, | 810 void setPixel(ImageFrame& buffer, |
797 ImageFrame::PixelData* pixel, | 811 ImageFrame::PixelData* pixel, |
798 JSAMPARRAY samples, | 812 JSAMPARRAY samples, |
799 int column) { | 813 int column) { |
800 ASSERT_NOT_REACHED(); | 814 ASSERT_NOT_REACHED(); |
801 } | 815 } |
802 | 816 |
803 // Used only for debugging with libjpeg (instead of libjpeg-turbo). | |
804 template <> | 817 template <> |
805 void setPixel<JCS_RGB>(ImageFrame& buffer, | 818 void setPixel<JCS_RGB>(ImageFrame& buffer, |
806 ImageFrame::PixelData* pixel, | 819 ImageFrame::PixelData* pixel, |
807 JSAMPARRAY samples, | 820 JSAMPARRAY samples, |
808 int column) { | 821 int column) { |
809 JSAMPLE* jsample = *samples + column * 3; | 822 JSAMPLE* jsample = *samples + column * 3; |
810 buffer.setRGBARaw(pixel, jsample[0], jsample[1], jsample[2], 255); | 823 buffer.setRGBARaw(pixel, jsample[0], jsample[1], jsample[2], 255); |
811 } | 824 } |
812 | 825 |
813 template <> | 826 template <> |
(...skipping 10 matching lines...) Expand all Loading... |
824 // X = X * (1 - K ) + K [for X = C, M, or Y] | 837 // X = X * (1 - K ) + K [for X = C, M, or Y] |
825 // Thus, from Inverted CMYK to CMY is: | 838 // Thus, from Inverted CMYK to CMY is: |
826 // X = (1-iX) * (1 - (1-iK)) + (1-iK) => 1 - iX*iK | 839 // X = (1-iX) * (1 - (1-iK)) + (1-iK) => 1 - iX*iK |
827 // From CMY (0..1) to RGB (0..1): | 840 // From CMY (0..1) to RGB (0..1): |
828 // R = 1 - C => 1 - (1 - iC*iK) => iC*iK [G and B similar] | 841 // R = 1 - C => 1 - (1 - iC*iK) => iC*iK [G and B similar] |
829 unsigned k = jsample[3]; | 842 unsigned k = jsample[3]; |
830 buffer.setRGBARaw(pixel, jsample[0] * k / 255, jsample[1] * k / 255, | 843 buffer.setRGBARaw(pixel, jsample[0] * k / 255, jsample[1] * k / 255, |
831 jsample[2] * k / 255, 255); | 844 jsample[2] * k / 255, 255); |
832 } | 845 } |
833 | 846 |
834 // Used only for JCS_CMYK and JCS_RGB output. Note that JCS_RGB is used only | |
835 // for debugging with libjpeg (instead of libjpeg-turbo). | |
836 template <J_COLOR_SPACE colorSpace> | 847 template <J_COLOR_SPACE colorSpace> |
837 bool outputRows(JPEGImageReader* reader, ImageFrame& buffer) { | 848 bool outputRows(JPEGImageReader* reader, ImageFrame& buffer) { |
838 JSAMPARRAY samples = reader->samples(); | 849 JSAMPARRAY samples = reader->samples(); |
839 jpeg_decompress_struct* info = reader->info(); | 850 jpeg_decompress_struct* info = reader->info(); |
840 int width = info->output_width; | 851 int width = info->output_width; |
841 | 852 |
842 while (info->output_scanline < info->output_height) { | 853 while (info->output_scanline < info->output_height) { |
843 // jpeg_read_scanlines will increase the scanline counter, so we | 854 // jpeg_read_scanlines will increase the scanline counter, so we |
844 // save the scanline before calling it. | 855 // save the scanline before calling it. |
845 int y = info->output_scanline; | 856 int y = info->output_scanline; |
846 // Request one scanline: returns 0 or 1 scanlines. | 857 // Request one scanline: returns 0 or 1 scanlines. |
847 if (jpeg_read_scanlines(info, samples, 1) != 1) | 858 if (jpeg_read_scanlines(info, samples, 1) != 1) |
848 return false; | 859 return false; |
849 | 860 #if USE(QCMSLIB) |
| 861 if (reader->decoder()->colorTransform() && colorSpace == JCS_RGB) |
| 862 qcms_transform_data(reader->decoder()->colorTransform(), *samples, |
| 863 *samples, width); |
| 864 #endif |
850 ImageFrame::PixelData* pixel = buffer.getAddr(0, y); | 865 ImageFrame::PixelData* pixel = buffer.getAddr(0, y); |
851 for (int x = 0; x < width; ++pixel, ++x) | 866 for (int x = 0; x < width; ++pixel, ++x) |
852 setPixel<colorSpace>(buffer, pixel, samples, x); | 867 setPixel<colorSpace>(buffer, pixel, samples, x); |
853 | |
854 #if USE(SKCOLORXFORM) | |
855 SkColorSpaceXform* xform = reader->decoder()->colorTransform(); | |
856 if (JCS_RGB == colorSpace && xform) { | |
857 ImageFrame::PixelData* row = buffer.getAddr(0, y); | |
858 xform->apply(xformColorFormat(), row, xformColorFormat(), row, width, | |
859 kOpaque_SkAlphaType); | |
860 } | |
861 #endif | |
862 } | 868 } |
863 | 869 |
864 buffer.setPixelsChanged(true); | 870 buffer.setPixelsChanged(true); |
865 return true; | 871 return true; |
866 } | 872 } |
867 | 873 |
868 static bool outputRawData(JPEGImageReader* reader, ImagePlanes* imagePlanes) { | 874 static bool outputRawData(JPEGImageReader* reader, ImagePlanes* imagePlanes) { |
869 JSAMPARRAY samples = reader->samples(); | 875 JSAMPARRAY samples = reader->samples(); |
870 jpeg_decompress_struct* info = reader->info(); | 876 jpeg_decompress_struct* info = reader->info(); |
871 | 877 |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
952 buffer.setOriginalFrameRect(IntRect(IntPoint(), size())); | 958 buffer.setOriginalFrameRect(IntRect(IntPoint(), size())); |
953 } | 959 } |
954 | 960 |
955 #if defined(TURBO_JPEG_RGB_SWIZZLE) | 961 #if defined(TURBO_JPEG_RGB_SWIZZLE) |
956 if (turboSwizzled(info->out_color_space)) { | 962 if (turboSwizzled(info->out_color_space)) { |
957 while (info->output_scanline < info->output_height) { | 963 while (info->output_scanline < info->output_height) { |
958 unsigned char* row = reinterpret_cast_ptr<unsigned char*>( | 964 unsigned char* row = reinterpret_cast_ptr<unsigned char*>( |
959 buffer.getAddr(0, info->output_scanline)); | 965 buffer.getAddr(0, info->output_scanline)); |
960 if (jpeg_read_scanlines(info, &row, 1) != 1) | 966 if (jpeg_read_scanlines(info, &row, 1) != 1) |
961 return false; | 967 return false; |
962 | 968 #if USE(QCMSLIB) |
963 #if USE(SKCOLORXFORM) | 969 if (qcms_transform* transform = colorTransform()) |
964 SkColorSpaceXform* xform = colorTransform(); | 970 qcms_transform_data_type(transform, row, row, info->output_width, |
965 if (xform) { | 971 rgbOutputColorSpace() == JCS_EXT_BGRA |
966 xform->apply(xformColorFormat(), row, xformColorFormat(), row, | 972 ? QCMS_OUTPUT_BGRX |
967 info->output_width, kOpaque_SkAlphaType); | 973 : QCMS_OUTPUT_RGBX); |
968 } | |
969 #endif | 974 #endif |
970 } | 975 } |
971 buffer.setPixelsChanged(true); | 976 buffer.setPixelsChanged(true); |
972 return true; | 977 return true; |
973 } | 978 } |
974 #endif | 979 #endif |
975 | 980 |
976 switch (info->out_color_space) { | 981 switch (info->out_color_space) { |
977 case JCS_RGB: | 982 case JCS_RGB: |
978 return outputRows<JCS_RGB>(m_reader.get(), buffer); | 983 return outputRows<JCS_RGB>(m_reader.get(), buffer); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1013 // has failed. | 1018 // has failed. |
1014 if (!m_reader->decode(onlySize) && isAllDataReceived()) | 1019 if (!m_reader->decode(onlySize) && isAllDataReceived()) |
1015 setFailed(); | 1020 setFailed(); |
1016 | 1021 |
1017 // If decoding is done or failed, we don't need the JPEGImageReader anymore. | 1022 // If decoding is done or failed, we don't need the JPEGImageReader anymore. |
1018 if (isComplete(this, onlySize) || failed()) | 1023 if (isComplete(this, onlySize) || failed()) |
1019 m_reader.reset(); | 1024 m_reader.reset(); |
1020 } | 1025 } |
1021 | 1026 |
1022 } // namespace blink | 1027 } // namespace blink |
OLD | NEW |