TOP > カテゴリ > HTML5・JavaScript >

カラーパレットのソート、整列[検証]

ペイント系アプリや画像ファイルで使用される256色のカラーパレットをソート、整列する方法を検証してみました。検証方法はRGB、HSL色空間と色相、彩度、明度のソートによる整列です。

ネットで探しても全く記事が見つかりませんでしたので試しました。

原パレット

検証対象となる256色のカラーパレットです。パレットの色は先頭から「基本16色」「Web216色」で残りは「黒色」となります。

次のJavascriptのコードは検証用です。初期値は「原パレット」を生成します。色空間によるソートの検証をする場合はwindow.onload()イベントの部分を後述するコードに変更します。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="PaletteArea"></div>
<script>   
var palette = new Array();

// Web216色 + 基本16色 + 黒 
var src_palette =["#000000","#ffffff","#c0c0c0","#808080","#800000","#ff0000","#800080","#ff00ff","#008000","#00ff00","#808000","#ffff00","#000080","#0000ff","#008080","#00ffff",

                  "#000000","#000033","#000066","#000099","#0000cc","#0000ff","#330000","#330033","#330066","#330099","#3300cc","#3300ff","#660000","#660033","#660066","#660099",
                  "#6600cc","#6600ff","#990000","#990033","#990066","#990099","#9900cc","#9900ff","#cc0000","#cc0033","#cc0066","#cc0099","#cc00cc","#cc00ff","#ff0000","#ff0033",
                  "#ff0066","#ff0099","#ff00cc","#ff00ff","#003300","#003333","#003366","#003399","#0033cc","#0033ff","#333300","#333333","#333366","#333399","#3333cc","#3333ff",
                  "#663300","#663333","#663366","#663399","#6633cc","#6633ff","#993300","#993333","#993366","#993399","#9933cc","#9933ff","#cc3300","#cc3333","#cc3366","#cc3399",
                  "#cc33cc","#cc33ff","#ff3300","#ff3333","#ff3366","#ff3399","#ff33cc","#ff33ff","#006600","#006633","#006666","#006699","#0066cc","#0066ff","#336600","#336633",
                  "#336666","#336699","#3366cc","#3366ff","#666600","#666633","#666666","#666699","#6666cc","#6666ff","#996600","#996633","#996666","#996699","#9966cc","#9966ff",
                  "#cc6600","#cc6633","#cc6666","#cc6699","#cc66cc","#cc66ff","#ff6600","#ff6633","#ff6666","#ff6699","#ff66cc","#ff66ff","#009900","#009933","#009966","#009999",
                  "#0099cc","#0099ff","#339900","#339933","#339966","#339999","#3399cc","#3399ff","#669900","#669933","#669966","#669999","#6699cc","#6699ff","#999900","#999933",
                  "#999966","#999999","#9999cc","#9999ff","#cc9900","#cc9933","#cc9966","#cc9999","#cc99cc","#cc99ff","#ff9900","#ff9933","#ff9966","#ff9999","#ff99cc","#ff99ff",
                  "#00cc00","#00cc33","#00cc66","#00cc99","#00cccc","#00ccff","#33cc00","#33cc33","#33cc66","#33cc99","#33cccc","#33ccff","#66cc00","#66cc33","#66cc66","#66cc99",
                  "#66cccc","#66ccff","#99cc00","#99cc33","#99cc66","#99cc99","#99cccc","#99ccff","#cccc00","#cccc33","#cccc66","#cccc99","#cccccc","#ccccff","#ffcc00","#ffcc33",
                  "#ffcc66","#ffcc99","#ffcccc","#ffccff","#00ff00","#00ff33","#00ff66","#00ff99","#00ffcc","#00ffff","#33ff00","#33ff33","#33ff66","#33ff99","#33ffcc","#33ffff",
                  "#66ff00","#66ff33","#66ff66","#66ff99","#66ffcc","#66ffff","#99ff00","#99ff33","#99ff66","#99ff99","#99ffcc","#99ffff","#ccff00","#ccff33","#ccff66","#ccff99",
                  "#ccffcc","#ccffff","#ffff00","#ffff33","#ffff66","#ffff99","#ffffcc","#ffffff",
                  
                  "#000000","#000000","#000000","#000000","#000000","#000000","#000000","#000000","#000000","#000000","#000000","#000000","#000000","#000000","#000000","#000000",
                  "#000000","#000000","#000000","#000000","#000000","#000000","#000000","#000000"];

window.onload = function(){ 
  
  Original();
  
  craetePaletteArea();
}  
 
// パレットエリアの作成
function craetePaletteArea() {
  var html  = '<table> ';
  
  for (var i = 0; i < 16; i++) {
    html += '<tr>';         
      for (var j = 0;j < 16; j++) {                  
        html += '<td>';
          html += '<div style="width:14px;height:14px;">' ;
            html += '<div';
              html += ' style="width:12px;height:12px;background-color:';
            
              html += palette[(i*16)+j] + ';"';
              
            html += '></div>';
          html +='</div>';
        html += '</td>';                
      }
    html += '</tr>';
  }
  html += '</table>';
  document.getElementById('PaletteArea').innerHTML = html;      
} 

// RGB色空間からHSL色空間へ変換する 
//  r(red)  : 赤色 0-255の値
//  g(green): 緑色 0-255の値
//  b(blue) : 青色 0-255の値 
function rgb2hsl(r, g, b){   
 var max = Math.max(r, g, b);
 var min = Math.min(r, g, b);   
 var hsl = {'h':0,
            's':0,
            'l':(max + min) / 2}; // L(明度)   
 
 if (max != min) {
   // H(色相)  
   if (max == r) hsl.h = 60 * (g - b) / (max-min);
   if (max == g) hsl.h = 60 * (b - r) / (max-min) + 120;
   if (max == b) hsl.h = 60 * (r - g) / (max-min) + 240;
   
   // S(彩度)
   if (hsl.l <= 127){
     hsl.s = (max - min) / (max + min);
   }else{
     hsl.s = (max - min) / (510 - max - min);
   }
 }   

 if (hsl.h < 0){
   hsl.h = hsl.h + 360;
 }
 
 hsl.h =  Math.round(hsl.h);
 hsl.s =  Math.round(hsl.s * 100);
 hsl.l =  Math.round((hsl.l / 255) * 100);     
 return hsl;   
}
 
// backgroundColorからRGB値を取得して配列で返す
function Color2RGB(backgroundcolor) {  
  
  // [IE/Chrome/FireFox] rgb(255,255,255)の文字列形式からRGBを取得する 
  var result = backgroundcolor.replace("rgb(","");
  result = result.replace(")","");
  result = result.replace(/ /g,"");
  result = result.split(",");
  
  // [Opera] #ffffff の文字列形式からRGBを取得する 
  var buffer; 
  if (result[0][0] == '#'){
    buffer = new Array();
    buffer[0] = parseInt(result[0].slice(1,3),16);
    buffer[1] = parseInt(result[0].slice(3,5),16);
    buffer[2] = parseInt(result[0].slice(5,7),16);
    result = buffer;
  }
  
  result[0] = parseInt(result[0],10);
  result[1] = parseInt(result[1],10);
  result[2] = parseInt(result[2],10);
  
  return {'r':result[0],'g':result[1],'b':result[2]}; 
} 

// 原パレット
function Original(){
  for (var i = 0; i < src_palette.length; i++) {
    palette[i] = src_palette[i];
  } 
}
 
// RGBのソート
function rgbSort(){
  
  src_palette.sort(function(a,b){
    var a_rgb = Color2RGB(a);
    var b_rgb = Color2RGB(b);          
    
    if(a_rgb.r < b_rgb.r) return  1;
    if(a_rgb.r > b_rgb.r) return -1;
    if(a_rgb.g < b_rgb.g) return  1;
    if(a_rgb.g > b_rgb.g) return -1;
    if(a_rgb.b < b_rgb.b) return  1;
    if(a_rgb.b > b_rgb.b) return -1;  
    
    return 0;        
    
  });  
        
  for (var i = 0; i < src_palette.length; i++) {
    palette[i] = src_palette[i];
  } 
}
 
// HSLによるソート
function hslSort(){  
  var rgb,hsl;      
  var hsl_palette = new Array();
  
  for (var i = 0; i < src_palette.length; i++) {
    rgb = Color2RGB(src_palette[i]);
    hsl = rgb2hsl(rgb.r,rgb.g,rgb.b); 
    hsl_palette[hsl_palette.length] = {'h':hsl.h,
                                       's':hsl.s,
                                       'l':hsl.l,
                                       'rgb':src_palette[i]};
  } 
  
  hsl_palette.sort(function(a,b){
  
    if(a.h < b.h) return  1;
    if(a.h > b.h) return -1; 
    if(a.s < b.s) return  1;
    if(a.s > b.s) return -1;     
    if(a.l < b.l) return  1;
    if(a.l > b.l) return -1;     

    return 0;            
     
  });
  
  for (var i = 0; i < hsl_palette.length; i++) {
    palette[i] = hsl_palette[i].rgb;
  } 
}

// HSLのHによるソート
function hsl_h_Sort(){  
  var rgb,hsl;      
  var hsl_palette = new Array();
  
  for (var i = 0; i < src_palette.length; i++) {
    rgb = Color2RGB(src_palette[i]);
    hsl = rgb2hsl(rgb.r,rgb.g,rgb.b); 
    hsl_palette[hsl_palette.length] = {'h':hsl.h,
                                       's':hsl.s,
                                       'l':hsl.l,
                                       'rgb':src_palette[i]};
  } 
  
  hsl_palette.sort(function(a,b){
  
    if(a.h < b.h) return  1;
    if(a.h > b.h) return -1; 
    
    return 0;       
          
  });
  
  for (var i = 0; i < hsl_palette.length; i++) {
    palette[i] = hsl_palette[i].rgb;
  } 
}

// HSLのSによるソート
function hsl_s_Sort(){  
  var rgb,hsl;      
  var hsl_palette = new Array();
  
  for (var i = 0; i < src_palette.length; i++) {
    rgb = Color2RGB(src_palette[i]);
    hsl = rgb2hsl(rgb.r,rgb.g,rgb.b); 
    hsl_palette[hsl_palette.length] = {'h':hsl.h,
                                       's':hsl.s,
                                       'l':hsl.l,
                                       'rgb':src_palette[i]};
  } 
  
  hsl_palette.sort(function(a,b){
  
    if(a.s < b.s) return  1;
    if(a.s > b.s) return -1; 
    
    return 0;             
    
  });
  
  for (var i = 0; i < hsl_palette.length; i++) {
    palette[i] = hsl_palette[i].rgb;
  } 
}

// HSLのLによるソート
function hsl_l_Sort(){  
  var rgb,hsl;      
  var hsl_palette = new Array();
  
  for (var i = 0; i < src_palette.length; i++) {
    rgb = Color2RGB(src_palette[i]);
    hsl = rgb2hsl(rgb.r,rgb.g,rgb.b); 
    hsl_palette[hsl_palette.length] = {'h':hsl.h,
                                       's':hsl.s,
                                       'l':hsl.l,
                                       'rgb':src_palette[i]};
  } 
  
  hsl_palette.sort(function(a,b){
  
    if(a.l < b.l) return  1;
    if(a.l > b.l) return -1; 
    
    return 0;        
         
  });
  
  for (var i = 0; i < hsl_palette.length; i++) {
    palette[i] = hsl_palette[i].rgb;
  } 
}
</script>     
</body>
</html> 

RGB

RGBの各値を降順でソートした結果です。

window.onload = function(){ 
  
  rgbSort();
  
  craetePaletteArea();
}  

HSL

HSLの各値を降順でソートした結果です。

window.onload = function(){ 
  
  hslSort();
  
  craetePaletteArea();
}  

色相

HSLの色相のみを降順でソートした結果です。

window.onload = function(){ 
  
  hsl_h_Sort();
  
  craetePaletteArea();
}  

彩度

HSLの彩度のみを降順でソートした結果です。

window.onload = function(){ 
  
  hsl_s_Sort();
  
  craetePaletteArea();
}  

明度

HSLの明度のみを降順でソートした結果です。

window.onload = function(){ 
  
  hsl_l_Sort();
  
  craetePaletteArea();
}  

検証結果

カラーパレットをRGB、HSV色空間でソートすると数値上は近い数字に並び替えは可能です。しかし、人間の目でみて納得する綺麗なグラデーションにはならない。

但し、グレースケールなど別のパレットを使用すると効果があるかも知れないです。

HSVはHSLとほとんど同じなので検証からはずしました。また、これとは別にLAB色空間でも試しましたが作業時間オーバーで断念しました。LABは画像の近似画像の検出などに重宝すると思います。

パレットを人間の目でみて綺麗に整列させるロジックは考えるだけで面白そうですので、また時間ができたら試したいと思います。

LAB色空間に関する外部リンク

RGBをLab色空間の座標に変換する





掲示板

ソフトウェア、ハードウェアのプログラミング用の掲示板を作成しました。質問やわからない事は@掲示板でユーザー同士で情報を共有して下さい。

関連記事



公開日:2016年02月25日 最終更新日:2016年03月01日
記事NO:01798