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