vim中将色彩转换为终端下色彩的算法的选择

2011年8月01日 19:24

 

看了 依云的文章, 让 Vim 在终端下和 GVIM 一样漂亮:gui2term.py 更新至 3.0 版
决定给自己的vim色彩插件加上终端支持。

colorscheme生成约50个色彩

ColorV的调色板生成约125个色彩

每个色彩需要对比255-16个终端颜色。

最后发现算法 delta_e_cie2000  实在太复杂,vim运行太费时间,要30+s。

而编译成delta.so,用vim的libcall()调用,

gcc  -c -fpic  -o delta.o delta.c
gcc -shared -lc  -o delta.so  delta.o

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
/* should declare function if it's not int; */
double degrees();
double radians();

int delta2000(char p_str[100])
{
    char ca[80],cb[80];
    sscanf(p_str,"%6s:%6s",ca,cb);
    hex2lab(ca);
    hex2lab(cb);
    float L1,a1,b1,L2,a2,b2,delta_E;
    sscanf(ca,"%f:%f:%f",&L1,&a1,&b1);
    sscanf(cb,"%f:%f:%f",&L2,&a2,&b2);

  int Kl = 1;int Kc = 1;int Kh = 1;
    
    float avg_Lp,C1,C2,avg_C1_C2,G,a1p,a2p,C1p,C2p,avg_C1p_C2p;
    float h1p,h2p,avg_Hp,T,diff_h2p_h1p,delta_hp,delta_Lp,delta_Cp,delta_Hp;
    float S_L,S_C,S_H,delta_ro,R_C,R_T;

  avg_Lp = (L1 + L2) / 2.0;
  C1 = sqrt(pow(a1, 2) + pow(b1, 2));
  C2 = sqrt(pow(a2, 2) + pow(b2, 2));
  avg_C1_C2 = (C1 + C2) / 2.0;

  G = 0.5 * (1 - sqrt(pow(avg_C1_C2 , 7.0) / (pow(avg_C1_C2, 7.0) + pow(25.0, 7.0))));

  a1p = (1.0 + G) * a1;
  a2p = (1.0 + G) * a2;
  C1p = sqrt(pow(a1p, 2) + pow(b1, 2));
  C2p = sqrt(pow(a2p, 2) + pow(b2, 2));
  avg_C1p_C2p =(C1p + C2p) / 2.0;
    
  if (degrees(atan2(b1,a1p)) >= 0)
    h1p = degrees(atan2(b1,a1p));
  else
    h1p = degrees(atan2(b1,a1p)) + 360;
    
  if (degrees(atan2(b2,a2p)) >= 0)
    h2p = degrees(atan2(b2,a2p));
  else
    h2p = degrees(atan2(b2,a2p)) + 360;

  if (abs(h1p - h2p) > 180)
    avg_Hp = (h1p + h2p + 360) / 2.0;
  else
    avg_Hp = (h1p + h2p) / 2.0;

  T = 1 - 0.17 * cos(radians(avg_Hp - 30)) + 0.24 * cos(radians(2 * avg_Hp)) + 0.32 * cos(radians(3 * avg_Hp + 6)) - 0.2  * cos(radians(4 * avg_Hp - 63));

  diff_h2p_h1p = h2p - h1p;
  if (abs(diff_h2p_h1p) <= 180)
    delta_hp = diff_h2p_h1p;
  else if ((abs(diff_h2p_h1p) > 180) && (h2p <= h1p))
    delta_hp = diff_h2p_h1p + 360;
  else
    delta_hp = diff_h2p_h1p - 360;

  delta_Lp = L2 - L1;
  delta_Cp = C2p - C1p;
  delta_Hp = 2 * sqrt(C2p * C1p) * sin(radians(delta_hp) / 2.0);

  S_L = 1 + ((0.015 * pow(avg_Lp - 50, 2)) / sqrt(20 + pow(avg_Lp - 50, 2.0)));
  S_C = 1 + 0.045 * avg_C1p_C2p;
  S_H = 1 + 0.015 * avg_C1p_C2p * T;

  delta_ro = 30 * exp(-(pow(((avg_Hp - 275) / 25), 2.0)));
  R_C = sqrt((pow(avg_C1p_C2p, 7.0)) / (pow(avg_C1p_C2p, 7.0) + pow(25.0, 7.0)));
  R_T = -2 * R_C * sin(2 * radians(delta_ro));

  delta_E = sqrt(pow(delta_Lp /(S_L * Kl), 2) + pow(delta_Cp /(S_C * Kc), 2) + pow(delta_Hp /(S_H * Kh), 2) + R_T * (delta_Cp /(S_C * Kc)) * (delta_Hp / (S_H * Kh)));
    sprintf(p_str,"%f",delta_E);
    return p_str;
}
double degrees(double radian)
{
    double degree ;
    degree = radian * 180 / 3.1415926 ;
    return degree;
}
double radians(double degree)
{
    double radian ;
    radian = degree / 180 * 3.1415926 ;
    return radian;
}
int hex2lab(char *hex)
{

    int ri,gi,bi;
    sscanf(hex,"%2x%2x%2x",&ri,&gi,&bi);
    double r,g,b;
    r=(double)ri/255.0,g=(double)gi/255.0,b=(double)bi/255.0;
    if (r>0.04045) {
        r = pow(((r + 0.055) / 1.055) , 2.4);
    } else {
        r = r / 12.92;
    }

    if (g>0.04045) {
        g = pow(((g + 0.055) / 1.055) , 2.4);
    } else{
        g = g / 12.92;
    }

    if (b>0.04045) {
        b = pow(((b + 0.055) / 1.055) , 2.4);
    } else {
        b = b / 12.92;
    }
    r=r*100,g=g*100,b=b*100;
    double X,Y,Z;
    X = r * 0.4124 + g * 0.3576 + b * 0.1805;
    Y = r * 0.2126 + g * 0.7152 + b * 0.0722;
    Z = r * 0.0193 + g * 0.1192 + b * 0.9505;

    X = X/95.047;
    Y = Y/100.000;
    Z = Z/108.883;

    if (X > 0.008856)
       X = pow(X ,(0.3333333));
    else
       X = (7.787 * X) + (16 / 116);
    if (Y > 0.008856)
       Y = pow(Y ,(0.3333333));
    else
       Y = (7.787 * Y) + (16 / 116);
    if (Z > 0.008856)
       Z = pow(Z ,(0.3333333));
    else
       Z = (7.787 * Z) + (16 / 116);

    double L,a;
    L = (116 * Y) - 16;
    a = 500 * (X - Y);
    b = 200 * (Y - Z);
    sprintf(hex,"%f:%f:%f",L,a,b);
    return 0;
}

不得不吐槽一下,vim的libcall不但功能很弱,只能传递一个参数,其速度也非常坑人。

要消耗20+s,只比用vim本身运行略好。

用py_delta_2000()的速度不错,只需要3秒。

之后用 delta_e_cie76 速度差别不大。

然后改成hsv之差的绝对值,不过默认scheme的转换效果不好,而且速度仍要20+s。

最后还是决定用最简单的算法,直接用rgb之差的绝对值。

d=abs(r1-r2)+abs(b1-b2)+abs(g1-g2)

效果还算不错。

py_delta_rgb()只需要1秒左右

best_match = 0
smallest_distance = 10000000

hex1 = vim.eval("hex1")
r1,g1,b1 = int(hex1[0:2],16),int(hex1[2:4],16),int(hex1[4:6],16)
for c in range(16, 256):
    hex2 = termcolor[c]
    r2,g2,b2 = int(hex2[1:3],16),int(hex2[3:5],16),int(hex2[5:7],16)
    d = abs(r1-r2)+abs(g1-g2)+abs(b1-b2)
    if d < smallest_distance:
        smallest_distance = d
        best_match = c

vim.command("let best_match = "+str(best_match))

vi_delta_rgb()需要3秒。

    let best_match=0
    let smallest_distance = 100000000
    let hex1=a:hex
    let [r1,g1,b1] = ["0x".hex1[0:1],"0x".hex1[2:3],"0x".hex1[4:5]]
    for c in range(16,255)
    	let hex2=s:fmt_hex(s:tmclr_dict[c])
        let [r2,g2,b2] = ["0x".hex2[0:1],"0x".hex2[2:3],"0x".hex2[4:5]]
        let d = abs(r1-r2)+abs(g1-g2)+abs(b1-b2)
    	if d < smallest_distance
    	    let smallest_distance = d
    	    let best_match = c
        endif
    endfor
    return best_match

不过最后一想,还是自己的问题。

毕竟别人的脚本是生成文件,我的目的是动态生成色彩,要求不一样,算法当然不同。

 

下图为各算法生成色彩与gvim调色板的对比

这个scheme是仿照butterscream.vim的配色生成的。

不过配色生成插件还没完成。

 

Tags: vim
评论(2) 阅读(4436)

编译 vim7.3 ( Winows and Linux)

2011年8月01日 17:40

最近将windows和ubuntu以及Archlinux下的vim都重新在本地编译并安装为最新版本, 因为vim.org提供的版本往往版本滞后而且没有编译需要的特性,必须自行编译。 将安装过程记录下来,以资参考。

Windows

  • 原版问题:
1. 缺少python3 等所需特性。
2. 没有字体渲染
3. 没有等宽字体支持
  • 配置环境:
1. 安装 MSYS-cn ,这个比MinGW更为方便
2. 下载并安装Lua/Python/Perl/Ruby等所需程序
  • 下载源码:
hg clone https://vim.googlecode.com/hg/ vim 如果已下载,只需 hg pull
  • 添加字体渲染,修改src/gui_w32.c
diff -r 6768ebd0bc04 -r 213b33df021a src/gui_w32.c
--- a/src/gui_w32.c     Sun Aug 08 16:38:42 2010 +0200
+++ b/src/gui_w32.c     Sat Sep 18 10:37:41 2010 +0800
@@ -2298,7 +2298,11 @@
     /* On NT, tell the font renderer not to "help" us with Hebrew and Arabic
      * text.  This doesn't work in 9x, so we have to deal with it manually on
      * those systems. */
-    if (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT)
+    if (
+#ifdef FEAT_RIGHTLEFT
+            curwin->w_p_rl &&
+#endif
+    os_version.dwPlatformId == VER_PLATFORM_WIN32_NT)
        foptions |= ETO_IGNORELANGUAGE;
  • 添加非等宽字体支持,修改src/os_mswin.c
diff -r 96b2b1cca7cd src/os_mswin.c
--- a/src/os_mswin.c    Mon Aug 23 12:55:47 2010 +0800
+++ b/src/os_mswin.c    Mon Aug 23 13:05:17 2010 +0800
@@ -3288,8 +3288,11 @@

 #ifndef FEAT_PROPORTIONAL_FONTS
     /* Ignore non-monospace fonts without further ado */
+    /*
+     * hzmangel: I need non-monospace fonts!
     if ((ntm->tmPitchAndFamily & 1) != 0)
        return 1;
+    */
 #endif

     /* Remember this LOGFONT as a "possible" */
  • 编译
注意:需要修改python/ruby等路径为本机安装位置 在MSYS-cn 下, c: , d: 盘符为 /c , /d
    cd vim/src  
    
    make -f Make_ming.mak \
    PYTHON=/d/python27 PYTHON_VER=27 \
    PYTHON3=/d/python31 PYTHON3_VER=31 \
    RUBY=/d/Ruby192 RUBY_VER=19 RUBY_VER_LONG=1.9.1 \
    gvim.exe
    
    make -f Make_ming.mak \
    PYTHON=/d/python27 PYTHON_VER=27 \
    PYTHON3=/d/python31 PYTHON3_VER=31 \
    RUBY=/d/Ruby192 RUBY_VER=19 RUBY_VER_LONG=1.9.1 \
    GUI=no vim.exe
  • 安装
最后将编译生成的exe文件拷贝到'$VIM/vimfile'文件夹就可以了。
vim的script文件都在源码包的runtime文件夹里, 可以将其复制到'$VIM/vimfile'文件夹
  • 使用
win下我是使用文泉驿微米黑
set gfw=Wenquanyi_Micro_Hei_Mono:h13:cANSI

Ubuntu

# install dependency
sudo apt-get install grep curl ctags cscope
sudo apt-get install libncurses5-dev libgnome2-dev libgnomeui-dev \
  libgtk2.0-dev libatk1.0-dev libbonoboui2-dev \
  libcairo2-dev libx11-dev libxpm-dev libxt-dev
sudo apt-get install python python-dev python3 python3-dev python2.7 python2.7-dev


sudo apt-get install ruby ruby-dev
# download src code or use 'hg pull' to update only
hg clone https://vim.googlecode.com/hg/ vim

cd vim/src

# use ./configure --help to see features
./configure --enable-multibyte --with-features=huge --enable-gui=gnome2 \
  --enable-python3interp=yes --enable-rubyinterp --enable-pythoninterp=yes \
  --enable-tclinterp  --enable-fontset  \
  
sudo make && sudo make install

Arch Linux

  • 官方源问题:
1. 其python的默认链接为python3
2. 好几个版本官方源里vim编译时的python2链接的gtk库存在问题,
  • 安装过程
# install +ruby +lua feature dependency. 
sudo pacman -S ruby lua

# download src code or use 'hg pull' to update only
hg clone https://vim.googlecode.com/hg/ vim

cd vim/src

# fix python name
sed -i -e 's|vi_cv_path_python, python)|vi_cv_path_python, python2)|' \
    configure.in
 
# use ./configure --help to see features
./configure --prefix=/usr \
    --enable-multibyte --with-features=huge --enable-gui=gtk2 \
    --enable-python3interp=yes --enable-rubyinterp \
    --enable-pythoninterp=yes  --enable-luainterp\
    --enable-tclinterp  --enable-fontset --enable-netbeans \
    
sudo make && sudo make install

Update:2012-04-17 整理注释。

Update:2012-03-16 整理并增加Archlinux部分。

Update:2012-04-01 整理Windows部分。

Tags: vim compile font
评论(3) 阅读(6291)