001package org.vishia.gral.base;
002
003import org.vishia.math.CurveInterpolation;
004import org.vishia.util.Debugutil;
005
006public class GralColorConv
007{
008  
009  
010  /**Sensivity of light in respect to the color. It is a table-given function used with interpolation.
011   */
012  static float[][] clight = 
013  { 
014    { 0, 1 }  //magenta
015  , { 4, 1 }  //red
016  , { 8, 1.4f }  //yellow
017  , {12, 1.3f }  //green
018  , {16, 1.4f }  //cyan
019  , {17, 1.1f }  //blue
020  , {20, 1 }  //blue
021  , {24, 1 }  //magenta
022  };
023  
024  
025  static float[][] clightSat = 
026  { 
027    {0, 0 }  
028  , { 0.2f, 0.05f } 
029  , { 0.3f, 0.1f } 
030  , { 0.5f, 0.9f } 
031  , { 1, 1 }  
032  };
033  
034  /**Light value in depending of hex*/
035  static float[][] clightVal = 
036  { 
037    { 0, 0 }  
038  , { 0x20, 0.3f } 
039  , { 0x40, 0.5f } 
040  , { 0x60, 0.65f } 
041  , { 0x80, 0.75f } 
042  , { 0xa0, 1.0f } 
043  , { 0xc0, 1.2f } 
044  , { 0xe0, 1.5f } 
045  , { 0xff, 2.0f }                           
046  };
047  
048  
049  static float[][] loTable =
050  { { 0,   0,    4,    5,    7,    8,    12,   16,   18,   19,   20,   21,   24   }
051  , {0.0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
052  , {0.2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
053  , {0.5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
054  , {0.8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00 }
055  , {1.0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x60, 0x40, 0x00 }
056  , {1.3f, 0x40, 0x50, 0x20, 0x00, 0x00, 0x00, 0x00, 0x30, 0x40, 0x70, 0x70, 0x50 }
057  , {1.5f, 0x60, 0x80, 0x40, 0x00, 0x00, 0x20, 0x00, 0x60, 0x70, 0x80, 0x70, 0x60 }
058  , {2.0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
059  };
060  
061  
062  static float[][] grayTable =
063  { {0.0f, 0x00 }
064  , {0.2f, 0x20 }
065  , {0.5f, 0x50 }
066  , {1.0f, 0x8a }
067  , {1.3f, 0xb0 }
068  , {1.5f, 0xc0 }
069  , {2.0f, 0xff }
070  };
071  
072  
073  static float[][] hiTable =
074  { { 0,   0,    4,    5,    7,    8,    12,   16,   18,   19,   20,   21,   24   }
075  , {0.0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
076  , {0.2f, 0x40, 0x50, 0x40, 0x38, 0x38, 0x40, 0x30, 0x50, 0x50, 0x70, 0x50, 0x50 }
077  , {0.5f, 0x98, 0xa6, 0x98, 0x70, 0x68, 0x70, 0x68, 0x80, 0xc0, 0xe0, 0xc0, 0xa6 }
078  , {0.8f, 0xc0, 0xe0, 0xc0, 0xa0, 0x90, 0x9c, 0x90, 0xb0, 0xff, 0xff, 0xc0, 0xa6 }
079  , {1.0f, 0xe0, 0xff, 0xe8, 0xc0, 0xb0, 0xc4, 0xb0, 0xd0, 0xff, 0xff, 0xff, 0xff }
080  , {1.3f, 0xff, 0xff, 0xff, 0xf0, 0xe0, 0xff, 0xd0, 0xf0, 0xff, 0xff, 0xff, 0xff }
081  , {1.5f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
082  , {2.0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
083  };
084  
085  
086  
087  public static int HLStoRGB(float hue, float light, float sat){  ////
088    float lo = CurveInterpolation.linearInterpolation(light, hue, loTable, -1);
089    float gr = CurveInterpolation.linearInterpolation(light, grayTable, -1);
090    float hi = CurveInterpolation.linearInterpolation(light, hue, hiTable, -1);
091    //either lo should be 0 or hi should be 0xff, it is full saturation:
092    if(hi < 0xff && lo !=0){ 
093      hi += lo/4; lo = 0;
094    }
095    if(lo > 0 && hi !=0xff){ 
096      lo -= (0xff - hi); hi = 0xff; 
097    }
098    if(lo < 0){ 
099      hi -= lo; lo = 0; 
100    }
101    if(hi > 0xff){ 
102      lo += hi - 0xff; hi = 0xff; 
103    }
104    //calculate saturation:
105    float sat1 = sat;
106    if(lo > 0){ //light color
107      lo = gr - sat1 * (gr - lo);  //between gr (sat = 0) and lo (sat = 1) 
108      hi = gr + sat1 * (hi - gr);
109    } else { //dark color
110      lo = gr - sat1 * (gr - lo);  //between gr (sat = 0) and lo (sat = 1) 
111      hi = gr + sat1 * (hi - gr);
112    }
113
114    float diff = hi - lo;
115    int rd, gn, bl;
116    float fc;
117    switch((int)(hue / 4)){
118      case 0: fc = (4 -hue)/4;  gn = (int)lo; bl = (int)(lo +  diff * fc + 0.5f); rd = (int)(hi); break; //0..4, rt, --bl
119      case 1: fc = (hue- 4)/4;  bl = (int)lo; gn = (int)(lo +  diff * fc + 0.5f); rd = (int)(hi); break; //4..8  rt, ++gn
120      case 2: fc = (12-hue)/4;  bl = (int)lo; rd = (int)(lo +  diff * fc + 0.5f); gn = (int)(hi); break; //8..12 gn, --rt
121      case 3: fc = (hue-12)/4;  rd = (int)lo; bl = (int)(lo +  diff * fc + 0.5f); gn = (int)(hi); break; //12..16 gn, ++bl
122      case 4: fc = (20 -hue)/4; rd = (int)lo; gn = (int)(lo +  diff * fc + 0.5f); bl = (int)(hi); break; //16..20 bl, --gn
123      case 5: fc = (hue-20)/4;  gn = (int)lo; rd = (int)(lo +  diff * fc + 0.5f); bl = (int)(hi); break; //20..24 bl, ++rt
124      default: rd = 0x80; gn = 0; bl = 0x80;
125    }
126    return ((rd << 16) & 0xff0000) + ((gn << 8) & 0x00ff00) + (bl & 0x0000ff);
127  }
128  
129  /**Converts a color given by hue, light and sat to rgb.
130   * @param hue The color in range 0..24.0. 0 is magenta, 4: red, 8 yellow, 12 green 16 cyan, 20 blue, 24 magenta.
131   * @param light The light, 0 to 2.0. 1.0 is the saturated red 0xff0000 or a darker yellow. 1.4 is yellow 0xffff00.
132   *   till 2.0 it uses the base values for color in white direction. 2.0 it is white.
133   * @param sat Saturation 0..1. part of gray. 1.0 is non-gray. 0 is full gray.
134   * @return rgb
135   */
136  public static int HLStoRGB3(float hue, float light, float sat){  ////
137
138    if(hue == 9 && sat == 1 && light == 1.95f)
139      Debugutil.stop();
140    float hue1 = (hue-4) / 24;
141    if(hue1 < 0 ){ hue1 += 1.0f; }
142    float nlight1 = CurveInterpolation.linearInterpolation(hue, clight, -1);
143    float nlightsat = CurveInterpolation.splineInterpolation(sat, clightSat, -1);
144    float nlight;
145    if(light <= 1){
146      nlight = 1 + (nlight1 - 1) * nlightsat;
147    } else {
148      nlight = nlight1;
149    }
150    float b1 = light / nlight;
151    //float sat1 = sat + (1-sat) * (nlight - 1 )/2; //yellow, saturation is greater
152    float sat1 = sat + (1-sat) * sat * (nlight1 - 1 ); //yellow, saturation is greater
153    float satLight = 1.0f;
154    if(b1 > 1){
155      //if the brightness of HSB system is >1 yet, decrease the saturation to force that brigthness
156      //float satCorr = sat1 * (light - nlight) / (2 - nlight);
157      //sat1 = sat1 - satCorr;
158      float satCorr = (light - nlight) / (2 - nlight);
159      satLight = 1.0f - satCorr;
160      b1 = 1;
161    }
162    int rgb = java.awt.Color.HSBtoRGB(hue1, satLight, b1);
163    float[] rgb1 = new float[3];
164    float rd = (rgb>>16) & 0xff;
165    float gn = (rgb>>8) & 0xff;
166    float bl = rgb & 0xff;
167    float hi = rd, lo = rd;
168    if(gn > hi){ hi = gn; }
169    if(bl > hi){ hi = bl; }
170    if(gn < lo){ lo = gn; }
171    if(bl < lo){ lo = bl; }
172    if(lo > 0){ //light color
173      float lightValue = (5 * hi + lo)/6;
174      lo = lightValue - sat1 * (lightValue - lo);  //between lightValue (sat = 0) and lo (sat = 1) 
175      rd = lightValue + sat1*(rd - lightValue);
176      gn = lightValue + sat1*(gn - lightValue);
177      bl = lightValue + sat1*(bl - lightValue);
178    } else { //dark color
179      //lo = 0, given sat < 1 increased lo
180      rd = hi - sat1 * (hi - rd); 
181      gn = hi - sat1 * (hi - gn); 
182      bl = hi - sat1 * (hi - bl); 
183    }
184    rgb = (((int)(rd + 0.5f)) << 16) + (((int)(gn + 0.5f)) << 8) +((int)(bl + 0.5f)); 
185    return rgb;
186  }
187  
188  
189  public static void HSBtoHLS(float hue, float sat, float brightness, float[] hls) {
190    hls[0] = hue;
191    float nlight1 = CurveInterpolation.linearInterpolation(hue, clight, -1);
192    float nlightsat = CurveInterpolation.splineInterpolation(sat, clightSat, -1);
193    float nlight;
194    if(brightness <= 1/nlight1) {
195      nlight = 1 + (nlight1 - 1) * nlightsat;
196    } else {
197      nlight = nlight1;
198    }
199    float light = brightness * nlight; 
200    float s1 = brightness * (1-sat);  //part of saturation which does not increase the light.
201    float s2 = (sat +  s1);     //increast the satuaration by the part which is add to the light. 1.0 if all is add to light.
202    hls[1] = light + (2 - light) * s1;
203    //float s2 = (1 - brightness) * sat;
204    //hls[2] = 1- ((1 - sat) - s1);  //same:
205    hls[2] = s2;
206  }
207  
208  
209
210  public static void RGBtoHLS(int rgb, float[] hls) {
211    float[] hsb = new float[3];
212    java.awt.Color.RGBtoHSB((rgb>>16)&0xff, (rgb>>8)&0xff, (rgb)&0xff, hsb);
213    float hue = 24*hsb[0] +4; 
214    if(hue >=24){ hue -=24; }
215    HSBtoHLS(hue, hsb[1], hsb[2], hls);
216    float light = ligthFromRGB(rgb);
217    hls[1] = light;
218    float sat = satFromRGB(rgb);
219    hls[2] = sat;
220  }
221  
222  
223  
224  static void XXXRGBtoHSL(int rgb, float[] hsl){
225    if(rgb == 0xF273FF)
226      Debugutil.stop();
227    float rd = (rgb>>16) & 0xff;
228    float gn = (rgb>>8) & 0xff;
229    float bl = rgb & 0xff;
230    
231    
232    float lval = Math.min(rd, Math.min(gn, bl));
233    float hval = Math.max(rd, Math.max(gn, bl));
234    float mid;
235    hsl[0] = RGBtoHue(rgb);
236    if(hval == 255) {
237      hsl[1] = 1.0f; //white or paster color is not gray.
238    } else if(hval == lval) {
239      hsl[1] = 0; //gray
240    } else {
241      hsl[1] = (float)(hval - lval) / hval;
242    }
243    hsl[2] = RGBtoligth(rd, gn, bl, hsl[1]); 
244  }
245  
246
247  
248  public static float satFromRGB(int rgb){
249    int rd = (rgb>>16) & 0xff;
250    int gn = (rgb>>8) & 0xff;
251    int bl = rgb & 0xff;
252    float ret;
253    int lighti;
254    int hi, mi, lo;
255    if(rd >= gn && rd >= bl){
256      hi = rd;
257      if(gn > bl){ mi = gn; lo = bl; }
258      else { mi = bl; lo = gn; }
259    } else if( gn >= rd && gn >= bl){
260      hi = gn;
261      if(rd > bl){ mi = rd; lo = bl; }
262      else { mi = bl; lo = rd; }
263    } else {
264      hi = bl;
265      if(rd > gn){ mi = rd; lo = gn; }
266      else { mi = gn; lo = rd; }
267    }
268    int add = 255 - hi;
269    if(add > lo){ add = lo; }
270    ret = hi > lo ? ((float)(hi - mi))/(hi - lo) : 0;
271    ////
272    if(lo == 255 || hi == 0) {
273      ret = 1.0f;
274    }
275    else if(255-hi < lo){
276      ret = (float)(hi - lo) / (255 - lo);  //colorvalue 0xff contained: sat = 1.0
277    } else { // if(hi > 0){
278      ret = (float)(hi-lo) / hi;  //same value like HSB-satuartion.
279    }
280    return ret;
281  }
282  
283  
284  
285  public static float ligthFromRGB(int rgb){
286    int rd = (rgb>>16) & 0xff;
287    int gn = (rgb>>8) & 0xff;
288    int bl = rgb & 0xff;
289    float ret;
290    int lighti;
291    int hi, mi, lo;
292    if(rd >= gn && rd >= bl){
293      hi = rd;
294      if(gn > bl){ mi = gn; lo = bl; }
295      else { mi = bl; lo = gn; }
296    } else if( gn >= rd && gn >= bl){
297      hi = gn;
298      if(rd > bl){ mi = rd; lo = bl; }
299      else { mi = bl; lo = rd; }
300    } else {
301      hi = bl;
302      if(rd > gn){ mi = rd; lo = gn; }
303      else { mi = gn; lo = rd; }
304    }
305    float ff = hi == 0 ? 1: ((float)hi) / (hi + 0.4f*mi + 0.2f*lo );
306    ////
307    float rd1 = CurveInterpolation.linearInterpolation(rd, clightVal, -1);
308    float gn1 = CurveInterpolation.linearInterpolation(gn, clightVal, -1);
309    float bl1 = CurveInterpolation.linearInterpolation(bl, clightVal, -1);
310    //return (0.55f * rd + gn + 0.26f * bl) /255  *ff;
311    return (rd + (1 + 0.4f * (gn-0.6f*rd)/hi) * gn + (1 - 0.4f * (bl-0.5f*gn)/hi) * bl) /255 *ff;
312  }
313  
314  
315  
316  
317  static float bfrd = 1.0f;
318  static float bfgn = 1.1f;
319  static float bfbl = 0.9f;
320  
321  static float cfrd = 1/0.7f;  //1.8f;
322  //static float cfye = 1.0f;
323  static float cfgn = 1/0.8f; //1.5f;
324  //static float cfcy = 1.0f;
325  static float cfbl = 1/0.6f; //2.2f;
326  //static float cfma = 1.3f;
327  
328  /**Factors for rd, ye, gn, cy, bl, ma */
329  static float[] cfrgb = { 1.0f, 1.2f, 0.8f}; //1/0.6f, 1/0.8f, 1/0.5f};
330  //static float[] cfrgb = { 1/0.6f, 1.0f, 1/0.8f, 1.0f, 1/0.5f, 1/0.8f};
331  
332
333  static float RGBtoHue(int rgb) {
334    float hue;
335    int rd = (rgb>>16) & 0xff;
336    int gn = (rgb>>8) & 0xff;
337    int bl = rgb & 0xff;
338    
339    
340    int lval = Math.min(rd, Math.min(gn, bl));
341    int hval = Math.max(rd, Math.max(gn, bl));
342    int mid;
343    if(hval == lval) { //gray
344      hue = 0;
345      mid = lval;
346    }
347    else if(hval == rd) {
348      if(lval == gn) { //bl is more significant
349        hue = 4 - ((float)(bl-lval) / (rd - lval) * 4 *cfbl / cfrd);
350        mid = bl;
351      } else {
352        hue = 4 + ((float)(gn-lval) / (rd - lval) * 4 *cfgn / cfrd);
353        mid = gn;
354      }
355    } else if(hval == gn) {
356      if(lval == bl) { //rd is more significant
357        hue = 12 - ((float)(rd-lval) / (gn - lval) * 4 * cfrd/ cfgn);
358        mid = rd;
359      } else { //bl is more significant
360        hue = 12 + ((float)(bl-lval) / (gn - lval) * 4 * cfbl / cfgn);
361        mid = bl;
362      }
363    } else { //bl 
364      if(lval == rd) { //gn is more significant
365        hue = 20 - ((float)(gn-lval) / (bl - lval) * 4 * cfgn / cfbl);
366        mid = gn;
367      } else {
368        hue = 20 + ((float)(rd-lval) / (bl - lval) * 4 * cfrd / cfbl);
369        mid = rd;
370      }
371    }
372    return hue;
373  }
374  
375  
376    static float RGBtoligth(float rd, float gn, float bl, float sat){
377    //++++++++++++++
378    //++++++++++++++++ ////
379    //+++
380    float rd1 = bfrd * rd;
381    float gn1 = bfgn * gn;
382    float bl1 = bfbl * bl;
383    //float rd1 =  rd;
384    //float gn1 =  gn;
385    //float bl1 =  bl;
386    
387    float lval = Math.min(rd1, Math.min(gn1, bl1));
388    float hval = Math.max(rd1, Math.max(gn1, bl1));
389    float mid;
390    if(hval == rd1 && lval == bl1) mid = gn1;
391    else if(hval == rd1 && lval == gn1) mid = bl1;
392    else if(hval == gn1 && lval == bl1) mid = rd1;
393    else if(hval == gn1 && lval == rd1) mid = bl1;
394    else if(hval == bl1 && lval == rd1) mid = gn1;
395    else mid = rd1;
396    
397    //float f = hval == 0 ? 1 : (0.2f * lval/hval + 0.2f * mid/hval + 1) / 1.4f; 
398    float fmid = 0.3f; //hval == 0 ? 1 : 1.0f - 0.8f * mid/hval;
399    float fl =  0.1f; //hval == 0 ? 1 : 1.0f - 0.8f * lval/hval;
400    //return (0.7f/255 * rd + 0.8f/255 * gn + 0.6f/255 * bl); // * (0.5f + 0.5f * sat);
401    //return (float)Math.sqrt(0.34f/255 * rd + 0.40f/255 * gn + 0.27f/255 * bl);
402    //float light1 = 0.33f/255 * rd + 0.45f/255 * gn + 0.22f/255 * bl; 
403    float light1 = (hval + fmid * mid + fl * lval) /255; 
404    return  light1 / 1.46f; //  *f;
405  }
406  
407  
408
409  
410
411
412
413  public static String htmlhls(float h, int l, int s) {
414    int color =  HLStoRGB(h, l/100.0f, s/100.0f) & 0xffffff;
415    String ret = String.format("#%06X", color);
416    return ret;
417  }
418  
419  public static String htmlhlb(float h, int l, int s) {
420    float hue1 = (h-4) / 24;
421    if(hue1 < 0 ){ hue1 += 1.0f; }
422    int color =  java.awt.Color.HSBtoRGB(hue1, s/100.0f, l/100.0f) & 0xffffff;
423    String ret = String.format("#%06X", color);
424    return ret;
425  }
426  
427  
428}