64 jpeg_compress_struct*
cinfo() {
return &fCInfo; }
74 fCInfo.err = jpeg_std_error(&fErrMgr);
76 jpeg_create_compress(&fCInfo);
77 fCInfo.dest = &fDstMgr;
81 jpeg_compress_struct fCInfo;
90 auto chooseProc8888 = [&]() {
98 J_COLOR_SPACE jpegColorType = JCS_EXT_RGBA;
99 int numComponents = 0;
102 fProc = chooseProc8888();
103 jpegColorType = JCS_EXT_RGBA;
107 fProc = chooseProc8888();
108 jpegColorType = JCS_EXT_BGRA;
113 jpegColorType = JCS_RGB;
122 jpegColorType = JCS_RGB;
128 jpegColorType = JCS_GRAYSCALE;
138 jpegColorType = JCS_EXT_RGBA;
145 fCInfo.image_width = srcInfo.
width();
146 fCInfo.image_height = srcInfo.
height();
147 fCInfo.in_color_space = jpegColorType;
148 fCInfo.input_components = numComponents;
149 jpeg_set_defaults(&fCInfo);
151 if (numComponents != 1) {
154 SkASSERT(2 == fCInfo.comp_info[0].h_samp_factor);
155 SkASSERT(2 == fCInfo.comp_info[0].v_samp_factor);
156 SkASSERT(1 == fCInfo.comp_info[1].h_samp_factor);
157 SkASSERT(1 == fCInfo.comp_info[1].v_samp_factor);
158 SkASSERT(1 == fCInfo.comp_info[2].h_samp_factor);
159 SkASSERT(1 == fCInfo.comp_info[2].v_samp_factor);
162 fCInfo.comp_info[0].h_samp_factor = 2;
163 fCInfo.comp_info[0].v_samp_factor = 1;
164 SkASSERT(1 == fCInfo.comp_info[1].h_samp_factor);
165 SkASSERT(1 == fCInfo.comp_info[1].v_samp_factor);
166 SkASSERT(1 == fCInfo.comp_info[2].h_samp_factor);
167 SkASSERT(1 == fCInfo.comp_info[2].v_samp_factor);
170 fCInfo.comp_info[0].h_samp_factor = 1;
171 fCInfo.comp_info[0].v_samp_factor = 1;
172 SkASSERT(1 == fCInfo.comp_info[1].h_samp_factor);
173 SkASSERT(1 == fCInfo.comp_info[1].v_samp_factor);
174 SkASSERT(1 == fCInfo.comp_info[2].h_samp_factor);
175 SkASSERT(1 == fCInfo.comp_info[2].v_samp_factor);
180 initializeCommon(
options, metadataSegments);
188 switch (
src.yuvaInfo().planeConfig()) {
190 auto [ssWidthU, ssHeightU] =
src.yuvaInfo().planeSubsamplingFactors(1);
191 auto [ssWidthV, ssHeightV] =
src.yuvaInfo().planeSubsamplingFactors(2);
192 const uint8_t* srcY =
reinterpret_cast<const uint8_t*
>(
src.plane(0).addr(0, row));
193 const uint8_t* srcU =
194 reinterpret_cast<const uint8_t*
>(
src.plane(1).addr(0, row / ssHeightU));
195 const uint8_t* srcV =
196 reinterpret_cast<const uint8_t*
>(
src.plane(2).addr(0, row / ssHeightV));
197 for (
int col = 0; col <
width; ++col) {
198 dst[3 * col + 0] = srcY[col];
199 dst[3 * col + 1] = srcU[col / ssWidthU];
200 dst[3 * col + 2] = srcV[col / ssWidthV];
205 auto [ssWidthUV, ssHeightUV] =
src.yuvaInfo().planeSubsamplingFactors(1);
206 const uint8_t* srcY =
reinterpret_cast<const uint8_t*
>(
src.plane(0).addr(0, row));
207 const uint8_t* srcUV =
208 reinterpret_cast<const uint8_t*
>(
src.plane(1).addr(0, row / ssHeightUV));
209 for (
int col = 0; col <
width; ++col) {
210 dst[3 * col + 0] = srcY[col];
211 dst[3 * col + 1] = srcUV[2 * (col / ssWidthUV) + 0];
212 dst[3 * col + 2] = srcUV[2 * (col / ssWidthUV) + 1];
226 fCInfo.in_color_space = JCS_YCbCr;
227 fCInfo.input_components = 3;
228 jpeg_set_defaults(&fCInfo);
256 fCInfo.comp_info[0].h_samp_factor = ssHoriz;
257 fCInfo.comp_info[0].v_samp_factor = ssVert;
259 initializeCommon(
options, metadataSegments);
263void SkJpegEncoderMgr::initializeCommon(
269 fCInfo.optimize_coding =
TRUE;
272 jpeg_start_compress(&fCInfo,
TRUE);
274 for (
const auto& segment : metadataSegments) {
275 jpeg_write_marker(&fCInfo,
277 segment.fParameters->bytes(),
278 segment.fParameters->size());
300 return std::unique_ptr<SkJpegEncoderImpl>(
318 if (!encoderMgr->initializeRGB(
src.info(),
options, metadataSegments)) {
324SkJpegEncoderImpl::SkJpegEncoderImpl(std::unique_ptr<SkJpegEncoderMgr> encoderMgr,
327 encoderMgr->proc() ? encoderMgr->cinfo()->input_components *
src.
width() : 0)
328 , fEncoderMgr(
std::move(encoderMgr)) {}
330SkJpegEncoderImpl::SkJpegEncoderImpl(std::unique_ptr<SkJpegEncoderMgr> encoderMgr,
333 , fEncoderMgr(
std::move(encoderMgr))
346 for (
int i = 0;
i < numRows;
i++) {
349 jpeg_write_scanlines(fEncoderMgr->cinfo(), &jpegSrcRow, 1);
353 const size_t jpegSrcBytes = fEncoderMgr->cinfo()->input_components *
fSrc.
width();
355 for (
int i = 0;
i < numRows;
i++) {
356 JSAMPLE* jpegSrcRow = (JSAMPLE*)(
const_cast<void*
>(srcRow));
357 if (fEncoderMgr->proc()) {
362 fEncoderMgr->cinfo()->input_components);
365 SkTAddOffset<const void>(jpegSrcRow, jpegSrcBytes));
370 SkTAddOffset<const void>(jpegSrcRow, jpegSrcBytes));
373 jpeg_write_scanlines(fEncoderMgr->cinfo(), &jpegSrcRow, 1);
374 srcRow = SkTAddOffset<const void>(srcRow,
fSrc.
rowBytes());
380 jpeg_finish_compress(fEncoderMgr->cinfo());
406 if (!
as_IB(img)->getROPixels(ctx, &bm)) {
411 return stream.detachAsData();
453 segmentList.emplace_back(
kICCMarker,
s.detachAsData());
464 s.write(xmpMetadata->
data(), xmpMetadata->
size());
465 segmentList.emplace_back(
kXMPMarker,
s.detachAsData());
@ kARGB_4444_SkColorType
pixel with 4 bits for alpha, red, green, blue; in 16-bit word
@ 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
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
static void transform_scanline_to_premul_legacy(char *dst, const char *src, int width, int)
static void transform_scanline_F16_to_8888(char *dst, const char *src, int width, int)
void(* transform_scanline_proc)(char *dst, const char *src, int width, int bpp)
static void transform_scanline_565(char *dst, const char *src, int width, int)
static void transform_scanline_F16_to_premul_8888(char *dst, const char *src, int width, int)
static void transform_scanline_444(char *dst, const char *src, int width, int)
static sk_sp< SkData > icc_from_color_space(const SkColorSpace *cs, const skcms_ICCProfile *profile, const char *profile_description)
static bool SkPixmapIsValid(const SkPixmap &src)
SK_API int SkColorTypeBytesPerPixel(SkColorType ct)
@ kJPEG_Full_SkYUVColorSpace
describes full range
static SkImage_Base * as_IB(SkImage *image)
void skjpeg_error_exit(j_common_ptr cinfo)
static constexpr uint8_t kICCSig[]
static constexpr uint32_t kICCMarker
static constexpr uint32_t kXMPMarker
static constexpr uint8_t kXMPStandardSig[]
static void yuva_copy_row(const SkYUVAPixmaps &src, int row, uint8_t *dst)
static void sk_msan_assert_initialized(const void *begin, const void *end)
const SkPixmap & pixmap() const
const void * data() const
skia_private::AutoTMalloc< uint8_t > fStorage
static std::unique_ptr< SkEncoder > MakeRGB(SkWStream *dst, const SkPixmap &src, const SkJpegEncoder::Options &options, const SkJpegMetadataEncoder::SegmentList &metadata)
bool onEncodeRows(int numRows) override
static std::unique_ptr< SkEncoder > MakeYUV(SkWStream *dst, const SkYUVAPixmaps &srcYUVA, const SkColorSpace *srcYUVAColorSpace, const SkJpegEncoder::Options &options, const SkJpegMetadataEncoder::SegmentList &metadata)
~SkJpegEncoderImpl() override
skjpeg_error_mgr * errorMgr()
bool initializeRGB(const SkImageInfo &, const SkJpegEncoder::Options &, const SkJpegMetadataEncoder::SegmentList &)
jpeg_compress_struct * cinfo()
transform_scanline_proc proc() const
static std::unique_ptr< SkJpegEncoderMgr > Make(SkWStream *stream)
bool initializeYUV(const SkYUVAPixmapInfo &, const SkJpegEncoder::Options &, const SkJpegMetadataEncoder::SegmentList &)
SkColorType colorType() const
const void * addr() const
@ kY_U_V
Plane 0: Y, Plane 1: U, Plane 2: V.
@ kY_UV
Plane 0: Y, Plane 1: UV.
PlaneConfig planeConfig() const
static std::tuple< int, int > SubsamplingFactors(Subsampling)
Subsampling subsampling() const
SkYUVColorSpace yuvColorSpace() const
const SkYUVAInfo & yuvaInfo() const
@ kUnorm8
8 bit unsigned normalized
DataType dataType() const
SkYUVAPixmapInfo pixmapsInfo() const
SK_API std::unique_ptr< SkEncoder > Make(SkWStream *dst, const SkPixmap &src, const Options &options)
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
SkAlphaType alphaType() const
SkColorType colorType() const