diff --git a/libs/pigment/KoColorConversions.cpp b/libs/pigment/KoColorConversions.cpp index 5071c8e3154..82f6d7edbe3 100644 --- a/libs/pigment/KoColorConversions.cpp +++ b/libs/pigment/KoColorConversions.cpp @@ -1,909 +1,909 @@ /* * Copyright (c) 2005 Boudewijn Rempt * Copyright (c) 2014 Wolthera van Hövell * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KoColorConversions.h" #include #include /** * A number of often-used conversions between color models */ void rgb_to_hsv(int R, int G, int B, int *H, int *S, int *V) { unsigned int max = R; unsigned int min = R; unsigned char maxValue = 0; // r = 0, g = 1, b = 2 // find maximum and minimum RGB values if (static_cast(G) > max) { max = G; maxValue = 1; } if (static_cast(B) > max) { max = B; maxValue = 2; } if (static_cast(G) < min) min = G; if (static_cast(B) < min) min = B; int delta = max - min; *V = max; // value *S = max ? (510 * delta + max) / (2 * max) : 0; // saturation // calc hue if (*S == 0) *H = -1; // undefined hue else { switch (maxValue) { case 0: // red if (G >= B) *H = (120 * (G - B) + delta) / (2 * delta); else *H = (120 * (G - B + delta) + delta) / (2 * delta) + 300; break; case 1: // green if (B > R) *H = 120 + (120 * (B - R) + delta) / (2 * delta); else *H = 60 + (120 * (B - R + delta) + delta) / (2 * delta); break; case 2: // blue if (R > G) *H = 240 + (120 * (R - G) + delta) / (2 * delta); else *H = 180 + (120 * (R - G + delta) + delta) / (2 * delta); break; } } } void hsv_to_rgb(int H, int S, int V, int *R, int *G, int *B) { *R = *G = *B = V; if (S != 0 && H != -1) { // chromatic if (H >= 360) { // angle > 360 H %= 360; } unsigned int f = H % 60; H /= 60; unsigned int p = static_cast(2 * V * (255 - S) + 255) / 510; if (H & 1) { unsigned int q = static_cast(2 * V * (15300 - S * f) + 15300) / 30600; switch (H) { case 1: *R = static_cast(q); *G = static_cast(V); *B = static_cast(p); break; case 3: *R = static_cast(p); *G = static_cast(q); *B = static_cast(V); break; case 5: *R = static_cast(V); *G = static_cast(p); *B = static_cast(q); break; } } else { unsigned int t = static_cast(2 * V * (15300 - (S * (60 - f))) + 15300) / 30600; switch (H) { case 0: *R = static_cast(V); *G = static_cast(t); *B = static_cast(p); break; case 2: *R = static_cast(p); *G = static_cast(V); *B = static_cast(t); break; case 4: *R = static_cast(t); *G = static_cast(p); *B = static_cast(V); break; } } } } #define EPSILON 1e-6 #define UNDEFINED_HUE -1 void RGBToHSV(float r, float g, float b, float *h, float *s, float *v) { float max = qMax(r, qMax(g, b)); float min = qMin(r, qMin(g, b)); *v = max; if (max > EPSILON) { *s = (max - min) / max; } else { *s = 0; } if (*s < EPSILON) { *h = UNDEFINED_HUE; } else { float delta = max - min; if (r == max) { *h = (g - b) / delta; } else if (g == max) { *h = 2 + (b - r) / delta; } else { *h = 4 + (r - g) / delta; } *h *= 60; if (*h < 0) { *h += 360; } } } void HSVToRGB(float h, float s, float v, float *r, float *g, float *b) { if (s < EPSILON || h == UNDEFINED_HUE) { // Achromatic case *r = v; *g = v; *b = v; } else { float f, p, q, t; int i; if (h > 360 - EPSILON) { h -= 360; } h /= 60; i = static_cast(floor(h)); f = h - i; p = v * (1 - s); q = v * (1 - (s * f)); t = v * (1 - (s * (1 - f))); switch (i) { case 0: *r = v; *g = t; *b = p; break; case 1: *r = q; *g = v; *b = p; break; case 2: *r = p; *g = v; *b = t; break; case 3: *r = p; *g = q; *b = v; break; case 4: *r = t; *g = p; *b = v; break; case 5: *r = v; *g = p; *b = q; break; } } } void rgb_to_hls(quint8 red, quint8 green, quint8 blue, float * hue, float * lightness, float * saturation) { float r = red / 255.0; float g = green / 255.0; float b = blue / 255.0; float h = 0; float l = 0; float s = 0; float max, min, delta; max = qMax(r, g); max = qMax(max, b); min = qMin(r, g); min = qMin(min, b); delta = max - min; l = (max + min) / 2; if (delta == 0) { // This is a gray, no chroma... h = 0; s = 0; } else { if (l < 0.5) s = delta / (max + min); else s = delta / (2 - max - min); float delta_r, delta_g, delta_b; delta_r = ((max - r) / 6) / delta; delta_g = ((max - g) / 6) / delta; delta_b = ((max - b) / 6) / delta; if (r == max) h = delta_b - delta_g; else if (g == max) h = (1.0 / 3) + delta_r - delta_b; else if (b == max) h = (2.0 / 3) + delta_g - delta_r; if (h < 0) h += 1; if (h > 1) h += 1; } *hue = h * 360; *saturation = s; *lightness = l; } float hue_value(float n1, float n2, float hue) { if (hue > 360) hue = hue - 360; else if (hue < 0) hue = hue + 360; if (hue < 60) return n1 + (((n2 - n1) * hue) / 60); else if (hue < 180) return n2; else if (hue < 240) return n1 + (((n2 - n1) *(240 - hue)) / 60); else return n1; } void hls_to_rgb(float h, float l, float s, quint8 * r, quint8 * g, quint8 * b) { float m1, m2; if (l <= 0.5) m2 = l * (1 + s); else m2 = l + s - l * s; m1 = 2 * l - m2; *r = (quint8)(hue_value(m1, m2, h + 120) * 255 + 0.5); *g = (quint8)(hue_value(m1, m2, h) * 255 + 0.5); *b = (quint8)(hue_value(m1, m2, h - 120) * 255 + 0.5); } void rgb_to_hls(quint8 r, quint8 g, quint8 b, int * h, int * l, int * s) { float hue, saturation, lightness; rgb_to_hls(r, g, b, &hue, &lightness, &saturation); *h = (int)(hue + 0.5); *l = (int)(lightness * 255 + 0.5); *s = (int)(saturation * 255 + 0.5); } void hls_to_rgb(int h, int l, int s, quint8 * r, quint8 * g, quint8 * b) { float hue = h; float lightness = l / 255.0; float saturation = s / 255.0; hls_to_rgb(hue, lightness, saturation, r, g, b); } /* A Fast HSL-to-RGB Transform by Ken Fishkin from "Graphics Gems", Academic Press, 1990 */ void RGBToHSL(float r, float g, float b, float *h, float *s, float *l) { float v; float m; float vm; float r2, g2, b2; v = qMax(r, g); v = qMax(v, b); m = qMin(r, g); m = qMin(m, b); if ((*l = (m + v) / 2.0) <= 0.0) { *h = UNDEFINED_HUE; *s = 0; return; } if ((*s = vm = v - m) > 0.0) { *s /= (*l <= 0.5) ? (v + m) : (2.0 - v - m) ; } else { *h = UNDEFINED_HUE; return; } r2 = (v - r) / vm; g2 = (v - g) / vm; b2 = (v - b) / vm; if (r == v) *h = (g == m ? 5.0 + b2 : 1.0 - g2); else if (g == v) *h = (b == m ? 1.0 + r2 : 3.0 - b2); else *h = (r == m ? 3.0 + g2 : 5.0 - r2); *h *= 60; if (*h == 360.) { *h = 0; } } void HSLToRGB(float h, float sl, float l, float *r, float *g, float *b) { float v; v = (l <= 0.5) ? (l * (1.0 + sl)) : (l + sl - l * sl); if (v <= 0) { *r = *g = *b = 0.0; } else { float m; float sv; int sextant; float fract, vsf, mid1, mid2; m = l + l - v; sv = (v - m) / v; h /= 60.0; sextant = static_cast(h); fract = h - sextant; vsf = v * sv * fract; mid1 = m + vsf; mid2 = v - vsf; switch (sextant) { case 0: *r = v; *g = mid1; *b = m; break; case 1: *r = mid2; *g = v; *b = m; break; case 2: *r = m; *g = v; *b = mid1; break; case 3: *r = m; *g = mid2; *b = v; break; case 4: *r = mid1; *g = m; *b = v; break; case 5: *r = v; *g = m; *b = mid2; break; } } } //functions for converting from and back to HSI void HSIToRGB(const qreal h,const qreal s, const qreal i, qreal *red, qreal *green, qreal *blue) {//This function takes H, S and I values, which are converted to rgb. qreal onethird = 1.0/3.0; HSYToRGB(h, s, i, red, green, blue, onethird, onethird, onethird); } void RGBToHSI(qreal r,qreal g, qreal b, qreal *h, qreal *s, qreal *i) { qreal onethird = 1.0/3.0; RGBToHSY(r, g, b, h, s, i, onethird, onethird, onethird); } //functions for converting from and back to hsy' void HSYToRGB(const qreal h,const qreal s, const qreal y, qreal *red, qreal *green, qreal *blue, qreal R, qreal G, qreal B) {//This function takes H, S and Y values, which are converted to rgb. //Those are then used to create a qcolor. qreal hue = 0.0; qreal sat = 0.0; qreal luma = 0.0; if (h>1.0 || h<0.0){hue=fmod(h, 1.0);} else {hue=h;} if (s<0.0){sat=0.0;} else {sat=s;} //if (y>1.0){luma=1.0;} if (y<0.0){luma=0.0;} else {luma=y;} qreal segment = 0.166667;//1/6; qreal r=0.0; qreal g=0.0; qreal b=0.0; //weights for rgb to Y'(Luma), these are the same weights used in color space maths and the desaturate. //This is not luminance or luminosity, it just quacks like it. //qreal R=0.299; //qreal G=0.587; //qreal B=0.114; //The intermediary variables for the weighted HSL formula, based on the HSL in KoColorConversions. qreal max_sat, m, fract, luma_a, chroma, x; if (hue >= 0.0 && hue < (segment) ) { //need to treat this as a weighted hsl thingy. //so first things first, at which luma is the maximum saturation for this hue? //between R and G+R (yellow) max_sat = R + ( G*(hue*6) ); if (luma<=max_sat){luma_a = (luma/max_sat)*0.5; chroma=sat*2*luma_a;} else {luma_a = ((luma-max_sat)/(1-max_sat)*0.5)+0.5; chroma=sat*(2-2*luma_a);} fract = hue*6.0; x = (1-fabs(fmod(fract,2)-1))*chroma; r = chroma; g=x; b=0; m = luma-( (R*r)+(B*b)+(G*g) ); r += m; g += m; b += m; } else if (hue >= (segment) && hue < (2.0*segment) ) { max_sat = (G+R) - (R*(hue-segment)*6); if (luma= (2.0*segment) && hue < (3.0*segment) ) { max_sat = G + (B*(hue-2.0*segment)*6); if (luma= (3.0*segment) && hue < (4.0*segment) ) { max_sat = (G+B) - (G*(hue-3.0*segment)*6); if (luma= (4.0*segment) && hue < (5*segment) ) { max_sat = B + (R*((hue-4.0*segment)*6)); if (luma= (5.0*segment) && hue <= 1.0) { max_sat = (B+R) - (B*(hue-5.0*segment)*6); if (luma1.0){r=1.0;} //if (g>1.0){g=1.0;} //if (b>1.0){b=1.0;} //don't limit upwards due to floating point. if (r<0.0){r=0.0;} if (g<0.0){g=0.0;} if (b<0.0){b=0.0;} *red=r; *green=g; *blue=b; } void RGBToHSY(const qreal r,const qreal g,const qreal b, qreal *h, qreal *s, qreal *y, qreal R, qreal G, qreal B) { //This is LUMA btw, not Luminance. //Using these RGB values, we calculate the H, S and I. qreal red; qreal green; qreal blue; if (r<0.0){red=0.0;} else {red=r;} if (g<0.0){green=0.0;} else {green=g;} if (b<0.0){blue=0.0;} else {blue=b;} qreal minval = qMin(r, qMin(g, b)); qreal maxval = qMax(r, qMax(g, b)); qreal hue = 0.0; qreal sat = 0.0; qreal luma = 0.0; //weights for rgb, these are the same weights used in color space maths and the desaturate. //qreal R=0.299; //qreal G=0.587; //qreal B=0.114; luma=(R*red+G*green+B*blue); qreal luma_a=luma;//defined later qreal chroma = maxval-minval; qreal max_sat=0.5; if(chroma==0) { hue = 0.0; sat = 0.0; } else { //the following finds the hue if(maxval==r) { //hue = fmod(((g-b)/chroma), 6.0); //above doesn't work so let's try this one: if (minval==b) { hue = (g-b)/chroma; } else { hue = (g-b)/chroma + 6.0; } } else if(maxval==g) { hue = (b-r)/chroma + 2.0; } else if(maxval==b) { hue = (r-g)/chroma + 4.0; } hue /=6.0;//this makes sure that hue is in the 0-1.0 range. //Most HSY formula will tell you that Sat=Chroma. However, this HSY' formula tries to be a //weighted HSL formula, where instead of 0.5, we search for a Max_Sat value, which is the Y' //at which the saturation is maximum. //This requires using the hue, and combining the weighting values accordingly. qreal segment = 0.166667; if (hue>1.0 || hue<0.0) { hue=fmod(hue, 1.0); } if (hue>=0.0 && hue=segment && hue<(2.0*segment)) { max_sat = (G+R) - R*((hue-segment)*6); } else if (hue>=(2.0*segment) && hue<(3.0*segment)) { max_sat = G + B*((hue-2.0*segment)*6); } else if (hue>=(3.0*segment) && hue<(4.0*segment)) { max_sat = (B+G) - G*((hue-3.0*segment)*6); } else if (hue>=(4.0*segment) && hue<(5.0*segment)) { max_sat = (B) + R*((hue-4.0*segment)*6); } else if (hue>=(5.0*segment) && hue<=1.0) { max_sat = (R+B) - B*((hue-5.0*segment)*6); } else { max_sat=0.5; } if(max_sat>1.0 || max_sat<0.0){ //This should not show up during normal use max_sat=(fmod(max_sat,1.0)); } //If it does, it'll try to correct, but it's not good! //This is weighting the luma for the saturation) if (luma <= max_sat) { luma_a = (luma/max_sat)*0.5; } else{ luma_a = ((luma-max_sat)/(1-max_sat)*0.5)+0.5; } if (chroma > 0.0) { sat = (luma <= max_sat) ? (chroma/ (2*luma_a) ) :(chroma/(2.0-(2*luma_a) ) ) ; } } //if (sat>1.0){sat=1.0;} //if (luma>1.0){luma=1.0;} if (sat<0.0){sat=0.0;} if (luma<0.0){luma=0.0;} *h=hue; *s=sat; *y=luma; } //Extra: Functions for converting from and back to HCI. Where the HSI function is forced cylindrical, HCI is a //double cone. This is for compatibility purposes, and of course, making future programmers who expect a double-cone // function less sad. These algorithms were taken from wikipedia. void HCIToRGB(const qreal h, const qreal c, const qreal i, qreal *red, qreal *green, qreal *blue) { //This function may not be correct, but it's based on the HCY function on the basis of seeing HCI as similar //to the weighted HCY, but assuming that the weights are the same(one-third). qreal hue=0.0; qreal chroma=0.0; qreal intensity=0.0; if(i<0.0){intensity = 0.0;} else{intensity = i;} if (h>1.0 || h<0.0){hue=fmod(h, 1.0);} else {hue=h;} if(c<0.0){chroma = 0.0;} else{chroma = c;} const qreal onethird = 1.0/3.0; qreal r=0.0; qreal g=0.0; qreal b=0.0; int fract = static_cast(hue*6.0); qreal x = (1-fabs(fmod(hue*6.0,2)-1) )*chroma; switch (fract) { case 0:r = chroma; g=x; b=0;break; case 1:r = x; g=chroma; b=0;break; case 2:r = 0; g=chroma; b=x;break; case 3:r = 0; g=x; b=chroma;break; case 4:r = x; g=0; b=chroma;break; case 5:r = chroma; g=0; b=x;break; } qreal m = intensity-( onethird*(r+g+b) ); r += m; g += m; b += m; *red=r; *green=g; *blue=b; } void RGBToHCI(const qreal r,const qreal g,const qreal b, qreal *h, qreal *c, qreal *i) { qreal minval = qMin(r, qMin(g, b)); qreal maxval = qMax(r, qMax(g, b)); qreal hue = 0.0; qreal sat = 0.0; qreal intensity = 0.0; intensity=(r+g+b)/3.0; qreal chroma = maxval-minval; if(chroma==0) { hue = 0.0; sat = 0.0; } else { //the following finds the hue if(maxval==r) { if (minval==b) { hue = (g-b)/chroma; } else { hue = (g-b)/chroma + 6.0; } } else if(maxval==g) { hue = (b-r)/chroma + 2.0; } else if(maxval==b) { hue = (r-g)/chroma + 4.0; } hue /=6.0;//this makes sure that hue is in the 0-1.0 range. sat= 1-(minval/intensity); } *h=hue; *c=sat; *i=intensity; } void HCYToRGB(const qreal h, const qreal c, const qreal y, qreal *red, qreal *green, qreal *blue, qreal R, qreal G, qreal B) { qreal hue=0.0; qreal chroma=c; qreal luma=y; if (h>1.0 || h<0.0){hue=(fmod((h*2.0), 2.0))/2.0;} else {hue=h;} //const qreal R=0.299; //const qreal G=0.587; //const qreal B=0.114; qreal r=0.0; qreal g=0.0; qreal b=0.0; int fract =static_cast(hue*6.0); qreal x = (1-fabs(fmod(hue*6.0,2)-1) )*chroma; switch (fract) { case 0:r = chroma; g=x; b=0;break; case 1:r = x; g=chroma; b=0;break; case 2:r = 0; g=chroma; b=x;break; case 3:r = 0; g=x; b=chroma;break; case 4:r = x; g=0; b=chroma;break; case 5:r = chroma; g=0; b=x;break; } qreal m = luma-( (R*r)+(B*b)+(G*g) ); r += m; g += m; b += m; *red=r; *green=g; *blue=b; } void RGBToHCY(const qreal r,const qreal g,const qreal b, qreal *h, qreal *c, qreal *y, qreal R, qreal G, qreal B) { qreal minval = qMin(r, qMin(g, b)); qreal maxval = qMax(r, qMax(g, b)); qreal hue = 0.0; qreal chroma = 0.0; qreal luma = 0.0; //weights for rgb, these are the same weights used in color space maths and the desaturate. //qreal R=0.299; //qreal G=0.587; //qreal B=0.114; luma=(R*r+G*g+B*b); chroma = maxval-minval; if(chroma==0) { hue = 0.0; } else { //the following finds the hue if(maxval==r) { //hue = fmod(((g-b)/chroma), 6.0); //above doesn't work so let's try this one: if (minval==b) { hue = (g-b)/chroma; } else { hue = (g-b)/chroma + 6.0; } } else if(maxval==g) { hue = (b-r)/chroma + 2.0; } else if(maxval==b) { hue = (r-g)/chroma + 4.0; } hue /=6.0;//this makes sure that hue is in the 0-1.0 range. } if (chroma<0.0){chroma=0.0;} if (luma<0.0){luma=0.0;} - *h=qBound(0.0,hue,1.0); + *h=qBound(0.0,hue,1.0); *c=chroma; *y=luma; } void RGBToYUV(const qreal r,const qreal g,const qreal b, qreal *y, qreal *u, qreal *v, qreal R, qreal G, qreal B) { qreal uvmax = 0.5; qreal luma = R*r+G*g+B*b; qreal chromaBlue = uvmax*( (b - luma) / (1.0-B) ); qreal chromaRed = uvmax*( (r - luma) / (1.0-R) ); *y = luma; //qBound(0.0,luma,1.0); *u = chromaBlue+uvmax;//qBound(0.0,chromaBlue+ uvmax,1.0); *v = chromaRed+uvmax;//qBound(0.0,chromaRed + uvmax,1.0); } void YUVToRGB(const qreal y, const qreal u, const qreal v, qreal *r, qreal *g, qreal *b, qreal R, qreal G, qreal B) { qreal uvmax = 0.5; qreal chromaBlue = u-uvmax;//qBound(0.0,u,1.0)- uvmax;//put into -0.5-+0.5 range// qreal chromaRed = v-uvmax;//qBound(0.0,v,1.0)- uvmax; qreal negB = 1.0-B; qreal negR = 1.0-R; qreal red = y+(chromaRed * (negR / uvmax) ); qreal green = y-(chromaBlue * ((B*negB) / (uvmax*G)) ) - (chromaRed* ((R*negR) / (uvmax*G))); qreal blue = y+(chromaBlue * (negB / uvmax) ); *r=red;//qBound(0.0,red ,1.0); *g=green;//qBound(0.0,green,1.0); *b=blue;//qBound(0.0,blue ,1.0); } void LabToLCH(const qreal l, const qreal a, const qreal b, qreal *L, qreal *C, qreal *H) { qreal atemp = (a - 0.5)*10.0;//the multiplication is only so that we get out of floating-point maths qreal btemp = (b - 0.5)*10.0; - *L=qBound(0.0,l,1.0); + *L=qBound(0.0,l,1.0); *C=sqrt( pow(atemp,2.0) + pow(btemp,2.0) )*0.1; qreal hue = (atan2(btemp,atemp))* 180.0 / M_PI; if (hue<0.0) { hue+=360.0; } else { hue = fmod(hue, 360.0); } *H=hue/360.0; } void LCHToLab(const qreal L, const qreal C, const qreal H, qreal *l, qreal *a, qreal *b) { - qreal chroma = qBound(0.0,C,1.0); - qreal hue = (qBound(0.0,H,1.0)*360.0)* M_PI / 180.0; - *l=qBound(0.0,L,1.0); + qreal chroma = qBound(0.0,C,1.0); + qreal hue = (qBound(0.0,H,1.0)*360.0)* M_PI / 180.0; + *l=qBound(0.0,L,1.0); *a=(chroma * cos(hue) ) + 0.5; *b=(chroma * sin(hue) ) + 0.5; } void XYZToxyY(const qreal X, const qreal Y, const qreal Z, qreal *x, qreal *y, qreal *yY) { - qBound(0.0,X,1.0); - qBound(0.0,Y,1.0); - qBound(0.0,Z,1.0); + qBound(0.0,X,1.0); + qBound(0.0,Y,1.0); + qBound(0.0,Z,1.0); *x=X/(X+Y+Z); *y=Y/(X+Y+Z); *yY=Y; } void xyYToXYZ(const qreal x, const qreal y, const qreal yY, qreal *X, qreal *Y, qreal *Z) { - qBound(0.0,x,1.0); - qBound(0.0,y,1.0); - qBound(0.0,yY,1.0); + qBound(0.0,x,1.0); + qBound(0.0,y,1.0); + qBound(0.0,yY,1.0); *X=(x*yY)/y; *Z=((1.0-x-y)/yY)/y; *Y=yY; } void CMYToCMYK(qreal *c, qreal *m, qreal *y, qreal *k) { qreal cyan, magenta, yellow, key = 1.0; cyan = *c; magenta = *m; yellow = *y; if ( cyan < key ) {key = cyan;} if ( magenta < key ) {key = magenta;} if ( yellow < key ) {key = yellow;} if ( key == 1 ) { //Black cyan = 0; magenta = 0; yellow = 0; } else { cyan = ( cyan - key ) / ( 1.0 - key ); magenta = ( magenta - key ) / ( 1.0 - key ); yellow = ( yellow - key ) / ( 1.0 - key ); } - *c=qBound(0.0,cyan ,1.0); - *m=qBound(0.0,magenta,1.0); - *y=qBound(0.0,yellow ,1.0); - *k=qBound(0.0,key ,1.0); + *c=qBound(0.0,cyan ,1.0); + *m=qBound(0.0,magenta,1.0); + *y=qBound(0.0,yellow ,1.0); + *k=qBound(0.0,key ,1.0); } /*code from easyrgb.com*/ void CMYKToCMY(qreal *c, qreal *m, qreal *y, qreal *k) { qreal key = *k; qreal cyan = *c; qreal magenta = *m; qreal yellow = *y; cyan = ( cyan * ( 1.0 - key ) + key ); magenta = ( magenta * ( 1.0 - key ) + key ); yellow = ( yellow * ( 1.0 - key ) + key ); - *c=qBound(0.0,cyan ,1.0); - *m=qBound(0.0,magenta,1.0); - *y=qBound(0.0,yellow ,1.0); + *c=qBound(0.0,cyan ,1.0); + *m=qBound(0.0,magenta,1.0); + *y=qBound(0.0,yellow ,1.0); } diff --git a/libs/pigment/KoColorSpace.cpp b/libs/pigment/KoColorSpace.cpp index c34c458dcec..55b29567ba0 100644 --- a/libs/pigment/KoColorSpace.cpp +++ b/libs/pigment/KoColorSpace.cpp @@ -1,796 +1,726 @@ /* * Copyright (c) 2005 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoColorSpace.h" #include "KoColorSpace_p.h" #include "KoChannelInfo.h" #include "DebugPigment.h" #include "KoCompositeOp.h" #include "KoColorTransformation.h" #include "KoColorTransformationFactory.h" #include "KoColorTransformationFactoryRegistry.h" #include "KoColorConversionCache.h" #include "KoColorConversionSystem.h" #include "KoColorSpaceRegistry.h" #include "KoColorProfile.h" #include "KoCopyColorConversionTransformation.h" #include "KoFallBackColorTransformation.h" #include "KoUniqueNumberForIdServer.h" #include "KoMixColorsOp.h" #include "KoConvolutionOp.h" #include "KoCompositeOpRegistry.h" #include #include #include #include #include #include KoColorSpace::KoColorSpace() : d(new Private()) { } KoColorSpace::KoColorSpace(const QString &id, const QString &name, KoMixColorsOp* mixColorsOp, KoConvolutionOp* convolutionOp) : d(new Private()) { d->id = id; d->idNumber = KoUniqueNumberForIdServer::instance()->numberForId(d->id); d->name = name; d->mixColorsOp = mixColorsOp; d->convolutionOp = convolutionOp; d->transfoToRGBA16 = 0; d->transfoFromRGBA16 = 0; d->transfoToLABA16 = 0; d->transfoFromLABA16 = 0; d->gamutXYY = QPolygonF(); d->TRCXYY = QPolygonF(); d->colorants = QVector (0); d->lumaCoefficients = QVector (0); d->deletability = NotOwnedByRegistry; } KoColorSpace::~KoColorSpace() { Q_ASSERT(d->deletability != OwnedByRegistryDoNotDelete); qDeleteAll(d->compositeOps); foreach(KoChannelInfo * channel, d->channels) { delete channel; } if (d->deletability == NotOwnedByRegistry) { KoColorConversionCache* cache = KoColorSpaceRegistry::instance()->colorConversionCache(); if (cache) { cache->colorSpaceIsDestroyed(this); } } delete d->mixColorsOp; delete d->convolutionOp; delete d->transfoToRGBA16; delete d->transfoFromRGBA16; delete d->transfoToLABA16; delete d->transfoFromLABA16; delete d; } bool KoColorSpace::operator==(const KoColorSpace& rhs) const { const KoColorProfile* p1 = rhs.profile(); const KoColorProfile* p2 = profile(); return d->idNumber == rhs.d->idNumber && ((p1 == p2) || (*p1 == *p2)); } QString KoColorSpace::id() const { return d->id; } QString KoColorSpace::name() const { return d->name; } //Color space info stuff. QPolygonF KoColorSpace::gamutXYY() const { if (d->gamutXYY.empty()) { //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. //first make a list of colors. qreal max = 1.0; if ((colorModelId().id()=="CMYKA" || colorModelId().id()=="LABA") && colorDepthId().id()=="F32") { //boundaries for cmyka/laba have trouble getting the max values for Float, and are pretty awkward in general. max = this->channels().at(0)->getUIMax(); } int samples = 5;//amount of samples in our color space. QString name = KoColorSpaceRegistry::instance()->colorSpaceFactory("XYZAF32")->defaultProfile(); const KoColorSpace* xyzColorSpace = KoColorSpaceRegistry::instance()->colorSpace("XYZA", "F32", name); quint8 *data = new quint8[pixelSize()]; quint8 data2[16]; // xyza f32 is 4 floats, that is 16 bytes per pixel. //QVector sampleCoordinates(pow(colorChannelCount(),samples)); //sampleCoordinates.fill(0.0); // This is fixed to 5 since the maximum number of channels are 5 for CMYKA - QVector channelValuesF(5);//for getting the coordinates. + QVector channelValues(5);//for getting the coordinates. for(int x=0;xnormalisedChannelsValue(data2, channelValuesF); - qreal x = channelValuesF[0]/(channelValuesF[0]+channelValuesF[1]+channelValuesF[2]); - qreal y = channelValuesF[1]/(channelValuesF[0]+channelValuesF[1]+channelValuesF[2]); + xyzColorSpace->normalisedChannelsValue(data2, channelValues); + qreal x = channelValues[0]/(channelValues[0]+channelValues[1]+channelValues[2]); + qreal y = channelValues[1]/(channelValues[0]+channelValues[1]+channelValues[2]); d->gamutXYY << QPointF(x,y); } else { for(int y=0;ynormalisedChannelsValue(data2, channelValuesF); - qreal x = channelValuesF[0] / (channelValuesF[0] + channelValuesF[1] + channelValuesF[2]); - qreal y = channelValuesF[1] / (channelValuesF[0] + channelValuesF[1] + channelValuesF[2]); + xyzColorSpace->normalisedChannelsValue(data2, channelValues); + qreal x = channelValues[0] / (channelValues[0] + channelValues[1] + channelValues[2]); + qreal y = channelValues[1] / (channelValues[0] + channelValues[1] + channelValues[2]); d->gamutXYY<< QPointF(x,y); } } else { - channelValuesF[0]=(max/(samples-1))*(x); - channelValuesF[1]=(max/(samples-1))*(y); - channelValuesF[2]=(max/(samples-1))*(z); - channelValuesF[3]=max; + channelValues[0]=(max/(samples-1))*(x); + channelValues[1]=(max/(samples-1))*(y); + channelValues[2]=(max/(samples-1))*(z); + channelValues[3]=max; if (colorModelId().id()!="XYZA") { //no need for conversion when using xyz. - fromNormalisedChannelsValue(data, channelValuesF); + fromNormalisedChannelsValue(data, channelValues); convertPixelsTo(data, data2, xyzColorSpace, 1, KoColorConversionTransformation::IntentAbsoluteColorimetric, KoColorConversionTransformation::adjustmentConversionFlags()); - xyzColorSpace->normalisedChannelsValue(data2,channelValuesF); + xyzColorSpace->normalisedChannelsValue(data2,channelValues); } - qreal x = channelValuesF[0]/(channelValuesF[0]+channelValuesF[1]+channelValuesF[2]); - qreal y = channelValuesF[1]/(channelValuesF[0]+channelValuesF[1]+channelValuesF[2]); + qreal x = channelValues[0]/(channelValues[0]+channelValues[1]+channelValues[2]); + qreal y = channelValues[1]/(channelValues[0]+channelValues[1]+channelValues[2]); d->gamutXYY<< QPointF(x,y); } } } } } delete[] data; //if we ever implement a boundary-checking thing I'd add it here. return d->gamutXYY; } else { return d->gamutXYY; } } QPolygonF KoColorSpace::estimatedTRCXYY() const { if (d->TRCXYY.empty()){ qreal max = 1.0; if ((colorModelId().id()=="CMYKA" || colorModelId().id()=="LABA") && colorDepthId().id()=="F32") { //boundaries for cmyka/laba have trouble getting the max values for Float, and are pretty awkward in general. max = this->channels().at(0)->getUIMax(); } QString name = KoColorSpaceRegistry::instance()->colorSpaceFactory("XYZAF16")->defaultProfile(); const KoColorSpace* xyzColorSpace = KoColorSpaceRegistry::instance()->colorSpace("XYZA", "F16", name); quint8 *data = new quint8[pixelSize()]; quint8 data2[8]; // xyza is 8 bytes per pixel. // This is fixed to 5 since the maximum number of channels are 5 for CMYKA - QVector channelValuesF(5);//for getting the coordinates. + QVector channelValues(5);//for getting the coordinates. for (quint32 i=0; i0; j--){ - channelValuesF.fill(0.0); - channelValuesF[i] = ((max/4)*(5-j)); + channelValues.fill(0.0); + channelValues[i] = ((max/4)*(5-j)); if (colorModelId().id()!="XYZA") { //no need for conversion when using xyz. - fromNormalisedChannelsValue(data, channelValuesF); + fromNormalisedChannelsValue(data, channelValues); convertPixelsTo(data, data2, xyzColorSpace, 1, KoColorConversionTransformation::IntentAbsoluteColorimetric, KoColorConversionTransformation::adjustmentConversionFlags()); - xyzColorSpace->normalisedChannelsValue(data2,channelValuesF); + xyzColorSpace->normalisedChannelsValue(data2,channelValues); } if (j==0) { - colorantY = channelValuesF[1]; + colorantY = channelValues[1]; if (d->colorants.size()<2){ d->colorants.resize(3*colorChannelCount()); - d->colorants[i] = channelValuesF[0]/(channelValuesF[0]+channelValuesF[1]+channelValuesF[2]); - d->colorants[i+1]= channelValuesF[1]/(channelValuesF[0]+channelValuesF[1]+channelValuesF[2]); - d->colorants[i+2]= channelValuesF[1]; + d->colorants[i] = channelValues[0]/(channelValues[0]+channelValues[1]+channelValues[2]); + d->colorants[i+1]= channelValues[1]/(channelValues[0]+channelValues[1]+channelValues[2]); + d->colorants[i+2]= channelValues[1]; } } - d->TRCXYY << QPointF(channelValuesF[1]/colorantY, ((1.0/4)*(5-j))); + d->TRCXYY << QPointF(channelValues[1]/colorantY, ((1.0/4)*(5-j))); } } else { for (int j=0; j<5; j++){ - channelValuesF.fill(0.0); - channelValuesF[i] = ((max/4)*(j)); + channelValues.fill(0.0); + channelValues[i] = ((max/4)*(j)); - fromNormalisedChannelsValue(data, channelValuesF); + fromNormalisedChannelsValue(data, channelValues); convertPixelsTo(data, data2, xyzColorSpace, 1, KoColorConversionTransformation::IntentAbsoluteColorimetric, KoColorConversionTransformation::adjustmentConversionFlags()); - xyzColorSpace->normalisedChannelsValue(data2,channelValuesF); + xyzColorSpace->normalisedChannelsValue(data2,channelValues); if (j==0) { - colorantY = channelValuesF[1]; + colorantY = channelValues[1]; if (d->colorants.size()<2){ d->colorants.resize(3*colorChannelCount()); - d->colorants[i] = channelValuesF[0]/(channelValuesF[0]+channelValuesF[1]+channelValuesF[2]); - d->colorants[i+1]= channelValuesF[1]/(channelValuesF[0]+channelValuesF[1]+channelValuesF[2]); - d->colorants[i+2]= channelValuesF[1]; + d->colorants[i] = channelValues[0]/(channelValues[0]+channelValues[1]+channelValues[2]); + d->colorants[i+1]= channelValues[1]/(channelValues[0]+channelValues[1]+channelValues[2]); + d->colorants[i+2]= channelValues[1]; } } - d->TRCXYY << QPointF(channelValuesF[1]/colorantY, ((1.0/4)*(j))); + d->TRCXYY << QPointF(channelValues[1]/colorantY, ((1.0/4)*(j))); } } } delete[] data; return d->TRCXYY; } else { return d->TRCXYY; } } QVector KoColorSpace::colorants() const { if (d->colorants.size()>1){ return d->colorants; } else if (profile() && profile()->hasColorants()) { d->colorants.resize(3*colorChannelCount()); d->colorants = profile()->getColorantsxyY(); return d->colorants; } else { estimatedTRCXYY(); return d->colorants; } } QVector KoColorSpace::lumaCoefficients() const { if (d->lumaCoefficients.size()>1){ return d->lumaCoefficients; } else { d->lumaCoefficients.resize(3); if (colorModelId().id()!="RGBA") { d->lumaCoefficients.fill(0.33); } else { colorants(); if (d->colorants[2]<0 || d->colorants[5]<0 || d->colorants[8]<0) { d->lumaCoefficients[0]=0.2126; d->lumaCoefficients[1]=0.7152; d->lumaCoefficients[2]=0.0722; } else { d->lumaCoefficients[0]=d->colorants[2]; d->lumaCoefficients[1]=d->colorants[5]; d->lumaCoefficients[2]=d->colorants[8]; } } return d->lumaCoefficients; } } QList KoColorSpace::channels() const { return d->channels; } QBitArray KoColorSpace::channelFlags(bool color, bool alpha) const { QBitArray ba(d->channels.size()); if (!color && !alpha) return ba; for (int i = 0; i < d->channels.size(); ++i) { KoChannelInfo * channel = d->channels.at(i); if ((color && channel->channelType() == KoChannelInfo::COLOR) || (alpha && channel->channelType() == KoChannelInfo::ALPHA)) ba.setBit(i, true); } return ba; } void KoColorSpace::addChannel(KoChannelInfo * ci) { d->channels.push_back(ci); } bool KoColorSpace::hasCompositeOp(const QString& id) const { return d->compositeOps.contains(id); } QList KoColorSpace::compositeOps() const { return d->compositeOps.values(); } KoMixColorsOp* KoColorSpace::mixColorsOp() const { return d->mixColorsOp; } KoConvolutionOp* KoColorSpace::convolutionOp() const { return d->convolutionOp; } const KoCompositeOp * KoColorSpace::compositeOp(const QString & id) const { const QHash::ConstIterator it = d->compositeOps.constFind(id); if (it != d->compositeOps.constEnd()) { return it.value(); } else { warnPigment << "Asking for non-existent composite operation " << id << ", returning " << COMPOSITE_OVER; return d->compositeOps.value(COMPOSITE_OVER); } } void KoColorSpace::addCompositeOp(const KoCompositeOp * op) { if (op->colorSpace()->id() == id()) { d->compositeOps.insert(op->id(), const_cast(op)); } } const KoColorConversionTransformation* KoColorSpace::toLabA16Converter() const { if (!d->transfoToLABA16) { d->transfoToLABA16 = KoColorSpaceRegistry::instance()->colorConversionSystem()->createColorConverter(this, KoColorSpaceRegistry::instance()->lab16(""), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()) ; } return d->transfoToLABA16; } const KoColorConversionTransformation* KoColorSpace::fromLabA16Converter() const { if (!d->transfoFromLABA16) { d->transfoFromLABA16 = KoColorSpaceRegistry::instance()->colorConversionSystem()->createColorConverter(KoColorSpaceRegistry::instance()->lab16(""), this, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()) ; } return d->transfoFromLABA16; } const KoColorConversionTransformation* KoColorSpace::toRgbA16Converter() const { if (!d->transfoToRGBA16) { d->transfoToRGBA16 = KoColorSpaceRegistry::instance()->colorConversionSystem()->createColorConverter(this, KoColorSpaceRegistry::instance()->rgb16(""), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()) ; } return d->transfoToRGBA16; } const KoColorConversionTransformation* KoColorSpace::fromRgbA16Converter() const { if (!d->transfoFromRGBA16) { d->transfoFromRGBA16 = KoColorSpaceRegistry::instance()->colorConversionSystem()->createColorConverter(KoColorSpaceRegistry::instance()->rgb16("") , this, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()) ; } return d->transfoFromRGBA16; } void KoColorSpace::toLabA16(const quint8 * src, quint8 * dst, quint32 nPixels) const { toLabA16Converter()->transform(src, dst, nPixels); } void KoColorSpace::fromLabA16(const quint8 * src, quint8 * dst, quint32 nPixels) const { fromLabA16Converter()->transform(src, dst, nPixels); } void KoColorSpace::toRgbA16(const quint8 * src, quint8 * dst, quint32 nPixels) const { toRgbA16Converter()->transform(src, dst, nPixels); } void KoColorSpace::fromRgbA16(const quint8 * src, quint8 * dst, quint32 nPixels) const { fromRgbA16Converter()->transform(src, dst, nPixels); } KoColorConversionTransformation* KoColorSpace::createColorConverter(const KoColorSpace * dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const { if (*this == *dstColorSpace) { return new KoCopyColorConversionTransformation(this); } else { return KoColorSpaceRegistry::instance()->colorConversionSystem()->createColorConverter(this, dstColorSpace, renderingIntent, conversionFlags); } } bool KoColorSpace::convertPixelsTo(const quint8 * src, quint8 * dst, const KoColorSpace * dstColorSpace, quint32 numPixels, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const { if (*this == *dstColorSpace) { if (src != dst) { memcpy(dst, src, numPixels * sizeof(quint8) * pixelSize()); } } else { KoCachedColorConversionTransformation cct = KoColorSpaceRegistry::instance()->colorConversionCache()->cachedConverter(this, dstColorSpace, renderingIntent, conversionFlags); cct.transformation()->transform(src, dst, numPixels); } return true; } void KoColorSpace::bitBlt(const KoColorSpace* srcSpace, const KoCompositeOp::ParameterInfo& params, const KoCompositeOp* op, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const { 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()); if(params.rows <= 0 || params.cols <= 0) return; if(!(*this == *srcSpace)) { if (preferCompositionInSourceColorSpace() && srcSpace->hasCompositeOp(op->id())) { quint32 conversionDstBufferStride = params.cols * srcSpace->pixelSize(); QVector * conversionDstCache = threadLocalConversionCache(params.rows * conversionDstBufferStride); quint8* conversionDstData = conversionDstCache->data(); for(qint32 row=0; rowcompositeOp(op->id()); KoCompositeOp::ParameterInfo paramInfo(params); paramInfo.dstRowStart = conversionDstData; paramInfo.dstRowStride = conversionDstBufferStride; otherOp->composite(paramInfo); for(qint32 row=0; rowconvertPixelsTo(conversionDstData + row * conversionDstBufferStride, params.dstRowStart + row * params.dstRowStride, this, params.cols, renderingIntent, conversionFlags); } } else { quint32 conversionBufferStride = params.cols * pixelSize(); QVector * conversionCache = threadLocalConversionCache(params.rows * conversionBufferStride); quint8* conversionData = conversionCache->data(); for(qint32 row=0; rowconvertPixelsTo(params.srcRowStart + row * params.srcRowStride, conversionData + row * conversionBufferStride, this, params.cols, renderingIntent, conversionFlags); } KoCompositeOp::ParameterInfo paramInfo(params); paramInfo.srcRowStart = conversionData; paramInfo.srcRowStride = conversionBufferStride; op->composite(paramInfo); } } else { op->composite(params); } } QVector * KoColorSpace::threadLocalConversionCache(quint32 size) const { QVector * ba = 0; if (!d->conversionCache.hasLocalData()) { ba = new QVector(size, '0'); d->conversionCache.setLocalData(ba); } else { ba = d->conversionCache.localData(); if ((quint8)ba->size() < size) ba->resize(size); } return ba; } KoColorTransformation* KoColorSpace::createColorTransformation(const QString & id, const QHash & parameters) const { KoColorTransformationFactory* factory = KoColorTransformationFactoryRegistry::instance()->get(id); if (!factory) return 0; QPair model(colorModelId(), colorDepthId()); QList< QPair > models = factory->supportedModels(); if (models.isEmpty() || models.contains(model)) { return factory->createTransformation(this, parameters); } else { // Find the best solution // TODO use the color conversion cache KoColorConversionTransformation* csToFallBack = 0; KoColorConversionTransformation* fallBackToCs = 0; KoColorSpaceRegistry::instance()->colorConversionSystem()->createColorConverters(this, models, csToFallBack, fallBackToCs); Q_ASSERT(csToFallBack); Q_ASSERT(fallBackToCs); KoColorTransformation* transfo = factory->createTransformation(fallBackToCs->srcColorSpace(), parameters); return new KoFallBackColorTransformation(csToFallBack, fallBackToCs, transfo); } } void KoColorSpace::increaseLuminosity(quint8 * pixel, qreal step) const{ int channelnumber = channelCount(); - QVector channelValues(channelnumber); - QVector channelValuesF(channelnumber); - normalisedChannelsValue(pixel, channelValuesF); - for (int i=0;i channelValues(channelnumber); + normalisedChannelsValue(pixel, channelValues); if (profile()->hasTRC()){ //only linearise and crunch the luma if there's a TRC profile()->linearizeFloatValue(channelValues); qreal hue, sat, luma = 0.0; toHSY(channelValues, &hue, &sat, &luma); luma = pow(luma, 1/2.2); - luma = qMin(1.0, luma + step); + luma = qMin(1.0, luma + step); luma = pow(luma, 2.2); channelValues = fromHSY(&hue, &sat, &luma); - profile()->delinearizeFloatValue(channelValues); + profile()->delinearizeFloatValue(channelValues); } else { qreal hue, sat, luma = 0.0; toHSY(channelValues, &hue, &sat, &luma); - luma = qMin(1.0, luma + step); + luma = qMin(1.0, luma + step); channelValues = fromHSY(&hue, &sat, &luma); } - for (int i=0;i channelValues(channelnumber); - QVector channelValuesF(channelnumber); - normalisedChannelsValue(pixel, channelValuesF); - for (int i=0;i channelValues(channelnumber); + normalisedChannelsValue(pixel, channelValues); if (profile()->hasTRC()){ //only linearise and crunch the luma if there's a TRC profile()->linearizeFloatValue(channelValues); qreal hue, sat, luma = 0.0; toHSY(channelValues, &hue, &sat, &luma); luma = pow(luma, 1/2.2); if (luma-step<0.0) { luma=0.0; } else { luma -= step; } luma = pow(luma, 2.2); channelValues = fromHSY(&hue, &sat, &luma); profile()->delinearizeFloatValue(channelValues); } else { qreal hue, sat, luma = 0.0; toHSY(channelValues, &hue, &sat, &luma); if (luma-step<0.0) { luma=0.0; } else { luma -= step; } channelValues = fromHSY(&hue, &sat, &luma); } - for (int i=0;i channelValues(channelnumber); - QVector channelValuesF(channelnumber); - normalisedChannelsValue(pixel, channelValuesF); - for (int i=0;i channelValues(channelnumber); + normalisedChannelsValue(pixel, channelValues); profile()->linearizeFloatValue(channelValues); qreal hue, sat, luma = 0.0; toHSY(channelValues, &hue, &sat, &luma); sat += step; - sat = qBound(0.0, sat, 1.0); + sat = qBound(0.0, sat, 1.0); channelValues = fromHSY(&hue, &sat, &luma); profile()->delinearizeFloatValue(channelValues); - for (int i=0;i channelValues(channelnumber); - QVector channelValuesF(channelnumber); - normalisedChannelsValue(pixel, channelValuesF); - for (int i=0;i channelValues(channelnumber); + normalisedChannelsValue(pixel, channelValues); profile()->linearizeFloatValue(channelValues); qreal hue, sat, luma = 0.0; toHSY(channelValues, &hue, &sat, &luma); sat -= step; - sat = qBound(0.0, sat, 1.0); + sat = qBound(0.0, sat, 1.0); channelValues = fromHSY(&hue, &sat, &luma); profile()->delinearizeFloatValue(channelValues); - for (int i=0;i channelValues(channelnumber); - QVector channelValuesF(channelnumber); - normalisedChannelsValue(pixel, channelValuesF); - for (int i=0;i channelValues(channelnumber); + normalisedChannelsValue(pixel, channelValues); profile()->linearizeFloatValue(channelValues); qreal hue, sat, luma = 0.0; toHSY(channelValues, &hue, &sat, &luma); if (hue+step>1.0){ hue=(hue+step)- 1.0; } else { hue += step; } channelValues = fromHSY(&hue, &sat, &luma); profile()->delinearizeFloatValue(channelValues); - for (int i=0;i channelValues(channelnumber); - QVector channelValuesF(channelnumber); - normalisedChannelsValue(pixel, channelValuesF); - for (int i=0;i channelValues(channelnumber); + normalisedChannelsValue(pixel, channelValues); profile()->linearizeFloatValue(channelValues); qreal hue, sat, luma = 0.0; toHSY(channelValues, &hue, &sat, &luma); if (hue-step<0.0){ hue=1.0-(step-hue); } else { hue -= step; } channelValues = fromHSY(&hue, &sat, &luma); profile()->delinearizeFloatValue(channelValues); - for (int i=0;i channelValues(channelnumber); - QVector channelValuesF(channelnumber); - normalisedChannelsValue(pixel, channelValuesF); - for (int i=0;i channelValues(channelnumber); + normalisedChannelsValue(pixel, channelValues); profile()->linearizeFloatValue(channelValues); qreal y, u, v = 0.0; toYUV(channelValues, &y, &u, &v); u += step; - u = qBound(0.0, u, 1.0); + u = qBound(0.0, u, 1.0); channelValues = fromYUV(&y, &u, &v); profile()->delinearizeFloatValue(channelValues); - for (int i=0;i channelValues(channelnumber); - QVector channelValuesF(channelnumber); - normalisedChannelsValue(pixel, channelValuesF); - for (int i=0;i channelValues(channelnumber); + normalisedChannelsValue(pixel, channelValues); profile()->linearizeFloatValue(channelValues); qreal y, u, v = 0.0; toYUV(channelValues, &y, &u, &v); u -= step; - u = qBound(0.0, u, 1.0); + u = qBound(0.0, u, 1.0); channelValues = fromYUV(&y, &u, &v); profile()->delinearizeFloatValue(channelValues); - for (int i=0;i channelValues(channelnumber); - QVector channelValuesF(channelnumber); - normalisedChannelsValue(pixel, channelValuesF); - for (int i=0;i channelValues(channelnumber); + normalisedChannelsValue(pixel, channelValues); profile()->linearizeFloatValue(channelValues); qreal y, u, v = 0.0; toYUV(channelValues, &y, &u, &v); v += step; - v = qBound(0.0, v, 1.0); + v = qBound(0.0, v, 1.0); channelValues = fromYUV(&y, &u, &v); profile()->delinearizeFloatValue(channelValues); - for (int i=0;i channelValues(channelnumber); - QVector channelValuesF(channelnumber); - normalisedChannelsValue(pixel, channelValuesF); - for (int i=0;i channelValues(channelnumber); + normalisedChannelsValue(pixel, channelValues); profile()->linearizeFloatValue(channelValues); qreal y, u, v = 0.0; toYUV(channelValues, &y, &u, &v); v -= step; - v = qBound(0.0, v, 1.0); + v = qBound(0.0, v, 1.0); channelValues = fromYUV(&y, &u, &v); profile()->delinearizeFloatValue(channelValues); - for (int i=0;irgb8(dstProfile); if (data) this->convertPixelsTo(const_cast(data), img.bits(), dstCS, width * height, renderingIntent, conversionFlags); return img; } bool KoColorSpace::preferCompositionInSourceColorSpace() const { return false; } diff --git a/libs/pigment/KoColorSpace.h b/libs/pigment/KoColorSpace.h index fc53f87a332..724f05ff47d 100644 --- a/libs/pigment/KoColorSpace.h +++ b/libs/pigment/KoColorSpace.h @@ -1,614 +1,614 @@ /* * Copyright (c) 2005 Boudewijn Rempt * Copyright (c) 2006-2007 Cyrille Berger * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOCOLORSPACE_H #define KOCOLORSPACE_H #include #include #include #include #include #include "KoColorSpaceConstants.h" #include "KoColorConversionTransformation.h" #include "KoCompositeOp.h" #include #include "pigment_export.h" class QDomDocument; class QDomElement; class KoChannelInfo; class KoColorProfile; class KoColorTransformation; class QBitArray; enum Deletability { OwnedByRegistryDoNotDelete, OwnedByRegistryRegistryDeletes, NotOwnedByRegistry }; enum ColorSpaceIndependence { FULLY_INDEPENDENT, TO_LAB16, TO_RGBA8, TO_RGBA16 }; class KoMixColorsOp; class KoConvolutionOp; /** * A KoColorSpace is the definition of a certain color space. * * A color model and a color space are two related concepts. A color * model is more general in that it describes the channels involved and * how they in broad terms combine to describe a color. Examples are * RGB, HSV, CMYK. * * A color space is more specific in that it also describes exactly how * the channels are combined. So for each color model there can be a * number of specific color spaces. So RGB is the model and sRGB, * adobeRGB, etc are colorspaces. * * In Pigment KoColorSpace acts as both a color model and a color space. * You can think of the class definition as the color model, but the * instance of the class as representing a colorspace. * * A third concept is the profile represented by KoColorProfile. It * represents the info needed to specialize a color model into a color * space. * * KoColorSpace is an abstract class serving as an interface. * * Subclasses implement actual color spaces * Some subclasses implement only some parts and are named Traits * */ class PIGMENTCMS_EXPORT KoColorSpace { friend class KoColorSpaceRegistry; friend class KoColorSpaceFactory; protected: /// Only for use by classes that serve as baseclass for real color spaces KoColorSpace(); public: /// Should be called by real color spaces KoColorSpace(const QString &id, const QString &name, KoMixColorsOp* mixColorsOp, KoConvolutionOp* convolutionOp); virtual bool operator==(const KoColorSpace& rhs) const; protected: virtual ~KoColorSpace(); public: //========== Gamut and other basic info ===================================// /* * @returns QPolygonF with 5*channel samples converted to xyY. * maybe convert to 3d space in future? */ QPolygonF gamutXYY() const; /* * @returns a polygon with 5 samples per channel converted to xyY, but unlike * gamutxyY it focuses on the luminance. This then can be used to visualise * the approximate trc of a given colorspace. */ QPolygonF estimatedTRCXYY() const; QVector colorants() const; QVector lumaCoefficients() const; //========== Channels =====================================================// /// Return a list describing all the channels this color model has. The order /// of the channels in the list is the order of channels in the pixel. To find /// out the preferred display position, use KoChannelInfo::displayPosition. virtual QList channels() const; /** * The total number of channels for a single pixel in this color model */ virtual quint32 channelCount() const = 0; /** * The total number of color channels (excludes alpha) for a single * pixel in this color model. */ virtual quint32 colorChannelCount() const = 0; /** * returns a QBitArray that contains true for the specified * channel types: * * @param color if true, set all color channels to true * @param alpha if true, set all alpha channels to true * * The order of channels is the colorspace descriptive order, * not the pixel order. */ QBitArray channelFlags(bool color = true, bool alpha = false) const; /** * The size in bytes of a single pixel in this color model */ virtual quint32 pixelSize() const = 0; /** * Return a string with the channel's value suitable for display in the gui. */ virtual QString channelValueText(const quint8 *pixel, quint32 channelIndex) const = 0; /** * Return a string with the channel's value with integer * channels normalised to the floating point range 0 to 1, if * appropriate. */ virtual QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) const = 0; /** * Return a QVector of floats with channels' values normalized * to floating point range 0 to 1. */ - virtual void normalisedChannelsValue(const quint8 *pixel, QVector &channels) const = 0; + virtual void normalisedChannelsValue(const quint8 *pixel, QVector &channels) const = 0; /** * Write in the pixel the value from the normalized vector. */ - virtual void fromNormalisedChannelsValue(quint8 *pixel, const QVector &values) const = 0; + virtual void fromNormalisedChannelsValue(quint8 *pixel, const QVector &values) const = 0; /** * Convert the value of the channel at the specified position into * an 8-bit value. The position is not the number of bytes, but * the position of the channel as defined in the channel info list. */ virtual quint8 scaleToU8(const quint8 * srcPixel, qint32 channelPos) const = 0; /** * Set dstPixel to the pixel containing only the given channel of srcPixel. The remaining channels * should be set to whatever makes sense for 'empty' channels of this color space, * with the intent being that the pixel should look like it only has the given channel. */ virtual void singleChannelPixel(quint8 *dstPixel, const quint8 *srcPixel, quint32 channelIndex) const = 0; //========== Identification ===============================================// /** * ID for use in files and internally: unchanging name. As the id must be unique * it is usually the concatenation of the id of the color model and of the color * depth, for instance "RGBA8" or "CMYKA16" or "XYZA32f". */ virtual QString id() const; /** * User visible name which contains the name of the color model and of the color depth. * For intance "RGBA (8-bits)" or "CMYKA (16-bits)". */ virtual QString name() const; /** * @return a string that identify the color model (for instance "RGB" or "CMYK" ...) * @see KoColorModelStandardIds.h */ virtual KoID colorModelId() const = 0; /** * @return a string that identify the bit depth (for instance "U8" or "F16" ...) * @see KoColorModelStandardIds.h */ virtual KoID colorDepthId() const = 0; /** * @return true if the profile given in argument can be used by this color space */ virtual bool profileIsCompatible(const KoColorProfile* profile) const = 0; /** * If false, images in this colorspace will degrade considerably by * functions, tools and filters that have the given measure of colorspace * independence. * * @param independence the measure to which this colorspace will suffer * from the manipulations of the tool or filter asking * @return false if no degradation will take place, true if degradation will * take place */ virtual bool willDegrade(ColorSpaceIndependence independence) const = 0; //========== Capabilities =================================================// /** * Tests if the colorspace offers the specific composite op. */ virtual bool hasCompositeOp(const QString & id) const; /** * Returns the list of user-visible composite ops supported by this colorspace. */ virtual QList compositeOps() const; /** * Retrieve a single composite op from the ones this colorspace offers. * If the requested composite op does not exist, COMPOSITE_OVER is returned. */ virtual const KoCompositeOp * compositeOp(const QString & id) const; /** * add a composite op to this colorspace. */ virtual void addCompositeOp(const KoCompositeOp * op); /** * Returns true if the colorspace supports channel values outside the * (normalised) range 0 to 1. */ virtual bool hasHighDynamicRange() const = 0; //========== Display profiles =============================================// /** * Return the profile of this color space. */ virtual const KoColorProfile * profile() const = 0; //================= Conversion functions ==================================// /** * The fromQColor methods take a given color defined as an RGB QColor * and fills a byte array with the corresponding color in the * the colorspace managed by this strategy. * * @param color the QColor that will be used to fill dst * @param dst a pointer to a pixel * @param profile the optional profile that describes the color values of QColor */ virtual void fromQColor(const QColor& color, quint8 *dst, const KoColorProfile * profile = 0) const = 0; /** * The toQColor methods take a byte array that is at least pixelSize() long * and converts the contents to a QColor, using the given profile as a source * profile and the optional profile as a destination profile. * * @param src a pointer to the source pixel * @param c the QColor that will be filled with the color at src * @param profile the optional profile that describes the color in c, for instance the monitor profile */ virtual void toQColor(const quint8 *src, QColor *c, const KoColorProfile * profile = 0) const = 0; /** * Convert the pixels in data to (8-bit BGRA) QImage using the specified profiles. * * @param data A pointer to a contiguous memory region containing width * height pixels * @param width in pixels * @param height in pixels * @param dstProfile destination profile * @param renderingIntent the rendering intent */ virtual QImage convertToQImage(const quint8 *data, qint32 width, qint32 height, const KoColorProfile * dstProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const; /** * Convert the specified data to Lab (D50). All colorspaces are guaranteed to support this * * @param src the source data * @param dst the destination data * @param nPixels the number of source pixels */ virtual void toLabA16(const quint8 * src, quint8 * dst, quint32 nPixels) const; /** * Convert the specified data from Lab (D50). to this colorspace. All colorspaces are * guaranteed to support this. * * @param src the pixels in 16 bit lab format * @param dst the destination data * @param nPixels the number of pixels in the array */ virtual void fromLabA16(const quint8 * src, quint8 * dst, quint32 nPixels) const; /** * Convert the specified data to sRGB 16 bits. All colorspaces are guaranteed to support this * * @param src the source data * @param dst the destination data * @param nPixels the number of source pixels */ virtual void toRgbA16(const quint8 * src, quint8 * dst, quint32 nPixels) const; /** * Convert the specified data from sRGB 16 bits. to this colorspace. All colorspaces are * guaranteed to support this. * * @param src the pixels in 16 bit rgb format * @param dst the destination data * @param nPixels the number of pixels in the array */ virtual void fromRgbA16(const quint8 * src, quint8 * dst, quint32 nPixels) const; /** * Create a color conversion transformation. */ virtual KoColorConversionTransformation* createColorConverter(const KoColorSpace * dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const; /** * Convert a byte array of srcLen pixels *src to the specified color space * and put the converted bytes into the prepared byte array *dst. * * Returns false if the conversion failed, true if it succeeded * * This function is not thread-safe. If you want to apply multiple conversion * in different threads at the same time, you need to create one color converter * per-thread using createColorConverter. */ virtual bool convertPixelsTo(const quint8 * src, quint8 * dst, const KoColorSpace * dstColorSpace, quint32 numPixels, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const; //============================== Manipulation functions ==========================// // // The manipulation functions have default implementations that _convert_ the pixel // to a QColor and back. Reimplement these methods in your color strategy! // /** * Get the alpha value of the given pixel, downscaled to an 8-bit value. */ virtual quint8 opacityU8(const quint8 * pixel) const = 0; virtual qreal opacityF(const quint8 * pixel) const = 0; /** * Set the alpha channel of the given run of pixels to the given value. * * pixels -- a pointer to the pixels that will have their alpha set to this value * alpha -- a downscaled 8-bit value for opacity * nPixels -- the number of pixels * */ virtual void setOpacity(quint8 * pixels, quint8 alpha, qint32 nPixels) const = 0; virtual void setOpacity(quint8 * pixels, qreal alpha, qint32 nPixels) const = 0; /** * Multiply the alpha channel of the given run of pixels by the given value. * * pixels -- a pointer to the pixels that will have their alpha set to this value * alpha -- a downscaled 8-bit value for opacity * nPixels -- the number of pixels * */ virtual void multiplyAlpha(quint8 * pixels, quint8 alpha, qint32 nPixels) const = 0; /** * Applies the specified 8-bit alpha mask to the pixels. We assume that there are just * as many alpha values as pixels but we do not check this; the alpha values * are assumed to be 8-bits. */ virtual void applyAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) const = 0; /** * Applies the inverted 8-bit alpha mask to the pixels. We assume that there are just * as many alpha values as pixels but we do not check this; the alpha values * are assumed to be 8-bits. */ virtual void applyInverseAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) const = 0; /** * Applies the specified float alpha mask to the pixels. We assume that there are just * as many alpha values as pixels but we do not check this; alpha values have to be between 0.0 and 1.0 */ virtual void applyAlphaNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) const = 0; /** * Applies the inverted specified float alpha mask to the pixels. We assume that there are just * as many alpha values as pixels but we do not check this; alpha values have to be between 0.0 and 1.0 */ virtual void applyInverseNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) const = 0; /** * Create an adjustment object for adjusting the brightness and contrast * transferValues is a 256 bins array with values from 0 to 0xFFFF * This function is thread-safe, but you need to create one KoColorTransformation per thread. */ virtual KoColorTransformation *createBrightnessContrastAdjustment(const quint16 *transferValues) const = 0; /** * Create an adjustment object for adjusting individual channels * transferValues is an array of colorChannelCount number of 256 bins array with values from 0 to 0xFFFF * This function is thread-safe, but you need to create one KoColorTransformation per thread. * * The layout of the channels must be the following: * * 0..N-2 - color channels of the pixel; * N-1 - alpha channel of the pixel (if exists) */ virtual KoColorTransformation *createPerChannelAdjustment(const quint16 * const* transferValues) const = 0; /** * Darken all color channels with the given amount. If compensate is true, * the compensation factor will be used to limit the darkening. * */ virtual KoColorTransformation *createDarkenAdjustment(qint32 shade, bool compensate, qreal compensation) const = 0; /** * Invert color channels of the given pixels * This function is thread-safe, but you need to create one KoColorTransformation per thread. */ virtual KoColorTransformation *createInvertTransformation() const = 0; /** * Get the difference between 2 colors, normalized in the range (0,255). Only completely * opaque and completely transparent are taken into account when computing the different; * other transparency levels are not regarded when finding the difference. */ virtual quint8 difference(const quint8* src1, const quint8* src2) const = 0; /** * Get the difference between 2 colors, normalized in the range (0,255). This function * takes the Alpha channel of the pixel into account. Alpha channel has the same * weight as Lightness channel. */ virtual quint8 differenceA(const quint8* src1, const quint8* src2) const = 0; /** * @return the mix color operation of this colorspace (do not delete it locally, it's deleted by the colorspace). */ virtual KoMixColorsOp* mixColorsOp() const; /** * @return the convolution operation of this colorspace (do not delete it locally, it's deleted by the colorspace). */ virtual KoConvolutionOp* convolutionOp() const; /** * Calculate the intensity of the given pixel, scaled down to the range 0-255. XXX: Maybe this should be more flexible */ virtual quint8 intensity8(const quint8 * src) const = 0; /* *increase luminosity by step */ virtual void increaseLuminosity(quint8 * pixel, qreal step) const; virtual void decreaseLuminosity(quint8 * pixel, qreal step) const; virtual void increaseSaturation(quint8 * pixel, qreal step) const; virtual void decreaseSaturation(quint8 * pixel, qreal step) const; virtual void increaseHue(quint8 * pixel, qreal step) const; virtual void decreaseHue(quint8 * pixel, qreal step) const; virtual void increaseRed(quint8 * pixel, qreal step) const; virtual void increaseGreen(quint8 * pixel, qreal step) const; virtual void increaseBlue(quint8 * pixel, qreal step) const; virtual void increaseYellow(quint8 * pixel, qreal step) const; - virtual void toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const = 0; - virtual QVector fromHSY(qreal *hue, qreal *sat, qreal *luma) const = 0; - virtual void toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const = 0; - virtual QVector fromYUV(qreal *y, qreal *u, qreal *v) const = 0; + virtual void toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const = 0; + virtual QVector fromHSY(qreal *hue, qreal *sat, qreal *luma) const = 0; + virtual void toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const = 0; + virtual QVector fromYUV(qreal *y, qreal *u, qreal *v) const = 0; /** * Compose two arrays of pixels together. If source and target * are not the same color model, the source pixels will be * converted to the target model. We're "dst" -- "dst" pixels are always in _this_ * colorspace. * * @param srcSpace the colorspace of the source pixels that will be composited onto "us" * @param param the information needed for blitting e.g. the source and destination pixel data, * the opacity and flow, ... * @param op the composition operator to use, e.g. COPY_OVER * */ virtual void bitBlt(const KoColorSpace* srcSpace, const KoCompositeOp::ParameterInfo& params, const KoCompositeOp* op, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const; /** * Serialize this color following Create's swatch color specification available * at http://create.freedesktop.org/wiki/index.php/Swatches_-_colour_file_format * * This function doesn't create the element but rather the , * , ... elements. It is assumed that colorElt is the * element. * * @param pixel buffer to serialized * @param colorElt root element for the serialization, it is assumed that this * element is * @param doc is the document containing colorElt */ virtual void colorToXML(const quint8* pixel, QDomDocument& doc, QDomElement& colorElt) const = 0; /** * Unserialize a color following Create's swatch color specification available * at http://create.freedesktop.org/wiki/index.php/Swatches_-_colour_file_format * * @param pixel buffer where the color will be unserialized * @param elt the element to unserialize (, , ) * @return the unserialize color, or an empty color object if the function failed * to unserialize the color */ virtual void colorFromXML(quint8* pixel, const QDomElement& elt) const = 0; KoColorTransformation* createColorTransformation(const QString & id, const QHash & parameters) const; protected: /** * Use this function in the constructor of your colorspace to add the information about a channel. * @param ci a pointer to the information about a channel */ virtual void addChannel(KoChannelInfo * ci); const KoColorConversionTransformation* toLabA16Converter() const; const KoColorConversionTransformation* fromLabA16Converter() const; const KoColorConversionTransformation* toRgbA16Converter() const; const KoColorConversionTransformation* fromRgbA16Converter() const; /** * Returns the thread-local conversion cache. If it doesn't exist * yet, it is created. If it is currently too small, it is resized. */ QVector * threadLocalConversionCache(quint32 size) const; /** * This function defines the behavior of the bitBlt function * when the composition of pixels in different colorspaces is * requested, that is in case: * * srcCS == any * dstCS == this * * 1) preferCompositionInSourceColorSpace() == false, * * the source pixels are first converted to *this color space * and then composition is performed. * * 2) preferCompositionInSourceColorSpace() == true, * * the destination pixels are first converted into *srcCS color * space, then the composition is done, and the result is finally * converted into *this colorspace. * * This is used by alpha8() color space mostly, because it has * weaker representation of the color, so the composition * should be done in CS with richer functionality. */ virtual bool preferCompositionInSourceColorSpace() const; struct Private; Private * const d; }; inline QDebug operator<<(QDebug dbg, const KoColorSpace *cs) { dbg.nospace() << cs->name() << " (" << cs->colorModelId().id() << "," << cs->colorDepthId().id() << " )"; return dbg.space(); } #endif // KOCOLORSPACE_H diff --git a/libs/pigment/KoColorSpaceAbstract.h b/libs/pigment/KoColorSpaceAbstract.h index ee920abfbe9..c9a4003fe4c 100644 --- a/libs/pigment/KoColorSpaceAbstract.h +++ b/libs/pigment/KoColorSpaceAbstract.h @@ -1,209 +1,209 @@ /* * Copyright (c) 2006 Cyrille Berger * Copyright (c) 2007 Emanuele Tamponi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOCOLORSPACEABSTRACT_H #define KOCOLORSPACEABSTRACT_H #include #include #include #include #include #include #include "KoFallBackColorTransformation.h" #include "KoLabDarkenColorTransformation.h" #include "KoMixColorsOpImpl.h" #include "KoConvolutionOpImpl.h" #include "KoInvertColorTransformation.h" /** * This in an implementation of KoColorSpace which can be used as a base for colorspaces with as many * different channels of the same type. * * The template parameters must be a class which inherits KoColorSpaceTrait (or a class with the same signature). * * SOMETYPE is the type of the channel for instance (quint8, quint32...), * SOMENBOFCHANNELS is the number of channels including the alpha channel * SOMEALPHAPOS is the position of the alpha channel in the pixel (can be equal to -1 if no alpha channel). */ template class KoColorSpaceAbstract : public KoColorSpace { public: KoColorSpaceAbstract(const QString &id, const QString &name) : KoColorSpace(id, name, new KoMixColorsOpImpl< _CSTrait>(), new KoConvolutionOpImpl< _CSTrait>()) { } virtual quint32 colorChannelCount() const { if (_CSTrait::alpha_pos == -1) return _CSTrait::channels_nb; else return _CSTrait::channels_nb - 1; } virtual quint32 channelCount() const { return _CSTrait::channels_nb; } virtual quint32 pixelSize() const { return _CSTrait::pixelSize; } virtual QString channelValueText(const quint8 *pixel, quint32 channelIndex) const { return _CSTrait::channelValueText(pixel, channelIndex); } virtual QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) const { return _CSTrait::normalisedChannelValueText(pixel, channelIndex); } - virtual void normalisedChannelsValue(const quint8 *pixel, QVector &channels) const { + virtual void normalisedChannelsValue(const quint8 *pixel, QVector &channels) const { return _CSTrait::normalisedChannelsValue(pixel, channels); } - virtual void fromNormalisedChannelsValue(quint8 *pixel, const QVector &values) const { + virtual void fromNormalisedChannelsValue(quint8 *pixel, const QVector &values) const { return _CSTrait::fromNormalisedChannelsValue(pixel, values); } virtual quint8 scaleToU8(const quint8 * srcPixel, qint32 channelIndex) const { typename _CSTrait::channels_type c = _CSTrait::nativeArray(srcPixel)[channelIndex]; return KoColorSpaceMaths::scaleToA(c); } virtual void singleChannelPixel(quint8 *dstPixel, const quint8 *srcPixel, quint32 channelIndex) const { _CSTrait::singleChannelPixel(dstPixel, srcPixel, channelIndex); } virtual quint8 opacityU8(const quint8 * U8_pixel) const { return _CSTrait::opacityU8(U8_pixel); } virtual qreal opacityF(const quint8 * U8_pixel) const { return _CSTrait::opacityF(U8_pixel); } virtual void setOpacity(quint8 * pixels, quint8 alpha, qint32 nPixels) const { _CSTrait::setOpacity(pixels, alpha, nPixels); } virtual void setOpacity(quint8 * pixels, qreal alpha, qint32 nPixels) const { _CSTrait::setOpacity(pixels, alpha, nPixels); } virtual void multiplyAlpha(quint8 * pixels, quint8 alpha, qint32 nPixels) const { _CSTrait::multiplyAlpha(pixels, alpha, nPixels); } virtual void applyAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) const { _CSTrait::applyAlphaU8Mask(pixels, alpha, nPixels); } virtual void applyInverseAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) const { _CSTrait::applyInverseAlphaU8Mask(pixels, alpha, nPixels); } virtual void applyAlphaNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) const { _CSTrait::applyAlphaNormedFloatMask(pixels, alpha, nPixels); } virtual void applyInverseNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) const { _CSTrait::applyInverseAlphaNormedFloatMask(pixels, alpha, nPixels); } virtual quint8 intensity8(const quint8 * src) const { QColor c; const_cast *>(this)->toQColor(src, &c); return static_cast((c.red() * 0.30 + c.green() * 0.59 + c.blue() * 0.11) + 0.5); } virtual KoColorTransformation* createInvertTransformation() const { return new KoInvertColorTransformation(this); } virtual KoColorTransformation *createDarkenAdjustment(qint32 shade, bool compensate, qreal compensation) const { return new KoFallBackColorTransformation(this, KoColorSpaceRegistry::instance()->lab16(""), new KoLabDarkenColorTransformation(shade, compensate, compensation, KoColorSpaceRegistry::instance()->lab16(""))); } virtual bool convertPixelsTo(const quint8 *src, quint8 *dst, const KoColorSpace *dstColorSpace, quint32 numPixels, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const { // check whether we have the same profile and color model, but only a different bit // depth; in that case we don't convert as such, but scale bool scaleOnly = false; // Note: getting the id() is really, really expensive, so only do that if // we are sure there is a difference between the colorspaces if (!(*this == *dstColorSpace)) { scaleOnly = dstColorSpace->colorModelId().id() == colorModelId().id() && dstColorSpace->colorDepthId().id() != colorDepthId().id() && dstColorSpace->profile()->name() == profile()->name(); } if (scaleOnly && dynamic_cast(dstColorSpace)) { typedef typename _CSTrait::channels_type channels_type; switch(dstColorSpace->channels().at(0)->channelValueType()) { case KoChannelInfo::UINT8: scalePixels<_CSTrait::pixelSize, 1, channels_type, quint8>(src, dst, numPixels); return true; // case KoChannelInfo::INT8: // scalePixels<_CSTrait::pixelSize, 1, channels_type, qint8>(src, dst, numPixels); // return true; case KoChannelInfo::UINT16: scalePixels<_CSTrait::pixelSize, 2, channels_type, quint16>(src, dst, numPixels); return true; case KoChannelInfo::INT16: scalePixels<_CSTrait::pixelSize, 2, channels_type, qint16>(src, dst, numPixels); return true; case KoChannelInfo::UINT32: scalePixels<_CSTrait::pixelSize, 4, channels_type, quint32>(src, dst, numPixels); return true; default: break; } } return KoColorSpace::convertPixelsTo(src, dst, dstColorSpace, numPixels, renderingIntent, conversionFlags); } private: template void scalePixels(const quint8* src, quint8* dst, quint32 numPixels) const { qint32 dstPixelSize = dstChannelSize * _CSTrait::channels_nb; for(quint32 i=0; i(src + i * srcPixelSize); TDstChannel* dstPixel = reinterpret_cast(dst + i * dstPixelSize); for(quint32 c=0; c<_CSTrait::channels_nb; ++c) dstPixel[c] = Arithmetic::scale(srcPixel[c]); } } }; #endif // KOCOLORSPACEABSTRACT_H diff --git a/libs/pigment/KoColorSpaceTraits.h b/libs/pigment/KoColorSpaceTraits.h index 1122353ab11..db1353ec583 100644 --- a/libs/pigment/KoColorSpaceTraits.h +++ b/libs/pigment/KoColorSpaceTraits.h @@ -1,225 +1,225 @@ /* * Copyright (c) 2006-2007 Cyrille Berger * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KO_COLORSPACE_TRAITS_H_ #define _KO_COLORSPACE_TRAITS_H_ #include #include "KoColorSpaceConstants.h" #include "KoColorSpaceMaths.h" #include "DebugPigment.h" /** * This class is the base class to define the main characteristics of a colorspace * which inherits KoColorSpaceAbstract. * * - _channels_type_ is the type of the value use for each channel, for example quint8 for 8bits per channel * color spaces, or quint16 for 16bits integer per channel, float for 32bits per channel * floating point color spaces * - _channels_nb_ is the total number of channels in an image (for example RGB is 3 but RGBA is four) * - _alpha_pos_ is the position of the alpha channel among the channels, if there is no alpha channel, * then _alpha_pos_ is set to -1 * * For instance a colorspace of three color channels and alpha channel in 16bits, * will be defined as KoColorSpaceTrait\. The same without the alpha * channel is KoColorSpaceTrait\ * */ template struct KoColorSpaceTrait { /// the type of the value of the channels of this color space typedef _channels_type_ channels_type; /// the number of channels in this color space static const quint32 channels_nb = _channels_nb_; /// the position of the alpha channel in the channels of the pixel (or -1 if no alpha /// channel. static const qint32 alpha_pos = _alpha_pos_; /// the number of bit for each channel static const int depth = KoColorSpaceMathsTraits<_channels_type_>::bits; /** * @return the size in byte of one pixel */ static const quint32 pixelSize = channels_nb * sizeof(channels_type); /** * @return the value of the alpha channel for this pixel in the 0..255 range */ inline static quint8 opacityU8(const quint8 * U8_pixel) { if (alpha_pos < 0) return OPACITY_OPAQUE_U8; channels_type c = nativeArray(U8_pixel)[alpha_pos]; return KoColorSpaceMaths::scaleToA(c); } inline static qreal opacityF(const quint8 * U8_pixel) { if (alpha_pos < 0) return OPACITY_OPAQUE_F; channels_type c = nativeArray(U8_pixel)[alpha_pos]; return KoColorSpaceMaths::scaleToA(c); } /** * Set the alpha channel for this pixel from a value in the 0..255 range */ inline static void setOpacity(quint8 * pixels, quint8 alpha, qint32 nPixels) { if (alpha_pos < 0) return; qint32 psize = pixelSize; channels_type valpha = KoColorSpaceMaths::scaleToA(alpha); for (; nPixels > 0; --nPixels, pixels += psize) { nativeArray(pixels)[alpha_pos] = valpha; } } inline static void setOpacity(quint8 * pixels, qreal alpha, qint32 nPixels) { if (alpha_pos < 0) return; qint32 psize = pixelSize; channels_type valpha = KoColorSpaceMaths::scaleToA(alpha); for (; nPixels > 0; --nPixels, pixels += psize) { nativeArray(pixels)[alpha_pos] = valpha; } } /** * Convenient function for transforming a quint8* array in a pointer of the native channels type */ inline static const channels_type* nativeArray(const quint8 * a) { return reinterpret_cast(a); } /** * Convenient function for transforming a quint8* array in a pointer of the native channels type */ inline static channels_type* nativeArray(quint8 * a) { return reinterpret_cast< channels_type*>(a); } /** * Allocate nPixels pixels for this colorspace. */ inline static quint8* allocate(quint32 nPixels) { return new quint8[ nPixels * pixelSize ]; } inline static void singleChannelPixel(quint8 *dstPixel, const quint8 *srcPixel, quint32 channelIndex) { const channels_type* src = nativeArray(srcPixel); channels_type* dst = nativeArray(dstPixel); for (uint i = 0; i < channels_nb; i++) { if (i != channelIndex) { dst[i] = 0; } else { dst[i] = src[i]; } } } inline static QString channelValueText(const quint8 *pixel, quint32 channelIndex) { if (channelIndex > channels_nb) return QString("Error"); channels_type c = nativeArray(pixel)[channelIndex]; return QString().setNum(c); } inline static QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) { if (channelIndex > channels_nb) return QString("Error"); channels_type c = nativeArray(pixel)[channelIndex]; return QString().setNum(100. *((qreal)c) / KoColorSpaceMathsTraits< channels_type>::unitValue); } - inline static void normalisedChannelsValue(const quint8 *pixel, QVector &channels) { + inline static void normalisedChannelsValue(const quint8 *pixel, QVector &channels) { Q_ASSERT((int)channels.count() == (int)channels_nb); channels_type c; for (uint i = 0; i < channels_nb; i++) { c = nativeArray(pixel)[i]; channels[i] = ((qreal)c) / KoColorSpaceMathsTraits::unitValue; } } - inline static void fromNormalisedChannelsValue(quint8 *pixel, const QVector &values) { + inline static void fromNormalisedChannelsValue(quint8 *pixel, const QVector &values) { Q_ASSERT((int)values.count() == (int)channels_nb); channels_type c; for (uint i = 0; i < channels_nb; i++) { c = (channels_type) ((float)KoColorSpaceMathsTraits::unitValue * values[i]); nativeArray(pixel)[i] = c; } } inline static void multiplyAlpha(quint8 * pixels, quint8 alpha, qint32 nPixels) { if (alpha_pos < 0) return; channels_type valpha = KoColorSpaceMaths::scaleToA(alpha); for (; nPixels > 0; --nPixels, pixels += pixelSize) { channels_type* alphapixel = nativeArray(pixels) + alpha_pos; *alphapixel = KoColorSpaceMaths::multiply(*alphapixel, valpha); } } inline static void applyAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) { if (alpha_pos < 0) return; for (; nPixels > 0; --nPixels, pixels += pixelSize, ++alpha) { channels_type valpha = KoColorSpaceMaths::scaleToA(*alpha); channels_type* alphapixel = nativeArray(pixels) + alpha_pos; *alphapixel = KoColorSpaceMaths::multiply(*alphapixel, valpha); } } inline static void applyInverseAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) { if (alpha_pos < 0) return; for (; nPixels > 0; --nPixels, pixels += pixelSize, ++alpha) { channels_type valpha = KoColorSpaceMaths::scaleToA(OPACITY_OPAQUE_U8 - *alpha); channels_type* alphapixel = nativeArray(pixels) + alpha_pos; *alphapixel = KoColorSpaceMaths::multiply(*alphapixel, valpha); } } inline static void applyAlphaNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) { if (alpha_pos < 0) return; for (; nPixels > 0; --nPixels, pixels += pixelSize, ++alpha) { channels_type valpha = channels_type(KoColorSpaceMathsTraits::unitValue * (*alpha)); channels_type* alphapixel = nativeArray(pixels) + alpha_pos; *alphapixel = KoColorSpaceMaths::multiply(*alphapixel, valpha); } } inline static void applyInverseAlphaNormedFloatMask(quint8 * pixels, const float * alpha, qint32 nPixels) { if (alpha_pos < 0) return; for (; nPixels > 0; --nPixels, pixels += pixelSize, ++alpha) { channels_type valpha = channels_type(KoColorSpaceMathsTraits::unitValue * (1.0f - *alpha)); channels_type* alphapixel = nativeArray(pixels) + alpha_pos; *alphapixel = KoColorSpaceMaths::multiply(*alphapixel, valpha); } } }; #include "KoRgbColorSpaceTraits.h" #include "KoBgrColorSpaceTraits.h" #include "KoGrayColorSpaceTraits.h" #include "KoLabColorSpaceTraits.h" #include "KoXyzColorSpaceTraits.h" #include "KoYcbcrColorSpaceTraits.h" #include "KoCmykColorSpaceTraits.h" #endif diff --git a/libs/pigment/colorprofiles/KoDummyColorProfile.cpp b/libs/pigment/colorprofiles/KoDummyColorProfile.cpp index 3db133f14c2..06778403e31 100644 --- a/libs/pigment/colorprofiles/KoDummyColorProfile.cpp +++ b/libs/pigment/colorprofiles/KoDummyColorProfile.cpp @@ -1,136 +1,136 @@ /* * Copyright (c) 2010 Cyrille Berger * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoDummyColorProfile.h" KoDummyColorProfile::KoDummyColorProfile() { setName("default"); } KoDummyColorProfile::~KoDummyColorProfile() { } KoColorProfile* KoDummyColorProfile::clone() const { return new KoDummyColorProfile(); } bool KoDummyColorProfile::valid() const { return true; } float KoDummyColorProfile::version() const { return 0.0; } bool KoDummyColorProfile::isSuitableForOutput() const { return true; } bool KoDummyColorProfile::isSuitableForPrinting() const { return true; } bool KoDummyColorProfile::isSuitableForDisplay() const { return true; } bool KoDummyColorProfile::supportsPerceptual() const { return true; } bool KoDummyColorProfile::supportsSaturation() const { return true; } bool KoDummyColorProfile::supportsAbsolute() const { return true; } bool KoDummyColorProfile::supportsRelative() const { return true; } bool KoDummyColorProfile::hasColorants() const { return true; } bool KoDummyColorProfile::hasTRC() const { return true; } -QVector KoDummyColorProfile::getColorantsXYZ() const +QVector KoDummyColorProfile::getColorantsXYZ() const { - QVector d50Dummy(3); + QVector d50Dummy(3); d50Dummy<<0.34773<<0.35952<<1.0; return d50Dummy; } -QVector KoDummyColorProfile::getColorantsxyY() const +QVector KoDummyColorProfile::getColorantsxyY() const { - QVector d50Dummy(3); + QVector d50Dummy(3); d50Dummy<<0.34773<<0.35952<<1.0; return d50Dummy; } -QVector KoDummyColorProfile::getWhitePointXYZ() const +QVector KoDummyColorProfile::getWhitePointXYZ() const { - QVector d50Dummy(3); + QVector d50Dummy(3); d50Dummy<<0.9642<<1.0000<<0.8249; return d50Dummy; } -QVector KoDummyColorProfile::getWhitePointxyY() const +QVector KoDummyColorProfile::getWhitePointxyY() const { - QVector d50Dummy(3); + QVector d50Dummy(3); d50Dummy<<0.34773<<0.35952<<1.0; return d50Dummy; } -QVector KoDummyColorProfile::getEstimatedTRC() const +QVector KoDummyColorProfile::getEstimatedTRC() const { - QVector Dummy(3); + QVector Dummy(3); Dummy.fill(2.2); return Dummy; } -void KoDummyColorProfile::linearizeFloatValue(QVector & ) const +void KoDummyColorProfile::linearizeFloatValue(QVector & ) const { } -void KoDummyColorProfile::delinearizeFloatValue(QVector & ) const +void KoDummyColorProfile::delinearizeFloatValue(QVector & ) const { } -void KoDummyColorProfile::linearizeFloatValueFast(QVector & ) const +void KoDummyColorProfile::linearizeFloatValueFast(QVector & ) const { } -void KoDummyColorProfile::delinearizeFloatValueFast(QVector & ) const +void KoDummyColorProfile::delinearizeFloatValueFast(QVector & ) const { } bool KoDummyColorProfile::operator==(const KoColorProfile& rhs) const { return dynamic_cast(&rhs); } diff --git a/libs/pigment/colorprofiles/KoDummyColorProfile.h b/libs/pigment/colorprofiles/KoDummyColorProfile.h index c8a3f71f481..cbd8cdff6b2 100644 --- a/libs/pigment/colorprofiles/KoDummyColorProfile.h +++ b/libs/pigment/colorprofiles/KoDummyColorProfile.h @@ -1,54 +1,54 @@ /* * Copyright (c) 2010 Cyrille Berger * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KO_DUMMY_COLOR_PROFILE_H_ #define _KO_DUMMY_COLOR_PROFILE_H_ #include "KoColorProfile.h" class KoDummyColorProfile : public KoColorProfile { public: KoDummyColorProfile(); virtual ~KoDummyColorProfile(); virtual KoColorProfile* clone() const; virtual bool valid() const; virtual float version() const; virtual bool isSuitableForOutput() const; virtual bool isSuitableForPrinting() const; virtual bool isSuitableForDisplay() const; virtual bool supportsPerceptual() const; virtual bool supportsSaturation() const; virtual bool supportsAbsolute() const; virtual bool supportsRelative() const; virtual bool hasColorants() const; virtual bool hasTRC() const; - virtual QVector getColorantsXYZ() const; - virtual QVector getColorantsxyY() const; - virtual QVector getWhitePointXYZ() const; - virtual QVector getWhitePointxyY() const; - virtual QVector getEstimatedTRC() const; - virtual void linearizeFloatValue(QVector & Value) const; - virtual void delinearizeFloatValue(QVector & Value) const; - virtual void linearizeFloatValueFast(QVector & Value) const; - virtual void delinearizeFloatValueFast(QVector & Value) const; + virtual QVector getColorantsXYZ() const; + virtual QVector getColorantsxyY() const; + virtual QVector getWhitePointXYZ() const; + virtual QVector getWhitePointxyY() const; + virtual QVector getEstimatedTRC() const; + virtual void linearizeFloatValue(QVector & Value) const; + virtual void delinearizeFloatValue(QVector & Value) const; + virtual void linearizeFloatValueFast(QVector & Value) const; + virtual void delinearizeFloatValueFast(QVector & Value) const; virtual bool operator==(const KoColorProfile&) const; }; #endif diff --git a/libs/pigment/colorspaces/KoAlphaColorSpace.h b/libs/pigment/colorspaces/KoAlphaColorSpace.h index 17f4b092f05..562e74750ea 100644 --- a/libs/pigment/colorspaces/KoAlphaColorSpace.h +++ b/libs/pigment/colorspaces/KoAlphaColorSpace.h @@ -1,208 +1,208 @@ /* * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2006 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KOALPHACOLORSPACE_H #define KOALPHACOLORSPACE_H #include #include "DebugPigment.h" #include "pigment_export.h" #include "KoColorSpaceAbstract.h" #include "KoColorSpaceTraits.h" #include "KoColorModelStandardIds.h" #include "KoSimpleColorSpaceFactory.h" typedef KoColorSpaceTrait AlphaU8Traits; class QBitArray; /** * The alpha mask is a special color strategy that treats all pixels as * alpha value with a color common to the mask. The default color is white. */ class PIGMENTCMS_EXPORT KoAlphaColorSpace : public KoColorSpaceAbstract { public: KoAlphaColorSpace(); virtual ~KoAlphaColorSpace(); static QString colorSpaceId() { return "ALPHA"; } virtual KoID colorModelId() const { return AlphaColorModelID; } virtual KoID colorDepthId() const { return Integer8BitsColorDepthID; } virtual KoColorSpace* clone() const; virtual bool willDegrade(ColorSpaceIndependence independence) const { Q_UNUSED(independence); return false; } virtual bool profileIsCompatible(const KoColorProfile* /*profile*/) const { return false; } virtual void fromQColor(const QColor& color, quint8 *dst, const KoColorProfile * profile = 0) const; virtual void toQColor(const quint8 *src, QColor *c, const KoColorProfile * profile = 0) const; virtual quint8 difference(const quint8 *src1, const quint8 *src2) const; virtual quint8 differenceA(const quint8 *src1, const quint8 *src2) const; virtual quint32 colorChannelCount() const { return 0; } virtual QString channelValueText(const quint8 *pixel, quint32 channelIndex) const; virtual QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) const; virtual void convolveColors(quint8** colors, qreal* kernelValues, quint8 *dst, qreal factor, qreal offset, qint32 nColors, const QBitArray & channelFlags) const; virtual quint32 colorSpaceType() const { return 0; } virtual bool hasHighDynamicRange() const { return false; } virtual const KoColorProfile* profile() const { return m_profile; } virtual QImage convertToQImage(const quint8 *data, qint32 width, qint32 height, const KoColorProfile * dstProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const; virtual void toLabA16(const quint8* src, quint8* dst, quint32 nPixels) const { quint16* lab = reinterpret_cast(dst); while (nPixels--) { lab[3] = src[0]; src++; lab += 4; } } virtual void fromLabA16(const quint8* src, quint8* dst, quint32 nPixels) const { const quint16* lab = reinterpret_cast(src); while (nPixels--) { dst[0] = lab[3]; dst++; lab += 4; } } virtual void toRgbA16(const quint8* src, quint8* dst, quint32 nPixels) const { quint16* rgb = reinterpret_cast(dst); while (nPixels--) { rgb[3] = src[0]; src++; rgb += 4; } } virtual void fromRgbA16(const quint8* src, quint8* dst, quint32 nPixels) const { const quint16* rgb = reinterpret_cast(src); while (nPixels--) { dst[0] = rgb[3]; dst++; rgb += 4; } } virtual KoColorTransformation* createBrightnessContrastAdjustment(const quint16* transferValues) const { Q_UNUSED(transferValues); warnPigment << i18n("Undefined operation in the alpha color space"); return 0; } virtual KoColorTransformation* createPerChannelAdjustment(const quint16* const*) const { warnPigment << i18n("Undefined operation in the alpha color space"); return 0; } virtual KoColorTransformation *createDarkenAdjustment(qint32 , bool , qreal) const { warnPigment << i18n("Undefined operation in the alpha color space"); return 0; } virtual void invertColor(quint8*, qint32) const { warnPigment << i18n("Undefined operation in the alpha color space"); } virtual void colorToXML(const quint8* , QDomDocument& , QDomElement&) const { warnPigment << i18n("Undefined operation in the alpha color space"); } virtual void colorFromXML(quint8* , const QDomElement&) const { warnPigment << i18n("Undefined operation in the alpha color space"); } - virtual void toHSY(const QVector &, qreal *, qreal *, qreal *) const { + virtual void toHSY(const QVector &, qreal *, qreal *, qreal *) const { warnPigment << i18n("Undefined operation in the alpha color space"); } - virtual QVector fromHSY(qreal *, qreal *, qreal *) const { + virtual QVector fromHSY(qreal *, qreal *, qreal *) const { warnPigment << i18n("Undefined operation in the alpha color space"); - QVector channelValues (1); + QVector channelValues (1); channelValues.fill(0.0); return channelValues; } - virtual void toYUV(const QVector &, qreal *, qreal *, qreal *) const { + virtual void toYUV(const QVector &, qreal *, qreal *, qreal *) const { warnPigment << i18n("Undefined operation in the alpha color space"); } - virtual QVector fromYUV(qreal *, qreal *, qreal *) const { + virtual QVector fromYUV(qreal *, qreal *, qreal *) const { warnPigment << i18n("Undefined operation in the alpha color space"); - QVector channelValues (1); + QVector channelValues (1); channelValues.fill(0.0); return channelValues; } protected: virtual bool preferCompositionInSourceColorSpace() const; private: KoColorProfile* m_profile; QList m_compositeOps; }; class KoAlphaColorSpaceFactory : public KoSimpleColorSpaceFactory { public: KoAlphaColorSpaceFactory() : KoSimpleColorSpaceFactory("ALPHA", i18n("Alpha mask"), false, AlphaColorModelID, Integer8BitsColorDepthID, 8) { } virtual KoColorSpace *createColorSpace(const KoColorProfile *) const { return new KoAlphaColorSpace(); } }; #endif // KO_COLORSPACE_ALPHA_H_ diff --git a/libs/pigment/colorspaces/KoLabColorSpace.cpp b/libs/pigment/colorspaces/KoLabColorSpace.cpp index 03a37feb272..46882f119c0 100644 --- a/libs/pigment/colorspaces/KoLabColorSpace.cpp +++ b/libs/pigment/colorspaces/KoLabColorSpace.cpp @@ -1,196 +1,196 @@ /* * Copyright (c) 2004-2009 Boudewijn Rempt * Copyright (c) 2006 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KoLabColorSpace.h" #include #include #include #include #include #include #include "KoChannelInfo.h" #include "KoID.h" #include "KoIntegerMaths.h" #include "KoColorConversions.h" #include "../compositeops/KoCompositeOps.h" KoLabColorSpace::KoLabColorSpace() : KoSimpleColorSpace(colorSpaceId(), i18n("L*a*b* (16-bit integer/channel, unmanaged)"), LABAColorModelID, Integer16BitsColorDepthID) { addChannel(new KoChannelInfo(i18n("Lightness"), CHANNEL_L * sizeof(quint16), CHANNEL_L, KoChannelInfo::COLOR, KoChannelInfo::UINT16, sizeof(quint16), QColor(100, 100, 100))); addChannel(new KoChannelInfo(i18n("a*"), CHANNEL_A * sizeof(quint16), CHANNEL_A, KoChannelInfo::COLOR, KoChannelInfo::UINT16, sizeof(quint16), QColor(150, 150, 150))); addChannel(new KoChannelInfo(i18n("b*"), CHANNEL_B * sizeof(quint16), CHANNEL_B, KoChannelInfo::COLOR, KoChannelInfo::UINT16, sizeof(quint16), QColor(200, 200, 200))); addChannel(new KoChannelInfo(i18n("Alpha"), CHANNEL_ALPHA * sizeof(quint16), CHANNEL_ALPHA, KoChannelInfo::ALPHA, KoChannelInfo::UINT16, sizeof(quint16))); // ADD, ALPHA_DARKEN, BURN, DIVIDE, DODGE, ERASE, MULTIPLY, OVER, OVERLAY, SCREEN, SUBTRACT addStandardCompositeOps(this); } KoLabColorSpace::~KoLabColorSpace() { } QString KoLabColorSpace::colorSpaceId() { return QString("LABA"); } KoColorSpace* KoLabColorSpace::clone() const { return new KoLabColorSpace(); } void KoLabColorSpace::fromQColor(const QColor& c, quint8 *dst, const KoColorProfile * /*profile*/) const { // Convert between RGB and CIE-Lab color spaces // Uses ITU-R recommendation BT.709 with D65 as reference white. // algorithm contributed by "Mark A. Ruzon" int R, G, B, A; c.getRgb(&R, &G, &B, &A); double X, Y, Z, fX, fY, fZ; X = 0.412453 * R + 0.357580 * G + 0.180423 * B; Y = 0.212671 * R + 0.715160 * G + 0.072169 * B; Z = 0.019334 * R + 0.119193 * G + 0.950227 * B; X /= (255 * 0.950456); Y /= 255; Z /= (255 * 1.088754); quint8 L, a, b; if (Y > 0.008856) { fY = pow(Y, 1.0 / 3.0); L = static_cast(116.0 * fY - 16.0 + 0.5); } else { fY = 7.787 * Y + 16.0 / 116.0; L = static_cast(903.3 * Y + 0.5); } if (X > 0.008856) fX = pow(X, 1.0 / 3.0); else fX = 7.787 * X + 16.0 / 116.0; if (Z > 0.008856) fZ = pow(Z, 1.0 / 3.0); else fZ = 7.787 * Z + 16.0 / 116.0; a = static_cast(500.0 * (fX - fY) + 0.5); b = static_cast(200.0 * (fY - fZ) + 0.5); dst[CHANNEL_L] = UINT8_TO_UINT16(L); dst[CHANNEL_A] = UINT8_TO_UINT16(a); dst[CHANNEL_B] = UINT8_TO_UINT16(b); dst[CHANNEL_ALPHA] = UINT8_TO_UINT16(A); } void KoLabColorSpace::toQColor(const quint8 * src, QColor *c, const KoColorProfile * /*profile*/) const { // Convert between RGB and CIE-Lab color spaces // Uses ITU-R recommendation BT.709 with D65 as reference white. // algorithm contributed by "Mark A. Ruzon" quint8 L, a, b, A; L = UINT16_TO_UINT8(src[CHANNEL_L]); a = UINT16_TO_UINT8(src[CHANNEL_A]); b = UINT16_TO_UINT8(src[CHANNEL_B]); A = UINT16_TO_UINT8(src[CHANNEL_ALPHA]); double X, Y, Z, fX, fY, fZ; int RR, GG, BB; fY = pow((L + 16.0) / 116.0, 3.0); if (fY < 0.008856) fY = L / 903.3; Y = fY; if (fY > 0.008856) fY = pow(fY, 1.0 / 3.0); else fY = 7.787 * fY + 16.0 / 116.0; fX = a / 500.0 + fY; if (fX > 0.206893) X = pow(fX, 3.0); else X = (fX - 16.0 / 116.0) / 7.787; fZ = fY - b / 200.0; if (fZ > 0.206893) Z = pow(fZ, 3.0); else Z = (fZ - 16.0 / 116.0) / 7.787; X *= 0.950456 * 255; Y *= 255; Z *= 1.088754 * 255; RR = static_cast(3.240479 * X - 1.537150 * Y - 0.498535 * Z + 0.5); GG = static_cast(-0.969256 * X + 1.875992 * Y + 0.041556 * Z + 0.5); BB = static_cast(0.055648 * X - 0.204043 * Y + 1.057311 * Z + 0.5); quint8 R = RR < 0 ? 0 : RR > 255 ? 255 : RR; quint8 G = GG < 0 ? 0 : GG > 255 ? 255 : GG; quint8 B = BB < 0 ? 0 : BB > 255 ? 255 : BB; c->setRgba(qRgba(R, G, B, A)); } -void KoLabColorSpace::toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const +void KoLabColorSpace::toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const { LabToLCH(channelValues[0],channelValues[1],channelValues[2], luma, sat, hue); } -QVector KoLabColorSpace::fromHSY(qreal *hue, qreal *sat, qreal *luma) const +QVector KoLabColorSpace::fromHSY(qreal *hue, qreal *sat, qreal *luma) const { - QVector channelValues(4); + QVector channelValues(4); LCHToLab(*luma, *sat, *hue, &channelValues[0],&channelValues[1],&channelValues[2]); channelValues[3]=1.0; return channelValues; } -void KoLabColorSpace::toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const +void KoLabColorSpace::toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const { *y =channelValues[0]; *v=channelValues[1]; *u=channelValues[2]; } -QVector KoLabColorSpace::fromYUV(qreal *y, qreal *u, qreal *v) const +QVector KoLabColorSpace::fromYUV(qreal *y, qreal *u, qreal *v) const { - QVector channelValues(4); + QVector channelValues(4); channelValues[0]=*y; channelValues[1]=*v; channelValues[2]=*u; channelValues[3]=1.0; return channelValues; } diff --git a/libs/pigment/colorspaces/KoLabColorSpace.h b/libs/pigment/colorspaces/KoLabColorSpace.h index 86bc5ef9631..b3ce5db63d8 100644 --- a/libs/pigment/colorspaces/KoLabColorSpace.h +++ b/libs/pigment/colorspaces/KoLabColorSpace.h @@ -1,88 +1,88 @@ /* * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2006 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KOLABCOLORSPACE_H #define KOLABCOLORSPACE_H #include #include "KoSimpleColorSpace.h" #include "KoSimpleColorSpaceFactory.h" #include "KoColorModelStandardIds.h" struct KoLabU16Traits; /** * Basic and simple implementation of the LAB colorspace */ class KoLabColorSpace : public KoSimpleColorSpace { public: KoLabColorSpace(); virtual ~KoLabColorSpace(); static QString colorSpaceId(); virtual KoColorSpace* clone() const; virtual void fromQColor(const QColor& color, quint8 *dst, const KoColorProfile * profile = 0) const; virtual void toQColor(const quint8 *src, QColor *c, const KoColorProfile * profile = 0) const; - virtual void toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const; - virtual QVector fromHSY(qreal *hue, qreal *sat, qreal *luma) const; - virtual void toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const; - virtual QVector fromYUV(qreal *y, qreal *u, qreal *v) const; + virtual void toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const; + virtual QVector fromHSY(qreal *hue, qreal *sat, qreal *luma) const; + virtual void toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const; + virtual QVector fromYUV(qreal *y, qreal *u, qreal *v) const; private: static const quint32 CHANNEL_L = 0; static const quint32 CHANNEL_A = 1; static const quint32 CHANNEL_B = 2; static const quint32 CHANNEL_ALPHA = 3; static const quint32 MAX_CHANNEL_L = 0xff00; static const quint32 MAX_CHANNEL_AB = 0xffff; static const quint32 CHANNEL_AB_ZERO_OFFSET = 0x8000; }; class KoLabColorSpaceFactory : public KoSimpleColorSpaceFactory { public: KoLabColorSpaceFactory() : KoSimpleColorSpaceFactory("LABA", i18n("L*a*b* (16-bit integer/channel, unmanaged)"), true, LABAColorModelID, Integer16BitsColorDepthID, 16) { } virtual KoColorSpace *createColorSpace(const KoColorProfile *) const { return new KoLabColorSpace(); } }; #endif diff --git a/libs/pigment/colorspaces/KoRgbU16ColorSpace.cpp b/libs/pigment/colorspaces/KoRgbU16ColorSpace.cpp index 927ae3c04e1..862d6210266 100644 --- a/libs/pigment/colorspaces/KoRgbU16ColorSpace.cpp +++ b/libs/pigment/colorspaces/KoRgbU16ColorSpace.cpp @@ -1,98 +1,97 @@ /* * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2006 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KoRgbU16ColorSpace.h" #include #include #include #include #include #include "KoChannelInfo.h" #include "KoID.h" #include "KoIntegerMaths.h" #include "KoColorConversions.h" KoRgbU16ColorSpace::KoRgbU16ColorSpace() : KoSimpleColorSpace(colorSpaceId(), i18n("RGB (16-bit integer/channel, unmanaged)"), RGBAColorModelID, Integer16BitsColorDepthID) { } KoRgbU16ColorSpace::~KoRgbU16ColorSpace() { } QString KoRgbU16ColorSpace::colorSpaceId() { return QString("RGBA16"); } KoColorSpace* KoRgbU16ColorSpace::clone() const { return new KoRgbU16ColorSpace(); } void KoRgbU16ColorSpace::fromQColor(const QColor& c, quint8 *dst, const KoColorProfile * /*profile*/) const { - QVector channelValues; + QVector channelValues; channelValues << c.blueF() << c.greenF() << c.redF() << c.alphaF(); fromNormalisedChannelsValue(dst, channelValues); } void KoRgbU16ColorSpace::toQColor(const quint8 * src, QColor *c, const KoColorProfile * /*profile*/) const { - QVector channelValues(4); + QVector channelValues(4); normalisedChannelsValue(src, channelValues); c->setRgbF(channelValues[2], channelValues[1], channelValues[0], channelValues[3]); } -void KoRgbU16ColorSpace::toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const +void KoRgbU16ColorSpace::toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const { RGBToHSY(channelValues[0],channelValues[1],channelValues[2], hue, sat, luma); } -QVector KoRgbU16ColorSpace::fromHSY(qreal *hue, qreal *sat, qreal *luma) const +QVector KoRgbU16ColorSpace::fromHSY(qreal *hue, qreal *sat, qreal *luma) const { - QVector channelValues(4); + QVector channelValues(4); HSYToRGB(*hue, *sat, *luma, &channelValues[0],&channelValues[1],&channelValues[2]); channelValues[3]=1.0; return channelValues; - } -void KoRgbU16ColorSpace::toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const +void KoRgbU16ColorSpace::toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const { RGBToYUV(channelValues[0],channelValues[1],channelValues[2], y, u, v); } -QVector KoRgbU16ColorSpace::fromYUV(qreal *y, qreal *u, qreal *v) const +QVector KoRgbU16ColorSpace::fromYUV(qreal *y, qreal *u, qreal *v) const { - QVector channelValues(4); + QVector channelValues(4); YUVToRGB(*y, *u, *v, &channelValues[0],&channelValues[1],&channelValues[2]); channelValues[3]=1.0; return channelValues; } diff --git a/libs/pigment/colorspaces/KoRgbU16ColorSpace.h b/libs/pigment/colorspaces/KoRgbU16ColorSpace.h index 6a866dcb521..21b31f22c17 100644 --- a/libs/pigment/colorspaces/KoRgbU16ColorSpace.h +++ b/libs/pigment/colorspaces/KoRgbU16ColorSpace.h @@ -1,77 +1,77 @@ /* * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2006 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KORGBU16COLORSPACE_H #define KORGBU16COLORSPACE_H #include #include "KoSimpleColorSpace.h" #include "KoSimpleColorSpaceFactory.h" #include "KoColorModelStandardIds.h" struct KoBgrU16Traits; /** * The alpha mask is a special color strategy that treats all pixels as * alpha value with a color common to the mask. The default color is white. */ class KoRgbU16ColorSpace : public KoSimpleColorSpace { public: KoRgbU16ColorSpace(); virtual ~KoRgbU16ColorSpace(); static QString colorSpaceId(); virtual KoColorSpace* clone() const; virtual void fromQColor(const QColor& color, quint8 *dst, const KoColorProfile * profile = 0) const; virtual void toQColor(const quint8 *src, QColor *c, const KoColorProfile * profile = 0) const; - virtual void toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const; - virtual QVector fromHSY(qreal *hue, qreal *sat, qreal *luma) const; - virtual void toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const; - virtual QVector fromYUV(qreal *y, qreal *u, qreal *v) const; + virtual void toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const; + virtual QVector fromHSY(qreal *hue, qreal *sat, qreal *luma) const; + virtual void toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const; + virtual QVector fromYUV(qreal *y, qreal *u, qreal *v) const; }; class KoRgbU16ColorSpaceFactory : public KoSimpleColorSpaceFactory { public: KoRgbU16ColorSpaceFactory() : KoSimpleColorSpaceFactory(KoRgbU16ColorSpace::colorSpaceId(), i18n("RGB (16-bit integer/channel, unmanaged)"), true, RGBAColorModelID, Integer16BitsColorDepthID, 16) { } virtual KoColorSpace *createColorSpace(const KoColorProfile *) const { return new KoRgbU16ColorSpace(); } }; #endif diff --git a/libs/pigment/colorspaces/KoRgbU8ColorSpace.cpp b/libs/pigment/colorspaces/KoRgbU8ColorSpace.cpp index 9539a18f8d8..e72b03e2540 100644 --- a/libs/pigment/colorspaces/KoRgbU8ColorSpace.cpp +++ b/libs/pigment/colorspaces/KoRgbU8ColorSpace.cpp @@ -1,111 +1,111 @@ /* * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2006 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KoRgbU8ColorSpace.h" #include #include #include #include #include #include "KoChannelInfo.h" #include "KoID.h" #include "KoIntegerMaths.h" #include "compositeops/KoCompositeOps.h" #include "KoColorConversions.h" KoRgbU8ColorSpace::KoRgbU8ColorSpace() : KoSimpleColorSpace(colorSpaceId(), i18n("RGB (8-bit integer/channel, unmanaged)"), RGBAColorModelID, Integer8BitsColorDepthID) { addChannel(new KoChannelInfo(i18n("Blue"), 0, 2, KoChannelInfo::COLOR, KoChannelInfo::UINT8, 1, QColor(0, 0, 255))); addChannel(new KoChannelInfo(i18n("Green"), 1, 1, KoChannelInfo::COLOR, KoChannelInfo::UINT8, 1, QColor(0, 255, 0))); addChannel(new KoChannelInfo(i18n("Red"), 2, 0, KoChannelInfo::COLOR, KoChannelInfo::UINT8, 1, QColor(255, 0, 0))); addChannel(new KoChannelInfo(i18n("Alpha"), 3, 3, KoChannelInfo::ALPHA, KoChannelInfo::UINT8)); // ADD, ALPHA_DARKEN, BURN, DIVIDE, DODGE, ERASE, MULTIPLY, OVER, OVERLAY, SCREEN, SUBTRACT addStandardCompositeOps(this); } KoRgbU8ColorSpace::~KoRgbU8ColorSpace() { } QString KoRgbU8ColorSpace::colorSpaceId() { return QString("RGBA"); } KoColorSpace* KoRgbU8ColorSpace::clone() const { return new KoRgbU8ColorSpace(); } void KoRgbU8ColorSpace::fromQColor(const QColor& c, quint8 *dst, const KoColorProfile * /*profile*/) const { - QVector channelValues; + QVector channelValues; channelValues << c.blueF() << c.greenF() << c.redF() << c.alphaF(); fromNormalisedChannelsValue(dst, channelValues); } void KoRgbU8ColorSpace::toQColor(const quint8 * src, QColor *c, const KoColorProfile * /*profile*/) const { - QVector channelValues(4); + QVector channelValues(4); normalisedChannelsValue(src, channelValues); c->setRgbF(channelValues[2], channelValues[1], channelValues[0], channelValues[3]); } -void KoRgbU8ColorSpace::toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const +void KoRgbU8ColorSpace::toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const { RGBToHSY(channelValues[0],channelValues[1],channelValues[2], hue, sat, luma); } -QVector KoRgbU8ColorSpace::fromHSY(qreal *hue, qreal *sat, qreal *luma) const +QVector KoRgbU8ColorSpace::fromHSY(qreal *hue, qreal *sat, qreal *luma) const { - QVector channelValues(4); + QVector channelValues(4); HSYToRGB(*hue, *sat, *luma, &channelValues[0],&channelValues[1],&channelValues[2]); channelValues[3]=1.0; return channelValues; } -void KoRgbU8ColorSpace::toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const +void KoRgbU8ColorSpace::toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const { RGBToYUV(channelValues[0],channelValues[1],channelValues[2], y, u, v); } -QVector KoRgbU8ColorSpace::fromYUV(qreal *y, qreal *u, qreal *v) const +QVector KoRgbU8ColorSpace::fromYUV(qreal *y, qreal *u, qreal *v) const { - QVector channelValues(4); + QVector channelValues(4); YUVToRGB(*y, *u, *v, &channelValues[0],&channelValues[1],&channelValues[2]); channelValues[3]=1.0; return channelValues; } diff --git a/libs/pigment/colorspaces/KoRgbU8ColorSpace.h b/libs/pigment/colorspaces/KoRgbU8ColorSpace.h index d5157d4adb1..3b2585766a5 100644 --- a/libs/pigment/colorspaces/KoRgbU8ColorSpace.h +++ b/libs/pigment/colorspaces/KoRgbU8ColorSpace.h @@ -1,77 +1,77 @@ /* * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2006 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KORGBU8COLORSPACE_H #define KORGBU8COLORSPACE_H #include #include "KoSimpleColorSpace.h" #include "KoSimpleColorSpaceFactory.h" #include "KoColorModelStandardIds.h" struct KoBgrU8Traits; /** * The alpha mask is a special color strategy that treats all pixels as * alpha value with a color common to the mask. The default color is white. */ class KoRgbU8ColorSpace : public KoSimpleColorSpace { public: KoRgbU8ColorSpace(); virtual ~KoRgbU8ColorSpace(); static QString colorSpaceId(); virtual KoColorSpace* clone() const; virtual void fromQColor(const QColor& color, quint8 *dst, const KoColorProfile * profile = 0) const; virtual void toQColor(const quint8 *src, QColor *c, const KoColorProfile * profile = 0) const; - virtual void toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const; - virtual QVector fromHSY(qreal *hue, qreal *sat, qreal *luma) const; - virtual void toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const; - virtual QVector fromYUV(qreal *y, qreal *u, qreal *v) const; + virtual void toHSY(const QVector &channelValues, qreal *hue, qreal *sat, qreal *luma) const; + virtual QVector fromHSY(qreal *hue, qreal *sat, qreal *luma) const; + virtual void toYUV(const QVector &channelValues, qreal *y, qreal *u, qreal *v) const; + virtual QVector fromYUV(qreal *y, qreal *u, qreal *v) const; }; class KoRgbU8ColorSpaceFactory : public KoSimpleColorSpaceFactory { public: KoRgbU8ColorSpaceFactory() : KoSimpleColorSpaceFactory("RGBA", i18n("RGB (8-bit integer/channel, unmanaged)"), true, RGBAColorModelID, Integer8BitsColorDepthID, 8) { } virtual KoColorSpace *createColorSpace(const KoColorProfile *) const { return new KoRgbU8ColorSpace(); } }; #endif diff --git a/libs/pigment/colorspaces/KoSimpleColorSpace.h b/libs/pigment/colorspaces/KoSimpleColorSpace.h index 08c914df4ed..ee723708d23 100644 --- a/libs/pigment/colorspaces/KoSimpleColorSpace.h +++ b/libs/pigment/colorspaces/KoSimpleColorSpace.h @@ -1,229 +1,229 @@ /* * Copyright (c) 2004-2009 Boudewijn Rempt * Copyright (c) 2006 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KOSIMPLECOLORSPACE_H #define KOSIMPLECOLORSPACE_H #include #include "DebugPigment.h" #include "KoColorSpaceAbstract.h" #include "KoSimpleColorSpaceFactory.h" #include "KoColorModelStandardIds.h" #include "colorprofiles/KoDummyColorProfile.h" template class KoSimpleColorSpace : public KoColorSpaceAbstract<_CSTraits> { public: KoSimpleColorSpace(const QString& id, const QString& name, const KoID& colorModelId, const KoID& colorDepthId) : KoColorSpaceAbstract<_CSTraits>(id, name) , m_name(name) , m_colorModelId(colorModelId) , m_colorDepthId(colorDepthId) , m_profile(new KoDummyColorProfile) { } virtual ~KoSimpleColorSpace() { delete m_profile; } virtual KoID colorModelId() const { return m_colorModelId; } virtual KoID colorDepthId() const { return m_colorDepthId; } virtual bool willDegrade(ColorSpaceIndependence independence) const { Q_UNUSED(independence); return false; } virtual bool profileIsCompatible(const KoColorProfile* /*profile*/) const { return true; } virtual quint8 difference(const quint8 *src1, const quint8 *src2) const { Q_UNUSED(src1); Q_UNUSED(src2); warnPigment << i18n("Undefined operation in the %1 space", m_name); return 0; } virtual quint8 differenceA(const quint8 *src1, const quint8 *src2) const { Q_UNUSED(src1); Q_UNUSED(src2); warnPigment << i18n("Undefined operation in the %1 space", m_name); return 0; } virtual quint32 colorSpaceType() const { return 0; } virtual bool hasHighDynamicRange() const { return false; } virtual const KoColorProfile* profile() const { return m_profile; } virtual KoColorTransformation* createBrightnessContrastAdjustment(const quint16*) const { warnPigment << i18n("Undefined operation in the %1 color space", m_name); return 0; } virtual KoColorTransformation* createDesaturateAdjustment() const { warnPigment << i18n("Undefined operation in the %1 color space", m_name); return 0; } virtual KoColorTransformation* createPerChannelAdjustment(const quint16* const*) const { warnPigment << i18n("Undefined operation in the %1 color space", m_name); return 0; } virtual KoColorTransformation *createDarkenAdjustment(qint32 , bool , qreal) const { warnPigment << i18n("Undefined operation in the %1 color space", m_name); return 0; } virtual void invertColor(quint8*, qint32) const { warnPigment << i18n("Undefined operation in the %1 color space", m_name); } virtual void colorToXML(const quint8* , QDomDocument& , QDomElement&) const { warnPigment << i18n("Undefined operation in the %1 color space", m_name); } virtual void colorFromXML(quint8* , const QDomElement&) const { warnPigment << i18n("Undefined operation in the %1 color space", m_name); } - virtual void toHSY(const QVector &, qreal *, qreal *, qreal *) const { + virtual void toHSY(const QVector &, qreal *, qreal *, qreal *) const { warnPigment << i18n("Undefined operation in the %1 color space", m_name); } - virtual QVector fromHSY(qreal *, qreal *, qreal *) const { + virtual QVector fromHSY(qreal *, qreal *, qreal *) const { warnPigment << i18n("Undefined operation in the %1 color space", m_name); - QVector channelValues (2); + QVector channelValues (2); channelValues.fill(0.0); return channelValues; } - virtual void toYUV(const QVector &, qreal *, qreal *, qreal *) const { + virtual void toYUV(const QVector &, qreal *, qreal *, qreal *) const { warnPigment << i18n("Undefined operation in the %1 color space", m_name); } - virtual QVector fromYUV(qreal *, qreal *, qreal *) const { + virtual QVector fromYUV(qreal *, qreal *, qreal *) const { warnPigment << i18n("Undefined operation in the %1 color space", m_name); - QVector channelValues (2); + QVector channelValues (2); channelValues.fill(0.0); return channelValues; } virtual void toLabA16(const quint8* src, quint8* dst, quint32 nPixels) const { if (colorDepthId() == Integer16BitsColorDepthID && colorModelId() == LABAColorModelID) { memcpy(dst, src, nPixels * 2); } else { const KoColorSpace* dstCs = KoColorSpaceRegistry::instance()->lab16(); convertPixelsTo(src, dst, dstCs, nPixels, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); } } virtual void fromLabA16(const quint8* src, quint8* dst, quint32 nPixels) const { if (colorDepthId() == Integer16BitsColorDepthID && colorModelId() == LABAColorModelID) { memcpy(dst, src, nPixels * 2); } else { const KoColorSpace* srcCs = KoColorSpaceRegistry::instance()->lab16(); srcCs->convertPixelsTo(src, dst, this, nPixels, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); } } virtual void toRgbA16(const quint8* src, quint8* dst, quint32 nPixels) const { if (colorDepthId() == Integer16BitsColorDepthID && colorModelId() == RGBAColorModelID) { memcpy(dst, src, nPixels * 2); } else { const KoColorSpace* dstCs = KoColorSpaceRegistry::instance()->rgb16(); convertPixelsTo(src, dst, dstCs, nPixels, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); } } virtual void fromRgbA16(const quint8* src, quint8* dst, quint32 nPixels) const { if (colorDepthId() == Integer16BitsColorDepthID && colorModelId() == RGBAColorModelID) { memcpy(dst, src, nPixels * 2); } else { const KoColorSpace* srcCs = KoColorSpaceRegistry::instance()->rgb16(); srcCs->convertPixelsTo(src, dst, this, nPixels, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); } } virtual bool convertPixelsTo(const quint8 *src, quint8 *dst, const KoColorSpace * dstColorSpace, quint32 numPixels, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const { Q_UNUSED(renderingIntent); Q_UNUSED(conversionFlags); QColor c; quint32 srcPixelsize = this->pixelSize(); quint32 dstPixelsize = dstColorSpace->pixelSize(); while (numPixels > 0) { this->toQColor(src, &c); dstColorSpace->fromQColor(c, dst); src += srcPixelsize; dst += dstPixelsize; --numPixels; } return true; } virtual QString colorSpaceEngine() const { return "simple"; } private: QString m_name; KoID m_colorModelId; KoID m_colorDepthId; KoColorProfile* m_profile; }; #endif // KOSIMPLECOLORSPACE_H