12#ifndef KIS_JPEGXL_EXPORT_TOOLS_H
13#define KIS_JPEGXL_EXPORT_TOOLS_H
24#include <jxl/encode_cxx.h>
28template<
typename CSTrait>
32 const int channels = isTrichromatic ? 3 : 1;
33 const int chSize =
static_cast<int>(CSTrait::pixelSize / 5);
34 const int pxSize = chSize * channels;
35 const int chOffset = chPos * chSize;
38 res.resize(width * height * pxSize);
40 quint8 *ptr =
reinterpret_cast<quint8 *
>(res.data());
42 for (
int y = 0; y < height; y++) {
43 for (
int x = 0; x < width; x++) {
47 for (
int i = 0; i < channels; i++) {
48 std::memcpy(ptr, src + (i * chSize), chSize);
52 std::memcpy(ptr, src + chOffset, chSize);
64template<
typename... Args>
68 return writeCMYKPixels<KoCmykU8Traits>(std::forward<Args>(args)...);
70 return writeCMYKPixels<KoCmykU16Traits>(std::forward<Args>(args)...);
73 return writeCMYKPixels<KoCmykF16Traits>(std::forward<Args>(args)...);
76 return writeCMYKPixels<KoCmykF32Traits>(std::forward<Args>(args)...);
78 KIS_ASSERT_X(
false,
"JPEGXLExport::writeLayer",
"unsupported bit depth!");
89#if JPEGXL_NUMERIC_VERSION >= JPEGXL_COMPUTE_NUMERIC_VERSION(0, 10, 1)
99 *size = std::min<size_t>(*size, 1u << 16);
100 if (
static_cast<size_t>(self->
output.size()) < *size) {
101 self->
output.resize(*size);
103 return self->
output.data();
110 if (
static_cast<size_t>(
111 self->
outDevice->write(
reinterpret_cast<const char *
>(self->
output.data()), written_bytes))
113 warnFile <<
"Failed to write" << written_bytes <<
"bytes to output";
116 warnFile <<
"ReleaseBuffer failed, file not open";
121 static void seek(
void *opaque, uint64_t position)
127 warnFile <<
"Seek failed, file not open";
145template<ConversionPolicy policy>
158template<
typename CSTrait,
160 bool convertToRec2020,
169 float hlgNominalPeak,
172 const int channels =
static_cast<int>(CSTrait::channels_nb);
177 double *src = pixelValuesLinear.data();
178 float *dst = pixelValues.data();
181 res.resize(width * height *
static_cast<int>(DestTrait::pixelSize));
183 quint8 *ptr =
reinterpret_cast<quint8 *
>(res.data());
185 for (
int y = 0; y < height; y++) {
186 for (
int x = 0; x < width; x++) {
187 CSTrait::normalisedChannelsValue(it->
rawDataConst(), pixelValues);
188 if (!convertToRec2020 && !isLinear) {
189 for (
int i = 0; i < channels; i++) {
190 src[i] =
static_cast<double>(dst[i]);
193 for (
int i = 0; i < channels; i++) {
194 dst[i] =
static_cast<float>(src[i]);
199 removeHLGOOTF(dst, lCoef.constData(), hlgGamma, hlgNominalPeak);
202 for (
int ch = 0; ch < channels; ch++) {
203 if (ch == CSTrait::alpha_pos) {
204 dst[ch] = applyCurveAsNeeded<ConversionPolicy::KeepTheSame>(
207 dst[ch] = applyCurveAsNeeded<conversionPolicy>(dst[ch]);
212 std::swap(dst[0], dst[2]);
215 DestTrait::fromNormalisedChannelsValue(ptr, pixelValues);
217 ptr += DestTrait::pixelSize;
228template<
typename CSTrait,
bool swap>
233 float hlgNominalPeak,
237 Q_UNUSED(hlgNominalPeak);
240 const int channels =
static_cast<int>(CSTrait::channels_nb);
245 res.resize(width * height *
static_cast<int>(CSTrait::pixelSize));
247 quint8 *ptr =
reinterpret_cast<quint8 *
>(res.data());
249 for (
int y = 0; y < height; y++) {
250 for (
int x = 0; x < width; x++) {
251 auto *dst =
reinterpret_cast<typename CSTrait::channels_type *
>(ptr);
253 std::memcpy(dst, it->
rawDataConst(), CSTrait::pixelSize);
256 std::swap(dst[0], dst[2]);
259 ptr += CSTrait::pixelSize;
270template<
typename CSTrait,
272 bool convertToRec2020,
281 return writeLayer<CSTrait, swap, convertToRec2020, isLinear, linearizePolicy, DestTrait, removeOOTF>(
282 std::forward<Args>(args)...);
284 return writeLayerNoConversion<CSTrait, swap>(std::forward<Args>(args)...);
288template<
typename CSTrait,
290 bool convertToRec2020,
298 return writeLayerSimplify<CSTrait, swap, convertToRec2020, isLinear, linearizePolicy, DestTrait, true>(
299 std::forward<Args>(args)...);
301 return writeLayerSimplify<CSTrait, swap, convertToRec2020, isLinear, linearizePolicy, DestTrait, false>(
302 std::forward<Args>(args)...);
306template<
typename CSTrait,
bool swap,
bool convertToRec2020,
bool isLinear,
typename... Args>
331 return writeLayerWithPolicy<CSTrait, swap, convertToRec2020, isLinear, ConversionPolicy::KeepTheSame, CSTrait>(
332 std::forward<Args>(args)...);
336template<
typename CSTrait,
bool swap,
bool convertToRec2020,
typename... Args>
340 return writeLayerWithLinear<CSTrait, swap, convertToRec2020, true>(std::forward<Args>(args)...);
342 return writeLayerWithLinear<CSTrait, swap, convertToRec2020, false>(std::forward<Args>(args)...);
346template<
typename CSTrait,
bool swap,
typename... Args>
349 if (convertToRec2020) {
350 return writeLayerWithRec2020<CSTrait, swap, true>(std::forward<Args>(args)...);
352 return writeLayerWithRec2020<CSTrait, swap, false>(std::forward<Args>(args)...);
356template<
typename... Args>
360 return writeLayerWithSwap<KoBgrU8Traits, true>(std::forward<Args>(args)...);
362 return writeLayerWithSwap<KoBgrU16Traits, true>(std::forward<Args>(args)...);
365 return writeLayerWithSwap<KoBgrF16Traits, false>(std::forward<Args>(args)...);
368 return writeLayerWithSwap<KoBgrF32Traits, false>(std::forward<Args>(args)...);
370 KIS_ASSERT_X(
false,
"JPEGXLExport::writeLayer",
"unsupported bit depth!");
float value(const T *src, size_t ch)
const KoID Float32BitsColorDepthID("F32", ki18n("32-bit float/channel"))
const KoID Float16BitsColorDepthID("F16", ki18n("16-bit float/channel"))
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const KoID Integer16BitsColorDepthID("U16", ki18n("16-bit integer/channel"))
ALWAYS_INLINE void removeHLGOOTF(float *rgb, const double *lumaCoefficients, float gamma=1.2f, float nominalPeak=1000.0f) noexcept
ALWAYS_INLINE float applySmpte2048Curve(float x) noexcept
ALWAYS_INLINE float applySMPTE_ST_428Curve(float x) noexcept
ALWAYS_INLINE float applyHLGCurve(float x) noexcept
virtual const quint8 * rawDataConst() const =0
virtual bool nextPixel()=0
QVector< qreal > lumaCoefficients
virtual const KoColorProfile * profile() const =0
#define KIS_ASSERT_X(cond, where, what)
ALWAYS_INLINE auto writeLayerWithPolicy(bool removeOOTF, Args &&...args)
ALWAYS_INLINE auto writeLayerSimplify(Args &&...args)
ALWAYS_INLINE auto writeLayerWithRec2020(bool isLinear, Args &&...args)
QByteArray writeLayerNoConversion(const int width, const int height, KisHLineConstIteratorSP it, float hlgGamma, float hlgNominalPeak, const KoColorSpace *cs)
ALWAYS_INLINE auto writeLayerWithLinear(ConversionPolicy linearizePolicy, Args &&...args)
ALWAYS_INLINE auto writeLayerWithSwap(bool convertToRec2020, Args &&...args)
ALWAYS_INLINE float applyCurveAsNeeded(float value)
QByteArray writeLayer(const int width, const int height, KisHLineConstIteratorSP it, float hlgGamma, float hlgNominalPeak, const KoColorSpace *cs)
virtual void linearizeFloatValue(QVector< qreal > &Value) const =0