33#include <QThreadStorage>
52 d->transfoToRGBA16 = 0;
53 d->transfoFromRGBA16 = 0;
54 d->transfoToLABA16 = 0;
55 d->transfoFromLABA16 = 0;
56 d->gamutXYY = QPolygonF();
57 d->TRCXYY = QPolygonF();
58 d->colorants = QVector <KoColorimetryUtils::xyY> (0);
59 d->lumaCoefficients = QVector <qreal> (0);
71 d->compositeOps.clear();
72 for (
const auto& map:
d->ditherOps) {
86 delete d->mixColorsOp;
87 delete d->convolutionOp;
88 delete d->transfoToRGBA16;
89 delete d->transfoFromRGBA16;
90 delete d->transfoToLABA16;
91 delete d->transfoFromLABA16;
99 return d->idNumber == rhs.
d->idNumber && ((
p1 ==
p2) || (*
p1 == *
p2));
115 if (
d->gamutXYY.empty()) {
132 QVector <float> channelValuesF(5);
134 for(
int x=0;
x<samples;
x++){
136 channelValuesF[0]=(
max/(samples-1))*(
x);
137 channelValuesF[1]=
max;
141 qreal
x = channelValuesF[0]/(channelValuesF[0]+channelValuesF[1]+channelValuesF[2]);
142 qreal
y = channelValuesF[1]/(channelValuesF[0]+channelValuesF[1]+channelValuesF[2]);
143 d->gamutXYY << QPointF(x,y);
145 for(
int y=0;
y<samples;
y++){
146 for(
int z=0;z<samples;z++){
148 for(
int k=0;k<samples;k++){
149 channelValuesF[0] = (
max / (samples - 1)) * (
x);
150 channelValuesF[1] = (
max / (samples - 1)) * (
y);
151 channelValuesF[2] = (
max / (samples - 1)) * (z);
152 channelValuesF[3] = (
max / (samples - 1)) * (k);
153 channelValuesF[4] =
max;
157 qreal
x = channelValuesF[0] / (channelValuesF[0] + channelValuesF[1] + channelValuesF[2]);
158 qreal
y = channelValuesF[1] / (channelValuesF[0] + channelValuesF[1] + channelValuesF[2]);
159 d->gamutXYY<< QPointF(x,y);
162 channelValuesF[0]=(
max/(samples-1))*(
x);
163 channelValuesF[1]=(
max/(samples-1))*(
y);
164 channelValuesF[2]=(
max/(samples-1))*(z);
165 channelValuesF[3]=
max;
171 qreal
x = channelValuesF[0]/(channelValuesF[0]+channelValuesF[1]+channelValuesF[2]);
172 qreal
y = channelValuesF[1]/(channelValuesF[0]+channelValuesF[1]+channelValuesF[2]);
173 d->gamutXYY<< QPointF(x,y);
190 if (
d->TRCXYY.empty()){
196 max = channelInfo[0]->getUIMax();
200 quint8 *data2 =
new quint8[xyzColorSpace->
pixelSize()];
203 QVector <float> channelValuesF(5);
207 const int segments = 10;
211 for (
int j = 0; j <= segments; j++) {
212 channelValuesF.fill(0.0);
213 channelValuesF[channelInfo[i]->displayPosition()] = ((max/segments)*(segments-j));
221 colorantY = channelValuesF[1];
222 d->colorants[i].x = channelValuesF[0]/(channelValuesF[0]+channelValuesF[1]+channelValuesF[2]);
223 d->colorants[i].y = channelValuesF[1]/(channelValuesF[0]+channelValuesF[1]+channelValuesF[2]);
224 d->colorants[i].Y = channelValuesF[1];
226 d->TRCXYY << QPointF(channelValuesF[1]/colorantY, ((1.0/segments)*(segments-j)));
229 for (
int j = 0; j <= segments; j++) {
230 channelValuesF.fill(0.0);
231 channelValuesF[i] = ((max/segments)*(j));
240 colorantY = channelValuesF[1];
241 d->colorants[i].x = channelValuesF[0]/(channelValuesF[0]+channelValuesF[1]+channelValuesF[2]);
242 d->colorants[i].y = channelValuesF[1]/(channelValuesF[0]+channelValuesF[1]+channelValuesF[2]);
243 d->colorants[i].Y = channelValuesF[1];
245 d->TRCXYY << QPointF(channelValuesF[1]/colorantY, ((1.0/segments)*(j)));
260 if (
d->lumaCoefficients.size()>1){
261 return d->lumaCoefficients;
263 d->lumaCoefficients.resize(3);
265 d->lumaCoefficients.fill(0.33);
267 if (
d->colorants.size() <= 0) {
276 if (
d->colorants.size() < 3 ||
d->colorants[0].Y<0 ||
d->colorants[1].Y<0 ||
d->colorants[2].Y<0) {
277 d->lumaCoefficients[0]=0.2126;
278 d->lumaCoefficients[1]=0.7152;
279 d->lumaCoefficients[2]=0.0722;
282 qreal sum =
d->colorants[0].Y +
d->colorants[1].Y +
d->colorants[2].Y;
283 d->lumaCoefficients[0] =
d->colorants[0].Y / sum;
284 d->lumaCoefficients[1] =
d->colorants[1].Y / sum;
285 d->lumaCoefficients[2] =
d->colorants[2].Y / sum;
288 return d->lumaCoefficients;
299 QBitArray ba(
d->channels.size());
300 if (!color && !alpha)
return ba;
302 for (
int i = 0; i <
d->channels.size(); ++i) {
313 d->channels.push_back(ci);
320 return d->compositeOps.contains(
id);
325 return d->compositeOps.values();
330 return d->mixColorsOp;
335 const auto it =
d->ditherOps.constFind(depth);
336 if (it !=
d->ditherOps.constEnd()) {
367 return d->convolutionOp;
377 const QHash<QString, KoCompositeOp*>::ConstIterator it =
d->compositeOps.constFind(
id);
378 if (it !=
d->compositeOps.constEnd()) {
402 if (!
d->transfoToLABA16) {
405 return d->transfoToLABA16;
410 if (!
d->transfoFromLABA16) {
413 return d->transfoFromLABA16;
417 if (!
d->transfoToRGBA16) {
420 return d->transfoToRGBA16;
424 if (!
d->transfoFromRGBA16) {
427 return d->transfoFromRGBA16;
452 if (*
this == *dstColorSpace) {
464 KoColorConversionTransformation::ConversionFlags conversionFlags)
const
466 if (*
this == *dstColorSpace) {
468 memcpy(dst, src, numPixels *
sizeof(quint8) *
pixelSize());
482 if (!
d->iccEngine)
return 0;
484 return d->iccEngine->createColorProofingTransformation(
this, dstColorSpace, proofingSpace, renderingIntent, proofingIntent, bpcFirstTransform, gamutWarning, displayConversionFlags);
492 proofingTransform->
transform(src, dst, numPixels);
500 KoColorConversionTransformation::ConversionFlags conversionFlags)
const
505 if(params.
rows <= 0 || params.
cols <= 0)
508 if(!(*
this == *srcSpace)) {
512 quint32 conversionDstBufferStride = params.
cols * srcSpace->
pixelSize();
513 QVector<quint8> * conversionDstCache =
d->conversionCache.get(params.
rows * conversionDstBufferStride);
514 quint8* conversionDstData = conversionDstCache->data();
516 for(qint32 row=0; row<params.
rows; row++) {
518 conversionDstData + row * conversionDstBufferStride, srcSpace, params.
cols,
519 renderingIntent, conversionFlags);
531 for(qint32 row=0; row<params.
rows; row++) {
532 srcSpace->
convertPixelsTo(conversionDstData + row * conversionDstBufferStride,
534 renderingIntent, conversionFlags);
543 const bool noChannelFlags = params.
channelFlags.isEmpty() ||
546 if (noChannelFlags) {
547 for(qint32 row=0; row<params.
rows; row++) {
549 conversionData + row * conversionBufferStride,
this, params.
cols,
550 renderingIntent, conversionFlags);
559 quint32 homogenizationBufferStride = params.
cols * srcSpace->
pixelSize();
560 QVector<quint8> * homogenizationCache =
d->channelFlagsApplicationCache.get(homogenizationBufferStride);
561 quint8* homogenizationData = homogenizationCache->data();
563 for(qint32 row=0; row<params.
rows; row++) {
565 homogenizationData, params.
cols,
568 conversionData + row * conversionBufferStride,
this, params.
cols,
569 renderingIntent, conversionFlags);
591 if (!factory)
return 0;
594 if (models.isEmpty() || models.contains(model)) {
602 Q_ASSERT(csToFallBack);
603 Q_ASSERT(fallBackToCs);
611 QVector <double> channelValues(channelnumber);
612 QVector <float> channelValuesF(channelnumber);
614 for (
int i=0;i<channelnumber;i++){
615 channelValues[i]=channelValuesF[i];
620 qreal hue, sat, luma = 0.0;
621 toHSY(channelValues, &hue, &sat, &luma);
622 luma = pow(luma, 1/2.2);
623 luma = qMin(1.0, luma + step);
624 luma = pow(luma, 2.2);
625 channelValues =
fromHSY(&hue, &sat, &luma);
628 qreal hue, sat, luma = 0.0;
629 toHSY(channelValues, &hue, &sat, &luma);
630 luma = qMin(1.0, luma + step);
631 channelValues =
fromHSY(&hue, &sat, &luma);
633 for (
int i=0;i<channelnumber;i++){
634 channelValuesF[i]=channelValues[i];
641 QVector <double> channelValues(channelnumber);
642 QVector <float> channelValuesF(channelnumber);
644 for (
int i=0;i<channelnumber;i++){
645 channelValues[i]=channelValuesF[i];
650 qreal hue, sat, luma = 0.0;
651 toHSY(channelValues, &hue, &sat, &luma);
652 luma = pow(luma, 1/2.2);
658 luma = pow(luma, 2.2);
659 channelValues =
fromHSY(&hue, &sat, &luma);
662 qreal hue, sat, luma = 0.0;
663 toHSY(channelValues, &hue, &sat, &luma);
669 channelValues =
fromHSY(&hue, &sat, &luma);
671 for (
int i=0;i<channelnumber;i++){
672 channelValuesF[i]=channelValues[i];
679 QVector <double> channelValues(channelnumber);
680 QVector <float> channelValuesF(channelnumber);
682 for (
int i=0;i<channelnumber;i++){
683 channelValues[i]=channelValuesF[i];
686 qreal hue, sat, luma = 0.0;
687 toHSY(channelValues, &hue, &sat, &luma);
689 sat = qBound(0.0, sat, 1.0);
690 channelValues =
fromHSY(&hue, &sat, &luma);
692 for (
int i=0;i<channelnumber;i++){
693 channelValuesF[i]=channelValues[i];
700 QVector <double> channelValues(channelnumber);
701 QVector <float> channelValuesF(channelnumber);
703 for (
int i=0;i<channelnumber;i++){
704 channelValues[i]=channelValuesF[i];
707 qreal hue, sat, luma = 0.0;
708 toHSY(channelValues, &hue, &sat, &luma);
710 sat = qBound(0.0, sat, 1.0);
711 channelValues =
fromHSY(&hue, &sat, &luma);
713 for (
int i=0;i<channelnumber;i++){
714 channelValuesF[i]=channelValues[i];
721 QVector <double> channelValues(channelnumber);
722 QVector <float> channelValuesF(channelnumber);
724 for (
int i=0;i<channelnumber;i++){
725 channelValues[i]=channelValuesF[i];
728 qreal hue, sat, luma = 0.0;
729 toHSY(channelValues, &hue, &sat, &luma);
735 channelValues =
fromHSY(&hue, &sat, &luma);
737 for (
int i=0;i<channelnumber;i++){
738 channelValuesF[i]=channelValues[i];
745 QVector <double> channelValues(channelnumber);
746 QVector <float> channelValuesF(channelnumber);
748 for (
int i=0;i<channelnumber;i++){
749 channelValues[i]=channelValuesF[i];
752 qreal hue, sat, luma = 0.0;
753 toHSY(channelValues, &hue, &sat, &luma);
759 channelValues =
fromHSY(&hue, &sat, &luma);
761 for (
int i=0;i<channelnumber;i++){
762 channelValuesF[i]=channelValues[i];
770 QVector <double> channelValues(channelnumber);
771 QVector <float> channelValuesF(channelnumber);
773 for (
int i=0;i<channelnumber;i++){
774 channelValues[i]=channelValuesF[i];
778 toYUV(channelValues, &y, &
u, &
v);
780 u = qBound(0.0,
u, 1.0);
783 for (
int i=0;i<channelnumber;i++){
784 channelValuesF[i]=channelValues[i];
791 QVector <double> channelValues(channelnumber);
792 QVector <float> channelValuesF(channelnumber);
794 for (
int i=0;i<channelnumber;i++){
795 channelValues[i]=channelValuesF[i];
799 toYUV(channelValues, &y, &
u, &
v);
801 u = qBound(0.0,
u, 1.0);
804 for (
int i=0;i<channelnumber;i++){
805 channelValuesF[i]=channelValues[i];
813 QVector <double> channelValues(channelnumber);
814 QVector <float> channelValuesF(channelnumber);
816 for (
int i=0;i<channelnumber;i++){
817 channelValues[i]=channelValuesF[i];
821 toYUV(channelValues, &y, &
u, &
v);
823 v = qBound(0.0,
v, 1.0);
826 for (
int i=0;i<channelnumber;i++){
827 channelValuesF[i]=channelValues[i];
835 QVector <double> channelValues(channelnumber);
836 QVector <float> channelValuesF(channelnumber);
838 for (
int i=0;i<channelnumber;i++){
839 channelValues[i]=channelValuesF[i];
843 toYUV(channelValues, &y, &
u, &
v);
845 v = qBound(0.0,
v, 1.0);
848 for (
int i=0;i<channelnumber;i++){
849 channelValuesF[i]=channelValues[i];
858 KoColorConversionTransformation::ConversionFlags conversionFlags)
const
861 QImage img = QImage(width, height, QImage::Format_ARGB32);
866 this->
convertPixelsTo(
const_cast<quint8 *
>(data), img.bits(), dstCS, width * height, renderingIntent, conversionFlags);
886 const int rgbPixelSize =
sizeof(KoBgrU16Traits::Pixel);
887 QScopedArrayPointer<quint8> rgbBuffer(
new quint8[(nPixels + 1) * rgbPixelSize]);
888 quint8* rgbBrushColorBuffer = rgbBuffer.data() + nPixels * rgbPixelSize;
892 this->
toRgbA16(brushColor, rgbBrushColorBuffer, 1);
893 fillGrayBrushWithColorPreserveLightnessRGB<KoBgrU16Traits>(rgbBuffer.data(), brush, rgbBrushColorBuffer, strength, nPixels);
894 this->
fromRgbA16(rgbBuffer.data(), dst, nPixels);
902 const int rgbPixelSize =
sizeof(KoBgrU16Traits::Pixel);
903 QScopedArrayPointer<quint8> dstBuffer(
new quint8[nPixels * rgbPixelSize]);
905 this->
toRgbA16(dst, dstBuffer.data(), nPixels);
906 modulateLightnessByGrayBrushRGB<KoBgrU16Traits>(dstBuffer.data(), brush, strength, nPixels);
907 this->
fromRgbA16(dstBuffer.data(), dst, nPixels);
const quint8 OPACITY_TRANSPARENT_U8
@ OwnedByRegistryDoNotDelete
const QString COMPOSITE_OVER
virtual KoID destinationDepthId() const =0
virtual KoID sourceDepthId() const =0
virtual DitherType type() const =0
@ ALPHA
The channel represents the opacity of a pixel.
@ COLOR
The channel represents a color.
enumChannelType channelType() const
KoCachedColorConversionTransformation cachedConverter(const KoColorSpace *src, const KoColorSpace *dst, KoColorConversionTransformation::Intent _renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
void colorSpaceIsDestroyed(const KoColorSpace *src)
static KoColorSpaceEngineRegistry * instance()
virtual quint32 alphaPos() const =0
const KoColorConversionTransformation * toLabA16Converter() const
virtual void modulateLightnessByGrayBrush(quint8 *dst, const QRgb *brush, qreal strength, qint32 nPixels) const
virtual void increaseHue(quint8 *pixel, qreal step) const
virtual quint32 pixelSize() const =0
virtual void toRgbA16(const quint8 *src, quint8 *dst, quint32 nPixels) const
virtual void increaseBlue(quint8 *pixel, qreal step) const
virtual void convertChannelToVisualRepresentation(const quint8 *src, quint8 *dst, quint32 nPixels, const qint32 selectedChannelIndex) const =0
virtual QImage convertToQImage(const quint8 *data, qint32 width, qint32 height, const KoColorProfile *dstProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
virtual void increaseRed(quint8 *pixel, qreal step) const
ThreadLocalCache conversionCache
const KoColorConversionTransformation * fromRgbA16Converter() const
virtual void addDitherOp(KisDitherOp *op)
KoColorSpace()
Only for use by classes that serve as baseclass for real color spaces.
virtual void decreaseHue(quint8 *pixel, qreal step) const
virtual void fillGrayBrushWithColorAndLightnessOverlay(quint8 *dst, const QRgb *brush, quint8 *brushColor, qint32 nPixels) const
QBitArray channelFlags(bool color=true, bool alpha=false) const
virtual void toHSY(const QVector< double > &channelValues, qreal *hue, qreal *sat, qreal *luma) const =0
KoConvolutionOp * convolutionOp
virtual void increaseSaturation(quint8 *pixel, qreal step) const
virtual void toYUV(const QVector< double > &channelValues, qreal *y, qreal *u, qreal *v) const =0
virtual void addCompositeOp(const KoCompositeOp *op)
virtual bool preferCompositionInSourceColorSpace() const
const KoColorConversionTransformation * fromLabA16Converter() const
virtual void toLabA16(const quint8 *src, quint8 *dst, quint32 nPixels) const
virtual void bitBlt(const KoColorSpace *srcSpace, const KoCompositeOp::ParameterInfo ¶ms, const KoCompositeOp *op, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
virtual void increaseGreen(quint8 *pixel, qreal step) const
virtual void decreaseLuminosity(quint8 *pixel, qreal step) const
virtual void setOpacity(quint8 *pixels, quint8 alpha, qint32 nPixels) const =0
QList< KoChannelInfo * > channels
virtual void increaseLuminosity(quint8 *pixel, qreal step) const
virtual const KisDitherOp * ditherOp(const QString &depth, DitherType type) const
virtual QVector< double > fromYUV(qreal *y, qreal *u, qreal *v) const =0
virtual KoID colorModelId() const =0
QHash< QString, KoCompositeOp * > compositeOps
QVector< qreal > lumaCoefficients
virtual KoColorConversionTransformation * createProofingTransform(const KoColorSpace *dstColorSpace, const KoColorSpace *proofingSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::Intent proofingIntent, bool bpcFirstTransform, quint8 *gamutWarning, KoColorConversionTransformation::ConversionFlags displayConversionFlags) const
createProofingTransform Create a proofing transform. This is a two part transform that can also do ga...
virtual void fromRgbA16(const quint8 *src, quint8 *dst, quint32 nPixels) const
virtual void fromLabA16(const quint8 *src, quint8 *dst, quint32 nPixels) const
virtual bool proofPixelsTo(const quint8 *src, quint8 *dst, quint32 numPixels, KoColorConversionTransformation *proofingTransform) const
proofPixelsTo
virtual quint32 channelCount() const =0
virtual KoID colorDepthId() const =0
virtual void normalisedChannelsValue(const quint8 *pixel, QVector< float > &channels) const =0
virtual void fromNormalisedChannelsValue(quint8 *pixel, const QVector< float > &values) const =0
virtual bool convertPixelsTo(const quint8 *src, quint8 *dst, const KoColorSpace *dstColorSpace, quint32 numPixels, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
virtual void fillGrayBrushWithColorAndLightnessWithStrength(quint8 *dst, const QRgb *brush, quint8 *brushColor, qreal strength, qint32 nPixels) const
virtual quint32 colorChannelCount() const =0
virtual bool hasCompositeOp(const QString &id, const KoColorSpace *srcSpace=nullptr) const
virtual bool operator==(const KoColorSpace &rhs) const
KoColorTransformation * createColorTransformation(const QString &id, const QHash< QString, QVariant > ¶meters) const
const KoCompositeOp * compositeOp(const QString &id, const KoColorSpace *srcSpace=nullptr) const
virtual void addChannel(KoChannelInfo *ci)
KoMixColorsOp * mixColorsOp
virtual QVector< double > fromHSY(qreal *hue, qreal *sat, qreal *luma) const =0
virtual void transparentColor(quint8 *dst, quint32 nPixels) const
virtual const KoColorProfile * profile() const =0
virtual void decreaseSaturation(quint8 *pixel, qreal step) const
virtual KoColorConversionTransformation * createColorConverter(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
virtual void increaseYellow(quint8 *pixel, qreal step) const
QPolygonF estimatedTRCXYY() const
const KoColorConversionTransformation * toRgbA16Converter() const
T get(const QString &id) const
constexpr std::enable_if< sizeof...(values)==0, size_t >::type max()
virtual void linearizeFloatValue(QVector< qreal > &Value) const =0
virtual void delinearizeFloatValue(QVector< qreal > &Value) const =0
virtual QVector< KoColorimetryUtils::xyY > getColorantsxyY() const =0
KoColorConversionCache * colorConversionCache
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
KoColorConversionTransformation * createColorConverter(const KoColorSpace *srcColorSpace, const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
static KoColorSpaceRegistry * instance()
const KoColorSpace * rgb8(const QString &profileName=QString())
void createColorConverters(const KoColorSpace *colorSpace, const QList< QPair< KoID, KoID > > &possibilities, KoColorConversionTransformation *&fromCS, KoColorConversionTransformation *&toCS) const
const quint8 * srcRowStart
void composite(quint8 *dstRowStart, qint32 dstRowStride, const quint8 *srcRowStart, qint32 srcRowStride, const quint8 *maskRowStart, qint32 maskRowStride, qint32 rows, qint32 numColumns, float opacity, const QBitArray &channelFlags=QBitArray()) const
const KoColorSpace * colorSpace