Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_heif_export_tools.h
Go to the documentation of this file.
1
8#ifndef KIS_HEIF_EXPORT_TOOLS_H
9#define KIS_HEIF_EXPORT_TOOLS_H
10
11#include <cstdint>
12
14#include <KoColorProfile.h>
15#include <KoColorSpace.h>
16#include <KoColorSpaceTraits.h>
18#include <kis_iterator_ng.h>
19
20namespace Gray
21{
22template<int endValue0, int endValue1, int luma>
23inline void
24applyValue(const quint8 *data, uint8_t *ptrG, int strideG, int x, int y)
25{
26 if (luma == 8) {
27 ptrG[y * strideG + x] = KoGrayU8Traits::gray(data);
28 } else {
29 uint16_t v = qBound<uint16_t>(
30 0,
31 static_cast<uint16_t>(float(KoGrayU16Traits::gray(data))
33 max12bit);
34 ptrG[(x * 2) + y * strideG + endValue0] = static_cast<uint8_t>(v >> 8);
35 ptrG[(x * 2) + y * strideG + endValue1] =
36 static_cast<uint8_t>(v & 0xFF);
37 }
38}
39
40template<int endValue0, int endValue1, int luma, bool hasAlpha>
41inline void
42applyAlpha(const quint8 *data, uint8_t *ptrA, const int strideA, int x, int y)
43{
44 if (hasAlpha) {
45 if (luma == 8) {
46 ptrA[y * strideA + x] = KoGrayU8Traits::opacityU8(data);
47 } else {
48 uint16_t vA = qBound<uint16_t>(
49 0,
50 static_cast<uint16_t>(KoGrayU16Traits::opacityF(data)
51 * max12bit),
52 max12bit);
53 ptrA[(x * 2) + y * strideA + endValue0] = (uint8_t)(vA >> 8);
54 ptrA[(x * 2) + y * strideA + endValue1] = (uint8_t)(vA & 0xFF);
55 }
56 }
57}
58
59template<int endValue0, int endValue1, int luma, bool hasAlpha>
60inline void writeLayer(const int width,
61 const int height,
62 uint8_t *ptrG,
63 const int strideG,
64 uint8_t *ptrA,
65 const int strideA,
67{
68 for (int y = 0; y < height; y++) {
69 for (int x = 0; x < width; x++) {
70 const uint8_t *data = it->rawDataConst();
71
72 applyValue<endValue0, endValue1, luma>(data, ptrG, strideG, x, y);
73
74 applyAlpha<endValue0, endValue1, luma, hasAlpha>(data,
75 ptrA,
76 strideA,
77 x,
78 y);
79
80 it->nextPixel();
81 }
82
83 it->nextRow();
84 }
85}
86
87template<int endValue0, int endValue1, int luma, typename... Args>
88inline auto writePlanarWithAlpha(bool hasAlpha, Args &&...args)
89{
90 if (hasAlpha) {
91 return Gray::writeLayer<endValue0, endValue1, luma, true>(
92 std::forward<Args>(args)...);
93 } else {
94 return Gray::writeLayer<endValue0, endValue1, luma, false>(
95 std::forward<Args>(args)...);
96 }
97}
98
99template<int endValue0, int endValue1, typename... Args>
100inline auto writePlanarWithLuma(const int luma, Args &&...args)
101{
102 if (luma == 8) {
103 return writePlanarWithAlpha<endValue0, endValue1, 8>(
104 std::forward<Args>(args)...);
105 } else {
106 return writePlanarWithAlpha<endValue0, endValue1, 12>(
107 std::forward<Args>(args)...);
108 }
109}
110
111template<typename... Args>
112inline auto writePlanarLayer(QSysInfo::Endian endian, Args &&...args)
113{
114 if (endian == QSysInfo::LittleEndian) {
115 return Gray::writePlanarWithLuma<1, 0>(std::forward<Args>(args)...);
116 } else {
117 return Gray::writePlanarWithLuma<0, 1>(std::forward<Args>(args)...);
118 }
119}
120} // namespace Gray
121
122namespace Planar
123{
124template<bool hasAlpha>
125inline void writeLayerImpl(const int width,
126 const int height,
127 uint8_t *ptrR,
128 const int strideR,
129 uint8_t *ptrG,
130 const int strideG,
131 uint8_t *ptrB,
132 const int strideB,
133 uint8_t *ptrA,
134 const int strideA,
136{
137 for (int y = 0; y < height; y++) {
138 for (int x = 0; x < width; x++) {
139 const quint8 *data = it->rawDataConst();
140 ptrR[y * strideR + x] = KoBgrU8Traits::red(data);
141 ptrG[y * strideG + x] = KoBgrU8Traits::green(data);
142 ptrB[y * strideB + x] = KoBgrU8Traits::blue(data);
143
144 // If we already employ KoBgrU8Traits to access the iterator,
145 // we can use it for the opacity too. -amyspark
146 if (hasAlpha) {
147 ptrA[y * strideA + x] = KoBgrU8Traits::opacityU8(data);
148 }
149
150 it->nextPixel();
151 }
152
153 it->nextRow();
154 }
155}
156
157template<typename... Args>
158inline auto writeLayer(bool hasAlpha, Args &&...args)
159{
160 if (hasAlpha) {
161 return Planar::writeLayerImpl<true>(std::forward<Args>(args)...);
162 } else {
163 return Planar::writeLayerImpl<false>(std::forward<Args>(args)...);
164 }
165}
166} // namespace Planar
167
168namespace HDRInt
169{
170template<int endValue0, int endValue1, int channels>
171inline void writeLayerImpl(const int width,
172 const int height,
173 uint8_t *ptr,
174 const int stride,
176{
177 std::array<KoBgrU16Traits::channels_type, channels> pixelValues{};
178
179 for (int y = 0; y < height; y++) {
180 for (int x = 0; x < width; x++) {
181 const quint8 *data = it->rawDataConst();
182 pixelValues[0] = KoBgrU16Traits::red(data);
183 pixelValues[1] = KoBgrU16Traits::green(data);
184 pixelValues[2] = KoBgrU16Traits::blue(data);
185 if (channels == 4) {
186 pixelValues[3] = static_cast<KoBgrU16Traits::channels_type>(
188 }
189
190 for (int ch = 0; ch < channels; ch++) {
191 uint16_t v = qBound<uint16_t>(
192 0,
193 static_cast<uint16_t>(float(pixelValues[ch])
195 max12bit);
196 ptr[2 * (x * channels) + y * stride + endValue0 + (ch * 2)] =
197 static_cast<uint8_t>(v >> 8);
198 ptr[2 * (x * channels) + y * stride + endValue1 + (ch * 2)] =
199 static_cast<uint8_t>(v & 0xFF);
200 }
201
202 it->nextPixel();
203 }
204
205 it->nextRow();
206 }
207}
208
209template<int endValue0, int endValue1, typename... Args>
210inline auto writeInterleavedWithAlpha(bool hasAlpha, Args &&...args)
211{
212 if (hasAlpha) {
213 return HDRInt::writeLayerImpl<endValue0, endValue1, 4>(
214 std::forward<Args>(args)...);
215 } else {
216 return HDRInt::writeLayerImpl<endValue0, endValue1, 3>(
217 std::forward<Args>(args)...);
218 }
219}
220
221template<typename... Args>
222inline auto writeInterleavedLayer(QSysInfo::Endian endian, Args &&...args)
223{
224 if (endian == QSysInfo::LittleEndian) {
225 return writeInterleavedWithAlpha<1, 0>(std::forward<Args>(args)...);
226 } else {
227 return writeInterleavedWithAlpha<0, 1>(std::forward<Args>(args)...);
228 }
229}
230} // namespace HDRInt
231
232namespace HDRFloat
233{
234
235template<ConversionPolicy policy>
236inline float applyCurveAsNeeded(float value)
237{
238 if (policy == ConversionPolicy::ApplyPQ) {
240 } else if (policy == ConversionPolicy::ApplyHLG) {
241 return applyHLGCurve(value);
242 } else if (policy == ConversionPolicy::ApplySMPTE428) {
244 }
245 return value;
246}
247
248template<typename CSTrait,
249 QSysInfo::Endian endianness,
250 int channels,
251 bool convertToRec2020,
252 bool isLinear,
253 ConversionPolicy conversionPolicy,
254 bool removeOOTF>
255inline void writeFloatLayerImpl(const int width,
256 const int height,
257 uint8_t *ptr,
258 const int stride,
260 float hlgGamma,
261 float hlgNominalPeak,
262 const KoColorSpace *cs)
263{
264 const int endValue0 = endianness == QSysInfo::LittleEndian ? 1 : 0;
265 const int endValue1 = endianness == QSysInfo::LittleEndian ? 0 : 1;
266 QVector<float> pixelValues(4);
267 QVector<qreal> pixelValuesLinear(4);
268 const KoColorProfile *profile = cs->profile();
269 const QVector<qreal> lCoef{cs->lumaCoefficients()};
270 double *src = pixelValuesLinear.data();
271 float *dst = pixelValues.data();
272
273 for (int y = 0; y < height; y++) {
274 for (int x = 0; x < width; x++) {
275 CSTrait::normalisedChannelsValue(it->rawDataConst(), pixelValues);
276 if (!convertToRec2020 && !isLinear) {
277 for (int i = 0; i < 4; i++) {
278 src[i] = static_cast<double>(dst[i]);
279 }
280 profile->linearizeFloatValue(pixelValuesLinear);
281 for (int i = 0; i < 4; i++) {
282 dst[i] = static_cast<float>(src[i]);
283 }
284 }
285
286 if (conversionPolicy == ConversionPolicy::ApplyHLG && removeOOTF) {
287 removeHLGOOTF(dst, lCoef.constData(), hlgGamma, hlgNominalPeak);
288 }
289
290 for (int ch = 0; ch < channels; ch++) {
291 uint16_t v = 0;
292 if (ch == CSTrait::alpha_pos) {
293 v = qBound<uint16_t>(
294 0,
295 static_cast<uint16_t>(
296 applyCurveAsNeeded<ConversionPolicy::KeepTheSame>(
297 dst[ch])
298 * max12bit),
299 max12bit);
300 } else {
301 v = qBound<uint16_t>(
302 0,
303 static_cast<uint16_t>(
304 applyCurveAsNeeded<conversionPolicy>(dst[ch])
305 * max12bit),
306 max12bit);
307 }
308 ptr[2 * (x * channels) + y * stride + endValue0 + (ch * 2)] =
309 (uint8_t)(v >> 8);
310 ptr[2 * (x * channels) + y * stride + endValue1 + (ch * 2)] =
311 (uint8_t)(v & 0xFF);
312 }
313
314 it->nextPixel();
315 }
316
317 it->nextRow();
318 }
319}
320template<typename CSTrait,
321 QSysInfo::Endian endianness,
322 int channels,
323 bool convertToRec2020,
324 bool isLinear,
325 ConversionPolicy linearizePolicy,
326 typename... Args>
327inline auto writeInterleavedWithPolicy(bool removeOOTF, Args &&...args)
328{
329 if (removeOOTF) {
330 return writeFloatLayerImpl<CSTrait,
331 endianness,
332 channels,
333 convertToRec2020,
334 isLinear,
335 linearizePolicy,
336 true>(std::forward<Args>(args)...);
337 } else {
338 return writeFloatLayerImpl<CSTrait,
339 endianness,
340 channels,
341 convertToRec2020,
342 isLinear,
343 linearizePolicy,
344 false>(std::forward<Args>(args)...);
345 }
346}
347
348template<typename CSTrait,
349 QSysInfo::Endian endianness,
350 int channels,
351 bool convertToRec2020,
352 bool isLinear,
353 typename... Args>
355 Args &&...args)
356{
357 if (linearizePolicy == ConversionPolicy::ApplyHLG) {
358 return writeInterleavedWithPolicy<CSTrait,
359 endianness,
360 channels,
361 convertToRec2020,
362 isLinear,
363 ConversionPolicy::ApplyHLG>(std::forward<Args>(args)...);
364 } else if (linearizePolicy == ConversionPolicy::ApplyPQ) {
365 return writeInterleavedWithPolicy<CSTrait,
366 endianness,
367 channels,
368 convertToRec2020,
369 isLinear,
370 ConversionPolicy::ApplyPQ>(std::forward<Args>(args)...);
371 } else if (linearizePolicy == ConversionPolicy::ApplySMPTE428) {
372 return writeInterleavedWithPolicy<CSTrait,
373 endianness,
374 channels,
375 convertToRec2020,
376 isLinear,
377 ConversionPolicy::ApplySMPTE428>(std::forward<Args>(args)...);
378 } else {
379 return writeInterleavedWithPolicy<CSTrait,
380 endianness,
381 channels,
382 convertToRec2020,
383 isLinear,
384 ConversionPolicy::KeepTheSame>(std::forward<Args>(args)...);
385 }
386}
387
388template<typename CSTrait,
389 QSysInfo::Endian endianness,
390 int channels,
391 bool convertToRec2020,
392 typename... Args>
393inline auto writeInterleavedWithRec2020(bool isLinear, Args &&...args)
394{
395 if (isLinear) {
396 return writeInterleavedWithLinear<CSTrait,
397 endianness,
398 channels,
399 convertToRec2020,
400 true>(std::forward<Args>(args)...);
401 } else {
402 return writeInterleavedWithLinear<CSTrait,
403 endianness,
404 channels,
405 convertToRec2020,
406 false>(std::forward<Args>(args)...);
407 }
408}
409
410template<typename CSTrait,
411 QSysInfo::Endian endianness,
412 int channels,
413 typename... Args>
414inline auto writeInterleavedWithAlpha(bool convertToRec2020, Args &&...args)
415{
416 if (convertToRec2020) {
417 return writeInterleavedWithRec2020<CSTrait, endianness, channels, true>(
418 std::forward<Args>(args)...);
419 } else {
420 return writeInterleavedWithRec2020<CSTrait,
421 endianness,
422 channels,
423 false>(std::forward<Args>(args)...);
424 }
425}
426
427template<typename CSTrait, QSysInfo::Endian endianness, typename... Args>
428inline auto writeInterleavedWithEndian(bool hasAlpha, Args &&...args)
429{
430 if (hasAlpha) {
431 return writeInterleavedWithAlpha<CSTrait, endianness, 4>(
432 std::forward<Args>(args)...);
433 } else {
434 return writeInterleavedWithAlpha<CSTrait, endianness, 3>(
435 std::forward<Args>(args)...);
436 }
437}
438
439template<typename CSTrait, typename... Args>
440inline auto writeInterleavedWithDepth(QSysInfo::Endian endian, Args &&...args)
441{
442 if (endian == QSysInfo::LittleEndian) {
443 return writeInterleavedWithEndian<CSTrait, QSysInfo::LittleEndian>(
444 std::forward<Args>(args)...);
445 } else {
446 return writeInterleavedWithEndian<CSTrait, QSysInfo::BigEndian>(
447 std::forward<Args>(args)...);
448 }
449}
450
451template<typename... Args>
452inline auto writeInterleavedLayer(const KoID &id, Args &&...args)
453{
454#ifdef HAVE_OPENEXR
455 if (id == Float16BitsColorDepthID) {
456 return writeInterleavedWithDepth<KoBgrF16Traits>(
457 std::forward<Args>(args)...);
458 } else
459#else
460 Q_UNUSED(id);
461#endif
462 {
463 return writeInterleavedWithDepth<KoBgrF32Traits>(
464 std::forward<Args>(args)...);
465 }
466}
467} // namespace HDRFloat
468
469#endif // KIS_HEIF_EXPORT_TOOLS_H
float value(const T *src, size_t ch)
qreal v
const KoID Float16BitsColorDepthID("F16", ki18n("16-bit float/channel"))
ALWAYS_INLINE void removeHLGOOTF(float *rgb, const double *lumaCoefficients, float gamma=1.2f, float nominalPeak=1000.0f) noexcept
static constexpr float max16bit
static constexpr uint16_t max12bit
static constexpr float multiplier16bit
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
virtual void nextRow()=0
QVector< qreal > lumaCoefficients
virtual const KoColorProfile * profile() const =0
Definition KoID.h:30
void applyValue(const quint8 *data, uint8_t *ptrG, int strideG, int x, int y)
auto writePlanarWithAlpha(bool hasAlpha, Args &&...args)
void applyAlpha(const quint8 *data, uint8_t *ptrA, const int strideA, int x, int y)
void writeLayer(const int width, const int height, uint8_t *ptrG, const int strideG, uint8_t *ptrA, const int strideA, KisHLineConstIteratorSP it)
auto writePlanarLayer(QSysInfo::Endian endian, Args &&...args)
auto writePlanarWithLuma(const int luma, Args &&...args)
auto writeInterleavedWithEndian(bool hasAlpha, Args &&...args)
auto writeInterleavedWithLinear(ConversionPolicy linearizePolicy, Args &&...args)
float applyCurveAsNeeded(float value)
auto writeInterleavedWithPolicy(bool removeOOTF, Args &&...args)
auto writeInterleavedWithRec2020(bool isLinear, Args &&...args)
auto writeInterleavedLayer(const KoID &id, Args &&...args)
auto writeInterleavedWithAlpha(bool convertToRec2020, Args &&...args)
void writeFloatLayerImpl(const int width, const int height, uint8_t *ptr, const int stride, KisHLineConstIteratorSP it, float hlgGamma, float hlgNominalPeak, const KoColorSpace *cs)
auto writeInterleavedWithDepth(QSysInfo::Endian endian, Args &&...args)
auto writeInterleavedLayer(QSysInfo::Endian endian, Args &&...args)
void writeLayerImpl(const int width, const int height, uint8_t *ptr, const int stride, KisHLineConstIteratorSP it)
auto writeInterleavedWithAlpha(bool hasAlpha, Args &&...args)
auto writeLayer(bool hasAlpha, Args &&...args)
void writeLayerImpl(const int width, const int height, uint8_t *ptrR, const int strideR, uint8_t *ptrG, const int strideG, uint8_t *ptrB, const int strideB, uint8_t *ptrA, const int strideA, KisHLineConstIteratorSP it)
static channels_type blue(const quint8 *data)
static channels_type green(const quint8 *data)
static channels_type red(const quint8 *data)
virtual void linearizeFloatValue(QVector< qreal > &Value) const =0
static quint8 opacityU8(const quint8 *U8_pixel)
_channels_type_ channels_type
the type of the value of the channels of this color space
static qreal opacityF(const quint8 *U8_pixel)
static channels_type gray(const quint8 *data)