Warning, file /office/calligra/libs/pigment/KoColorSpace.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org> 0003 * 0004 * This library is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU Lesser General Public 0006 * License as published by the Free Software Foundation; either 0007 * version 2.1 of the License, or (at your option) any later version. 0008 * 0009 * This library is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 * Lesser General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU Lesser General Public License 0015 * along with this library; see the file COPYING.LIB. If not, write to 0016 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #include "KoColorSpace.h" 0021 #include "KoColorSpace_p.h" 0022 0023 #include "KoChannelInfo.h" 0024 #include "DebugPigment.h" 0025 #include "KoCompositeOp.h" 0026 #include "KoColorTransformation.h" 0027 #include "KoColorTransformationFactory.h" 0028 #include "KoColorTransformationFactoryRegistry.h" 0029 #include "KoColorConversionCache.h" 0030 #include "KoColorConversionSystem.h" 0031 #include "KoColorSpaceRegistry.h" 0032 #include "KoColorProfile.h" 0033 #include "KoCopyColorConversionTransformation.h" 0034 #include "KoFallBackColorTransformation.h" 0035 #include "KoUniqueNumberForIdServer.h" 0036 #include "KoMixColorsOp.h" 0037 #include "KoConvolutionOp.h" 0038 #include "KoCompositeOpRegistry.h" 0039 0040 #include <QThreadStorage> 0041 #include <QByteArray> 0042 #include <QBitArray> 0043 #include <QPolygonF> 0044 #include <QPointF> 0045 0046 #include <math.h> 0047 0048 KoColorSpace::KoColorSpace() 0049 : d(new Private()) 0050 { 0051 } 0052 0053 KoColorSpace::KoColorSpace(const QString &id, const QString &name, KoMixColorsOp* mixColorsOp, KoConvolutionOp* convolutionOp) 0054 : d(new Private()) 0055 { 0056 d->id = id; 0057 d->idNumber = KoUniqueNumberForIdServer::instance()->numberForId(d->id); 0058 d->name = name; 0059 d->mixColorsOp = mixColorsOp; 0060 d->convolutionOp = convolutionOp; 0061 d->transfoToRGBA16 = 0; 0062 d->transfoFromRGBA16 = 0; 0063 d->transfoToLABA16 = 0; 0064 d->transfoFromLABA16 = 0; 0065 d->gamutXYY = QPolygonF(); 0066 d->TRCXYY = QPolygonF(); 0067 d->colorants = QVector <qreal> (0); 0068 d->lumaCoefficients = QVector <qreal> (0); 0069 d->deletability = NotOwnedByRegistry; 0070 } 0071 0072 KoColorSpace::~KoColorSpace() 0073 { 0074 Q_ASSERT(d->deletability != OwnedByRegistryDoNotDelete); 0075 0076 qDeleteAll(d->compositeOps); 0077 foreach(KoChannelInfo * channel, d->channels) { 0078 delete channel; 0079 } 0080 if (d->deletability == NotOwnedByRegistry) { 0081 KoColorConversionCache* cache = KoColorSpaceRegistry::instance()->colorConversionCache(); 0082 if (cache) { 0083 cache->colorSpaceIsDestroyed(this); 0084 } 0085 } 0086 delete d->mixColorsOp; 0087 delete d->convolutionOp; 0088 delete d->transfoToRGBA16; 0089 delete d->transfoFromRGBA16; 0090 delete d->transfoToLABA16; 0091 delete d->transfoFromLABA16; 0092 delete d; 0093 } 0094 0095 bool KoColorSpace::operator==(const KoColorSpace& rhs) const 0096 { 0097 const KoColorProfile* p1 = rhs.profile(); 0098 const KoColorProfile* p2 = profile(); 0099 return d->idNumber == rhs.d->idNumber && ((p1 == p2) || (*p1 == *p2)); 0100 } 0101 0102 QString KoColorSpace::id() const 0103 { 0104 return d->id; 0105 } 0106 0107 QString KoColorSpace::name() const 0108 { 0109 return d->name; 0110 } 0111 0112 //Color space info stuff. 0113 QPolygonF KoColorSpace::gamutXYY() const 0114 { 0115 if (d->gamutXYY.empty()) { 0116 //now, let's decide on the boundary. This is a bit tricky because icc profiles can be both matrix-shaper and cLUT at once if the maker so pleases. 0117 //first make a list of colors. 0118 qreal max = 1.0; 0119 if ((colorModelId().id()=="CMYKA" || colorModelId().id()=="LABA") && colorDepthId().id()=="F32") { 0120 //boundaries for cmyka/laba have trouble getting the max values for Float, and are pretty awkward in general. 0121 max = this->channels().at(0)->getUIMax(); 0122 0123 } 0124 int samples = 5;//amount of samples in our color space. 0125 QString name = KoColorSpaceRegistry::instance()->colorSpaceFactory("XYZAF32")->defaultProfile(); 0126 const KoColorSpace* xyzColorSpace = KoColorSpaceRegistry::instance()->colorSpace("XYZA", "F32", name); 0127 quint8 *data = new quint8[pixelSize()]; 0128 quint8 data2[16]; // xyza f32 is 4 floats, that is 16 bytes per pixel. 0129 //QVector <qreal> sampleCoordinates(pow(colorChannelCount(),samples)); 0130 //sampleCoordinates.fill(0.0); 0131 0132 // This is fixed to 5 since the maximum number of channels are 5 for CMYKA 0133 QVector <qreal> channelValues(5);//for getting the coordinates. 0134 0135 for(int x=0;x<samples;x++){ 0136 if (colorChannelCount()==1) {//gray 0137 channelValues[0]=(max/(samples-1))*(x); 0138 channelValues[1]=max; 0139 fromNormalisedChannelsValue(data, channelValues); 0140 convertPixelsTo(data, data2, xyzColorSpace, 1, KoColorConversionTransformation::IntentAbsoluteColorimetric, KoColorConversionTransformation::adjustmentConversionFlags()); 0141 xyzColorSpace->normalisedChannelsValue(data2, channelValues); 0142 qreal x = channelValues[0]/(channelValues[0]+channelValues[1]+channelValues[2]); 0143 qreal y = channelValues[1]/(channelValues[0]+channelValues[1]+channelValues[2]); 0144 d->gamutXYY << QPointF(x,y); 0145 } else { 0146 for(int y=0;y<samples;y++){ 0147 for(int z=0;z<samples;z++){ 0148 if (colorChannelCount()==4) { 0149 for(int k=0;k<samples;k++){ 0150 channelValues[0] = (max / (samples - 1)) * (x); 0151 channelValues[1] = (max / (samples - 1)) * (y); 0152 channelValues[2] = (max / (samples - 1)) * (z); 0153 channelValues[3] = (max / (samples - 1)) * (k); 0154 channelValues[4] = max; 0155 fromNormalisedChannelsValue(data, channelValues); 0156 convertPixelsTo(data, data2, xyzColorSpace, 1, KoColorConversionTransformation::IntentAbsoluteColorimetric, KoColorConversionTransformation::adjustmentConversionFlags()); 0157 xyzColorSpace->normalisedChannelsValue(data2, channelValues); 0158 qreal x = channelValues[0] / (channelValues[0] + channelValues[1] + channelValues[2]); 0159 qreal y = channelValues[1] / (channelValues[0] + channelValues[1] + channelValues[2]); 0160 d->gamutXYY<< QPointF(x,y); 0161 } 0162 } else { 0163 channelValues[0]=(max/(samples-1))*(x); 0164 channelValues[1]=(max/(samples-1))*(y); 0165 channelValues[2]=(max/(samples-1))*(z); 0166 channelValues[3]=max; 0167 if (colorModelId().id()!="XYZA") { //no need for conversion when using xyz. 0168 fromNormalisedChannelsValue(data, channelValues); 0169 convertPixelsTo(data, data2, xyzColorSpace, 1, KoColorConversionTransformation::IntentAbsoluteColorimetric, KoColorConversionTransformation::adjustmentConversionFlags()); 0170 xyzColorSpace->normalisedChannelsValue(data2,channelValues); 0171 } 0172 qreal x = channelValues[0]/(channelValues[0]+channelValues[1]+channelValues[2]); 0173 qreal y = channelValues[1]/(channelValues[0]+channelValues[1]+channelValues[2]); 0174 d->gamutXYY<< QPointF(x,y); 0175 } 0176 } 0177 } 0178 0179 } 0180 } 0181 delete[] data; 0182 //if we ever implement a boundary-checking thing I'd add it here. 0183 return d->gamutXYY; 0184 } else { 0185 return d->gamutXYY; 0186 } 0187 } 0188 0189 QPolygonF KoColorSpace::estimatedTRCXYY() const 0190 { 0191 if (d->TRCXYY.empty()){ 0192 qreal max = 1.0; 0193 if ((colorModelId().id()=="CMYKA" || colorModelId().id()=="LABA") && colorDepthId().id()=="F32") { 0194 //boundaries for cmyka/laba have trouble getting the max values for Float, and are pretty awkward in general. 0195 max = this->channels().at(0)->getUIMax(); 0196 } 0197 QString name = KoColorSpaceRegistry::instance()->colorSpaceFactory("XYZAF16")->defaultProfile(); 0198 const KoColorSpace* xyzColorSpace = KoColorSpaceRegistry::instance()->colorSpace("XYZA", "F16", name); 0199 quint8 *data = new quint8[pixelSize()]; 0200 quint8 data2[8]; // xyza is 8 bytes per pixel. 0201 0202 // This is fixed to 5 since the maximum number of channels are 5 for CMYKA 0203 QVector <qreal> channelValues(5);//for getting the coordinates. 0204 0205 for (quint32 i=0; i<colorChannelCount(); i++) { 0206 qreal colorantY=1.0; 0207 if (colorModelId().id()!="CMYKA") { 0208 for (int j=5; j>0; j--){ 0209 channelValues.fill(0.0); 0210 channelValues[i] = ((max/4)*(5-j)); 0211 0212 if (colorModelId().id()!="XYZA") { //no need for conversion when using xyz. 0213 fromNormalisedChannelsValue(data, channelValues); 0214 convertPixelsTo(data, data2, xyzColorSpace, 1, KoColorConversionTransformation::IntentAbsoluteColorimetric, KoColorConversionTransformation::adjustmentConversionFlags()); 0215 xyzColorSpace->normalisedChannelsValue(data2,channelValues); 0216 } 0217 0218 if (j==0) { 0219 colorantY = channelValues[1]; 0220 if (d->colorants.size()<2){ 0221 d->colorants.resize(3*colorChannelCount()); 0222 d->colorants[i] = channelValues[0]/(channelValues[0]+channelValues[1]+channelValues[2]); 0223 d->colorants[i+1]= channelValues[1]/(channelValues[0]+channelValues[1]+channelValues[2]); 0224 d->colorants[i+2]= channelValues[1]; 0225 } 0226 } 0227 d->TRCXYY << QPointF(channelValues[1]/colorantY, ((1.0/4)*(5-j))); 0228 } 0229 } else { 0230 for (int j=0; j<5; j++){ 0231 channelValues.fill(0.0); 0232 channelValues[i] = ((max/4)*(j)); 0233 0234 fromNormalisedChannelsValue(data, channelValues); 0235 0236 convertPixelsTo(data, data2, xyzColorSpace, 1, KoColorConversionTransformation::IntentAbsoluteColorimetric, KoColorConversionTransformation::adjustmentConversionFlags()); 0237 0238 xyzColorSpace->normalisedChannelsValue(data2,channelValues); 0239 0240 if (j==0) { 0241 colorantY = channelValues[1]; 0242 if (d->colorants.size()<2){ 0243 d->colorants.resize(3*colorChannelCount()); 0244 d->colorants[i] = channelValues[0]/(channelValues[0]+channelValues[1]+channelValues[2]); 0245 d->colorants[i+1]= channelValues[1]/(channelValues[0]+channelValues[1]+channelValues[2]); 0246 d->colorants[i+2]= channelValues[1]; 0247 } 0248 } 0249 d->TRCXYY << QPointF(channelValues[1]/colorantY, ((1.0/4)*(j))); 0250 } 0251 } 0252 } 0253 0254 delete[] data; 0255 return d->TRCXYY; 0256 } else { 0257 return d->TRCXYY; 0258 } 0259 } 0260 0261 QVector <qreal> KoColorSpace::colorants() const 0262 { 0263 if (d->colorants.size()>1){ 0264 return d->colorants; 0265 } else if (profile() && profile()->hasColorants()) { 0266 d->colorants.resize(3*colorChannelCount()); 0267 d->colorants = profile()->getColorantsxyY(); 0268 return d->colorants; 0269 } else { 0270 estimatedTRCXYY(); 0271 return d->colorants; 0272 } 0273 } 0274 QVector <qreal> KoColorSpace::lumaCoefficients() const 0275 { 0276 if (d->lumaCoefficients.size()>1){ 0277 return d->lumaCoefficients; 0278 } else { 0279 d->lumaCoefficients.resize(3); 0280 if (colorModelId().id()!="RGBA") { 0281 d->lumaCoefficients.fill(0.33); 0282 } else { 0283 colorants(); 0284 if (d->colorants[2]<0 || d->colorants[5]<0 || d->colorants[8]<0) { 0285 d->lumaCoefficients[0]=0.2126; 0286 d->lumaCoefficients[1]=0.7152; 0287 d->lumaCoefficients[2]=0.0722; 0288 } else { 0289 d->lumaCoefficients[0]=d->colorants[2]; 0290 d->lumaCoefficients[1]=d->colorants[5]; 0291 d->lumaCoefficients[2]=d->colorants[8]; 0292 } 0293 } 0294 return d->lumaCoefficients; 0295 } 0296 } 0297 0298 QList<KoChannelInfo *> KoColorSpace::channels() const 0299 { 0300 return d->channels; 0301 } 0302 0303 QBitArray KoColorSpace::channelFlags(bool color, bool alpha) const 0304 { 0305 QBitArray ba(d->channels.size()); 0306 if (!color && !alpha) return ba; 0307 0308 for (int i = 0; i < d->channels.size(); ++i) { 0309 KoChannelInfo * channel = d->channels.at(i); 0310 if ((color && channel->channelType() == KoChannelInfo::COLOR) || 0311 (alpha && channel->channelType() == KoChannelInfo::ALPHA)) 0312 ba.setBit(i, true); 0313 } 0314 return ba; 0315 } 0316 0317 void KoColorSpace::addChannel(KoChannelInfo * ci) 0318 { 0319 d->channels.push_back(ci); 0320 } 0321 bool KoColorSpace::hasCompositeOp(const QString& id) const 0322 { 0323 return d->compositeOps.contains(id); 0324 } 0325 0326 QList<KoCompositeOp*> KoColorSpace::compositeOps() const 0327 { 0328 return d->compositeOps.values(); 0329 } 0330 0331 KoMixColorsOp* KoColorSpace::mixColorsOp() const 0332 { 0333 return d->mixColorsOp; 0334 } 0335 0336 0337 KoConvolutionOp* KoColorSpace::convolutionOp() const 0338 { 0339 return d->convolutionOp; 0340 } 0341 0342 const KoCompositeOp * KoColorSpace::compositeOp(const QString & id) const 0343 { 0344 const QHash<QString, KoCompositeOp*>::ConstIterator it = d->compositeOps.constFind(id); 0345 if (it != d->compositeOps.constEnd()) { 0346 return it.value(); 0347 } 0348 else { 0349 warnPigment << "Asking for non-existent composite operation " << id << ", returning " << COMPOSITE_OVER; 0350 return d->compositeOps.value(COMPOSITE_OVER); 0351 } 0352 } 0353 0354 void KoColorSpace::addCompositeOp(const KoCompositeOp * op) 0355 { 0356 if (op->colorSpace()->id() == id()) { 0357 d->compositeOps.insert(op->id(), const_cast<KoCompositeOp*>(op)); 0358 } 0359 } 0360 0361 const KoColorConversionTransformation* KoColorSpace::toLabA16Converter() const 0362 { 0363 if (!d->transfoToLABA16) { 0364 d->transfoToLABA16 = KoColorSpaceRegistry::instance()->colorConversionSystem()->createColorConverter(this, KoColorSpaceRegistry::instance()->lab16(""), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()) ; 0365 } 0366 return d->transfoToLABA16; 0367 } 0368 0369 const KoColorConversionTransformation* KoColorSpace::fromLabA16Converter() const 0370 { 0371 if (!d->transfoFromLABA16) { 0372 d->transfoFromLABA16 = KoColorSpaceRegistry::instance()->colorConversionSystem()->createColorConverter(KoColorSpaceRegistry::instance()->lab16(""), this, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()) ; 0373 } 0374 return d->transfoFromLABA16; 0375 } 0376 const KoColorConversionTransformation* KoColorSpace::toRgbA16Converter() const 0377 { 0378 if (!d->transfoToRGBA16) { 0379 d->transfoToRGBA16 = KoColorSpaceRegistry::instance()->colorConversionSystem()->createColorConverter(this, KoColorSpaceRegistry::instance()->rgb16(""), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()) ; 0380 } 0381 return d->transfoToRGBA16; 0382 } 0383 const KoColorConversionTransformation* KoColorSpace::fromRgbA16Converter() const 0384 { 0385 if (!d->transfoFromRGBA16) { 0386 d->transfoFromRGBA16 = KoColorSpaceRegistry::instance()->colorConversionSystem()->createColorConverter(KoColorSpaceRegistry::instance()->rgb16("") , this, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()) ; 0387 } 0388 return d->transfoFromRGBA16; 0389 } 0390 0391 void KoColorSpace::toLabA16(const quint8 * src, quint8 * dst, quint32 nPixels) const 0392 { 0393 toLabA16Converter()->transform(src, dst, nPixels); 0394 } 0395 0396 void KoColorSpace::fromLabA16(const quint8 * src, quint8 * dst, quint32 nPixels) const 0397 { 0398 fromLabA16Converter()->transform(src, dst, nPixels); 0399 } 0400 0401 void KoColorSpace::toRgbA16(const quint8 * src, quint8 * dst, quint32 nPixels) const 0402 { 0403 toRgbA16Converter()->transform(src, dst, nPixels); 0404 } 0405 0406 void KoColorSpace::fromRgbA16(const quint8 * src, quint8 * dst, quint32 nPixels) const 0407 { 0408 fromRgbA16Converter()->transform(src, dst, nPixels); 0409 } 0410 0411 KoColorConversionTransformation* KoColorSpace::createColorConverter(const KoColorSpace * dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const 0412 { 0413 if (*this == *dstColorSpace) { 0414 return new KoCopyColorConversionTransformation(this); 0415 } else { 0416 return KoColorSpaceRegistry::instance()->colorConversionSystem()->createColorConverter(this, dstColorSpace, renderingIntent, conversionFlags); 0417 } 0418 } 0419 0420 bool KoColorSpace::convertPixelsTo(const quint8 * src, 0421 quint8 * dst, 0422 const KoColorSpace * dstColorSpace, 0423 quint32 numPixels, 0424 KoColorConversionTransformation::Intent renderingIntent, 0425 KoColorConversionTransformation::ConversionFlags conversionFlags) const 0426 { 0427 if (*this == *dstColorSpace) { 0428 if (src != dst) { 0429 memcpy(dst, src, numPixels * sizeof(quint8) * pixelSize()); 0430 } 0431 } else { 0432 KoCachedColorConversionTransformation cct = KoColorSpaceRegistry::instance()->colorConversionCache()->cachedConverter(this, dstColorSpace, renderingIntent, conversionFlags); 0433 cct.transformation()->transform(src, dst, numPixels); 0434 } 0435 return true; 0436 } 0437 0438 0439 void KoColorSpace::bitBlt(const KoColorSpace* srcSpace, const KoCompositeOp::ParameterInfo& params, const KoCompositeOp* op, 0440 KoColorConversionTransformation::Intent renderingIntent, 0441 KoColorConversionTransformation::ConversionFlags conversionFlags) const 0442 { 0443 Q_ASSERT_X(*op->colorSpace() == *this, "KoColorSpace::bitBlt", QString("Composite op is for color space %1 (%2) while this is %3 (%4)").arg(op->colorSpace()->id()).arg(op->colorSpace()->profile()->name()).arg(id()).arg(profile()->name()).toLatin1()); 0444 0445 if(params.rows <= 0 || params.cols <= 0) 0446 return; 0447 0448 if(!(*this == *srcSpace)) { 0449 if (preferCompositionInSourceColorSpace() && 0450 srcSpace->hasCompositeOp(op->id())) { 0451 0452 quint32 conversionDstBufferStride = params.cols * srcSpace->pixelSize(); 0453 QVector<quint8> * conversionDstCache = threadLocalConversionCache(params.rows * conversionDstBufferStride); 0454 quint8* conversionDstData = conversionDstCache->data(); 0455 0456 for(qint32 row=0; row<params.rows; row++) { 0457 convertPixelsTo(params.dstRowStart + row * params.dstRowStride, 0458 conversionDstData + row * conversionDstBufferStride, srcSpace, params.cols, 0459 renderingIntent, conversionFlags); 0460 } 0461 0462 // FIXME: do not calculate the otherOp every time 0463 const KoCompositeOp *otherOp = srcSpace->compositeOp(op->id()); 0464 0465 KoCompositeOp::ParameterInfo paramInfo(params); 0466 paramInfo.dstRowStart = conversionDstData; 0467 paramInfo.dstRowStride = conversionDstBufferStride; 0468 otherOp->composite(paramInfo); 0469 0470 for(qint32 row=0; row<params.rows; row++) { 0471 srcSpace->convertPixelsTo(conversionDstData + row * conversionDstBufferStride, 0472 params.dstRowStart + row * params.dstRowStride, this, params.cols, 0473 renderingIntent, conversionFlags); 0474 } 0475 0476 } else { 0477 quint32 conversionBufferStride = params.cols * pixelSize(); 0478 QVector<quint8> * conversionCache = threadLocalConversionCache(params.rows * conversionBufferStride); 0479 quint8* conversionData = conversionCache->data(); 0480 0481 for(qint32 row=0; row<params.rows; row++) { 0482 srcSpace->convertPixelsTo(params.srcRowStart + row * params.srcRowStride, 0483 conversionData + row * conversionBufferStride, this, params.cols, 0484 renderingIntent, conversionFlags); 0485 } 0486 0487 KoCompositeOp::ParameterInfo paramInfo(params); 0488 paramInfo.srcRowStart = conversionData; 0489 paramInfo.srcRowStride = conversionBufferStride; 0490 op->composite(paramInfo); 0491 } 0492 } 0493 else { 0494 op->composite(params); 0495 } 0496 } 0497 0498 0499 QVector<quint8> * KoColorSpace::threadLocalConversionCache(quint32 size) const 0500 { 0501 QVector<quint8> * ba = 0; 0502 if (!d->conversionCache.hasLocalData()) { 0503 ba = new QVector<quint8>(size, '0'); 0504 d->conversionCache.setLocalData(ba); 0505 } else { 0506 ba = d->conversionCache.localData(); 0507 if ((quint8)ba->size() < size) 0508 ba->resize(size); 0509 } 0510 return ba; 0511 } 0512 0513 KoColorTransformation* KoColorSpace::createColorTransformation(const QString & id, const QHash<QString, QVariant> & parameters) const 0514 { 0515 KoColorTransformationFactory* factory = KoColorTransformationFactoryRegistry::instance()->get(id); 0516 if (!factory) return 0; 0517 QPair<KoID, KoID> model(colorModelId(), colorDepthId()); 0518 QList< QPair<KoID, KoID> > models = factory->supportedModels(); 0519 if (models.isEmpty() || models.contains(model)) { 0520 return factory->createTransformation(this, parameters); 0521 } else { 0522 // Find the best solution 0523 // TODO use the color conversion cache 0524 KoColorConversionTransformation* csToFallBack = 0; 0525 KoColorConversionTransformation* fallBackToCs = 0; 0526 KoColorSpaceRegistry::instance()->colorConversionSystem()->createColorConverters(this, models, csToFallBack, fallBackToCs); 0527 Q_ASSERT(csToFallBack); 0528 Q_ASSERT(fallBackToCs); 0529 KoColorTransformation* transfo = factory->createTransformation(fallBackToCs->srcColorSpace(), parameters); 0530 return new KoFallBackColorTransformation(csToFallBack, fallBackToCs, transfo); 0531 } 0532 } 0533 0534 void KoColorSpace::increaseLuminosity(quint8 * pixel, qreal step) const{ 0535 int channelnumber = channelCount(); 0536 QVector <qreal> channelValues(channelnumber); 0537 normalisedChannelsValue(pixel, channelValues); 0538 if (profile()->hasTRC()){ 0539 //only linearise and crunch the luma if there's a TRC 0540 profile()->linearizeFloatValue(channelValues); 0541 qreal hue, sat, luma = 0.0; 0542 toHSY(channelValues, &hue, &sat, &luma); 0543 luma = pow(luma, 1/2.2); 0544 luma = qMin<qreal>(1.0, luma + step); 0545 luma = pow(luma, 2.2); 0546 channelValues = fromHSY(&hue, &sat, &luma); 0547 profile()->delinearizeFloatValue(channelValues); 0548 } else { 0549 qreal hue, sat, luma = 0.0; 0550 toHSY(channelValues, &hue, &sat, &luma); 0551 luma = qMin<qreal>(1.0, luma + step); 0552 channelValues = fromHSY(&hue, &sat, &luma); 0553 } 0554 fromNormalisedChannelsValue(pixel, channelValues); 0555 setOpacity(pixel, qreal(1.0), 1); 0556 } 0557 void KoColorSpace::decreaseLuminosity(quint8 * pixel, qreal step) const { 0558 int channelnumber = channelCount(); 0559 QVector <qreal> channelValues(channelnumber); 0560 normalisedChannelsValue(pixel, channelValues); 0561 if (profile()->hasTRC()){ 0562 //only linearise and crunch the luma if there's a TRC 0563 profile()->linearizeFloatValue(channelValues); 0564 qreal hue, sat, luma = 0.0; 0565 toHSY(channelValues, &hue, &sat, &luma); 0566 luma = pow(luma, 1/2.2); 0567 if (luma-step<0.0) { 0568 luma=0.0; 0569 } else { 0570 luma -= step; 0571 } 0572 luma = pow(luma, 2.2); 0573 channelValues = fromHSY(&hue, &sat, &luma); 0574 profile()->delinearizeFloatValue(channelValues); 0575 } else { 0576 qreal hue, sat, luma = 0.0; 0577 toHSY(channelValues, &hue, &sat, &luma); 0578 if (luma-step<0.0) { 0579 luma=0.0; 0580 } else { 0581 luma -= step; 0582 } 0583 channelValues = fromHSY(&hue, &sat, &luma); 0584 } 0585 fromNormalisedChannelsValue(pixel, channelValues); 0586 setOpacity(pixel, qreal(1.0), 1); 0587 } 0588 void KoColorSpace::increaseSaturation(quint8 * pixel, qreal step) const{ 0589 int channelnumber = channelCount(); 0590 QVector <qreal> channelValues(channelnumber); 0591 normalisedChannelsValue(pixel, channelValues); 0592 profile()->linearizeFloatValue(channelValues); 0593 qreal hue, sat, luma = 0.0; 0594 toHSY(channelValues, &hue, &sat, &luma); 0595 sat += step; 0596 sat = qBound<qreal>(0.0, sat, 1.0); 0597 channelValues = fromHSY(&hue, &sat, &luma); 0598 profile()->delinearizeFloatValue(channelValues); 0599 fromNormalisedChannelsValue(pixel, channelValues); 0600 setOpacity(pixel, qreal(1.0), 1); 0601 } 0602 void KoColorSpace::decreaseSaturation(quint8 * pixel, qreal step) const{ 0603 int channelnumber = channelCount(); 0604 QVector <qreal> channelValues(channelnumber); 0605 normalisedChannelsValue(pixel, channelValues); 0606 profile()->linearizeFloatValue(channelValues); 0607 qreal hue, sat, luma = 0.0; 0608 toHSY(channelValues, &hue, &sat, &luma); 0609 sat -= step; 0610 sat = qBound<qreal>(0.0, sat, 1.0); 0611 channelValues = fromHSY(&hue, &sat, &luma); 0612 profile()->delinearizeFloatValue(channelValues); 0613 fromNormalisedChannelsValue(pixel, channelValues); 0614 setOpacity(pixel, qreal(1.0), 1); 0615 } 0616 void KoColorSpace::increaseHue(quint8 * pixel, qreal step) const{ 0617 int channelnumber = channelCount(); //doesn't work for cmyka... 0618 QVector <qreal> channelValues(channelnumber); 0619 normalisedChannelsValue(pixel, channelValues); 0620 profile()->linearizeFloatValue(channelValues); 0621 qreal hue, sat, luma = 0.0; 0622 toHSY(channelValues, &hue, &sat, &luma); 0623 if (hue+step>1.0){ 0624 hue=(hue+step)- 1.0; 0625 } else { 0626 hue += step; 0627 } 0628 channelValues = fromHSY(&hue, &sat, &luma); 0629 profile()->delinearizeFloatValue(channelValues); 0630 fromNormalisedChannelsValue(pixel, channelValues); 0631 setOpacity(pixel, qreal(1.0), 1); 0632 } 0633 void KoColorSpace::decreaseHue(quint8 * pixel, qreal step) const{ 0634 int channelnumber = channelCount(); 0635 QVector <qreal> channelValues(channelnumber); 0636 normalisedChannelsValue(pixel, channelValues); 0637 profile()->linearizeFloatValue(channelValues); 0638 qreal hue, sat, luma = 0.0; 0639 toHSY(channelValues, &hue, &sat, &luma); 0640 if (hue-step<0.0){ 0641 hue=1.0-(step-hue); 0642 } else { 0643 hue -= step; 0644 } 0645 channelValues = fromHSY(&hue, &sat, &luma); 0646 profile()->delinearizeFloatValue(channelValues); 0647 fromNormalisedChannelsValue(pixel, channelValues); 0648 setOpacity(pixel, qreal(1.0), 1); 0649 } 0650 0651 void KoColorSpace::increaseRed(quint8 * pixel, qreal step) const{ 0652 int channelnumber = channelCount(); 0653 QVector <qreal> channelValues(channelnumber); 0654 normalisedChannelsValue(pixel, channelValues); 0655 profile()->linearizeFloatValue(channelValues); 0656 qreal y, u, v = 0.0; 0657 toYUV(channelValues, &y, &u, &v); 0658 u += step; 0659 u = qBound<qreal>(0.0, u, 1.0); 0660 channelValues = fromYUV(&y, &u, &v); 0661 profile()->delinearizeFloatValue(channelValues); 0662 fromNormalisedChannelsValue(pixel, channelValues); 0663 setOpacity(pixel, qreal(1.0), 1); 0664 } 0665 void KoColorSpace::increaseGreen(quint8 * pixel, qreal step) const{ 0666 int channelnumber = channelCount(); 0667 QVector <qreal> channelValues(channelnumber); 0668 normalisedChannelsValue(pixel, channelValues); 0669 profile()->linearizeFloatValue(channelValues); 0670 qreal y, u, v = 0.0; 0671 toYUV(channelValues, &y, &u, &v); 0672 u -= step; 0673 u = qBound<qreal>(0.0, u, 1.0); 0674 channelValues = fromYUV(&y, &u, &v); 0675 profile()->delinearizeFloatValue(channelValues); 0676 fromNormalisedChannelsValue(pixel, channelValues); 0677 setOpacity(pixel, qreal(1.0), 1); 0678 } 0679 void KoColorSpace::increaseBlue(quint8 * pixel, qreal step) const{ 0680 int channelnumber = channelCount(); 0681 QVector <qreal> channelValues(channelnumber); 0682 normalisedChannelsValue(pixel, channelValues); 0683 profile()->linearizeFloatValue(channelValues); 0684 qreal y, u, v = 0.0; 0685 toYUV(channelValues, &y, &u, &v); 0686 v += step; 0687 v = qBound<qreal>(0.0, v, 1.0); 0688 channelValues = fromYUV(&y, &u, &v); 0689 profile()->delinearizeFloatValue(channelValues); 0690 fromNormalisedChannelsValue(pixel, channelValues); 0691 setOpacity(pixel, qreal(1.0), 1); 0692 } 0693 void KoColorSpace::increaseYellow(quint8 * pixel, qreal step) const{ 0694 int channelnumber = channelCount(); 0695 QVector <qreal> channelValues(channelnumber); 0696 normalisedChannelsValue(pixel, channelValues); 0697 profile()->linearizeFloatValue(channelValues); 0698 qreal y, u, v = 0.0; 0699 toYUV(channelValues, &y, &u, &v); 0700 v -= step; 0701 v = qBound<qreal>(0.0, v, 1.0); 0702 channelValues = fromYUV(&y, &u, &v); 0703 profile()->delinearizeFloatValue(channelValues); 0704 fromNormalisedChannelsValue(pixel, channelValues); 0705 setOpacity(pixel, qreal(1.0), 1); 0706 } 0707 QImage KoColorSpace::convertToQImage(const quint8 *data, qint32 width, qint32 height, 0708 const KoColorProfile *dstProfile, 0709 KoColorConversionTransformation::Intent renderingIntent, 0710 KoColorConversionTransformation::ConversionFlags conversionFlags) const 0711 0712 { 0713 QImage img = QImage(width, height, QImage::Format_ARGB32); 0714 0715 const KoColorSpace * dstCS = KoColorSpaceRegistry::instance()->rgb8(dstProfile); 0716 0717 if (data) 0718 this->convertPixelsTo(const_cast<quint8 *>(data), img.bits(), dstCS, width * height, renderingIntent, conversionFlags); 0719 0720 return img; 0721 } 0722 0723 bool KoColorSpace::preferCompositionInSourceColorSpace() const 0724 { 0725 return false; 0726 }