1/*
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 "src/codec/SkJpegCodec.h"
9
10#include "include/codec/SkCodec.h"
11#include "include/codec/SkJpegDecoder.h"
12#include "include/core/SkAlphaType.h"
13#include "include/core/SkColorType.h"
14#include "include/core/SkData.h"
15#include "include/core/SkImageInfo.h"
16#include "include/core/SkPixmap.h"
17#include "include/core/SkRefCnt.h"
18#include "include/core/SkStream.h"
19#include "include/core/SkTypes.h"
20#include "include/core/SkYUVAInfo.h"
21#include "include/private/SkJpegMetadataDecoder.h"
22#include "include/private/base/SkAlign.h"
23#include "include/private/base/SkMalloc.h"
24#include "include/private/base/SkTemplates.h"
25#include "modules/skcms/skcms.h"
26#include "src/codec/SkCodecPriv.h"
27#include "src/codec/SkJpegConstants.h"
28#include "src/codec/SkJpegDecoderMgr.h"
29#include "src/codec/SkJpegPriv.h"
30#include "src/codec/SkParseEncodedOrigin.h"
31#include "src/codec/SkSwizzler.h"
32
33#ifdef SK_CODEC_DECODES_JPEG_GAINMAPS
34#include "include/private/SkGainmapInfo.h"
35#include "include/private/SkXmp.h"
36#include "src/codec/SkJpegMultiPicture.h"
37#include "src/codec/SkJpegSegmentScan.h"
38#include "src/codec/SkJpegXmp.h"
39#endif // SK_CODEC_DECODES_JPEG_GAINMAPS
40
41#include <array>
42#include <csetjmp>
43#include <cstring>
44#include <utility>
45#include <vector>
46
47using namespace skia_private;
48
49class SkSampler;
50struct SkGainmapInfo;
51
52// This warning triggers false postives way too often in here.
53#if defined(__GNUC__) && !defined(__clang__)
54 #pragma GCC diagnostic ignored "-Wclobbered"
55#endif
56
57extern "C" {
58 #include "jpeglib.h"
59 #include "jmorecfg.h"
60}
61
62bool SkJpegCodec::IsJpeg(const void* buffer, size_t bytesRead) {
63 return bytesRead >= sizeof(kJpegSig) && !memcmp(s1: buffer, s2: kJpegSig, n: sizeof(kJpegSig));
64}
65
66using SkJpegMarker = SkJpegMetadataDecoder::Segment;
67using SkJpegMarkerList = std::vector<SkJpegMarker>;
68
69SkJpegMarkerList get_sk_marker_list(jpeg_decompress_struct* dinfo) {
70 SkJpegMarkerList markerList;
71 for (auto* marker = dinfo->marker_list; marker; marker = marker->next) {
72 markerList.emplace_back(args&: marker->marker,
73 args: SkData::MakeWithoutCopy(data: marker->data, length: marker->data_length));
74 }
75 return markerList;
76}
77
78/**
79 * Return true if the specified SkJpegMarker has marker |targetMarker| and begins with the specified
80 * signature.
81 */
82static bool marker_has_signature(const SkJpegMarker& marker,
83 const uint32_t targetMarker,
84 const uint8_t* signature,
85 size_t signatureSize) {
86 if (targetMarker != marker.fMarker) {
87 return false;
88 }
89 if (marker.fData->size() <= signatureSize) {
90 return false;
91 }
92 if (memcmp(s1: marker.fData->bytes(), s2: signature, n: signatureSize) != 0) {
93 return false;
94 }
95 return true;
96}
97
98/*
99 * Return metadata with a specific marker and signature.
100 *
101 * Search for segments that start with the specified targetMarker, followed by the specified
102 * signature, followed by (optional) padding.
103 *
104 * Some types of metadata (e.g, ICC profiles) are too big to fit into a single segment's data (which
105 * is limited to 64k), and come in multiple parts. For this type of data, bytesInIndex is >0. After
106 * the signature comes bytesInIndex bytes (big endian) for the index of the segment's part, followed
107 * by bytesInIndex bytes (big endian) for the total number of parts. If all parts are present,
108 * stitch them together and return the combined result. Return failure if parts are absent, there
109 * are duplicate parts, or parts disagree on the total number of parts.
110 *
111 * Visually, each segment is:
112 * [|signatureSize| bytes containing |signature|]
113 * [|signaturePadding| bytes that are unexamined]
114 * [|bytesInIndex] bytes listing the segment index for multi-segment metadata]
115 * [|bytesInIndex] bytes listing the segment count for multi-segment metadata]
116 * [the returned data]
117 *
118 * If alwaysCopyData is true, then return a copy of the data. If alwaysCopyData is false, then
119 * return a direct reference to the data pointed to by dinfo, if possible.
120 */
121static sk_sp<SkData> read_metadata(const SkJpegMarkerList& markerList,
122 const uint32_t targetMarker,
123 const uint8_t* signature,
124 size_t signatureSize,
125 size_t signaturePadding,
126 size_t bytesInIndex,
127 bool alwaysCopyData) {
128 // Compute the total size of the entire header (signature plus padding plus index plus count),
129 // since we'll use it often.
130 const size_t headerSize = signatureSize + signaturePadding + 2 * bytesInIndex;
131
132 // A map from part index to the data in each part.
133 std::vector<sk_sp<SkData>> parts;
134
135 // Running total of number of data in all parts.
136 size_t partsTotalSize = 0;
137
138 // Running total number of parts found.
139 uint32_t foundPartCount = 0;
140
141 // The expected number of parts (initialized at the first part we encounter).
142 uint32_t expectedPartCount = 0;
143
144 // Iterate through the image's segments.
145 for (const auto& marker : markerList) {
146 // Skip segments that don't have the right marker or signature.
147 if (!marker_has_signature(marker, targetMarker, signature, signatureSize)) {
148 continue;
149 }
150
151 // Skip segments that are too small to include the index and count.
152 const size_t dataLength = marker.fData->size();
153 if (dataLength <= headerSize) {
154 continue;
155 }
156
157 // Read this part's index and count as big-endian (if they are present, otherwise hard-code
158 // them to 1).
159 const uint8_t* data = marker.fData->bytes();
160 uint32_t partIndex = 0;
161 uint32_t partCount = 0;
162 if (bytesInIndex == 0) {
163 partIndex = 1;
164 partCount = 1;
165 } else {
166 for (size_t i = 0; i < bytesInIndex; ++i) {
167 const size_t offset = signatureSize + signaturePadding;
168 partIndex = (partIndex << 8) + data[offset + i];
169 partCount = (partCount << 8) + data[offset + bytesInIndex + i];
170 }
171 }
172
173 // A part count of 0 is invalid.
174 if (!partCount) {
175 SkCodecPrintf("Invalid marker part count zero\n");
176 return nullptr;
177 }
178
179 // The indices must in the range 1, ..., count.
180 if (partIndex <= 0 || partIndex > partCount) {
181 SkCodecPrintf("Invalid marker index %u for count %u\n", partIndex, partCount);
182 return nullptr;
183 }
184
185 // If this is the first marker we've encountered set the expected part count to its count.
186 if (expectedPartCount == 0) {
187 expectedPartCount = partCount;
188 parts.resize(sz: expectedPartCount);
189 }
190
191 // If this does not match the expected part count, then fail.
192 if (partCount != expectedPartCount) {
193 SkCodecPrintf("Conflicting marker counts %u vs %u\n", partCount, expectedPartCount);
194 return nullptr;
195 }
196
197 // Make an SkData directly referencing the decoder's data for this part.
198 auto partData = SkData::MakeWithoutCopy(data: data + headerSize, length: dataLength - headerSize);
199
200 // Fail if duplicates are found.
201 if (parts[partIndex-1]) {
202 SkCodecPrintf("Duplicate parts for index %u of %u\n", partIndex, expectedPartCount);
203 return nullptr;
204 }
205
206 // Save part in the map.
207 partsTotalSize += partData->size();
208 parts[partIndex-1] = std::move(partData);
209 foundPartCount += 1;
210
211 // Stop as soon as we find all of the parts.
212 if (foundPartCount == expectedPartCount) {
213 break;
214 }
215 }
216
217 // Return nullptr if we don't find the data (this is not an error).
218 if (expectedPartCount == 0) {
219 return nullptr;
220 }
221
222 // Fail if we don't have all of the parts.
223 if (foundPartCount != expectedPartCount) {
224 SkCodecPrintf("Incomplete set of markers (expected %u got %u)\n",
225 expectedPartCount,
226 foundPartCount);
227 return nullptr;
228 }
229
230 // Return a direct reference to the data if there is only one part and we're allowed to.
231 if (!alwaysCopyData && expectedPartCount == 1) {
232 return std::move(parts[0]);
233 }
234
235 // Copy all of the markers and stitch them together.
236 auto result = SkData::MakeUninitialized(length: partsTotalSize);
237 void* copyDest = result->writable_data();
238 for (const auto& part : parts) {
239 memcpy(dest: copyDest, src: part->data(), n: part->size());
240 copyDest = SkTAddOffset<void>(ptr: copyDest, byteOffset: part->size());
241 }
242 return result;
243}
244
245static SkEncodedOrigin get_exif_orientation(sk_sp<SkData> exifData) {
246 SkEncodedOrigin origin = kDefault_SkEncodedOrigin;
247 if (exifData && SkParseEncodedOrigin(data: exifData->bytes(), data_length: exifData->size(), out: &origin)) {
248 return origin;
249 }
250 return kDefault_SkEncodedOrigin;
251}
252
253SkCodec::Result SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
254 JpegDecoderMgr** decoderMgrOut,
255 std::unique_ptr<SkEncodedInfo::ICCProfile> defaultColorProfile) {
256
257 // Create a JpegDecoderMgr to own all of the decompress information
258 std::unique_ptr<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream));
259
260 // libjpeg errors will be caught and reported here
261 skjpeg_error_mgr::AutoPushJmpBuf jmp(decoderMgr->errorMgr());
262 if (setjmp(jmp)) {
263 return decoderMgr->returnFailure(caller: "ReadHeader", result: kInvalidInput);
264 }
265
266 // Initialize the decompress info and the source manager
267 decoderMgr->init();
268 auto* dinfo = decoderMgr->dinfo();
269
270 // Instruct jpeg library to save the markers that we care about. Since
271 // the orientation and color profile will not change, we can skip this
272 // step on rewinds.
273 if (codecOut) {
274 jpeg_save_markers(cinfo: dinfo, marker_code: kExifMarker, length_limit: 0xFFFF);
275 jpeg_save_markers(cinfo: dinfo, marker_code: kICCMarker, length_limit: 0xFFFF);
276 jpeg_save_markers(cinfo: dinfo, marker_code: kMpfMarker, length_limit: 0xFFFF);
277 jpeg_save_markers(cinfo: dinfo, marker_code: kGainmapMarker, length_limit: 0xFFFF);
278 }
279
280 // Read the jpeg header
281 switch (jpeg_read_header(cinfo: dinfo, require_image: true)) {
282 case JPEG_HEADER_OK:
283 break;
284 case JPEG_SUSPENDED:
285 return decoderMgr->returnFailure(caller: "ReadHeader", result: kIncompleteInput);
286 default:
287 return decoderMgr->returnFailure(caller: "ReadHeader", result: kInvalidInput);
288 }
289
290 if (codecOut) {
291 // Get the encoded color type
292 SkEncodedInfo::Color color;
293 if (!decoderMgr->getEncodedColor(outColor: &color)) {
294 return kInvalidInput;
295 }
296
297 auto metadataDecoder = SkJpegMetadataDecoder::Make(headerSegments: get_sk_marker_list(dinfo));
298
299 SkEncodedOrigin orientation =
300 get_exif_orientation(exifData: metadataDecoder->getExifMetadata(/*copyData=*/false));
301
302 std::unique_ptr<SkEncodedInfo::ICCProfile> profile;
303 if (auto iccProfileData = metadataDecoder->getICCProfileData(/*copyData=*/true)) {
304 profile = SkEncodedInfo::ICCProfile::Make(std::move(iccProfileData));
305 }
306 if (profile) {
307 auto type = profile->profile()->data_color_space;
308 switch (decoderMgr->dinfo()->jpeg_color_space) {
309 case JCS_CMYK:
310 case JCS_YCCK:
311 if (type != skcms_Signature_CMYK) {
312 profile = nullptr;
313 }
314 break;
315 case JCS_GRAYSCALE:
316 if (type != skcms_Signature_Gray &&
317 type != skcms_Signature_RGB)
318 {
319 profile = nullptr;
320 }
321 break;
322 default:
323 if (type != skcms_Signature_RGB) {
324 profile = nullptr;
325 }
326 break;
327 }
328 }
329 if (!profile) {
330 profile = std::move(defaultColorProfile);
331 }
332
333 SkEncodedInfo info = SkEncodedInfo::Make(width: dinfo->image_width, height: dinfo->image_height,
334 color, alpha: SkEncodedInfo::kOpaque_Alpha, bitsPerComponent: 8,
335 profile: std::move(profile));
336
337 SkJpegCodec* codec = new SkJpegCodec(std::move(info),
338 std::unique_ptr<SkStream>(stream),
339 decoderMgr.release(),
340 orientation);
341 *codecOut = codec;
342 } else {
343 SkASSERT(nullptr != decoderMgrOut);
344 *decoderMgrOut = decoderMgr.release();
345 }
346 return kSuccess;
347}
348
349std::unique_ptr<SkCodec> SkJpegCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
350 Result* result) {
351 return SkJpegCodec::MakeFromStream(std::move(stream), result, defaultColorProfile: nullptr);
352}
353
354std::unique_ptr<SkCodec> SkJpegCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
355 Result* result, std::unique_ptr<SkEncodedInfo::ICCProfile> defaultColorProfile) {
356 SkASSERT(result);
357 if (!stream) {
358 *result = SkCodec::kInvalidInput;
359 return nullptr;
360 }
361 SkCodec* codec = nullptr;
362 *result = ReadHeader(stream: stream.get(), codecOut: &codec, decoderMgrOut: nullptr, defaultColorProfile: std::move(defaultColorProfile));
363 if (kSuccess == *result) {
364 // Codec has taken ownership of the stream, we do not need to delete it
365 SkASSERT(codec);
366 stream.release();
367 return std::unique_ptr<SkCodec>(codec);
368 }
369 return nullptr;
370}
371
372SkJpegCodec::SkJpegCodec(SkEncodedInfo&& info,
373 std::unique_ptr<SkStream> stream,
374 JpegDecoderMgr* decoderMgr,
375 SkEncodedOrigin origin)
376 : INHERITED(std::move(info), skcms_PixelFormat_RGBA_8888, std::move(stream), origin)
377 , fDecoderMgr(decoderMgr)
378 , fReadyState(decoderMgr->dinfo()->global_state) {}
379SkJpegCodec::~SkJpegCodec() = default;
380
381/*
382 * Return the row bytes of a particular image type and width
383 */
384static size_t get_row_bytes(const j_decompress_ptr dinfo) {
385 const size_t colorBytes = (dinfo->out_color_space == JCS_RGB565) ? 2 :
386 dinfo->out_color_components;
387 return dinfo->output_width * colorBytes;
388
389}
390
391/*
392 * Calculate output dimensions based on the provided factors.
393 *
394 * Not to be used on the actual jpeg_decompress_struct used for decoding, since it will
395 * incorrectly modify num_components.
396 */
397void calc_output_dimensions(jpeg_decompress_struct* dinfo, unsigned int num, unsigned int denom) {
398 dinfo->num_components = 0;
399 dinfo->scale_num = num;
400 dinfo->scale_denom = denom;
401 jpeg_calc_output_dimensions(cinfo: dinfo);
402}
403
404/*
405 * Return a valid set of output dimensions for this decoder, given an input scale
406 */
407SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const {
408 // 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
409 // support these as well
410 unsigned int num;
411 unsigned int denom = 8;
412 if (desiredScale >= 0.9375) {
413 num = 8;
414 } else if (desiredScale >= 0.8125) {
415 num = 7;
416 } else if (desiredScale >= 0.6875f) {
417 num = 6;
418 } else if (desiredScale >= 0.5625f) {
419 num = 5;
420 } else if (desiredScale >= 0.4375f) {
421 num = 4;
422 } else if (desiredScale >= 0.3125f) {
423 num = 3;
424 } else if (desiredScale >= 0.1875f) {
425 num = 2;
426 } else {
427 num = 1;
428 }
429
430 // Set up a fake decompress struct in order to use libjpeg to calculate output dimensions
431 jpeg_decompress_struct dinfo;
432 sk_bzero(buffer: &dinfo, size: sizeof(dinfo));
433 dinfo.image_width = this->dimensions().width();
434 dinfo.image_height = this->dimensions().height();
435 dinfo.global_state = fReadyState;
436 calc_output_dimensions(dinfo: &dinfo, num, denom);
437
438 // Return the calculated output dimensions for the given scale
439 return SkISize::Make(w: dinfo.output_width, h: dinfo.output_height);
440}
441
442bool SkJpegCodec::onRewind() {
443 JpegDecoderMgr* decoderMgr = nullptr;
444 if (kSuccess != ReadHeader(stream: this->stream(), codecOut: nullptr, decoderMgrOut: &decoderMgr, defaultColorProfile: nullptr)) {
445 return fDecoderMgr->returnFalse(caller: "onRewind");
446 }
447 SkASSERT(nullptr != decoderMgr);
448 fDecoderMgr.reset(p: decoderMgr);
449
450 fSwizzler.reset(p: nullptr);
451 fSwizzleSrcRow = nullptr;
452 fColorXformSrcRow = nullptr;
453 fStorage.reset();
454
455 return true;
456}
457
458bool SkJpegCodec::conversionSupported(const SkImageInfo& dstInfo, bool srcIsOpaque,
459 bool needsColorXform) {
460 SkASSERT(srcIsOpaque);
461
462 if (kUnknown_SkAlphaType == dstInfo.alphaType()) {
463 return false;
464 }
465
466 if (kOpaque_SkAlphaType != dstInfo.alphaType()) {
467 SkCodecPrintf("Warning: an opaque image should be decoded as opaque "
468 "- it is being decoded as non-opaque, which will draw slower\n");
469 }
470
471 J_COLOR_SPACE encodedColorType = fDecoderMgr->dinfo()->jpeg_color_space;
472
473 // Check for valid color types and set the output color space
474 switch (dstInfo.colorType()) {
475 case kRGBA_8888_SkColorType:
476 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
477 break;
478 case kBGRA_8888_SkColorType:
479 if (needsColorXform) {
480 // Always using RGBA as the input format for color xforms makes the
481 // implementation a little simpler.
482 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
483 } else {
484 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA;
485 }
486 break;
487 case kRGB_565_SkColorType:
488 if (needsColorXform) {
489 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
490 } else {
491 fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE;
492 fDecoderMgr->dinfo()->out_color_space = JCS_RGB565;
493 }
494 break;
495 case kGray_8_SkColorType:
496 if (JCS_GRAYSCALE != encodedColorType) {
497 return false;
498 }
499
500 if (needsColorXform) {
501 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
502 } else {
503 fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE;
504 }
505 break;
506 case kBGR_101010x_XR_SkColorType:
507 case kRGBA_F16_SkColorType:
508 SkASSERT(needsColorXform);
509 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
510 break;
511 default:
512 return false;
513 }
514
515 // Check if we will decode to CMYK. libjpeg-turbo does not convert CMYK to RGBA, so
516 // we must do it ourselves.
517 if (JCS_CMYK == encodedColorType || JCS_YCCK == encodedColorType) {
518 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
519 }
520
521 return true;
522}
523
524/*
525 * Checks if we can natively scale to the requested dimensions and natively scales the
526 * dimensions if possible
527 */
528bool SkJpegCodec::onDimensionsSupported(const SkISize& size) {
529 skjpeg_error_mgr::AutoPushJmpBuf jmp(fDecoderMgr->errorMgr());
530 if (setjmp(jmp)) {
531 return fDecoderMgr->returnFalse(caller: "onDimensionsSupported");
532 }
533
534 const unsigned int dstWidth = size.width();
535 const unsigned int dstHeight = size.height();
536
537 // Set up a fake decompress struct in order to use libjpeg to calculate output dimensions
538 // FIXME: Why is this necessary?
539 jpeg_decompress_struct dinfo;
540 sk_bzero(buffer: &dinfo, size: sizeof(dinfo));
541 dinfo.image_width = this->dimensions().width();
542 dinfo.image_height = this->dimensions().height();
543 dinfo.global_state = fReadyState;
544
545 // libjpeg-turbo can scale to 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, and 1/1
546 unsigned int num = 8;
547 const unsigned int denom = 8;
548 calc_output_dimensions(dinfo: &dinfo, num, denom);
549 while (dinfo.output_width != dstWidth || dinfo.output_height != dstHeight) {
550
551 // Return a failure if we have tried all of the possible scales
552 if (1 == num || dstWidth > dinfo.output_width || dstHeight > dinfo.output_height) {
553 return false;
554 }
555
556 // Try the next scale
557 num -= 1;
558 calc_output_dimensions(dinfo: &dinfo, num, denom);
559 }
560
561 fDecoderMgr->dinfo()->scale_num = num;
562 fDecoderMgr->dinfo()->scale_denom = denom;
563 return true;
564}
565
566int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count,
567 const Options& opts) {
568 // Set the jump location for libjpeg-turbo errors
569 skjpeg_error_mgr::AutoPushJmpBuf jmp(fDecoderMgr->errorMgr());
570 if (setjmp(jmp)) {
571 return 0;
572 }
573
574 // When fSwizzleSrcRow is non-null, it means that we need to swizzle. In this case,
575 // we will always decode into fSwizzlerSrcRow before swizzling into the next buffer.
576 // We can never swizzle "in place" because the swizzler may perform sampling and/or
577 // subsetting.
578 // When fColorXformSrcRow is non-null, it means that we need to color xform and that
579 // we cannot color xform "in place" (many times we can, but not when the src and dst
580 // are different sizes).
581 // In this case, we will color xform from fColorXformSrcRow into the dst.
582 JSAMPLE* decodeDst = (JSAMPLE*) dst;
583 uint32_t* swizzleDst = (uint32_t*) dst;
584 size_t decodeDstRowBytes = rowBytes;
585 size_t swizzleDstRowBytes = rowBytes;
586 int dstWidth = opts.fSubset ? opts.fSubset->width() : dstInfo.width();
587 if (fSwizzleSrcRow && fColorXformSrcRow) {
588 decodeDst = (JSAMPLE*) fSwizzleSrcRow;
589 swizzleDst = fColorXformSrcRow;
590 decodeDstRowBytes = 0;
591 swizzleDstRowBytes = 0;
592 dstWidth = fSwizzler->swizzleWidth();
593 } else if (fColorXformSrcRow) {
594 decodeDst = (JSAMPLE*) fColorXformSrcRow;
595 swizzleDst = fColorXformSrcRow;
596 decodeDstRowBytes = 0;
597 swizzleDstRowBytes = 0;
598 } else if (fSwizzleSrcRow) {
599 decodeDst = (JSAMPLE*) fSwizzleSrcRow;
600 decodeDstRowBytes = 0;
601 dstWidth = fSwizzler->swizzleWidth();
602 }
603
604 for (int y = 0; y < count; y++) {
605 uint32_t lines = jpeg_read_scanlines(cinfo: fDecoderMgr->dinfo(), scanlines: &decodeDst, max_lines: 1);
606 if (0 == lines) {
607 return y;
608 }
609
610 if (fSwizzler) {
611 fSwizzler->swizzle(dst: swizzleDst, src: decodeDst);
612 }
613
614 if (this->colorXform()) {
615 this->applyColorXform(dst, src: swizzleDst, count: dstWidth);
616 dst = SkTAddOffset<void>(ptr: dst, byteOffset: rowBytes);
617 }
618
619 decodeDst = SkTAddOffset<JSAMPLE>(ptr: decodeDst, byteOffset: decodeDstRowBytes);
620 swizzleDst = SkTAddOffset<uint32_t>(ptr: swizzleDst, byteOffset: swizzleDstRowBytes);
621 }
622
623 return count;
624}
625
626/*
627 * This is a bit tricky. We only need the swizzler to do format conversion if the jpeg is
628 * encoded as CMYK.
629 * And even then we still may not need it. If the jpeg has a CMYK color profile and a color
630 * xform, the color xform will handle the CMYK->RGB conversion.
631 */
632static inline bool needs_swizzler_to_convert_from_cmyk(J_COLOR_SPACE jpegColorType,
633 const skcms_ICCProfile* srcProfile,
634 bool hasColorSpaceXform) {
635 if (JCS_CMYK != jpegColorType) {
636 return false;
637 }
638
639 bool hasCMYKColorSpace = srcProfile && srcProfile->data_color_space == skcms_Signature_CMYK;
640 return !hasCMYKColorSpace || !hasColorSpaceXform;
641}
642
643/*
644 * Performs the jpeg decode
645 */
646SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
647 void* dst, size_t dstRowBytes,
648 const Options& options,
649 int* rowsDecoded) {
650 if (options.fSubset) {
651 // Subsets are not supported.
652 return kUnimplemented;
653 }
654
655 // Get a pointer to the decompress info since we will use it quite frequently
656 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
657
658 // Set the jump location for libjpeg errors
659 skjpeg_error_mgr::AutoPushJmpBuf jmp(fDecoderMgr->errorMgr());
660 if (setjmp(jmp)) {
661 return fDecoderMgr->returnFailure(caller: "setjmp", result: kInvalidInput);
662 }
663
664 if (!jpeg_start_decompress(cinfo: dinfo)) {
665 return fDecoderMgr->returnFailure(caller: "startDecompress", result: kInvalidInput);
666 }
667
668 // The recommended output buffer height should always be 1 in high quality modes.
669 // If it's not, we want to know because it means our strategy is not optimal.
670 SkASSERT(1 == dinfo->rec_outbuf_height);
671
672 if (needs_swizzler_to_convert_from_cmyk(jpegColorType: dinfo->out_color_space,
673 srcProfile: this->getEncodedInfo().profile(), hasColorSpaceXform: this->colorXform())) {
674 this->initializeSwizzler(dstInfo, options, needsCMYKToRGB: true);
675 }
676
677 if (!this->allocateStorage(dstInfo)) {
678 return kInternalError;
679 }
680
681 int rows = this->readRows(dstInfo, dst, rowBytes: dstRowBytes, count: dstInfo.height(), opts: options);
682 if (rows < dstInfo.height()) {
683 *rowsDecoded = rows;
684 return fDecoderMgr->returnFailure(caller: "Incomplete image data", result: kIncompleteInput);
685 }
686
687 return kSuccess;
688}
689
690bool SkJpegCodec::allocateStorage(const SkImageInfo& dstInfo) {
691 int dstWidth = dstInfo.width();
692
693 size_t swizzleBytes = 0;
694 if (fSwizzler) {
695 swizzleBytes = get_row_bytes(dinfo: fDecoderMgr->dinfo());
696 dstWidth = fSwizzler->swizzleWidth();
697 SkASSERT(!this->colorXform() || SkIsAlign4(swizzleBytes));
698 }
699
700 size_t xformBytes = 0;
701
702 if (this->colorXform() && sizeof(uint32_t) != dstInfo.bytesPerPixel()) {
703 xformBytes = dstWidth * sizeof(uint32_t);
704 }
705
706 size_t totalBytes = swizzleBytes + xformBytes;
707 if (totalBytes > 0) {
708 if (!fStorage.reset(count: totalBytes)) {
709 return false;
710 }
711 fSwizzleSrcRow = (swizzleBytes > 0) ? fStorage.get() : nullptr;
712 fColorXformSrcRow = (xformBytes > 0) ?
713 SkTAddOffset<uint32_t>(ptr: fStorage.get(), byteOffset: swizzleBytes) : nullptr;
714 }
715 return true;
716}
717
718void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options,
719 bool needsCMYKToRGB) {
720 Options swizzlerOptions = options;
721 if (options.fSubset) {
722 // Use fSwizzlerSubset if this is a subset decode. This is necessary in the case
723 // where libjpeg-turbo provides a subset and then we need to subset it further.
724 // Also, verify that fSwizzlerSubset is initialized and valid.
725 SkASSERT(!fSwizzlerSubset.isEmpty() && fSwizzlerSubset.x() <= options.fSubset->x() &&
726 fSwizzlerSubset.width() == options.fSubset->width());
727 swizzlerOptions.fSubset = &fSwizzlerSubset;
728 }
729
730 SkImageInfo swizzlerDstInfo = dstInfo;
731 if (this->colorXform()) {
732 // The color xform will be expecting RGBA 8888 input.
733 swizzlerDstInfo = swizzlerDstInfo.makeColorType(newColorType: kRGBA_8888_SkColorType);
734 }
735
736 if (needsCMYKToRGB) {
737 // The swizzler is used to convert to from CMYK.
738 // The swizzler does not use the width or height on SkEncodedInfo.
739 auto swizzlerInfo = SkEncodedInfo::Make(width: 0, height: 0, color: SkEncodedInfo::kInvertedCMYK_Color,
740 alpha: SkEncodedInfo::kOpaque_Alpha, bitsPerComponent: 8);
741 fSwizzler = SkSwizzler::Make(encodedInfo: swizzlerInfo, ctable: nullptr, dstInfo: swizzlerDstInfo, swizzlerOptions);
742 } else {
743 int srcBPP = 0;
744 switch (fDecoderMgr->dinfo()->out_color_space) {
745 case JCS_EXT_RGBA:
746 case JCS_EXT_BGRA:
747 case JCS_CMYK:
748 srcBPP = 4;
749 break;
750 case JCS_RGB565:
751 srcBPP = 2;
752 break;
753 case JCS_GRAYSCALE:
754 srcBPP = 1;
755 break;
756 default:
757 SkASSERT(false);
758 break;
759 }
760 fSwizzler = SkSwizzler::MakeSimple(srcBPP, dstInfo: swizzlerDstInfo, swizzlerOptions);
761 }
762 SkASSERT(fSwizzler);
763}
764
765SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) {
766 if (!createIfNecessary || fSwizzler) {
767 SkASSERT(!fSwizzler || (fSwizzleSrcRow && fStorage.get() == fSwizzleSrcRow));
768 return fSwizzler.get();
769 }
770
771 bool needsCMYKToRGB = needs_swizzler_to_convert_from_cmyk(
772 jpegColorType: fDecoderMgr->dinfo()->out_color_space, srcProfile: this->getEncodedInfo().profile(),
773 hasColorSpaceXform: this->colorXform());
774 this->initializeSwizzler(dstInfo: this->dstInfo(), options: this->options(), needsCMYKToRGB);
775 if (!this->allocateStorage(dstInfo: this->dstInfo())) {
776 return nullptr;
777 }
778 return fSwizzler.get();
779}
780
781SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
782 const Options& options) {
783 // Set the jump location for libjpeg errors
784 skjpeg_error_mgr::AutoPushJmpBuf jmp(fDecoderMgr->errorMgr());
785 if (setjmp(jmp)) {
786 SkCodecPrintf("setjmp: Error from libjpeg\n");
787 return kInvalidInput;
788 }
789
790 if (!jpeg_start_decompress(cinfo: fDecoderMgr->dinfo())) {
791 SkCodecPrintf("start decompress failed\n");
792 return kInvalidInput;
793 }
794
795 bool needsCMYKToRGB = needs_swizzler_to_convert_from_cmyk(
796 jpegColorType: fDecoderMgr->dinfo()->out_color_space, srcProfile: this->getEncodedInfo().profile(),
797 hasColorSpaceXform: this->colorXform());
798 if (options.fSubset) {
799 uint32_t startX = options.fSubset->x();
800 uint32_t width = options.fSubset->width();
801
802 // libjpeg-turbo may need to align startX to a multiple of the IDCT
803 // block size. If this is the case, it will decrease the value of
804 // startX to the appropriate alignment and also increase the value
805 // of width so that the right edge of the requested subset remains
806 // the same.
807 jpeg_crop_scanline(cinfo: fDecoderMgr->dinfo(), xoffset: &startX, width: &width);
808
809 SkASSERT(startX <= (uint32_t) options.fSubset->x());
810 SkASSERT(width >= (uint32_t) options.fSubset->width());
811 SkASSERT(startX + width >= (uint32_t) options.fSubset->right());
812
813 // Instruct the swizzler (if it is necessary) to further subset the
814 // output provided by libjpeg-turbo.
815 //
816 // We set this here (rather than in the if statement below), so that
817 // if (1) we don't need a swizzler for the subset, and (2) we need a
818 // swizzler for CMYK, the swizzler will still use the proper subset
819 // dimensions.
820 //
821 // Note that the swizzler will ignore the y and height parameters of
822 // the subset. Since the scanline decoder (and the swizzler) handle
823 // one row at a time, only the subsetting in the x-dimension matters.
824 fSwizzlerSubset.setXYWH(x: options.fSubset->x() - startX, y: 0,
825 width: options.fSubset->width(), height: options.fSubset->height());
826
827 // We will need a swizzler if libjpeg-turbo cannot provide the exact
828 // subset that we request.
829 if (startX != (uint32_t) options.fSubset->x() ||
830 width != (uint32_t) options.fSubset->width()) {
831 this->initializeSwizzler(dstInfo, options, needsCMYKToRGB);
832 }
833 }
834
835 // Make sure we have a swizzler if we are converting from CMYK.
836 if (!fSwizzler && needsCMYKToRGB) {
837 this->initializeSwizzler(dstInfo, options, needsCMYKToRGB: true);
838 }
839
840 if (!this->allocateStorage(dstInfo)) {
841 return kInternalError;
842 }
843
844 return kSuccess;
845}
846
847int SkJpegCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
848 int rows = this->readRows(dstInfo: this->dstInfo(), dst, rowBytes: dstRowBytes, count, opts: this->options());
849 if (rows < count) {
850 // This allows us to skip calling jpeg_finish_decompress().
851 fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height();
852 }
853
854 return rows;
855}
856
857bool SkJpegCodec::onSkipScanlines(int count) {
858 // Set the jump location for libjpeg errors
859 skjpeg_error_mgr::AutoPushJmpBuf jmp(fDecoderMgr->errorMgr());
860 if (setjmp(jmp)) {
861 return fDecoderMgr->returnFalse(caller: "onSkipScanlines");
862 }
863
864 return (uint32_t) count == jpeg_skip_scanlines(cinfo: fDecoderMgr->dinfo(), num_lines: count);
865}
866
867static bool is_yuv_supported(const jpeg_decompress_struct* dinfo,
868 const SkJpegCodec& codec,
869 const SkYUVAPixmapInfo::SupportedDataTypes* supportedDataTypes,
870 SkYUVAPixmapInfo* yuvaPixmapInfo) {
871 // Scaling is not supported in raw data mode.
872 SkASSERT(dinfo->scale_num == dinfo->scale_denom);
873
874 // I can't imagine that this would ever change, but we do depend on it.
875 static_assert(8 == DCTSIZE, "DCTSIZE (defined in jpeg library) should always be 8.");
876
877 if (JCS_YCbCr != dinfo->jpeg_color_space) {
878 return false;
879 }
880
881 SkASSERT(3 == dinfo->num_components);
882 SkASSERT(dinfo->comp_info);
883
884 // It is possible to perform a YUV decode for any combination of
885 // horizontal and vertical sampling that is supported by
886 // libjpeg/libjpeg-turbo. However, we will start by supporting only the
887 // common cases (where U and V have samp_factors of one).
888 //
889 // The definition of samp_factor is kind of the opposite of what SkCodec
890 // thinks of as a sampling factor. samp_factor is essentially a
891 // multiplier, and the larger the samp_factor is, the more samples that
892 // there will be. Ex:
893 // U_plane_width = image_width * (U_h_samp_factor / max_h_samp_factor)
894 //
895 // Supporting cases where the samp_factors for U or V were larger than
896 // that of Y would be an extremely difficult change, given that clients
897 // allocate memory as if the size of the Y plane is always the size of the
898 // image. However, this case is very, very rare.
899 if ((1 != dinfo->comp_info[1].h_samp_factor) ||
900 (1 != dinfo->comp_info[1].v_samp_factor) ||
901 (1 != dinfo->comp_info[2].h_samp_factor) ||
902 (1 != dinfo->comp_info[2].v_samp_factor))
903 {
904 return false;
905 }
906
907 // Support all common cases of Y samp_factors.
908 // TODO (msarett): As mentioned above, it would be possible to support
909 // more combinations of samp_factors. The issues are:
910 // (1) Are there actually any images that are not covered
911 // by these cases?
912 // (2) How much complexity would be added to the
913 // implementation in order to support these rare
914 // cases?
915 int hSampY = dinfo->comp_info[0].h_samp_factor;
916 int vSampY = dinfo->comp_info[0].v_samp_factor;
917 SkASSERT(hSampY == dinfo->max_h_samp_factor);
918 SkASSERT(vSampY == dinfo->max_v_samp_factor);
919
920 SkYUVAInfo::Subsampling tempSubsampling;
921 if (1 == hSampY && 1 == vSampY) {
922 tempSubsampling = SkYUVAInfo::Subsampling::k444;
923 } else if (2 == hSampY && 1 == vSampY) {
924 tempSubsampling = SkYUVAInfo::Subsampling::k422;
925 } else if (2 == hSampY && 2 == vSampY) {
926 tempSubsampling = SkYUVAInfo::Subsampling::k420;
927 } else if (1 == hSampY && 2 == vSampY) {
928 tempSubsampling = SkYUVAInfo::Subsampling::k440;
929 } else if (4 == hSampY && 1 == vSampY) {
930 tempSubsampling = SkYUVAInfo::Subsampling::k411;
931 } else if (4 == hSampY && 2 == vSampY) {
932 tempSubsampling = SkYUVAInfo::Subsampling::k410;
933 } else {
934 return false;
935 }
936 if (supportedDataTypes &&
937 !supportedDataTypes->supported(config: SkYUVAInfo::PlaneConfig::kY_U_V,
938 type: SkYUVAPixmapInfo::DataType::kUnorm8)) {
939 return false;
940 }
941 if (yuvaPixmapInfo) {
942 SkColorType colorTypes[SkYUVAPixmapInfo::kMaxPlanes];
943 size_t rowBytes[SkYUVAPixmapInfo::kMaxPlanes];
944 for (int i = 0; i < 3; ++i) {
945 colorTypes[i] = kAlpha_8_SkColorType;
946 rowBytes[i] = dinfo->comp_info[i].width_in_blocks * DCTSIZE;
947 }
948 SkYUVAInfo yuvaInfo(codec.dimensions(),
949 SkYUVAInfo::PlaneConfig::kY_U_V,
950 tempSubsampling,
951 kJPEG_Full_SkYUVColorSpace,
952 codec.getOrigin(),
953 SkYUVAInfo::Siting::kCentered,
954 SkYUVAInfo::Siting::kCentered);
955 *yuvaPixmapInfo = SkYUVAPixmapInfo(yuvaInfo, colorTypes, rowBytes);
956 }
957 return true;
958}
959
960bool SkJpegCodec::onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes& supportedDataTypes,
961 SkYUVAPixmapInfo* yuvaPixmapInfo) const {
962 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
963 return is_yuv_supported(dinfo, codec: *this, supportedDataTypes: &supportedDataTypes, yuvaPixmapInfo);
964}
965
966SkCodec::Result SkJpegCodec::onGetYUVAPlanes(const SkYUVAPixmaps& yuvaPixmaps) {
967 // Get a pointer to the decompress info since we will use it quite frequently
968 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
969 if (!is_yuv_supported(dinfo, codec: *this, supportedDataTypes: nullptr, yuvaPixmapInfo: nullptr)) {
970 return fDecoderMgr->returnFailure(caller: "onGetYUVAPlanes", result: kInvalidInput);
971 }
972 // Set the jump location for libjpeg errors
973 skjpeg_error_mgr::AutoPushJmpBuf jmp(fDecoderMgr->errorMgr());
974 if (setjmp(jmp)) {
975 return fDecoderMgr->returnFailure(caller: "setjmp", result: kInvalidInput);
976 }
977
978 dinfo->raw_data_out = TRUE;
979 if (!jpeg_start_decompress(cinfo: dinfo)) {
980 return fDecoderMgr->returnFailure(caller: "startDecompress", result: kInvalidInput);
981 }
982
983 const std::array<SkPixmap, SkYUVAPixmaps::kMaxPlanes>& planes = yuvaPixmaps.planes();
984
985#ifdef SK_DEBUG
986 {
987 // A previous implementation claims that the return value of is_yuv_supported()
988 // may change after calling jpeg_start_decompress(). It looks to me like this
989 // was caused by a bug in the old code, but we'll be safe and check here.
990 // Also check that pixmap properties agree with expectations.
991 SkYUVAPixmapInfo info;
992 SkASSERT(is_yuv_supported(dinfo, *this, nullptr, &info));
993 SkASSERT(info.yuvaInfo() == yuvaPixmaps.yuvaInfo());
994 for (int i = 0; i < info.numPlanes(); ++i) {
995 SkASSERT(planes[i].colorType() == kAlpha_8_SkColorType);
996 SkASSERT(info.planeInfo(i) == planes[i].info());
997 }
998 }
999#endif
1000
1001 // Build a JSAMPIMAGE to handle output from libjpeg-turbo. A JSAMPIMAGE has
1002 // a 2-D array of pixels for each of the components (Y, U, V) in the image.
1003 // Cheat Sheet:
1004 // JSAMPIMAGE == JSAMPLEARRAY* == JSAMPROW** == JSAMPLE***
1005 JSAMPARRAY yuv[3];
1006
1007 // Set aside enough space for pointers to rows of Y, U, and V.
1008 JSAMPROW rowptrs[2 * DCTSIZE + DCTSIZE + DCTSIZE];
1009 yuv[0] = &rowptrs[0]; // Y rows (DCTSIZE or 2 * DCTSIZE)
1010 yuv[1] = &rowptrs[2 * DCTSIZE]; // U rows (DCTSIZE)
1011 yuv[2] = &rowptrs[3 * DCTSIZE]; // V rows (DCTSIZE)
1012
1013 // Initialize rowptrs.
1014 int numYRowsPerBlock = DCTSIZE * dinfo->comp_info[0].v_samp_factor;
1015 static_assert(sizeof(JSAMPLE) == 1);
1016 for (int i = 0; i < numYRowsPerBlock; i++) {
1017 rowptrs[i] = static_cast<JSAMPLE*>(planes[0].writable_addr()) + i* planes[0].rowBytes();
1018 }
1019 for (int i = 0; i < DCTSIZE; i++) {
1020 rowptrs[i + 2 * DCTSIZE] =
1021 static_cast<JSAMPLE*>(planes[1].writable_addr()) + i* planes[1].rowBytes();
1022 rowptrs[i + 3 * DCTSIZE] =
1023 static_cast<JSAMPLE*>(planes[2].writable_addr()) + i* planes[2].rowBytes();
1024 }
1025
1026 // After each loop iteration, we will increment pointers to Y, U, and V.
1027 size_t blockIncrementY = numYRowsPerBlock * planes[0].rowBytes();
1028 size_t blockIncrementU = DCTSIZE * planes[1].rowBytes();
1029 size_t blockIncrementV = DCTSIZE * planes[2].rowBytes();
1030
1031 uint32_t numRowsPerBlock = numYRowsPerBlock;
1032
1033 // We intentionally round down here, as this first loop will only handle
1034 // full block rows. As a special case at the end, we will handle any
1035 // remaining rows that do not make up a full block.
1036 const int numIters = dinfo->output_height / numRowsPerBlock;
1037 for (int i = 0; i < numIters; i++) {
1038 JDIMENSION linesRead = jpeg_read_raw_data(cinfo: dinfo, data: yuv, max_lines: numRowsPerBlock);
1039 if (linesRead < numRowsPerBlock) {
1040 // FIXME: Handle incomplete YUV decodes without signalling an error.
1041 return kInvalidInput;
1042 }
1043
1044 // Update rowptrs.
1045 for (int j = 0; j < numYRowsPerBlock; j++) {
1046 rowptrs[j] += blockIncrementY;
1047 }
1048 for (int j = 0; j < DCTSIZE; j++) {
1049 rowptrs[j + 2 * DCTSIZE] += blockIncrementU;
1050 rowptrs[j + 3 * DCTSIZE] += blockIncrementV;
1051 }
1052 }
1053
1054 uint32_t remainingRows = dinfo->output_height - dinfo->output_scanline;
1055 SkASSERT(remainingRows == dinfo->output_height % numRowsPerBlock);
1056 SkASSERT(dinfo->output_scanline == numIters * numRowsPerBlock);
1057 if (remainingRows > 0) {
1058 // libjpeg-turbo needs memory to be padded by the block sizes. We will fulfill
1059 // this requirement using an extra row buffer.
1060 // FIXME: Should SkCodec have an extra memory buffer that can be shared among
1061 // all of the implementations that use temporary/garbage memory?
1062 AutoTMalloc<JSAMPLE> extraRow(planes[0].rowBytes());
1063 for (int i = remainingRows; i < numYRowsPerBlock; i++) {
1064 rowptrs[i] = extraRow.get();
1065 }
1066 int remainingUVRows = dinfo->comp_info[1].downsampled_height - DCTSIZE * numIters;
1067 for (int i = remainingUVRows; i < DCTSIZE; i++) {
1068 rowptrs[i + 2 * DCTSIZE] = extraRow.get();
1069 rowptrs[i + 3 * DCTSIZE] = extraRow.get();
1070 }
1071
1072 JDIMENSION linesRead = jpeg_read_raw_data(cinfo: dinfo, data: yuv, max_lines: numRowsPerBlock);
1073 if (linesRead < remainingRows) {
1074 // FIXME: Handle incomplete YUV decodes without signalling an error.
1075 return kInvalidInput;
1076 }
1077 }
1078
1079 return kSuccess;
1080}
1081
1082#ifdef SK_CODEC_DECODES_JPEG_GAINMAPS
1083// Collect and parse the primary and extended XMP metadata.
1084static std::unique_ptr<SkXmp> get_xmp_metadata(const SkJpegMarkerList& markerList) {
1085 std::vector<sk_sp<SkData>> decoderApp1Params;
1086 for (const auto& marker : markerList) {
1087 if (marker.fMarker == kXMPMarker) {
1088 decoderApp1Params.push_back(marker.fData);
1089 }
1090 }
1091 return SkJpegMakeXmp(decoderApp1Params);
1092}
1093
1094// Extract the SkJpegMultiPictureParameters from this image (if they exist). If |sourceMgr| and
1095// |outMpParamsSegment| are non-nullptr, then also return the SkJpegSegment that the parameters came
1096// from (and return nullptr if one cannot be found).
1097static std::unique_ptr<SkJpegMultiPictureParameters> find_mp_params(
1098 const SkJpegMarkerList& markerList,
1099 SkJpegSourceMgr* sourceMgr,
1100 SkJpegSegment* outMpParamsSegment) {
1101 std::unique_ptr<SkJpegMultiPictureParameters> mpParams;
1102 size_t skippedSegmentCount = 0;
1103
1104 // Search though the libjpeg segments until we find a segment that parses as MP parameters. Keep
1105 // track of how many segments with the MPF marker we skipped over to get there.
1106 for (const auto& marker : markerList) {
1107 if (marker.fMarker != kMpfMarker) {
1108 continue;
1109 }
1110 mpParams = SkJpegMultiPictureParameters::Make(marker.fData);
1111 if (mpParams) {
1112 break;
1113 }
1114 ++skippedSegmentCount;
1115 }
1116 if (!mpParams) {
1117 return nullptr;
1118 }
1119
1120 // If |sourceMgr| is not specified, then do not try to find the SkJpegSegment.
1121 if (!sourceMgr) {
1122 SkASSERT(!outMpParamsSegment);
1123 return mpParams;
1124 }
1125
1126 // Now, find the SkJpegSegmentScanner segment that corresponds to the libjpeg marker.
1127 // TODO(ccameron): It may be preferable to make SkJpegSourceMgr save segments with certain
1128 // markers to avoid this strangeness.
1129 for (const auto& segment : sourceMgr->getAllSegments()) {
1130 if (segment.marker != kMpfMarker) {
1131 continue;
1132 }
1133 if (skippedSegmentCount == 0) {
1134 *outMpParamsSegment = segment;
1135 return mpParams;
1136 }
1137 skippedSegmentCount--;
1138 }
1139 return nullptr;
1140}
1141
1142// Attempt to extract a gainmap image from a specified offset and size within the decoder's stream.
1143// Returns true only if the extracted gainmap image includes XMP metadata that specifies HDR gainmap
1144// rendering parameters.
1145static bool extract_gainmap(SkJpegSourceMgr* decoderSource,
1146 size_t offset,
1147 size_t size,
1148 bool base_image_has_hdrgm,
1149 SkGainmapInfo* outInfo,
1150 std::unique_ptr<SkStream>* outGainmapImageStream) {
1151 // Extract the SkData for this image.
1152 bool imageDataWasCopied = false;
1153 auto imageData = decoderSource->getSubsetData(offset, size, &imageDataWasCopied);
1154 if (!imageData) {
1155 SkCodecPrintf("Failed to extract MP image.\n");
1156 return false;
1157 }
1158
1159 // Scan through the image up to the StartOfScan. We'll be searching for the XMP metadata.
1160 SkJpegSegmentScanner scan(kJpegMarkerStartOfScan);
1161 scan.onBytes(imageData->data(), imageData->size());
1162 if (scan.hadError() || !scan.isDone()) {
1163 SkCodecPrintf("Failed to scan header of MP image.\n");
1164 return false;
1165 }
1166
1167 // Collect the potential XMP segments and build the XMP.
1168 std::vector<sk_sp<SkData>> app1Params;
1169 for (const auto& segment : scan.getSegments()) {
1170 if (segment.marker != kXMPMarker) {
1171 continue;
1172 }
1173 auto parameters = SkJpegSegmentScanner::GetParameters(imageData.get(), segment);
1174 if (!parameters) {
1175 continue;
1176 }
1177 app1Params.push_back(std::move(parameters));
1178 }
1179 auto xmp = SkJpegMakeXmp(app1Params);
1180 if (!xmp) {
1181 return false;
1182 }
1183
1184 // Check if this image identifies itself as a gainmap.
1185 bool did_populate_info = false;
1186 SkGainmapInfo info;
1187
1188 // Check for HDRGM only if the base image specified hdrgm:Version="1.0".
1189 did_populate_info = base_image_has_hdrgm && xmp->getGainmapInfoHDRGM(&info);
1190
1191 // Next, check HDRGainMap. This does not require anything specific from the base image.
1192 if (!did_populate_info) {
1193 did_populate_info = xmp->getGainmapInfoHDRGainMap(&info);
1194 }
1195
1196 // If none of the formats identified itself as a gainmap and populated |info| then fail.
1197 if (!did_populate_info) {
1198 return false;
1199 }
1200
1201 // This image is a gainmap. Populate its stream.
1202 if (outGainmapImageStream) {
1203 if (imageDataWasCopied) {
1204 *outGainmapImageStream = SkMemoryStream::Make(imageData);
1205 } else {
1206 *outGainmapImageStream = SkMemoryStream::MakeCopy(imageData->data(), imageData->size());
1207 }
1208 }
1209 *outInfo = info;
1210 return true;
1211}
1212
1213static bool get_gainmap_info(const SkJpegMarkerList& markerList,
1214 SkJpegSourceMgr* sourceMgr,
1215 SkGainmapInfo* info,
1216 std::unique_ptr<SkStream>* gainmapImageStream) {
1217 // The GContainer and APP15-based HDRGM formats require XMP metadata. Extract it now.
1218 std::unique_ptr<SkXmp> xmp = get_xmp_metadata(markerList);
1219
1220 // Let |base_image_info| be the HDRGM gainmap information found in the base image (if any).
1221 SkGainmapInfo base_image_info;
1222
1223 // Set |base_image_has_hdrgm| to be true if the base image has HDRGM XMP metadata that includes
1224 // the a Version 1.0 attribute.
1225 const bool base_image_has_hdrgm = xmp && xmp->getGainmapInfoHDRGM(&base_image_info);
1226
1227 // Attempt to locate the gainmap from the container XMP.
1228 size_t containerGainmapOffset = 0;
1229 size_t containerGainmapSize = 0;
1230 if (xmp && xmp->getContainerGainmapLocation(&containerGainmapOffset, &containerGainmapSize)) {
1231 const auto& segments = sourceMgr->getAllSegments();
1232 if (!segments.empty()) {
1233 const auto& lastSegment = segments.back();
1234 if (lastSegment.marker == kJpegMarkerEndOfImage) {
1235 containerGainmapOffset += lastSegment.offset + kJpegMarkerCodeSize;
1236 }
1237 }
1238 }
1239
1240 // Attempt to find MultiPicture parameters.
1241 SkJpegSegment mpParamsSegment;
1242 auto mpParams = find_mp_params(markerList, sourceMgr, &mpParamsSegment);
1243
1244 // First, search through the Multi-Picture images.
1245 if (mpParams) {
1246 for (size_t mpImageIndex = 1; mpImageIndex < mpParams->images.size(); ++mpImageIndex) {
1247 size_t mpImageOffset = SkJpegMultiPictureParameters::GetAbsoluteOffset(
1248 mpParams->images[mpImageIndex].dataOffset, mpParamsSegment.offset);
1249 size_t mpImageSize = mpParams->images[mpImageIndex].size;
1250
1251 if (extract_gainmap(sourceMgr,
1252 mpImageOffset,
1253 mpImageSize,
1254 base_image_has_hdrgm,
1255 info,
1256 gainmapImageStream)) {
1257 // If the GContainer also suggested an offset and size, assert that we found the
1258 // image that the GContainer suggested.
1259 if (containerGainmapOffset) {
1260 SkASSERT(containerGainmapOffset == mpImageOffset);
1261 SkASSERT(containerGainmapSize == mpImageSize);
1262 }
1263 return true;
1264 }
1265 }
1266 }
1267
1268 // Next, try the location suggested by the container XMP.
1269 if (containerGainmapOffset) {
1270 if (extract_gainmap(sourceMgr,
1271 containerGainmapOffset,
1272 containerGainmapSize,
1273 base_image_has_hdrgm,
1274 info,
1275 gainmapImageStream)) {
1276 return true;
1277 }
1278 SkCodecPrintf("Failed to extract container-specified gainmap.\n");
1279 }
1280
1281 // Finally, attempt to extract SkGainmapInfo from the primary image's XMP and extract the
1282 // gainmap from APP15 segments.
1283 if (xmp && base_image_has_hdrgm) {
1284 auto gainmapData = read_metadata(markerList,
1285 kGainmapMarker,
1286 kGainmapSig,
1287 sizeof(kGainmapSig),
1288 /*signaturePadding=*/0,
1289 kGainmapMarkerIndexSize,
1290 /*alwaysCopyData=*/true);
1291 if (gainmapData) {
1292 *gainmapImageStream = SkMemoryStream::Make(std::move(gainmapData));
1293 if (*gainmapImageStream) {
1294 *info = base_image_info;
1295 return true;
1296 }
1297 } else {
1298 SkCodecPrintf("Parsed HDRGM metadata but did not find image\n");
1299 }
1300 }
1301 return false;
1302}
1303
1304bool SkJpegCodec::onGetGainmapInfo(SkGainmapInfo* info,
1305 std::unique_ptr<SkStream>* gainmapImageStream) {
1306 auto markerList = get_sk_marker_list(fDecoderMgr->dinfo());
1307 return get_gainmap_info(markerList, fDecoderMgr->getSourceMgr(), info, gainmapImageStream);
1308}
1309
1310#else
1311bool SkJpegCodec::onGetGainmapInfo(SkGainmapInfo* info,
1312 std::unique_ptr<SkStream>* gainmapImageStream) {
1313 return false;
1314}
1315#endif // SK_CODEC_DECODES_JPEG_GAINMAPS
1316
1317class SkJpegMetadataDecoderImpl : public SkJpegMetadataDecoder {
1318public:
1319 SkJpegMetadataDecoderImpl(SkJpegMarkerList markerList) : fMarkerList(std::move(markerList)) {}
1320
1321 sk_sp<SkData> getExifMetadata(bool copyData) const override {
1322 return read_metadata(markerList: fMarkerList,
1323 targetMarker: kExifMarker,
1324 signature: kExifSig,
1325 signatureSize: sizeof(kExifSig),
1326 /*signaturePadding=*/1,
1327 /*bytesInIndex=*/0,
1328 alwaysCopyData: copyData);
1329 }
1330
1331 sk_sp<SkData> getICCProfileData(bool copyData) const override {
1332 return read_metadata(markerList: fMarkerList,
1333 targetMarker: kICCMarker,
1334 signature: kICCSig,
1335 signatureSize: sizeof(kICCSig),
1336 /*signaturePadding=*/0,
1337 bytesInIndex: kICCMarkerIndexSize,
1338 alwaysCopyData: copyData);
1339 }
1340
1341 bool mightHaveGainmapImage() const override {
1342#ifdef SK_CODEC_DECODES_JPEG_GAINMAPS
1343 // All supported gainmap formats require MPF. Reject images that do not have MPF.
1344 return find_mp_params(fMarkerList, nullptr, nullptr) != nullptr;
1345#else
1346 return false;
1347#endif
1348 }
1349
1350 bool findGainmapImage(sk_sp<SkData> baseImageData,
1351 sk_sp<SkData>& outGainmapImageData,
1352 SkGainmapInfo& outGainmapInfo) override {
1353#ifdef SK_CODEC_DECODES_JPEG_GAINMAPS
1354 auto baseImageStream = SkMemoryStream::Make(baseImageData);
1355 auto sourceMgr = SkJpegSourceMgr::Make(baseImageStream.get());
1356 SkGainmapInfo gainmapInfo;
1357 std::unique_ptr<SkStream> gainmapImageStream;
1358 if (!get_gainmap_info(fMarkerList, sourceMgr.get(), &gainmapInfo, &gainmapImageStream)) {
1359 return false;
1360 }
1361
1362 // TODO(https://crbug.com/1404000): The function |get_gainmap_info| will always return an
1363 // SkStream that is backed by an SkData. Change it to return that SkData, to avoid this
1364 // re-extraction of the SkData.
1365 SkASSERT(gainmapImageStream->getMemoryBase());
1366 outGainmapImageData = SkData::MakeWithCopy(gainmapImageStream->getMemoryBase(),
1367 gainmapImageStream->getLength());
1368 outGainmapInfo = gainmapInfo;
1369 return true;
1370#else
1371 return false;
1372#endif
1373 }
1374
1375private:
1376 SkJpegMarkerList fMarkerList;
1377};
1378
1379std::unique_ptr<SkJpegMetadataDecoder> SkJpegMetadataDecoder::Make(std::vector<Segment> segments) {
1380 SkJpegMarkerList markerList;
1381 for (const auto& segment : segments) {
1382 markerList.emplace_back(args: segment.fMarker, args: segment.fData);
1383 }
1384 return std::make_unique<SkJpegMetadataDecoderImpl>(args: std::move(markerList));
1385}
1386
1387namespace SkJpegDecoder {
1388bool IsJpeg(const void* data, size_t len) {
1389 return SkJpegCodec::IsJpeg(buffer: data, bytesRead: len);
1390}
1391
1392std::unique_ptr<SkCodec> Decode(std::unique_ptr<SkStream> stream,
1393 SkCodec::Result* outResult,
1394 SkCodecs::DecodeContext) {
1395 SkCodec::Result resultStorage;
1396 if (!outResult) {
1397 outResult = &resultStorage;
1398 }
1399 return SkJpegCodec::MakeFromStream(stream: std::move(stream), result: outResult);
1400}
1401
1402std::unique_ptr<SkCodec> Decode(sk_sp<SkData> data,
1403 SkCodec::Result* outResult,
1404 SkCodecs::DecodeContext) {
1405 if (!data) {
1406 if (outResult) {
1407 *outResult = SkCodec::kInvalidInput;
1408 }
1409 return nullptr;
1410 }
1411 return Decode(stream: SkMemoryStream::Make(data: std::move(data)), outResult, nullptr);
1412}
1413
1414} // namespace SkJpegDecoder
1415
1416namespace SkJpegPriv {
1417
1418SkEncodedOrigin get_exif_orientation(jpeg_decompress_struct* dinfo) {
1419 auto metadataDecoder = SkJpegMetadataDecoder::Make(segments: get_sk_marker_list(dinfo));
1420 return get_exif_orientation(exifData: metadataDecoder->getExifMetadata(/*copyData=*/false));
1421}
1422
1423} // namespace SkJpegPriv
1424

source code of flutter_engine/third_party/skia/src/codec/SkJpegCodec.cpp