#include "Gradient.h" #include //extern char *GetBinDir(char *str); BYTE GetRValue(COLORREF colour) { QColor color(colour); return color.red(); } BYTE GetGValue(COLORREF colour) { QColor color(colour); return color.green(); } BYTE GetBValue(COLORREF colour) { QColor color(colour); return color.blue(); } CGradient::CGradient() { m_StartPeg.colour = 0x00FFFFFF;// m_StartPeg.position = 0.0f; m_EndPeg.colour = 0x00000000;// m_EndPeg.position = 1.0f; m_Background.colour = 0x00FFFFFF; //A default pal m_Background.position = 0.0f; m_InterpolationMethod = Linear; m_UseBackground = false; m_Quantization = -1; m_FileFlag = "LogPlus"; pegs.clear(); } CGradient::~CGradient() { pegs.clear(); } //void CGradient::MakeEntries(RGBTRIPLE *lpPal, int iEntryCount) //{ // float pos; // COLORREF colour; // int curpeg; // if ( iEntryCount < 1 || iEntryCount >= 65535) // return ; // InterpolateFn Interpolate = GetInterpolationProc(); // if(pegs.count() > 0) // { // //Some things are already constant and so can be found early // float firstpegpos = pegs[0].position; // float lastpegpos = pegs[pegs.count()-1].position; // COLORREF lastpegcolour = pegs[pegs.count()-1].colour; // for(int i = 0; i < iEntryCount; i++) // { // if(m_Quantization == -1) // pos = (float)i/iEntryCount; // else // pos = ((float)(int)(((float)i/iEntryCount)*m_Quantization))/m_Quantization + 0.5f / m_Quantization; // if(pos <= firstpegpos) // { // colour = Interpolate(m_StartPeg.colour, pegs[0].colour, pos, 0, firstpegpos); // lpPal[i].rgbtRed = GetRValue(colour); // lpPal[i].rgbtGreen = GetGValue(colour); // lpPal[i].rgbtBlue = GetBValue(colour); // } // else if(pos > lastpegpos) // { // colour = Interpolate(lastpegcolour, m_EndPeg.colour, pos, lastpegpos, 1); // lpPal[i].rgbtRed = GetRValue(colour); // lpPal[i].rgbtGreen = GetGValue(colour); // lpPal[i].rgbtBlue = GetBValue(colour); // } // else // { // curpeg = IndexFromPos(pos); // colour = Interpolate(pegs[curpeg].colour, pegs[curpeg+1].colour, pos, pegs[curpeg].position, pegs[curpeg+1].position); // lpPal[i].rgbtRed = GetRValue(colour); // lpPal[i].rgbtGreen = GetGValue(colour); // lpPal[i].rgbtBlue = GetBValue(colour); // } // } // } // else // { // //When there are no extra peg we can just interpolate the start and end // for(int i = 0; i < iEntryCount; i++) // { // if(m_Quantization == -1) // pos = (float)i/iEntryCount; // else // pos = ((float)(int)(((float)i/iEntryCount)*m_Quantization))/m_Quantization + 0.5f / m_Quantization; // colour = Interpolate(m_StartPeg.colour, m_EndPeg.colour, pos, 0, 1); // lpPal[i].rgbtRed = GetRValue(colour); // lpPal[i].rgbtGreen = GetGValue(colour); // lpPal[i].rgbtBlue = GetBValue(colour); // } // } // if(m_UseBackground) // { // lpPal[0].rgbtRed = GetRValue(m_Background.colour); // lpPal[0].rgbtGreen = GetGValue(m_Background.colour); // lpPal[0].rgbtBlue = GetBValue(m_Background.colour); // } //} InterpolateFn CGradient::GetInterpolationProc() { switch(m_InterpolationMethod) { case Linear: return InterpolateLinear; case FlatStart: return InterpolateFlatStart; case FlatMid: return InterpolateFlatMid; case FlatEnd: return InterpolateFlatEnd; case Cosine: return InterpolateCosine; case HSLRedBlue: return InterpolateHSLClockwise; case HSLBlueRed: return InterpolateHSLAntiClockwise; case HSLShortest: return InterpolateHSLShortest; case HSLLongest: return InterpolateHSLLongest; case Reverse: { QVector pegsTemp; //CArray pegsTemp; int n = pegs.count(); pegsTemp.clear(); pegsTemp.resize(n); for (int i=0; i= 0.0f && pos <= 1.0f); if ( pos<0 || pos>1 ) return NONE; // positions betwen 0 and 1! if(pos < pegs[0].position) return STARTPEG; for(int i = 0; i < pegs.count()-1; i++) if(pos >= pegs[i].position && pos <= pegs[i+1].position) return i; return -1; // Eh? somethings wrong here } COLORREF CGradient::InterpolateLinear(COLORREF first, COLORREF second, float position, float start, float end) { if(start == end) return first; if(end - start == 0) return second; if(position == start) return first; if(position == end) return second; return RGB((BYTE)((GetRValue(second)*(position - start) + GetRValue(first)*(end-position))/(end-start)), (BYTE)((GetGValue(second)*(position - start) + GetGValue(first)*(end-position))/(end-start)), (BYTE)((GetBValue(second)*(position - start) + GetBValue(first)*(end-position))/(end-start))); } COLORREF CGradient::InterpolateReverse(COLORREF first, COLORREF second, float position, float start, float end) { if(start == end) return first; if(end - start == 0) return second; if(position == start) return first; if(position == end) return second; // return RGB((BYTE)((GetRValue(first)*(position - start) + GetRValue(second)*(end-position))/(end-start)), // (BYTE)((GetGValue(first)*(position - start) + GetGValue(second)*(end-position))/(end-start)), // (BYTE)((GetBValue(first)*(position - start) + GetBValue(second)*(end-position))/(end-start))); return RGB((BYTE)((GetRValue(second)*(position - start) + GetRValue(first)*(end-position))/(end-start)), (BYTE)((GetGValue(second)*(position - start) + GetGValue(first)*(end-position))/(end-start)), (BYTE)((GetBValue(second)*(position - start) + GetBValue(first)*(end-position))/(end-start))); } COLORREF CGradient::InterpolateFlatStart(COLORREF first, COLORREF, float, float, float) {return first;} COLORREF CGradient::InterpolateFlatMid(COLORREF first, COLORREF second, float, float, float) { unsigned short sr, sg, sb, er, eg, eb; sr = GetRValue(first); sg = GetGValue(first); sb = GetBValue(first); er = GetRValue(second); eg = GetGValue(second); eb = GetBValue(second); return RGB((sr+er)/2, (sg+eg)/2, (sb+eb)/2); } COLORREF CGradient::InterpolateFlatEnd(COLORREF, COLORREF second, float, float, float) {return second;} COLORREF CGradient::InterpolateCosine(COLORREF first, COLORREF second, float position, float start, float end) { float theta = (position-start)/(end-start) * 3.1415927f; float f = (1 - cosf(theta)) * .5f; return RGB((BYTE)(((float)GetRValue(first))*(1-f) + ((float)GetRValue(second))*f), (BYTE)(((float)GetGValue(first))*(1-f) + ((float)GetGValue(second))*f), (BYTE)(((float)GetBValue(first))*(1-f) + ((float)GetBValue(second))*f)); } void RGB_to_HSL (float r, float g, float b, float *h, float *s, float *l) { float v; float m; float vm; float r2, g2, b2; v = max(r,g); v = max(v,b); m = min(r,g); m = min(m,b); if ((*l = (m + v) / 2.0f) <= 0.0f) return; if ((*s = vm = v - m) > 0.0f) { *s /= (*l <= 0.5f) ? (v + m ) : (2.0f - v - m) ; } else return; r2 = (v - r) / vm; g2 = (v - g) / vm; b2 = (v - b) / vm; if (r == v) *h = (g == m ? 5.0f + b2 : 1.0f - g2); else if (g == v) *h = (b == m ? 1.0f + r2 : 3.0f - b2); else *h = (r == m ? 3.0f + g2 : 5.0f - r2); *h /= 6.0f; } void HSL_to_RGB(float h, float sl, float l, float *r, float *g, float *b) { float v; v = (l <= 0.5f) ? (l * (1.0f + sl)) : (l + sl - l * sl); if (v <= 0) { *r = *g = *b = 0.0f; } else { float m; float sv; int sextant; float fract, vsf, mid1, mid2; m = l + l - v; sv = (v - m ) / v; h *= 6.0f; sextant = (int)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; } } } COLORREF CGradient::InterpolateHSLClockwise(COLORREF first, COLORREF second, float position, float start, float end) { float sh = 0, ss = 0, sl = 0, eh = 0, es = 0, el = 0, h = 0, s = 0, l = 0, r = 0, g = 0, b = 0; RGB_to_HSL((float)GetRValue(first)/255.0f, (float)GetGValue(first)/255.0f, (float)GetBValue(first)/255.0f, &sh, &ss, &sl); RGB_to_HSL((float)GetRValue(second)/255.0f, (float)GetGValue(second)/255.0f, (float)GetBValue(second)/255.0f, &eh, &es, &el); sh = sh - floorf(sh); eh = eh - floorf(eh); //Interpolate H clockwise if(eh >= sh) h = (eh*(position - start) + sh*(end-position))/(end-start); else h = ((eh + 1.0f)*(position - start) + sh*(end-position))/(end-start); h = (h>=1.0f)?h-1.0f:h; s = ((es*(position - start) + ss*(end-position))/(end-start)); l = ((el*(position - start) + sl*(end-position))/(end-start)); HSL_to_RGB(h, s, l, &r, &g, &b); return RGB((BYTE)(r*255.0f), (BYTE)(g*255.0f), (BYTE)(b*255.0f)); } COLORREF CGradient::InterpolateHSLAntiClockwise(COLORREF first, COLORREF second, float position, float start, float end) { float sh = 0, ss = 0, sl = 0, eh = 0, es = 0, el = 0, h = 0, s = 0, l = 0, r = 0, g = 0, b = 0; RGB_to_HSL((float)GetRValue(first)/255.0f, (float)GetGValue(first)/255.0f, (float)GetBValue(first)/255.0f, &sh, &ss, &sl); RGB_to_HSL((float)GetRValue(second)/255.0f, (float)GetGValue(second)/255.0f, (float)GetBValue(second)/255.0f, &eh, &es, &el); sh = sh - floorf(sh); eh = eh - floorf(eh); //Interpolate H anticlockwise if(eh <= sh) h = (eh*(position - start) + sh*(end-position))/(end-start); else h = ((eh + 1.0f)*(position - start) + sh*(end-position))/(end-start); h = (h>=1.0f)?h-1.0f:h; s = ((es*(position - start) + ss*(end-position))/(end-start)); l = ((el*(position - start) + sl*(end-position))/(end-start)); HSL_to_RGB(h, s, l, &r, &g, &b); return RGB((BYTE)(r*255.0f), (BYTE)(g*255.0f), (BYTE)(b*255.0f)); } COLORREF CGradient::InterpolateHSLLongest(COLORREF first, COLORREF second, float position, float start, float end) { float sh = 0, ss = 0, sl = 0, eh = 0, es = 0, el = 0, h = 0, s = 0, l = 0, r = 0, g = 0, b = 0; RGB_to_HSL((float)GetRValue(first)/255.0f, (float)GetGValue(first)/255.0f, (float)GetBValue(first)/255.0f, &sh, &ss, &sl); RGB_to_HSL((float)GetRValue(second)/255.0f, (float)GetGValue(second)/255.0f, (float)GetBValue(second)/255.0f, &eh, &es, &el); sh = sh - (float)floor(sh); eh = eh - (float)floor(eh); //Interpolate H short route if(((eh-sh)-floor(eh-sh) < 0.5f)?(eh < sh):(eh >= sh)) h = (eh*(position - start) + sh*(end-position))/(end-start); else h = ((eh+(sh>eh?1.0f:-1.0f))*(position - start) + sh*(end-position))/(end-start); //TRACE3("sh: %f eh: %f h: %f\n", sh, eh, h); h = h - floorf(h); s = ((es*(position - start) + ss*(end-position))/(end-start)); l = ((el*(position - start) + sl*(end-position))/(end-start)); HSL_to_RGB(h, s, l, &r, &g, &b); return RGB((BYTE)(r*255.0f), (BYTE)(g*255.0f), (BYTE)(b*255.0f)); } COLORREF CGradient::InterpolateHSLShortest(COLORREF first, COLORREF second, float position, float start, float end) { float sh = 0, ss = 0, sl = 0, eh = 0, es = 0, el = 0, h = 0, s = 0, l = 0, r = 0, g = 0, b = 0; RGB_to_HSL((float)GetRValue(first)/255.0f, (float)GetGValue(first)/255.0f, (float)GetBValue(first)/255.0f, &sh, &ss, &sl); RGB_to_HSL((float)GetRValue(second)/255.0f, (float)GetGValue(second)/255.0f, (float)GetBValue(second)/255.0f, &eh, &es, &el); sh = sh - (float)floor(sh); eh = eh - (float)floor(eh); //Interpolate H short route if(((eh-sh)-floor(eh-sh) > 0.5f)?(eh < sh):(eh >= sh)) h = (eh*(position - start) + sh*(end-position))/(end-start); else h = ((eh+(sh>eh?1.0f:-1.0f))*(position - start) + sh*(end-position))/(end-start); //TRACE3("sh: %f eh: %f h: %f\n", sh, eh, h); h = h - floorf(h); s = ((es*(position - start) + ss*(end-position))/(end-start)); l = ((el*(position - start) + sl*(end-position))/(end-start)); HSL_to_RGB(h, s, l, &r, &g, &b); return RGB((BYTE)(r*255.0f), (BYTE)(g*255.0f), (BYTE)(b*255.0f)); } void CGradient::GetColorArray(COLORREF colorArr[]) { float pos; InterpolateFn Interpolate = GetInterpolationProc(); //if (pegs.GetSize() > 0) if (pegs.count() > 0) { float firstpegpos = pegs[0].position; COLORREF fistpegcolour = pegs[0].colour; float lastpegpos = pegs[pegs.count()-1].position; COLORREF lastpegcolour = pegs[pegs.count()-1].colour; //float lastpegpos = pegs[pegs.GetUpperBound()].position; //COLORREF lastpegcolour = pegs[pegs.GetUpperBound()].colour; int curpeg; int index; float pos2; COLORREF colour; for (index=0,pos=0.0; index<256; index++,pos+=0.003906) { if(m_Quantization != -1) pos2 = ((float)(int)(pos*m_Quantization))/m_Quantization + 0.5f / m_Quantization; else pos2 = pos; if (pos2 <= firstpegpos) { colour = Interpolate(m_StartPeg.colour, pegs[0].colour, pos2, 0, firstpegpos); colorArr[index] = colour; } else if (pos2 > lastpegpos) { colour = Interpolate(lastpegcolour, m_EndPeg.colour, pos2, lastpegpos, 1); colorArr[index] = colour; } else { curpeg = IndexFromPos2(pos2); colour = Interpolate(pegs[curpeg].colour, pegs[curpeg+1].colour, pos2, pegs[curpeg].position, pegs[curpeg+1].position); colorArr[index] = colour; } } } else //pegs.size == 0 { int index; float pos2; COLORREF colour; for (index=0,pos=0.0; index<256; index++,pos+=0.003906) { if (m_Quantization != -1) pos2 = ((float)(int)(pos*m_Quantization))/m_Quantization + 0.5f / m_Quantization; else pos2 = pos; colour = Interpolate(m_StartPeg.colour, m_EndPeg.colour, pos2, 0, 1); colorArr[index] = colour; } } } int CGradient::IndexFromPos2(float pos) { int begin = 0; //int end = pegs.GetSize()-1; int end = pegs.count()-1; int mid; while(begin <= end) { mid = (begin + end) / 2; if (pos > pegs[mid].position) { begin = mid+1; } else { end = mid-1; } } // if (mid==0) // mid =1; return end; } //读取配色方案 void CGradient::Serialize(QString strCfg)//CArchive &ar) { //lhj 2019-8-14 配色文件转换成TXT格式 // 保存为TXT格式 // strCfg.TrimLeft(); // strCfg.TrimRight(); strCfg.trimmed(); int i,n; char str[256],strName[256]; //CString strCipPath; CPeg peg; //GetBinDir(str); memset(str, '\0', sizeof (str)); strcat(str, QCoreApplication::applicationDirPath().toStdString().c_str()); strcat(str,"\\color\\"); strcat(str,strCfg.toStdString().c_str()); //strcat(str,"_clr.cfg"); FILE *fp; fp=fopen(str,"r"); if ( fp!=NULL) { fgets(strName,256,fp); sscanf(strName,"%s",str); //m_FileFlag.Format("%s",str); m_FileFlag = str; fgets(strName,256,fp); sscanf(strName,"%ld",&m_Background.colour); fgets(strName,256,fp); sscanf(strName,"%ld %ld",&m_StartPeg.colour,&m_EndPeg.colour); fgets(strName,256,fp); sscanf(strName,"%d",&i); m_UseBackground=i; fgets(strName,256,fp); sscanf(strName,"%d",&m_Quantization); fgets(strName,256,fp); sscanf(strName,"%d",&m_InterpolationMethod); fgets(strName,256,fp); sscanf(strName,"%d",&n); pegs.clear(); for( i = 0; i < n; i++) { fgets(strName,256,fp); sscanf(strName,"%ld %g",&peg.colour,&peg.position); pegs.append(peg); } fclose(fp); } }