void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) { SkSwizzler::SrcConfig srcConfig = SkSwizzler::kUnknown; if (JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) { srcConfig = SkSwizzler::kCMYK; } else { // If the out_color_space is not CMYK, the only reason we would need a swizzler is // for sampling and/or subsetting. switch (dstInfo.colorType()) { case kGray_8_SkColorType: srcConfig = SkSwizzler::kNoOp8; break; case kN32_SkColorType: srcConfig = SkSwizzler::kNoOp32; break; case kRGB_565_SkColorType: srcConfig = SkSwizzler::kNoOp16; break; default: // This function should only be called if the colorType is supported by jpeg SkASSERT(false); } } fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, dstInfo, options)); fStorage.reset(get_row_bytes(fDecoderMgr->dinfo())); fSrcRow = fStorage.get(); }
int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count) { // Set the jump location for libjpeg-turbo errors if (setjmp(fDecoderMgr->getJmpBuf())) { return 0; } // When fSwizzleSrcRow is non-null, it means that we need to swizzle. In this case, // we will always decode into fSwizzlerSrcRow before swizzling into the next buffer. // We can never swizzle "in place" because the swizzler may perform sampling and/or // subsetting. // When fColorXformSrcRow is non-null, it means that we need to color xform and that // we cannot color xform "in place" (many times we can, but not when the dst is F16). // In this case, we will color xform from fColorXformSrc into the dst. JSAMPLE* decodeDst = (JSAMPLE*) dst; uint32_t* swizzleDst = (uint32_t*) dst; size_t decodeDstRowBytes = rowBytes; size_t swizzleDstRowBytes = rowBytes; if (fSwizzleSrcRow && fColorXformSrcRow) { decodeDst = (JSAMPLE*) fSwizzleSrcRow; swizzleDst = fColorXformSrcRow; decodeDstRowBytes = 0; swizzleDstRowBytes = 0; } else if (fColorXformSrcRow) { decodeDst = (JSAMPLE*) fColorXformSrcRow; swizzleDst = fColorXformSrcRow; decodeDstRowBytes = 0; swizzleDstRowBytes = 0; } else if (fSwizzleSrcRow) { decodeDst = (JSAMPLE*) fSwizzleSrcRow; decodeDstRowBytes = 0; } for (int y = 0; y < count; y++) { uint32_t lines = jpeg_read_scanlines(fDecoderMgr->dinfo(), &decodeDst, 1); size_t srcRowBytes = get_row_bytes(fDecoderMgr->dinfo()); sk_msan_mark_initialized(decodeDst, decodeDst + srcRowBytes, "skbug.com/4550"); if (0 == lines) { return y; } if (fSwizzler) { fSwizzler->swizzle(swizzleDst, decodeDst); } if (fColorXform) { fColorXform->apply(dst, swizzleDst, dstInfo.width(), dstInfo.colorType(), kOpaque_SkAlphaType); dst = SkTAddOffset<void>(dst, rowBytes); } decodeDst = SkTAddOffset<JSAMPLE>(decodeDst, decodeDstRowBytes); swizzleDst = SkTAddOffset<uint32_t>(swizzleDst, swizzleDstRowBytes); } return count; }
// TODO (msarett): Avoid reallocating the memory buffer on each call to skip. static uint32_t jpeg_skip_scanlines(jpeg_decompress_struct* dinfo, int count) { SkAutoTMalloc<uint8_t> storage(get_row_bytes(dinfo)); uint8_t* storagePtr = storage.get(); for (int y = 0; y < count; y++) { if (1 != jpeg_read_scanlines(dinfo, &storagePtr, 1)) { return y; } } return count; }
void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) { SkSwizzler::SrcConfig srcConfig = SkSwizzler::kUnknown; if (JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) { srcConfig = SkSwizzler::kCMYK; } else { // If the out_color_space is not CMYK, the only reason we would need a swizzler is // for sampling and/or subsetting. switch (dstInfo.colorType()) { case kGray_8_SkColorType: srcConfig = SkSwizzler::kNoOp8; break; case kN32_SkColorType: srcConfig = SkSwizzler::kNoOp32; break; case kRGB_565_SkColorType: srcConfig = SkSwizzler::kNoOp16; break; default: // This function should only be called if the colorType is supported by jpeg SkASSERT(false); } } if (JCS_RGB == fDecoderMgr->dinfo()->out_color_space) { srcConfig = SkSwizzler::kRGB; } Options swizzlerOptions = options; if (options.fSubset) { // Use fSwizzlerSubset if this is a subset decode. This is necessary in the case // where libjpeg-turbo provides a subset and then we need to subset it further. // Also, verify that fSwizzlerSubset is initialized and valid. SkASSERT(!fSwizzlerSubset.isEmpty() && fSwizzlerSubset.x() <= options.fSubset->x() && fSwizzlerSubset.width() == options.fSubset->width()); swizzlerOptions.fSubset = &fSwizzlerSubset; } fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, dstInfo, swizzlerOptions)); SkASSERT(fSwizzler); fStorage.reset(get_row_bytes(fDecoderMgr->dinfo())); fSrcRow = fStorage.get(); }
void SkJpegCodec::allocateStorage(const SkImageInfo& dstInfo) { size_t swizzleBytes = 0; if (fSwizzler) { swizzleBytes = get_row_bytes(fDecoderMgr->dinfo()); SkASSERT(!fColorXform || SkIsAlign4(swizzleBytes)); } size_t xformBytes = 0; if (kRGBA_F16_SkColorType == dstInfo.colorType()) { SkASSERT(fColorXform); xformBytes = dstInfo.width() * sizeof(uint32_t); } size_t totalBytes = swizzleBytes + xformBytes; if (totalBytes > 0) { fStorage.reset(totalBytes); fSwizzleSrcRow = (swizzleBytes > 0) ? fStorage.get() : nullptr; fColorXformSrcRow = (xformBytes > 0) ? SkTAddOffset<uint32_t>(fStorage.get(), swizzleBytes) : nullptr; } }
bool SkJpegCodec::onSkipScanlines(int count) { // Set the jump location for libjpeg errors if (setjmp(fDecoderMgr->getJmpBuf())) { return fDecoderMgr->returnFalse("setjmp"); } #ifdef TURBO_HAS_SKIP return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count); #else if (!fSrcRow) { fStorage.reset(get_row_bytes(fDecoderMgr->dinfo())); fSrcRow = fStorage.get(); } for (int y = 0; y < count; y++) { if (1 != jpeg_read_scanlines(fDecoderMgr->dinfo(), &fSrcRow, 1)) { return false; } } return true; #endif }
void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) { // libjpeg-turbo may have already performed color conversion. We must indicate the // appropriate format to the swizzler. SkEncodedInfo swizzlerInfo = this->getEncodedInfo(); bool preSwizzled = true; switch (fDecoderMgr->dinfo()->out_color_space) { case JCS_RGB: preSwizzled = false; swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kRGB_Color, swizzlerInfo.alpha(), swizzlerInfo.bitsPerComponent()); break; case JCS_CMYK: preSwizzled = false; swizzlerInfo = SkEncodedInfo::Make( SkEncodedInfo::kInvertedCMYK_Color, swizzlerInfo.alpha(), swizzlerInfo.bitsPerComponent()); break; default: break; } Options swizzlerOptions = options; if (options.fSubset) { // Use fSwizzlerSubset if this is a subset decode. This is necessary in the case // where libjpeg-turbo provides a subset and then we need to subset it further. // Also, verify that fSwizzlerSubset is initialized and valid. SkASSERT(!fSwizzlerSubset.isEmpty() && fSwizzlerSubset.x() <= options.fSubset->x() && fSwizzlerSubset.width() == options.fSubset->width()); swizzlerOptions.fSubset = &fSwizzlerSubset; } fSwizzler.reset(SkSwizzler::CreateSwizzler(swizzlerInfo, nullptr, dstInfo, swizzlerOptions, nullptr, preSwizzled)); SkASSERT(fSwizzler); fStorage.reset(get_row_bytes(fDecoderMgr->dinfo())); fSrcRow = fStorage.get(); }
int SkJpegCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) { // Set the jump location for libjpeg errors if (setjmp(fDecoderMgr->getJmpBuf())) { return fDecoderMgr->returnFailure("setjmp", kInvalidInput); } // Read rows one at a time JSAMPLE* dstRow; size_t srcRowBytes = get_row_bytes(fDecoderMgr->dinfo()); if (fSwizzler) { // write data to storage row, then sample using swizzler dstRow = fSrcRow; } else { // write data directly to dst SkASSERT(count == 1 || dstRowBytes >= srcRowBytes); dstRow = (JSAMPLE*) dst; } for (int y = 0; y < count; y++) { // Read row of the image uint32_t rowsDecoded = jpeg_read_scanlines(fDecoderMgr->dinfo(), &dstRow, 1); sk_msan_mark_initialized(dstRow, dstRow + srcRowBytes, "skbug.com/4550"); if (rowsDecoded != 1) { fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height(); return y; } if (fSwizzler) { // use swizzler to sample row fSwizzler->swizzle(dst, dstRow); dst = SkTAddOffset<JSAMPLE>(dst, dstRowBytes); } else { dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes); } } return count; }