blob: 8c2f5dc4e38156afa0986f73ec9b6db8db9e1ac1 [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"
mtkleine721a8e2016-02-06 19:12:23 -08009#include "SkMSAN.h"
msarette16b04a2015-04-15 07:32:19 -070010#include "SkJpegCodec.h"
11#include "SkJpegDecoderMgr.h"
msarette16b04a2015-04-15 07:32:19 -070012#include "SkCodecPriv.h"
13#include "SkColorPriv.h"
raftias54761282016-12-01 13:44:07 -050014#include "SkColorSpace_Base.h"
msarette16b04a2015-04-15 07:32:19 -070015#include "SkStream.h"
16#include "SkTemplates.h"
17#include "SkTypes.h"
18
msarett1c8a5872015-07-07 08:50:01 -070019// stdio is needed for libjpeg-turbo
msarette16b04a2015-04-15 07:32:19 -070020#include <stdio.h>
msarettc1d03122016-03-25 08:58:55 -070021#include "SkJpegUtility.h"
msarette16b04a2015-04-15 07:32:19 -070022
mtkleindc90b532016-07-28 14:45:28 -070023// This warning triggers false postives way too often in here.
24#if defined(__GNUC__) && !defined(__clang__)
25 #pragma GCC diagnostic ignored "-Wclobbered"
26#endif
27
msarette16b04a2015-04-15 07:32:19 -070028extern "C" {
29 #include "jerror.h"
msarette16b04a2015-04-15 07:32:19 -070030 #include "jpeglib.h"
31}
32
scroggodb30be22015-12-08 18:54:13 -080033bool SkJpegCodec::IsJpeg(const void* buffer, size_t bytesRead) {
msarette16b04a2015-04-15 07:32:19 -070034 static const uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF };
scroggodb30be22015-12-08 18:54:13 -080035 return bytesRead >= 3 && !memcmp(buffer, jpegSig, sizeof(jpegSig));
msarette16b04a2015-04-15 07:32:19 -070036}
37
msarett0e6274f2016-03-21 08:04:40 -070038static uint32_t get_endian_int(const uint8_t* data, bool littleEndian) {
39 if (littleEndian) {
40 return (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | (data[0]);
41 }
42
43 return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3]);
44}
45
46const uint32_t kExifHeaderSize = 14;
47const uint32_t kICCHeaderSize = 14;
48const uint32_t kExifMarker = JPEG_APP0 + 1;
49const uint32_t kICCMarker = JPEG_APP0 + 2;
50
51static bool is_orientation_marker(jpeg_marker_struct* marker, SkCodec::Origin* orientation) {
52 if (kExifMarker != marker->marker || marker->data_length < kExifHeaderSize) {
53 return false;
54 }
55
56 const uint8_t* data = marker->data;
57 static const uint8_t kExifSig[] { 'E', 'x', 'i', 'f', '\0' };
58 if (memcmp(data, kExifSig, sizeof(kExifSig))) {
59 return false;
60 }
61
62 bool littleEndian;
63 if (!is_valid_endian_marker(data + 6, &littleEndian)) {
64 return false;
65 }
66
67 // Get the offset from the start of the marker.
68 // Account for 'E', 'x', 'i', 'f', '\0', '<fill byte>'.
69 uint32_t offset = get_endian_int(data + 10, littleEndian);
70 offset += sizeof(kExifSig) + 1;
71
72 // Require that the marker is at least large enough to contain the number of entries.
73 if (marker->data_length < offset + 2) {
74 return false;
75 }
76 uint32_t numEntries = get_endian_short(data + offset, littleEndian);
77
78 // Tag (2 bytes), Datatype (2 bytes), Number of elements (4 bytes), Data (4 bytes)
79 const uint32_t kEntrySize = 12;
80 numEntries = SkTMin(numEntries, (marker->data_length - offset - 2) / kEntrySize);
81
82 // Advance the data to the start of the entries.
83 data += offset + 2;
84
85 const uint16_t kOriginTag = 0x112;
86 const uint16_t kOriginType = 3;
87 for (uint32_t i = 0; i < numEntries; i++, data += kEntrySize) {
88 uint16_t tag = get_endian_short(data, littleEndian);
89 uint16_t type = get_endian_short(data + 2, littleEndian);
90 uint32_t count = get_endian_int(data + 4, littleEndian);
91 if (kOriginTag == tag && kOriginType == type && 1 == count) {
92 uint16_t val = get_endian_short(data + 8, littleEndian);
93 if (0 < val && val <= SkCodec::kLast_Origin) {
94 *orientation = (SkCodec::Origin) val;
95 return true;
96 }
97 }
98 }
99
100 return false;
101}
102
103static SkCodec::Origin get_exif_orientation(jpeg_decompress_struct* dinfo) {
104 SkCodec::Origin orientation;
105 for (jpeg_marker_struct* marker = dinfo->marker_list; marker; marker = marker->next) {
106 if (is_orientation_marker(marker, &orientation)) {
107 return orientation;
108 }
109 }
110
111 return SkCodec::kDefault_Origin;
112}
113
114static bool is_icc_marker(jpeg_marker_struct* marker) {
115 if (kICCMarker != marker->marker || marker->data_length < kICCHeaderSize) {
116 return false;
117 }
118
119 static const uint8_t kICCSig[] { 'I', 'C', 'C', '_', 'P', 'R', 'O', 'F', 'I', 'L', 'E', '\0' };
120 return !memcmp(marker->data, kICCSig, sizeof(kICCSig));
121}
122
123/*
124 * ICC profiles may be stored using a sequence of multiple markers. We obtain the ICC profile
125 * in two steps:
126 * (1) Discover all ICC profile markers and verify that they are numbered properly.
127 * (2) Copy the data from each marker into a contiguous ICC profile.
128 */
msarett9876ac52016-06-01 14:47:18 -0700129static sk_sp<SkData> get_icc_profile(jpeg_decompress_struct* dinfo) {
msarett0e6274f2016-03-21 08:04:40 -0700130 // Note that 256 will be enough storage space since each markerIndex is stored in 8-bits.
131 jpeg_marker_struct* markerSequence[256];
132 memset(markerSequence, 0, sizeof(markerSequence));
133 uint8_t numMarkers = 0;
134 size_t totalBytes = 0;
135
136 // Discover any ICC markers and verify that they are numbered properly.
137 for (jpeg_marker_struct* marker = dinfo->marker_list; marker; marker = marker->next) {
138 if (is_icc_marker(marker)) {
139 // Verify that numMarkers is valid and consistent.
140 if (0 == numMarkers) {
141 numMarkers = marker->data[13];
142 if (0 == numMarkers) {
143 SkCodecPrintf("ICC Profile Error: numMarkers must be greater than zero.\n");
144 return nullptr;
145 }
146 } else if (numMarkers != marker->data[13]) {
147 SkCodecPrintf("ICC Profile Error: numMarkers must be consistent.\n");
148 return nullptr;
149 }
150
151 // Verify that the markerIndex is valid and unique. Note that zero is not
152 // a valid index.
153 uint8_t markerIndex = marker->data[12];
154 if (markerIndex == 0 || markerIndex > numMarkers) {
155 SkCodecPrintf("ICC Profile Error: markerIndex is invalid.\n");
156 return nullptr;
157 }
158 if (markerSequence[markerIndex]) {
159 SkCodecPrintf("ICC Profile Error: Duplicate value of markerIndex.\n");
160 return nullptr;
161 }
162 markerSequence[markerIndex] = marker;
163 SkASSERT(marker->data_length >= kICCHeaderSize);
164 totalBytes += marker->data_length - kICCHeaderSize;
165 }
166 }
167
168 if (0 == totalBytes) {
169 // No non-empty ICC profile markers were found.
170 return nullptr;
171 }
172
173 // Combine the ICC marker data into a contiguous profile.
msarett9876ac52016-06-01 14:47:18 -0700174 sk_sp<SkData> iccData = SkData::MakeUninitialized(totalBytes);
175 void* dst = iccData->writable_data();
msarett0e6274f2016-03-21 08:04:40 -0700176 for (uint32_t i = 1; i <= numMarkers; i++) {
177 jpeg_marker_struct* marker = markerSequence[i];
178 if (!marker) {
179 SkCodecPrintf("ICC Profile Error: Missing marker %d of %d.\n", i, numMarkers);
180 return nullptr;
181 }
182
183 void* src = SkTAddOffset<void>(marker->data, kICCHeaderSize);
184 size_t bytes = marker->data_length - kICCHeaderSize;
185 memcpy(dst, src, bytes);
186 dst = SkTAddOffset<void>(dst, bytes);
187 }
188
msarett9876ac52016-06-01 14:47:18 -0700189 return iccData;
msarett0e6274f2016-03-21 08:04:40 -0700190}
191
msarette16b04a2015-04-15 07:32:19 -0700192bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
193 JpegDecoderMgr** decoderMgrOut) {
194
195 // Create a JpegDecoderMgr to own all of the decompress information
Ben Wagner145dbcd2016-11-03 14:40:50 -0400196 std::unique_ptr<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream));
msarette16b04a2015-04-15 07:32:19 -0700197
198 // libjpeg errors will be caught and reported here
mtklein2f428962016-07-28 13:59:59 -0700199 if (setjmp(decoderMgr->getJmpBuf())) {
msarett50ce1f22016-07-29 06:23:33 -0700200 return decoderMgr->returnFalse("ReadHeader");
msarette16b04a2015-04-15 07:32:19 -0700201 }
202
203 // Initialize the decompress info and the source manager
204 decoderMgr->init();
205
msarett0e6274f2016-03-21 08:04:40 -0700206 // Instruct jpeg library to save the markers that we care about. Since
207 // the orientation and color profile will not change, we can skip this
208 // step on rewinds.
209 if (codecOut) {
210 jpeg_save_markers(decoderMgr->dinfo(), kExifMarker, 0xFFFF);
211 jpeg_save_markers(decoderMgr->dinfo(), kICCMarker, 0xFFFF);
212 }
213
msarette16b04a2015-04-15 07:32:19 -0700214 // Read the jpeg header
msarettfbccb592015-09-01 06:43:41 -0700215 if (JPEG_HEADER_OK != jpeg_read_header(decoderMgr->dinfo(), true)) {
msarett50ce1f22016-07-29 06:23:33 -0700216 return decoderMgr->returnFalse("ReadHeader");
msarette16b04a2015-04-15 07:32:19 -0700217 }
218
msarett0e6274f2016-03-21 08:04:40 -0700219 if (codecOut) {
msarettc30c4182016-04-20 11:53:35 -0700220 // Get the encoded color type
msarettac6c7502016-04-25 09:30:24 -0700221 SkEncodedInfo::Color color;
222 if (!decoderMgr->getEncodedColor(&color)) {
msarettc30c4182016-04-20 11:53:35 -0700223 return false;
224 }
msarette16b04a2015-04-15 07:32:19 -0700225
226 // Create image info object and the codec
msarettc30c4182016-04-20 11:53:35 -0700227 SkEncodedInfo info = SkEncodedInfo::Make(color, SkEncodedInfo::kOpaque_Alpha, 8);
msarett0e6274f2016-03-21 08:04:40 -0700228
229 Origin orientation = get_exif_orientation(decoderMgr->dinfo());
msarett9876ac52016-06-01 14:47:18 -0700230 sk_sp<SkData> iccData = get_icc_profile(decoderMgr->dinfo());
231 sk_sp<SkColorSpace> colorSpace = nullptr;
raftiasd737bee2016-12-08 10:53:24 -0500232 bool unsupportedICC = false;
msarett9876ac52016-06-01 14:47:18 -0700233 if (iccData) {
raftias54761282016-12-01 13:44:07 -0500234 SkColorSpace_Base::InputColorFormat inputColorFormat =
235 SkColorSpace_Base::InputColorFormat::kRGB;
236 switch (decoderMgr->dinfo()->jpeg_color_space) {
237 case JCS_CMYK:
238 case JCS_YCCK:
239 inputColorFormat = SkColorSpace_Base::InputColorFormat::kCMYK;
240 break;
raftias91db12d2016-12-02 11:56:59 -0500241 case JCS_GRAYSCALE:
242 inputColorFormat = SkColorSpace_Base::InputColorFormat::kGray;
243 break;
raftias54761282016-12-01 13:44:07 -0500244 default:
245 break;
246 }
247 colorSpace = SkColorSpace_Base::MakeICC(iccData->data(), iccData->size(),
248 inputColorFormat);
msarett9876ac52016-06-01 14:47:18 -0700249 if (!colorSpace) {
250 SkCodecPrintf("Could not create SkColorSpace from ICC data.\n");
raftiasd737bee2016-12-08 10:53:24 -0500251 unsupportedICC = true;
msarett9876ac52016-06-01 14:47:18 -0700252 }
253 }
msarettf34cd632016-05-25 10:13:53 -0700254 if (!colorSpace) {
255 // Treat unmarked jpegs as sRGB.
Brian Osman526972e2016-10-24 09:24:02 -0400256 colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
msarettf34cd632016-05-25 10:13:53 -0700257 }
msarett0e6274f2016-03-21 08:04:40 -0700258
msarettc30c4182016-04-20 11:53:35 -0700259 const int width = decoderMgr->dinfo()->image_width;
260 const int height = decoderMgr->dinfo()->image_height;
raftiasd737bee2016-12-08 10:53:24 -0500261 SkJpegCodec* codec = new SkJpegCodec(width, height, info, stream, decoderMgr.release(),
262 std::move(colorSpace), orientation);
263 codec->setUnsupportedICC(unsupportedICC);
264 *codecOut = codec;
msarette16b04a2015-04-15 07:32:19 -0700265 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700266 SkASSERT(nullptr != decoderMgrOut);
mtklein18300a32016-03-16 13:53:35 -0700267 *decoderMgrOut = decoderMgr.release();
msarette16b04a2015-04-15 07:32:19 -0700268 }
269 return true;
270}
271
272SkCodec* SkJpegCodec::NewFromStream(SkStream* stream) {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400273 std::unique_ptr<SkStream> streamDeleter(stream);
halcanary96fcdcc2015-08-27 07:41:13 -0700274 SkCodec* codec = nullptr;
275 if (ReadHeader(stream, &codec, nullptr)) {
msarette16b04a2015-04-15 07:32:19 -0700276 // Codec has taken ownership of the stream, we do not need to delete it
277 SkASSERT(codec);
mtklein18300a32016-03-16 13:53:35 -0700278 streamDeleter.release();
msarette16b04a2015-04-15 07:32:19 -0700279 return codec;
280 }
halcanary96fcdcc2015-08-27 07:41:13 -0700281 return nullptr;
msarette16b04a2015-04-15 07:32:19 -0700282}
283
msarettc30c4182016-04-20 11:53:35 -0700284SkJpegCodec::SkJpegCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream,
Matt Saretta9e9bfc2016-11-01 12:19:50 -0400285 JpegDecoderMgr* decoderMgr, sk_sp<SkColorSpace> colorSpace, Origin origin)
msarettf34cd632016-05-25 10:13:53 -0700286 : INHERITED(width, height, info, stream, std::move(colorSpace), origin)
msarette16b04a2015-04-15 07:32:19 -0700287 , fDecoderMgr(decoderMgr)
msarettfbccb592015-09-01 06:43:41 -0700288 , fReadyState(decoderMgr->dinfo()->global_state)
msarett50ce1f22016-07-29 06:23:33 -0700289 , fSwizzleSrcRow(nullptr)
290 , fColorXformSrcRow(nullptr)
msarett91c22b22016-02-22 12:27:46 -0800291 , fSwizzlerSubset(SkIRect::MakeEmpty())
msarette16b04a2015-04-15 07:32:19 -0700292{}
293
294/*
emmaleer8f4ba762015-08-14 07:44:46 -0700295 * Return the row bytes of a particular image type and width
296 */
msarett23e78d32016-02-06 15:58:50 -0800297static size_t get_row_bytes(const j_decompress_ptr dinfo) {
msarett70e418b2016-02-12 12:35:48 -0800298 const size_t colorBytes = (dinfo->out_color_space == JCS_RGB565) ? 2 :
299 dinfo->out_color_components;
emmaleer8f4ba762015-08-14 07:44:46 -0700300 return dinfo->output_width * colorBytes;
301
302}
scroggoe7fc14b2015-10-02 13:14:46 -0700303
304/*
305 * Calculate output dimensions based on the provided factors.
306 *
307 * Not to be used on the actual jpeg_decompress_struct used for decoding, since it will
308 * incorrectly modify num_components.
309 */
310void calc_output_dimensions(jpeg_decompress_struct* dinfo, unsigned int num, unsigned int denom) {
311 dinfo->num_components = 0;
312 dinfo->scale_num = num;
313 dinfo->scale_denom = denom;
314 jpeg_calc_output_dimensions(dinfo);
315}
316
emmaleer8f4ba762015-08-14 07:44:46 -0700317/*
msarette16b04a2015-04-15 07:32:19 -0700318 * Return a valid set of output dimensions for this decoder, given an input scale
319 */
320SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const {
msarett1c8a5872015-07-07 08:50:01 -0700321 // 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
322 // support these as well
scroggoe7fc14b2015-10-02 13:14:46 -0700323 unsigned int num;
324 unsigned int denom = 8;
msarettfdb47572015-10-13 12:50:14 -0700325 if (desiredScale >= 0.9375) {
msarett1c8a5872015-07-07 08:50:01 -0700326 num = 8;
msarettfdb47572015-10-13 12:50:14 -0700327 } else if (desiredScale >= 0.8125) {
msarett1c8a5872015-07-07 08:50:01 -0700328 num = 7;
msarettfdb47572015-10-13 12:50:14 -0700329 } else if (desiredScale >= 0.6875f) {
msarett1c8a5872015-07-07 08:50:01 -0700330 num = 6;
msarettfdb47572015-10-13 12:50:14 -0700331 } else if (desiredScale >= 0.5625f) {
msarett1c8a5872015-07-07 08:50:01 -0700332 num = 5;
msarettfdb47572015-10-13 12:50:14 -0700333 } else if (desiredScale >= 0.4375f) {
msarett1c8a5872015-07-07 08:50:01 -0700334 num = 4;
msarettfdb47572015-10-13 12:50:14 -0700335 } else if (desiredScale >= 0.3125f) {
msarett1c8a5872015-07-07 08:50:01 -0700336 num = 3;
msarettfdb47572015-10-13 12:50:14 -0700337 } else if (desiredScale >= 0.1875f) {
msarett1c8a5872015-07-07 08:50:01 -0700338 num = 2;
msarette16b04a2015-04-15 07:32:19 -0700339 } else {
msarett1c8a5872015-07-07 08:50:01 -0700340 num = 1;
msarette16b04a2015-04-15 07:32:19 -0700341 }
342
343 // Set up a fake decompress struct in order to use libjpeg to calculate output dimensions
344 jpeg_decompress_struct dinfo;
mtkleinf7aaadb2015-04-16 06:09:27 -0700345 sk_bzero(&dinfo, sizeof(dinfo));
msarette16b04a2015-04-15 07:32:19 -0700346 dinfo.image_width = this->getInfo().width();
347 dinfo.image_height = this->getInfo().height();
msarettfbccb592015-09-01 06:43:41 -0700348 dinfo.global_state = fReadyState;
scroggoe7fc14b2015-10-02 13:14:46 -0700349 calc_output_dimensions(&dinfo, num, denom);
msarette16b04a2015-04-15 07:32:19 -0700350
351 // Return the calculated output dimensions for the given scale
352 return SkISize::Make(dinfo.output_width, dinfo.output_height);
353}
354
scroggob427db12015-08-12 07:24:13 -0700355bool SkJpegCodec::onRewind() {
halcanary96fcdcc2015-08-27 07:41:13 -0700356 JpegDecoderMgr* decoderMgr = nullptr;
357 if (!ReadHeader(this->stream(), nullptr, &decoderMgr)) {
msarett50ce1f22016-07-29 06:23:33 -0700358 return fDecoderMgr->returnFalse("onRewind");
msarett97fdea62015-04-29 08:17:15 -0700359 }
halcanary96fcdcc2015-08-27 07:41:13 -0700360 SkASSERT(nullptr != decoderMgr);
scroggob427db12015-08-12 07:24:13 -0700361 fDecoderMgr.reset(decoderMgr);
msarett2812f032016-07-18 15:56:08 -0700362
363 fSwizzler.reset(nullptr);
msarett50ce1f22016-07-29 06:23:33 -0700364 fSwizzleSrcRow = nullptr;
365 fColorXformSrcRow = nullptr;
msarett2812f032016-07-18 15:56:08 -0700366 fStorage.reset();
367
scroggob427db12015-08-12 07:24:13 -0700368 return true;
msarett97fdea62015-04-29 08:17:15 -0700369}
370
371/*
msarett1c8a5872015-07-07 08:50:01 -0700372 * Checks if the conversion between the input image and the requested output
373 * image has been implemented
374 * Sets the output color space
375 */
msarett2ecc35f2016-09-08 11:55:16 -0700376bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dstInfo) {
msarett50ce1f22016-07-29 06:23:33 -0700377 if (kUnknown_SkAlphaType == dstInfo.alphaType()) {
msarett1c8a5872015-07-07 08:50:01 -0700378 return false;
379 }
380
msarett50ce1f22016-07-29 06:23:33 -0700381 if (kOpaque_SkAlphaType != dstInfo.alphaType()) {
scroggoc5560be2016-02-03 09:42:42 -0800382 SkCodecPrintf("Warning: an opaque image should be decoded as opaque "
383 "- it is being decoded as non-opaque, which will draw slower\n");
384 }
385
msarett50ce1f22016-07-29 06:23:33 -0700386 // Check if we will decode to CMYK. libjpeg-turbo does not convert CMYK to RGBA, so
387 // we must do it ourselves.
388 J_COLOR_SPACE encodedColorType = fDecoderMgr->dinfo()->jpeg_color_space;
389 bool isCMYK = (JCS_CMYK == encodedColorType || JCS_YCCK == encodedColorType);
msarett1c8a5872015-07-07 08:50:01 -0700390
391 // Check for valid color types and set the output color space
msarett50ce1f22016-07-29 06:23:33 -0700392 switch (dstInfo.colorType()) {
msarett34e0ec42016-04-22 16:27:24 -0700393 case kRGBA_8888_SkColorType:
msarett1c8a5872015-07-07 08:50:01 -0700394 if (isCMYK) {
395 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
396 } else {
msarettf25bff92016-07-21 12:00:24 -0700397 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
msarett34e0ec42016-04-22 16:27:24 -0700398 }
399 return true;
400 case kBGRA_8888_SkColorType:
401 if (isCMYK) {
402 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
Matt Sarett313c4632016-10-20 12:35:23 -0400403 } else if (this->colorXform()) {
Matt Sarett562e6812016-11-08 16:13:43 -0500404 // Always using RGBA as the input format for color xforms makes the
405 // implementation a little simpler.
msarett50ce1f22016-07-29 06:23:33 -0700406 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
msarett34e0ec42016-04-22 16:27:24 -0700407 } else {
msarettf25bff92016-07-21 12:00:24 -0700408 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA;
msarett1c8a5872015-07-07 08:50:01 -0700409 }
410 return true;
411 case kRGB_565_SkColorType:
Matt Sarett313c4632016-10-20 12:35:23 -0400412 if (this->colorXform()) {
msarett50ce1f22016-07-29 06:23:33 -0700413 return false;
414 }
415
msarett1c8a5872015-07-07 08:50:01 -0700416 if (isCMYK) {
scroggoef27d892015-10-23 09:29:22 -0700417 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
msarett1c8a5872015-07-07 08:50:01 -0700418 } else {
msarett8ff6ca62015-09-18 12:06:04 -0700419 fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE;
msarett1c8a5872015-07-07 08:50:01 -0700420 fDecoderMgr->dinfo()->out_color_space = JCS_RGB565;
421 }
422 return true;
423 case kGray_8_SkColorType:
Matt Sarett313c4632016-10-20 12:35:23 -0400424 if (this->colorXform() || JCS_GRAYSCALE != encodedColorType) {
msarett39979d82016-07-28 17:11:18 -0700425 return false;
msarett50ce1f22016-07-29 06:23:33 -0700426 }
427
428 fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE;
429 return true;
430 case kRGBA_F16_SkColorType:
Matt Sarett313c4632016-10-20 12:35:23 -0400431 SkASSERT(this->colorXform());
432
msarett2ecc35f2016-09-08 11:55:16 -0700433 if (!dstInfo.colorSpace()->gammaIsLinear()) {
434 return false;
435 }
msarett50ce1f22016-07-29 06:23:33 -0700436
437 if (isCMYK) {
438 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
msarett1c8a5872015-07-07 08:50:01 -0700439 } else {
msarett50ce1f22016-07-29 06:23:33 -0700440 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
msarett1c8a5872015-07-07 08:50:01 -0700441 }
442 return true;
443 default:
444 return false;
445 }
446}
447
448/*
mtkleine721a8e2016-02-06 19:12:23 -0800449 * Checks if we can natively scale to the requested dimensions and natively scales the
emmaleer8f4ba762015-08-14 07:44:46 -0700450 * dimensions if possible
msarett97fdea62015-04-29 08:17:15 -0700451 */
scroggoe7fc14b2015-10-02 13:14:46 -0700452bool SkJpegCodec::onDimensionsSupported(const SkISize& size) {
mtklein2f428962016-07-28 13:59:59 -0700453 if (setjmp(fDecoderMgr->getJmpBuf())) {
msarett50ce1f22016-07-29 06:23:33 -0700454 return fDecoderMgr->returnFalse("onDimensionsSupported");
scroggoe7fc14b2015-10-02 13:14:46 -0700455 }
456
457 const unsigned int dstWidth = size.width();
458 const unsigned int dstHeight = size.height();
459
460 // Set up a fake decompress struct in order to use libjpeg to calculate output dimensions
461 // FIXME: Why is this necessary?
462 jpeg_decompress_struct dinfo;
463 sk_bzero(&dinfo, sizeof(dinfo));
464 dinfo.image_width = this->getInfo().width();
465 dinfo.image_height = this->getInfo().height();
466 dinfo.global_state = fReadyState;
467
msarett1c8a5872015-07-07 08:50:01 -0700468 // 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 -0700469 unsigned int num = 8;
470 const unsigned int denom = 8;
471 calc_output_dimensions(&dinfo, num, denom);
472 while (dinfo.output_width != dstWidth || dinfo.output_height != dstHeight) {
msarett97fdea62015-04-29 08:17:15 -0700473
474 // Return a failure if we have tried all of the possible scales
scroggoe7fc14b2015-10-02 13:14:46 -0700475 if (1 == num || dstWidth > dinfo.output_width || dstHeight > dinfo.output_height) {
emmaleer8f4ba762015-08-14 07:44:46 -0700476 return false;
msarett97fdea62015-04-29 08:17:15 -0700477 }
478
479 // Try the next scale
scroggoe7fc14b2015-10-02 13:14:46 -0700480 num -= 1;
481 calc_output_dimensions(&dinfo, num, denom);
msarett97fdea62015-04-29 08:17:15 -0700482 }
scroggoe7fc14b2015-10-02 13:14:46 -0700483
484 fDecoderMgr->dinfo()->scale_num = num;
485 fDecoderMgr->dinfo()->scale_denom = denom;
msarett97fdea62015-04-29 08:17:15 -0700486 return true;
487}
488
msarett50ce1f22016-07-29 06:23:33 -0700489int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count) {
490 // Set the jump location for libjpeg-turbo errors
491 if (setjmp(fDecoderMgr->getJmpBuf())) {
492 return 0;
493 }
494
495 // When fSwizzleSrcRow is non-null, it means that we need to swizzle. In this case,
496 // we will always decode into fSwizzlerSrcRow before swizzling into the next buffer.
497 // We can never swizzle "in place" because the swizzler may perform sampling and/or
498 // subsetting.
499 // When fColorXformSrcRow is non-null, it means that we need to color xform and that
500 // we cannot color xform "in place" (many times we can, but not when the dst is F16).
Matt Sarett313c4632016-10-20 12:35:23 -0400501 // In this case, we will color xform from fColorXformSrcRow into the dst.
msarett50ce1f22016-07-29 06:23:33 -0700502 JSAMPLE* decodeDst = (JSAMPLE*) dst;
503 uint32_t* swizzleDst = (uint32_t*) dst;
504 size_t decodeDstRowBytes = rowBytes;
505 size_t swizzleDstRowBytes = rowBytes;
Matt Sarett966bb342016-12-12 16:30:13 -0500506 int dstWidth = this->options().fSubset ? this->options().fSubset->width() : dstInfo.width();
msarett50ce1f22016-07-29 06:23:33 -0700507 if (fSwizzleSrcRow && fColorXformSrcRow) {
508 decodeDst = (JSAMPLE*) fSwizzleSrcRow;
509 swizzleDst = fColorXformSrcRow;
510 decodeDstRowBytes = 0;
511 swizzleDstRowBytes = 0;
msarett35bb74b2016-08-22 07:41:28 -0700512 dstWidth = fSwizzler->swizzleWidth();
msarett50ce1f22016-07-29 06:23:33 -0700513 } else if (fColorXformSrcRow) {
514 decodeDst = (JSAMPLE*) fColorXformSrcRow;
515 swizzleDst = fColorXformSrcRow;
516 decodeDstRowBytes = 0;
517 swizzleDstRowBytes = 0;
518 } else if (fSwizzleSrcRow) {
519 decodeDst = (JSAMPLE*) fSwizzleSrcRow;
520 decodeDstRowBytes = 0;
msarett35bb74b2016-08-22 07:41:28 -0700521 dstWidth = fSwizzler->swizzleWidth();
msarett50ce1f22016-07-29 06:23:33 -0700522 }
523
524 for (int y = 0; y < count; y++) {
525 uint32_t lines = jpeg_read_scanlines(fDecoderMgr->dinfo(), &decodeDst, 1);
526 size_t srcRowBytes = get_row_bytes(fDecoderMgr->dinfo());
527 sk_msan_mark_initialized(decodeDst, decodeDst + srcRowBytes, "skbug.com/4550");
528 if (0 == lines) {
529 return y;
530 }
531
532 if (fSwizzler) {
533 fSwizzler->swizzle(swizzleDst, decodeDst);
534 }
535
Matt Sarett313c4632016-10-20 12:35:23 -0400536 if (this->colorXform()) {
537 SkAssertResult(this->colorXform()->apply(select_xform_format(dstInfo.colorType()), dst,
538 SkColorSpaceXform::kRGBA_8888_ColorFormat, swizzleDst, dstWidth,
539 kOpaque_SkAlphaType));
msarett50ce1f22016-07-29 06:23:33 -0700540 dst = SkTAddOffset<void>(dst, rowBytes);
541 }
542
543 decodeDst = SkTAddOffset<JSAMPLE>(decodeDst, decodeDstRowBytes);
544 swizzleDst = SkTAddOffset<uint32_t>(swizzleDst, swizzleDstRowBytes);
545 }
546
547 return count;
548}
549
msarett97fdea62015-04-29 08:17:15 -0700550/*
msarette16b04a2015-04-15 07:32:19 -0700551 * Performs the jpeg decode
552 */
553SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
554 void* dst, size_t dstRowBytes,
msarette6dd0042015-10-09 11:07:34 -0700555 const Options& options, SkPMColor*, int*,
556 int* rowsDecoded) {
scroggob636b452015-07-22 07:16:20 -0700557 if (options.fSubset) {
558 // Subsets are not supported.
559 return kUnimplemented;
560 }
561
msarette16b04a2015-04-15 07:32:19 -0700562 // Get a pointer to the decompress info since we will use it quite frequently
563 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
564
565 // Set the jump location for libjpeg errors
mtklein2f428962016-07-28 13:59:59 -0700566 if (setjmp(fDecoderMgr->getJmpBuf())) {
msarette16b04a2015-04-15 07:32:19 -0700567 return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
568 }
569
Matt Sarett313c4632016-10-20 12:35:23 -0400570 if (!this->initializeColorXform(dstInfo)) {
571 return kInvalidConversion;
572 }
msarett50ce1f22016-07-29 06:23:33 -0700573
msarett2ecc35f2016-09-08 11:55:16 -0700574 // Check if we can decode to the requested destination and set the output color space
575 if (!this->setOutputColorSpace(dstInfo)) {
576 return fDecoderMgr->returnFailure("setOutputColorSpace", kInvalidConversion);
msarett85c922a2016-09-08 10:54:34 -0700577 }
578
msarettfbccb592015-09-01 06:43:41 -0700579 if (!jpeg_start_decompress(dinfo)) {
msarette16b04a2015-04-15 07:32:19 -0700580 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
581 }
582
msarett1c8a5872015-07-07 08:50:01 -0700583 // The recommended output buffer height should always be 1 in high quality modes.
584 // If it's not, we want to know because it means our strategy is not optimal.
585 SkASSERT(1 == dinfo->rec_outbuf_height);
msarette16b04a2015-04-15 07:32:19 -0700586
msarett70e418b2016-02-12 12:35:48 -0800587 J_COLOR_SPACE colorSpace = dinfo->out_color_space;
raftias54761282016-12-01 13:44:07 -0500588 if (JCS_CMYK == colorSpace && nullptr == this->colorXform()) {
scroggoef27d892015-10-23 09:29:22 -0700589 this->initializeSwizzler(dstInfo, options);
590 }
591
msarett50ce1f22016-07-29 06:23:33 -0700592 this->allocateStorage(dstInfo);
scroggoef27d892015-10-23 09:29:22 -0700593
msarett50ce1f22016-07-29 06:23:33 -0700594 int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height());
595 if (rows < dstInfo.height()) {
596 *rowsDecoded = rows;
597 return fDecoderMgr->returnFailure("Incomplete image data", kIncompleteInput);
msarette16b04a2015-04-15 07:32:19 -0700598 }
msarette16b04a2015-04-15 07:32:19 -0700599
600 return kSuccess;
601}
msarett97fdea62015-04-29 08:17:15 -0700602
msarett50ce1f22016-07-29 06:23:33 -0700603void SkJpegCodec::allocateStorage(const SkImageInfo& dstInfo) {
msarett35bb74b2016-08-22 07:41:28 -0700604 int dstWidth = dstInfo.width();
605
msarett50ce1f22016-07-29 06:23:33 -0700606 size_t swizzleBytes = 0;
607 if (fSwizzler) {
608 swizzleBytes = get_row_bytes(fDecoderMgr->dinfo());
msarett35bb74b2016-08-22 07:41:28 -0700609 dstWidth = fSwizzler->swizzleWidth();
Matt Sarett313c4632016-10-20 12:35:23 -0400610 SkASSERT(!this->colorXform() || SkIsAlign4(swizzleBytes));
msarett50ce1f22016-07-29 06:23:33 -0700611 }
612
613 size_t xformBytes = 0;
614 if (kRGBA_F16_SkColorType == dstInfo.colorType()) {
Matt Sarett313c4632016-10-20 12:35:23 -0400615 SkASSERT(this->colorXform());
msarett35bb74b2016-08-22 07:41:28 -0700616 xformBytes = dstWidth * sizeof(uint32_t);
msarett50ce1f22016-07-29 06:23:33 -0700617 }
618
619 size_t totalBytes = swizzleBytes + xformBytes;
620 if (totalBytes > 0) {
621 fStorage.reset(totalBytes);
622 fSwizzleSrcRow = (swizzleBytes > 0) ? fStorage.get() : nullptr;
623 fColorXformSrcRow = (xformBytes > 0) ?
624 SkTAddOffset<uint32_t>(fStorage.get(), swizzleBytes) : nullptr;
625 }
626}
627
msarettfdb47572015-10-13 12:50:14 -0700628void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) {
Matt Sarett9bf39c22016-12-13 13:29:54 -0500629 // libjpeg-turbo will handle format conversion from YUV to RGBA, BGRA, or 565. fColorXform
630 // will handle format conversion from CMYK. We only need the swizzler to perform format
631 // conversion when we have a CMYK image without a fColorXform.
632 bool skipFormatConversion = this->colorXform() ||
633 (JCS_CMYK != fDecoderMgr->dinfo()->out_color_space);
634
msaretta45a6682016-04-22 13:18:37 -0700635 SkEncodedInfo swizzlerInfo = this->getEncodedInfo();
Matt Sarett9bf39c22016-12-13 13:29:54 -0500636 if (!skipFormatConversion) {
mtkleinda19f6f2016-08-23 11:49:29 -0700637 swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kInvertedCMYK_Color,
638 swizzlerInfo.alpha(),
639 swizzlerInfo.bitsPerComponent());
msarett70e418b2016-02-12 12:35:48 -0800640 }
641
msarett91c22b22016-02-22 12:27:46 -0800642 Options swizzlerOptions = options;
643 if (options.fSubset) {
644 // Use fSwizzlerSubset if this is a subset decode. This is necessary in the case
645 // where libjpeg-turbo provides a subset and then we need to subset it further.
646 // Also, verify that fSwizzlerSubset is initialized and valid.
647 SkASSERT(!fSwizzlerSubset.isEmpty() && fSwizzlerSubset.x() <= options.fSubset->x() &&
648 fSwizzlerSubset.width() == options.fSubset->width());
649 swizzlerOptions.fSubset = &fSwizzlerSubset;
650 }
msarett68758ae2016-04-25 11:41:15 -0700651 fSwizzler.reset(SkSwizzler::CreateSwizzler(swizzlerInfo, nullptr, dstInfo, swizzlerOptions,
Matt Sarett9bf39c22016-12-13 13:29:54 -0500652 nullptr, skipFormatConversion));
msarettb30d6982016-02-15 10:18:45 -0800653 SkASSERT(fSwizzler);
msarett50ce1f22016-07-29 06:23:33 -0700654}
655
msarettfdb47572015-10-13 12:50:14 -0700656SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) {
657 if (!createIfNecessary || fSwizzler) {
msarett50ce1f22016-07-29 06:23:33 -0700658 SkASSERT(!fSwizzler || (fSwizzleSrcRow && fStorage.get() == fSwizzleSrcRow));
Ben Wagner145dbcd2016-11-03 14:40:50 -0400659 return fSwizzler.get();
msarettfdb47572015-10-13 12:50:14 -0700660 }
661
662 this->initializeSwizzler(this->dstInfo(), this->options());
msarett50ce1f22016-07-29 06:23:33 -0700663 this->allocateStorage(this->dstInfo());
Ben Wagner145dbcd2016-11-03 14:40:50 -0400664 return fSwizzler.get();
scroggo46c57472015-09-30 08:57:13 -0700665}
scroggo1c005e42015-08-04 09:24:45 -0700666
scroggo46c57472015-09-30 08:57:13 -0700667SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
668 const Options& options, SkPMColor ctable[], int* ctableCount) {
scroggo46c57472015-09-30 08:57:13 -0700669 // Set the jump location for libjpeg errors
mtklein2f428962016-07-28 13:59:59 -0700670 if (setjmp(fDecoderMgr->getJmpBuf())) {
scroggo46c57472015-09-30 08:57:13 -0700671 SkCodecPrintf("setjmp: Error from libjpeg\n");
672 return kInvalidInput;
673 }
674
Matt Sarett313c4632016-10-20 12:35:23 -0400675 if (!this->initializeColorXform(dstInfo)) {
676 return kInvalidConversion;
677 }
msarett85c922a2016-09-08 10:54:34 -0700678
msarett2ecc35f2016-09-08 11:55:16 -0700679 // Check if we can decode to the requested destination and set the output color space
680 if (!this->setOutputColorSpace(dstInfo)) {
681 return fDecoderMgr->returnFailure("setOutputColorSpace", kInvalidConversion);
msarett50ce1f22016-07-29 06:23:33 -0700682 }
683
scroggo46c57472015-09-30 08:57:13 -0700684 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) {
685 SkCodecPrintf("start decompress failed\n");
686 return kInvalidInput;
687 }
688
msarett91c22b22016-02-22 12:27:46 -0800689 if (options.fSubset) {
690 uint32_t startX = options.fSubset->x();
691 uint32_t width = options.fSubset->width();
692
693 // libjpeg-turbo may need to align startX to a multiple of the IDCT
694 // block size. If this is the case, it will decrease the value of
695 // startX to the appropriate alignment and also increase the value
696 // of width so that the right edge of the requested subset remains
697 // the same.
698 jpeg_crop_scanline(fDecoderMgr->dinfo(), &startX, &width);
699
700 SkASSERT(startX <= (uint32_t) options.fSubset->x());
701 SkASSERT(width >= (uint32_t) options.fSubset->width());
702 SkASSERT(startX + width >= (uint32_t) options.fSubset->right());
703
704 // Instruct the swizzler (if it is necessary) to further subset the
705 // output provided by libjpeg-turbo.
706 //
707 // We set this here (rather than in the if statement below), so that
708 // if (1) we don't need a swizzler for the subset, and (2) we need a
709 // swizzler for CMYK, the swizzler will still use the proper subset
710 // dimensions.
711 //
712 // Note that the swizzler will ignore the y and height parameters of
713 // the subset. Since the scanline decoder (and the swizzler) handle
714 // one row at a time, only the subsetting in the x-dimension matters.
715 fSwizzlerSubset.setXYWH(options.fSubset->x() - startX, 0,
716 options.fSubset->width(), options.fSubset->height());
717
718 // We will need a swizzler if libjpeg-turbo cannot provide the exact
719 // subset that we request.
720 if (startX != (uint32_t) options.fSubset->x() ||
721 width != (uint32_t) options.fSubset->width()) {
722 this->initializeSwizzler(dstInfo, options);
723 }
724 }
725
726 // Make sure we have a swizzler if we are converting from CMYK.
727 if (!fSwizzler && JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) {
728 this->initializeSwizzler(dstInfo, options);
729 }
msarettfdb47572015-10-13 12:50:14 -0700730
msarett50ce1f22016-07-29 06:23:33 -0700731 this->allocateStorage(dstInfo);
732
scroggo46c57472015-09-30 08:57:13 -0700733 return kSuccess;
734}
735
mtkleine721a8e2016-02-06 19:12:23 -0800736int SkJpegCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
msarett50ce1f22016-07-29 06:23:33 -0700737 int rows = this->readRows(this->dstInfo(), dst, dstRowBytes, count);
738 if (rows < count) {
739 // This allows us to skip calling jpeg_finish_decompress().
740 fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height();
scroggo46c57472015-09-30 08:57:13 -0700741 }
742
msarett50ce1f22016-07-29 06:23:33 -0700743 return rows;
scroggo46c57472015-09-30 08:57:13 -0700744}
msarett97fdea62015-04-29 08:17:15 -0700745
msarette6dd0042015-10-09 11:07:34 -0700746bool SkJpegCodec::onSkipScanlines(int count) {
scroggo46c57472015-09-30 08:57:13 -0700747 // Set the jump location for libjpeg errors
mtklein2f428962016-07-28 13:59:59 -0700748 if (setjmp(fDecoderMgr->getJmpBuf())) {
msarett50ce1f22016-07-29 06:23:33 -0700749 return fDecoderMgr->returnFalse("onSkipScanlines");
msarett97fdea62015-04-29 08:17:15 -0700750 }
751
msarettf724b992015-10-15 06:41:06 -0700752 return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count);
msarett97fdea62015-04-29 08:17:15 -0700753}
msarettb714fb02016-01-22 14:46:42 -0800754
755static bool is_yuv_supported(jpeg_decompress_struct* dinfo) {
756 // Scaling is not supported in raw data mode.
757 SkASSERT(dinfo->scale_num == dinfo->scale_denom);
758
759 // I can't imagine that this would ever change, but we do depend on it.
760 static_assert(8 == DCTSIZE, "DCTSIZE (defined in jpeg library) should always be 8.");
761
762 if (JCS_YCbCr != dinfo->jpeg_color_space) {
763 return false;
764 }
765
766 SkASSERT(3 == dinfo->num_components);
767 SkASSERT(dinfo->comp_info);
768
769 // It is possible to perform a YUV decode for any combination of
770 // horizontal and vertical sampling that is supported by
771 // libjpeg/libjpeg-turbo. However, we will start by supporting only the
772 // common cases (where U and V have samp_factors of one).
773 //
774 // The definition of samp_factor is kind of the opposite of what SkCodec
775 // thinks of as a sampling factor. samp_factor is essentially a
776 // multiplier, and the larger the samp_factor is, the more samples that
777 // there will be. Ex:
778 // U_plane_width = image_width * (U_h_samp_factor / max_h_samp_factor)
779 //
780 // Supporting cases where the samp_factors for U or V were larger than
781 // that of Y would be an extremely difficult change, given that clients
782 // allocate memory as if the size of the Y plane is always the size of the
783 // image. However, this case is very, very rare.
msarett7c87cf42016-03-04 06:23:20 -0800784 if ((1 != dinfo->comp_info[1].h_samp_factor) ||
785 (1 != dinfo->comp_info[1].v_samp_factor) ||
786 (1 != dinfo->comp_info[2].h_samp_factor) ||
787 (1 != dinfo->comp_info[2].v_samp_factor))
788 {
msarettb714fb02016-01-22 14:46:42 -0800789 return false;
790 }
791
792 // Support all common cases of Y samp_factors.
793 // TODO (msarett): As mentioned above, it would be possible to support
794 // more combinations of samp_factors. The issues are:
795 // (1) Are there actually any images that are not covered
796 // by these cases?
797 // (2) How much complexity would be added to the
798 // implementation in order to support these rare
799 // cases?
800 int hSampY = dinfo->comp_info[0].h_samp_factor;
801 int vSampY = dinfo->comp_info[0].v_samp_factor;
802 return (1 == hSampY && 1 == vSampY) ||
803 (2 == hSampY && 1 == vSampY) ||
804 (2 == hSampY && 2 == vSampY) ||
805 (1 == hSampY && 2 == vSampY) ||
806 (4 == hSampY && 1 == vSampY) ||
807 (4 == hSampY && 2 == vSampY);
808}
809
msarett4984c3c2016-03-10 05:44:43 -0800810bool SkJpegCodec::onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const {
msarettb714fb02016-01-22 14:46:42 -0800811 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
812 if (!is_yuv_supported(dinfo)) {
813 return false;
814 }
815
msarett4984c3c2016-03-10 05:44:43 -0800816 sizeInfo->fSizes[SkYUVSizeInfo::kY].set(dinfo->comp_info[0].downsampled_width,
817 dinfo->comp_info[0].downsampled_height);
818 sizeInfo->fSizes[SkYUVSizeInfo::kU].set(dinfo->comp_info[1].downsampled_width,
819 dinfo->comp_info[1].downsampled_height);
820 sizeInfo->fSizes[SkYUVSizeInfo::kV].set(dinfo->comp_info[2].downsampled_width,
821 dinfo->comp_info[2].downsampled_height);
822 sizeInfo->fWidthBytes[SkYUVSizeInfo::kY] = dinfo->comp_info[0].width_in_blocks * DCTSIZE;
823 sizeInfo->fWidthBytes[SkYUVSizeInfo::kU] = dinfo->comp_info[1].width_in_blocks * DCTSIZE;
824 sizeInfo->fWidthBytes[SkYUVSizeInfo::kV] = dinfo->comp_info[2].width_in_blocks * DCTSIZE;
msarettb714fb02016-01-22 14:46:42 -0800825
826 if (colorSpace) {
827 *colorSpace = kJPEG_SkYUVColorSpace;
828 }
829
830 return true;
831}
832
msarett4984c3c2016-03-10 05:44:43 -0800833SkCodec::Result SkJpegCodec::onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) {
834 SkYUVSizeInfo defaultInfo;
msarettb714fb02016-01-22 14:46:42 -0800835
836 // This will check is_yuv_supported(), so we don't need to here.
837 bool supportsYUV = this->onQueryYUV8(&defaultInfo, nullptr);
msarett4984c3c2016-03-10 05:44:43 -0800838 if (!supportsYUV ||
839 sizeInfo.fSizes[SkYUVSizeInfo::kY] != defaultInfo.fSizes[SkYUVSizeInfo::kY] ||
840 sizeInfo.fSizes[SkYUVSizeInfo::kU] != defaultInfo.fSizes[SkYUVSizeInfo::kU] ||
841 sizeInfo.fSizes[SkYUVSizeInfo::kV] != defaultInfo.fSizes[SkYUVSizeInfo::kV] ||
842 sizeInfo.fWidthBytes[SkYUVSizeInfo::kY] < defaultInfo.fWidthBytes[SkYUVSizeInfo::kY] ||
843 sizeInfo.fWidthBytes[SkYUVSizeInfo::kU] < defaultInfo.fWidthBytes[SkYUVSizeInfo::kU] ||
844 sizeInfo.fWidthBytes[SkYUVSizeInfo::kV] < defaultInfo.fWidthBytes[SkYUVSizeInfo::kV]) {
msarettb714fb02016-01-22 14:46:42 -0800845 return fDecoderMgr->returnFailure("onGetYUV8Planes", kInvalidInput);
846 }
847
848 // Set the jump location for libjpeg errors
mtklein2f428962016-07-28 13:59:59 -0700849 if (setjmp(fDecoderMgr->getJmpBuf())) {
msarettb714fb02016-01-22 14:46:42 -0800850 return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
851 }
852
853 // Get a pointer to the decompress info since we will use it quite frequently
854 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
855
856 dinfo->raw_data_out = TRUE;
857 if (!jpeg_start_decompress(dinfo)) {
858 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
859 }
860
861 // A previous implementation claims that the return value of is_yuv_supported()
862 // may change after calling jpeg_start_decompress(). It looks to me like this
863 // was caused by a bug in the old code, but we'll be safe and check here.
864 SkASSERT(is_yuv_supported(dinfo));
865
866 // Currently, we require that the Y plane dimensions match the image dimensions
867 // and that the U and V planes are the same dimensions.
msarett4984c3c2016-03-10 05:44:43 -0800868 SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kU] == sizeInfo.fSizes[SkYUVSizeInfo::kV]);
869 SkASSERT((uint32_t) sizeInfo.fSizes[SkYUVSizeInfo::kY].width() == dinfo->output_width &&
870 (uint32_t) sizeInfo.fSizes[SkYUVSizeInfo::kY].height() == dinfo->output_height);
msarettb714fb02016-01-22 14:46:42 -0800871
872 // Build a JSAMPIMAGE to handle output from libjpeg-turbo. A JSAMPIMAGE has
873 // a 2-D array of pixels for each of the components (Y, U, V) in the image.
874 // Cheat Sheet:
875 // JSAMPIMAGE == JSAMPLEARRAY* == JSAMPROW** == JSAMPLE***
876 JSAMPARRAY yuv[3];
877
878 // Set aside enough space for pointers to rows of Y, U, and V.
879 JSAMPROW rowptrs[2 * DCTSIZE + DCTSIZE + DCTSIZE];
880 yuv[0] = &rowptrs[0]; // Y rows (DCTSIZE or 2 * DCTSIZE)
881 yuv[1] = &rowptrs[2 * DCTSIZE]; // U rows (DCTSIZE)
882 yuv[2] = &rowptrs[3 * DCTSIZE]; // V rows (DCTSIZE)
883
884 // Initialize rowptrs.
885 int numYRowsPerBlock = DCTSIZE * dinfo->comp_info[0].v_samp_factor;
886 for (int i = 0; i < numYRowsPerBlock; i++) {
msarett4984c3c2016-03-10 05:44:43 -0800887 rowptrs[i] = SkTAddOffset<JSAMPLE>(planes[SkYUVSizeInfo::kY],
888 i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kY]);
msarettb714fb02016-01-22 14:46:42 -0800889 }
890 for (int i = 0; i < DCTSIZE; i++) {
msarett4984c3c2016-03-10 05:44:43 -0800891 rowptrs[i + 2 * DCTSIZE] = SkTAddOffset<JSAMPLE>(planes[SkYUVSizeInfo::kU],
892 i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kU]);
893 rowptrs[i + 3 * DCTSIZE] = SkTAddOffset<JSAMPLE>(planes[SkYUVSizeInfo::kV],
894 i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kV]);
msarettb714fb02016-01-22 14:46:42 -0800895 }
896
897 // After each loop iteration, we will increment pointers to Y, U, and V.
msarett4984c3c2016-03-10 05:44:43 -0800898 size_t blockIncrementY = numYRowsPerBlock * sizeInfo.fWidthBytes[SkYUVSizeInfo::kY];
899 size_t blockIncrementU = DCTSIZE * sizeInfo.fWidthBytes[SkYUVSizeInfo::kU];
900 size_t blockIncrementV = DCTSIZE * sizeInfo.fWidthBytes[SkYUVSizeInfo::kV];
msarettb714fb02016-01-22 14:46:42 -0800901
902 uint32_t numRowsPerBlock = numYRowsPerBlock;
903
904 // We intentionally round down here, as this first loop will only handle
905 // full block rows. As a special case at the end, we will handle any
906 // remaining rows that do not make up a full block.
907 const int numIters = dinfo->output_height / numRowsPerBlock;
908 for (int i = 0; i < numIters; i++) {
909 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock);
910 if (linesRead < numRowsPerBlock) {
911 // FIXME: Handle incomplete YUV decodes without signalling an error.
912 return kInvalidInput;
913 }
914
915 // Update rowptrs.
916 for (int i = 0; i < numYRowsPerBlock; i++) {
917 rowptrs[i] += blockIncrementY;
918 }
919 for (int i = 0; i < DCTSIZE; i++) {
920 rowptrs[i + 2 * DCTSIZE] += blockIncrementU;
921 rowptrs[i + 3 * DCTSIZE] += blockIncrementV;
922 }
923 }
924
925 uint32_t remainingRows = dinfo->output_height - dinfo->output_scanline;
926 SkASSERT(remainingRows == dinfo->output_height % numRowsPerBlock);
927 SkASSERT(dinfo->output_scanline == numIters * numRowsPerBlock);
928 if (remainingRows > 0) {
929 // libjpeg-turbo needs memory to be padded by the block sizes. We will fulfill
930 // this requirement using a dummy row buffer.
931 // FIXME: Should SkCodec have an extra memory buffer that can be shared among
932 // all of the implementations that use temporary/garbage memory?
msarett4984c3c2016-03-10 05:44:43 -0800933 SkAutoTMalloc<JSAMPLE> dummyRow(sizeInfo.fWidthBytes[SkYUVSizeInfo::kY]);
msarettb714fb02016-01-22 14:46:42 -0800934 for (int i = remainingRows; i < numYRowsPerBlock; i++) {
935 rowptrs[i] = dummyRow.get();
936 }
937 int remainingUVRows = dinfo->comp_info[1].downsampled_height - DCTSIZE * numIters;
938 for (int i = remainingUVRows; i < DCTSIZE; i++) {
939 rowptrs[i + 2 * DCTSIZE] = dummyRow.get();
940 rowptrs[i + 3 * DCTSIZE] = dummyRow.get();
941 }
942
943 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock);
944 if (linesRead < remainingRows) {
945 // FIXME: Handle incomplete YUV decodes without signalling an error.
946 return kInvalidInput;
947 }
948 }
949
950 return kSuccess;
951}