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 <qreal> (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[3*i] = channelValuesF[0]/(channelValuesF[0]+channelValuesF[1]+channelValuesF[2]);
223 d->colorants[3*i+1] = channelValuesF[1]/(channelValuesF[0]+channelValuesF[1]+channelValuesF[2]);
224 d->colorants[3*i+2] = 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[3*i] = channelValuesF[0]/(channelValuesF[0]+channelValuesF[1]+channelValuesF[2]);
242 d->colorants[3*i+1] = channelValuesF[1]/(channelValuesF[0]+channelValuesF[1]+channelValuesF[2]);
243 d->colorants[3*i+2] = 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) {
277 if (
d->colorants[2]<0 ||
d->colorants[5]<0 ||
d->colorants[8]<0) {
278 d->lumaCoefficients[0]=0.2126;
279 d->lumaCoefficients[1]=0.7152;
280 d->lumaCoefficients[2]=0.0722;
283 qreal sum =
d->colorants[2] +
d->colorants[5] +
d->colorants[8];
284 d->lumaCoefficients[0] =
d->colorants[2] / sum;
285 d->lumaCoefficients[1] =
d->colorants[5] / sum;
286 d->lumaCoefficients[2] =
d->colorants[8] / sum;
289 return d->lumaCoefficients;
300 QBitArray ba(
d->channels.size());
301 if (!color && !alpha)
return ba;
303 for (
int i = 0; i <
d->channels.size(); ++i) {
314 d->channels.push_back(ci);
321 return d->compositeOps.contains(
id);
326 return d->compositeOps.values();
331 return d->mixColorsOp;
336 const auto it =
d->ditherOps.constFind(depth);
337 if (it !=
d->ditherOps.constEnd()) {
368 return d->convolutionOp;
378 const QHash<QString, KoCompositeOp*>::ConstIterator it =
d->compositeOps.constFind(
id);
379 if (it !=
d->compositeOps.constEnd()) {
403 if (!
d->transfoToLABA16) {
406 return d->transfoToLABA16;
411 if (!
d->transfoFromLABA16) {
414 return d->transfoFromLABA16;
418 if (!
d->transfoToRGBA16) {
421 return d->transfoToRGBA16;
425 if (!
d->transfoFromRGBA16) {
428 return d->transfoFromRGBA16;
453 if (*
this == *dstColorSpace) {
465 KoColorConversionTransformation::ConversionFlags conversionFlags)
const
467 if (*
this == *dstColorSpace) {
469 memcpy(dst, src, numPixels *
sizeof(quint8) *
pixelSize());
483 if (!
d->iccEngine)
return 0;
485 return d->iccEngine->createColorProofingTransformation(
this, dstColorSpace, proofingSpace, renderingIntent, proofingIntent, bpcFirstTransform, gamutWarning, displayConversionFlags);
493 proofingTransform->
transform(src, dst, numPixels);
501 KoColorConversionTransformation::ConversionFlags conversionFlags)
const
506 if(params.
rows <= 0 || params.
cols <= 0)
509 if(!(*
this == *srcSpace)) {
513 quint32 conversionDstBufferStride = params.
cols * srcSpace->
pixelSize();
514 QVector<quint8> * conversionDstCache =
d->conversionCache.get(params.
rows * conversionDstBufferStride);
515 quint8* conversionDstData = conversionDstCache->data();
517 for(qint32 row=0; row<params.
rows; row++) {
519 conversionDstData + row * conversionDstBufferStride, srcSpace, params.
cols,
520 renderingIntent, conversionFlags);
532 for(qint32 row=0; row<params.
rows; row++) {
533 srcSpace->
convertPixelsTo(conversionDstData + row * conversionDstBufferStride,
535 renderingIntent, conversionFlags);
544 const bool noChannelFlags = params.
channelFlags.isEmpty() ||
547 if (noChannelFlags) {
548 for(qint32 row=0; row<params.
rows; row++) {
550 conversionData + row * conversionBufferStride,
this, params.
cols,
551 renderingIntent, conversionFlags);
560 quint32 homogenizationBufferStride = params.
cols * srcSpace->
pixelSize();
561 QVector<quint8> * homogenizationCache =
d->channelFlagsApplicationCache.get(homogenizationBufferStride);
562 quint8* homogenizationData = homogenizationCache->data();
564 for(qint32 row=0; row<params.
rows; row++) {
566 homogenizationData, params.
cols,
569 conversionData + row * conversionBufferStride,
this, params.
cols,
570 renderingIntent, conversionFlags);
592 if (!factory)
return 0;
595 if (models.isEmpty() || models.contains(model)) {
603 Q_ASSERT(csToFallBack);
604 Q_ASSERT(fallBackToCs);
612 QVector <double> channelValues(channelnumber);
613 QVector <float> channelValuesF(channelnumber);
615 for (
int i=0;i<channelnumber;i++){
616 channelValues[i]=channelValuesF[i];
621 qreal hue, sat, luma = 0.0;
622 toHSY(channelValues, &hue, &sat, &luma);
623 luma = pow(luma, 1/2.2);
624 luma = qMin(1.0, luma + step);
625 luma = pow(luma, 2.2);
626 channelValues =
fromHSY(&hue, &sat, &luma);
629 qreal hue, sat, luma = 0.0;
630 toHSY(channelValues, &hue, &sat, &luma);
631 luma = qMin(1.0, luma + step);
632 channelValues =
fromHSY(&hue, &sat, &luma);
634 for (
int i=0;i<channelnumber;i++){
635 channelValuesF[i]=channelValues[i];
642 QVector <double> channelValues(channelnumber);
643 QVector <float> channelValuesF(channelnumber);
645 for (
int i=0;i<channelnumber;i++){
646 channelValues[i]=channelValuesF[i];
651 qreal hue, sat, luma = 0.0;
652 toHSY(channelValues, &hue, &sat, &luma);
653 luma = pow(luma, 1/2.2);
659 luma = pow(luma, 2.2);
660 channelValues =
fromHSY(&hue, &sat, &luma);
663 qreal hue, sat, luma = 0.0;
664 toHSY(channelValues, &hue, &sat, &luma);
670 channelValues =
fromHSY(&hue, &sat, &luma);
672 for (
int i=0;i<channelnumber;i++){
673 channelValuesF[i]=channelValues[i];
680 QVector <double> channelValues(channelnumber);
681 QVector <float> channelValuesF(channelnumber);
683 for (
int i=0;i<channelnumber;i++){
684 channelValues[i]=channelValuesF[i];
687 qreal hue, sat, luma = 0.0;
688 toHSY(channelValues, &hue, &sat, &luma);
690 sat = qBound(0.0, sat, 1.0);
691 channelValues =
fromHSY(&hue, &sat, &luma);
693 for (
int i=0;i<channelnumber;i++){
694 channelValuesF[i]=channelValues[i];
701 QVector <double> channelValues(channelnumber);
702 QVector <float> channelValuesF(channelnumber);
704 for (
int i=0;i<channelnumber;i++){
705 channelValues[i]=channelValuesF[i];
708 qreal hue, sat, luma = 0.0;
709 toHSY(channelValues, &hue, &sat, &luma);
711 sat = qBound(0.0, sat, 1.0);
712 channelValues =
fromHSY(&hue, &sat, &luma);
714 for (
int i=0;i<channelnumber;i++){
715 channelValuesF[i]=channelValues[i];
722 QVector <double> channelValues(channelnumber);
723 QVector <float> channelValuesF(channelnumber);
725 for (
int i=0;i<channelnumber;i++){
726 channelValues[i]=channelValuesF[i];
729 qreal hue, sat, luma = 0.0;
730 toHSY(channelValues, &hue, &sat, &luma);
736 channelValues =
fromHSY(&hue, &sat, &luma);
738 for (
int i=0;i<channelnumber;i++){
739 channelValuesF[i]=channelValues[i];
746 QVector <double> channelValues(channelnumber);
747 QVector <float> channelValuesF(channelnumber);
749 for (
int i=0;i<channelnumber;i++){
750 channelValues[i]=channelValuesF[i];
753 qreal hue, sat, luma = 0.0;
754 toHSY(channelValues, &hue, &sat, &luma);
760 channelValues =
fromHSY(&hue, &sat, &luma);
762 for (
int i=0;i<channelnumber;i++){
763 channelValuesF[i]=channelValues[i];
771 QVector <double> channelValues(channelnumber);
772 QVector <float> channelValuesF(channelnumber);
774 for (
int i=0;i<channelnumber;i++){
775 channelValues[i]=channelValuesF[i];
779 toYUV(channelValues, &y, &
u, &
v);
781 u = qBound(0.0,
u, 1.0);
784 for (
int i=0;i<channelnumber;i++){
785 channelValuesF[i]=channelValues[i];
792 QVector <double> channelValues(channelnumber);
793 QVector <float> channelValuesF(channelnumber);
795 for (
int i=0;i<channelnumber;i++){
796 channelValues[i]=channelValuesF[i];
800 toYUV(channelValues, &y, &
u, &
v);
802 u = qBound(0.0,
u, 1.0);
805 for (
int i=0;i<channelnumber;i++){
806 channelValuesF[i]=channelValues[i];
814 QVector <double> channelValues(channelnumber);
815 QVector <float> channelValuesF(channelnumber);
817 for (
int i=0;i<channelnumber;i++){
818 channelValues[i]=channelValuesF[i];
822 toYUV(channelValues, &y, &
u, &
v);
824 v = qBound(0.0,
v, 1.0);
827 for (
int i=0;i<channelnumber;i++){
828 channelValuesF[i]=channelValues[i];
836 QVector <double> channelValues(channelnumber);
837 QVector <float> channelValuesF(channelnumber);
839 for (
int i=0;i<channelnumber;i++){
840 channelValues[i]=channelValuesF[i];
844 toYUV(channelValues, &y, &
u, &
v);
846 v = qBound(0.0,
v, 1.0);
849 for (
int i=0;i<channelnumber;i++){
850 channelValuesF[i]=channelValues[i];
859 KoColorConversionTransformation::ConversionFlags conversionFlags)
const
862 QImage img = QImage(width, height, QImage::Format_ARGB32);
867 this->
convertPixelsTo(
const_cast<quint8 *
>(data), img.bits(), dstCS, width * height, renderingIntent, conversionFlags);
887 const int rgbPixelSize =
sizeof(KoBgrU16Traits::Pixel);
888 QScopedArrayPointer<quint8> rgbBuffer(
new quint8[(nPixels + 1) * rgbPixelSize]);
889 quint8* rgbBrushColorBuffer = rgbBuffer.data() + nPixels * rgbPixelSize;
893 this->
toRgbA16(brushColor, rgbBrushColorBuffer, 1);
894 fillGrayBrushWithColorPreserveLightnessRGB<KoBgrU16Traits>(rgbBuffer.data(), brush, rgbBrushColorBuffer, strength, nPixels);
895 this->
fromRgbA16(rgbBuffer.data(), dst, nPixels);
903 const int rgbPixelSize =
sizeof(KoBgrU16Traits::Pixel);
904 QScopedArrayPointer<quint8> dstBuffer(
new quint8[nPixels * rgbPixelSize]);
906 this->
toRgbA16(dst, dstBuffer.data(), nPixels);
907 modulateLightnessByGrayBrushRGB<KoBgrU16Traits>(dstBuffer.data(), brush, strength, nPixels);
908 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 QVector< qreal > getColorantsxyY() const =0
virtual void linearizeFloatValue(QVector< qreal > &Value) const =0
virtual void delinearizeFloatValue(QVector< qreal > &Value) 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