71 dbgFile << QString(
"libjxl version: %1.%2.%3")
72 .arg(JPEGXL_MAJOR_VERSION)
73 .arg(JPEGXL_MINOR_VERSION)
74 .arg(JPEGXL_PATCH_VERSION);
79 const bool cfgFlattenLayer = cfg->getBool(
"flattenLayers",
true);
80 const bool cfgHaveAnimation = cfg->getBool(
"haveAnimation",
false);
81 const bool cfgMultiLayer = cfg->getBool(
"multiLayer",
false);
82 const bool cfgMultiPage = cfg->getBool(
"multiPage",
false);
84 auto enc = JxlEncoderMake(
nullptr);
85 auto runner = JxlResizableParallelRunnerMake(
nullptr);
86 if (JXL_ENC_SUCCESS != JxlEncoderSetParallelRunner(enc.get(), JxlResizableParallelRunner, runner.get())) {
87 errFile <<
"JxlEncoderSetParallelRunner failed";
91 JxlResizableParallelRunnerSetThreads(runner.get(),
92 JxlResizableParallelRunnerSuggestThreads(
static_cast<uint64_t
>(
bounds.width()),
static_cast<uint64_t
>(
bounds.height())));
96 bool convertToRec2020 =
false;
99 const QString conversionOption = (cfg->getString(
"floatingPointConversionOption",
"Rec2100PQ"));
100 if (conversionOption ==
"Rec2100PQ") {
101 convertToRec2020 =
true;
103 }
else if (conversionOption ==
"Rec2100HLG") {
104 convertToRec2020 =
true;
106 }
else if (conversionOption ==
"ApplyPQ") {
108 }
else if (conversionOption ==
"ApplyHLG") {
110 }
else if (conversionOption ==
"ApplySMPTE428") {
120 errFile <<
"Unable to find a working profile for Rec. 2020";
133 const float hlgGamma = cfg->getFloat(
"HLGgamma", 1.2f);
134 const float hlgNominalPeak = cfg->getFloat(
"HLGnominalPeak", 1000.0f);
135 const bool removeHGLOOTF = cfg->getBool(
"removeHGLOOTF",
true);
139 static constexpr std::array<TransferCharacteristics, 14> supportedTRC = {
TRC_LINEAR,
153 const bool isSupportedTRC = std::find(supportedTRC.begin(), supportedTRC.end(), gamma) != supportedTRC.end();
155#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 10, 1)
157 if (JXL_ENC_SUCCESS != JxlEncoderSetOutputProcessor(enc.get(), processor.
getOutputProcessor())) {
158 errFile <<
"JxlEncoderSetOutputProcessor failed";
163 const JxlPixelFormat pixelFormat = [&]() {
164 JxlPixelFormat pixelFormat{};
166 pixelFormat.data_type = JXL_TYPE_UINT8;
169 pixelFormat.data_type = JXL_TYPE_UINT16;
172 pixelFormat.data_type = JXL_TYPE_FLOAT16;
175 pixelFormat.data_type = JXL_TYPE_FLOAT;
178 pixelFormat.num_channels = 4;
180 pixelFormat.num_channels = 2;
182 pixelFormat.num_channels = 3;
187 if (JXL_ENC_SUCCESS != JxlEncoderUseBoxes(enc.get())) {
188 errFile <<
"JxlEncoderUseBoxes failed";
192 const auto basicInfo = [&]() {
193 auto info{std::make_unique<JxlBasicInfo>()};
194 JxlEncoderInitBasicInfo(info.get());
195 info->xsize =
static_cast<uint32_t
>(
bounds.width());
196 info->ysize =
static_cast<uint32_t
>(
bounds.height());
198 if (pixelFormat.data_type == JXL_TYPE_UINT8) {
199 info->bits_per_sample = 8;
200 info->exponent_bits_per_sample = 0;
201 info->alpha_bits = 8;
202 info->alpha_exponent_bits = 0;
203 }
else if (pixelFormat.data_type == JXL_TYPE_UINT16) {
204 info->bits_per_sample = 16;
205 info->exponent_bits_per_sample = 0;
206 info->alpha_bits = 16;
207 info->alpha_exponent_bits = 0;
209 }
else if (pixelFormat.data_type == JXL_TYPE_FLOAT16) {
210 info->bits_per_sample = 16;
211 info->exponent_bits_per_sample = 5;
212 info->alpha_bits = 16;
213 info->alpha_exponent_bits = 5;
215 }
else if (pixelFormat.data_type == JXL_TYPE_FLOAT) {
216 info->bits_per_sample = 32;
217 info->exponent_bits_per_sample = 8;
218 info->alpha_bits = 32;
219 info->alpha_exponent_bits = 8;
223 info->num_color_channels = 3;
224 info->num_extra_channels = 1;
226 info->num_color_channels = 1;
227 info->num_extra_channels = 1;
229 info->num_color_channels = 3;
230 info->num_extra_channels = 2;
234 || !isSupportedTRC) {
235 info->uses_original_profile = JXL_TRUE;
236 dbgFile <<
"JXL use original profile";
238 info->uses_original_profile = JXL_FALSE;
239 dbgFile <<
"JXL use internal XYB profile";
242 info->have_animation = JXL_TRUE;
243 info->animation.have_timecodes = JXL_FALSE;
244 info->animation.num_loops = 0;
246 info->animation.tps_numerator =
248 info->animation.tps_denominator = 1;
249 }
else if (cfgMultiPage) {
250 info->have_animation = JXL_TRUE;
251 info->animation.have_timecodes = JXL_FALSE;
252 info->animation.num_loops = 0;
253 info->animation.tps_numerator = 1;
254 info->animation.tps_denominator = 1;
259 if (JXL_ENC_SUCCESS != JxlEncoderSetBasicInfo(enc.get(), basicInfo.get())) {
260 errFile <<
"JxlEncoderSetBasicInfo failed";
266 const auto blackInfo = [&]() {
267 auto black{std::make_unique<JxlExtraChannelInfo>()};
268 JxlEncoderInitExtraChannelInfo(JXL_CHANNEL_BLACK, black.get());
269 black->bits_per_sample = basicInfo->bits_per_sample;
270 black->exponent_bits_per_sample = basicInfo->exponent_bits_per_sample;
273 const auto alphaInfo = [&]() {
274 auto alpha{std::make_unique<JxlExtraChannelInfo>()};
275 JxlEncoderInitExtraChannelInfo(JXL_CHANNEL_ALPHA, alpha.get());
276 alpha->bits_per_sample = basicInfo->bits_per_sample;
277 alpha->exponent_bits_per_sample = basicInfo->exponent_bits_per_sample;
281 if (JXL_ENC_SUCCESS != JxlEncoderSetExtraChannelInfo(enc.get(), 0, blackInfo.get())) {
282 errFile <<
"JxlEncoderSetBasicInfo Key failed";
285 if (JXL_ENC_SUCCESS != JxlEncoderSetExtraChannelInfo(enc.get(), 1, alphaInfo.get())) {
286 errFile <<
"JxlEncoderSetBasicInfo Alpha failed";
292 JxlColorEncoding cicpDescription{};
294 switch (conversionPolicy) {
296 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_PQ;
299 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_HLG;
302 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_DCI;
308 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_LINEAR;
313 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_709;
316 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_GAMMA;
317 cicpDescription.gamma = 1.0 / 2.2;
320 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_GAMMA;
321 cicpDescription.gamma = 1.0 / 2.8;
324 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_SRGB;
327 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_PQ;
330 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_DCI;
333 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_HLG;
336 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_GAMMA;
337 cicpDescription.gamma = 1.0 / 1.8;
340 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_GAMMA;
341 cicpDescription.gamma = 1.0 / 2.4;
344 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_GAMMA;
345 cicpDescription.gamma = 1.0 / 1.8;
348 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_GAMMA;
349 cicpDescription.gamma = 256.0 / 563.0;
360 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_LINEAR;
362 dbgFile <<
"JXL CICP cannot describe the current transfer function" << gamma
363 <<
", falling back to ICC";
364 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_UNKNOWN;
374 && !cfg->getBool(
"forceCicpLossless"))
378 dbgFile <<
"Saving with ICC profile";
381 != JxlEncoderSetICCProfile(enc.get(),
reinterpret_cast<const uint8_t *
>(profile.constData()),
static_cast<size_t>(profile.size()))) {
382 errFile <<
"JxlEncoderSetICCProfile failed";
386 dbgFile <<
"Saving with CICP profile";
393 warnFile <<
"Using workaround for libjxl grayscale whitepoint";
394 cicpDescription.white_point = JXL_WHITE_POINT_D65;
395 cicpDescription.color_space = JXL_COLOR_SPACE_GRAY;
399 cicpDescription.primaries = JXL_PRIMARIES_SRGB;
402 cicpDescription.primaries = JXL_PRIMARIES_2100;
405 cicpDescription.primaries = JXL_PRIMARIES_P3;
408 warnFile <<
"Writing possibly non-roundtrip primaries!";
410 cicpDescription.primaries = JXL_PRIMARIES_CUSTOM;
411 cicpDescription.primaries_red_xy[0] = colorants[0];
412 cicpDescription.primaries_red_xy[1] = colorants[1];
413 cicpDescription.primaries_green_xy[0] = colorants[3];
414 cicpDescription.primaries_green_xy[1] = colorants[4];
415 cicpDescription.primaries_blue_xy[0] = colorants[6];
416 cicpDescription.primaries_blue_xy[1] = colorants[7];
422 cicpDescription.white_point = JXL_WHITE_POINT_CUSTOM;
423 cicpDescription.white_point_xy[0] = whitePoint[0];
424 cicpDescription.white_point_xy[1] = whitePoint[1];
427 if (JXL_ENC_SUCCESS != JxlEncoderSetColorEncoding(enc.get(), &cicpDescription)) {
428 errFile <<
"JxlEncoderSetColorEncoding failed";
434 if (cfg->getBool(
"storeMetaData",
false)) {
435 auto metaDataStore = [&]() -> std::unique_ptr<KisMetaData::Store> {
439 return std::make_unique<KisMetaData::Store>(*exivInfoVisitor.
exifInfo());
440 }
else if (cfg->getBool(
"storeAuthor",
true)) {
441 return std::make_unique<KisMetaData::Store>();
447 if (metaDataStore && !metaDataStore->isEmpty()) {
457 if (cfg->getBool(
"storeAuthor",
true)) {
458 QString author = document->documentInfo()->authorInfo(
"creator");
459 if (!author.isEmpty()) {
460 if (!document->documentInfo()->authorContactInfo().isEmpty()) {
461 QString contact = document->documentInfo()->authorContactInfo().at(0);
462 if (!contact.isEmpty()) {
463 author = author +
"(" + contact +
")";
466 if (metaDataStore->containsEntry(
"creator")) {
467 metaDataStore->removeEntry(
"creator");
473 if (metaDataStore && cfg->getBool(
"exif",
true)) {
479 io->
saveTo(metaDataStore.get(), &ioDevice);
482 != JxlEncoderAddBox(enc.get(),
484 reinterpret_cast<const uint8_t *
>(ioDevice.data().constData()),
485 static_cast<size_t>(ioDevice.size()),
486 cfg->getBool(
"lossless") ? JXL_FALSE : JXL_TRUE)) {
487 errFile <<
"JxlEncoderAddBox for EXIF failed";
492 if (metaDataStore && cfg->getBool(
"xmp",
true)) {
498 io->
saveTo(metaDataStore.get(), &ioDevice);
501 != JxlEncoderAddBox(enc.get(),
503 reinterpret_cast<const uint8_t *
>(ioDevice.data().constData()),
504 static_cast<size_t>(ioDevice.size()),
505 cfg->getBool(
"lossless") ? JXL_FALSE : JXL_TRUE)) {
506 errFile <<
"JxlEncoderAddBox for XMP failed";
511 if (metaDataStore && cfg->getBool(
"iptc",
true)) {
517 io->
saveTo(metaDataStore.get(), &ioDevice);
520 != JxlEncoderAddBox(enc.get(),
522 reinterpret_cast<const uint8_t *
>(ioDevice.data().constData()),
523 static_cast<size_t>(ioDevice.size()),
524 cfg->getBool(
"lossless") ? JXL_FALSE : JXL_TRUE)) {
525 errFile <<
"JxlEncoderAddBox for IPTC failed";
531 auto *frameSettings = JxlEncoderFrameSettingsCreate(enc.get(),
nullptr);
533 const auto setFrameLossless = [&](
bool v) {
534 if (JxlEncoderSetFrameLossless(frameSettings,
v ? JXL_TRUE : JXL_FALSE) != JXL_ENC_SUCCESS) {
535 errFile <<
"JxlEncoderSetFrameLossless failed";
541 const auto setSetting = [&](JxlEncoderFrameSettingId id,
int v) {
543 if (
id == JXL_ENC_FRAME_SETTING_RESAMPLING &&
v == -1)
545 if (JxlEncoderFrameSettingsSetOption(frameSettings,
id,
v) != JXL_ENC_SUCCESS) {
546 errFile <<
"JxlEncoderFrameSettingsSetOption failed";
553 const auto setDistance = [&](
float v) {
554 const float distance = cfg->getBool(
"lossless") ? 0.0
555 :
v >= 30 ? 0.1 + (100 -
v) * 0.09
556 : 53.0 / 3000.0 *
v *
v - 23.0 / 20.0 *
v + 25.0;
558 if (JxlEncoderSetFrameDistance(frameSettings,
distance) != JXL_ENC_SUCCESS) {
559 errFile <<
"JxlEncoderSetFrameDistance failed";
562#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 9, 0)
564 if (!cfg->getBool(
"lossless")) {
565 if (cfg->getBool(
"losslessAlpha")) {
566 if (JxlEncoderSetExtraChannelDistance(frameSettings,
569 != JXL_ENC_SUCCESS) {
570 errFile <<
"JxlEncoderSetExtraChannelDistance failed";
574 if (JxlEncoderSetExtraChannelDistance(frameSettings,
577 != JXL_ENC_SUCCESS) {
578 errFile <<
"JxlEncoderSetExtraChannelDistance failed";
593 const int setResponsive = [&]() ->
int {
594 if (pixelFormat.data_type == JXL_TYPE_FLOAT && !cfg->getBool(
"lossless")) {
595 warnFile <<
"Using workaround for lossy 32-bit float, disabling progressive option";
598 return cfg->getInt(
"responsive", -1);
605 const int setPatches = [&]() ->
int {
606#if JPEGXL_NUMERIC_VERSION < JPEGXL_COMPUTE_NUMERIC_VERSION(0, 9, 0)
607 if ((cfg->getInt(
"effort", 7) > 4) && cfgFlattenLayer) {
608 warnFile <<
"Using workaround for layer exports, disabling patches option on effort > 4";
612 return cfg->getInt(
"patches", -1);
615 if (!setFrameLossless(cfg->getBool(
"lossless"))
616 || !setSetting(JXL_ENC_FRAME_SETTING_EFFORT, cfg->getInt(
"effort", 7))
617 || !setSetting(JXL_ENC_FRAME_SETTING_DECODING_SPEED, cfg->getInt(
"decodingSpeed", 0))
618 || !setSetting(JXL_ENC_FRAME_SETTING_RESAMPLING, cfg->getInt(
"resampling", -1))
619 || !setSetting(JXL_ENC_FRAME_SETTING_EXTRA_CHANNEL_RESAMPLING, cfg->getInt(
"extraChannelResampling", -1))
620 || !setSetting(JXL_ENC_FRAME_SETTING_DOTS, cfg->getInt(
"dots", -1))
621 || !setSetting(JXL_ENC_FRAME_SETTING_PATCHES, setPatches)
622 || !setSetting(JXL_ENC_FRAME_SETTING_EPF, cfg->getInt(
"epf", -1))
623 || !setSetting(JXL_ENC_FRAME_SETTING_GABORISH, cfg->getInt(
"gaborish", -1))
624 || !setSetting(JXL_ENC_FRAME_SETTING_MODULAR, cfg->getInt(
"modular", -1))
625 || !setSetting(JXL_ENC_FRAME_SETTING_KEEP_INVISIBLE, cfg->getInt(
"keepInvisible", -1))
626 || !setSetting(JXL_ENC_FRAME_SETTING_GROUP_ORDER, cfg->getInt(
"groupOrder", -1))
627 || !setSetting(JXL_ENC_FRAME_SETTING_RESPONSIVE, setResponsive)
628 || !setSetting(JXL_ENC_FRAME_SETTING_PROGRESSIVE_AC, cfg->getInt(
"progressiveAC", -1))
629 || !setSetting(JXL_ENC_FRAME_SETTING_QPROGRESSIVE_AC, cfg->getInt(
"qProgressiveAC", -1))
630 || !setSetting(JXL_ENC_FRAME_SETTING_PROGRESSIVE_DC, cfg->getInt(
"progressiveDC", -1))
631 || !setSetting(JXL_ENC_FRAME_SETTING_PALETTE_COLORS, cfg->getInt(
"paletteColors", -1))
632 || !setSetting(JXL_ENC_FRAME_SETTING_LOSSY_PALETTE, cfg->getInt(
"lossyPalette", -1))
633 || !setSetting(JXL_ENC_FRAME_SETTING_MODULAR_GROUP_SIZE, cfg->getInt(
"modularGroupSize", -1))
634 || !setSetting(JXL_ENC_FRAME_SETTING_MODULAR_PREDICTOR, cfg->getInt(
"modularPredictor", -1))
635 || !setSetting(JXL_ENC_FRAME_SETTING_JPEG_RECON_CFL, cfg->getInt(
"jpegReconCFL", -1))
636 || !setDistance(cfg->getInt(
"lossyQuality", 100))) {
642 const auto setSettingFloat = [&](JxlEncoderFrameSettingId id,
float v) {
643 if (JxlEncoderFrameSettingsSetFloatOption(frameSettings,
id,
v) != JXL_ENC_SUCCESS) {
644 errFile <<
"JxlEncoderFrameSettingsSetFloatOption failed";
650 if (!setSettingFloat(JXL_ENC_FRAME_SETTING_PHOTON_NOISE, cfg->getFloat(
"photonNoise", 0))
651 || !setSettingFloat(JXL_ENC_FRAME_SETTING_CHANNEL_COLORS_GLOBAL_PERCENT,
652 cfg->getFloat(
"channelColorsGlobalPercent", -1))
653 || !setSettingFloat(JXL_ENC_FRAME_SETTING_CHANNEL_COLORS_GROUP_PERCENT,
654 cfg->getFloat(
"channelColorsGroupPercent", -1))
655 || !setSettingFloat(JXL_ENC_FRAME_SETTING_MODULAR_MA_TREE_LEARNING_PERCENT,
656 cfg->getFloat(
"modularMATreeLearningPercent", -1))) {
662 const bool isAnimated = [&]() {
683 const auto times = [&]() {
685 QSet<int> s = frames->allKeyframeTimes();
687 std::sort(t.begin(), t.end());
691 auto frameHeader = []() {
692 auto header = std::make_unique<JxlFrameHeader>();
693 JxlEncoderInitFrameHeader(header.get());
698 for (
const auto i : times) {
699 frameHeader->duration = [&]() {
700 const auto nextKeyframe = frames->nextKeyframeTime(i);
701 if (nextKeyframe == -1) {
702 return static_cast<uint32_t
>(
706 return static_cast<uint32_t
>(frames->nextKeyframeTime(i) - i);
709 frameHeader->is_last = 0;
711 if (JxlEncoderSetFrameHeader(frameSettings, frameHeader.get()) != JXL_ENC_SUCCESS) {
712 errFile <<
"JxlEncoderSetFrameHeader failed";
716 const QByteArray pixels = [&]() {
720 frameData->writeFrameToDevice(dev);
728 dev->readBytes(
reinterpret_cast<quint8 *
>(
p.data()),
bounds);
749 if (JxlEncoderAddImageFrame(frameSettings,
752 static_cast<size_t>(pixels.size()))
753 != JXL_ENC_SUCCESS) {
754 errFile <<
"JxlEncoderAddImageFrame @" << i <<
"failed";
758#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 10, 1)
763 const int progress = (frameNum * 100) / times.size();
766 if (frames->nextKeyframeTime(i) == -1) {
767 JxlEncoderCloseInput(enc.get());
769 if (JxlEncoderFlushInput(enc.get()) != JXL_ENC_SUCCESS) {
770 errFile <<
"JxlEncoderFlushInput failed";
776 auto frameHeader = std::make_unique<JxlFrameHeader>();
780 quint32 lastValidLayer = 0;
781 if (cfgMultiLayer || cfgMultiPage) {
782 for (quint32 pos = 0; pos < image->
root()->childCount(); pos++) {
784 KisLayer *layer = qobject_cast<KisLayer *>(node.
data());
785 if (layer && (layer->inherits(
"KisGroupLayer") || layer->
childCount() > 0 || layer->
layerStyle())
791 lastValidLayer = pos;
798 for (quint32 pos = 0; pos < image->
root()->childCount(); pos++) {
801 if ((cfgMultiLayer || cfgMultiPage) && (!node || !node->
visible() || node->
isFakeNode())) {
802 dbgFile <<
"Skipping hidden layer" << node->
name();
807 if (cfgMultiLayer || cfgMultiPage) {
810 if (!node->inherits(
"KisPaintLayer")) {
812 node = convertedNode.get();
816 if (lcs && (lcs != cs)) {
821 dbgFile <<
"Saving flattened image";
824 const QRect layerBounds = [&]() {
825 if (node->
exactBounds().isEmpty() || cfgFlattenLayer) {
832 if (cfgFlattenLayer) {
845 f->process(dev, layerBounds, kfc->cloneWithResourcesSnapshot());
848 const QByteArray pixels = [&]() {
865 layerBounds.height(),
870 p.resize(layerBounds.width() * layerBounds.height() *
static_cast<int>(cs->
pixelSize()));
871 dev->
readBytes(
reinterpret_cast<quint8 *
>(
p.data()), layerBounds);
885 layerBounds.height(),
893 if (cfgMultiLayer || cfgMultiPage) {
894 JxlEncoderInitFrameHeader(frameHeader.get());
898 frameHeader->duration = 0;
899 }
else if (cfgMultiPage) {
900 frameHeader->duration = 0xFFFFFFFF;
906 frameHeader->layer_info.have_crop =
false;
908 frameHeader->layer_info.have_crop =
true;
910 frameHeader->layer_info.crop_x0 = layerBounds.x();
911 frameHeader->layer_info.crop_y0 = layerBounds.y();
912 frameHeader->layer_info.xsize = layerBounds.width();
913 frameHeader->layer_info.ysize = layerBounds.height();
916 frameHeader->layer_info.blend_info.alpha = 1;
918 frameHeader->layer_info.blend_info.alpha = 0;
923 const QString frameName = node->
name();
924 if (!isFirstLayer && cfgMultiLayer) {
926 frameHeader->layer_info.blend_info.blendmode = JXL_BLEND_MULADD;
928 frameHeader->layer_info.blend_info.blendmode = JXL_BLEND_BLEND;
932 if (JxlEncoderSetFrameHeader(frameSettings, frameHeader.get()) != JXL_ENC_SUCCESS) {
933 errFile <<
"JxlEncoderSetFrameHeader failed";
936 if (JxlEncoderSetFrameName(frameSettings, frameName.toLocal8Bit()) != JXL_ENC_SUCCESS) {
937 errFile <<
"JxlEncoderSetFrameName failed";
942 if (JxlEncoderAddImageFrame(frameSettings,
945 static_cast<size_t>(pixels.size()))
946 != JXL_ENC_SUCCESS) {
947 errFile <<
"JxlEncoderAddImageFrame failed";
960 layerBounds.height(),
967 layerBounds.height(),
970 if (JxlEncoderSetExtraChannelBuffer(frameSettings,
973 static_cast<size_t>(chaK.size()),
975 != JXL_ENC_SUCCESS) {
976 errFile <<
"JxlEncoderSetExtraChannelBuffer Key failed";
979 if (JxlEncoderSetExtraChannelBuffer(frameSettings,
982 static_cast<size_t>(chaA.size()),
984 != JXL_ENC_SUCCESS) {
985 errFile <<
"JxlEncoderSetExtraChannelBuffer Alpha failed";
990#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 10, 1)
997 if ((pos == lastValidLayer && (cfgMultiLayer || cfgMultiPage)) || cfgFlattenLayer) {
998 JxlEncoderCloseInput(enc.get());
1000 if (JxlEncoderFlushInput(enc.get()) != JXL_ENC_SUCCESS) {
1001 errFile <<
"JxlEncoderFlushInput failed";
1004 if (cfgFlattenLayer) {
1011 if (cfgFlattenLayer) {
1016 JxlEncoderCloseInput(enc.get());
1018 QByteArray compressed(16384, 0x0);
1019 auto *nextOut =
reinterpret_cast<uint8_t *
>(compressed.data());
1020 auto availOut =
static_cast<size_t>(compressed.size());
1021 auto result = JXL_ENC_NEED_MORE_OUTPUT;
1022 while (result == JXL_ENC_NEED_MORE_OUTPUT) {
1023 result = JxlEncoderProcessOutput(enc.get(), &nextOut, &availOut);
1024 if (result != JXL_ENC_ERROR) {
1025 io->write(compressed.data(), compressed.size() -
static_cast<int>(availOut));
1027 if (result == JXL_ENC_NEED_MORE_OUTPUT) {
1028 compressed.resize(compressed.size() * 2);
1029 nextOut =
reinterpret_cast<uint8_t *
>(compressed.data());
1030 availOut =
static_cast<size_t>(compressed.size());
1033 if (JXL_ENC_SUCCESS != result) {
1034 errFile <<
"JxlEncoderProcessOutput failed";