blob: d158b4215a0a632f9e5b8ad2a6b61777c98c3bd5 [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"
14#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;
46const uint32_t kICCHeaderSize = 14;
47const uint32_t kExifMarker = JPEG_APP0 + 1;
48const uint32_t kICCMarker = JPEG_APP0 + 2;
49
50static bool is_orientation_marker(jpeg_marker_struct* marker, SkCodec::Origin* orientation) {
51 if (kExifMarker != marker->marker || marker->data_length < kExifHeaderSize) {
52 return false;
53 }
54
55 const uint8_t* data = marker->data;
56 static const uint8_t kExifSig[] { 'E', 'x', 'i', 'f', '\0' };
57 if (memcmp(data, kExifSig, sizeof(kExifSig))) {
58 return false;
59 }
60
61 bool littleEndian;
62 if (!is_valid_endian_marker(data + 6, &littleEndian)) {
63 return false;
64 }
65
66 // Get the offset from the start of the marker.
67 // Account for 'E', 'x', 'i', 'f', '\0', '<fill byte>'.
68 uint32_t offset = get_endian_int(data + 10, littleEndian);
69 offset += sizeof(kExifSig) + 1;
70
71 // Require that the marker is at least large enough to contain the number of entries.
72 if (marker->data_length < offset + 2) {
73 return false;
74 }
75 uint32_t numEntries = get_endian_short(data + offset, littleEndian);
76
77 // Tag (2 bytes), Datatype (2 bytes), Number of elements (4 bytes), Data (4 bytes)
78 const uint32_t kEntrySize = 12;
79 numEntries = SkTMin(numEntries, (marker->data_length - offset - 2) / kEntrySize);
80
81 // Advance the data to the start of the entries.
82 data += offset + 2;
83
84 const uint16_t kOriginTag = 0x112;
85 const uint16_t kOriginType = 3;
86 for (uint32_t i = 0; i < numEntries; i++, data += kEntrySize) {
87 uint16_t tag = get_endian_short(data, littleEndian);
88 uint16_t type = get_endian_short(data + 2, littleEndian);
89 uint32_t count = get_endian_int(data + 4, littleEndian);
90 if (kOriginTag == tag && kOriginType == type && 1 == count) {
91 uint16_t val = get_endian_short(data + 8, littleEndian);
92 if (0 < val && val <= SkCodec::kLast_Origin) {
93 *orientation = (SkCodec::Origin) val;
94 return true;
95 }
96 }
97 }
98
99 return false;
100}
101
102static SkCodec::Origin get_exif_orientation(jpeg_decompress_struct* dinfo) {
103 SkCodec::Origin orientation;
104 for (jpeg_marker_struct* marker = dinfo->marker_list; marker; marker = marker->next) {
105 if (is_orientation_marker(marker, &orientation)) {
106 return orientation;
107 }
108 }
109
110 return SkCodec::kDefault_Origin;
111}
112
113static bool is_icc_marker(jpeg_marker_struct* marker) {
114 if (kICCMarker != marker->marker || marker->data_length < kICCHeaderSize) {
115 return false;
116 }
117
118 static const uint8_t kICCSig[] { 'I', 'C', 'C', '_', 'P', 'R', 'O', 'F', 'I', 'L', 'E', '\0' };
119 return !memcmp(marker->data, kICCSig, sizeof(kICCSig));
120}
121
122/*
123 * ICC profiles may be stored using a sequence of multiple markers. We obtain the ICC profile
124 * in two steps:
125 * (1) Discover all ICC profile markers and verify that they are numbered properly.
126 * (2) Copy the data from each marker into a contiguous ICC profile.
127 */
msarett9876ac52016-06-01 14:47:18 -0700128static sk_sp<SkData> get_icc_profile(jpeg_decompress_struct* dinfo) {
msarett0e6274f2016-03-21 08:04:40 -0700129 // Note that 256 will be enough storage space since each markerIndex is stored in 8-bits.
130 jpeg_marker_struct* markerSequence[256];
131 memset(markerSequence, 0, sizeof(markerSequence));
132 uint8_t numMarkers = 0;
133 size_t totalBytes = 0;
134
135 // Discover any ICC markers and verify that they are numbered properly.
136 for (jpeg_marker_struct* marker = dinfo->marker_list; marker; marker = marker->next) {
137 if (is_icc_marker(marker)) {
138 // Verify that numMarkers is valid and consistent.
139 if (0 == numMarkers) {
140 numMarkers = marker->data[13];
141 if (0 == numMarkers) {
142 SkCodecPrintf("ICC Profile Error: numMarkers must be greater than zero.\n");
143 return nullptr;
144 }
145 } else if (numMarkers != marker->data[13]) {
146 SkCodecPrintf("ICC Profile Error: numMarkers must be consistent.\n");
147 return nullptr;
148 }
149
150 // Verify that the markerIndex is valid and unique. Note that zero is not
151 // a valid index.
152 uint8_t markerIndex = marker->data[12];
153 if (markerIndex == 0 || markerIndex > numMarkers) {
154 SkCodecPrintf("ICC Profile Error: markerIndex is invalid.\n");
155 return nullptr;
156 }
157 if (markerSequence[markerIndex]) {
158 SkCodecPrintf("ICC Profile Error: Duplicate value of markerIndex.\n");
159 return nullptr;
160 }
161 markerSequence[markerIndex] = marker;
162 SkASSERT(marker->data_length >= kICCHeaderSize);
163 totalBytes += marker->data_length - kICCHeaderSize;
164 }
165 }
166
167 if (0 == totalBytes) {
168 // No non-empty ICC profile markers were found.
169 return nullptr;
170 }
171
172 // Combine the ICC marker data into a contiguous profile.
msarett9876ac52016-06-01 14:47:18 -0700173 sk_sp<SkData> iccData = SkData::MakeUninitialized(totalBytes);
174 void* dst = iccData->writable_data();
msarett0e6274f2016-03-21 08:04:40 -0700175 for (uint32_t i = 1; i <= numMarkers; i++) {
176 jpeg_marker_struct* marker = markerSequence[i];
177 if (!marker) {
178 SkCodecPrintf("ICC Profile Error: Missing marker %d of %d.\n", i, numMarkers);
179 return nullptr;
180 }
181
182 void* src = SkTAddOffset<void>(marker->data, kICCHeaderSize);
183 size_t bytes = marker->data_length - kICCHeaderSize;
184 memcpy(dst, src, bytes);
185 dst = SkTAddOffset<void>(dst, bytes);
186 }
187
msarett9876ac52016-06-01 14:47:18 -0700188 return iccData;
msarett0e6274f2016-03-21 08:04:40 -0700189}
190
msarette16b04a2015-04-15 07:32:19 -0700191bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
192 JpegDecoderMgr** decoderMgrOut) {
193
194 // Create a JpegDecoderMgr to own all of the decompress information
halcanary385fe4d2015-08-26 13:07:48 -0700195 SkAutoTDelete<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream));
msarette16b04a2015-04-15 07:32:19 -0700196
197 // libjpeg errors will be caught and reported here
mtklein2f428962016-07-28 13:59:59 -0700198 if (setjmp(decoderMgr->getJmpBuf())) {
msarett50ce1f22016-07-29 06:23:33 -0700199 return decoderMgr->returnFalse("ReadHeader");
msarette16b04a2015-04-15 07:32:19 -0700200 }
201
202 // Initialize the decompress info and the source manager
203 decoderMgr->init();
204
msarett0e6274f2016-03-21 08:04:40 -0700205 // Instruct jpeg library to save the markers that we care about. Since
206 // the orientation and color profile will not change, we can skip this
207 // step on rewinds.
208 if (codecOut) {
209 jpeg_save_markers(decoderMgr->dinfo(), kExifMarker, 0xFFFF);
210 jpeg_save_markers(decoderMgr->dinfo(), kICCMarker, 0xFFFF);
211 }
212
msarette16b04a2015-04-15 07:32:19 -0700213 // Read the jpeg header
msarettfbccb592015-09-01 06:43:41 -0700214 if (JPEG_HEADER_OK != jpeg_read_header(decoderMgr->dinfo(), true)) {
msarett50ce1f22016-07-29 06:23:33 -0700215 return decoderMgr->returnFalse("ReadHeader");
msarette16b04a2015-04-15 07:32:19 -0700216 }
217
msarett0e6274f2016-03-21 08:04:40 -0700218 if (codecOut) {
msarettc30c4182016-04-20 11:53:35 -0700219 // Get the encoded color type
msarettac6c7502016-04-25 09:30:24 -0700220 SkEncodedInfo::Color color;
221 if (!decoderMgr->getEncodedColor(&color)) {
msarettc30c4182016-04-20 11:53:35 -0700222 return false;
223 }
msarette16b04a2015-04-15 07:32:19 -0700224
225 // Create image info object and the codec
msarettc30c4182016-04-20 11:53:35 -0700226 SkEncodedInfo info = SkEncodedInfo::Make(color, SkEncodedInfo::kOpaque_Alpha, 8);
msarett0e6274f2016-03-21 08:04:40 -0700227
228 Origin orientation = get_exif_orientation(decoderMgr->dinfo());
msarett9876ac52016-06-01 14:47:18 -0700229 sk_sp<SkData> iccData = get_icc_profile(decoderMgr->dinfo());
230 sk_sp<SkColorSpace> colorSpace = nullptr;
231 if (iccData) {
232 colorSpace = SkColorSpace::NewICC(iccData->data(), iccData->size());
233 if (!colorSpace) {
234 SkCodecPrintf("Could not create SkColorSpace from ICC data.\n");
235 }
236 }
msarettf34cd632016-05-25 10:13:53 -0700237 if (!colorSpace) {
238 // Treat unmarked jpegs as sRGB.
239 colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
240 }
msarett0e6274f2016-03-21 08:04:40 -0700241
msarettc30c4182016-04-20 11:53:35 -0700242 const int width = decoderMgr->dinfo()->image_width;
243 const int height = decoderMgr->dinfo()->image_height;
msarettf34cd632016-05-25 10:13:53 -0700244 *codecOut = new SkJpegCodec(width, height, info, stream, decoderMgr.release(),
msarett9876ac52016-06-01 14:47:18 -0700245 std::move(colorSpace), orientation, std::move(iccData));
msarette16b04a2015-04-15 07:32:19 -0700246 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700247 SkASSERT(nullptr != decoderMgrOut);
mtklein18300a32016-03-16 13:53:35 -0700248 *decoderMgrOut = decoderMgr.release();
msarette16b04a2015-04-15 07:32:19 -0700249 }
250 return true;
251}
252
253SkCodec* SkJpegCodec::NewFromStream(SkStream* stream) {
254 SkAutoTDelete<SkStream> streamDeleter(stream);
halcanary96fcdcc2015-08-27 07:41:13 -0700255 SkCodec* codec = nullptr;
256 if (ReadHeader(stream, &codec, nullptr)) {
msarette16b04a2015-04-15 07:32:19 -0700257 // Codec has taken ownership of the stream, we do not need to delete it
258 SkASSERT(codec);
mtklein18300a32016-03-16 13:53:35 -0700259 streamDeleter.release();
msarette16b04a2015-04-15 07:32:19 -0700260 return codec;
261 }
halcanary96fcdcc2015-08-27 07:41:13 -0700262 return nullptr;
msarette16b04a2015-04-15 07:32:19 -0700263}
264
msarettc30c4182016-04-20 11:53:35 -0700265SkJpegCodec::SkJpegCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream,
msarett9876ac52016-06-01 14:47:18 -0700266 JpegDecoderMgr* decoderMgr, sk_sp<SkColorSpace> colorSpace, Origin origin,
267 sk_sp<SkData> iccData)
msarettf34cd632016-05-25 10:13:53 -0700268 : INHERITED(width, height, info, stream, std::move(colorSpace), origin)
msarette16b04a2015-04-15 07:32:19 -0700269 , fDecoderMgr(decoderMgr)
msarettfbccb592015-09-01 06:43:41 -0700270 , fReadyState(decoderMgr->dinfo()->global_state)
msarett50ce1f22016-07-29 06:23:33 -0700271 , fSwizzleSrcRow(nullptr)
272 , fColorXformSrcRow(nullptr)
msarett91c22b22016-02-22 12:27:46 -0800273 , fSwizzlerSubset(SkIRect::MakeEmpty())
msarett9876ac52016-06-01 14:47:18 -0700274 , fICCData(std::move(iccData))
msarette16b04a2015-04-15 07:32:19 -0700275{}
276
277/*
emmaleer8f4ba762015-08-14 07:44:46 -0700278 * Return the row bytes of a particular image type and width
279 */
msarett23e78d32016-02-06 15:58:50 -0800280static size_t get_row_bytes(const j_decompress_ptr dinfo) {
msarett70e418b2016-02-12 12:35:48 -0800281#ifdef TURBO_HAS_565
282 const size_t colorBytes = (dinfo->out_color_space == JCS_RGB565) ? 2 :
283 dinfo->out_color_components;
284#else
285 const size_t colorBytes = dinfo->out_color_components;
286#endif
emmaleer8f4ba762015-08-14 07:44:46 -0700287 return dinfo->output_width * colorBytes;
288
289}
scroggoe7fc14b2015-10-02 13:14:46 -0700290
291/*
292 * Calculate output dimensions based on the provided factors.
293 *
294 * Not to be used on the actual jpeg_decompress_struct used for decoding, since it will
295 * incorrectly modify num_components.
296 */
297void calc_output_dimensions(jpeg_decompress_struct* dinfo, unsigned int num, unsigned int denom) {
298 dinfo->num_components = 0;
299 dinfo->scale_num = num;
300 dinfo->scale_denom = denom;
301 jpeg_calc_output_dimensions(dinfo);
302}
303
emmaleer8f4ba762015-08-14 07:44:46 -0700304/*
msarette16b04a2015-04-15 07:32:19 -0700305 * Return a valid set of output dimensions for this decoder, given an input scale
306 */
307SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const {
msarett1c8a5872015-07-07 08:50:01 -0700308 // 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
309 // support these as well
scroggoe7fc14b2015-10-02 13:14:46 -0700310 unsigned int num;
311 unsigned int denom = 8;
msarettfdb47572015-10-13 12:50:14 -0700312 if (desiredScale >= 0.9375) {
msarett1c8a5872015-07-07 08:50:01 -0700313 num = 8;
msarettfdb47572015-10-13 12:50:14 -0700314 } else if (desiredScale >= 0.8125) {
msarett1c8a5872015-07-07 08:50:01 -0700315 num = 7;
msarettfdb47572015-10-13 12:50:14 -0700316 } else if (desiredScale >= 0.6875f) {
msarett1c8a5872015-07-07 08:50:01 -0700317 num = 6;
msarettfdb47572015-10-13 12:50:14 -0700318 } else if (desiredScale >= 0.5625f) {
msarett1c8a5872015-07-07 08:50:01 -0700319 num = 5;
msarettfdb47572015-10-13 12:50:14 -0700320 } else if (desiredScale >= 0.4375f) {
msarett1c8a5872015-07-07 08:50:01 -0700321 num = 4;
msarettfdb47572015-10-13 12:50:14 -0700322 } else if (desiredScale >= 0.3125f) {
msarett1c8a5872015-07-07 08:50:01 -0700323 num = 3;
msarettfdb47572015-10-13 12:50:14 -0700324 } else if (desiredScale >= 0.1875f) {
msarett1c8a5872015-07-07 08:50:01 -0700325 num = 2;
msarette16b04a2015-04-15 07:32:19 -0700326 } else {
msarett1c8a5872015-07-07 08:50:01 -0700327 num = 1;
msarette16b04a2015-04-15 07:32:19 -0700328 }
329
330 // Set up a fake decompress struct in order to use libjpeg to calculate output dimensions
331 jpeg_decompress_struct dinfo;
mtkleinf7aaadb2015-04-16 06:09:27 -0700332 sk_bzero(&dinfo, sizeof(dinfo));
msarette16b04a2015-04-15 07:32:19 -0700333 dinfo.image_width = this->getInfo().width();
334 dinfo.image_height = this->getInfo().height();
msarettfbccb592015-09-01 06:43:41 -0700335 dinfo.global_state = fReadyState;
scroggoe7fc14b2015-10-02 13:14:46 -0700336 calc_output_dimensions(&dinfo, num, denom);
msarette16b04a2015-04-15 07:32:19 -0700337
338 // Return the calculated output dimensions for the given scale
339 return SkISize::Make(dinfo.output_width, dinfo.output_height);
340}
341
scroggob427db12015-08-12 07:24:13 -0700342bool SkJpegCodec::onRewind() {
halcanary96fcdcc2015-08-27 07:41:13 -0700343 JpegDecoderMgr* decoderMgr = nullptr;
344 if (!ReadHeader(this->stream(), nullptr, &decoderMgr)) {
msarett50ce1f22016-07-29 06:23:33 -0700345 return fDecoderMgr->returnFalse("onRewind");
msarett97fdea62015-04-29 08:17:15 -0700346 }
halcanary96fcdcc2015-08-27 07:41:13 -0700347 SkASSERT(nullptr != decoderMgr);
scroggob427db12015-08-12 07:24:13 -0700348 fDecoderMgr.reset(decoderMgr);
msarett2812f032016-07-18 15:56:08 -0700349
350 fSwizzler.reset(nullptr);
msarett50ce1f22016-07-29 06:23:33 -0700351 fSwizzleSrcRow = nullptr;
352 fColorXformSrcRow = nullptr;
msarett2812f032016-07-18 15:56:08 -0700353 fStorage.reset();
msarett50ce1f22016-07-29 06:23:33 -0700354 fColorXform.reset(nullptr);
msarett2812f032016-07-18 15:56:08 -0700355
scroggob427db12015-08-12 07:24:13 -0700356 return true;
msarett97fdea62015-04-29 08:17:15 -0700357}
358
359/*
msarett1c8a5872015-07-07 08:50:01 -0700360 * Checks if the conversion between the input image and the requested output
361 * image has been implemented
362 * Sets the output color space
363 */
msarett50ce1f22016-07-29 06:23:33 -0700364bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dstInfo, bool needsColorXform) {
365 if (kUnknown_SkAlphaType == dstInfo.alphaType()) {
msarett1c8a5872015-07-07 08:50:01 -0700366 return false;
367 }
368
msarett50ce1f22016-07-29 06:23:33 -0700369 if (kOpaque_SkAlphaType != dstInfo.alphaType()) {
scroggoc5560be2016-02-03 09:42:42 -0800370 SkCodecPrintf("Warning: an opaque image should be decoded as opaque "
371 "- it is being decoded as non-opaque, which will draw slower\n");
372 }
373
msarett50ce1f22016-07-29 06:23:33 -0700374 // Check if we will decode to CMYK. libjpeg-turbo does not convert CMYK to RGBA, so
375 // we must do it ourselves.
376 J_COLOR_SPACE encodedColorType = fDecoderMgr->dinfo()->jpeg_color_space;
377 bool isCMYK = (JCS_CMYK == encodedColorType || JCS_YCCK == encodedColorType);
msarett1c8a5872015-07-07 08:50:01 -0700378
379 // Check for valid color types and set the output color space
msarett50ce1f22016-07-29 06:23:33 -0700380 switch (dstInfo.colorType()) {
msarett34e0ec42016-04-22 16:27:24 -0700381 case kRGBA_8888_SkColorType:
msarett1c8a5872015-07-07 08:50:01 -0700382 if (isCMYK) {
383 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
384 } else {
msarettf25bff92016-07-21 12:00:24 -0700385 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
msarett34e0ec42016-04-22 16:27:24 -0700386 }
387 return true;
388 case kBGRA_8888_SkColorType:
389 if (isCMYK) {
390 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
msarett50ce1f22016-07-29 06:23:33 -0700391 } else if (needsColorXform) {
392 // Our color transformation code requires RGBA order inputs, but it'll swizzle
393 // to BGRA for us.
394 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
msarett34e0ec42016-04-22 16:27:24 -0700395 } else {
msarettf25bff92016-07-21 12:00:24 -0700396 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA;
msarett1c8a5872015-07-07 08:50:01 -0700397 }
398 return true;
399 case kRGB_565_SkColorType:
msarett50ce1f22016-07-29 06:23:33 -0700400 if (needsColorXform) {
401 return false;
402 }
403
msarett1c8a5872015-07-07 08:50:01 -0700404 if (isCMYK) {
scroggoef27d892015-10-23 09:29:22 -0700405 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
msarett1c8a5872015-07-07 08:50:01 -0700406 } else {
msarett70e418b2016-02-12 12:35:48 -0800407#ifdef TURBO_HAS_565
msarett8ff6ca62015-09-18 12:06:04 -0700408 fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE;
msarett1c8a5872015-07-07 08:50:01 -0700409 fDecoderMgr->dinfo()->out_color_space = JCS_RGB565;
msarett70e418b2016-02-12 12:35:48 -0800410#else
411 fDecoderMgr->dinfo()->out_color_space = JCS_RGB;
412#endif
msarett1c8a5872015-07-07 08:50:01 -0700413 }
414 return true;
415 case kGray_8_SkColorType:
msarett50ce1f22016-07-29 06:23:33 -0700416 if (needsColorXform || JCS_GRAYSCALE != encodedColorType) {
msarett39979d82016-07-28 17:11:18 -0700417 return false;
msarett50ce1f22016-07-29 06:23:33 -0700418 }
419
420 fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE;
421 return true;
422 case kRGBA_F16_SkColorType:
423 SkASSERT(needsColorXform);
424
425 if (isCMYK) {
426 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
msarett1c8a5872015-07-07 08:50:01 -0700427 } else {
msarett50ce1f22016-07-29 06:23:33 -0700428 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
msarett1c8a5872015-07-07 08:50:01 -0700429 }
430 return true;
431 default:
432 return false;
433 }
434}
435
436/*
mtkleine721a8e2016-02-06 19:12:23 -0800437 * Checks if we can natively scale to the requested dimensions and natively scales the
emmaleer8f4ba762015-08-14 07:44:46 -0700438 * dimensions if possible
msarett97fdea62015-04-29 08:17:15 -0700439 */
scroggoe7fc14b2015-10-02 13:14:46 -0700440bool SkJpegCodec::onDimensionsSupported(const SkISize& size) {
mtklein2f428962016-07-28 13:59:59 -0700441 if (setjmp(fDecoderMgr->getJmpBuf())) {
msarett50ce1f22016-07-29 06:23:33 -0700442 return fDecoderMgr->returnFalse("onDimensionsSupported");
scroggoe7fc14b2015-10-02 13:14:46 -0700443 }
444
445 const unsigned int dstWidth = size.width();
446 const unsigned int dstHeight = size.height();
447
448 // Set up a fake decompress struct in order to use libjpeg to calculate output dimensions
449 // FIXME: Why is this necessary?
450 jpeg_decompress_struct dinfo;
451 sk_bzero(&dinfo, sizeof(dinfo));
452 dinfo.image_width = this->getInfo().width();
453 dinfo.image_height = this->getInfo().height();
454 dinfo.global_state = fReadyState;
455
msarett1c8a5872015-07-07 08:50:01 -0700456 // 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 -0700457 unsigned int num = 8;
458 const unsigned int denom = 8;
459 calc_output_dimensions(&dinfo, num, denom);
460 while (dinfo.output_width != dstWidth || dinfo.output_height != dstHeight) {
msarett97fdea62015-04-29 08:17:15 -0700461
462 // Return a failure if we have tried all of the possible scales
scroggoe7fc14b2015-10-02 13:14:46 -0700463 if (1 == num || dstWidth > dinfo.output_width || dstHeight > dinfo.output_height) {
emmaleer8f4ba762015-08-14 07:44:46 -0700464 return false;
msarett97fdea62015-04-29 08:17:15 -0700465 }
466
467 // Try the next scale
scroggoe7fc14b2015-10-02 13:14:46 -0700468 num -= 1;
469 calc_output_dimensions(&dinfo, num, denom);
msarett97fdea62015-04-29 08:17:15 -0700470 }
scroggoe7fc14b2015-10-02 13:14:46 -0700471
472 fDecoderMgr->dinfo()->scale_num = num;
473 fDecoderMgr->dinfo()->scale_denom = denom;
msarett97fdea62015-04-29 08:17:15 -0700474 return true;
475}
476
msarett50ce1f22016-07-29 06:23:33 -0700477static bool needs_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) {
478 // FIXME (msarett):
479 // Do a better check for color space equality.
480 return (kRGBA_F16_SkColorType == dstInfo.colorType()) ||
481 (dstInfo.colorSpace() && (dstInfo.colorSpace() != srcInfo.colorSpace()));
482}
483
484int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count) {
485 // Set the jump location for libjpeg-turbo errors
486 if (setjmp(fDecoderMgr->getJmpBuf())) {
487 return 0;
488 }
489
490 // When fSwizzleSrcRow is non-null, it means that we need to swizzle. In this case,
491 // we will always decode into fSwizzlerSrcRow before swizzling into the next buffer.
492 // We can never swizzle "in place" because the swizzler may perform sampling and/or
493 // subsetting.
494 // When fColorXformSrcRow is non-null, it means that we need to color xform and that
495 // we cannot color xform "in place" (many times we can, but not when the dst is F16).
496 // In this case, we will color xform from fColorXformSrc into the dst.
497 JSAMPLE* decodeDst = (JSAMPLE*) dst;
498 uint32_t* swizzleDst = (uint32_t*) dst;
499 size_t decodeDstRowBytes = rowBytes;
500 size_t swizzleDstRowBytes = rowBytes;
501 if (fSwizzleSrcRow && fColorXformSrcRow) {
502 decodeDst = (JSAMPLE*) fSwizzleSrcRow;
503 swizzleDst = fColorXformSrcRow;
504 decodeDstRowBytes = 0;
505 swizzleDstRowBytes = 0;
506 } else if (fColorXformSrcRow) {
507 decodeDst = (JSAMPLE*) fColorXformSrcRow;
508 swizzleDst = fColorXformSrcRow;
509 decodeDstRowBytes = 0;
510 swizzleDstRowBytes = 0;
511 } else if (fSwizzleSrcRow) {
512 decodeDst = (JSAMPLE*) fSwizzleSrcRow;
513 decodeDstRowBytes = 0;
514 }
515
516 for (int y = 0; y < count; y++) {
517 uint32_t lines = jpeg_read_scanlines(fDecoderMgr->dinfo(), &decodeDst, 1);
518 size_t srcRowBytes = get_row_bytes(fDecoderMgr->dinfo());
519 sk_msan_mark_initialized(decodeDst, decodeDst + srcRowBytes, "skbug.com/4550");
520 if (0 == lines) {
521 return y;
522 }
523
524 if (fSwizzler) {
525 fSwizzler->swizzle(swizzleDst, decodeDst);
526 }
527
528 if (fColorXform) {
529 int width = dstInfo.width();
530 switch (dstInfo.colorType()) {
531 case kRGBA_8888_SkColorType:
532 fColorXform->applyToRGBA((uint32_t*) dst, swizzleDst, width);
533 break;
534 case kBGRA_8888_SkColorType:
535 fColorXform->applyToBGRA((uint32_t*) dst, swizzleDst, width);
536 break;
537 case kRGBA_F16_SkColorType:
538 fColorXform->applyToF16((uint64_t*) dst, swizzleDst, width);
539 break;
540 default:
541 SkASSERT(false);
542 break;
543 }
544
545 dst = SkTAddOffset<void>(dst, rowBytes);
546 }
547
548 decodeDst = SkTAddOffset<JSAMPLE>(decodeDst, decodeDstRowBytes);
549 swizzleDst = SkTAddOffset<uint32_t>(swizzleDst, swizzleDstRowBytes);
550 }
551
552 return count;
553}
554
msarett97fdea62015-04-29 08:17:15 -0700555/*
msarette16b04a2015-04-15 07:32:19 -0700556 * Performs the jpeg decode
557 */
558SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
559 void* dst, size_t dstRowBytes,
msarette6dd0042015-10-09 11:07:34 -0700560 const Options& options, SkPMColor*, int*,
561 int* rowsDecoded) {
scroggob636b452015-07-22 07:16:20 -0700562 if (options.fSubset) {
563 // Subsets are not supported.
564 return kUnimplemented;
565 }
566
msarette16b04a2015-04-15 07:32:19 -0700567 // Get a pointer to the decompress info since we will use it quite frequently
568 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
569
570 // Set the jump location for libjpeg errors
mtklein2f428962016-07-28 13:59:59 -0700571 if (setjmp(fDecoderMgr->getJmpBuf())) {
msarette16b04a2015-04-15 07:32:19 -0700572 return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
573 }
574
msarett1c8a5872015-07-07 08:50:01 -0700575 // Check if we can decode to the requested destination and set the output color space
msarett50ce1f22016-07-29 06:23:33 -0700576 bool needsColorXform = needs_color_xform(dstInfo, this->getInfo());
577 if (!this->setOutputColorSpace(dstInfo, needsColorXform)) {
578 return fDecoderMgr->returnFailure("setOutputColorSpace", kInvalidConversion);
msarette16b04a2015-04-15 07:32:19 -0700579 }
msarette16b04a2015-04-15 07:32:19 -0700580
msarett50ce1f22016-07-29 06:23:33 -0700581 if (!this->initializeColorXform(dstInfo, needsColorXform)) {
582 return fDecoderMgr->returnFailure("initializeColorXform", kInvalidParameters);
583 }
584
msarettfbccb592015-09-01 06:43:41 -0700585 if (!jpeg_start_decompress(dinfo)) {
msarette16b04a2015-04-15 07:32:19 -0700586 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
587 }
588
msarett1c8a5872015-07-07 08:50:01 -0700589 // The recommended output buffer height should always be 1 in high quality modes.
590 // If it's not, we want to know because it means our strategy is not optimal.
591 SkASSERT(1 == dinfo->rec_outbuf_height);
msarette16b04a2015-04-15 07:32:19 -0700592
msarett70e418b2016-02-12 12:35:48 -0800593 J_COLOR_SPACE colorSpace = dinfo->out_color_space;
594 if (JCS_CMYK == colorSpace || JCS_RGB == colorSpace) {
scroggoef27d892015-10-23 09:29:22 -0700595 this->initializeSwizzler(dstInfo, options);
596 }
597
msarett50ce1f22016-07-29 06:23:33 -0700598 this->allocateStorage(dstInfo);
scroggoef27d892015-10-23 09:29:22 -0700599
msarett50ce1f22016-07-29 06:23:33 -0700600 int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height());
601 if (rows < dstInfo.height()) {
602 *rowsDecoded = rows;
603 return fDecoderMgr->returnFailure("Incomplete image data", kIncompleteInput);
msarette16b04a2015-04-15 07:32:19 -0700604 }
msarette16b04a2015-04-15 07:32:19 -0700605
606 return kSuccess;
607}
msarett97fdea62015-04-29 08:17:15 -0700608
msarett50ce1f22016-07-29 06:23:33 -0700609void SkJpegCodec::allocateStorage(const SkImageInfo& dstInfo) {
610 size_t swizzleBytes = 0;
611 if (fSwizzler) {
612 swizzleBytes = get_row_bytes(fDecoderMgr->dinfo());
613 SkASSERT(!fColorXform || SkIsAlign4(swizzleBytes));
614 }
615
616 size_t xformBytes = 0;
617 if (kRGBA_F16_SkColorType == dstInfo.colorType()) {
618 SkASSERT(fColorXform);
619 xformBytes = dstInfo.width() * sizeof(SkColorSpaceXform::RGBA32);
620 }
621
622 size_t totalBytes = swizzleBytes + xformBytes;
623 if (totalBytes > 0) {
624 fStorage.reset(totalBytes);
625 fSwizzleSrcRow = (swizzleBytes > 0) ? fStorage.get() : nullptr;
626 fColorXformSrcRow = (xformBytes > 0) ?
627 SkTAddOffset<uint32_t>(fStorage.get(), swizzleBytes) : nullptr;
628 }
629}
630
msarettfdb47572015-10-13 12:50:14 -0700631void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) {
msaretta45a6682016-04-22 13:18:37 -0700632 // libjpeg-turbo may have already performed color conversion. We must indicate the
633 // appropriate format to the swizzler.
634 SkEncodedInfo swizzlerInfo = this->getEncodedInfo();
msarett68758ae2016-04-25 11:41:15 -0700635 bool preSwizzled = true;
msaretta45a6682016-04-22 13:18:37 -0700636 switch (fDecoderMgr->dinfo()->out_color_space) {
637 case JCS_RGB:
msarett68758ae2016-04-25 11:41:15 -0700638 preSwizzled = false;
halcanarya9ef92a2016-05-31 10:57:36 -0700639 swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kRGB_Color,
640 swizzlerInfo.alpha(),
641 swizzlerInfo.bitsPerComponent());
msaretta45a6682016-04-22 13:18:37 -0700642 break;
643 case JCS_CMYK:
msarett68758ae2016-04-25 11:41:15 -0700644 preSwizzled = false;
msarett50ce1f22016-07-29 06:23:33 -0700645 swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kInvertedCMYK_Color,
646 swizzlerInfo.alpha(),
647 swizzlerInfo.bitsPerComponent());
msaretta45a6682016-04-22 13:18:37 -0700648 break;
649 default:
msaretta45a6682016-04-22 13:18:37 -0700650 break;
msarett70e418b2016-02-12 12:35:48 -0800651 }
652
msarett91c22b22016-02-22 12:27:46 -0800653 Options swizzlerOptions = options;
654 if (options.fSubset) {
655 // Use fSwizzlerSubset if this is a subset decode. This is necessary in the case
656 // where libjpeg-turbo provides a subset and then we need to subset it further.
657 // Also, verify that fSwizzlerSubset is initialized and valid.
658 SkASSERT(!fSwizzlerSubset.isEmpty() && fSwizzlerSubset.x() <= options.fSubset->x() &&
659 fSwizzlerSubset.width() == options.fSubset->width());
660 swizzlerOptions.fSubset = &fSwizzlerSubset;
661 }
msarett68758ae2016-04-25 11:41:15 -0700662 fSwizzler.reset(SkSwizzler::CreateSwizzler(swizzlerInfo, nullptr, dstInfo, swizzlerOptions,
663 nullptr, preSwizzled));
msarettb30d6982016-02-15 10:18:45 -0800664 SkASSERT(fSwizzler);
msarett50ce1f22016-07-29 06:23:33 -0700665}
666
667bool SkJpegCodec::initializeColorXform(const SkImageInfo& dstInfo, bool needsColorXform) {
668 if (needsColorXform) {
669 fColorXform = SkColorSpaceXform::New(sk_ref_sp(this->getInfo().colorSpace()),
670 sk_ref_sp(dstInfo.colorSpace()));
671 if (!fColorXform && kRGBA_F16_SkColorType == dstInfo.colorType()) {
672 return false;
673 }
674 }
675
676 return true;
msarettfdb47572015-10-13 12:50:14 -0700677}
678
679SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) {
680 if (!createIfNecessary || fSwizzler) {
msarett50ce1f22016-07-29 06:23:33 -0700681 SkASSERT(!fSwizzler || (fSwizzleSrcRow && fStorage.get() == fSwizzleSrcRow));
msarettfdb47572015-10-13 12:50:14 -0700682 return fSwizzler;
683 }
684
685 this->initializeSwizzler(this->dstInfo(), this->options());
msarett50ce1f22016-07-29 06:23:33 -0700686 this->allocateStorage(this->dstInfo());
scroggoe7fc14b2015-10-02 13:14:46 -0700687 return fSwizzler;
scroggo46c57472015-09-30 08:57:13 -0700688}
scroggo1c005e42015-08-04 09:24:45 -0700689
scroggo46c57472015-09-30 08:57:13 -0700690SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
691 const Options& options, SkPMColor ctable[], int* ctableCount) {
scroggo46c57472015-09-30 08:57:13 -0700692 // Set the jump location for libjpeg errors
mtklein2f428962016-07-28 13:59:59 -0700693 if (setjmp(fDecoderMgr->getJmpBuf())) {
scroggo46c57472015-09-30 08:57:13 -0700694 SkCodecPrintf("setjmp: Error from libjpeg\n");
695 return kInvalidInput;
696 }
697
698 // Check if we can decode to the requested destination and set the output color space
msarett50ce1f22016-07-29 06:23:33 -0700699 bool needsColorXform = needs_color_xform(dstInfo, this->getInfo());
700 if (!this->setOutputColorSpace(dstInfo, needsColorXform)) {
scroggo46c57472015-09-30 08:57:13 -0700701 return kInvalidConversion;
702 }
703
msarett50ce1f22016-07-29 06:23:33 -0700704 if (!this->initializeColorXform(dstInfo, needsColorXform)) {
705 return fDecoderMgr->returnFailure("initializeColorXform", kInvalidParameters);
706 }
707
scroggo46c57472015-09-30 08:57:13 -0700708 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) {
709 SkCodecPrintf("start decompress failed\n");
710 return kInvalidInput;
711 }
712
msarett91c22b22016-02-22 12:27:46 -0800713#ifdef TURBO_HAS_CROP
714 if (options.fSubset) {
715 uint32_t startX = options.fSubset->x();
716 uint32_t width = options.fSubset->width();
717
718 // libjpeg-turbo may need to align startX to a multiple of the IDCT
719 // block size. If this is the case, it will decrease the value of
720 // startX to the appropriate alignment and also increase the value
721 // of width so that the right edge of the requested subset remains
722 // the same.
723 jpeg_crop_scanline(fDecoderMgr->dinfo(), &startX, &width);
724
725 SkASSERT(startX <= (uint32_t) options.fSubset->x());
726 SkASSERT(width >= (uint32_t) options.fSubset->width());
727 SkASSERT(startX + width >= (uint32_t) options.fSubset->right());
728
729 // Instruct the swizzler (if it is necessary) to further subset the
730 // output provided by libjpeg-turbo.
731 //
732 // We set this here (rather than in the if statement below), so that
733 // if (1) we don't need a swizzler for the subset, and (2) we need a
734 // swizzler for CMYK, the swizzler will still use the proper subset
735 // dimensions.
736 //
737 // Note that the swizzler will ignore the y and height parameters of
738 // the subset. Since the scanline decoder (and the swizzler) handle
739 // one row at a time, only the subsetting in the x-dimension matters.
740 fSwizzlerSubset.setXYWH(options.fSubset->x() - startX, 0,
741 options.fSubset->width(), options.fSubset->height());
742
743 // We will need a swizzler if libjpeg-turbo cannot provide the exact
744 // subset that we request.
745 if (startX != (uint32_t) options.fSubset->x() ||
746 width != (uint32_t) options.fSubset->width()) {
747 this->initializeSwizzler(dstInfo, options);
748 }
749 }
750
751 // Make sure we have a swizzler if we are converting from CMYK.
752 if (!fSwizzler && JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) {
753 this->initializeSwizzler(dstInfo, options);
754 }
755#else
msarettf25bff92016-07-21 12:00:24 -0700756 if (options.fSubset) {
757 fSwizzlerSubset = *options.fSubset;
758 }
759
scroggoef27d892015-10-23 09:29:22 -0700760 // We will need a swizzler if we are performing a subset decode or
761 // converting from CMYK.
msarett70e418b2016-02-12 12:35:48 -0800762 J_COLOR_SPACE colorSpace = fDecoderMgr->dinfo()->out_color_space;
763 if (options.fSubset || JCS_CMYK == colorSpace || JCS_RGB == colorSpace) {
msarettfdb47572015-10-13 12:50:14 -0700764 this->initializeSwizzler(dstInfo, options);
765 }
msarett91c22b22016-02-22 12:27:46 -0800766#endif
msarettfdb47572015-10-13 12:50:14 -0700767
msarett50ce1f22016-07-29 06:23:33 -0700768 this->allocateStorage(dstInfo);
769
scroggo46c57472015-09-30 08:57:13 -0700770 return kSuccess;
771}
772
mtkleine721a8e2016-02-06 19:12:23 -0800773int SkJpegCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
msarett50ce1f22016-07-29 06:23:33 -0700774 int rows = this->readRows(this->dstInfo(), dst, dstRowBytes, count);
775 if (rows < count) {
776 // This allows us to skip calling jpeg_finish_decompress().
777 fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height();
scroggo46c57472015-09-30 08:57:13 -0700778 }
779
msarett50ce1f22016-07-29 06:23:33 -0700780 return rows;
scroggo46c57472015-09-30 08:57:13 -0700781}
msarett97fdea62015-04-29 08:17:15 -0700782
msarette6dd0042015-10-09 11:07:34 -0700783bool SkJpegCodec::onSkipScanlines(int count) {
scroggo46c57472015-09-30 08:57:13 -0700784 // Set the jump location for libjpeg errors
mtklein2f428962016-07-28 13:59:59 -0700785 if (setjmp(fDecoderMgr->getJmpBuf())) {
msarett50ce1f22016-07-29 06:23:33 -0700786 return fDecoderMgr->returnFalse("onSkipScanlines");
msarett97fdea62015-04-29 08:17:15 -0700787 }
788
msarettd5951b12016-02-10 13:49:36 -0800789#ifdef TURBO_HAS_SKIP
msarettf724b992015-10-15 06:41:06 -0700790 return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count);
msarettd5951b12016-02-10 13:49:36 -0800791#else
msarett50ce1f22016-07-29 06:23:33 -0700792 if (!fSwizzleSrcRow) {
msarettd5951b12016-02-10 13:49:36 -0800793 fStorage.reset(get_row_bytes(fDecoderMgr->dinfo()));
msarett50ce1f22016-07-29 06:23:33 -0700794 fSwizzleSrcRow = fStorage.get();
msarettd5951b12016-02-10 13:49:36 -0800795 }
796
797 for (int y = 0; y < count; y++) {
msarett50ce1f22016-07-29 06:23:33 -0700798 if (1 != jpeg_read_scanlines(fDecoderMgr->dinfo(), &fSwizzleSrcRow, 1)) {
msarettd5951b12016-02-10 13:49:36 -0800799 return false;
800 }
801 }
802 return true;
803#endif
msarett97fdea62015-04-29 08:17:15 -0700804}
msarettb714fb02016-01-22 14:46:42 -0800805
806static bool is_yuv_supported(jpeg_decompress_struct* dinfo) {
807 // Scaling is not supported in raw data mode.
808 SkASSERT(dinfo->scale_num == dinfo->scale_denom);
809
810 // I can't imagine that this would ever change, but we do depend on it.
811 static_assert(8 == DCTSIZE, "DCTSIZE (defined in jpeg library) should always be 8.");
812
813 if (JCS_YCbCr != dinfo->jpeg_color_space) {
814 return false;
815 }
816
817 SkASSERT(3 == dinfo->num_components);
818 SkASSERT(dinfo->comp_info);
819
820 // It is possible to perform a YUV decode for any combination of
821 // horizontal and vertical sampling that is supported by
822 // libjpeg/libjpeg-turbo. However, we will start by supporting only the
823 // common cases (where U and V have samp_factors of one).
824 //
825 // The definition of samp_factor is kind of the opposite of what SkCodec
826 // thinks of as a sampling factor. samp_factor is essentially a
827 // multiplier, and the larger the samp_factor is, the more samples that
828 // there will be. Ex:
829 // U_plane_width = image_width * (U_h_samp_factor / max_h_samp_factor)
830 //
831 // Supporting cases where the samp_factors for U or V were larger than
832 // that of Y would be an extremely difficult change, given that clients
833 // allocate memory as if the size of the Y plane is always the size of the
834 // image. However, this case is very, very rare.
msarett7c87cf42016-03-04 06:23:20 -0800835 if ((1 != dinfo->comp_info[1].h_samp_factor) ||
836 (1 != dinfo->comp_info[1].v_samp_factor) ||
837 (1 != dinfo->comp_info[2].h_samp_factor) ||
838 (1 != dinfo->comp_info[2].v_samp_factor))
839 {
msarettb714fb02016-01-22 14:46:42 -0800840 return false;
841 }
842
843 // Support all common cases of Y samp_factors.
844 // TODO (msarett): As mentioned above, it would be possible to support
845 // more combinations of samp_factors. The issues are:
846 // (1) Are there actually any images that are not covered
847 // by these cases?
848 // (2) How much complexity would be added to the
849 // implementation in order to support these rare
850 // cases?
851 int hSampY = dinfo->comp_info[0].h_samp_factor;
852 int vSampY = dinfo->comp_info[0].v_samp_factor;
853 return (1 == hSampY && 1 == vSampY) ||
854 (2 == hSampY && 1 == vSampY) ||
855 (2 == hSampY && 2 == vSampY) ||
856 (1 == hSampY && 2 == vSampY) ||
857 (4 == hSampY && 1 == vSampY) ||
858 (4 == hSampY && 2 == vSampY);
859}
860
msarett4984c3c2016-03-10 05:44:43 -0800861bool SkJpegCodec::onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const {
msarettb714fb02016-01-22 14:46:42 -0800862 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
863 if (!is_yuv_supported(dinfo)) {
864 return false;
865 }
866
msarett4984c3c2016-03-10 05:44:43 -0800867 sizeInfo->fSizes[SkYUVSizeInfo::kY].set(dinfo->comp_info[0].downsampled_width,
868 dinfo->comp_info[0].downsampled_height);
869 sizeInfo->fSizes[SkYUVSizeInfo::kU].set(dinfo->comp_info[1].downsampled_width,
870 dinfo->comp_info[1].downsampled_height);
871 sizeInfo->fSizes[SkYUVSizeInfo::kV].set(dinfo->comp_info[2].downsampled_width,
872 dinfo->comp_info[2].downsampled_height);
873 sizeInfo->fWidthBytes[SkYUVSizeInfo::kY] = dinfo->comp_info[0].width_in_blocks * DCTSIZE;
874 sizeInfo->fWidthBytes[SkYUVSizeInfo::kU] = dinfo->comp_info[1].width_in_blocks * DCTSIZE;
875 sizeInfo->fWidthBytes[SkYUVSizeInfo::kV] = dinfo->comp_info[2].width_in_blocks * DCTSIZE;
msarettb714fb02016-01-22 14:46:42 -0800876
877 if (colorSpace) {
878 *colorSpace = kJPEG_SkYUVColorSpace;
879 }
880
881 return true;
882}
883
msarett4984c3c2016-03-10 05:44:43 -0800884SkCodec::Result SkJpegCodec::onGetYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) {
885 SkYUVSizeInfo defaultInfo;
msarettb714fb02016-01-22 14:46:42 -0800886
887 // This will check is_yuv_supported(), so we don't need to here.
888 bool supportsYUV = this->onQueryYUV8(&defaultInfo, nullptr);
msarett4984c3c2016-03-10 05:44:43 -0800889 if (!supportsYUV ||
890 sizeInfo.fSizes[SkYUVSizeInfo::kY] != defaultInfo.fSizes[SkYUVSizeInfo::kY] ||
891 sizeInfo.fSizes[SkYUVSizeInfo::kU] != defaultInfo.fSizes[SkYUVSizeInfo::kU] ||
892 sizeInfo.fSizes[SkYUVSizeInfo::kV] != defaultInfo.fSizes[SkYUVSizeInfo::kV] ||
893 sizeInfo.fWidthBytes[SkYUVSizeInfo::kY] < defaultInfo.fWidthBytes[SkYUVSizeInfo::kY] ||
894 sizeInfo.fWidthBytes[SkYUVSizeInfo::kU] < defaultInfo.fWidthBytes[SkYUVSizeInfo::kU] ||
895 sizeInfo.fWidthBytes[SkYUVSizeInfo::kV] < defaultInfo.fWidthBytes[SkYUVSizeInfo::kV]) {
msarettb714fb02016-01-22 14:46:42 -0800896 return fDecoderMgr->returnFailure("onGetYUV8Planes", kInvalidInput);
897 }
898
899 // Set the jump location for libjpeg errors
mtklein2f428962016-07-28 13:59:59 -0700900 if (setjmp(fDecoderMgr->getJmpBuf())) {
msarettb714fb02016-01-22 14:46:42 -0800901 return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
902 }
903
904 // Get a pointer to the decompress info since we will use it quite frequently
905 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
906
907 dinfo->raw_data_out = TRUE;
908 if (!jpeg_start_decompress(dinfo)) {
909 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
910 }
911
912 // A previous implementation claims that the return value of is_yuv_supported()
913 // may change after calling jpeg_start_decompress(). It looks to me like this
914 // was caused by a bug in the old code, but we'll be safe and check here.
915 SkASSERT(is_yuv_supported(dinfo));
916
917 // Currently, we require that the Y plane dimensions match the image dimensions
918 // and that the U and V planes are the same dimensions.
msarett4984c3c2016-03-10 05:44:43 -0800919 SkASSERT(sizeInfo.fSizes[SkYUVSizeInfo::kU] == sizeInfo.fSizes[SkYUVSizeInfo::kV]);
920 SkASSERT((uint32_t) sizeInfo.fSizes[SkYUVSizeInfo::kY].width() == dinfo->output_width &&
921 (uint32_t) sizeInfo.fSizes[SkYUVSizeInfo::kY].height() == dinfo->output_height);
msarettb714fb02016-01-22 14:46:42 -0800922
923 // Build a JSAMPIMAGE to handle output from libjpeg-turbo. A JSAMPIMAGE has
924 // a 2-D array of pixels for each of the components (Y, U, V) in the image.
925 // Cheat Sheet:
926 // JSAMPIMAGE == JSAMPLEARRAY* == JSAMPROW** == JSAMPLE***
927 JSAMPARRAY yuv[3];
928
929 // Set aside enough space for pointers to rows of Y, U, and V.
930 JSAMPROW rowptrs[2 * DCTSIZE + DCTSIZE + DCTSIZE];
931 yuv[0] = &rowptrs[0]; // Y rows (DCTSIZE or 2 * DCTSIZE)
932 yuv[1] = &rowptrs[2 * DCTSIZE]; // U rows (DCTSIZE)
933 yuv[2] = &rowptrs[3 * DCTSIZE]; // V rows (DCTSIZE)
934
935 // Initialize rowptrs.
936 int numYRowsPerBlock = DCTSIZE * dinfo->comp_info[0].v_samp_factor;
937 for (int i = 0; i < numYRowsPerBlock; i++) {
msarett4984c3c2016-03-10 05:44:43 -0800938 rowptrs[i] = SkTAddOffset<JSAMPLE>(planes[SkYUVSizeInfo::kY],
939 i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kY]);
msarettb714fb02016-01-22 14:46:42 -0800940 }
941 for (int i = 0; i < DCTSIZE; i++) {
msarett4984c3c2016-03-10 05:44:43 -0800942 rowptrs[i + 2 * DCTSIZE] = SkTAddOffset<JSAMPLE>(planes[SkYUVSizeInfo::kU],
943 i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kU]);
944 rowptrs[i + 3 * DCTSIZE] = SkTAddOffset<JSAMPLE>(planes[SkYUVSizeInfo::kV],
945 i * sizeInfo.fWidthBytes[SkYUVSizeInfo::kV]);
msarettb714fb02016-01-22 14:46:42 -0800946 }
947
948 // After each loop iteration, we will increment pointers to Y, U, and V.
msarett4984c3c2016-03-10 05:44:43 -0800949 size_t blockIncrementY = numYRowsPerBlock * sizeInfo.fWidthBytes[SkYUVSizeInfo::kY];
950 size_t blockIncrementU = DCTSIZE * sizeInfo.fWidthBytes[SkYUVSizeInfo::kU];
951 size_t blockIncrementV = DCTSIZE * sizeInfo.fWidthBytes[SkYUVSizeInfo::kV];
msarettb714fb02016-01-22 14:46:42 -0800952
953 uint32_t numRowsPerBlock = numYRowsPerBlock;
954
955 // We intentionally round down here, as this first loop will only handle
956 // full block rows. As a special case at the end, we will handle any
957 // remaining rows that do not make up a full block.
958 const int numIters = dinfo->output_height / numRowsPerBlock;
959 for (int i = 0; i < numIters; i++) {
960 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock);
961 if (linesRead < numRowsPerBlock) {
962 // FIXME: Handle incomplete YUV decodes without signalling an error.
963 return kInvalidInput;
964 }
965
966 // Update rowptrs.
967 for (int i = 0; i < numYRowsPerBlock; i++) {
968 rowptrs[i] += blockIncrementY;
969 }
970 for (int i = 0; i < DCTSIZE; i++) {
971 rowptrs[i + 2 * DCTSIZE] += blockIncrementU;
972 rowptrs[i + 3 * DCTSIZE] += blockIncrementV;
973 }
974 }
975
976 uint32_t remainingRows = dinfo->output_height - dinfo->output_scanline;
977 SkASSERT(remainingRows == dinfo->output_height % numRowsPerBlock);
978 SkASSERT(dinfo->output_scanline == numIters * numRowsPerBlock);
979 if (remainingRows > 0) {
980 // libjpeg-turbo needs memory to be padded by the block sizes. We will fulfill
981 // this requirement using a dummy row buffer.
982 // FIXME: Should SkCodec have an extra memory buffer that can be shared among
983 // all of the implementations that use temporary/garbage memory?
msarett4984c3c2016-03-10 05:44:43 -0800984 SkAutoTMalloc<JSAMPLE> dummyRow(sizeInfo.fWidthBytes[SkYUVSizeInfo::kY]);
msarettb714fb02016-01-22 14:46:42 -0800985 for (int i = remainingRows; i < numYRowsPerBlock; i++) {
986 rowptrs[i] = dummyRow.get();
987 }
988 int remainingUVRows = dinfo->comp_info[1].downsampled_height - DCTSIZE * numIters;
989 for (int i = remainingUVRows; i < DCTSIZE; i++) {
990 rowptrs[i + 2 * DCTSIZE] = dummyRow.get();
991 rowptrs[i + 3 * DCTSIZE] = dummyRow.get();
992 }
993
994 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock);
995 if (linesRead < remainingRows) {
996 // FIXME: Handle incomplete YUV decodes without signalling an error.
997 return kInvalidInput;
998 }
999 }
1000
1001 return kSuccess;
1002}