Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_tiff_ycbcr_reader.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006 Cyrille Berger <cberger@cberger.net>
3 * SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8#ifndef _KIS_TIFF_YCBCR_READER_H_
9#define _KIS_TIFF_YCBCR_READER_H_
10
11#include <cmath>
12#include <cstdint>
13#include <memory>
14
15#include <QSharedPointer>
16
17#include <kis_buffer_stream.h>
18#include <kis_global.h>
19#include <kis_iterator_ng.h>
20#include <kis_paint_device.h>
21
22#include "kis_tiff_reader.h"
23
24namespace KisTIFFYCbCr
25{
27}
28
29template<typename T> class KisTIFFYCbCrReader : public KisTIFFReaderBase
30{
31public:
32 using type = T;
33
39 quint32 width,
40 quint32 height,
41 const std::array<quint8, 5> &poses,
42 int32_t alphapos,
43 uint16_t sourceDepth,
44 uint16_t sampleformat,
45 uint16_t nbcolorssamples,
46 uint16_t extrasamplescount,
47 bool premultipliedAlpha,
48 KoColorTransformation *transformProfile,
50 uint16_t hsub,
51 uint16_t vsub)
52 : KisTIFFReaderBase(device,
53 poses,
54 alphapos,
56 sampleformat,
57 nbcolorssamples,
58 extrasamplescount,
59 premultipliedAlpha,
60 transformProfile,
61 postprocessor)
62 , m_hsub(hsub)
63 , m_vsub(vsub)
64 , m_imageWidth(width)
65 {
66 // Initialize the buffer
67 if (2 * (m_imageWidth / 2) != m_imageWidth)
70 m_imageHeight = height;
71 if (2 * (m_imageHeight / 2) != m_imageHeight)
74 m_bufferCb = std::make_unique<T[]>(m_bufferWidth * m_bufferHeight);
75 m_bufferCr = std::make_unique<T[]>(m_bufferWidth * m_bufferHeight);
76 }
77
78 ~KisTIFFYCbCrReader() override = default;
79
80 uint32_t
82 quint32 y,
83 quint32 dataWidth,
84 QSharedPointer<KisBufferStreamBase> tiffstream) override
85 {
86 return copyDataToChannelsImpl(x, y, dataWidth, tiffstream);
87 }
88
89 void finalize() override
90 {
91 return finalizeImpl();
92 }
93
94private:
95 template<typename U = T,
96 typename std::enable_if<!std::numeric_limits<U>::is_integer,
97 void>::type * = nullptr>
98 uint32_t
100 quint32 y,
101 quint32 dataWidth,
103 {
104 quint32 numcols = dataWidth / m_hsub;
105 quint32 buffPos = y / m_vsub * m_bufferWidth + x / m_hsub;
106 for (quint32 index = 0; index < numcols; index++) {
108 for (int vindex = 0; vindex < m_vsub; vindex++) {
109 do {
110 T *d = reinterpret_cast<T *>(it->rawData());
111 d[0] = static_cast<T>(tiffstream->nextValue());
112 d[3] = std::numeric_limits<T>::max();
113 for (int k = 0; k < nbExtraSamples(); k++) {
114 if (k == alphaPos())
115 d[3] = static_cast<T>(tiffstream->nextValue());
116 else
117 tiffstream->nextValue();
118 }
119 } while (it->nextPixel());
120 it->nextRow();
121 }
122 m_bufferCb[buffPos] = static_cast<T>(tiffstream->nextValue());
123 m_bufferCr[buffPos] = static_cast<T>(tiffstream->nextValue());
124 buffPos++;
125 }
126 return m_vsub;
127 }
128
129 template<typename U = T,
130 typename std::enable_if<std::numeric_limits<U>::is_integer,
131 void>::type * = nullptr>
132 uint32_t
134 quint32 y,
135 quint32 dataWidth,
137 {
138 quint32 numcols = dataWidth / m_hsub;
139 double coeff = std::numeric_limits<T>::max() / (double)(std::pow(2.0, this->sourceDepth()) - 1);
140 // dbgFile <<" depth expansion coefficient :" << coeff;
141 // dbgFile <<" y =" << y;
142 size_t buffPos = y / m_vsub * m_bufferWidth + x / m_hsub;
143 for (quint32 index = 0; index < numcols; index++) {
145 for (int vindex = 0; vindex < m_vsub; vindex++) {
146 do {
147 T *d = reinterpret_cast<T *>(it->rawData());
148 d[0] = static_cast<T>(tiffstream->nextValue() * coeff);
149 d[3] = std::numeric_limits<T>::max();
150 for (int k = 0; k < nbExtraSamples(); k++) {
151 if (k == alphaPos())
152 d[3] = static_cast<T>(tiffstream->nextValue() * coeff);
153 else
154 tiffstream->nextValue();
155 }
156 } while (it->nextPixel());
157 it->nextRow();
158 }
159 m_bufferCb[buffPos] = static_cast<T>(tiffstream->nextValue() * coeff);
160 m_bufferCr[buffPos] = static_cast<T>(tiffstream->nextValue() * coeff);
161 buffPos++;
162 }
163 return m_vsub;
164 }
165
166 template<typename U = T, typename std::enable_if<!std::numeric_limits<U>::is_integer, void>::type * = nullptr> void finalizeImpl()
167 {
169 for (size_t y = 0; y < m_imageHeight; y++) {
170 size_t x = 0;
171 do {
172 T *d = reinterpret_cast<T *>(it->rawData());
173 size_t index = x / m_hsub + y / m_vsub * m_bufferWidth;
174 d[1] = m_bufferCb[index];
175 d[2] = m_bufferCr[index];
176 ++x;
177
178 if (this->hasPremultipliedAlpha()) {
179 auto unmultipliedColorsConsistent = [](T *d) { return !(std::abs(d[3]) < std::numeric_limits<T>::epsilon()); };
180
181 auto checkUnmultipliedColorsConsistent = [this](const T *d) {
182 const T alpha = std::abs(d[3]);
183
184 if (alpha >= static_cast<T>(0.01)) {
185 return true;
186 } else {
187 for (size_t i = 0; i < this->nbColorsSamples(); i++) {
188 if (!qFuzzyCompare(T(d[i] * alpha), d[i])) {
189 return false;
190 }
191 }
192 return true;
193 }
194 };
195
196 if (!unmultipliedColorsConsistent(d)) {
197 while (1) {
198 T newAlpha = d[3];
199
200 for (quint8 i = 0; i < this->nbColorsSamples(); i++) {
201 d[i] = std::lroundf(d[i] * newAlpha);
202 }
203
204 d[3] = newAlpha;
205
206 if (checkUnmultipliedColorsConsistent(d)) {
207 break;
208 }
209
210 newAlpha += std::numeric_limits<T>::epsilon();
211 }
212 } else {
213 const T alpha = d[3];
214 for (quint8 i = 0; i < this->nbColorsSamples(); i++) {
215 d[i] = std::lroundf(d[i] * alpha);
216 }
217 }
218 }
219 } while (it->nextPixel());
220 it->nextRow();
221 }
222 }
223
224 template<typename U = T, typename std::enable_if<std::numeric_limits<U>::is_integer, void>::type * = nullptr> void finalizeImpl()
225 {
227 for (size_t y = 0; y < m_imageHeight; y++) {
228 size_t x = 0;
229 do {
230 T *d = reinterpret_cast<T *>(it->rawData());
231 size_t index = x / m_hsub + y / m_vsub * m_bufferWidth;
232 d[1] = m_bufferCb[index];
233 d[2] = m_bufferCr[index];
234 ++x;
235
236 if (this->hasPremultipliedAlpha()) {
237 const T alpha = d[3];
238 const float factor = alpha == 0 ? 0 : static_cast<float>(std::numeric_limits<T>::max()) / alpha;
239
240 for (quint8 i = 0; i < this->nbColorsSamples(); i++) {
241 d[i] = std::lroundf(d[i] * factor);
242 }
243 }
244 } while (it->nextPixel());
245 it->nextRow();
246 }
247 }
248
249private:
250 std::unique_ptr<T[]> m_bufferCb;
251 std::unique_ptr<T[]> m_bufferCr;
253 uint16_t m_hsub;
254 uint16_t m_vsub;
256};
257
258#endif
KisHLineIteratorSP createHLineIteratorNG(qint32 x, qint32 y, qint32 w)
const std::array< quint8, 5 > & poses() const
qint32 alphaPos() const
quint16 nbExtraSamples() const
quint16 nbColorsSamples() const
KisPaintDeviceSP paintDevice() const
bool hasPremultipliedAlpha() const
quint16 sourceDepth() const
~KisTIFFYCbCrReader() override=default
std::unique_ptr< T[]> m_bufferCr
uint32_t copyDataToChannels(quint32 x, quint32 y, quint32 dataWidth, QSharedPointer< KisBufferStreamBase > tiffstream) override
std::unique_ptr< T[]> m_bufferCb
KisTIFFYCbCrReader(KisPaintDeviceSP device, quint32 width, quint32 height, const std::array< quint8, 5 > &poses, int32_t alphapos, uint16_t sourceDepth, uint16_t sampleformat, uint16_t nbcolorssamples, uint16_t extrasamplescount, bool premultipliedAlpha, KoColorTransformation *transformProfile, QSharedPointer< KisTIFFPostProcessor > postprocessor, uint16_t hsub, uint16_t vsub)
uint32_t copyDataToChannelsImpl(quint32 x, quint32 y, quint32 dataWidth, QSharedPointer< KisBufferStreamBase > tiffstream)
static bool qFuzzyCompare(half p1, half p2)