filters

kis_ycbcr_u16_colorspace.cpp

00001 /*
00002  *  Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
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 /*        *( j + 2 ) = Y;
00207         *( j + 1 ) = Cb;
00208         *( j + 0 ) = Cr;*/
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         // Undefined == no composition
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             // apply the alphamask
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 /*opacity*/)
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                 // apply the alphamask
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 }
KDE Home | KDE Accessibility Home | Description of Access Keys