filters

kis_ycbcr_u8_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_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 /*        *( j + 2 ) = Y;
00206         *( j + 1 ) = Cb;
00207         *( j + 0 ) = Cr;*/
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         // Undefined == no composition
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             // apply the alphamask
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 /*opacity*/)
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             // apply the alphamask
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 */*mask*/, Q_INT32 /*maskRowStride*/, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 /*opacity*/)
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 }
KDE Home | KDE Accessibility Home | Description of Access Keys