60 jpeg_compress_struct*
cinfo() {
return &fCInfo; }
70 fCInfo.err = jpeg_std_error(&fErrMgr);
72 jpeg_create_compress(&fCInfo);
73 fCInfo.dest = &fDstMgr;
76 jpeg_compress_struct fCInfo;
84 auto chooseProc8888 = [&]() {
92 J_COLOR_SPACE jpegColorType = JCS_EXT_RGBA;
93 int numComponents = 0;
96 fProc = chooseProc8888();
97 jpegColorType = JCS_EXT_RGBA;
101 fProc = chooseProc8888();
102 jpegColorType = JCS_EXT_BGRA;
107 jpegColorType = JCS_RGB;
116 jpegColorType = JCS_RGB;
122 jpegColorType = JCS_GRAYSCALE;
132 jpegColorType = JCS_EXT_RGBA;
139 fCInfo.image_width = srcInfo.
width();
140 fCInfo.image_height = srcInfo.
height();
141 fCInfo.in_color_space = jpegColorType;
142 fCInfo.input_components = numComponents;
143 jpeg_set_defaults(&fCInfo);
145 if (numComponents != 1) {
148 SkASSERT(2 == fCInfo.comp_info[0].h_samp_factor);
149 SkASSERT(2 == fCInfo.comp_info[0].v_samp_factor);
150 SkASSERT(1 == fCInfo.comp_info[1].h_samp_factor);
151 SkASSERT(1 == fCInfo.comp_info[1].v_samp_factor);
152 SkASSERT(1 == fCInfo.comp_info[2].h_samp_factor);
153 SkASSERT(1 == fCInfo.comp_info[2].v_samp_factor);
156 fCInfo.comp_info[0].h_samp_factor = 2;
157 fCInfo.comp_info[0].v_samp_factor = 1;
158 SkASSERT(1 == fCInfo.comp_info[1].h_samp_factor);
159 SkASSERT(1 == fCInfo.comp_info[1].v_samp_factor);
160 SkASSERT(1 == fCInfo.comp_info[2].h_samp_factor);
161 SkASSERT(1 == fCInfo.comp_info[2].v_samp_factor);
164 fCInfo.comp_info[0].h_samp_factor = 1;
165 fCInfo.comp_info[0].v_samp_factor = 1;
166 SkASSERT(1 == fCInfo.comp_info[1].h_samp_factor);
167 SkASSERT(1 == fCInfo.comp_info[1].v_samp_factor);
168 SkASSERT(1 == fCInfo.comp_info[2].h_samp_factor);
169 SkASSERT(1 == fCInfo.comp_info[2].v_samp_factor);
177 fCInfo.optimize_coding =
TRUE;
184 int width = src->plane(0).width();
185 switch (src->yuvaInfo().planeConfig()) {
187 auto [ssWidthU, ssHeightU] = src->yuvaInfo().planeSubsamplingFactors(1);
188 auto [ssWidthV, ssHeightV] = src->yuvaInfo().planeSubsamplingFactors(2);
189 const uint8_t* srcY =
reinterpret_cast<const uint8_t*
>(src->plane(0).addr(0, row));
190 const uint8_t* srcU =
191 reinterpret_cast<const uint8_t*
>(src->plane(1).addr(0, row / ssHeightU));
192 const uint8_t* srcV =
193 reinterpret_cast<const uint8_t*
>(src->plane(2).addr(0, row / ssHeightV));
194 for (
int col = 0; col <
width; ++col) {
195 dst[3 * col + 0] = srcY[col];
196 dst[3 * col + 1] = srcU[col / ssWidthU];
197 dst[3 * col + 2] = srcV[col / ssWidthV];
202 auto [ssWidthUV, ssHeightUV] = src->yuvaInfo().planeSubsamplingFactors(1);
203 const uint8_t* srcY =
reinterpret_cast<const uint8_t*
>(src->plane(0).addr(0, row));
204 const uint8_t* srcUV =
205 reinterpret_cast<const uint8_t*
>(src->plane(1).addr(0, row / ssHeightUV));
206 for (
int col = 0; col <
width; ++col) {
207 dst[3 * col + 0] = srcY[col];
208 dst[3 * col + 1] = srcUV[2 * (col / ssWidthUV) + 0];
209 dst[3 * col + 2] = srcUV[2 * (col / ssWidthUV) + 1];
222 fCInfo.in_color_space = JCS_YCbCr;
223 fCInfo.input_components = 3;
224 jpeg_set_defaults(&fCInfo);
252 fCInfo.comp_info[0].h_samp_factor = ssHoriz;
253 fCInfo.comp_info[0].v_samp_factor = ssVert;
255 fCInfo.optimize_coding =
TRUE;
289 if (!encoderMgr->setParams(src->info(),
options)) {
294 jpeg_set_quality(encoderMgr->cinfo(),
options.fQuality,
TRUE);
295 jpeg_start_compress(encoderMgr->cinfo(),
TRUE);
303 auto data =
s.detachAsData();
304 jpeg_write_marker(encoderMgr->cinfo(),
kXMPMarker, data->bytes(), data->size());
312 options.fICCProfileDescription);
316 uint8_t* ptr = (uint8_t*)markerData->writable_data();
321 memcpy(ptr, icc->data(), icc->size());
323 jpeg_write_marker(encoderMgr->cinfo(),
kICCMarker, markerData->bytes(), markerData->size());
327 return std::make_unique<SkJpegEncoderImpl>(std::move(encoderMgr), srcYUVA);
329 return std::make_unique<SkJpegEncoderImpl>(std::move(encoderMgr), *src);
335 encoderMgr->proc() ? encoderMgr->cinfo()->input_components * src.
width() : 0)
336 , fEncoderMgr(
std::move(encoderMgr)) {}
340 :
SkEncoder(src->plane(0), encoderMgr->cinfo()->input_components * src->yuvaInfo().
width())
341 , fEncoderMgr(
std::move(encoderMgr))
354 for (
int i = 0; i < numRows; i++) {
357 jpeg_write_scanlines(fEncoderMgr->cinfo(), &jpegSrcRow, 1);
361 const size_t jpegSrcBytes = fEncoderMgr->cinfo()->input_components *
fSrc.
width();
363 for (
int i = 0; i < numRows; i++) {
364 JSAMPLE* jpegSrcRow = (JSAMPLE*)(
const_cast<void*
>(srcRow));
365 if (fEncoderMgr->proc()) {
370 fEncoderMgr->cinfo()->input_components);
373 SkTAddOffset<const void>(jpegSrcRow, jpegSrcBytes));
378 SkTAddOffset<const void>(jpegSrcRow, jpegSrcBytes));
381 jpeg_write_scanlines(fEncoderMgr->cinfo(), &jpegSrcRow, 1);
382 srcRow = SkTAddOffset<const void>(srcRow,
fSrc.
rowBytes());
388 jpeg_finish_compress(fEncoderMgr->cinfo());
406 return encoder.get() &&
encoder->encodeRows(src.yuvaInfo().height());
414 if (!
as_IB(img)->getROPixels(ctx, &bm)) {
419 return stream.detachAsData();
432 return Make(dst,
nullptr, &src, srcColorSpace,
options);
@ 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 constexpr uint32_t kICCMarkerHeaderSize
static void yuva_copy_row(const SkYUVAPixmaps *src, int row, uint8_t *dst)
static std::unique_ptr< SkEncoder > Make(SkWStream *dst, const SkPixmap *src, const SkYUVAPixmaps *srcYUVA, const SkColorSpace *srcYUVAColorSpace, const SkJpegEncoder::Options &options)
static void sk_msan_assert_initialized(const void *begin, const void *end)
const SkPixmap & pixmap() const
static sk_sp< SkData > MakeUninitialized(size_t length)
skia_private::AutoTMalloc< uint8_t > fStorage
SkJpegEncoderImpl(std::unique_ptr< SkJpegEncoderMgr >, const SkPixmap &src)
bool onEncodeRows(int numRows) override
~SkJpegEncoderImpl() override
skjpeg_error_mgr * errorMgr()
jpeg_compress_struct * cinfo()
bool setParams(const SkImageInfo &srcInfo, const SkJpegEncoder::Options &options)
transform_scanline_proc proc() const
static std::unique_ptr< SkJpegEncoderMgr > Make(SkWStream *stream)
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