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