blob: 43d54a86c78f8f5be78bf9717e5c87c97c9c3731 [file] [log] [blame]
msarette16b04a2015-04-15 07:32:19 -07001/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkCodec.h"
9#include "SkJpegCodec.h"
10#include "SkJpegDecoderMgr.h"
msarette16b04a2015-04-15 07:32:19 -070011#include "SkCodecPriv.h"
12#include "SkColorPriv.h"
raftias54761282016-12-01 13:44:07 -050013#include "SkColorSpace_Base.h"
msarette16b04a2015-04-15 07:32:19 -070014#include "SkStream.h"
15#include "SkTemplates.h"
16#include "SkTypes.h"
17
msarett1c8a5872015-07-07 08:50:01 -070018// stdio is needed for libjpeg-turbo
msarette16b04a2015-04-15 07:32:19 -070019#include <stdio.h>
msarettc1d03122016-03-25 08:58:55 -070020#include "SkJpegUtility.h"
msarette16b04a2015-04-15 07:32:19 -070021
mtkleindc90b532016-07-28 14:45:28 -070022// This warning triggers false postives way too often in here.
23#if defined(__GNUC__) && !defined(__clang__)
24 #pragma GCC diagnostic ignored "-Wclobbered"
25#endif
26
msarette16b04a2015-04-15 07:32:19 -070027extern "C" {
28 #include "jerror.h"
msarette16b04a2015-04-15 07:32:19 -070029 #include "jpeglib.h"
30}
31
scroggodb30be22015-12-08 18:54:13 -080032bool SkJpegCodec::IsJpeg(const void* buffer, size_t bytesRead) {
msarette16b04a2015-04-15 07:32:19 -070033 static const uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF };
scroggodb30be22015-12-08 18:54:13 -080034 return bytesRead >= 3 && !memcmp(buffer, jpegSig, sizeof(jpegSig));
msarette16b04a2015-04-15 07:32:19 -070035}
36
msarett0e6274f2016-03-21 08:04:40 -070037static uint32_t get_endian_int(const uint8_t* data, bool littleEndian) {
38 if (littleEndian) {
39 return (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | (data[0]);
40 }
41
42 return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3]);
43}
44
45const uint32_t kExifHeaderSize = 14;
msarett0e6274f2016-03-21 08:04:40 -070046const uint32_t kExifMarker = JPEG_APP0 + 1;
msarett0e6274f2016-03-21 08:04:40 -070047
48static bool is_orientation_marker(jpeg_marker_struct* marker, SkCodec::Origin* orientation) {
49 if (kExifMarker != marker->marker || marker->data_length < kExifHeaderSize) {
50 return false;
51 }
52
53 const uint8_t* data = marker->data;
54 static const uint8_t kExifSig[] { 'E', 'x', 'i', 'f', '\0' };
55 if (memcmp(data, kExifSig, sizeof(kExifSig))) {
56 return false;
57 }
58
59 bool littleEndian;
60 if (!is_valid_endian_marker(data + 6, &littleEndian)) {
61 return false;
62 }
63
64 // Get the offset from the start of the marker.
65 // Account for 'E', 'x', 'i', 'f', '\0', '<fill byte>'.
66 uint32_t offset = get_endian_int(data + 10, littleEndian);
67 offset += sizeof(kExifSig) + 1;
68
69 // Require that the marker is at least large enough to contain the number of entries.
70 if (marker->data_length < offset + 2) {
71 return false;
72 }
73 uint32_t numEntries = get_endian_short(data + offset, littleEndian);
74
75 // Tag (2 bytes), Datatype (2 bytes), Number of elements (4 bytes), Data (4 bytes)
76 const uint32_t kEntrySize = 12;
77 numEntries = SkTMin(numEntries, (marker->data_length - offset - 2) / kEntrySize);
78
79 // Advance the data to the start of the entries.
80 data += offset + 2;
81
82 const uint16_t kOriginTag = 0x112;
83 const uint16_t kOriginType = 3;
84 for (uint32_t i = 0; i < numEntries; i++, data += kEntrySize) {
85 uint16_t tag = get_endian_short(data, littleEndian);
86 uint16_t type = get_endian_short(data + 2, littleEndian);
87 uint32_t count = get_endian_int(data + 4, littleEndian);
88 if (kOriginTag == tag && kOriginType == type && 1 == count) {
89 uint16_t val = get_endian_short(data + 8, littleEndian);
90 if (0 < val && val <= SkCodec::kLast_Origin) {
91 *orientation = (SkCodec::Origin) val;
92 return true;
93 }
94 }
95 }
96
97 return false;
98}
99
100static SkCodec::Origin get_exif_orientation(jpeg_decompress_struct* dinfo) {
101 SkCodec::Origin orientation;
102 for (jpeg_marker_struct* marker = dinfo->marker_list; marker; marker = marker->next) {
103 if (is_orientation_marker(marker, &orientation)) {
104 return orientation;
105 }
106 }
107
108 return SkCodec::kDefault_Origin;
109}
110
111static bool is_icc_marker(jpeg_marker_struct* marker) {
Matt Sarett5df93de2017-03-22 21:52:47 +0000112 if (kICCMarker != marker->marker || marker->data_length < kICCMarkerHeaderSize) {
msarett0e6274f2016-03-21 08:04:40 -0700113 return false;
114 }
115
msarett0e6274f2016-03-21 08:04:40 -0700116 return !memcmp(marker->data, kICCSig, sizeof(kICCSig));
117}
118
119/*
120 * ICC profiles may be stored using a sequence of multiple markers. We obtain the ICC profile
121 * in two steps:
122 * (1) Discover all ICC profile markers and verify that they are numbered properly.
123 * (2) Copy the data from each marker into a contiguous ICC profile.
124 */
msarett9876ac52016-06-01 14:47:18 -0700125static sk_sp<SkData> get_icc_profile(jpeg_decompress_struct* dinfo) {
msarett0e6274f2016-03-21 08:04:40 -0700126 // Note that 256 will be enough storage space since each markerIndex is stored in 8-bits.
127 jpeg_marker_struct* markerSequence[256];
128 memset(markerSequence, 0, sizeof(markerSequence));
129 uint8_t numMarkers = 0;
130 size_t totalBytes = 0;
131
132 // Discover any ICC markers and verify that they are numbered properly.
133 for (jpeg_marker_struct* marker = dinfo->marker_list; marker; marker = marker->next) {
134 if (is_icc_marker(marker)) {
135 // Verify that numMarkers is valid and consistent.
136 if (0 == numMarkers) {
137 numMarkers = marker->data[13];
138 if (0 == numMarkers) {
139 SkCodecPrintf("ICC Profile Error: numMarkers must be greater than zero.\n");
140 return nullptr;
141 }
142 } else if (numMarkers != marker->data[13]) {
143 SkCodecPrintf("ICC Profile Error: numMarkers must be consistent.\n");
144 return nullptr;
145 }
146
147 // Verify that the markerIndex is valid and unique. Note that zero is not
148 // a valid index.
149 uint8_t markerIndex = marker->data[12];
150 if (markerIndex == 0 || markerIndex > numMarkers) {
151 SkCodecPrintf("ICC Profile Error: markerIndex is invalid.\n");
152 return nullptr;
153 }
154 if (markerSequence[markerIndex]) {
155 SkCodecPrintf("ICC Profile Error: Duplicate value of markerIndex.\n");
156 return nullptr;
157 }
158 markerSequence[markerIndex] = marker;
Matt Sarett5df93de2017-03-22 21:52:47 +0000159 SkASSERT(marker->data_length >= kICCMarkerHeaderSize);
160 totalBytes += marker->data_length - kICCMarkerHeaderSize;
msarett0e6274f2016-03-21 08:04:40 -0700161 }
162 }
163
164 if (0 == totalBytes) {
165 // No non-empty ICC profile markers were found.
166 return nullptr;
167 }
168
169 // Combine the ICC marker data into a contiguous profile.
msarett9876ac52016-06-01 14:47:18 -0700170 sk_sp<SkData> iccData = SkData::MakeUninitialized(totalBytes);
171 void* dst = iccData->writable_data();
msarett0e6274f2016-03-21 08:04:40 -0700172 for (uint32_t i = 1; i <= numMarkers; i++) {
173 jpeg_marker_struct* marker = markerSequence[i];
174 if (!marker) {
175 SkCodecPrintf("ICC Profile Error: Missing marker %d of %d.\n", i, numMarkers);
176 return nullptr;
177 }
178
Matt Sarett5df93de2017-03-22 21:52:47 +0000179 void* src = SkTAddOffset<void>(marker->data, kICCMarkerHeaderSize);
180 size_t bytes = marker->data_length - kICCMarkerHeaderSize;
msarett0e6274f2016-03-21 08:04:40 -0700181 memcpy(dst, src, bytes);
182 dst = SkTAddOffset<void>(dst, bytes);
183 }
184
msarett9876ac52016-06-01 14:47:18 -0700185 return iccData;
msarett0e6274f2016-03-21 08:04:40 -0700186}
187
Matt Sarettc5eabe72017-02-24 14:51:08 -0500188bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, JpegDecoderMgr** decoderMgrOut,
189 sk_sp<SkColorSpace> defaultColorSpace) {
msarette16b04a2015-04-15 07:32:19 -0700190
191 // Create a JpegDecoderMgr to own all of the decompress information
Ben Wagner145dbcd2016-11-03 14:40:50 -0400192 std::unique_ptr<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream));
msarette16b04a2015-04-15 07:32:19 -0700193
194 // libjpeg errors will be caught and reported here
mtklein2f428962016-07-28 13:59:59 -0700195 if (setjmp(decoderMgr->getJmpBuf())) {
msarett50ce1f22016-07-29 06:23:33 -0700196 return decoderMgr->returnFalse("ReadHeader");
msarette16b04a2015-04-15 07:32:19 -0700197 }
198
199 // Initialize the decompress info and the source manager
200 decoderMgr->init();
201
msarett0e6274f2016-03-21 08:04:40 -0700202 // Instruct jpeg library to save the markers that we care about. Since
203 // the orientation and color profile will not change, we can skip this
204 // step on rewinds.
205 if (codecOut) {
206 jpeg_save_markers(decoderMgr->dinfo(), kExifMarker, 0xFFFF);
207 jpeg_save_markers(decoderMgr->dinfo(), kICCMarker, 0xFFFF);
208 }
209
msarette16b04a2015-04-15 07:32:19 -0700210 // Read the jpeg header
msarettfbccb592015-09-01 06:43:41 -0700211 if (JPEG_HEADER_OK != jpeg_read_header(decoderMgr->dinfo(), true)) {
msarett50ce1f22016-07-29 06:23:33 -0700212 return decoderMgr->returnFalse("ReadHeader");
msarette16b04a2015-04-15 07:32:19 -0700213 }
214
msarett0e6274f2016-03-21 08:04:40 -0700215 if (codecOut) {
msarettc30c4182016-04-20 11:53:35 -0700216 // Get the encoded color type
msarettac6c7502016-04-25 09:30:24 -0700217 SkEncodedInfo::Color color;
218 if (!decoderMgr->getEncodedColor(&color)) {
msarettc30c4182016-04-20 11:53:35 -0700219 return false;
220 }
msarette16b04a2015-04-15 07:32:19 -0700221
222 // Create image info object and the codec
msarettc30c4182016-04-20 11:53:35 -0700223 SkEncodedInfo info = SkEncodedInfo::Make(color, SkEncodedInfo::kOpaque_Alpha, 8);
msarett0e6274f2016-03-21 08:04:40 -0700224
225 Origin orientation = get_exif_orientation(decoderMgr->dinfo());
msarett9876ac52016-06-01 14:47:18 -0700226 sk_sp<SkData> iccData = get_icc_profile(decoderMgr->dinfo());
227 sk_sp<SkColorSpace> colorSpace = nullptr;
raftiasd737bee2016-12-08 10:53:24 -0500228 bool unsupportedICC = false;
msarett9876ac52016-06-01 14:47:18 -0700229 if (iccData) {
Matt Sarett523116d2017-01-12 18:36:38 -0500230 SkColorSpace_Base::ICCTypeFlag iccType = SkColorSpace_Base::kRGB_ICCTypeFlag;
raftias54761282016-12-01 13:44:07 -0500231 switch (decoderMgr->dinfo()->jpeg_color_space) {
232 case JCS_CMYK:
233 case JCS_YCCK:
Matt Sarett523116d2017-01-12 18:36:38 -0500234 iccType = SkColorSpace_Base::kCMYK_ICCTypeFlag;
raftias54761282016-12-01 13:44:07 -0500235 break;
raftias91db12d2016-12-02 11:56:59 -0500236 case JCS_GRAYSCALE:
Matt Sarett523116d2017-01-12 18:36:38 -0500237 // Note the "or equals". We will accept gray or rgb profiles for gray images.
238 iccType |= SkColorSpace_Base::kGray_ICCTypeFlag;
raftias91db12d2016-12-02 11:56:59 -0500239 break;
raftias54761282016-12-01 13:44:07 -0500240 default:
241 break;
242 }
Matt Sarett523116d2017-01-12 18:36:38 -0500243 colorSpace = SkColorSpace_Base::MakeICC(iccData->data(), iccData->size(), iccType);
msarett9876ac52016-06-01 14:47:18 -0700244 if (!colorSpace) {
245 SkCodecPrintf("Could not create SkColorSpace from ICC data.\n");
raftiasd737bee2016-12-08 10:53:24 -0500246 unsupportedICC = true;
msarett9876ac52016-06-01 14:47:18 -0700247 }
248 }
msarettf34cd632016-05-25 10:13:53 -0700249 if (!colorSpace) {
Matt Sarettc5eabe72017-02-24 14:51:08 -0500250 colorSpace = defaultColorSpace;
msarettf34cd632016-05-25 10:13:53 -0700251 }
msarett0e6274f2016-03-21 08:04:40 -0700252
msarettc30c4182016-04-20 11:53:35 -0700253 const int width = decoderMgr->dinfo()->image_width;
254 const int height = decoderMgr->dinfo()->image_height;
raftiasd737bee2016-12-08 10:53:24 -0500255 SkJpegCodec* codec = new SkJpegCodec(width, height, info, stream, decoderMgr.release(),
256 std::move(colorSpace), orientation);
257 codec->setUnsupportedICC(unsupportedICC);
258 *codecOut = codec;
msarette16b04a2015-04-15 07:32:19 -0700259 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700260 SkASSERT(nullptr != decoderMgrOut);
mtklein18300a32016-03-16 13:53:35 -0700261 *decoderMgrOut = decoderMgr.release();
msarette16b04a2015-04-15 07:32:19 -0700262 }
263 return true;
264}
265
266SkCodec* SkJpegCodec::NewFromStream(SkStream* stream) {
Matt Sarettc5eabe72017-02-24 14:51:08 -0500267 return SkJpegCodec::NewFromStream(stream, SkColorSpace::MakeSRGB());
268}
269
270SkCodec* SkJpegCodec::NewFromStream(SkStream* stream, sk_sp<SkColorSpace> defaultColorSpace) {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400271 std::unique_ptr<SkStream> streamDeleter(stream);
halcanary96fcdcc2015-08-27 07:41:13 -0700272 SkCodec* codec = nullptr;
Chris Blume66f23322017-04-19 12:40:46 -0700273 if (ReadHeader(stream, &codec, nullptr, std::move(defaultColorSpace))) {
msarette16b04a2015-04-15 07:32:19 -0700274 // Codec has taken ownership of the stream, we do not need to delete it
275 SkASSERT(codec);
mtklein18300a32016-03-16 13:53:35 -0700276 streamDeleter.release();
msarette16b04a2015-04-15 07:32:19 -0700277 return codec;
278 }
halcanary96fcdcc2015-08-27 07:41:13 -0700279 return nullptr;
msarette16b04a2015-04-15 07:32:19 -0700280}
281
msarettc30c4182016-04-20 11:53:35 -0700282SkJpegCodec::SkJpegCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream,
Matt Saretta9e9bfc2016-11-01 12:19:50 -0400283 JpegDecoderMgr* decoderMgr, sk_sp<SkColorSpace> colorSpace, Origin origin)
msarettf34cd632016-05-25 10:13:53 -0700284 : INHERITED(width, height, info, stream, std::move(colorSpace), origin)
msarette16b04a2015-04-15 07:32:19 -0700285 , fDecoderMgr(decoderMgr)
msarettfbccb592015-09-01 06:43:41 -0700286 , fReadyState(decoderMgr->dinfo()->global_state)
msarett50ce1f22016-07-29 06:23:33 -0700287 , fSwizzleSrcRow(nullptr)
288 , fColorXformSrcRow(nullptr)
msarett91c22b22016-02-22 12:27:46 -0800289 , fSwizzlerSubset(SkIRect::MakeEmpty())
msarette16b04a2015-04-15 07:32:19 -0700290{}
291
292/*
emmaleer8f4ba762015-08-14 07:44:46 -0700293 * Return the row bytes of a particular image type and width
294 */
msarett23e78d32016-02-06 15:58:50 -0800295static size_t get_row_bytes(const j_decompress_ptr dinfo) {
msarett70e418b2016-02-12 12:35:48 -0800296 const size_t colorBytes = (dinfo->out_color_space == JCS_RGB565) ? 2 :
297 dinfo->out_color_components;
emmaleer8f4ba762015-08-14 07:44:46 -0700298 return dinfo->output_width * colorBytes;
299
300}
scroggoe7fc14b2015-10-02 13:14:46 -0700301
302/*
303 * Calculate output dimensions based on the provided factors.
304 *
305 * Not to be used on the actual jpeg_decompress_struct used for decoding, since it will
306 * incorrectly modify num_components.
307 */
308void calc_output_dimensions(jpeg_decompress_struct* dinfo, unsigned int num, unsigned int denom) {
309 dinfo->num_components = 0;
310 dinfo->scale_num = num;
311 dinfo->scale_denom = denom;
312 jpeg_calc_output_dimensions(dinfo);
313}
314
emmaleer8f4ba762015-08-14 07:44:46 -0700315/*
msarette16b04a2015-04-15 07:32:19 -0700316 * Return a valid set of output dimensions for this decoder, given an input scale
317 */
318SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const {
msarett1c8a5872015-07-07 08:50:01 -0700319 // libjpeg-turbo supports scaling by 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, and 1/1, so we will
320 // support these as well
scroggoe7fc14b2015-10-02 13:14:46 -0700321 unsigned int num;
322 unsigned int denom = 8;
msarettfdb47572015-10-13 12:50:14 -0700323 if (desiredScale >= 0.9375) {
msarett1c8a5872015-07-07 08:50:01 -0700324 num = 8;
msarettfdb47572015-10-13 12:50:14 -0700325 } else if (desiredScale >= 0.8125) {
msarett1c8a5872015-07-07 08:50:01 -0700326 num = 7;
msarettfdb47572015-10-13 12:50:14 -0700327 } else if (desiredScale >= 0.6875f) {
msarett1c8a5872015-07-07 08:50:01 -0700328 num = 6;
msarettfdb47572015-10-13 12:50:14 -0700329 } else if (desiredScale >= 0.5625f) {
msarett1c8a5872015-07-07 08:50:01 -0700330 num = 5;
msarettfdb47572015-10-13 12:50:14 -0700331 } else if (desiredScale >= 0.4375f) {
msarett1c8a5872015-07-07 08:50:01 -0700332 num = 4;
msarettfdb47572015-10-13 12:50:14 -0700333 } else if (desiredScale >= 0.3125f) {
msarett1c8a5872015-07-07 08:50:01 -0700334 num = 3;
msarettfdb47572015-10-13 12:50:14 -0700335 } else if (desiredScale >= 0.1875f) {
msarett1c8a5872015-07-07 08:50:01 -0700336 num = 2;
msarette16b04a2015-04-15 07:32:19 -0700337 } else {
msarett1c8a5872015-07-07 08:50:01 -0700338 num = 1;
msarette16b04a2015-04-15 07:32:19 -0700339 }
340
341 // Set up a fake decompress struct in order to use libjpeg to calculate output dimensions
342 jpeg_decompress_struct dinfo;
mtkleinf7aaadb2015-04-16 06:09:27 -0700343 sk_bzero(&dinfo, sizeof(dinfo));
msarette16b04a2015-04-15 07:32:19 -0700344 dinfo.image_width = this->getInfo().width();
345 dinfo.image_height = this->getInfo().height();
msarettfbccb592015-09-01 06:43:41 -0700346 dinfo.global_state = fReadyState;
scroggoe7fc14b2015-10-02 13:14:46 -0700347 calc_output_dimensions(&dinfo, num, denom);
msarette16b04a2015-04-15 07:32:19 -0700348
349 // Return the calculated output dimensions for the given scale
350 return SkISize::Make(dinfo.output_width, dinfo.output_height);
351}
352
scroggob427db12015-08-12 07:24:13 -0700353bool SkJpegCodec::onRewind() {
halcanary96fcdcc2015-08-27 07:41:13 -0700354 JpegDecoderMgr* decoderMgr = nullptr;
Matt Sarettc5eabe72017-02-24 14:51:08 -0500355 if (!ReadHeader(this->stream(), nullptr, &decoderMgr, nullptr)) {
msarett50ce1f22016-07-29 06:23:33 -0700356 return fDecoderMgr->returnFalse("onRewind");
msarett97fdea62015-04-29 08:17:15 -0700357 }
halcanary96fcdcc2015-08-27 07:41:13 -0700358 SkASSERT(nullptr != decoderMgr);
scroggob427db12015-08-12 07:24:13 -0700359 fDecoderMgr.reset(decoderMgr);
msarett2812f032016-07-18 15:56:08 -0700360
361 fSwizzler.reset(nullptr);
msarett50ce1f22016-07-29 06:23:33 -0700362 fSwizzleSrcRow = nullptr;
363 fColorXformSrcRow = nullptr;
msarett2812f032016-07-18 15:56:08 -0700364 fStorage.reset();
365
scroggob427db12015-08-12 07:24:13 -0700366 return true;
msarett97fdea62015-04-29 08:17:15 -0700367}
368
369/*
msarett1c8a5872015-07-07 08:50:01 -0700370 * Checks if the conversion between the input image and the requested output
371 * image has been implemented
372 * Sets the output color space
373 */
msarett2ecc35f2016-09-08 11:55:16 -0700374bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dstInfo) {
msarett50ce1f22016-07-29 06:23:33 -0700375 if (kUnknown_SkAlphaType == dstInfo.alphaType()) {
msarett1c8a5872015-07-07 08:50:01 -0700376 return false;
377 }
378
msarett50ce1f22016-07-29 06:23:33 -0700379 if (kOpaque_SkAlphaType != dstInfo.alphaType()) {
scroggoc5560be2016-02-03 09:42:42 -0800380 SkCodecPrintf("Warning: an opaque image should be decoded as opaque "
381 "- it is being decoded as non-opaque, which will draw slower\n");
382 }
383
msarett50ce1f22016-07-29 06:23:33 -0700384 // Check if we will decode to CMYK. libjpeg-turbo does not convert CMYK to RGBA, so
385 // we must do it ourselves.
386 J_COLOR_SPACE encodedColorType = fDecoderMgr->dinfo()->jpeg_color_space;
387 bool isCMYK = (JCS_CMYK == encodedColorType || JCS_YCCK == encodedColorType);
msarett1c8a5872015-07-07 08:50:01 -0700388
389 // Check for valid color types and set the output color space
msarett50ce1f22016-07-29 06:23:33 -0700390 switch (dstInfo.colorType()) {
msarett34e0ec42016-04-22 16:27:24 -0700391 case kRGBA_8888_SkColorType:
msarett1c8a5872015-07-07 08:50:01 -0700392 if (isCMYK) {
393 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
394 } else {
msarettf25bff92016-07-21 12:00:24 -0700395 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
msarett34e0ec42016-04-22 16:27:24 -0700396 }
397 return true;
398 case kBGRA_8888_SkColorType:
399 if (isCMYK) {
400 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
Matt Sarett313c4632016-10-20 12:35:23 -0400401 } else if (this->colorXform()) {
Matt Sarett562e6812016-11-08 16:13:43 -0500402 // Always using RGBA as the input format for color xforms makes the
403 // implementation a little simpler.
msarett50ce1f22016-07-29 06:23:33 -0700404 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
msarett34e0ec42016-04-22 16:27:24 -0700405 } else {
msarettf25bff92016-07-21 12:00:24 -0700406 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA;
msarett1c8a5872015-07-07 08:50:01 -0700407 }
408 return true;
409 case kRGB_565_SkColorType:
410 if (isCMYK) {
scroggoef27d892015-10-23 09:29:22 -0700411 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
Matt Sarett3725f0a2017-03-28 14:34:20 -0400412 } else if (this->colorXform()) {
413 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
msarett1c8a5872015-07-07 08:50:01 -0700414 } else {
msarett8ff6ca62015-09-18 12:06:04 -0700415 fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE;
msarett1c8a5872015-07-07 08:50:01 -0700416 fDecoderMgr->dinfo()->out_color_space = JCS_RGB565;
417 }
418 return true;
419 case kGray_8_SkColorType:
Matt Sarett313c4632016-10-20 12:35:23 -0400420 if (this->colorXform() || JCS_GRAYSCALE != encodedColorType) {
msarett39979d82016-07-28 17:11:18 -0700421 return false;
msarett50ce1f22016-07-29 06:23:33 -0700422 }
423
424 fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE;
425 return true;
426 case kRGBA_F16_SkColorType:
Matt Sarett313c4632016-10-20 12:35:23 -0400427 SkASSERT(this->colorXform());
428
msarett2ecc35f2016-09-08 11:55:16 -0700429 if (!dstInfo.colorSpace()->gammaIsLinear()) {
430 return false;
431 }
msarett50ce1f22016-07-29 06:23:33 -0700432
433 if (isCMYK) {
434 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
msarett1c8a5872015-07-07 08:50:01 -0700435 } else {
msarett50ce1f22016-07-29 06:23:33 -0700436 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
msarett1c8a5872015-07-07 08:50:01 -0700437 }
438 return true;
439 default:
440 return false;
441 }
442}
443
444/*
mtkleine721a8e2016-02-06 19:12:23 -0800445 * Checks if we can natively scale to the requested dimensions and natively scales the
emmaleer8f4ba762015-08-14 07:44:46 -0700446 * dimensions if possible
msarett97fdea62015-04-29 08:17:15 -0700447 */
scroggoe7fc14b2015-10-02 13:14:46 -0700448bool SkJpegCodec::onDimensionsSupported(const SkISize& size) {
mtklein2f428962016-07-28 13:59:59 -0700449 if (setjmp(fDecoderMgr->getJmpBuf())) {
msarett50ce1f22016-07-29 06:23:33 -0700450 return fDecoderMgr->returnFalse("onDimensionsSupported");
scroggoe7fc14b2015-10-02 13:14:46 -0700451 }
452
453 const unsigned int dstWidth = size.width();
454 const unsigned int dstHeight = size.height();
455
456 // Set up a fake decompress struct in order to use libjpeg to calculate output dimensions
457 // FIXME: Why is this necessary?
458 jpeg_decompress_struct dinfo;
459 sk_bzero(&dinfo, sizeof(dinfo));
460 dinfo.image_width = this->getInfo().width();
461 dinfo.image_height = this->getInfo().height();
462 dinfo.global_state = fReadyState;
463
msarett1c8a5872015-07-07 08:50:01 -0700464 // libjpeg-turbo can scale to 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, and 1/1
scroggoe7fc14b2015-10-02 13:14:46 -0700465 unsigned int num = 8;
466 const unsigned int denom = 8;
467 calc_output_dimensions(&dinfo, num, denom);
468 while (dinfo.output_width != dstWidth || dinfo.output_height != dstHeight) {
msarett97fdea62015-04-29 08:17:15 -0700469
470 // Return a failure if we have tried all of the possible scales
scroggoe7fc14b2015-10-02 13:14:46 -0700471 if (1 == num || dstWidth > dinfo.output_width || dstHeight > dinfo.output_height) {
emmaleer8f4ba762015-08-14 07:44:46 -0700472 return false;
msarett97fdea62015-04-29 08:17:15 -0700473 }
474
475 // Try the next scale
scroggoe7fc14b2015-10-02 13:14:46 -0700476 num -= 1;
477 calc_output_dimensions(&dinfo, num, denom);
msarett97fdea62015-04-29 08:17:15 -0700478 }
scroggoe7fc14b2015-10-02 13:14:46 -0700479
480 fDecoderMgr->dinfo()->scale_num = num;
481 fDecoderMgr->dinfo()->scale_denom = denom;
msarett97fdea62015-04-29 08:17:15 -0700482 return true;
483}
484
Matt Sarettc8c901f2017-01-24 16:16:33 -0500485int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count,
486 const Options& opts) {
msarett50ce1f22016-07-29 06:23:33 -0700487 // Set the jump location for libjpeg-turbo errors
488 if (setjmp(fDecoderMgr->getJmpBuf())) {
489 return 0;
490 }
491
492 // When fSwizzleSrcRow is non-null, it means that we need to swizzle. In this case,
493 // we will always decode into fSwizzlerSrcRow before swizzling into the next buffer.
494 // We can never swizzle "in place" because the swizzler may perform sampling and/or
495 // subsetting.
496 // When fColorXformSrcRow is non-null, it means that we need to color xform and that
497 // we cannot color xform "in place" (many times we can, but not when the dst is F16).
Matt Sarett313c4632016-10-20 12:35:23 -0400498 // In this case, we will color xform from fColorXformSrcRow into the dst.
msarett50ce1f22016-07-29 06:23:33 -0700499 JSAMPLE* decodeDst = (JSAMPLE*) dst;
500 uint32_t* swizzleDst = (uint32_t*) dst;
501 size_t decodeDstRowBytes = rowBytes;
502 size_t swizzleDstRowBytes = rowBytes;
Matt Sarettc8c901f2017-01-24 16:16:33 -0500503 int dstWidth = opts.fSubset ? opts.fSubset->width() : dstInfo.width();
msarett50ce1f22016-07-29 06:23:33 -0700504 if (fSwizzleSrcRow && fColorXformSrcRow) {
505 decodeDst = (JSAMPLE*) fSwizzleSrcRow;
506 swizzleDst = fColorXformSrcRow;
507 decodeDstRowBytes = 0;
508 swizzleDstRowBytes = 0;
msarett35bb74b2016-08-22 07:41:28 -0700509 dstWidth = fSwizzler->swizzleWidth();
msarett50ce1f22016-07-29 06:23:33 -0700510 } else if (fColorXformSrcRow) {
511 decodeDst = (JSAMPLE*) fColorXformSrcRow;
512 swizzleDst = fColorXformSrcRow;
513 decodeDstRowBytes = 0;
514 swizzleDstRowBytes = 0;
515 } else if (fSwizzleSrcRow) {
516 decodeDst = (JSAMPLE*) fSwizzleSrcRow;
517 decodeDstRowBytes = 0;
msarett35bb74b2016-08-22 07:41:28 -0700518 dstWidth = fSwizzler->swizzleWidth();
msarett50ce1f22016-07-29 06:23:33 -0700519 }
520
521 for (int y = 0; y < count; y++) {
522 uint32_t lines = jpeg_read_scanlines(fDecoderMgr->dinfo(), &decodeDst, 1);
msarett50ce1f22016-07-29 06:23:33 -0700523 if (0 == lines) {
524 return y;
525 }
526
527 if (fSwizzler) {
528 fSwizzler->swizzle(swizzleDst, decodeDst);
529 }
530
Matt Sarett313c4632016-10-20 12:35:23 -0400531 if (this->colorXform()) {
532 SkAssertResult(this->colorXform()->apply(select_xform_format(dstInfo.colorType()), dst,
533 SkColorSpaceXform::kRGBA_8888_ColorFormat, swizzleDst, dstWidth,
534 kOpaque_SkAlphaType));
msarett50ce1f22016-07-29 06:23:33 -0700535 dst = SkTAddOffset<void>(dst, rowBytes);
536 }
537
538 decodeDst = SkTAddOffset<JSAMPLE>(decodeDst, decodeDstRowBytes);
539 swizzleDst = SkTAddOffset<uint32_t>(swizzleDst, swizzleDstRowBytes);
540 }
541
542 return count;
543}
544
msarett97fdea62015-04-29 08:17:15 -0700545/*
Matt Sarett7f15b682017-02-24 17:22:09 -0500546 * This is a bit tricky. We only need the swizzler to do format conversion if the jpeg is
547 * encoded as CMYK.
548 * And even then we still may not need it. If the jpeg has a CMYK color space and a color
549 * xform, the color xform will handle the CMYK->RGB conversion.
550 */
551static inline bool needs_swizzler_to_convert_from_cmyk(J_COLOR_SPACE jpegColorType,
552 const SkImageInfo& srcInfo, bool hasColorSpaceXform) {
553 if (JCS_CMYK != jpegColorType) {
554 return false;
555 }
556
557 bool hasCMYKColorSpace = as_CSB(srcInfo.colorSpace())->onIsCMYK();
558 return !hasCMYKColorSpace || !hasColorSpaceXform;
559}
560
561/*
msarette16b04a2015-04-15 07:32:19 -0700562 * Performs the jpeg decode
563 */
564SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
565 void* dst, size_t dstRowBytes,
msarette6dd0042015-10-09 11:07:34 -0700566 const Options& options, SkPMColor*, int*,
567 int* rowsDecoded) {
scroggob636b452015-07-22 07:16:20 -0700568 if (options.fSubset) {
569 // Subsets are not supported.
570 return kUnimplemented;
571 }
572
msarette16b04a2015-04-15 07:32:19 -0700573 // Get a pointer to the decompress info since we will use it quite frequently
574 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
575
576 // Set the jump location for libjpeg errors
mtklein2f428962016-07-28 13:59:59 -0700577 if (setjmp(fDecoderMgr->getJmpBuf())) {
msarette16b04a2015-04-15 07:32:19 -0700578 return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
579 }
580
Matt Sarettcf3f2342017-03-23 15:32:25 -0400581 if (!this->initializeColorXform(dstInfo, options.fPremulBehavior)) {
Matt Sarett313c4632016-10-20 12:35:23 -0400582 return kInvalidConversion;
583 }
msarett50ce1f22016-07-29 06:23:33 -0700584
msarett2ecc35f2016-09-08 11:55:16 -0700585 // Check if we can decode to the requested destination and set the output color space
586 if (!this->setOutputColorSpace(dstInfo)) {
587 return fDecoderMgr->returnFailure("setOutputColorSpace", kInvalidConversion);
msarett85c922a2016-09-08 10:54:34 -0700588 }
589
msarettfbccb592015-09-01 06:43:41 -0700590 if (!jpeg_start_decompress(dinfo)) {
msarette16b04a2015-04-15 07:32:19 -0700591 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
592 }
593
msarett1c8a5872015-07-07 08:50:01 -0700594 // The recommended output buffer height should always be 1 in high quality modes.
595 // If it's not, we want to know because it means our strategy is not optimal.
596 SkASSERT(1 == dinfo->rec_outbuf_height);
msarette16b04a2015-04-15 07:32:19 -0700597
Matt Sarett7f15b682017-02-24 17:22:09 -0500598 if (needs_swizzler_to_convert_from_cmyk(dinfo->out_color_space, this->getInfo(),
599 this->colorXform())) {
600 this->initializeSwizzler(dstInfo, options, true);
scroggoef27d892015-10-23 09:29:22 -0700601 }
602
msarett50ce1f22016-07-29 06:23:33 -0700603 this->allocateStorage(dstInfo);
scroggoef27d892015-10-23 09:29:22 -0700604
Matt Sarettc8c901f2017-01-24 16:16:33 -0500605 int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height(), options);
msarett50ce1f22016-07-29 06:23:33 -0700606 if (rows < dstInfo.height()) {
607 *rowsDecoded = rows;
608 return fDecoderMgr->returnFailure("Incomplete image data", kIncompleteInput);
msarette16b04a2015-04-15 07:32:19 -0700609 }
msarette16b04a2015-04-15 07:32:19 -0700610
611 return kSuccess;
612}
msarett97fdea62015-04-29 08:17:15 -0700613
msarett50ce1f22016-07-29 06:23:33 -0700614void SkJpegCodec::allocateStorage(const SkImageInfo& dstInfo) {
msarett35bb74b2016-08-22 07:41:28 -0700615 int dstWidth = dstInfo.width();
616
msarett50ce1f22016-07-29 06:23:33 -0700617 size_t swizzleBytes = 0;
618 if (fSwizzler) {
619 swizzleBytes = get_row_bytes(fDecoderMgr->dinfo());
msarett35bb74b2016-08-22 07:41:28 -0700620 dstWidth = fSwizzler->swizzleWidth();
Matt Sarett313c4632016-10-20 12:35:23 -0400621 SkASSERT(!this->colorXform() || SkIsAlign4(swizzleBytes));
msarett50ce1f22016-07-29 06:23:33 -0700622 }
623
624 size_t xformBytes = 0;
Matt Sarett3725f0a2017-03-28 14:34:20 -0400625 if (this->colorXform() && (kRGBA_F16_SkColorType == dstInfo.colorType() ||
626 kRGB_565_SkColorType == dstInfo.colorType())) {
msarett35bb74b2016-08-22 07:41:28 -0700627 xformBytes = dstWidth * sizeof(uint32_t);
msarett50ce1f22016-07-29 06:23:33 -0700628 }
629
630 size_t totalBytes = swizzleBytes + xformBytes;
631 if (totalBytes > 0) {
632 fStorage.reset(totalBytes);
633 fSwizzleSrcRow = (swizzleBytes > 0) ? fStorage.get() : nullptr;
634 fColorXformSrcRow = (xformBytes > 0) ?
635 SkTAddOffset<uint32_t>(fStorage.get(), swizzleBytes) : nullptr;
636 }
637}
638
Matt Sarett7f15b682017-02-24 17:22:09 -0500639void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options,
640 bool needsCMYKToRGB) {
msaretta45a6682016-04-22 13:18:37 -0700641 SkEncodedInfo swizzlerInfo = this->getEncodedInfo();
Matt Sarett7f15b682017-02-24 17:22:09 -0500642 if (needsCMYKToRGB) {
mtkleinda19f6f2016-08-23 11:49:29 -0700643 swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kInvertedCMYK_Color,
644 swizzlerInfo.alpha(),
645 swizzlerInfo.bitsPerComponent());
msarett70e418b2016-02-12 12:35:48 -0800646 }
647
msarett91c22b22016-02-22 12:27:46 -0800648 Options swizzlerOptions = options;
649 if (options.fSubset) {
650 // Use fSwizzlerSubset if this is a subset decode. This is necessary in the case
651 // where libjpeg-turbo provides a subset and then we need to subset it further.
652 // Also, verify that fSwizzlerSubset is initialized and valid.
653 SkASSERT(!fSwizzlerSubset.isEmpty() && fSwizzlerSubset.x() <= options.fSubset->x() &&
654 fSwizzlerSubset.width() == options.fSubset->width());
655 swizzlerOptions.fSubset = &fSwizzlerSubset;
656 }
Matt Sarett09a1c082017-02-01 15:34:22 -0800657
658 SkImageInfo swizzlerDstInfo = dstInfo;
Matt Sarett7f15b682017-02-24 17:22:09 -0500659 if (this->colorXform()) {
660 // The color xform will be expecting RGBA 8888 input.
Matt Sarett09a1c082017-02-01 15:34:22 -0800661 swizzlerDstInfo = swizzlerDstInfo.makeColorType(kRGBA_8888_SkColorType);
662 }
663
664 fSwizzler.reset(SkSwizzler::CreateSwizzler(swizzlerInfo, nullptr, swizzlerDstInfo,
Matt Sarett7f15b682017-02-24 17:22:09 -0500665 swizzlerOptions, nullptr, !needsCMYKToRGB));
msarettb30d6982016-02-15 10:18:45 -0800666 SkASSERT(fSwizzler);
msarett50ce1f22016-07-29 06:23:33 -0700667}
668
msarettfdb47572015-10-13 12:50:14 -0700669SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) {
670 if (!createIfNecessary || fSwizzler) {
msarett50ce1f22016-07-29 06:23:33 -0700671 SkASSERT(!fSwizzler || (fSwizzleSrcRow && fStorage.get() == fSwizzleSrcRow));
Ben Wagner145dbcd2016-11-03 14:40:50 -0400672 return fSwizzler.get();
msarettfdb47572015-10-13 12:50:14 -0700673 }
674
Matt Sarett7f15b682017-02-24 17:22:09 -0500675 bool needsCMYKToRGB = needs_swizzler_to_convert_from_cmyk(
676 fDecoderMgr->dinfo()->out_color_space, this->getInfo(), this->colorXform());
677 this->initializeSwizzler(this->dstInfo(), this->options(), needsCMYKToRGB);
msarett50ce1f22016-07-29 06:23:33 -0700678 this->allocateStorage(this->dstInfo());
Ben Wagner145dbcd2016-11-03 14:40:50 -0400679 return fSwizzler.get();
scroggo46c57472015-09-30 08:57:13 -0700680}
scroggo1c005e42015-08-04 09:24:45 -0700681
scroggo46c57472015-09-30 08:57:13 -0700682SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
683 const Options& options, SkPMColor ctable[], int* ctableCount) {
scroggo46c57472015-09-30 08:57:13 -0700684 // Set the jump location for libjpeg errors
mtklein2f428962016-07-28 13:59:59 -0700685 if (setjmp(fDecoderMgr->getJmpBuf())) {
scroggo46c57472015-09-30 08:57:13 -0700686 SkCodecPrintf("setjmp: Error from libjpeg\n");
687 return kInvalidInput;
688 }
689
Matt Sarettcf3f2342017-03-23 15:32:25 -0400690 if (!this->initializeColorXform(dstInfo, options.fPremulBehavior)) {
Matt Sarett313c4632016-10-20 12:35:23 -0400691 return kInvalidConversion;
692 }
msarett85c922a2016-09-08 10:54:34 -0700693
msarett2ecc35f2016-09-08 11:55:16 -0700694 // Check if we can decode to the requested destination and set the output color space
695 if (!this->setOutputColorSpace(dstInfo)) {
696 return fDecoderMgr->returnFailure("setOutputColorSpace", kInvalidConversion);
msarett50ce1f22016-07-29 06:23:33 -0700697 }
698
scroggo46c57472015-09-30 08:57:13 -0700699 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) {
700 SkCodecPrintf("start decompress failed\n");
701 return kInvalidInput;
702 }
703
Matt Sarett7f15b682017-02-24 17:22:09 -0500704 bool needsCMYKToRGB = needs_swizzler_to_convert_from_cmyk(
705 fDecoderMgr->dinfo()->out_color_space, this->getInfo(), this->colorXform());
msarett91c22b22016-02-22 12:27:46 -0800706 if (options.fSubset) {
707 uint32_t startX = options.fSubset->x();
708 uint32_t width = options.fSubset->width();
709
710 // libjpeg-turbo may need to align startX to a multiple of the IDCT
711 // block size. If this is the case, it will decrease the value of
712 // startX to the appropriate alignment and also increase the value
713 // of width so that the right edge of the requested subset remains
714 // the same.
715 jpeg_crop_scanline(fDecoderMgr->dinfo(), &startX, &width);
716
717 SkASSERT(startX <= (uint32_t) options.fSubset->x());
718 SkASSERT(width >= (uint32_t) options.fSubset->width());
719 SkASSERT(startX + width >= (uint32_t) options.fSubset->right());
720
721 // Instruct the swizzler (if it is necessary) to further subset the
722 // output provided by libjpeg-turbo.
723 //
724 // We set this here (rather than in the if statement below), so that
725 // if (1) we don't need a swizzler for the subset, and (2) we need a
726 // swizzler for CMYK, the swizzler will still use the proper subset
727 // dimensions.
728 //
729 // Note that the swizzler will ignore the y and height parameters of
730 // the subset. Since the scanline decoder (and the swizzler) handle
731 // one row at a time, only the subsetting in the x-dimension matters.
732 fSwizzlerSubset.setXYWH(options.fSubset->x() - startX, 0,
733 options.fSubset->width(), options.fSubset->height());
734
735 // We will need a swizzler if libjpeg-turbo cannot provide the exact
736 // subset that we request.
737 if (startX != (uint32_t) options.fSubset->x() ||
738 width != (uint32_t) options.fSubset->width()) {
Matt Sarett7f15b682017-02-24 17:22:09 -0500739 this->initializeSwizzler(dstInfo, options, needsCMYKToRGB);
msarett91c22b22016-02-22 12:27:46 -0800740 }
741 }
742
743 // Make sure we have a swizzler if we are converting from CMYK.
Matt Sarett7f15b682017-02-24 17:22:09 -0500744 if (!fSwizzler && needsCMYKToRGB) {
745 this->initializeSwizzler(dstInfo, options, true);
msarett91c22b22016-02-22 12:27:46 -0800746 }
msarettfdb47572015-10-13 12:50:14 -0700747
msarett50ce1f22016-07-29 06:23:33 -0700748 this->allocateStorage(dstInfo);
749
scroggo46c57472015-09-30 08:57:13 -0700750 return kSuccess;
751}
752
mtkleine721a8e2016-02-06 19:12:23 -0800753int SkJpegCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
Matt Sarettc8c901f2017-01-24 16:16:33 -0500754 int rows = this->readRows(this->dstInfo(), dst, dstRowBytes, count, this->options());
msarett50ce1f22016-07-29 06:23:33 -0700755 if (rows < count) {
756 // This allows us to skip calling jpeg_finish_decompress().
757 fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height();
scroggo46c57472015-09-30 08:57:13 -0700758 }
759
msarett50ce1f22016-07-29 06:23:33 -0700760 return rows;
scroggo46c57472015-09-30 08:57:13 -0700761}
msarett97fdea62015-04-29 08:17:15 -0700762
msarette6dd0042015-10-09 11:07:34 -0700763bool SkJpegCodec::onSkipScanlines(int count) {
scroggo46c57472015-09-30 08:57:13 -0700764 // Set the jump location for libjpeg errors
mtklein2f428962016-07-28 13:59:59 -0700765 if (setjmp(fDecoderMgr->getJmpBuf())) {
msarett50ce1f22016-07-29 06:23:33 -0700766 return fDecoderMgr->returnFalse("onSkipScanlines");
msarett97fdea62015-04-29 08:17:15 -0700767 }
768
msarettf724b992015-10-15 06:41:06 -0700769 return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count);
msarett97fdea62015-04-29 08:17:15 -0700770}
msarettb714fb02016-01-22 14:46:42 -0800771
772static bool is_yuv_supported(jpeg_decompress_struct* dinfo) {
773 // Scaling is not supported in raw data mode.
774 SkASSERT(dinfo->scale_num == dinfo->scale_denom);
775
776 // I can't imagine that this would ever change, but we do depend on it.
777 static_assert(8 == DCTSIZE, "DCTSIZE (defined in jpeg library) should always be 8.");
778
779 if (JCS_YCbCr != dinfo->jpeg_color_space) {
780 return false;
781 }
782
783 SkASSERT(3 == dinfo->num_components);
784 SkASSERT(dinfo->comp_info);
785
786 // It is possible to perform a YUV decode for any combination of
787 // horizontal and vertical sampling that is supported by
788 // libjpeg/libjpeg-turbo. However, we will start by supporting only the
789 // common cases (where U and V have samp_factors of one).
790 //
791 // The definition of samp_factor is kind of the opposite of what SkCodec
792 // thinks of as a sampling factor. samp_factor is essentially a
793 // multiplier, and the larger the samp_factor is, the more samples that
794 // there will be. Ex:
795 // U_plane_width = image_width * (U_h_samp_factor / max_h_samp_factor)
796 //
797 // Supporting cases where the samp_factors for U or V were larger than
798 // that of Y would be an extremely difficult change, given that clients
799 // allocate memory as if the size of the Y plane is always the size of the
800 // image. However, this case is very, very rare.
msarett7c87cf42016-03-04 06:23:20 -0800801 if ((1 != dinfo->comp_info[1].h_samp_factor) ||
802 (1 != dinfo->comp_info[1].v_samp_factor) ||
803 (1 != dinfo->comp_info[2].h_samp_factor) ||
804 (1 != dinfo->comp_info[2].v_samp_factor))
805 {
msarettb714fb02016-01-22 14:46:42 -0800806 return false;
807 }
808
809 // Support all common cases of Y samp_factors.
810 // TODO (msarett): As mentioned above, it would be possible to support
811 // more combinations of samp_factors. The issues are:
812 // (1) Are there actually any images that are not covered
813 // by these cases?
814 // (2) How much complexity would be added to the
815 // implementation in order to support these rare
816 // cases?
817 int hSampY = dinfo->comp_info[0].h_samp_factor;
818 int vSampY = dinfo->comp_info[0].v_samp_factor;
819 return (1 == hSampY && 1 == vSampY) ||
820 (2 == hSampY && 1 == vSampY) ||
821 (2 == hSampY && 2 == vSampY) ||
822 (1 == hSampY && 2 == vSampY) ||
823 (4 == hSampY && 1 == vSampY) ||
824 (4 == hSampY && 2 == vSampY);
825}
826
msarett4984c3c2016-03-10 05:44:43 -0800827bool SkJpegCodec::onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const {
msarettb714fb02016-01-22 14:46:42 -0800828 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
829 if (!is_yuv_supported(dinfo)) {
830 return false;
831 }
832
msarett4984c3c2016-03-10 05:44:43 -0800833 sizeInfo->fSizes[SkYUVSizeInfo::kY].set(dinfo->comp_info[0].downsampled_width,
834 dinfo->comp_info[0].downsampled_height);
835 sizeInfo->fSizes[SkYUVSizeInfo::kU].set(dinfo->comp_info[1].downsampled_width,
836 dinfo->comp_info[1].downsampled_height);
837 sizeInfo->fSizes[SkYUVSizeInfo::kV].set(dinfo->comp_info[2].downsampled_width,
838 dinfo->comp_info[2].downsampled_height);
839 sizeInfo->fWidthBytes[SkYUVSizeInfo::kY] = dinfo->comp_info[0].width_in_blocks * DCTSIZE;
840 sizeInfo->fWidthBytes[SkYUVSizeInfo::kU] = dinfo->comp_info[1].width_in_blocks * DCTSIZE;
841 sizeInfo->fWidthBytes[SkYUVSizeInfo::kV] = dinfo->comp_info[2].width_in_blocks * DCTSIZE;
msarettb714fb02016-01-22 14:46:42 -0800842
843 if (colorSpace) {
844 *colorSpace = kJPEG_SkYUVColorSpace;
845 }
846
847 return true;
848}
849
msarett4984c3c2016-03-10 05:44:43 -0800850SkCodec::Result SkJpegCodec::onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) {
851 SkYUVSizeInfo defaultInfo;
msarettb714fb02016-01-22 14:46:42 -0800852
853 // This will check is_yuv_supported(), so we don't need to here.
854 bool supportsYUV = this->onQueryYUV8(&defaultInfo, nullptr);
msarett4984c3c2016-03-10 05:44:43 -0800855 if (!supportsYUV ||
856 sizeInfo.fSizes[SkYUVSizeInfo::kY] != defaultInfo.fSizes[SkYUVSizeInfo::kY] ||
857 sizeInfo.fSizes[SkYUVSizeInfo::kU] != defaultInfo.fSizes[SkYUVSizeInfo::kU] ||
858 sizeInfo.fSizes[SkYUVSizeInfo::kV] != defaultInfo.fSizes[SkYUVSizeInfo::kV] ||
859 sizeInfo.fWidthBytes[SkYUVSizeInfo::kY] < defaultInfo.fWidthBytes[SkYUVSizeInfo::kY] ||
860 sizeInfo.fWidthBytes[SkYUVSizeInfo::kU] < defaultInfo.fWidthBytes[SkYUVSizeInfo::kU] ||
861 sizeInfo.fWidthBytes[SkYUVSizeInfo::kV] < defaultInfo.fWidthBytes[SkYUVSizeInfo::kV]) {
msarettb714fb02016-01-22 14:46:42 -0800862 return fDecoderMgr->returnFailure("onGetYUV8Planes", kInvalidInput);
863 }
864
865 // Set the jump location for libjpeg errors
mtklein2f428962016-07-28 13:59:59 -0700866 if (setjmp(fDecoderMgr->getJmpBuf())) {
msarettb714fb02016-01-22 14:46:42 -0800867 return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
868 }
869
870 // Get a pointer to the decompress info since we will use it quite frequently
871 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
872
873 dinfo->raw_data_out = TRUE;
874 if (!jpeg_start_decompress(dinfo)) {
875 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
876 }
877
878 // A previous implementation claims that the return value of is_yuv_supported()
879 // may change after calling jpeg_start_decompress(). It looks to me like this
880 // was caused by a bug in the old code, but we'll be safe and check here.
881 SkASSERT(is_yuv_supported(dinfo));
882
883 // Currently, we require that the Y plane dimensions match the image dimensions
884 // and that the U and V planes are the same dimensions.
msarett4984c3c2016-03-10 05:44:43 -0800885 SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kU] == sizeInfo.fSizes[SkYUVSizeInfo::kV]);
886 SkASSERT((uint32_t) sizeInfo.fSizes[SkYUVSizeInfo::kY].width() == dinfo->output_width &&
887 (uint32_t) sizeInfo.fSizes[SkYUVSizeInfo::kY].height() == dinfo->output_height);
msarettb714fb02016-01-22 14:46:42 -0800888
889 // Build a JSAMPIMAGE to handle output from libjpeg-turbo. A JSAMPIMAGE has
890 // a 2-D array of pixels for each of the components (Y, U, V) in the image.
891 // Cheat Sheet:
892 // JSAMPIMAGE == JSAMPLEARRAY* == JSAMPROW** == JSAMPLE***
893 JSAMPARRAY yuv[3];
894
895 // Set aside enough space for pointers to rows of Y, U, and V.
896 JSAMPROW rowptrs[2 * DCTSIZE + DCTSIZE + DCTSIZE];
897 yuv[0] = &rowptrs[0]; // Y rows (DCTSIZE or 2 * DCTSIZE)
898 yuv[1] = &rowptrs[2 * DCTSIZE]; // U rows (DCTSIZE)
899 yuv[2] = &rowptrs[3 * DCTSIZE]; // V rows (DCTSIZE)
900
901 // Initialize rowptrs.
902 int numYRowsPerBlock = DCTSIZE * dinfo->comp_info[0].v_samp_factor;
903 for (int i = 0; i < numYRowsPerBlock; i++) {
msarett4984c3c2016-03-10 05:44:43 -0800904 rowptrs[i] = SkTAddOffset<JSAMPLE>(planes[SkYUVSizeInfo::kY],
905 i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kY]);
msarettb714fb02016-01-22 14:46:42 -0800906 }
907 for (int i = 0; i < DCTSIZE; i++) {
msarett4984c3c2016-03-10 05:44:43 -0800908 rowptrs[i + 2 * DCTSIZE] = SkTAddOffset<JSAMPLE>(planes[SkYUVSizeInfo::kU],
909 i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kU]);
910 rowptrs[i + 3 * DCTSIZE] = SkTAddOffset<JSAMPLE>(planes[SkYUVSizeInfo::kV],
911 i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kV]);
msarettb714fb02016-01-22 14:46:42 -0800912 }
913
914 // After each loop iteration, we will increment pointers to Y, U, and V.
msarett4984c3c2016-03-10 05:44:43 -0800915 size_t blockIncrementY = numYRowsPerBlock * sizeInfo.fWidthBytes[SkYUVSizeInfo::kY];
916 size_t blockIncrementU = DCTSIZE * sizeInfo.fWidthBytes[SkYUVSizeInfo::kU];
917 size_t blockIncrementV = DCTSIZE * sizeInfo.fWidthBytes[SkYUVSizeInfo::kV];
msarettb714fb02016-01-22 14:46:42 -0800918
919 uint32_t numRowsPerBlock = numYRowsPerBlock;
920
921 // We intentionally round down here, as this first loop will only handle
922 // full block rows. As a special case at the end, we will handle any
923 // remaining rows that do not make up a full block.
924 const int numIters = dinfo->output_height / numRowsPerBlock;
925 for (int i = 0; i < numIters; i++) {
926 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock);
927 if (linesRead < numRowsPerBlock) {
928 // FIXME: Handle incomplete YUV decodes without signalling an error.
929 return kInvalidInput;
930 }
931
932 // Update rowptrs.
933 for (int i = 0; i < numYRowsPerBlock; i++) {
934 rowptrs[i] += blockIncrementY;
935 }
936 for (int i = 0; i < DCTSIZE; i++) {
937 rowptrs[i + 2 * DCTSIZE] += blockIncrementU;
938 rowptrs[i + 3 * DCTSIZE] += blockIncrementV;
939 }
940 }
941
942 uint32_t remainingRows = dinfo->output_height - dinfo->output_scanline;
943 SkASSERT(remainingRows == dinfo->output_height % numRowsPerBlock);
944 SkASSERT(dinfo->output_scanline == numIters * numRowsPerBlock);
945 if (remainingRows > 0) {
946 // libjpeg-turbo needs memory to be padded by the block sizes. We will fulfill
947 // this requirement using a dummy row buffer.
948 // FIXME: Should SkCodec have an extra memory buffer that can be shared among
949 // all of the implementations that use temporary/garbage memory?
msarett4984c3c2016-03-10 05:44:43 -0800950 SkAutoTMalloc<JSAMPLE> dummyRow(sizeInfo.fWidthBytes[SkYUVSizeInfo::kY]);
msarettb714fb02016-01-22 14:46:42 -0800951 for (int i = remainingRows; i < numYRowsPerBlock; i++) {
952 rowptrs[i] = dummyRow.get();
953 }
954 int remainingUVRows = dinfo->comp_info[1].downsampled_height - DCTSIZE * numIters;
955 for (int i = remainingUVRows; i < DCTSIZE; i++) {
956 rowptrs[i + 2 * DCTSIZE] = dummyRow.get();
957 rowptrs[i + 3 * DCTSIZE] = dummyRow.get();
958 }
959
960 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock);
961 if (linesRead < remainingRows) {
962 // FIXME: Handle incomplete YUV decodes without signalling an error.
963 return kInvalidInput;
964 }
965 }
966
967 return kSuccess;
968}