72 dbgFile << QString(
"libjxl version: %1.%2.%3")
73 .arg(JPEGXL_MAJOR_VERSION)
74 .arg(JPEGXL_MINOR_VERSION)
75 .arg(JPEGXL_PATCH_VERSION);
80 const bool cfgFlattenLayer = cfg->getBool(
"flattenLayers",
true);
81 const bool cfgHaveAnimation = cfg->getBool(
"haveAnimation",
false);
82 const bool cfgMultiLayer = cfg->getBool(
"multiLayer",
false);
83 const bool cfgMultiPage = cfg->getBool(
"multiPage",
false);
85 auto enc = JxlEncoderMake(
nullptr);
86 auto runner = JxlResizableParallelRunnerMake(
nullptr);
87 if (JXL_ENC_SUCCESS != JxlEncoderSetParallelRunner(enc.get(), JxlResizableParallelRunner, runner.get())) {
88 errFile <<
"JxlEncoderSetParallelRunner failed";
92 JxlResizableParallelRunnerSetThreads(runner.get(),
93 JxlResizableParallelRunnerSuggestThreads(
static_cast<uint64_t
>(
bounds.width()),
static_cast<uint64_t
>(
bounds.height())));
97 bool convertToRec2020 =
false;
100 const QString conversionOption = (cfg->getString(
"floatingPointConversionOption",
"Rec2100PQ"));
101 if (conversionOption ==
"Rec2100PQ") {
102 convertToRec2020 =
true;
104 }
else if (conversionOption ==
"Rec2100HLG") {
105 convertToRec2020 =
true;
107 }
else if (conversionOption ==
"ApplyPQ") {
109 }
else if (conversionOption ==
"ApplyHLG") {
111 }
else if (conversionOption ==
"ApplySMPTE428") {
121 errFile <<
"Unable to find a working profile for Rec. 2020";
134 const float hlgGamma = cfg->getFloat(
"HLGgamma", 1.2f);
135 const float hlgNominalPeak = cfg->getFloat(
"HLGnominalPeak", 1000.0f);
136 const bool removeHGLOOTF = cfg->getBool(
"removeHGLOOTF",
true);
140 static constexpr std::array<TransferCharacteristics, 14> supportedTRC = {
TRC_LINEAR,
154 const bool isSupportedTRC = std::find(supportedTRC.begin(), supportedTRC.end(), gamma) != supportedTRC.end();
156#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 10, 1)
158 if (JXL_ENC_SUCCESS != JxlEncoderSetOutputProcessor(enc.get(), processor.
getOutputProcessor())) {
159 errFile <<
"JxlEncoderSetOutputProcessor failed";
164 const JxlPixelFormat pixelFormat = [&]() {
165 JxlPixelFormat pixelFormat{};
167 pixelFormat.data_type = JXL_TYPE_UINT8;
170 pixelFormat.data_type = JXL_TYPE_UINT16;
173 pixelFormat.data_type = JXL_TYPE_FLOAT16;
176 pixelFormat.data_type = JXL_TYPE_FLOAT;
179 pixelFormat.num_channels = 4;
181 pixelFormat.num_channels = 2;
183 pixelFormat.num_channels = 3;
188 if (JXL_ENC_SUCCESS != JxlEncoderUseBoxes(enc.get())) {
189 errFile <<
"JxlEncoderUseBoxes failed";
193 const auto basicInfo = [&]() {
194 auto info{std::make_unique<JxlBasicInfo>()};
195 JxlEncoderInitBasicInfo(info.get());
196 info->xsize =
static_cast<uint32_t
>(
bounds.width());
197 info->ysize =
static_cast<uint32_t
>(
bounds.height());
199 if (pixelFormat.data_type == JXL_TYPE_UINT8) {
200 info->bits_per_sample = 8;
201 info->exponent_bits_per_sample = 0;
202 info->alpha_bits = 8;
203 info->alpha_exponent_bits = 0;
204 }
else if (pixelFormat.data_type == JXL_TYPE_UINT16) {
205 info->bits_per_sample = 16;
206 info->exponent_bits_per_sample = 0;
207 info->alpha_bits = 16;
208 info->alpha_exponent_bits = 0;
210 }
else if (pixelFormat.data_type == JXL_TYPE_FLOAT16) {
211 info->bits_per_sample = 16;
212 info->exponent_bits_per_sample = 5;
213 info->alpha_bits = 16;
214 info->alpha_exponent_bits = 5;
216 }
else if (pixelFormat.data_type == JXL_TYPE_FLOAT) {
217 info->bits_per_sample = 32;
218 info->exponent_bits_per_sample = 8;
219 info->alpha_bits = 32;
220 info->alpha_exponent_bits = 8;
224 info->num_color_channels = 3;
225 info->num_extra_channels = 1;
227 info->num_color_channels = 1;
228 info->num_extra_channels = 1;
230 info->num_color_channels = 3;
231 info->num_extra_channels = 2;
235 || !isSupportedTRC) {
236 info->uses_original_profile = JXL_TRUE;
237 dbgFile <<
"JXL use original profile";
239 info->uses_original_profile = JXL_FALSE;
240 dbgFile <<
"JXL use internal XYB profile";
243 info->have_animation = JXL_TRUE;
244 info->animation.have_timecodes = JXL_FALSE;
245 info->animation.num_loops = 0;
247 info->animation.tps_numerator =
249 info->animation.tps_denominator = 1;
250 }
else if (cfgMultiPage) {
251 info->have_animation = JXL_TRUE;
252 info->animation.have_timecodes = JXL_FALSE;
253 info->animation.num_loops = 0;
254 info->animation.tps_numerator = 1;
255 info->animation.tps_denominator = 1;
260 if (JXL_ENC_SUCCESS != JxlEncoderSetBasicInfo(enc.get(), basicInfo.get())) {
261 errFile <<
"JxlEncoderSetBasicInfo failed";
267 const auto blackInfo = [&]() {
268 auto black{std::make_unique<JxlExtraChannelInfo>()};
269 JxlEncoderInitExtraChannelInfo(JXL_CHANNEL_BLACK, black.get());
270 black->bits_per_sample = basicInfo->bits_per_sample;
271 black->exponent_bits_per_sample = basicInfo->exponent_bits_per_sample;
274 const auto alphaInfo = [&]() {
275 auto alpha{std::make_unique<JxlExtraChannelInfo>()};
276 JxlEncoderInitExtraChannelInfo(JXL_CHANNEL_ALPHA, alpha.get());
277 alpha->bits_per_sample = basicInfo->bits_per_sample;
278 alpha->exponent_bits_per_sample = basicInfo->exponent_bits_per_sample;
282 if (JXL_ENC_SUCCESS != JxlEncoderSetExtraChannelInfo(enc.get(), 0, blackInfo.get())) {
283 errFile <<
"JxlEncoderSetBasicInfo Key failed";
286 if (JXL_ENC_SUCCESS != JxlEncoderSetExtraChannelInfo(enc.get(), 1, alphaInfo.get())) {
287 errFile <<
"JxlEncoderSetBasicInfo Alpha failed";
293 JxlColorEncoding cicpDescription{};
295 switch (conversionPolicy) {
297 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_PQ;
300 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_HLG;
303 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_DCI;
309 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_LINEAR;
314 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_709;
317 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_GAMMA;
318 cicpDescription.gamma = 1.0 / 2.2;
321 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_GAMMA;
322 cicpDescription.gamma = 1.0 / 2.8;
325 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_SRGB;
328 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_PQ;
331 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_DCI;
334 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_HLG;
337 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_GAMMA;
338 cicpDescription.gamma = 1.0 / 1.8;
341 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_GAMMA;
342 cicpDescription.gamma = 1.0 / 2.4;
345 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_GAMMA;
346 cicpDescription.gamma = 1.0 / 1.8;
349 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_GAMMA;
350 cicpDescription.gamma = 256.0 / 563.0;
361 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_LINEAR;
363 dbgFile <<
"JXL CICP cannot describe the current transfer function" << gamma
364 <<
", falling back to ICC";
365 cicpDescription.transfer_function = JXL_TRANSFER_FUNCTION_UNKNOWN;
375 && !cfg->getBool(
"forceCicpLossless"))
379 dbgFile <<
"Saving with ICC profile";
382 != JxlEncoderSetICCProfile(enc.get(),
reinterpret_cast<const uint8_t *
>(profile.constData()),
static_cast<size_t>(profile.size()))) {
383 errFile <<
"JxlEncoderSetICCProfile failed";
387 dbgFile <<
"Saving with CICP profile";
394 warnFile <<
"Using workaround for libjxl grayscale whitepoint";
395 cicpDescription.white_point = JXL_WHITE_POINT_D65;
396 cicpDescription.color_space = JXL_COLOR_SPACE_GRAY;
400 cicpDescription.primaries = JXL_PRIMARIES_SRGB;
403 cicpDescription.primaries = JXL_PRIMARIES_2100;
406 cicpDescription.primaries = JXL_PRIMARIES_P3;
409 warnFile <<
"Writing possibly non-roundtrip primaries!";
411 cicpDescription.primaries = JXL_PRIMARIES_CUSTOM;
412 cicpDescription.primaries_red_xy[0] = colorants[0].x;
413 cicpDescription.primaries_red_xy[1] = colorants[0].y;
414 cicpDescription.primaries_green_xy[0] = colorants[1].x;
415 cicpDescription.primaries_green_xy[1] = colorants[1].y;
416 cicpDescription.primaries_blue_xy[0] = colorants[2].x;
417 cicpDescription.primaries_blue_xy[1] = colorants[2].y;
423 cicpDescription.white_point = JXL_WHITE_POINT_CUSTOM;
424 cicpDescription.white_point_xy[0] = whitePoint.
x;
425 cicpDescription.white_point_xy[1] = whitePoint.
y;
428 if (JXL_ENC_SUCCESS != JxlEncoderSetColorEncoding(enc.get(), &cicpDescription)) {
429 errFile <<
"JxlEncoderSetColorEncoding failed";
435 if (cfg->getBool(
"storeMetaData",
false)) {
436 auto metaDataStore = [&]() -> std::unique_ptr<KisMetaData::Store> {
440 return std::make_unique<KisMetaData::Store>(*exivInfoVisitor.
exifInfo());
441 }
else if (cfg->getBool(
"storeAuthor",
true)) {
442 return std::make_unique<KisMetaData::Store>();
448 if (metaDataStore && !metaDataStore->isEmpty()) {
458 if (cfg->getBool(
"storeAuthor",
true)) {
459 QString author = document->documentInfo()->authorInfo(
"creator");
460 if (!author.isEmpty()) {
461 if (!document->documentInfo()->authorContactInfo().isEmpty()) {
462 QString contact = document->documentInfo()->authorContactInfo().at(0);
463 if (!contact.isEmpty()) {
464 author = author +
"(" + contact +
")";
467 if (metaDataStore->containsEntry(
"creator")) {
468 metaDataStore->removeEntry(
"creator");
474 if (metaDataStore && cfg->getBool(
"exif",
true)) {
480 io->
saveTo(metaDataStore.get(), &ioDevice);
483 != JxlEncoderAddBox(enc.get(),
485 reinterpret_cast<const uint8_t *
>(ioDevice.data().constData()),
486 static_cast<size_t>(ioDevice.size()),
487 cfg->getBool(
"lossless") ? JXL_FALSE : JXL_TRUE)) {
488 errFile <<
"JxlEncoderAddBox for EXIF failed";
493 if (metaDataStore && cfg->getBool(
"xmp",
true)) {
499 io->
saveTo(metaDataStore.get(), &ioDevice);
502 != JxlEncoderAddBox(enc.get(),
504 reinterpret_cast<const uint8_t *
>(ioDevice.data().constData()),
505 static_cast<size_t>(ioDevice.size()),
506 cfg->getBool(
"lossless") ? JXL_FALSE : JXL_TRUE)) {
507 errFile <<
"JxlEncoderAddBox for XMP failed";
512 if (metaDataStore && cfg->getBool(
"iptc",
true)) {
518 io->
saveTo(metaDataStore.get(), &ioDevice);
521 != JxlEncoderAddBox(enc.get(),
523 reinterpret_cast<const uint8_t *
>(ioDevice.data().constData()),
524 static_cast<size_t>(ioDevice.size()),
525 cfg->getBool(
"lossless") ? JXL_FALSE : JXL_TRUE)) {
526 errFile <<
"JxlEncoderAddBox for IPTC failed";
532 auto *frameSettings = JxlEncoderFrameSettingsCreate(enc.get(),
nullptr);
534 const auto setFrameLossless = [&](
bool v) {
535 if (JxlEncoderSetFrameLossless(frameSettings,
v ? JXL_TRUE : JXL_FALSE) != JXL_ENC_SUCCESS) {
536 errFile <<
"JxlEncoderSetFrameLossless failed";
542 const auto setSetting = [&](JxlEncoderFrameSettingId id,
int v) {
544 if (
id == JXL_ENC_FRAME_SETTING_RESAMPLING &&
v == -1)
546 if (JxlEncoderFrameSettingsSetOption(frameSettings,
id,
v) != JXL_ENC_SUCCESS) {
547 errFile <<
"JxlEncoderFrameSettingsSetOption failed";
554 const auto setDistance = [&](
float v) {
555 const float distance = cfg->getBool(
"lossless") ? 0.0
556 :
v >= 30 ? 0.1 + (100 -
v) * 0.09
557 : 53.0 / 3000.0 *
v *
v - 23.0 / 20.0 *
v + 25.0;
559 if (JxlEncoderSetFrameDistance(frameSettings,
distance) != JXL_ENC_SUCCESS) {
560 errFile <<
"JxlEncoderSetFrameDistance failed";
563#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 9, 0)
565 if (!cfg->getBool(
"lossless")) {
566 if (cfg->getBool(
"losslessAlpha")) {
567 if (JxlEncoderSetExtraChannelDistance(frameSettings,
570 != JXL_ENC_SUCCESS) {
571 errFile <<
"JxlEncoderSetExtraChannelDistance failed";
575 if (JxlEncoderSetExtraChannelDistance(frameSettings,
578 != JXL_ENC_SUCCESS) {
579 errFile <<
"JxlEncoderSetExtraChannelDistance failed";
594 const int setResponsive = [&]() ->
int {
595 if (pixelFormat.data_type == JXL_TYPE_FLOAT && !cfg->getBool(
"lossless")) {
596 warnFile <<
"Using workaround for lossy 32-bit float, disabling progressive option";
599 return cfg->getInt(
"responsive", -1);
606 const int setPatches = [&]() ->
int {
607#if JPEGXL_NUMERIC_VERSION < JPEGXL_COMPUTE_NUMERIC_VERSION(0, 9, 0)
608 if ((cfg->getInt(
"effort", 7) > 4) && cfgFlattenLayer) {
609 warnFile <<
"Using workaround for layer exports, disabling patches option on effort > 4";
613 return cfg->getInt(
"patches", -1);
616 if (!setFrameLossless(cfg->getBool(
"lossless"))
617 || !setSetting(JXL_ENC_FRAME_SETTING_EFFORT, cfg->getInt(
"effort", 7))
618 || !setSetting(JXL_ENC_FRAME_SETTING_DECODING_SPEED, cfg->getInt(
"decodingSpeed", 0))
619 || !setSetting(JXL_ENC_FRAME_SETTING_RESAMPLING, cfg->getInt(
"resampling", -1))
620 || !setSetting(JXL_ENC_FRAME_SETTING_EXTRA_CHANNEL_RESAMPLING, cfg->getInt(
"extraChannelResampling", -1))
621 || !setSetting(JXL_ENC_FRAME_SETTING_DOTS, cfg->getInt(
"dots", -1))
622 || !setSetting(JXL_ENC_FRAME_SETTING_PATCHES, setPatches)
623 || !setSetting(JXL_ENC_FRAME_SETTING_EPF, cfg->getInt(
"epf", -1))
624 || !setSetting(JXL_ENC_FRAME_SETTING_GABORISH, cfg->getInt(
"gaborish", -1))
625 || !setSetting(JXL_ENC_FRAME_SETTING_MODULAR, cfg->getInt(
"modular", -1))
626 || !setSetting(JXL_ENC_FRAME_SETTING_KEEP_INVISIBLE, cfg->getInt(
"keepInvisible", -1))
627 || !setSetting(JXL_ENC_FRAME_SETTING_GROUP_ORDER, cfg->getInt(
"groupOrder", -1))
628 || !setSetting(JXL_ENC_FRAME_SETTING_RESPONSIVE, setResponsive)
629 || !setSetting(JXL_ENC_FRAME_SETTING_PROGRESSIVE_AC, cfg->getInt(
"progressiveAC", -1))
630 || !setSetting(JXL_ENC_FRAME_SETTING_QPROGRESSIVE_AC, cfg->getInt(
"qProgressiveAC", -1))
631 || !setSetting(JXL_ENC_FRAME_SETTING_PROGRESSIVE_DC, cfg->getInt(
"progressiveDC", -1))
632 || !setSetting(JXL_ENC_FRAME_SETTING_PALETTE_COLORS, cfg->getInt(
"paletteColors", -1))
633 || !setSetting(JXL_ENC_FRAME_SETTING_LOSSY_PALETTE, cfg->getInt(
"lossyPalette", -1))
634 || !setSetting(JXL_ENC_FRAME_SETTING_MODULAR_GROUP_SIZE, cfg->getInt(
"modularGroupSize", -1))
635 || !setSetting(JXL_ENC_FRAME_SETTING_MODULAR_PREDICTOR, cfg->getInt(
"modularPredictor", -1))
636 || !setSetting(JXL_ENC_FRAME_SETTING_JPEG_RECON_CFL, cfg->getInt(
"jpegReconCFL", -1))
637 || !setDistance(cfg->getInt(
"lossyQuality", 100))) {
643 const auto setSettingFloat = [&](JxlEncoderFrameSettingId id,
float v) {
644 if (JxlEncoderFrameSettingsSetFloatOption(frameSettings,
id,
v) != JXL_ENC_SUCCESS) {
645 errFile <<
"JxlEncoderFrameSettingsSetFloatOption failed";
651 if (!setSettingFloat(JXL_ENC_FRAME_SETTING_PHOTON_NOISE, cfg->getFloat(
"photonNoise", 0))
652 || !setSettingFloat(JXL_ENC_FRAME_SETTING_CHANNEL_COLORS_GLOBAL_PERCENT,
653 cfg->getFloat(
"channelColorsGlobalPercent", -1))
654 || !setSettingFloat(JXL_ENC_FRAME_SETTING_CHANNEL_COLORS_GROUP_PERCENT,
655 cfg->getFloat(
"channelColorsGroupPercent", -1))
656 || !setSettingFloat(JXL_ENC_FRAME_SETTING_MODULAR_MA_TREE_LEARNING_PERCENT,
657 cfg->getFloat(
"modularMATreeLearningPercent", -1))) {
663 const bool isAnimated = [&]() {
684 const auto times = [&]() {
686 QSet<int> s = frames->allKeyframeTimes();
688 std::sort(t.begin(), t.end());
692 auto frameHeader = []() {
693 auto header = std::make_unique<JxlFrameHeader>();
694 JxlEncoderInitFrameHeader(header.get());
699 for (
const auto i : times) {
700 frameHeader->duration = [&]() {
701 const auto nextKeyframe = frames->nextKeyframeTime(i);
702 if (nextKeyframe == -1) {
703 return static_cast<uint32_t
>(
707 return static_cast<uint32_t
>(frames->nextKeyframeTime(i) - i);
710 frameHeader->is_last = 0;
712 if (JxlEncoderSetFrameHeader(frameSettings, frameHeader.get()) != JXL_ENC_SUCCESS) {
713 errFile <<
"JxlEncoderSetFrameHeader failed";
717 const QByteArray pixels = [&]() {
721 frameData->writeFrameToDevice(dev);
729 dev->readBytes(
reinterpret_cast<quint8 *
>(
p.data()),
bounds);
750 if (JxlEncoderAddImageFrame(frameSettings,
753 static_cast<size_t>(pixels.size()))
754 != JXL_ENC_SUCCESS) {
755 errFile <<
"JxlEncoderAddImageFrame @" << i <<
"failed";
759#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 10, 1)
764 const int progress = (frameNum * 100) / times.size();
767 if (frames->nextKeyframeTime(i) == -1) {
768 JxlEncoderCloseInput(enc.get());
770 if (JxlEncoderFlushInput(enc.get()) != JXL_ENC_SUCCESS) {
771 errFile <<
"JxlEncoderFlushInput failed";
777 auto frameHeader = std::make_unique<JxlFrameHeader>();
781 quint32 lastValidLayer = 0;
782 if (cfgMultiLayer || cfgMultiPage) {
783 for (quint32 pos = 0; pos < image->
root()->childCount(); pos++) {
785 KisLayer *layer = qobject_cast<KisLayer *>(node.
data());
786 if (layer && (layer->inherits(
"KisGroupLayer") || layer->
childCount() > 0 || layer->
layerStyle())
792 lastValidLayer = pos;
799 for (quint32 pos = 0; pos < image->
root()->childCount(); pos++) {
802 if ((cfgMultiLayer || cfgMultiPage) && (!node || !node->
visible() || node->
isFakeNode())) {
803 dbgFile <<
"Skipping hidden layer" << node->
name();
808 if (cfgMultiLayer || cfgMultiPage) {
811 if (!node->inherits(
"KisPaintLayer")) {
813 node = convertedNode.get();
817 if (lcs && (lcs != cs)) {
822 dbgFile <<
"Saving flattened image";
825 const QRect layerBounds = [&]() {
826 if (node->
exactBounds().isEmpty() || cfgFlattenLayer) {
833 if (cfgFlattenLayer) {
846 f->process(dev, layerBounds, kfc->cloneWithResourcesSnapshot());
849 const QByteArray pixels = [&]() {
866 layerBounds.height(),
871 p.resize(layerBounds.width() * layerBounds.height() *
static_cast<int>(cs->
pixelSize()));
872 dev->
readBytes(
reinterpret_cast<quint8 *
>(
p.data()), layerBounds);
886 layerBounds.height(),
894 if (cfgMultiLayer || cfgMultiPage) {
895 JxlEncoderInitFrameHeader(frameHeader.get());
899 frameHeader->duration = 0;
900 }
else if (cfgMultiPage) {
901 frameHeader->duration = 0xFFFFFFFF;
907 frameHeader->layer_info.have_crop =
false;
909 frameHeader->layer_info.have_crop =
true;
911 frameHeader->layer_info.crop_x0 = layerBounds.x();
912 frameHeader->layer_info.crop_y0 = layerBounds.y();
913 frameHeader->layer_info.xsize = layerBounds.width();
914 frameHeader->layer_info.ysize = layerBounds.height();
917 frameHeader->layer_info.blend_info.alpha = 1;
919 frameHeader->layer_info.blend_info.alpha = 0;
924 const QString frameName = node->
name();
925 if (!isFirstLayer && cfgMultiLayer) {
927 frameHeader->layer_info.blend_info.blendmode = JXL_BLEND_MULADD;
929 frameHeader->layer_info.blend_info.blendmode = JXL_BLEND_BLEND;
933 if (JxlEncoderSetFrameHeader(frameSettings, frameHeader.get()) != JXL_ENC_SUCCESS) {
934 errFile <<
"JxlEncoderSetFrameHeader failed";
937 if (JxlEncoderSetFrameName(frameSettings, frameName.toLocal8Bit()) != JXL_ENC_SUCCESS) {
938 errFile <<
"JxlEncoderSetFrameName failed";
943 if (JxlEncoderAddImageFrame(frameSettings,
946 static_cast<size_t>(pixels.size()))
947 != JXL_ENC_SUCCESS) {
948 errFile <<
"JxlEncoderAddImageFrame failed";
961 layerBounds.height(),
968 layerBounds.height(),
971 if (JxlEncoderSetExtraChannelBuffer(frameSettings,
974 static_cast<size_t>(chaK.size()),
976 != JXL_ENC_SUCCESS) {
977 errFile <<
"JxlEncoderSetExtraChannelBuffer Key failed";
980 if (JxlEncoderSetExtraChannelBuffer(frameSettings,
983 static_cast<size_t>(chaA.size()),
985 != JXL_ENC_SUCCESS) {
986 errFile <<
"JxlEncoderSetExtraChannelBuffer Alpha failed";
991#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 10, 1)
998 if ((pos == lastValidLayer && (cfgMultiLayer || cfgMultiPage)) || cfgFlattenLayer) {
999 JxlEncoderCloseInput(enc.get());
1001 if (JxlEncoderFlushInput(enc.get()) != JXL_ENC_SUCCESS) {
1002 errFile <<
"JxlEncoderFlushInput failed";
1005 if (cfgFlattenLayer) {
1012 if (cfgFlattenLayer) {
1017 JxlEncoderCloseInput(enc.get());
1019 QByteArray compressed(16384, 0x0);
1020 auto *nextOut =
reinterpret_cast<uint8_t *
>(compressed.data());
1021 auto availOut =
static_cast<size_t>(compressed.size());
1022 auto result = JXL_ENC_NEED_MORE_OUTPUT;
1023 while (result == JXL_ENC_NEED_MORE_OUTPUT) {
1024 result = JxlEncoderProcessOutput(enc.get(), &nextOut, &availOut);
1025 if (result != JXL_ENC_ERROR) {
1026 io->write(compressed.data(), compressed.size() -
static_cast<int>(availOut));
1028 if (result == JXL_ENC_NEED_MORE_OUTPUT) {
1029 compressed.resize(compressed.size() * 2);
1030 nextOut =
reinterpret_cast<uint8_t *
>(compressed.data());
1031 availOut =
static_cast<size_t>(compressed.size());
1034 if (JXL_ENC_SUCCESS != result) {
1035 errFile <<
"JxlEncoderProcessOutput failed";