1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2007 The Android Open Source Project 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/images/SkImageEncoderPriv.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#ifdef SK_ENCODE_JPEG 11cb93a386Sopenharmony_ci 12cb93a386Sopenharmony_ci#include "include/core/SkStream.h" 13cb93a386Sopenharmony_ci#include "include/encode/SkJpegEncoder.h" 14cb93a386Sopenharmony_ci#include "include/private/SkColorData.h" 15cb93a386Sopenharmony_ci#include "include/private/SkImageInfoPriv.h" 16cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h" 17cb93a386Sopenharmony_ci#include "src/core/SkMSAN.h" 18cb93a386Sopenharmony_ci#include "src/images/SkImageEncoderFns.h" 19cb93a386Sopenharmony_ci#include "src/images/SkJPEGWriteUtility.h" 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_ci#include <stdio.h> 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ciextern "C" { 24cb93a386Sopenharmony_ci #include "jpeglib.h" 25cb93a386Sopenharmony_ci #include "jerror.h" 26cb93a386Sopenharmony_ci} 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_ciclass SkJpegEncoderMgr final : SkNoncopyable { 29cb93a386Sopenharmony_cipublic: 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_ci /* 32cb93a386Sopenharmony_ci * Create the decode manager 33cb93a386Sopenharmony_ci * Does not take ownership of stream 34cb93a386Sopenharmony_ci */ 35cb93a386Sopenharmony_ci static std::unique_ptr<SkJpegEncoderMgr> Make(SkWStream* stream) { 36cb93a386Sopenharmony_ci return std::unique_ptr<SkJpegEncoderMgr>(new SkJpegEncoderMgr(stream)); 37cb93a386Sopenharmony_ci } 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci bool setParams(const SkImageInfo& srcInfo, const SkJpegEncoder::Options& options); 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci jpeg_compress_struct* cinfo() { return &fCInfo; } 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ci skjpeg_error_mgr* errorMgr() { return &fErrMgr; } 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_ci transform_scanline_proc proc() const { return fProc; } 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci ~SkJpegEncoderMgr() { 48cb93a386Sopenharmony_ci jpeg_destroy_compress(&fCInfo); 49cb93a386Sopenharmony_ci } 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ciprivate: 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_ci SkJpegEncoderMgr(SkWStream* stream) 54cb93a386Sopenharmony_ci : fDstMgr(stream) 55cb93a386Sopenharmony_ci , fProc(nullptr) 56cb93a386Sopenharmony_ci { 57cb93a386Sopenharmony_ci fCInfo.err = jpeg_std_error(&fErrMgr); 58cb93a386Sopenharmony_ci fErrMgr.error_exit = skjpeg_error_exit; 59cb93a386Sopenharmony_ci jpeg_create_compress(&fCInfo); 60cb93a386Sopenharmony_ci fCInfo.dest = &fDstMgr; 61cb93a386Sopenharmony_ci } 62cb93a386Sopenharmony_ci 63cb93a386Sopenharmony_ci jpeg_compress_struct fCInfo; 64cb93a386Sopenharmony_ci skjpeg_error_mgr fErrMgr; 65cb93a386Sopenharmony_ci skjpeg_destination_mgr fDstMgr; 66cb93a386Sopenharmony_ci transform_scanline_proc fProc; 67cb93a386Sopenharmony_ci}; 68cb93a386Sopenharmony_ci 69cb93a386Sopenharmony_cibool SkJpegEncoderMgr::setParams(const SkImageInfo& srcInfo, const SkJpegEncoder::Options& options) 70cb93a386Sopenharmony_ci{ 71cb93a386Sopenharmony_ci auto chooseProc8888 = [&]() { 72cb93a386Sopenharmony_ci if (kUnpremul_SkAlphaType == srcInfo.alphaType() && 73cb93a386Sopenharmony_ci options.fAlphaOption == SkJpegEncoder::AlphaOption::kBlendOnBlack) { 74cb93a386Sopenharmony_ci return transform_scanline_to_premul_legacy; 75cb93a386Sopenharmony_ci } 76cb93a386Sopenharmony_ci return (transform_scanline_proc) nullptr; 77cb93a386Sopenharmony_ci }; 78cb93a386Sopenharmony_ci 79cb93a386Sopenharmony_ci J_COLOR_SPACE jpegColorType = JCS_EXT_RGBA; 80cb93a386Sopenharmony_ci int numComponents = 0; 81cb93a386Sopenharmony_ci switch (srcInfo.colorType()) { 82cb93a386Sopenharmony_ci case kRGBA_8888_SkColorType: 83cb93a386Sopenharmony_ci fProc = chooseProc8888(); 84cb93a386Sopenharmony_ci jpegColorType = JCS_EXT_RGBA; 85cb93a386Sopenharmony_ci numComponents = 4; 86cb93a386Sopenharmony_ci break; 87cb93a386Sopenharmony_ci case kBGRA_8888_SkColorType: 88cb93a386Sopenharmony_ci fProc = chooseProc8888(); 89cb93a386Sopenharmony_ci jpegColorType = JCS_EXT_BGRA; 90cb93a386Sopenharmony_ci numComponents = 4; 91cb93a386Sopenharmony_ci break; 92cb93a386Sopenharmony_ci case kRGB_565_SkColorType: 93cb93a386Sopenharmony_ci fProc = transform_scanline_565; 94cb93a386Sopenharmony_ci jpegColorType = JCS_RGB; 95cb93a386Sopenharmony_ci numComponents = 3; 96cb93a386Sopenharmony_ci break; 97cb93a386Sopenharmony_ci case kARGB_4444_SkColorType: 98cb93a386Sopenharmony_ci if (SkJpegEncoder::AlphaOption::kBlendOnBlack == options.fAlphaOption) { 99cb93a386Sopenharmony_ci return false; 100cb93a386Sopenharmony_ci } 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_ci fProc = transform_scanline_444; 103cb93a386Sopenharmony_ci jpegColorType = JCS_RGB; 104cb93a386Sopenharmony_ci numComponents = 3; 105cb93a386Sopenharmony_ci break; 106cb93a386Sopenharmony_ci case kGray_8_SkColorType: 107cb93a386Sopenharmony_ci SkASSERT(srcInfo.isOpaque()); 108cb93a386Sopenharmony_ci jpegColorType = JCS_GRAYSCALE; 109cb93a386Sopenharmony_ci numComponents = 1; 110cb93a386Sopenharmony_ci break; 111cb93a386Sopenharmony_ci case kRGBA_F16_SkColorType: 112cb93a386Sopenharmony_ci if (kUnpremul_SkAlphaType == srcInfo.alphaType() && 113cb93a386Sopenharmony_ci options.fAlphaOption == SkJpegEncoder::AlphaOption::kBlendOnBlack) { 114cb93a386Sopenharmony_ci fProc = transform_scanline_F16_to_premul_8888; 115cb93a386Sopenharmony_ci } else { 116cb93a386Sopenharmony_ci fProc = transform_scanline_F16_to_8888; 117cb93a386Sopenharmony_ci } 118cb93a386Sopenharmony_ci jpegColorType = JCS_EXT_RGBA; 119cb93a386Sopenharmony_ci numComponents = 4; 120cb93a386Sopenharmony_ci break; 121cb93a386Sopenharmony_ci default: 122cb93a386Sopenharmony_ci return false; 123cb93a386Sopenharmony_ci } 124cb93a386Sopenharmony_ci 125cb93a386Sopenharmony_ci fCInfo.image_width = srcInfo.width(); 126cb93a386Sopenharmony_ci fCInfo.image_height = srcInfo.height(); 127cb93a386Sopenharmony_ci fCInfo.in_color_space = jpegColorType; 128cb93a386Sopenharmony_ci fCInfo.input_components = numComponents; 129cb93a386Sopenharmony_ci jpeg_set_defaults(&fCInfo); 130cb93a386Sopenharmony_ci 131cb93a386Sopenharmony_ci if (kGray_8_SkColorType != srcInfo.colorType()) { 132cb93a386Sopenharmony_ci switch (options.fDownsample) { 133cb93a386Sopenharmony_ci case SkJpegEncoder::Downsample::k420: 134cb93a386Sopenharmony_ci SkASSERT(2 == fCInfo.comp_info[0].h_samp_factor); 135cb93a386Sopenharmony_ci SkASSERT(2 == fCInfo.comp_info[0].v_samp_factor); 136cb93a386Sopenharmony_ci SkASSERT(1 == fCInfo.comp_info[1].h_samp_factor); 137cb93a386Sopenharmony_ci SkASSERT(1 == fCInfo.comp_info[1].v_samp_factor); 138cb93a386Sopenharmony_ci SkASSERT(1 == fCInfo.comp_info[2].h_samp_factor); 139cb93a386Sopenharmony_ci SkASSERT(1 == fCInfo.comp_info[2].v_samp_factor); 140cb93a386Sopenharmony_ci break; 141cb93a386Sopenharmony_ci case SkJpegEncoder::Downsample::k422: 142cb93a386Sopenharmony_ci fCInfo.comp_info[0].h_samp_factor = 2; 143cb93a386Sopenharmony_ci fCInfo.comp_info[0].v_samp_factor = 1; 144cb93a386Sopenharmony_ci fCInfo.comp_info[1].h_samp_factor = 1; 145cb93a386Sopenharmony_ci fCInfo.comp_info[1].v_samp_factor = 1; 146cb93a386Sopenharmony_ci fCInfo.comp_info[2].h_samp_factor = 1; 147cb93a386Sopenharmony_ci fCInfo.comp_info[2].v_samp_factor = 1; 148cb93a386Sopenharmony_ci break; 149cb93a386Sopenharmony_ci case SkJpegEncoder::Downsample::k444: 150cb93a386Sopenharmony_ci fCInfo.comp_info[0].h_samp_factor = 1; 151cb93a386Sopenharmony_ci fCInfo.comp_info[0].v_samp_factor = 1; 152cb93a386Sopenharmony_ci fCInfo.comp_info[1].h_samp_factor = 1; 153cb93a386Sopenharmony_ci fCInfo.comp_info[1].v_samp_factor = 1; 154cb93a386Sopenharmony_ci fCInfo.comp_info[2].h_samp_factor = 1; 155cb93a386Sopenharmony_ci fCInfo.comp_info[2].v_samp_factor = 1; 156cb93a386Sopenharmony_ci break; 157cb93a386Sopenharmony_ci } 158cb93a386Sopenharmony_ci } 159cb93a386Sopenharmony_ci 160cb93a386Sopenharmony_ci // Tells libjpeg-turbo to compute optimal Huffman coding tables 161cb93a386Sopenharmony_ci // for the image. This improves compression at the cost of 162cb93a386Sopenharmony_ci // slower encode performance. 163cb93a386Sopenharmony_ci fCInfo.optimize_coding = TRUE; 164cb93a386Sopenharmony_ci return true; 165cb93a386Sopenharmony_ci} 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_cistd::unique_ptr<SkEncoder> SkJpegEncoder::Make(SkWStream* dst, const SkPixmap& src, 168cb93a386Sopenharmony_ci const Options& options) { 169cb93a386Sopenharmony_ci if (!SkPixmapIsValid(src)) { 170cb93a386Sopenharmony_ci return nullptr; 171cb93a386Sopenharmony_ci } 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ci std::unique_ptr<SkJpegEncoderMgr> encoderMgr = SkJpegEncoderMgr::Make(dst); 174cb93a386Sopenharmony_ci 175cb93a386Sopenharmony_ci skjpeg_error_mgr::AutoPushJmpBuf jmp(encoderMgr->errorMgr()); 176cb93a386Sopenharmony_ci if (setjmp(jmp)) { 177cb93a386Sopenharmony_ci return nullptr; 178cb93a386Sopenharmony_ci } 179cb93a386Sopenharmony_ci 180cb93a386Sopenharmony_ci if (!encoderMgr->setParams(src.info(), options)) { 181cb93a386Sopenharmony_ci return nullptr; 182cb93a386Sopenharmony_ci } 183cb93a386Sopenharmony_ci 184cb93a386Sopenharmony_ci jpeg_set_quality(encoderMgr->cinfo(), options.fQuality, TRUE); 185cb93a386Sopenharmony_ci jpeg_start_compress(encoderMgr->cinfo(), TRUE); 186cb93a386Sopenharmony_ci 187cb93a386Sopenharmony_ci sk_sp<SkData> icc = icc_from_color_space(src.info()); 188cb93a386Sopenharmony_ci if (icc) { 189cb93a386Sopenharmony_ci // Create a contiguous block of memory with the icc signature followed by the profile. 190cb93a386Sopenharmony_ci sk_sp<SkData> markerData = 191cb93a386Sopenharmony_ci SkData::MakeUninitialized(kICCMarkerHeaderSize + icc->size()); 192cb93a386Sopenharmony_ci uint8_t* ptr = (uint8_t*) markerData->writable_data(); 193cb93a386Sopenharmony_ci memcpy(ptr, kICCSig, sizeof(kICCSig)); 194cb93a386Sopenharmony_ci ptr += sizeof(kICCSig); 195cb93a386Sopenharmony_ci *ptr++ = 1; // This is the first marker. 196cb93a386Sopenharmony_ci *ptr++ = 1; // Out of one total markers. 197cb93a386Sopenharmony_ci memcpy(ptr, icc->data(), icc->size()); 198cb93a386Sopenharmony_ci 199cb93a386Sopenharmony_ci jpeg_write_marker(encoderMgr->cinfo(), kICCMarker, markerData->bytes(), markerData->size()); 200cb93a386Sopenharmony_ci } 201cb93a386Sopenharmony_ci 202cb93a386Sopenharmony_ci return std::unique_ptr<SkJpegEncoder>(new SkJpegEncoder(std::move(encoderMgr), src)); 203cb93a386Sopenharmony_ci} 204cb93a386Sopenharmony_ci 205cb93a386Sopenharmony_ciSkJpegEncoder::SkJpegEncoder(std::unique_ptr<SkJpegEncoderMgr> encoderMgr, const SkPixmap& src) 206cb93a386Sopenharmony_ci : INHERITED(src, encoderMgr->proc() ? encoderMgr->cinfo()->input_components*src.width() : 0) 207cb93a386Sopenharmony_ci , fEncoderMgr(std::move(encoderMgr)) 208cb93a386Sopenharmony_ci{} 209cb93a386Sopenharmony_ci 210cb93a386Sopenharmony_ciSkJpegEncoder::~SkJpegEncoder() {} 211cb93a386Sopenharmony_ci 212cb93a386Sopenharmony_cibool SkJpegEncoder::onEncodeRows(int numRows) { 213cb93a386Sopenharmony_ci skjpeg_error_mgr::AutoPushJmpBuf jmp(fEncoderMgr->errorMgr()); 214cb93a386Sopenharmony_ci if (setjmp(jmp)) { 215cb93a386Sopenharmony_ci return false; 216cb93a386Sopenharmony_ci } 217cb93a386Sopenharmony_ci 218cb93a386Sopenharmony_ci const size_t srcBytes = SkColorTypeBytesPerPixel(fSrc.colorType()) * fSrc.width(); 219cb93a386Sopenharmony_ci const size_t jpegSrcBytes = fEncoderMgr->cinfo()->input_components * fSrc.width(); 220cb93a386Sopenharmony_ci 221cb93a386Sopenharmony_ci const void* srcRow = fSrc.addr(0, fCurrRow); 222cb93a386Sopenharmony_ci for (int i = 0; i < numRows; i++) { 223cb93a386Sopenharmony_ci JSAMPLE* jpegSrcRow = (JSAMPLE*) srcRow; 224cb93a386Sopenharmony_ci if (fEncoderMgr->proc()) { 225cb93a386Sopenharmony_ci sk_msan_assert_initialized(srcRow, SkTAddOffset<const void>(srcRow, srcBytes)); 226cb93a386Sopenharmony_ci fEncoderMgr->proc()((char*)fStorage.get(), 227cb93a386Sopenharmony_ci (const char*)srcRow, 228cb93a386Sopenharmony_ci fSrc.width(), 229cb93a386Sopenharmony_ci fEncoderMgr->cinfo()->input_components); 230cb93a386Sopenharmony_ci jpegSrcRow = fStorage.get(); 231cb93a386Sopenharmony_ci sk_msan_assert_initialized(jpegSrcRow, 232cb93a386Sopenharmony_ci SkTAddOffset<const void>(jpegSrcRow, jpegSrcBytes)); 233cb93a386Sopenharmony_ci } else { 234cb93a386Sopenharmony_ci // Same as above, but this repetition allows determining whether a 235cb93a386Sopenharmony_ci // proc was used when msan asserts. 236cb93a386Sopenharmony_ci sk_msan_assert_initialized(jpegSrcRow, 237cb93a386Sopenharmony_ci SkTAddOffset<const void>(jpegSrcRow, jpegSrcBytes)); 238cb93a386Sopenharmony_ci } 239cb93a386Sopenharmony_ci 240cb93a386Sopenharmony_ci jpeg_write_scanlines(fEncoderMgr->cinfo(), &jpegSrcRow, 1); 241cb93a386Sopenharmony_ci srcRow = SkTAddOffset<const void>(srcRow, fSrc.rowBytes()); 242cb93a386Sopenharmony_ci } 243cb93a386Sopenharmony_ci 244cb93a386Sopenharmony_ci fCurrRow += numRows; 245cb93a386Sopenharmony_ci if (fCurrRow == fSrc.height()) { 246cb93a386Sopenharmony_ci jpeg_finish_compress(fEncoderMgr->cinfo()); 247cb93a386Sopenharmony_ci } 248cb93a386Sopenharmony_ci 249cb93a386Sopenharmony_ci return true; 250cb93a386Sopenharmony_ci} 251cb93a386Sopenharmony_ci 252cb93a386Sopenharmony_cibool SkJpegEncoder::Encode(SkWStream* dst, const SkPixmap& src, const Options& options) { 253cb93a386Sopenharmony_ci auto encoder = SkJpegEncoder::Make(dst, src, options); 254cb93a386Sopenharmony_ci return encoder.get() && encoder->encodeRows(src.height()); 255cb93a386Sopenharmony_ci} 256cb93a386Sopenharmony_ci 257cb93a386Sopenharmony_ci#endif 258