00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kis_ycbcr_u8_colorspace.h"
00021 #include "kis_ycbcr_colorspace.h"
00022
00023 #include <qimage.h>
00024
00025 #include <klocale.h>
00026
00027 #include <kis_integer_maths.h>
00028
00029 KisYCbCrU8ColorSpace::KisYCbCrU8ColorSpace(KisColorSpaceFactoryRegistry* parent, KisProfile* p)
00030 : KisU8BaseColorSpace(KisID("YCbCrAU8", "YCbCr (8-bit integer/channel)"), TYPE_YCbCr_8, icSigYCbCrData, parent, p)
00031 {
00032 m_channels.push_back(new KisChannelInfo("Y", PIXEL_Y * sizeof(Q_UINT8), KisChannelInfo::COLOR, KisChannelInfo::UINT8, sizeof(Q_UINT8)));
00033 m_channels.push_back(new KisChannelInfo("Cb", PIXEL_Cb * sizeof(Q_UINT8), KisChannelInfo::COLOR, KisChannelInfo::UINT8, sizeof(Q_UINT8)));
00034 m_channels.push_back(new KisChannelInfo("Cr", PIXEL_Cr * sizeof(Q_UINT8), KisChannelInfo::COLOR, KisChannelInfo::UINT8, sizeof(Q_UINT8)));
00035 m_channels.push_back(new KisChannelInfo(i18n("Alpha"), PIXEL_ALPHA * sizeof(Q_UINT8), KisChannelInfo::ALPHA, KisChannelInfo::UINT8, sizeof(Q_UINT8)));
00036
00037 m_alphaPos = PIXEL_ALPHA * sizeof(Q_UINT8);
00038 }
00039
00040
00041 KisYCbCrU8ColorSpace::~KisYCbCrU8ColorSpace()
00042 {
00043 }
00044
00045 void KisYCbCrU8ColorSpace::setPixel(Q_UINT8 *dst, Q_UINT8 Y, Q_UINT8 Cb, Q_UINT8 Cr, Q_UINT8 alpha) const
00046 {
00047 Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
00048
00049 dstPixel->Y = Y;
00050 dstPixel->Cb = Cb;
00051 dstPixel->Cr = Cr;
00052 dstPixel->alpha = alpha;
00053 }
00054
00055 void KisYCbCrU8ColorSpace::getPixel(const Q_UINT8 *src, Q_UINT8 *Y, Q_UINT8 *Cb, Q_UINT8 *Cr, Q_UINT8 *alpha) const
00056 {
00057 const Pixel *srcPixel = reinterpret_cast<const Pixel *>(src);
00058
00059 *Y = srcPixel->Y;
00060 *Cb = srcPixel->Cb;
00061 *Cr = srcPixel->Cr;
00062 *alpha = srcPixel->alpha;
00063
00064 }
00065
00066 void KisYCbCrU8ColorSpace::fromQColor(const QColor& c, Q_UINT8 *dstU8, KisProfile * profile )
00067 {
00068 if(getProfile())
00069 {
00070 KisU8BaseColorSpace::fromQColor(c, dstU8, profile);
00071 } else {
00072 Pixel *dst = reinterpret_cast<Pixel *>(dstU8);
00073 dst->Y = computeY( c.red(), c.green(), c.blue());
00074 dst->Cb = computeCb( c.red(), c.green(), c.blue());
00075 dst->Cr = computeCr( c.red(), c.green(), c.blue());
00076 }
00077 }
00078
00079 void KisYCbCrU8ColorSpace::fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dstU8, KisProfile * profile )
00080 {
00081 if(getProfile())
00082 {
00083 KisU8BaseColorSpace::fromQColor(c, opacity, dstU8, profile);
00084 } else {
00085 Pixel *dst = reinterpret_cast<Pixel *>(dstU8);
00086 dst->Y = computeY( c.red(), c.green(), c.blue());
00087 dst->Cb = computeCb( c.red(), c.green(), c.blue());
00088 dst->Cr = computeCr( c.red(), c.green(), c.blue());
00089 dst->alpha = opacity;
00090 }
00091 }
00092
00093 void KisYCbCrU8ColorSpace::toQColor(const Q_UINT8 *srcU8, QColor *c, KisProfile * profile)
00094 {
00095 if(getProfile())
00096 {
00097 KisU8BaseColorSpace::toQColor(srcU8, c, profile);
00098
00099 } else {
00100 const Pixel *src = reinterpret_cast<const Pixel *>(srcU8);
00101 c->setRgb(computeRed(src->Y,src->Cb,src->Cr), computeGreen(src->Y,src->Cb,src->Cr), computeBlue(src->Y,src->Cb,src->Cr));
00102 }
00103 }
00104
00105 void KisYCbCrU8ColorSpace::toQColor(const Q_UINT8 *srcU8, QColor *c, Q_UINT8 *opacity, KisProfile * profile)
00106 {
00107 if(getProfile())
00108 {
00109 KisU8BaseColorSpace::toQColor(srcU8, c, opacity, profile);
00110 } else {
00111 const Pixel *src = reinterpret_cast<const Pixel *>(srcU8);
00112 c->setRgb(computeRed(src->Y,src->Cb,src->Cr), computeGreen(src->Y,src->Cb,src->Cr), computeBlue(src->Y,src->Cb,src->Cr));
00113 *opacity = src->alpha;
00114 }
00115 }
00116
00117 Q_UINT8 KisYCbCrU8ColorSpace::difference(const Q_UINT8 *src1U8, const Q_UINT8 *src2U8)
00118 {
00119 if(getProfile())
00120 return KisU8BaseColorSpace::difference(src1U8, src2U8);
00121 const Pixel *src1 = reinterpret_cast<const Pixel *>(src1U8);
00122 const Pixel *src2 = reinterpret_cast<const Pixel *>(src2U8);
00123
00124 return QMAX(QABS(src2->Y - src1->Y), QMAX(QABS(src2->Cb - src1->Cb), QABS(src2->Cr - src1->Cr)));
00125
00126 }
00127
00128 void KisYCbCrU8ColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const
00129 {
00130 Q_UINT8 totalY = 0, totalCb = 0, totalCr = 0, newAlpha = 0;
00131
00132 while (nColors--)
00133 {
00134 const Pixel *pixel = reinterpret_cast<const Pixel *>(*colors);
00135
00136 Q_UINT8 alpha = pixel->alpha;
00137 float alphaTimesWeight = alpha * *weights;
00138
00139 totalY += (Q_UINT8)(pixel->Y * alphaTimesWeight);
00140 totalCb += (Q_UINT8)(pixel->Cb * alphaTimesWeight);
00141 totalCr += (Q_UINT8)(pixel->Cr * alphaTimesWeight);
00142 newAlpha += (Q_UINT8)(alphaTimesWeight);
00143
00144 weights++;
00145 colors++;
00146 }
00147
00148 Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
00149
00150 dstPixel->alpha = newAlpha;
00151
00152 if (newAlpha > 0) {
00153 totalY = totalY / newAlpha;
00154 totalCb = totalCb / newAlpha;
00155 totalCr = totalCr / newAlpha;
00156 }
00157
00158 dstPixel->Y = totalY;
00159 dstPixel->Cb = totalCb;
00160 dstPixel->Cr = totalCr;
00161 }
00162
00163 QValueVector<KisChannelInfo *> KisYCbCrU8ColorSpace::channels() const {
00164 return m_channels;
00165 }
00166
00167 Q_UINT32 KisYCbCrU8ColorSpace::nChannels() const {
00168 return MAX_CHANNEL_YCbCrA;
00169 }
00170
00171 Q_UINT32 KisYCbCrU8ColorSpace::nColorChannels() const {
00172 return MAX_CHANNEL_YCbCr;
00173 }
00174
00175 Q_UINT32 KisYCbCrU8ColorSpace::pixelSize() const {
00176 return MAX_CHANNEL_YCbCrA*sizeof(Q_UINT8);
00177 }
00178
00179
00180 QImage KisYCbCrU8ColorSpace::convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height, KisProfile * dstProfile, Q_INT32 renderingIntent, float exposure )
00181 {
00182 if(getProfile())
00183 return KisU8BaseColorSpace::convertToQImage( data, width, height, dstProfile, renderingIntent, exposure);
00184
00185 QImage img = QImage(width, height, 32, 0, QImage::LittleEndian);
00186 img.setAlphaBuffer(true);
00187
00188 Q_INT32 i = 0;
00189 uchar *j = img.bits();
00190
00191 while ( i < width * height * MAX_CHANNEL_YCbCrA) {
00192 Q_UINT8 Y = *( data + i + PIXEL_Y );
00193 Q_UINT8 Cb = *( data + i + PIXEL_Cb );
00194 Q_UINT8 Cr = *( data + i + PIXEL_Cr );
00195 #ifdef __BIG_ENDIAN__
00196 *( j + 0) = *( data + i + PIXEL_ALPHA );
00197 *( j + 1 ) = computeRed(Y,Cb,Cr);
00198 *( j + 2 ) = computeGreen(Y,Cb,Cr);
00199 *( j + 3 ) = computeBlue(Y,Cr,Cr);
00200 #else
00201 *( j + 3) = *( data + i + PIXEL_ALPHA );
00202 *( j + 2 ) = computeRed(Y,Cb,Cr);
00203 *( j + 1 ) = computeGreen(Y,Cb,Cr);
00204 *( j + 0 ) = computeBlue(Y,Cb,Cr);
00205
00206
00207
00208 #endif
00209 i += MAX_CHANNEL_YCbCrA;
00210 j += MAX_CHANNEL_YCbCrA;
00211 }
00212 return img;
00213 }
00214
00215
00216 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)
00217 {
00218 switch (op.op()) {
00219 case COMPOSITE_UNDEF:
00220
00221 break;
00222 case COMPOSITE_OVER:
00223 compositeOver(dst, dstRowStride, src, srcRowStride, srcAlphaMask, maskRowStride, rows, cols, opacity);
00224 break;
00225 case COMPOSITE_COPY:
00226 compositeCopy(dst, dstRowStride, src, srcRowStride, srcAlphaMask, maskRowStride, rows, cols, opacity);
00227 break;
00228 case COMPOSITE_ERASE:
00229 compositeErase(dst, dstRowStride, src, srcRowStride, srcAlphaMask, maskRowStride, rows, cols, opacity);
00230 break;
00231 default:
00232 break;
00233 }
00234 }
00235
00236 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)
00237 {
00238 while (rows > 0) {
00239
00240 const Q_UINT8 *src = srcRowStart;
00241 Q_UINT8 *dst = dstRowStart;
00242 const Q_UINT8 *mask = maskRowStart;
00243 Q_INT32 columns = numColumns;
00244
00245 while (columns > 0) {
00246
00247 Q_UINT8 srcAlpha = src[PIXEL_ALPHA];
00248
00249
00250 if (mask != 0) {
00251 if (*mask != OPACITY_OPAQUE) {
00252 srcAlpha *= *mask;
00253 }
00254 mask++;
00255 }
00256
00257 if (srcAlpha > OPACITY_TRANSPARENT) {
00258
00259 if (opacity < OPACITY_OPAQUE) {
00260 srcAlpha *= opacity;
00261 }
00262
00263 if (srcAlpha == OPACITY_OPAQUE) {
00264 memcpy(dst, src, MAX_CHANNEL_YCbCrA * sizeof(Q_UINT8));
00265 } else {
00266 Q_UINT8 dstAlpha = dst[PIXEL_ALPHA];
00267
00268 Q_UINT8 srcBlend;
00269
00270 if (dstAlpha == OPACITY_OPAQUE ) {
00271 srcBlend = srcAlpha;
00272 } else {
00273 Q_UINT8 newAlpha = dstAlpha + (OPACITY_OPAQUE - dstAlpha) * srcAlpha;
00274 dst[PIXEL_ALPHA] = newAlpha;
00275
00276 if (newAlpha > 0) {
00277 srcBlend = srcAlpha / newAlpha;
00278 } else {
00279 srcBlend = srcAlpha;
00280 }
00281 }
00282
00283 if (srcBlend == OPACITY_OPAQUE) {
00284 memcpy(dst, src, MAX_CHANNEL_YCbCr * sizeof(Q_UINT8));
00285 } else {
00286 dst[PIXEL_Y] = UINT8_BLEND(src[PIXEL_Y], dst[PIXEL_Y], srcBlend);
00287 dst[PIXEL_Cb] = UINT8_BLEND(src[PIXEL_Cb], dst[PIXEL_Cb], srcBlend);
00288 dst[PIXEL_Cr] = UINT8_BLEND(src[PIXEL_Cr], dst[PIXEL_Cr], srcBlend);
00289 }
00290 }
00291 }
00292
00293 columns--;
00294 src += MAX_CHANNEL_YCbCrA;
00295 dst += MAX_CHANNEL_YCbCrA;
00296 }
00297
00298 rows--;
00299 srcRowStart += srcRowStride;
00300 dstRowStart += dstRowStride;
00301 if(maskRowStart) {
00302 maskRowStart += maskRowStride;
00303 }
00304 }
00305 }
00306
00307 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 )
00308 {
00309 while (rows-- > 0)
00310 {
00311 const Pixel *s = reinterpret_cast<const Pixel *>(src);
00312 Pixel *d = reinterpret_cast<Pixel *>(dst);
00313 const Q_UINT8 *mask = srcAlphaMask;
00314
00315 for (Q_INT32 i = cols; i > 0; i--, s++, d++)
00316 {
00317 Q_UINT8 srcAlpha = s -> alpha;
00318
00319
00320 if (mask != 0) {
00321 if (*mask != OPACITY_OPAQUE) {
00322 srcAlpha = *mask;
00323 }
00324 mask++;
00325 }
00326 d -> alpha = srcAlpha * d -> alpha;
00327 }
00328
00329 dst += dstRowSize;
00330 src += srcRowSize;
00331 if(srcAlphaMask) {
00332 srcAlphaMask += maskRowStride;
00333 }
00334 }
00335 }
00336
00337 void KisYCbCrU8ColorSpace::compositeCopy(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *, Q_INT32 , Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 )
00338 {
00339 while (rows > 0) {
00340 memcpy(dstRowStart, srcRowStart, numColumns * sizeof(Pixel));
00341 --rows;
00342 srcRowStart += srcRowStride;
00343 dstRowStart += dstRowStride;
00344 }
00345 }
00346
00347 KisCompositeOpList KisYCbCrU8ColorSpace::userVisiblecompositeOps() const
00348 {
00349 KisCompositeOpList list;
00350
00351 list.append(KisCompositeOp(COMPOSITE_OVER));
00352 return list;
00353 }