// Set comments in tEXt chunk const sk_sp<SkDataTable>& comments = options.fComments; if (comments != nullptr) { if (comments->count() % 2 != 0) { returnfalse;
}
std::vector<png_text> png_texts(comments->count());
std::vector<SkString> clippedKeys; for (int i = 0; i < comments->count() / 2; ++i) { constchar* keyword; constchar* originalKeyword = comments->atStr(2 * i); constchar* text = comments->atStr(2 * i + 1); if (strlen(originalKeyword) <= PNG_KEYWORD_MAX_LENGTH) {
keyword = originalKeyword;
} else {
SkDEBUGFAILF("PNG tEXt keyword should be no longer than %d.",
PNG_KEYWORD_MAX_LENGTH);
clippedKeys.emplace_back(originalKeyword, PNG_KEYWORD_MAX_LENGTH);
keyword = clippedKeys.back().c_str();
} // It seems safe to convert png_const_charp to png_charp for key/text, // and we don't have to provide text_length and other fields as we're providing // 0-terminated c_str with PNG_TEXT_COMPRESSION_NONE (no compression, no itxt).
png_texts[i].compression = PNG_TEXT_COMPRESSION_NONE;
png_texts[i].key = const_cast<png_charp>(keyword);
png_texts[i].text = const_cast<png_charp>(text);
}
png_set_text(fPngPtr, fInfoPtr, png_texts.data(), png_texts.size());
}
// List all chunks that might be included. constchar* hdrChunkNames = "gmAP\0" "gdAT\0" "mDCV\0" "cLLI\0";
constexpr int numHdrChunkNames = 4;
png_set_keep_unknown_chunks(fPngPtr, PNG_HANDLE_CHUNK_ALWAYS,
(png_const_bytep)hdrChunkNames, numHdrChunkNames);
// In the below `png_unknown_chunk` structures, the `data` member is a non-const pointer, // even though it will not be written to. In fact, `data` will be copied by the call to // `png_set_unknown_chunks`, so it is safe for it to be deallocated immediately after // the call.
skhdr::ContentLightLevelInformation clli; if (options.fHdrMetadata.getContentLightLevelInformation(&clli)) { auto data = clli.serializePngChunk();
png_unknown_chunk chunk = {
{'c', 'L', 'L', 'I', 0},
reinterpret_cast<png_byte*>(data->writable_data()),
data->size(),
PNG_HAVE_IHDR,
};
png_set_unknown_chunks(fPngPtr, fInfoPtr, &chunk, 1);
}
skhdr::MasteringDisplayColorVolume mdcv; if (options.fHdrMetadata.getMasteringDisplayColorVolume(&mdcv)) { auto data = mdcv.serialize();
png_unknown_chunk chunk = {
{'m', 'D', 'C', 'V', 0},
reinterpret_cast<png_byte*>(data->writable_data()),
data->size(),
PNG_HAVE_IHDR,
};
png_set_unknown_chunks(fPngPtr, fInfoPtr, &chunk, 1);
}
if (options.fGainmapInfo && options.fGainmap) {
sk_sp<SkData> gainmapVersion = SkGainmapInfo::SerializeVersion();
// When we encode the gainmap, we need to remove the gainmap from its // own encoding options, so that we don't recurse. auto modifiedOptions = options;
modifiedOptions.fGainmap = nullptr;
auto gainmapInfo = *(options.fGainmapInfo); auto gainmapPixels = *(options.fGainmap); auto targetInfo = SkPngEncoderBase::getTargetInfo(gainmapPixels.info());
if (targetInfo && targetInfo->fDstInfo.color() != SkEncodedInfo::kGray_Color &&
targetInfo->fDstInfo.color() != SkEncodedInfo::kGrayAlpha_Color) { // Encode the alternate image colorspace directly in the gainmap profile, // since the ISO gainmap payload does not contain the actual alternative // image primaries. constauto& gainmapColorSpace = options.fGainmapInfo->fGainmapMathColorSpace;
gainmapPixels.setColorSpace(gainmapColorSpace);
} else { // Scrub the gainmap colorspace, since grayscale PNGs don't support // RGB ICC profiles
gainmapInfo.fGainmapMathColorSpace = nullptr;
modifiedOptions.fGainmapInfo = &gainmapInfo;
}
sk_sp<SkData> gainmapData = SkPngEncoder::Encode(gainmapPixels, modifiedOptions); if (!gainmapData) { returnfalse;
}
// The base image contains chunks for both the gainmap versioning (for possible // forward-compat, and as a cheap way to check a gainmap might exist) as // well as the gainmap data.
png_unknown_chunk gmapChunk = {
{'g', 'm', 'A', 'P', 0},
reinterpret_cast<png_byte*>(gainmapVersion->writable_data()),
gainmapVersion->size(),
PNG_HAVE_IHDR,
};
png_set_unknown_chunks(fPngPtr, fInfoPtr, &gmapChunk, 1);
png_unknown_chunk gdatChunk = {
{'g', 'd', 'A', 'T', 0},
reinterpret_cast<png_byte*>(gainmapData->writable_data()),
gainmapData->size(),
PNG_HAVE_IHDR,
};
png_set_unknown_chunks(fPngPtr, fInfoPtr, &gdatChunk, 1);
} elseif (options.fGainmapInfo) { // If there is no gainmap provided for encoding, but we have info, then // we're currently encoding the gainmap pixels, so we need to encode the // gainmap metadata to interpret those pixels.
sk_sp<SkData> data = options.fGainmapInfo->serialize();
png_unknown_chunk chunk = {
{'g', 'm', 'A', 'P', 0},
reinterpret_cast<png_byte*>(data->writable_data()),
data->size(),
PNG_HAVE_IHDR,
};
png_set_unknown_chunks(fPngPtr, fInfoPtr, &chunk, 1);
} #endif return true;
}
// Strip input data that has 4 or 8 bytes per pixel down to 3 or 6 bytes if we don't want alpha. if (dstInfo.color() == SkEncodedInfo::kRGBA_Color) {
SkASSERT(dstRowInfo); if (dstRowInfo->isOpaque()) {
png_set_filler(fPngPtr, 0, PNG_FILLER_AFTER);
}
} return true;
}
bool SkPngEncoderImpl::onEncodeRow(SkSpan<const uint8_t> row) { if (setjmp(png_jmpbuf(fEncoderMgr->pngPtr()))) { returnfalse;
}
// `png_bytep` is `uint8_t*` rather than `const uint8_t*`.
png_bytep rowPtr = const_cast<png_bytep>(row.data());
// Swap to big endian if we are storing more than a byte per color channel // (SkColorTypes are little endian by default). // By this point our data will either be 8888 or 16161616, so we only check that case. if (png_get_bit_depth(fEncoderMgr->pngPtr(), fEncoderMgr->infoPtr()) == 16) {
png_set_swap(fEncoderMgr->pngPtr());
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.