    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}