33#ifdef SK_CODEC_DECODES_JPEG_GAINMAPS
48#if defined(__GNUC__) && !defined(__clang__)
49 #pragma GCC diagnostic ignored "-Wclobbered"
63 markerList.emplace_back(
marker->marker,
81 std::unique_ptr<SkEncodedInfo::ICCProfile> defaultColorProfile) {
88 return decoderMgr->returnFailure(
"ReadHeader",
kInvalidInput);
93 auto* dinfo = decoderMgr->dinfo();
105 switch (jpeg_read_header(dinfo,
true)) {
111 return decoderMgr->returnFailure(
"ReadHeader",
kInvalidInput);
117 if (!decoderMgr->getEncodedColor(&
color)) {
121 auto metadataDecoder =
127 std::unique_ptr<SkEncodedInfo::ICCProfile>
profile;
128 if (
auto iccProfileData = metadataDecoder->getICCProfileData(
true)) {
133 switch (decoderMgr->dinfo()->jpeg_color_space) {
155 profile = std::move(defaultColorProfile);
163 std::unique_ptr<SkStream>(
stream),
164 decoderMgr.release(),
169 *decoderMgrOut = decoderMgr.release();
180 Result*
result, std::unique_ptr<SkEncodedInfo::ICCProfile> defaultColorProfile) {
187 *
result = ReadHeader(
stream.get(), &codec,
nullptr, std::move(defaultColorProfile));
192 return std::unique_ptr<SkCodec>(codec);
198 std::unique_ptr<SkStream>
stream,
202 , fDecoderMgr(decoderMgr)
203 , fReadyState(decoderMgr->dinfo()->global_state) {}
210 const size_t colorBytes = (dinfo->out_color_space == JCS_RGB565) ? 2 :
211 dinfo->out_color_components;
212 return dinfo->output_width * colorBytes;
223 dinfo->num_components = 0;
224 dinfo->scale_num = num;
225 dinfo->scale_denom = denom;
226 jpeg_calc_output_dimensions(dinfo);
236 unsigned int denom = 8;
237 if (desiredScale >= 0.9375) {
239 }
else if (desiredScale >= 0.8125) {
241 }
else if (desiredScale >= 0.6875f) {
243 }
else if (desiredScale >= 0.5625f) {
245 }
else if (desiredScale >= 0.4375f) {
247 }
else if (desiredScale >= 0.3125f) {
249 }
else if (desiredScale >= 0.1875f) {
256 jpeg_decompress_struct dinfo;
260 dinfo.global_state = fReadyState;
264 return SkISize::Make(dinfo.output_width, dinfo.output_height);
269 if (
kSuccess != ReadHeader(this->
stream(),
nullptr, &decoderMgr,
nullptr)) {
270 return fDecoderMgr->returnFalse(
"onRewind");
273 fDecoderMgr.reset(decoderMgr);
275 fSwizzler.reset(
nullptr);
276 fSwizzleSrcRow =
nullptr;
277 fColorXformSrcRow =
nullptr;
284 bool needsColorXform) {
292 SkCodecPrintf(
"Warning: an opaque image should be decoded as opaque "
293 "- it is being decoded as non-opaque, which will draw slower\n");
296 J_COLOR_SPACE encodedColorType = fDecoderMgr->dinfo()->jpeg_color_space;
301 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
304 if (needsColorXform) {
307 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
309 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA;
313 if (needsColorXform) {
314 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
316 fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE;
317 fDecoderMgr->dinfo()->out_color_space = JCS_RGB565;
321 if (JCS_GRAYSCALE != encodedColorType) {
325 if (needsColorXform) {
326 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
328 fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE;
335 fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
343 if (JCS_CMYK == encodedColorType || JCS_YCCK == encodedColorType) {
344 fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
357 return fDecoderMgr->returnFalse(
"onDimensionsSupported");
360 const unsigned int dstWidth =
size.width();
361 const unsigned int dstHeight =
size.height();
365 jpeg_decompress_struct dinfo;
369 dinfo.global_state = fReadyState;
372 unsigned int num = 8;
373 const unsigned int denom = 8;
375 while (dinfo.output_width != dstWidth || dinfo.output_height != dstHeight) {
378 if (1 == num || dstWidth > dinfo.output_width || dstHeight > dinfo.output_height) {
387 fDecoderMgr->dinfo()->scale_num = num;
388 fDecoderMgr->dinfo()->scale_denom = denom;
392int SkJpegCodec::readRows(
const SkImageInfo& dstInfo,
void*
dst,
size_t rowBytes,
int count,
393 const Options& opts) {
408 JSAMPLE* decodeDst = (JSAMPLE*)
dst;
409 uint32_t* swizzleDst = (uint32_t*)
dst;
410 size_t decodeDstRowBytes = rowBytes;
411 size_t swizzleDstRowBytes = rowBytes;
412 int dstWidth = opts.fSubset ? opts.fSubset->width() :
dstInfo.
width();
413 if (fSwizzleSrcRow && fColorXformSrcRow) {
414 decodeDst = (JSAMPLE*) fSwizzleSrcRow;
415 swizzleDst = fColorXformSrcRow;
416 decodeDstRowBytes = 0;
417 swizzleDstRowBytes = 0;
418 dstWidth = fSwizzler->swizzleWidth();
419 }
else if (fColorXformSrcRow) {
420 decodeDst = (JSAMPLE*) fColorXformSrcRow;
421 swizzleDst = fColorXformSrcRow;
422 decodeDstRowBytes = 0;
423 swizzleDstRowBytes = 0;
424 }
else if (fSwizzleSrcRow) {
425 decodeDst = (JSAMPLE*) fSwizzleSrcRow;
426 decodeDstRowBytes = 0;
427 dstWidth = fSwizzler->swizzleWidth();
431 uint32_t
lines = jpeg_read_scanlines(fDecoderMgr->dinfo(), &decodeDst, 1);
437 fSwizzler->swizzle(swizzleDst, decodeDst);
442 dst = SkTAddOffset<void>(
dst, rowBytes);
445 decodeDst = SkTAddOffset<JSAMPLE>(decodeDst, decodeDstRowBytes);
446 swizzleDst = SkTAddOffset<uint32_t>(swizzleDst, swizzleDstRowBytes);
460 bool hasColorSpaceXform) {
461 if (JCS_CMYK != jpegColorType) {
466 return !hasCMYKColorSpace || !hasColorSpaceXform;
473 void*
dst,
size_t dstRowBytes,
482 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
490 if (!jpeg_start_decompress(dinfo)) {
491 return fDecoderMgr->returnFailure(
"startDecompress",
kInvalidInput);
496 SkASSERT(1 == dinfo->rec_outbuf_height);
499 this->getEncodedInfo().profile(), this->colorXform())) {
503 if (!this->allocateStorage(
dstInfo)) {
510 return fDecoderMgr->returnFailure(
"Incomplete image data",
kIncompleteInput);
516bool SkJpegCodec::allocateStorage(
const SkImageInfo& dstInfo) {
519 size_t swizzleBytes = 0;
522 dstWidth = fSwizzler->swizzleWidth();
526 size_t xformBytes = 0;
529 xformBytes = dstWidth *
sizeof(uint32_t);
532 size_t totalBytes = swizzleBytes + xformBytes;
533 if (totalBytes > 0) {
534 if (!fStorage.
reset(totalBytes)) {
537 fSwizzleSrcRow = (swizzleBytes > 0) ? fStorage.
get() :
nullptr;
538 fColorXformSrcRow = (xformBytes > 0) ?
539 SkTAddOffset<uint32_t>(fStorage.
get(), swizzleBytes) :
nullptr;
544void SkJpegCodec::initializeSwizzler(
const SkImageInfo& dstInfo,
const Options&
options,
545 bool needsCMYKToRGB) {
546 Options swizzlerOptions =
options;
553 swizzlerOptions.fSubset = &fSwizzlerSubset;
562 if (needsCMYKToRGB) {
567 fSwizzler =
SkSwizzler::Make(swizzlerInfo,
nullptr, swizzlerDstInfo, swizzlerOptions);
570 switch (fDecoderMgr->dinfo()->out_color_space) {
591SkSampler* SkJpegCodec::getSampler(
bool createIfNecessary) {
592 if (!createIfNecessary || fSwizzler) {
593 SkASSERT(!fSwizzler || (fSwizzleSrcRow && fStorage.
get() == fSwizzleSrcRow));
594 return fSwizzler.get();
598 fDecoderMgr->dinfo()->out_color_space, this->getEncodedInfo().profile(),
600 this->initializeSwizzler(this->
dstInfo(), this->
options(), needsCMYKToRGB);
601 if (!this->allocateStorage(this->
dstInfo())) {
604 return fSwizzler.get();
616 if (!jpeg_start_decompress(fDecoderMgr->dinfo())) {
622 fDecoderMgr->dinfo()->out_color_space, this->getEncodedInfo().profile(),
633 jpeg_crop_scanline(fDecoderMgr->dinfo(), &startX, &
width);
662 if (!fSwizzler && needsCMYKToRGB) {
666 if (!this->allocateStorage(
dstInfo)) {
673int SkJpegCodec::onGetScanlines(
void*
dst,
int count,
size_t dstRowBytes) {
677 fDecoderMgr->dinfo()->output_scanline = this->
dstInfo().
height();
683bool SkJpegCodec::onSkipScanlines(
int count) {
687 return fDecoderMgr->returnFalse(
"onSkipScanlines");
690 return (uint32_t)
count == jpeg_skip_scanlines(fDecoderMgr->dinfo(),
count);
698 SkASSERT(dinfo->scale_num == dinfo->scale_denom);
701 static_assert(8 == DCTSIZE,
"DCTSIZE (defined in jpeg library) should always be 8.");
703 if (JCS_YCbCr != dinfo->jpeg_color_space) {
707 SkASSERT(3 == dinfo->num_components);
725 if ((1 != dinfo->comp_info[1].h_samp_factor) ||
726 (1 != dinfo->comp_info[1].v_samp_factor) ||
727 (1 != dinfo->comp_info[2].h_samp_factor) ||
728 (1 != dinfo->comp_info[2].v_samp_factor))
741 int hSampY = dinfo->comp_info[0].h_samp_factor;
742 int vSampY = dinfo->comp_info[0].v_samp_factor;
743 SkASSERT(hSampY == dinfo->max_h_samp_factor);
744 SkASSERT(vSampY == dinfo->max_v_samp_factor);
747 if (1 == hSampY && 1 == vSampY) {
749 }
else if (2 == hSampY && 1 == vSampY) {
751 }
else if (2 == hSampY && 2 == vSampY) {
753 }
else if (1 == hSampY && 2 == vSampY) {
755 }
else if (4 == hSampY && 1 == vSampY) {
757 }
else if (4 == hSampY && 2 == vSampY) {
762 if (supportedDataTypes &&
767 if (yuvaPixmapInfo) {
770 for (
int i = 0;
i < 3; ++
i) {
772 rowBytes[
i] = dinfo->comp_info[
i].width_in_blocks * DCTSIZE;
788 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
794 jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo();
796 return fDecoderMgr->returnFailure(
"onGetYUVAPlanes",
kInvalidInput);
804 dinfo->raw_data_out =
TRUE;
805 if (!jpeg_start_decompress(dinfo)) {
806 return fDecoderMgr->returnFailure(
"startDecompress",
kInvalidInput);
809 const std::array<SkPixmap, SkYUVAPixmaps::kMaxPlanes>& planes = yuvaPixmaps.
planes();
820 for (
int i = 0;
i <
info.numPlanes(); ++
i) {
834 JSAMPROW rowptrs[2 * DCTSIZE + DCTSIZE + DCTSIZE];
835 yuv[0] = &rowptrs[0];
836 yuv[1] = &rowptrs[2 * DCTSIZE];
837 yuv[2] = &rowptrs[3 * DCTSIZE];
840 int numYRowsPerBlock = DCTSIZE * dinfo->comp_info[0].v_samp_factor;
841 static_assert(
sizeof(JSAMPLE) == 1);
842 for (
int i = 0;
i < numYRowsPerBlock;
i++) {
843 rowptrs[
i] =
static_cast<JSAMPLE*
>(planes[0].writable_addr()) +
i* planes[0].rowBytes();
845 for (
int i = 0;
i < DCTSIZE;
i++) {
846 rowptrs[
i + 2 * DCTSIZE] =
847 static_cast<JSAMPLE*
>(planes[1].writable_addr()) +
i* planes[1].rowBytes();
848 rowptrs[
i + 3 * DCTSIZE] =
849 static_cast<JSAMPLE*
>(planes[2].writable_addr()) +
i* planes[2].rowBytes();
853 size_t blockIncrementY = numYRowsPerBlock * planes[0].rowBytes();
854 size_t blockIncrementU = DCTSIZE * planes[1].rowBytes();
855 size_t blockIncrementV = DCTSIZE * planes[2].rowBytes();
857 uint32_t numRowsPerBlock = numYRowsPerBlock;
862 const int numIters = dinfo->output_height / numRowsPerBlock;
863 for (
int i = 0;
i < numIters;
i++) {
864 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock);
865 if (linesRead < numRowsPerBlock) {
871 for (
int j = 0; j < numYRowsPerBlock; j++) {
872 rowptrs[j] += blockIncrementY;
874 for (
int j = 0; j < DCTSIZE; j++) {
875 rowptrs[j + 2 * DCTSIZE] += blockIncrementU;
876 rowptrs[j + 3 * DCTSIZE] += blockIncrementV;
880 uint32_t remainingRows = dinfo->output_height - dinfo->output_scanline;
881 SkASSERT(remainingRows == dinfo->output_height % numRowsPerBlock);
882 SkASSERT(dinfo->output_scanline == numIters * numRowsPerBlock);
883 if (remainingRows > 0) {
889 for (
int i = remainingRows;
i < numYRowsPerBlock;
i++) {
890 rowptrs[
i] = extraRow.
get();
892 int remainingUVRows = dinfo->comp_info[1].downsampled_height - DCTSIZE * numIters;
893 for (
int i = remainingUVRows;
i < DCTSIZE;
i++) {
894 rowptrs[
i + 2 * DCTSIZE] = extraRow.
get();
895 rowptrs[
i + 3 * DCTSIZE] = extraRow.
get();
898 JDIMENSION linesRead = jpeg_read_raw_data(dinfo, yuv, numRowsPerBlock);
899 if (linesRead < remainingRows) {
909 std::unique_ptr<SkStream>* gainmapImageStream) {
910#ifdef SK_CODEC_DECODES_JPEG_GAINMAPS
914 auto metadataDecoder =
915 std::make_unique<SkJpegMetadataDecoderImpl>(
get_sk_marker_list(fDecoderMgr->dinfo()));
916 if (!metadataDecoder->findGainmapImage(
917 fDecoderMgr->getSourceMgr(), gainmap_data, gainmap_info)) {
921 *
info = gainmap_info;
939 outResult = &resultStorage;
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
sk_bzero(glyphs, sizeof(glyphs))
static const char marker[]
static constexpr bool SkIsAlign4(T x)
@ kUnknown_SkAlphaType
uninitialized
@ kOpaque_SkAlphaType
pixel is opaque
#define SkCodecPrintf(...)
@ kBGRA_8888_SkColorType
pixel with 8 bits for blue, green, red, alpha; in 32-bit word
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
@ kAlpha_8_SkColorType
pixel with alpha in 8-bit byte
@ kGray_8_SkColorType
pixel with grayscale level in 8-bit byte
@ kRGB_565_SkColorType
pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
@ kBGRA_10101010_XR_SkColorType
pixel with 10 bits each for blue, green, red, alpha; in 64-bit word, extended range
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
@ kBGR_101010x_XR_SkColorType
pixel with 10 bits each for blue, green, red; in 32-bit word, extended range
@ kDefault_SkEncodedOrigin
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
@ kJPEG_Full_SkYUVColorSpace
describes full range
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)
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 uint32_t kMpfMarker
static constexpr uint32_t kICCMarker
static constexpr uint8_t kJpegSig[]
bool SkParseEncodedOrigin(const void *data, size_t data_length, SkEncodedOrigin *orientation)
#define INHERITED(method,...)
SkISize dimensions() const
const SkImageInfo & dstInfo() const
void applyColorXform(void *dst, const void *src, int count) const
SkEncodedOrigin getOrigin() const
const Options & options() const
static sk_sp< SkData > MakeWithoutCopy(const void *data, size_t length)
const uint8_t * bytes() const
static std::unique_ptr< ICCProfile > Make(sk_sp< SkData >)
bool onQueryYUVAInfo(const SkYUVAPixmapInfo::SupportedDataTypes &, SkYUVAPixmapInfo *) const override
static bool IsJpeg(const void *, size_t)
Result onGetYUVAPlanes(const SkYUVAPixmaps &yuvaPixmaps) override
Result onGetPixels(const SkImageInfo &dstInfo, void *dst, size_t dstRowBytes, const Options &, int *) override
bool onDimensionsSupported(const SkISize &) override
SkISize onGetScaledDimensions(float desiredScale) const override
bool conversionSupported(const SkImageInfo &, bool, bool) override
bool onGetGainmapInfo(SkGainmapInfo *info, std::unique_ptr< SkStream > *gainmapImageStream) override
static std::unique_ptr< SkCodec > MakeFromStream(std::unique_ptr< SkStream >, Result *)
static std::unique_ptr< SkMemoryStream > Make(sk_sp< SkData > data)
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)
SK_API bool IsJpeg(const void *, size_t)
SK_API std::unique_ptr< SkCodec > Decode(std::unique_ptr< SkStream >, SkCodec::Result *, SkCodecs::DecodeContext=nullptr)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
@ skcms_PixelFormat_RGBA_8888
static SkEncodedInfo Make(int width, int height, Color color, Alpha alpha, int bitsPerComponent)
constexpr int32_t x() const
constexpr int32_t height() const
constexpr int32_t right() const
constexpr int32_t width() const
void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height)
static constexpr SkISize Make(int32_t w, int32_t h)
constexpr int32_t width() const
constexpr int32_t height() const
int bytesPerPixel() const
SkAlphaType alphaType() const
SkColorType colorType() const
SkImageInfo makeColorType(SkColorType newColorType) const
uint32_t data_color_space
std::shared_ptr< const fml::Mapping > data