blob: 2d324339d5d6b00f4762fb85fe7e07519f174bd0 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/codec/SkJpegCodec.h"
Hal Canary83e0f1b2018-04-05 16:58:41 -04009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/codec/SkCodec.h"
11#include "include/core/SkStream.h"
12#include "include/core/SkTypes.h"
13#include "include/private/SkColorData.h"
14#include "include/private/SkTemplates.h"
15#include "include/private/SkTo.h"
16#include "src/codec/SkCodecPriv.h"
17#include "src/codec/SkJpegDecoderMgr.h"
Leon Scroggins IIIba458302019-09-24 12:40:11 -040018#include "src/codec/SkParseEncodedOrigin.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "src/pdf/SkJpegInfo.h"
msarette16b04a2015-04-15 07:32:19 -070020
msarett1c8a5872015-07-07 08:50:01 -070021// stdio is needed for libjpeg-turbo
msarette16b04a2015-04-15 07:32:19 -070022#include <stdio.h>
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "src/codec/SkJpegUtility.h"
msarette16b04a2015-04-15 07:32:19 -070024
mtkleindc90b532016-07-28 14:45:28 -070025// This warning triggers false postives way too often in here.
26#if defined(__GNUC__) && !defined(__clang__)
27 #pragma GCC diagnostic ignored "-Wclobbered"
28#endif
29
msarette16b04a2015-04-15 07:32:19 -070030extern "C" {
31 #include "jerror.h"
msarette16b04a2015-04-15 07:32:19 -070032 #include "jpeglib.h"
33}
34
scroggodb30be22015-12-08 18:54:13 -080035bool SkJpegCodec::IsJpeg(const void* buffer, size_t bytesRead) {
Leon Scroggins III862c1962017-10-02 16:28:49 -040036 constexpr uint8_t jpegSig[] = { 0xFF, 0xD8, 0xFF };
scroggodb30be22015-12-08 18:54:13 -080037 return bytesRead >= 3 && !memcmp(buffer, jpegSig, sizeof(jpegSig));
msarette16b04a2015-04-15 07:32:19 -070038}
39
msarett0e6274f2016-03-21 08:04:40 -070040const uint32_t kExifHeaderSize = 14;
msarett0e6274f2016-03-21 08:04:40 -070041const uint32_t kExifMarker = JPEG_APP0 + 1;
msarett0e6274f2016-03-21 08:04:40 -070042
Leon Scroggins IIIb6ab10f2017-10-18 14:42:43 -040043static bool is_orientation_marker(jpeg_marker_struct* marker, SkEncodedOrigin* orientation) {
msarett0e6274f2016-03-21 08:04:40 -070044 if (kExifMarker != marker->marker || marker->data_length < kExifHeaderSize) {
45 return false;
46 }
47
Leon Scroggins III862c1962017-10-02 16:28:49 -040048 constexpr uint8_t kExifSig[] { 'E', 'x', 'i', 'f', '\0' };
John Stilesc1c3c6d2020-08-15 23:22:53 -040049 if (0 != memcmp(marker->data, kExifSig, sizeof(kExifSig))) {
msarett0e6274f2016-03-21 08:04:40 -070050 return false;
51 }
52
Leon Scroggins IIIda3e9ad2018-01-26 15:48:26 -050053 // Account for 'E', 'x', 'i', 'f', '\0', '<fill byte>'.
54 constexpr size_t kOffset = 6;
Leon Scroggins IIIba458302019-09-24 12:40:11 -040055 return SkParseEncodedOrigin(marker->data + kOffset, marker->data_length - kOffset,
Leon Scroggins IIIda3e9ad2018-01-26 15:48:26 -050056 orientation);
57}
58
Leon Scroggins IIIb6ab10f2017-10-18 14:42:43 -040059static SkEncodedOrigin get_exif_orientation(jpeg_decompress_struct* dinfo) {
60 SkEncodedOrigin orientation;
msarett0e6274f2016-03-21 08:04:40 -070061 for (jpeg_marker_struct* marker = dinfo->marker_list; marker; marker = marker->next) {
62 if (is_orientation_marker(marker, &orientation)) {
63 return orientation;
64 }
65 }
66
Leon Scroggins IIIb6ab10f2017-10-18 14:42:43 -040067 return kDefault_SkEncodedOrigin;
msarett0e6274f2016-03-21 08:04:40 -070068}
69
70static bool is_icc_marker(jpeg_marker_struct* marker) {
Matt Sarett5df93de2017-03-22 21:52:47 +000071 if (kICCMarker != marker->marker || marker->data_length < kICCMarkerHeaderSize) {
msarett0e6274f2016-03-21 08:04:40 -070072 return false;
73 }
74
msarett0e6274f2016-03-21 08:04:40 -070075 return !memcmp(marker->data, kICCSig, sizeof(kICCSig));
76}
77
78/*
79 * ICC profiles may be stored using a sequence of multiple markers. We obtain the ICC profile
80 * in two steps:
81 * (1) Discover all ICC profile markers and verify that they are numbered properly.
82 * (2) Copy the data from each marker into a contiguous ICC profile.
83 */
Leon Scroggins III36f7e322018-08-27 11:55:46 -040084static std::unique_ptr<SkEncodedInfo::ICCProfile> read_color_profile(jpeg_decompress_struct* dinfo)
85{
msarett0e6274f2016-03-21 08:04:40 -070086 // Note that 256 will be enough storage space since each markerIndex is stored in 8-bits.
87 jpeg_marker_struct* markerSequence[256];
88 memset(markerSequence, 0, sizeof(markerSequence));
89 uint8_t numMarkers = 0;
90 size_t totalBytes = 0;
91
92 // Discover any ICC markers and verify that they are numbered properly.
93 for (jpeg_marker_struct* marker = dinfo->marker_list; marker; marker = marker->next) {
94 if (is_icc_marker(marker)) {
95 // Verify that numMarkers is valid and consistent.
96 if (0 == numMarkers) {
97 numMarkers = marker->data[13];
98 if (0 == numMarkers) {
99 SkCodecPrintf("ICC Profile Error: numMarkers must be greater than zero.\n");
100 return nullptr;
101 }
102 } else if (numMarkers != marker->data[13]) {
103 SkCodecPrintf("ICC Profile Error: numMarkers must be consistent.\n");
104 return nullptr;
105 }
106
107 // Verify that the markerIndex is valid and unique. Note that zero is not
108 // a valid index.
109 uint8_t markerIndex = marker->data[12];
110 if (markerIndex == 0 || markerIndex > numMarkers) {
111 SkCodecPrintf("ICC Profile Error: markerIndex is invalid.\n");
112 return nullptr;
113 }
114 if (markerSequence[markerIndex]) {
115 SkCodecPrintf("ICC Profile Error: Duplicate value of markerIndex.\n");
116 return nullptr;
117 }
118 markerSequence[markerIndex] = marker;
Matt Sarett5df93de2017-03-22 21:52:47 +0000119 SkASSERT(marker->data_length >= kICCMarkerHeaderSize);
120 totalBytes += marker->data_length - kICCMarkerHeaderSize;
msarett0e6274f2016-03-21 08:04:40 -0700121 }
122 }
123
124 if (0 == totalBytes) {
125 // No non-empty ICC profile markers were found.
126 return nullptr;
127 }
128
129 // Combine the ICC marker data into a contiguous profile.
msarett9876ac52016-06-01 14:47:18 -0700130 sk_sp<SkData> iccData = SkData::MakeUninitialized(totalBytes);
131 void* dst = iccData->writable_data();
msarett0e6274f2016-03-21 08:04:40 -0700132 for (uint32_t i = 1; i <= numMarkers; i++) {
133 jpeg_marker_struct* marker = markerSequence[i];
134 if (!marker) {
135 SkCodecPrintf("ICC Profile Error: Missing marker %d of %d.\n", i, numMarkers);
136 return nullptr;
137 }
138
Matt Sarett5df93de2017-03-22 21:52:47 +0000139 void* src = SkTAddOffset<void>(marker->data, kICCMarkerHeaderSize);
140 size_t bytes = marker->data_length - kICCMarkerHeaderSize;
msarett0e6274f2016-03-21 08:04:40 -0700141 memcpy(dst, src, bytes);
142 dst = SkTAddOffset<void>(dst, bytes);
143 }
144
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400145 return SkEncodedInfo::ICCProfile::Make(std::move(iccData));
msarett0e6274f2016-03-21 08:04:40 -0700146}
147
Leon Scroggins III588fb042017-07-14 16:32:31 -0400148SkCodec::Result SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400149 JpegDecoderMgr** decoderMgrOut,
150 std::unique_ptr<SkEncodedInfo::ICCProfile> defaultColorProfile) {
msarette16b04a2015-04-15 07:32:19 -0700151
152 // Create a JpegDecoderMgr to own all of the decompress information
Ben Wagner145dbcd2016-11-03 14:40:50 -0400153 std::unique_ptr<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream));
msarette16b04a2015-04-15 07:32:19 -0700154
155 // libjpeg errors will be caught and reported here
Chris Dalton3e794592017-12-01 13:11:09 -0700156 skjpeg_error_mgr::AutoPushJmpBuf jmp(decoderMgr->errorMgr());
157 if (setjmp(jmp)) {
Leon Scroggins III588fb042017-07-14 16:32:31 -0400158 return decoderMgr->returnFailure("ReadHeader", kInvalidInput);
msarette16b04a2015-04-15 07:32:19 -0700159 }
160
161 // Initialize the decompress info and the source manager
162 decoderMgr->init();
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400163 auto* dinfo = decoderMgr->dinfo();
msarette16b04a2015-04-15 07:32:19 -0700164
msarett0e6274f2016-03-21 08:04:40 -0700165 // Instruct jpeg library to save the markers that we care about. Since
166 // the orientation and color profile will not change, we can skip this
167 // step on rewinds.
168 if (codecOut) {
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400169 jpeg_save_markers(dinfo, kExifMarker, 0xFFFF);
170 jpeg_save_markers(dinfo, kICCMarker, 0xFFFF);
msarett0e6274f2016-03-21 08:04:40 -0700171 }
172
msarette16b04a2015-04-15 07:32:19 -0700173 // Read the jpeg header
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400174 switch (jpeg_read_header(dinfo, true)) {
Leon Scroggins III588fb042017-07-14 16:32:31 -0400175 case JPEG_HEADER_OK:
176 break;
177 case JPEG_SUSPENDED:
178 return decoderMgr->returnFailure("ReadHeader", kIncompleteInput);
179 default:
180 return decoderMgr->returnFailure("ReadHeader", kInvalidInput);
msarette16b04a2015-04-15 07:32:19 -0700181 }
182
msarett0e6274f2016-03-21 08:04:40 -0700183 if (codecOut) {
msarettc30c4182016-04-20 11:53:35 -0700184 // Get the encoded color type
msarettac6c7502016-04-25 09:30:24 -0700185 SkEncodedInfo::Color color;
186 if (!decoderMgr->getEncodedColor(&color)) {
Leon Scroggins III588fb042017-07-14 16:32:31 -0400187 return kInvalidInput;
msarettc30c4182016-04-20 11:53:35 -0700188 }
msarette16b04a2015-04-15 07:32:19 -0700189
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400190 SkEncodedOrigin orientation = get_exif_orientation(dinfo);
191 auto profile = read_color_profile(dinfo);
192 if (profile) {
193 auto type = profile->profile()->data_color_space;
raftias54761282016-12-01 13:44:07 -0500194 switch (decoderMgr->dinfo()->jpeg_color_space) {
195 case JCS_CMYK:
196 case JCS_YCCK:
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400197 if (type != skcms_Signature_CMYK) {
198 profile = nullptr;
Leon Scroggins IIIf78b55c2017-10-31 13:49:14 -0400199 }
raftias54761282016-12-01 13:44:07 -0500200 break;
raftias91db12d2016-12-02 11:56:59 -0500201 case JCS_GRAYSCALE:
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400202 if (type != skcms_Signature_Gray &&
203 type != skcms_Signature_RGB)
Leon Scroggins IIIf78b55c2017-10-31 13:49:14 -0400204 {
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400205 profile = nullptr;
Leon Scroggins IIIf78b55c2017-10-31 13:49:14 -0400206 }
Mike Klein503bdcd2017-11-01 08:34:15 -0400207 break;
raftias54761282016-12-01 13:44:07 -0500208 default:
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400209 if (type != skcms_Signature_RGB) {
210 profile = nullptr;
Leon Scroggins IIIf78b55c2017-10-31 13:49:14 -0400211 }
raftias54761282016-12-01 13:44:07 -0500212 break;
213 }
msarett9876ac52016-06-01 14:47:18 -0700214 }
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400215 if (!profile) {
216 profile = std::move(defaultColorProfile);
msarettf34cd632016-05-25 10:13:53 -0700217 }
msarett0e6274f2016-03-21 08:04:40 -0700218
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400219 SkEncodedInfo info = SkEncodedInfo::Make(dinfo->image_width, dinfo->image_height,
220 color, SkEncodedInfo::kOpaque_Alpha, 8,
221 std::move(profile));
222
223 SkJpegCodec* codec = new SkJpegCodec(std::move(info), std::unique_ptr<SkStream>(stream),
224 decoderMgr.release(), orientation);
raftiasd737bee2016-12-08 10:53:24 -0500225 *codecOut = codec;
msarette16b04a2015-04-15 07:32:19 -0700226 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700227 SkASSERT(nullptr != decoderMgrOut);
mtklein18300a32016-03-16 13:53:35 -0700228 *decoderMgrOut = decoderMgr.release();
msarette16b04a2015-04-15 07:32:19 -0700229 }
Leon Scroggins III588fb042017-07-14 16:32:31 -0400230 return kSuccess;
msarette16b04a2015-04-15 07:32:19 -0700231}
232
Mike Reedede7bac2017-07-23 15:30:02 -0400233std::unique_ptr<SkCodec> SkJpegCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
234 Result* result) {
Leon Scroggins III5dd47e42018-09-27 15:26:48 -0400235 return SkJpegCodec::MakeFromStream(std::move(stream), result, nullptr);
Matt Sarettc5eabe72017-02-24 14:51:08 -0500236}
237
Mike Reedede7bac2017-07-23 15:30:02 -0400238std::unique_ptr<SkCodec> SkJpegCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400239 Result* result, std::unique_ptr<SkEncodedInfo::ICCProfile> defaultColorProfile) {
halcanary96fcdcc2015-08-27 07:41:13 -0700240 SkCodec* codec = nullptr;
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400241 *result = ReadHeader(stream.get(), &codec, nullptr, std::move(defaultColorProfile));
Leon Scroggins III588fb042017-07-14 16:32:31 -0400242 if (kSuccess == *result) {
msarette16b04a2015-04-15 07:32:19 -0700243 // Codec has taken ownership of the stream, we do not need to delete it
244 SkASSERT(codec);
Mike Reedede7bac2017-07-23 15:30:02 -0400245 stream.release();
246 return std::unique_ptr<SkCodec>(codec);
msarette16b04a2015-04-15 07:32:19 -0700247 }
halcanary96fcdcc2015-08-27 07:41:13 -0700248 return nullptr;
msarette16b04a2015-04-15 07:32:19 -0700249}
250
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400251SkJpegCodec::SkJpegCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
252 JpegDecoderMgr* decoderMgr, SkEncodedOrigin origin)
Brian Osmanb3f38302018-09-07 15:24:44 -0400253 : INHERITED(std::move(info), skcms_PixelFormat_RGBA_8888, std::move(stream), origin)
msarette16b04a2015-04-15 07:32:19 -0700254 , fDecoderMgr(decoderMgr)
msarettfbccb592015-09-01 06:43:41 -0700255 , fReadyState(decoderMgr->dinfo()->global_state)
msarett50ce1f22016-07-29 06:23:33 -0700256 , fSwizzleSrcRow(nullptr)
257 , fColorXformSrcRow(nullptr)
msarett91c22b22016-02-22 12:27:46 -0800258 , fSwizzlerSubset(SkIRect::MakeEmpty())
msarette16b04a2015-04-15 07:32:19 -0700259{}
260
261/*
emmaleer8f4ba762015-08-14 07:44:46 -0700262 * Return the row bytes of a particular image type and width
263 */
msarett23e78d32016-02-06 15:58:50 -0800264static size_t get_row_bytes(const j_decompress_ptr dinfo) {
msarett70e418b2016-02-12 12:35:48 -0800265 const size_t colorBytes = (dinfo->out_color_space == JCS_RGB565) ? 2 :
266 dinfo->out_color_components;
emmaleer8f4ba762015-08-14 07:44:46 -0700267 return dinfo->output_width * colorBytes;
268
269}
scroggoe7fc14b2015-10-02 13:14:46 -0700270
271/*
272 * Calculate output dimensions based on the provided factors.
273 *
274 * Not to be used on the actual jpeg_decompress_struct used for decoding, since it will
275 * incorrectly modify num_components.
276 */
277void calc_output_dimensions(jpeg_decompress_struct* dinfo, unsigned int num, unsigned int denom) {
278 dinfo->num_components = 0;
279 dinfo->scale_num = num;
280 dinfo->scale_denom = denom;
281 jpeg_calc_output_dimensions(dinfo);
282}
283
emmaleer8f4ba762015-08-14 07:44:46 -0700284/*
msarette16b04a2015-04-15 07:32:19 -0700285 * Return a valid set of output dimensions for this decoder, given an input scale
286 */
287SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const {
msarett1c8a5872015-07-07 08:50:01 -0700288 // 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
289 // support these as well
scroggoe7fc14b2015-10-02 13:14:46 -0700290 unsigned int num;
291 unsigned int denom = 8;
msarettfdb47572015-10-13 12:50:14 -0700292 if (desiredScale >= 0.9375) {
msarett1c8a5872015-07-07 08:50:01 -0700293 num = 8;
msarettfdb47572015-10-13 12:50:14 -0700294 } else if (desiredScale >= 0.8125) {
msarett1c8a5872015-07-07 08:50:01 -0700295 num = 7;
msarettfdb47572015-10-13 12:50:14 -0700296 } else if (desiredScale >= 0.6875f) {
msarett1c8a5872015-07-07 08:50:01 -0700297 num = 6;
msarettfdb47572015-10-13 12:50:14 -0700298 } else if (desiredScale >= 0.5625f) {
msarett1c8a5872015-07-07 08:50:01 -0700299 num = 5;
msarettfdb47572015-10-13 12:50:14 -0700300 } else if (desiredScale >= 0.4375f) {
msarett1c8a5872015-07-07 08:50:01 -0700301 num = 4;
msarettfdb47572015-10-13 12:50:14 -0700302 } else if (desiredScale >= 0.3125f) {
msarett1c8a5872015-07-07 08:50:01 -0700303 num = 3;
msarettfdb47572015-10-13 12:50:14 -0700304 } else if (desiredScale >= 0.1875f) {
msarett1c8a5872015-07-07 08:50:01 -0700305 num = 2;
msarette16b04a2015-04-15 07:32:19 -0700306 } else {
msarett1c8a5872015-07-07 08:50:01 -0700307 num = 1;
msarette16b04a2015-04-15 07:32:19 -0700308 }
309
310 // Set up a fake decompress struct in order to use libjpeg to calculate output dimensions
311 jpeg_decompress_struct dinfo;
mtkleinf7aaadb2015-04-16 06:09:27 -0700312 sk_bzero(&dinfo, sizeof(dinfo));
Leon Scroggins III712476e2018-10-03 15:47:00 -0400313 dinfo.image_width = this->dimensions().width();
314 dinfo.image_height = this->dimensions().height();
msarettfbccb592015-09-01 06:43:41 -0700315 dinfo.global_state = fReadyState;
scroggoe7fc14b2015-10-02 13:14:46 -0700316 calc_output_dimensions(&dinfo, num, denom);
msarette16b04a2015-04-15 07:32:19 -0700317
318 // Return the calculated output dimensions for the given scale
319 return SkISize::Make(dinfo.output_width, dinfo.output_height);
320}
321
scroggob427db12015-08-12 07:24:13 -0700322bool SkJpegCodec::onRewind() {
halcanary96fcdcc2015-08-27 07:41:13 -0700323 JpegDecoderMgr* decoderMgr = nullptr;
Leon Scroggins III588fb042017-07-14 16:32:31 -0400324 if (kSuccess != ReadHeader(this->stream(), nullptr, &decoderMgr, nullptr)) {
msarett50ce1f22016-07-29 06:23:33 -0700325 return fDecoderMgr->returnFalse("onRewind");
msarett97fdea62015-04-29 08:17:15 -0700326 }
halcanary96fcdcc2015-08-27 07:41:13 -0700327 SkASSERT(nullptr != decoderMgr);
scroggob427db12015-08-12 07:24:13 -0700328 fDecoderMgr.reset(decoderMgr);
msarett2812f032016-07-18 15:56:08 -0700329
330 fSwizzler.reset(nullptr);
msarett50ce1f22016-07-29 06:23:33 -0700331 fSwizzleSrcRow = nullptr;
332 fColorXformSrcRow = nullptr;
msarett2812f032016-07-18 15:56:08 -0700333 fStorage.reset();
334
scroggob427db12015-08-12 07:24:13 -0700335 return true;
msarett97fdea62015-04-29 08:17:15 -0700336}
337
Leon Scroggins III712476e2018-10-03 15:47:00 -0400338bool SkJpegCodec::conversionSupported(const SkImageInfo& dstInfo, bool srcIsOpaque,
339 bool needsColorXform) {
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400340 SkASSERT(srcIsOpaque);
341
msarett50ce1f22016-07-29 06:23:33 -0700342 if (kUnknown_SkAlphaType == dstInfo.alphaType()) {
msarett1c8a5872015-07-07 08:50:01 -0700343 return false;
344 }
345
msarett50ce1f22016-07-29 06:23:33 -0700346 if (kOpaque_SkAlphaType != dstInfo.alphaType()) {
scroggoc5560be2016-02-03 09:42:42 -0800347 SkCodecPrintf("Warning: an opaque image should be decoded as opaque "
348 "- it is being decoded as non-opaque, which will draw slower\n");
349 }
350
msarett50ce1f22016-07-29 06:23:33 -0700351 J_COLOR_SPACE encodedColorType = fDecoderMgr->dinfo()->jpeg_color_space;
msarett1c8a5872015-07-07 08:50:01 -0700352
353 // Check for valid color types and set the output color space
msarett50ce1f22016-07-29 06:23:33 -0700354 switch (dstInfo.colorType()) {
msarett34e0ec42016-04-22 16:27:24 -0700355 case kRGBA_8888_SkColorType:
nagarajan.n08cda142017-09-07 20:03:29 +0530356 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
357 break;
msarett34e0ec42016-04-22 16:27:24 -0700358 case kBGRA_8888_SkColorType:
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400359 if (needsColorXform) {
Matt Sarett562e6812016-11-08 16:13:43 -0500360 // Always using RGBA as the input format for color xforms makes the
361 // implementation a little simpler.
msarett50ce1f22016-07-29 06:23:33 -0700362 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
msarett34e0ec42016-04-22 16:27:24 -0700363 } else {
msarettf25bff92016-07-21 12:00:24 -0700364 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA;
msarett1c8a5872015-07-07 08:50:01 -0700365 }
nagarajan.n08cda142017-09-07 20:03:29 +0530366 break;
msarett1c8a5872015-07-07 08:50:01 -0700367 case kRGB_565_SkColorType:
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400368 if (needsColorXform) {
Matt Sarett3725f0a2017-03-28 14:34:20 -0400369 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
msarett1c8a5872015-07-07 08:50:01 -0700370 } else {
msarett8ff6ca62015-09-18 12:06:04 -0700371 fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE;
msarett1c8a5872015-07-07 08:50:01 -0700372 fDecoderMgr->dinfo()->out_color_space = JCS_RGB565;
373 }
nagarajan.n08cda142017-09-07 20:03:29 +0530374 break;
msarett1c8a5872015-07-07 08:50:01 -0700375 case kGray_8_SkColorType:
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400376 if (JCS_GRAYSCALE != encodedColorType) {
msarett39979d82016-07-28 17:11:18 -0700377 return false;
msarett50ce1f22016-07-29 06:23:33 -0700378 }
379
Brian Osmanb3f38302018-09-07 15:24:44 -0400380 if (needsColorXform) {
381 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
382 } else {
383 fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE;
384 }
nagarajan.n08cda142017-09-07 20:03:29 +0530385 break;
msarett50ce1f22016-07-29 06:23:33 -0700386 case kRGBA_F16_SkColorType:
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400387 SkASSERT(needsColorXform);
nagarajan.n08cda142017-09-07 20:03:29 +0530388 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
389 break;
msarett1c8a5872015-07-07 08:50:01 -0700390 default:
391 return false;
392 }
nagarajan.n08cda142017-09-07 20:03:29 +0530393
394 // Check if we will decode to CMYK. libjpeg-turbo does not convert CMYK to RGBA, so
395 // we must do it ourselves.
396 if (JCS_CMYK == encodedColorType || JCS_YCCK == encodedColorType) {
397 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
398 }
399
400 return true;
msarett1c8a5872015-07-07 08:50:01 -0700401}
402
403/*
mtkleine721a8e2016-02-06 19:12:23 -0800404 * Checks if we can natively scale to the requested dimensions and natively scales the
emmaleer8f4ba762015-08-14 07:44:46 -0700405 * dimensions if possible
msarett97fdea62015-04-29 08:17:15 -0700406 */
scroggoe7fc14b2015-10-02 13:14:46 -0700407bool SkJpegCodec::onDimensionsSupported(const SkISize& size) {
Chris Dalton3e794592017-12-01 13:11:09 -0700408 skjpeg_error_mgr::AutoPushJmpBuf jmp(fDecoderMgr->errorMgr());
409 if (setjmp(jmp)) {
msarett50ce1f22016-07-29 06:23:33 -0700410 return fDecoderMgr->returnFalse("onDimensionsSupported");
scroggoe7fc14b2015-10-02 13:14:46 -0700411 }
412
413 const unsigned int dstWidth = size.width();
414 const unsigned int dstHeight = size.height();
415
416 // Set up a fake decompress struct in order to use libjpeg to calculate output dimensions
417 // FIXME: Why is this necessary?
418 jpeg_decompress_struct dinfo;
419 sk_bzero(&dinfo, sizeof(dinfo));
Leon Scroggins III712476e2018-10-03 15:47:00 -0400420 dinfo.image_width = this->dimensions().width();
421 dinfo.image_height = this->dimensions().height();
scroggoe7fc14b2015-10-02 13:14:46 -0700422 dinfo.global_state = fReadyState;
423
msarett1c8a5872015-07-07 08:50:01 -0700424 // 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 -0700425 unsigned int num = 8;
426 const unsigned int denom = 8;
427 calc_output_dimensions(&dinfo, num, denom);
428 while (dinfo.output_width != dstWidth || dinfo.output_height != dstHeight) {
msarett97fdea62015-04-29 08:17:15 -0700429
430 // Return a failure if we have tried all of the possible scales
scroggoe7fc14b2015-10-02 13:14:46 -0700431 if (1 == num || dstWidth > dinfo.output_width || dstHeight > dinfo.output_height) {
emmaleer8f4ba762015-08-14 07:44:46 -0700432 return false;
msarett97fdea62015-04-29 08:17:15 -0700433 }
434
435 // Try the next scale
scroggoe7fc14b2015-10-02 13:14:46 -0700436 num -= 1;
437 calc_output_dimensions(&dinfo, num, denom);
msarett97fdea62015-04-29 08:17:15 -0700438 }
scroggoe7fc14b2015-10-02 13:14:46 -0700439
440 fDecoderMgr->dinfo()->scale_num = num;
441 fDecoderMgr->dinfo()->scale_denom = denom;
msarett97fdea62015-04-29 08:17:15 -0700442 return true;
443}
444
Matt Sarettc8c901f2017-01-24 16:16:33 -0500445int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count,
446 const Options& opts) {
msarett50ce1f22016-07-29 06:23:33 -0700447 // Set the jump location for libjpeg-turbo errors
Chris Dalton3e794592017-12-01 13:11:09 -0700448 skjpeg_error_mgr::AutoPushJmpBuf jmp(fDecoderMgr->errorMgr());
449 if (setjmp(jmp)) {
msarett50ce1f22016-07-29 06:23:33 -0700450 return 0;
451 }
452
453 // When fSwizzleSrcRow is non-null, it means that we need to swizzle. In this case,
454 // we will always decode into fSwizzlerSrcRow before swizzling into the next buffer.
455 // We can never swizzle "in place" because the swizzler may perform sampling and/or
456 // subsetting.
457 // When fColorXformSrcRow is non-null, it means that we need to color xform and that
Brian Osmanb3f38302018-09-07 15:24:44 -0400458 // we cannot color xform "in place" (many times we can, but not when the src and dst
459 // are different sizes).
Matt Sarett313c4632016-10-20 12:35:23 -0400460 // In this case, we will color xform from fColorXformSrcRow into the dst.
msarett50ce1f22016-07-29 06:23:33 -0700461 JSAMPLE* decodeDst = (JSAMPLE*) dst;
462 uint32_t* swizzleDst = (uint32_t*) dst;
463 size_t decodeDstRowBytes = rowBytes;
464 size_t swizzleDstRowBytes = rowBytes;
Matt Sarettc8c901f2017-01-24 16:16:33 -0500465 int dstWidth = opts.fSubset ? opts.fSubset->width() : dstInfo.width();
msarett50ce1f22016-07-29 06:23:33 -0700466 if (fSwizzleSrcRow && fColorXformSrcRow) {
467 decodeDst = (JSAMPLE*) fSwizzleSrcRow;
468 swizzleDst = fColorXformSrcRow;
469 decodeDstRowBytes = 0;
470 swizzleDstRowBytes = 0;
msarett35bb74b2016-08-22 07:41:28 -0700471 dstWidth = fSwizzler->swizzleWidth();
msarett50ce1f22016-07-29 06:23:33 -0700472 } else if (fColorXformSrcRow) {
473 decodeDst = (JSAMPLE*) fColorXformSrcRow;
474 swizzleDst = fColorXformSrcRow;
475 decodeDstRowBytes = 0;
476 swizzleDstRowBytes = 0;
477 } else if (fSwizzleSrcRow) {
478 decodeDst = (JSAMPLE*) fSwizzleSrcRow;
479 decodeDstRowBytes = 0;
msarett35bb74b2016-08-22 07:41:28 -0700480 dstWidth = fSwizzler->swizzleWidth();
msarett50ce1f22016-07-29 06:23:33 -0700481 }
482
483 for (int y = 0; y < count; y++) {
484 uint32_t lines = jpeg_read_scanlines(fDecoderMgr->dinfo(), &decodeDst, 1);
msarett50ce1f22016-07-29 06:23:33 -0700485 if (0 == lines) {
486 return y;
487 }
488
489 if (fSwizzler) {
490 fSwizzler->swizzle(swizzleDst, decodeDst);
491 }
492
Matt Sarett313c4632016-10-20 12:35:23 -0400493 if (this->colorXform()) {
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400494 this->applyColorXform(dst, swizzleDst, dstWidth);
msarett50ce1f22016-07-29 06:23:33 -0700495 dst = SkTAddOffset<void>(dst, rowBytes);
496 }
497
498 decodeDst = SkTAddOffset<JSAMPLE>(decodeDst, decodeDstRowBytes);
499 swizzleDst = SkTAddOffset<uint32_t>(swizzleDst, swizzleDstRowBytes);
500 }
501
502 return count;
503}
504
msarett97fdea62015-04-29 08:17:15 -0700505/*
Matt Sarett7f15b682017-02-24 17:22:09 -0500506 * This is a bit tricky. We only need the swizzler to do format conversion if the jpeg is
507 * encoded as CMYK.
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400508 * And even then we still may not need it. If the jpeg has a CMYK color profile and a color
Matt Sarett7f15b682017-02-24 17:22:09 -0500509 * xform, the color xform will handle the CMYK->RGB conversion.
510 */
511static inline bool needs_swizzler_to_convert_from_cmyk(J_COLOR_SPACE jpegColorType,
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400512 const skcms_ICCProfile* srcProfile,
513 bool hasColorSpaceXform) {
Matt Sarett7f15b682017-02-24 17:22:09 -0500514 if (JCS_CMYK != jpegColorType) {
515 return false;
516 }
517
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400518 bool hasCMYKColorSpace = srcProfile && srcProfile->data_color_space == skcms_Signature_CMYK;
Matt Sarett7f15b682017-02-24 17:22:09 -0500519 return !hasCMYKColorSpace || !hasColorSpaceXform;
520}
521
522/*
msarette16b04a2015-04-15 07:32:19 -0700523 * Performs the jpeg decode
524 */
525SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
526 void* dst, size_t dstRowBytes,
Leon Scroggins571b30f2017-07-11 17:35:31 +0000527 const Options& options,
msarette6dd0042015-10-09 11:07:34 -0700528 int* rowsDecoded) {
scroggob636b452015-07-22 07:16:20 -0700529 if (options.fSubset) {
530 // Subsets are not supported.
531 return kUnimplemented;
532 }
533
msarette16b04a2015-04-15 07:32:19 -0700534 // Get a pointer to the decompress info since we will use it quite frequently
535 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
536
537 // Set the jump location for libjpeg errors
Chris Dalton3e794592017-12-01 13:11:09 -0700538 skjpeg_error_mgr::AutoPushJmpBuf jmp(fDecoderMgr->errorMgr());
539 if (setjmp(jmp)) {
msarette16b04a2015-04-15 07:32:19 -0700540 return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
541 }
542
msarettfbccb592015-09-01 06:43:41 -0700543 if (!jpeg_start_decompress(dinfo)) {
msarette16b04a2015-04-15 07:32:19 -0700544 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
545 }
546
msarett1c8a5872015-07-07 08:50:01 -0700547 // The recommended output buffer height should always be 1 in high quality modes.
548 // If it's not, we want to know because it means our strategy is not optimal.
549 SkASSERT(1 == dinfo->rec_outbuf_height);
msarette16b04a2015-04-15 07:32:19 -0700550
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400551 if (needs_swizzler_to_convert_from_cmyk(dinfo->out_color_space,
552 this->getEncodedInfo().profile(), this->colorXform())) {
Matt Sarett7f15b682017-02-24 17:22:09 -0500553 this->initializeSwizzler(dstInfo, options, true);
scroggoef27d892015-10-23 09:29:22 -0700554 }
555
Leon Scroggins III9eb78742020-03-02 13:01:08 -0500556 if (!this->allocateStorage(dstInfo)) {
557 return kInternalError;
558 }
scroggoef27d892015-10-23 09:29:22 -0700559
Matt Sarettc8c901f2017-01-24 16:16:33 -0500560 int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height(), options);
msarett50ce1f22016-07-29 06:23:33 -0700561 if (rows < dstInfo.height()) {
562 *rowsDecoded = rows;
563 return fDecoderMgr->returnFailure("Incomplete image data", kIncompleteInput);
msarette16b04a2015-04-15 07:32:19 -0700564 }
msarette16b04a2015-04-15 07:32:19 -0700565
566 return kSuccess;
567}
msarett97fdea62015-04-29 08:17:15 -0700568
Leon Scroggins III9eb78742020-03-02 13:01:08 -0500569bool SkJpegCodec::allocateStorage(const SkImageInfo& dstInfo) {
msarett35bb74b2016-08-22 07:41:28 -0700570 int dstWidth = dstInfo.width();
571
msarett50ce1f22016-07-29 06:23:33 -0700572 size_t swizzleBytes = 0;
573 if (fSwizzler) {
574 swizzleBytes = get_row_bytes(fDecoderMgr->dinfo());
msarett35bb74b2016-08-22 07:41:28 -0700575 dstWidth = fSwizzler->swizzleWidth();
Matt Sarett313c4632016-10-20 12:35:23 -0400576 SkASSERT(!this->colorXform() || SkIsAlign4(swizzleBytes));
msarett50ce1f22016-07-29 06:23:33 -0700577 }
578
579 size_t xformBytes = 0;
Brian Osmanb3f38302018-09-07 15:24:44 -0400580
581 if (this->colorXform() && sizeof(uint32_t) != dstInfo.bytesPerPixel()) {
msarett35bb74b2016-08-22 07:41:28 -0700582 xformBytes = dstWidth * sizeof(uint32_t);
msarett50ce1f22016-07-29 06:23:33 -0700583 }
584
585 size_t totalBytes = swizzleBytes + xformBytes;
586 if (totalBytes > 0) {
Leon Scroggins III9eb78742020-03-02 13:01:08 -0500587 if (!fStorage.reset(totalBytes)) {
588 return false;
589 }
msarett50ce1f22016-07-29 06:23:33 -0700590 fSwizzleSrcRow = (swizzleBytes > 0) ? fStorage.get() : nullptr;
591 fColorXformSrcRow = (xformBytes > 0) ?
592 SkTAddOffset<uint32_t>(fStorage.get(), swizzleBytes) : nullptr;
593 }
Leon Scroggins III9eb78742020-03-02 13:01:08 -0500594 return true;
msarett50ce1f22016-07-29 06:23:33 -0700595}
596
Matt Sarett7f15b682017-02-24 17:22:09 -0500597void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options,
598 bool needsCMYKToRGB) {
msarett91c22b22016-02-22 12:27:46 -0800599 Options swizzlerOptions = options;
600 if (options.fSubset) {
601 // Use fSwizzlerSubset if this is a subset decode. This is necessary in the case
602 // where libjpeg-turbo provides a subset and then we need to subset it further.
603 // Also, verify that fSwizzlerSubset is initialized and valid.
604 SkASSERT(!fSwizzlerSubset.isEmpty() && fSwizzlerSubset.x() <= options.fSubset->x() &&
605 fSwizzlerSubset.width() == options.fSubset->width());
606 swizzlerOptions.fSubset = &fSwizzlerSubset;
607 }
Matt Sarett09a1c082017-02-01 15:34:22 -0800608
609 SkImageInfo swizzlerDstInfo = dstInfo;
Matt Sarett7f15b682017-02-24 17:22:09 -0500610 if (this->colorXform()) {
611 // The color xform will be expecting RGBA 8888 input.
Matt Sarett09a1c082017-02-01 15:34:22 -0800612 swizzlerDstInfo = swizzlerDstInfo.makeColorType(kRGBA_8888_SkColorType);
613 }
614
Leon Scroggins III65f4aea2018-10-24 12:17:22 -0400615 if (needsCMYKToRGB) {
616 // The swizzler is used to convert to from CMYK.
617 // The swizzler does not use the width or height on SkEncodedInfo.
618 auto swizzlerInfo = SkEncodedInfo::Make(0, 0, SkEncodedInfo::kInvertedCMYK_Color,
619 SkEncodedInfo::kOpaque_Alpha, 8);
620 fSwizzler = SkSwizzler::Make(swizzlerInfo, nullptr, swizzlerDstInfo, swizzlerOptions);
621 } else {
622 int srcBPP = 0;
623 switch (fDecoderMgr->dinfo()->out_color_space) {
624 case JCS_EXT_RGBA:
625 case JCS_EXT_BGRA:
626 case JCS_CMYK:
627 srcBPP = 4;
628 break;
629 case JCS_RGB565:
630 srcBPP = 2;
631 break;
632 case JCS_GRAYSCALE:
633 srcBPP = 1;
634 break;
635 default:
636 SkASSERT(false);
637 break;
638 }
639 fSwizzler = SkSwizzler::MakeSimple(srcBPP, swizzlerDstInfo, swizzlerOptions);
640 }
msarettb30d6982016-02-15 10:18:45 -0800641 SkASSERT(fSwizzler);
msarett50ce1f22016-07-29 06:23:33 -0700642}
643
msarettfdb47572015-10-13 12:50:14 -0700644SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) {
645 if (!createIfNecessary || fSwizzler) {
msarett50ce1f22016-07-29 06:23:33 -0700646 SkASSERT(!fSwizzler || (fSwizzleSrcRow && fStorage.get() == fSwizzleSrcRow));
Ben Wagner145dbcd2016-11-03 14:40:50 -0400647 return fSwizzler.get();
msarettfdb47572015-10-13 12:50:14 -0700648 }
649
Matt Sarett7f15b682017-02-24 17:22:09 -0500650 bool needsCMYKToRGB = needs_swizzler_to_convert_from_cmyk(
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400651 fDecoderMgr->dinfo()->out_color_space, this->getEncodedInfo().profile(),
652 this->colorXform());
Matt Sarett7f15b682017-02-24 17:22:09 -0500653 this->initializeSwizzler(this->dstInfo(), this->options(), needsCMYKToRGB);
Leon Scroggins III9eb78742020-03-02 13:01:08 -0500654 if (!this->allocateStorage(this->dstInfo())) {
655 return nullptr;
656 }
Ben Wagner145dbcd2016-11-03 14:40:50 -0400657 return fSwizzler.get();
scroggo46c57472015-09-30 08:57:13 -0700658}
scroggo1c005e42015-08-04 09:24:45 -0700659
scroggo46c57472015-09-30 08:57:13 -0700660SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
Leon Scroggins571b30f2017-07-11 17:35:31 +0000661 const Options& options) {
scroggo46c57472015-09-30 08:57:13 -0700662 // Set the jump location for libjpeg errors
Chris Dalton3e794592017-12-01 13:11:09 -0700663 skjpeg_error_mgr::AutoPushJmpBuf jmp(fDecoderMgr->errorMgr());
664 if (setjmp(jmp)) {
scroggo46c57472015-09-30 08:57:13 -0700665 SkCodecPrintf("setjmp: Error from libjpeg\n");
666 return kInvalidInput;
667 }
668
scroggo46c57472015-09-30 08:57:13 -0700669 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) {
670 SkCodecPrintf("start decompress failed\n");
671 return kInvalidInput;
672 }
673
Matt Sarett7f15b682017-02-24 17:22:09 -0500674 bool needsCMYKToRGB = needs_swizzler_to_convert_from_cmyk(
Leon Scroggins III36f7e322018-08-27 11:55:46 -0400675 fDecoderMgr->dinfo()->out_color_space, this->getEncodedInfo().profile(),
676 this->colorXform());
msarett91c22b22016-02-22 12:27:46 -0800677 if (options.fSubset) {
678 uint32_t startX = options.fSubset->x();
679 uint32_t width = options.fSubset->width();
680
681 // libjpeg-turbo may need to align startX to a multiple of the IDCT
682 // block size. If this is the case, it will decrease the value of
683 // startX to the appropriate alignment and also increase the value
684 // of width so that the right edge of the requested subset remains
685 // the same.
686 jpeg_crop_scanline(fDecoderMgr->dinfo(), &startX, &width);
687
688 SkASSERT(startX <= (uint32_t) options.fSubset->x());
689 SkASSERT(width >= (uint32_t) options.fSubset->width());
690 SkASSERT(startX + width >= (uint32_t) options.fSubset->right());
691
692 // Instruct the swizzler (if it is necessary) to further subset the
693 // output provided by libjpeg-turbo.
694 //
695 // We set this here (rather than in the if statement below), so that
696 // if (1) we don't need a swizzler for the subset, and (2) we need a
697 // swizzler for CMYK, the swizzler will still use the proper subset
698 // dimensions.
699 //
700 // Note that the swizzler will ignore the y and height parameters of
701 // the subset. Since the scanline decoder (and the swizzler) handle
702 // one row at a time, only the subsetting in the x-dimension matters.
703 fSwizzlerSubset.setXYWH(options.fSubset->x() - startX, 0,
704 options.fSubset->width(), options.fSubset->height());
705
706 // We will need a swizzler if libjpeg-turbo cannot provide the exact
707 // subset that we request.
708 if (startX != (uint32_t) options.fSubset->x() ||
709 width != (uint32_t) options.fSubset->width()) {
Matt Sarett7f15b682017-02-24 17:22:09 -0500710 this->initializeSwizzler(dstInfo, options, needsCMYKToRGB);
msarett91c22b22016-02-22 12:27:46 -0800711 }
712 }
713
714 // Make sure we have a swizzler if we are converting from CMYK.
Matt Sarett7f15b682017-02-24 17:22:09 -0500715 if (!fSwizzler && needsCMYKToRGB) {
716 this->initializeSwizzler(dstInfo, options, true);
msarett91c22b22016-02-22 12:27:46 -0800717 }
msarettfdb47572015-10-13 12:50:14 -0700718
Leon Scroggins III9eb78742020-03-02 13:01:08 -0500719 if (!this->allocateStorage(dstInfo)) {
720 return kInternalError;
721 }
msarett50ce1f22016-07-29 06:23:33 -0700722
scroggo46c57472015-09-30 08:57:13 -0700723 return kSuccess;
724}
725
mtkleine721a8e2016-02-06 19:12:23 -0800726int SkJpegCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
Matt Sarettc8c901f2017-01-24 16:16:33 -0500727 int rows = this->readRows(this->dstInfo(), dst, dstRowBytes, count, this->options());
msarett50ce1f22016-07-29 06:23:33 -0700728 if (rows < count) {
729 // This allows us to skip calling jpeg_finish_decompress().
730 fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height();
scroggo46c57472015-09-30 08:57:13 -0700731 }
732
msarett50ce1f22016-07-29 06:23:33 -0700733 return rows;
scroggo46c57472015-09-30 08:57:13 -0700734}
msarett97fdea62015-04-29 08:17:15 -0700735
msarette6dd0042015-10-09 11:07:34 -0700736bool SkJpegCodec::onSkipScanlines(int count) {
scroggo46c57472015-09-30 08:57:13 -0700737 // Set the jump location for libjpeg errors
Chris Dalton3e794592017-12-01 13:11:09 -0700738 skjpeg_error_mgr::AutoPushJmpBuf jmp(fDecoderMgr->errorMgr());
739 if (setjmp(jmp)) {
msarett50ce1f22016-07-29 06:23:33 -0700740 return fDecoderMgr->returnFalse("onSkipScanlines");
msarett97fdea62015-04-29 08:17:15 -0700741 }
742
msarettf724b992015-10-15 06:41:06 -0700743 return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count);
msarett97fdea62015-04-29 08:17:15 -0700744}
msarettb714fb02016-01-22 14:46:42 -0800745
Brian Salomon87d42e52020-08-24 09:18:16 -0400746static bool is_yuv_supported(const jpeg_decompress_struct* dinfo,
Brian Salomonbe0e42c2020-08-27 11:00:04 -0400747 const SkJpegCodec& codec,
Brian Salomon59c60b02020-09-01 15:01:15 -0400748 const SkYUVAPixmapInfo::SupportedDataTypes* supportedDataTypes,
Brian Salomonbe0e42c2020-08-27 11:00:04 -0400749 SkYUVAPixmapInfo* yuvaPixmapInfo) {
msarettb714fb02016-01-22 14:46:42 -0800750 // Scaling is not supported in raw data mode.
751 SkASSERT(dinfo->scale_num == dinfo->scale_denom);
752
753 // I can't imagine that this would ever change, but we do depend on it.
754 static_assert(8 == DCTSIZE, "DCTSIZE (defined in jpeg library) should always be 8.");
755
756 if (JCS_YCbCr != dinfo->jpeg_color_space) {
757 return false;
758 }
759
760 SkASSERT(3 == dinfo->num_components);
761 SkASSERT(dinfo->comp_info);
762
763 // It is possible to perform a YUV decode for any combination of
764 // horizontal and vertical sampling that is supported by
765 // libjpeg/libjpeg-turbo. However, we will start by supporting only the
766 // common cases (where U and V have samp_factors of one).
767 //
768 // The definition of samp_factor is kind of the opposite of what SkCodec
769 // thinks of as a sampling factor. samp_factor is essentially a
770 // multiplier, and the larger the samp_factor is, the more samples that
771 // there will be. Ex:
772 // U_plane_width = image_width * (U_h_samp_factor / max_h_samp_factor)
773 //
774 // Supporting cases where the samp_factors for U or V were larger than
775 // that of Y would be an extremely difficult change, given that clients
776 // allocate memory as if the size of the Y plane is always the size of the
777 // image. However, this case is very, very rare.
msarett7c87cf42016-03-04 06:23:20 -0800778 if ((1 != dinfo->comp_info[1].h_samp_factor) ||
779 (1 != dinfo->comp_info[1].v_samp_factor) ||
780 (1 != dinfo->comp_info[2].h_samp_factor) ||
781 (1 != dinfo->comp_info[2].v_samp_factor))
782 {
msarettb714fb02016-01-22 14:46:42 -0800783 return false;
784 }
785
786 // Support all common cases of Y samp_factors.
787 // TODO (msarett): As mentioned above, it would be possible to support
788 // more combinations of samp_factors. The issues are:
789 // (1) Are there actually any images that are not covered
790 // by these cases?
791 // (2) How much complexity would be added to the
792 // implementation in order to support these rare
793 // cases?
794 int hSampY = dinfo->comp_info[0].h_samp_factor;
795 int vSampY = dinfo->comp_info[0].v_samp_factor;
Brian Salomon87d42e52020-08-24 09:18:16 -0400796 SkASSERT(hSampY == dinfo->max_h_samp_factor);
797 SkASSERT(vSampY == dinfo->max_v_samp_factor);
msarettb714fb02016-01-22 14:46:42 -0800798
Brian Salomone4387382020-11-11 16:34:19 -0500799 SkYUVAInfo::Subsampling tempSubsampling;
Brian Salomon87d42e52020-08-24 09:18:16 -0400800 if (1 == hSampY && 1 == vSampY) {
Brian Salomone4387382020-11-11 16:34:19 -0500801 tempSubsampling = SkYUVAInfo::Subsampling::k444;
Brian Salomon87d42e52020-08-24 09:18:16 -0400802 } else if (2 == hSampY && 1 == vSampY) {
Brian Salomone4387382020-11-11 16:34:19 -0500803 tempSubsampling = SkYUVAInfo::Subsampling::k422;
Brian Salomon87d42e52020-08-24 09:18:16 -0400804 } else if (2 == hSampY && 2 == vSampY) {
Brian Salomone4387382020-11-11 16:34:19 -0500805 tempSubsampling = SkYUVAInfo::Subsampling::k420;
Brian Salomon87d42e52020-08-24 09:18:16 -0400806 } else if (1 == hSampY && 2 == vSampY) {
Brian Salomone4387382020-11-11 16:34:19 -0500807 tempSubsampling = SkYUVAInfo::Subsampling::k440;
Brian Salomon87d42e52020-08-24 09:18:16 -0400808 } else if (4 == hSampY && 1 == vSampY) {
Brian Salomone4387382020-11-11 16:34:19 -0500809 tempSubsampling = SkYUVAInfo::Subsampling::k411;
Brian Salomon87d42e52020-08-24 09:18:16 -0400810 } else if (4 == hSampY && 2 == vSampY) {
Brian Salomone4387382020-11-11 16:34:19 -0500811 tempSubsampling = SkYUVAInfo::Subsampling::k410;
Brian Salomon87d42e52020-08-24 09:18:16 -0400812 } else {
msarettb714fb02016-01-22 14:46:42 -0800813 return false;
814 }
Brian Salomon59c60b02020-09-01 15:01:15 -0400815 if (supportedDataTypes &&
Brian Salomone4387382020-11-11 16:34:19 -0500816 !supportedDataTypes->supported(SkYUVAInfo::PlaneConfig::kY_U_V,
817 SkYUVAPixmapInfo::DataType::kUnorm8)) {
Brian Salomon59c60b02020-09-01 15:01:15 -0400818 return false;
819 }
Brian Salomonbe0e42c2020-08-27 11:00:04 -0400820 if (yuvaPixmapInfo) {
821 SkColorType colorTypes[SkYUVAPixmapInfo::kMaxPlanes];
822 size_t rowBytes[SkYUVAPixmapInfo::kMaxPlanes];
Brian Salomon87d42e52020-08-24 09:18:16 -0400823 for (int i = 0; i < 3; ++i) {
824 colorTypes[i] = kAlpha_8_SkColorType;
Brian Salomon87d42e52020-08-24 09:18:16 -0400825 rowBytes[i] = dinfo->comp_info[i].width_in_blocks * DCTSIZE;
826 }
Brian Salomonbe0e42c2020-08-27 11:00:04 -0400827 SkYUVAInfo yuvaInfo(codec.dimensions(),
Brian Salomone4387382020-11-11 16:34:19 -0500828 SkYUVAInfo::PlaneConfig::kY_U_V,
829 tempSubsampling,
Brian Salomonbe0e42c2020-08-27 11:00:04 -0400830 kJPEG_Full_SkYUVColorSpace,
831 codec.getOrigin(),
832 SkYUVAInfo::Siting::kCentered,
833 SkYUVAInfo::Siting::kCentered);
834 *yuvaPixmapInfo = SkYUVAPixmapInfo(yuvaInfo, colorTypes, rowBytes);
Brian Salomon87d42e52020-08-24 09:18:16 -0400835 }
msarettb714fb02016-01-22 14:46:42 -0800836 return true;
837}
838
Brian Salomon59c60b02020-09-01 15:01:15 -0400839bool SkJpegCodec::onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes& supportedDataTypes,
840 SkYUVAPixmapInfo* yuvaPixmapInfo) const {
Brian Salomon87d42e52020-08-24 09:18:16 -0400841 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
Brian Salomon59c60b02020-09-01 15:01:15 -0400842 return is_yuv_supported(dinfo, *this, &supportedDataTypes, yuvaPixmapInfo);
Brian Salomon87d42e52020-08-24 09:18:16 -0400843}
msarettb714fb02016-01-22 14:46:42 -0800844
Brian Salomonbe0e42c2020-08-27 11:00:04 -0400845SkCodec::Result SkJpegCodec::onGetYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps) {
Brian Salomon87d42e52020-08-24 09:18:16 -0400846 // Get a pointer to the decompress info since we will use it quite frequently
847 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
Brian Salomon59c60b02020-09-01 15:01:15 -0400848 if (!is_yuv_supported(dinfo, *this, nullptr, nullptr)) {
Brian Salomon87d42e52020-08-24 09:18:16 -0400849 return fDecoderMgr->returnFailure("onGetYUVAPlanes", kInvalidInput);
850 }
msarettb714fb02016-01-22 14:46:42 -0800851 // Set the jump location for libjpeg errors
Chris Dalton3e794592017-12-01 13:11:09 -0700852 skjpeg_error_mgr::AutoPushJmpBuf jmp(fDecoderMgr->errorMgr());
853 if (setjmp(jmp)) {
msarettb714fb02016-01-22 14:46:42 -0800854 return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
855 }
856
msarettb714fb02016-01-22 14:46:42 -0800857 dinfo->raw_data_out = TRUE;
858 if (!jpeg_start_decompress(dinfo)) {
859 return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
860 }
861
Brian Salomonbe0e42c2020-08-27 11:00:04 -0400862 const std::array<SkPixmap, SkYUVAPixmaps::kMaxPlanes>& planes = yuvaPixmaps.planes();
863
Brian Salomon87d42e52020-08-24 09:18:16 -0400864#ifdef SK_DEBUG
865 {
866 // A previous implementation claims that the return value of is_yuv_supported()
867 // may change after calling jpeg_start_decompress(). It looks to me like this
868 // was caused by a bug in the old code, but we'll be safe and check here.
869 // Also check that pixmap properties agree with expectations.
Brian Salomonbe0e42c2020-08-27 11:00:04 -0400870 SkYUVAPixmapInfo info;
Brian Salomon59c60b02020-09-01 15:01:15 -0400871 SkASSERT(is_yuv_supported(dinfo, *this, nullptr, &info));
Brian Salomonbe0e42c2020-08-27 11:00:04 -0400872 SkASSERT(info.yuvaInfo() == yuvaPixmaps.yuvaInfo());
873 for (int i = 0; i < info.numPlanes(); ++i) {
Brian Salomon87d42e52020-08-24 09:18:16 -0400874 SkASSERT(planes[i].colorType() == kAlpha_8_SkColorType);
Brian Salomonbe0e42c2020-08-27 11:00:04 -0400875 SkASSERT(info.planeInfo(i) == planes[i].info());
Brian Salomon87d42e52020-08-24 09:18:16 -0400876 }
877 }
878#endif
msarettb714fb02016-01-22 14:46:42 -0800879
880 // Build a JSAMPIMAGE to handle output from libjpeg-turbo. A JSAMPIMAGE has
881 // a 2-D array of pixels for each of the components (Y, U, V) in the image.
882 // Cheat Sheet:
883 // JSAMPIMAGE == JSAMPLEARRAY* == JSAMPROW** == JSAMPLE***
884 JSAMPARRAY yuv[3];
885
886 // Set aside enough space for pointers to rows of Y, U, and V.
887 JSAMPROW rowptrs[2 * DCTSIZE + DCTSIZE + DCTSIZE];
Brian Salomon87d42e52020-08-24 09:18:16 -0400888 yuv[0] = &rowptrs[0]; // Y rows (DCTSIZE or 2 * DCTSIZE)
889 yuv[1] = &rowptrs[2 * DCTSIZE]; // U rows (DCTSIZE)
890 yuv[2] = &rowptrs[3 * DCTSIZE]; // V rows (DCTSIZE)
msarettb714fb02016-01-22 14:46:42 -0800891
892 // Initialize rowptrs.
893 int numYRowsPerBlock = DCTSIZE * dinfo->comp_info[0].v_samp_factor;
Brian Salomon87d42e52020-08-24 09:18:16 -0400894 static_assert(sizeof(JSAMPLE) == 1);
msarettb714fb02016-01-22 14:46:42 -0800895 for (int i = 0; i < numYRowsPerBlock; i++) {
Brian Salomonbe0e42c2020-08-27 11:00:04 -0400896 rowptrs[i] = static_cast<JSAMPLE*>(planes[0].writable_addr()) + i* planes[0].rowBytes();
msarettb714fb02016-01-22 14:46:42 -0800897 }
898 for (int i = 0; i < DCTSIZE; i++) {
Jim Van Verth8f11e432018-10-18 14:36:59 -0400899 rowptrs[i + 2 * DCTSIZE] =
Brian Salomonbe0e42c2020-08-27 11:00:04 -0400900 static_cast<JSAMPLE*>(planes[1].writable_addr()) + i* planes[1].rowBytes();
Jim Van Verth8f11e432018-10-18 14:36:59 -0400901 rowptrs[i + 3 * DCTSIZE] =
Brian Salomonbe0e42c2020-08-27 11:00:04 -0400902 static_cast<JSAMPLE*>(planes[2].writable_addr()) + i* planes[2].rowBytes();
msarettb714fb02016-01-22 14:46:42 -0800903 }
904
905 // After each loop iteration, we will increment pointers to Y, U, and V.
Brian Salomon87d42e52020-08-24 09:18:16 -0400906 size_t blockIncrementY = numYRowsPerBlock * planes[0].rowBytes();
907 size_t blockIncrementU = DCTSIZE * planes[1].rowBytes();
908 size_t blockIncrementV = DCTSIZE * planes[2].rowBytes();
msarettb714fb02016-01-22 14:46:42 -0800909
910 uint32_t numRowsPerBlock = numYRowsPerBlock;
911
912 // We intentionally round down here, as this first loop will only handle
913 // full block rows. As a special case at the end, we will handle any
914 // remaining rows that do not make up a full block.
915 const int numIters = dinfo->output_height / numRowsPerBlock;
916 for (int i = 0; i < numIters; i++) {
917 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock);
918 if (linesRead < numRowsPerBlock) {
919 // FIXME: Handle incomplete YUV decodes without signalling an error.
920 return kInvalidInput;
921 }
922
923 // Update rowptrs.
John Stileseeff41a2021-08-02 14:46:15 -0400924 for (int j = 0; j < numYRowsPerBlock; j++) {
925 rowptrs[j] += blockIncrementY;
msarettb714fb02016-01-22 14:46:42 -0800926 }
John Stileseeff41a2021-08-02 14:46:15 -0400927 for (int j = 0; j < DCTSIZE; j++) {
928 rowptrs[j + 2 * DCTSIZE] += blockIncrementU;
929 rowptrs[j + 3 * DCTSIZE] += blockIncrementV;
msarettb714fb02016-01-22 14:46:42 -0800930 }
931 }
932
933 uint32_t remainingRows = dinfo->output_height - dinfo->output_scanline;
934 SkASSERT(remainingRows == dinfo->output_height % numRowsPerBlock);
935 SkASSERT(dinfo->output_scanline == numIters * numRowsPerBlock);
936 if (remainingRows > 0) {
937 // libjpeg-turbo needs memory to be padded by the block sizes. We will fulfill
Brian Salomon87d42e52020-08-24 09:18:16 -0400938 // this requirement using an extra row buffer.
msarettb714fb02016-01-22 14:46:42 -0800939 // FIXME: Should SkCodec have an extra memory buffer that can be shared among
940 // all of the implementations that use temporary/garbage memory?
Brian Salomon87d42e52020-08-24 09:18:16 -0400941 SkAutoTMalloc<JSAMPLE> extraRow(planes[0].rowBytes());
msarettb714fb02016-01-22 14:46:42 -0800942 for (int i = remainingRows; i < numYRowsPerBlock; i++) {
Brian Salomon87d42e52020-08-24 09:18:16 -0400943 rowptrs[i] = extraRow.get();
msarettb714fb02016-01-22 14:46:42 -0800944 }
945 int remainingUVRows = dinfo->comp_info[1].downsampled_height - DCTSIZE * numIters;
946 for (int i = remainingUVRows; i < DCTSIZE; i++) {
Brian Salomon87d42e52020-08-24 09:18:16 -0400947 rowptrs[i + 2 * DCTSIZE] = extraRow.get();
948 rowptrs[i + 3 * DCTSIZE] = extraRow.get();
msarettb714fb02016-01-22 14:46:42 -0800949 }
950
951 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock);
952 if (linesRead < remainingRows) {
953 // FIXME: Handle incomplete YUV decodes without signalling an error.
954 return kInvalidInput;
955 }
956 }
957
958 return kSuccess;
959}
Hal Canary83e0f1b2018-04-05 16:58:41 -0400960
961// This function is declared in SkJpegInfo.h, used by SkPDF.
962bool SkGetJpegInfo(const void* data, size_t len,
963 SkISize* size,
964 SkEncodedInfo::Color* colorType,
965 SkEncodedOrigin* orientation) {
966 if (!SkJpegCodec::IsJpeg(data, len)) {
967 return false;
968 }
969
970 SkMemoryStream stream(data, len);
971 JpegDecoderMgr decoderMgr(&stream);
972 // libjpeg errors will be caught and reported here
973 skjpeg_error_mgr::AutoPushJmpBuf jmp(decoderMgr.errorMgr());
974 if (setjmp(jmp)) {
975 return false;
976 }
977 decoderMgr.init();
978 jpeg_decompress_struct* dinfo = decoderMgr.dinfo();
979 jpeg_save_markers(dinfo, kExifMarker, 0xFFFF);
980 jpeg_save_markers(dinfo, kICCMarker, 0xFFFF);
981 if (JPEG_HEADER_OK != jpeg_read_header(dinfo, true)) {
982 return false;
983 }
984 SkEncodedInfo::Color encodedColorType;
985 if (!decoderMgr.getEncodedColor(&encodedColorType)) {
986 return false; // Unable to interpret the color channels as colors.
987 }
988 if (colorType) {
989 *colorType = encodedColorType;
990 }
991 if (orientation) {
992 *orientation = get_exif_orientation(dinfo);
993 }
994 if (size) {
995 *size = {SkToS32(dinfo->image_width), SkToS32(dinfo->image_height)};
996 }
997 return true;
998}