bool SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& options, SkPMColor ctable[], int* ctableCount) { if (setjmp(png_jmpbuf(fPng_ptr))) { SkCodecPrintf("Failed on png_read_update_info.\n"); return false; } png_read_update_info(fPng_ptr, fInfo_ptr); // It's important to reset fColorXform to nullptr. We don't do this on rewinding // because the interlaced scanline decoder may need to rewind. fColorXform = nullptr; SkImageInfo swizzlerInfo = dstInfo; bool needsColorXform = needs_color_xform(dstInfo, this->getInfo()); if (needsColorXform) { switch (dstInfo.colorType()) { case kRGBA_8888_SkColorType: case kBGRA_8888_SkColorType: case kRGBA_F16_SkColorType: swizzlerInfo = swizzlerInfo.makeColorType(kRGBA_8888_SkColorType); if (kPremul_SkAlphaType == dstInfo.alphaType()) { swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType); } break; case kIndex_8_SkColorType: break; default: return false; } fColorXform = SkColorSpaceXform::New(sk_ref_sp(this->getInfo().colorSpace()), sk_ref_sp(dstInfo.colorSpace())); if (!fColorXform && kRGBA_F16_SkColorType == dstInfo.colorType()) { return false; } } if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) { if (!this->createColorTable(dstInfo, ctableCount)) { return false; } } // Copy the color table to the client if they request kIndex8 mode copy_color_table(swizzlerInfo, fColorTable, ctable, ctableCount); // Create the swizzler. SkPngCodec retains ownership of the color table. const SkPMColor* colors = get_color_ptr(fColorTable.get()); fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colors, swizzlerInfo, options)); SkASSERT(fSwizzler); return true; }
/* * Performs the jpeg decode */ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& options, SkPMColor*, int*, int* rowsDecoded) { if (options.fSubset) { // Subsets are not supported. return kUnimplemented; } // Get a pointer to the decompress info since we will use it quite frequently jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); // Set the jump location for libjpeg errors if (setjmp(fDecoderMgr->getJmpBuf())) { return fDecoderMgr->returnFailure("setjmp", kInvalidInput); } // Check if we can decode to the requested destination and set the output color space bool needsColorXform = needs_color_xform(dstInfo, this->getInfo()); if (!this->setOutputColorSpace(dstInfo, needsColorXform)) { return fDecoderMgr->returnFailure("setOutputColorSpace", kInvalidConversion); } if (!this->initializeColorXform(dstInfo, needsColorXform)) { return fDecoderMgr->returnFailure("initializeColorXform", kInvalidParameters); } if (!jpeg_start_decompress(dinfo)) { return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); } // The recommended output buffer height should always be 1 in high quality modes. // If it's not, we want to know because it means our strategy is not optimal. SkASSERT(1 == dinfo->rec_outbuf_height); J_COLOR_SPACE colorSpace = dinfo->out_color_space; if (JCS_CMYK == colorSpace || JCS_RGB == colorSpace) { this->initializeSwizzler(dstInfo, options); } this->allocateStorage(dstInfo); int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height()); if (rows < dstInfo.height()) { *rowsDecoded = rows; return fDecoderMgr->returnFailure("Incomplete image data", kIncompleteInput); } return kSuccess; }
SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options, SkPMColor ctable[], int* ctableCount) { // Set the jump location for libjpeg errors if (setjmp(fDecoderMgr->getJmpBuf())) { SkCodecPrintf("setjmp: Error from libjpeg\n"); return kInvalidInput; } // Check if we can decode to the requested destination and set the output color space bool needsColorXform = needs_color_xform(dstInfo, this->getInfo()); if (!this->setOutputColorSpace(dstInfo, needsColorXform)) { return kInvalidConversion; } if (!this->initializeColorXform(dstInfo, needsColorXform)) { return fDecoderMgr->returnFailure("initializeColorXform", kInvalidParameters); } if (!jpeg_start_decompress(fDecoderMgr->dinfo())) { SkCodecPrintf("start decompress failed\n"); return kInvalidInput; } #ifdef TURBO_HAS_CROP if (options.fSubset) { uint32_t startX = options.fSubset->x(); uint32_t width = options.fSubset->width(); // libjpeg-turbo may need to align startX to a multiple of the IDCT // block size. If this is the case, it will decrease the value of // startX to the appropriate alignment and also increase the value // of width so that the right edge of the requested subset remains // the same. jpeg_crop_scanline(fDecoderMgr->dinfo(), &startX, &width); SkASSERT(startX <= (uint32_t) options.fSubset->x()); SkASSERT(width >= (uint32_t) options.fSubset->width()); SkASSERT(startX + width >= (uint32_t) options.fSubset->right()); // Instruct the swizzler (if it is necessary) to further subset the // output provided by libjpeg-turbo. // // We set this here (rather than in the if statement below), so that // if (1) we don't need a swizzler for the subset, and (2) we need a // swizzler for CMYK, the swizzler will still use the proper subset // dimensions. // // Note that the swizzler will ignore the y and height parameters of // the subset. Since the scanline decoder (and the swizzler) handle // one row at a time, only the subsetting in the x-dimension matters. fSwizzlerSubset.setXYWH(options.fSubset->x() - startX, 0, options.fSubset->width(), options.fSubset->height()); // We will need a swizzler if libjpeg-turbo cannot provide the exact // subset that we request. if (startX != (uint32_t) options.fSubset->x() || width != (uint32_t) options.fSubset->width()) { this->initializeSwizzler(dstInfo, options); } } // Make sure we have a swizzler if we are converting from CMYK. if (!fSwizzler && JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) { this->initializeSwizzler(dstInfo, options); } #else if (options.fSubset) { fSwizzlerSubset = *options.fSubset; } // We will need a swizzler if we are performing a subset decode or // converting from CMYK. J_COLOR_SPACE colorSpace = fDecoderMgr->dinfo()->out_color_space; if (options.fSubset || JCS_CMYK == colorSpace || JCS_RGB == colorSpace) { this->initializeSwizzler(dstInfo, options); } #endif this->allocateStorage(dstInfo); return kSuccess; }