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

Side by Side Diff: third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp

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

Powered by Google App Engine
This is Rietveld 408576698