2
* Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
17
* Boston, MA 02110-1301, USA.
20
#include "kis_ycbcr_u8_colorspace.h"
21
#include "kis_ycbcr_colorspace.h"
27
#include <kis_integer_maths.h>
29
KisYCbCrU8ColorSpace::KisYCbCrU8ColorSpace(KisColorSpaceFactoryRegistry* parent, KisProfile* p)
30
: KisU8BaseColorSpace(KisID("YCbCrAU8", "YCbCr (8-bit integer/channel)"), TYPE_YCbCr_8, icSigYCbCrData, parent, p)
32
m_channels.push_back(new KisChannelInfo("Y", PIXEL_Y * sizeof(Q_UINT8), KisChannelInfo::COLOR, KisChannelInfo::UINT8, sizeof(Q_UINT8)));
33
m_channels.push_back(new KisChannelInfo("Cb", PIXEL_Cb * sizeof(Q_UINT8), KisChannelInfo::COLOR, KisChannelInfo::UINT8, sizeof(Q_UINT8)));
34
m_channels.push_back(new KisChannelInfo("Cr", PIXEL_Cr * sizeof(Q_UINT8), KisChannelInfo::COLOR, KisChannelInfo::UINT8, sizeof(Q_UINT8)));
35
m_channels.push_back(new KisChannelInfo(i18n("Alpha"), PIXEL_ALPHA * sizeof(Q_UINT8), KisChannelInfo::ALPHA, KisChannelInfo::UINT8, sizeof(Q_UINT8)));
37
m_alphaPos = PIXEL_ALPHA * sizeof(Q_UINT8);
41
KisYCbCrU8ColorSpace::~KisYCbCrU8ColorSpace()
45
void KisYCbCrU8ColorSpace::setPixel(Q_UINT8 *dst, Q_UINT8 Y, Q_UINT8 Cb, Q_UINT8 Cr, Q_UINT8 alpha) const
47
Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
52
dstPixel->alpha = alpha;
55
void KisYCbCrU8ColorSpace::getPixel(const Q_UINT8 *src, Q_UINT8 *Y, Q_UINT8 *Cb, Q_UINT8 *Cr, Q_UINT8 *alpha) const
57
const Pixel *srcPixel = reinterpret_cast<const Pixel *>(src);
62
*alpha = srcPixel->alpha;
66
void KisYCbCrU8ColorSpace::fromQColor(const QColor& c, Q_UINT8 *dstU8, KisProfile * profile )
70
KisU8BaseColorSpace::fromQColor(c, dstU8, profile);
72
Pixel *dst = reinterpret_cast<Pixel *>(dstU8);
73
dst->Y = computeY( c.red(), c.green(), c.blue());
74
dst->Cb = computeCb( c.red(), c.green(), c.blue());
75
dst->Cr = computeCr( c.red(), c.green(), c.blue());
79
void KisYCbCrU8ColorSpace::fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dstU8, KisProfile * profile )
83
KisU8BaseColorSpace::fromQColor(c, opacity, dstU8, profile);
85
Pixel *dst = reinterpret_cast<Pixel *>(dstU8);
86
dst->Y = computeY( c.red(), c.green(), c.blue());
87
dst->Cb = computeCb( c.red(), c.green(), c.blue());
88
dst->Cr = computeCr( c.red(), c.green(), c.blue());
93
void KisYCbCrU8ColorSpace::toQColor(const Q_UINT8 *srcU8, QColor *c, KisProfile * profile)
97
KisU8BaseColorSpace::toQColor(srcU8, c, profile);
100
const Pixel *src = reinterpret_cast<const Pixel *>(srcU8);
101
c->setRgb(computeRed(src->Y,src->Cb,src->Cr), computeGreen(src->Y,src->Cb,src->Cr), computeBlue(src->Y,src->Cb,src->Cr));
105
void KisYCbCrU8ColorSpace::toQColor(const Q_UINT8 *srcU8, QColor *c, Q_UINT8 *opacity, KisProfile * profile)
109
KisU8BaseColorSpace::toQColor(srcU8, c, opacity, profile);
111
const Pixel *src = reinterpret_cast<const Pixel *>(srcU8);
112
c->setRgb(computeRed(src->Y,src->Cb,src->Cr), computeGreen(src->Y,src->Cb,src->Cr), computeBlue(src->Y,src->Cb,src->Cr));
113
*opacity = src->alpha;
117
Q_UINT8 KisYCbCrU8ColorSpace::difference(const Q_UINT8 *src1U8, const Q_UINT8 *src2U8)
120
return KisU8BaseColorSpace::difference(src1U8, src2U8);
121
const Pixel *src1 = reinterpret_cast<const Pixel *>(src1U8);
122
const Pixel *src2 = reinterpret_cast<const Pixel *>(src2U8);
124
return QMAX(QABS(src2->Y - src1->Y), QMAX(QABS(src2->Cb - src1->Cb), QABS(src2->Cr - src1->Cr)));
128
void KisYCbCrU8ColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const
130
Q_UINT8 totalY = 0, totalCb = 0, totalCr = 0, newAlpha = 0;
134
const Pixel *pixel = reinterpret_cast<const Pixel *>(*colors);
136
Q_UINT8 alpha = pixel->alpha;
137
float alphaTimesWeight = alpha * *weights;
139
totalY += (Q_UINT8)(pixel->Y * alphaTimesWeight);
140
totalCb += (Q_UINT8)(pixel->Cb * alphaTimesWeight);
141
totalCr += (Q_UINT8)(pixel->Cr * alphaTimesWeight);
142
newAlpha += (Q_UINT8)(alphaTimesWeight);
148
Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
150
dstPixel->alpha = newAlpha;
153
totalY = totalY / newAlpha;
154
totalCb = totalCb / newAlpha;
155
totalCr = totalCr / newAlpha;
158
dstPixel->Y = totalY;
159
dstPixel->Cb = totalCb;
160
dstPixel->Cr = totalCr;
163
QValueVector<KisChannelInfo *> KisYCbCrU8ColorSpace::channels() const {
167
Q_UINT32 KisYCbCrU8ColorSpace::nChannels() const {
168
return MAX_CHANNEL_YCbCrA;
171
Q_UINT32 KisYCbCrU8ColorSpace::nColorChannels() const {
172
return MAX_CHANNEL_YCbCr;
175
Q_UINT32 KisYCbCrU8ColorSpace::pixelSize() const {
176
return MAX_CHANNEL_YCbCrA*sizeof(Q_UINT8);
180
QImage KisYCbCrU8ColorSpace::convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height, KisProfile * dstProfile, Q_INT32 renderingIntent, float exposure )
183
return KisU8BaseColorSpace::convertToQImage( data, width, height, dstProfile, renderingIntent, exposure);
185
QImage img = QImage(width, height, 32, 0, QImage::LittleEndian);
186
img.setAlphaBuffer(true);
189
uchar *j = img.bits();
191
while ( i < width * height * MAX_CHANNEL_YCbCrA) {
192
Q_UINT8 Y = *( data + i + PIXEL_Y );
193
Q_UINT8 Cb = *( data + i + PIXEL_Cb );
194
Q_UINT8 Cr = *( data + i + PIXEL_Cr );
195
#ifdef __BIG_ENDIAN__
196
*( j + 0) = *( data + i + PIXEL_ALPHA );
197
*( j + 1 ) = computeRed(Y,Cb,Cr);
198
*( j + 2 ) = computeGreen(Y,Cb,Cr);
199
*( j + 3 ) = computeBlue(Y,Cr,Cr);
201
*( j + 3) = *( data + i + PIXEL_ALPHA );
202
*( j + 2 ) = computeRed(Y,Cb,Cr);
203
*( j + 1 ) = computeGreen(Y,Cb,Cr);
204
*( j + 0 ) = computeBlue(Y,Cb,Cr);
209
i += MAX_CHANNEL_YCbCrA;
210
j += MAX_CHANNEL_YCbCrA;
216
void KisYCbCrU8ColorSpace::bitBlt(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *srcAlphaMask, Q_INT32 maskRowStride, Q_UINT8 opacity, Q_INT32 rows, Q_INT32 cols, const KisCompositeOp& op)
219
case COMPOSITE_UNDEF:
220
// Undefined == no composition
223
compositeOver(dst, dstRowStride, src, srcRowStride, srcAlphaMask, maskRowStride, rows, cols, opacity);
226
compositeCopy(dst, dstRowStride, src, srcRowStride, srcAlphaMask, maskRowStride, rows, cols, opacity);
228
case COMPOSITE_ERASE:
229
compositeErase(dst, dstRowStride, src, srcRowStride, srcAlphaMask, maskRowStride, rows, cols, opacity);
236
void KisYCbCrU8ColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
240
const Q_UINT8 *src = srcRowStart;
241
Q_UINT8 *dst = dstRowStart;
242
const Q_UINT8 *mask = maskRowStart;
243
Q_INT32 columns = numColumns;
245
while (columns > 0) {
247
Q_UINT8 srcAlpha = src[PIXEL_ALPHA];
249
// apply the alphamask
251
if (*mask != OPACITY_OPAQUE) {
257
if (srcAlpha > OPACITY_TRANSPARENT) {
259
if (opacity < OPACITY_OPAQUE) {
263
if (srcAlpha == OPACITY_OPAQUE) {
264
memcpy(dst, src, MAX_CHANNEL_YCbCrA * sizeof(Q_UINT8));
266
Q_UINT8 dstAlpha = dst[PIXEL_ALPHA];
270
if (dstAlpha == OPACITY_OPAQUE ) {
273
Q_UINT8 newAlpha = dstAlpha + (OPACITY_OPAQUE - dstAlpha) * srcAlpha;
274
dst[PIXEL_ALPHA] = newAlpha;
277
srcBlend = srcAlpha / newAlpha;
283
if (srcBlend == OPACITY_OPAQUE) {
284
memcpy(dst, src, MAX_CHANNEL_YCbCr * sizeof(Q_UINT8));
286
dst[PIXEL_Y] = UINT8_BLEND(src[PIXEL_Y], dst[PIXEL_Y], srcBlend);
287
dst[PIXEL_Cb] = UINT8_BLEND(src[PIXEL_Cb], dst[PIXEL_Cb], srcBlend);
288
dst[PIXEL_Cr] = UINT8_BLEND(src[PIXEL_Cr], dst[PIXEL_Cr], srcBlend);
294
src += MAX_CHANNEL_YCbCrA;
295
dst += MAX_CHANNEL_YCbCrA;
299
srcRowStart += srcRowStride;
300
dstRowStart += dstRowStride;
302
maskRowStart += maskRowStride;
307
void KisYCbCrU8ColorSpace::compositeErase(Q_UINT8 *dst, Q_INT32 dstRowSize, const Q_UINT8 *src, Q_INT32 srcRowSize, const Q_UINT8 *srcAlphaMask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 cols, Q_UINT8 /*opacity*/)
311
const Pixel *s = reinterpret_cast<const Pixel *>(src);
312
Pixel *d = reinterpret_cast<Pixel *>(dst);
313
const Q_UINT8 *mask = srcAlphaMask;
315
for (Q_INT32 i = cols; i > 0; i--, s++, d++)
317
Q_UINT8 srcAlpha = s -> alpha;
319
// apply the alphamask
321
if (*mask != OPACITY_OPAQUE) {
326
d -> alpha = srcAlpha * d -> alpha;
332
srcAlphaMask += maskRowStride;
337
void KisYCbCrU8ColorSpace::compositeCopy(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 */*mask*/, Q_INT32 /*maskRowStride*/, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 /*opacity*/)
340
memcpy(dstRowStart, srcRowStart, numColumns * sizeof(Pixel));
342
srcRowStart += srcRowStride;
343
dstRowStart += dstRowStride;
347
KisCompositeOpList KisYCbCrU8ColorSpace::userVisiblecompositeOps() const
349
KisCompositeOpList list;
351
list.append(KisCompositeOp(COMPOSITE_OVER));