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

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

Powered by Google App Engine
This is Rietveld 408576698