2023年12月2日发(作者:朱绮烟)
昨天说到bdf这种字体表示方式和一个加粗脚本,本文对其做了进一步分析。。。[@more@]
bdf文件解构:
--------------------
文件描述
包括字体名称/大小/
字数/编码等信息
--------------------
单个的字体点阵信息
STARTCHAR - ENDCHAR
.....
--------------------
例如:
1、terminus的6x12点阵字(常规)
//字体头部描述文
STARTFONT 2.1
COMMENT ter-u12n
FONT -xos4-Terminus-Medium-R-Normal--12-120-72-72-C-60-ISO10646-1
SIZE 12 72 72
FONTBOUNDINGBOX 6 12 0 -2
STARTPROPERTIES 19
FOUNDRY "xos4"
FAMILY_NAME "Terminus"
WEIGHT_NAME "Medium"
SLANT "R"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
PIXEL_SIZE 12
POINT_SIZE 120
RESOLUTION_X 72
RESOLUTION_Y 72
SPACING "C"
AVERAGE_WIDTH 60
CHARSET_REGISTRY "ISO10646"
CHARSET_ENCODING "1"
MIN_SPACE 0
FONT_ASCENT 10
FONT_DESCENT 2
DEFAULT_CHAR 65533
COPYRIGHT "Copyright (C) 2005 Dimitar Toshkov Zhekov"
ENDPROPERTIES
CHARS 603
....
//字体“A”点阵描述单元 STARTCHAR A
ENCODING 65
SWIDTH 500 0
DWIDTH 6 0
BBX 6 12 0 -2 //字体点阵大小6为宽12为高,见下面贴图中红框框
BITMAP
00 //字体第1行 00:为16进制 表示成2进制为:00000000
00 //字体第2行 00:为16进制 表示成2进制为:00000000
70 //字体第3行 70:为16进制 表示成2进制为:01110000
88 //字体第4行 88:为16进制 表示成2进制为:10001000
88 //字体第5行 88:为16进制 表示成2进制为:10001000
88 //字体第6行 88:为16进制 表示成2进制为:10001000
F8 //字体第7行 F8:为16进制 表示成2进制为:11111000
88 //字体第8行 88:为16进制 表示成2进制为:10001000
88 //字体第9行 88:为16进制 表示成2进制为:10001000
88 //字体第10行 88:为16进制 表示成2进制为:10001000
00 //字体第11行 00:为16进制 表示成2进制为:00000000
00 //字体第12行 00:为16进制 表示成2进制为:00000000
ENDCHAR
^
看出来了没?这里刚好组成一个向左对齐的大写的A字。
是的,BITMAP后面的16进制中用2进制表示话,1表示一个点/0表示空白,通过点和空白表示的就是一个点阵字。
2、terminus的6x12点阵字(粗体,由从上文转换)
//字体头部描述文
STARTFONT 2.1
COMMENT ter-u12n
FONT -xos4-Terminus-Bold-R-Normal--12-120-72-72-C-60-ISO10646-1
SIZE 12 72 72
FONTBOUNDINGBOX 7 12 0 -2
STARTPROPERTIES 19
FOUNDRY "xos4"
FAMILY_NAME "Terminus"
WEIGHT_NAME "Bold"
SLANT "R"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
PIXEL_SIZE 12
POINT_SIZE 120
RESOLUTION_X 72
RESOLUTION_Y 72
SPACING "C"
AVERAGE_WIDTH 60
CHARSET_REGISTRY "ISO10646"
CHARSET_ENCODING "1"
MIN_SPACE 0
FONT_ASCENT 10
FONT_DESCENT 2
DEFAULT_CHAR 65533
COPYRIGHT "Copyright (C) 2005 Dimitar Toshkov Zhekov"
ENDPROPERTIES
CHARS 603
....
//字体粗体“A”点阵描述单元
STARTCHAR A
ENCODING 65
SWIDTH 583 0
DWIDTH 7 0
BBX 7 12 0 -2 //字体点阵大小7为宽12为高,见下面贴图中红框框
BITMAP
00 //字体第1行 00:为16进制 表示成2进制为:00000000
00 //字体第2行 00:为16进制 表示成2进制为:00000000
78 //字体第3行 00:为16进制 表示成2进制为:01111000
CC //字体第4行 00:为16进制 表示成2进制为:11001100
CC //字体第5行 00:为16进制 表示成2进制为:11001100
CC //字体第6行 00:为16进制 表示成2进制为:11001100
FC //字体第7行 00:为16进制 表示成2进制为:11111100
CC //字体第8行 00:为16进制 表示成2进制为:11001100
CC //字体第9行 00:为16进制 表示成2进制为:11001100
CC //字体第10行 00:为16进制 表示成2进制为:11001100
00 //字体第11行 00:为16进制 表示成2进制为:00000000
00 //字体第12行 00:为16进制 表示成2进制为:00000000
ENDCHAR
^
跟上面比较这个是不是一个左对齐大写的粗体A字?
两个字体的xmbdfed中的表示,贴图:
下面来分析一下这个脚本到底做了什么
#!/usr/bin/perl -w
#
# Convert bdf fonts to bold style.
# Copyright (C) 1994-95 Cronyx Ltd.
# Author: Serge Vakulenko,
# Changes Copyright (C) 1995-1997 by Andrey A. Chernov, Moscow, Russia.
# # This software may be used, modified, copied, distributed, and sold,
# in both source and binary form provided that the above copyright
# and these terms are retained. Under no circumstances is the author
# responsible for the proper functioning of this software, nor does
# the author assume any responsibility for damages incurred with its use.
#
# Changes (C) 2000 by Serge Winitzki: speeded up algorithm by 2x.
#
# 下面这几个hash标量是用来做16进制到2进制表示转换的
# 从16进制到2进制
$pattern{"0"} = "0000";
$pattern{"1"} = "0001";
$pattern{"2"} = "0010";
$pattern{"3"} = "0011";
$pattern{"4"} = "0100";
$pattern{"5"} = "0101";
$pattern{"6"} = "0110";
$pattern{"7"} = "0111";
$pattern{"8"} = "1000";
$pattern{"9"} = "1001";
$pattern{"a"} = "1010"; $pattern{"A"} = "1010";
$pattern{"b"} = "1011"; $pattern{"B"} = "1011";
$pattern{"c"} = "1100"; $pattern{"C"} = "1100";
$pattern{"d"} = "1101"; $pattern{"D"} = "1101";
$pattern{"e"} = "1110"; $pattern{"E"} = "1110";
$pattern{"f"} = "1111"; $pattern{"F"} = "1111";
$pattern{"n"} = ""; $pattern{"r"} = "";
# 从2进制到16进制
$hexdig{"0000"} = "0";
$hexdig{"0001"} = "1";
$hexdig{"0010"} = "2";
$hexdig{"0011"} = "3";
$hexdig{"0100"} = "4";
$hexdig{"0101"} = "5";
$hexdig{"0110"} = "6";
$hexdig{"0111"} = "7";
$hexdig{"1000"} = "8";
$hexdig{"1001"} = "9";
$hexdig{"1010"} = "A";
$hexdig{"1011"} = "B";
$hexdig{"1100"} = "C";
$hexdig{"1101"} = "D";
$hexdig{"1110"} = "E"; $hexdig{"1111"} = "F";
$swidth = $dwidth = -1;
# 首先处理字体头部描述文
while () {
if (/^WEIGHT_NAMEs/) {
s/"Medium"/"Bold"/; # 将字体描述从Medium替换为Bold说明该字体是粗体
print;
} elsif (/^FONTs/) {
s/-Medium-/-Bold-/; # 同上
print;
} elsif (/^FONTBOUNDINGBOXs/) {
@r = split;
$h = $r[2];
$w = $r[1] + 1; # 将字体点阵宽度加1,因为要对字体做加粗处理。 printf "FONTBOUNDINGBOX %d %d %d %dn", $w, $h, $r[3], $r[4];
} elsif (/^CHARSs/) {
print;
last;
} else {
print;
}
}
while () {
if (/^STARTCHARs/) {
print;
} elsif (/^ENDCHAR/) {
print;
} elsif (/^ENCODINGs/) {
print;
} elsif (/^SWIDTHs/) {
@r = split;
$swidth = $r[1];
} elsif (/^DWIDTHs/) {
@r = split;
$dwidth = $r[1];
} elsif (/^BBXs/) {
@r = split;
$h = $r[2];
$w = $r[1];
# 以下为对dwidth和swidth做处理???
}
print "ENDFONTn";
# 加粗处理函数
sub makechar {
for ($i=0; $i<$h; ++$i) { # 按行循环单行单行处理
$b = "";
foreach $c (split(//,)) { # 读当前列的一个16进制表示
}
$b .= "0" x 8; # 后面追加8个bit位,这里已经将$b .= $pattern{$c}; # 通过上面的转换表将16进制转换
}
$h = int (($dwidth * 1000 / $swidth) + 0.5)
if ($h == 0 && $dwidth >= 0 && $swidth >= 0);
if ($dwidth < 0);
$dwidth = $w
$dwidth++; # dwidth 加1
$w++; # 点阵宽度加1
printf "SWIDTH %d 0n", int (($dwidth * 1000 / $h) + 0.5);
printf "DWIDTH %d 0n", $dwidth;
$w = 0
$h = 0
if ($r[2] == 0);
printf "BBX %d %d %d %dn", $w, $h, $r[3], $r[4];
$swidth = $dwidth = -1;
print "BITMAPn";
&makechar; # 调用该函数做加粗处理
if ($r[1] == 0 && $r[2] == 0);
} elsif (/^BITMAP/) { # 对BITMAP段的字体点阵描述表进行加粗处理
成2进制
16进制的描
# 述位转换成了0/1的二进制表示了。
for ($n=$w-1; $n>=1; --$n) { # 按列从右到前进行处理
if (substr($b, $n-1, 2) eq "10") { # 如果发现当前位是0而前一位为1
# (0表示空白,1表示点,所以10
# 表示前一位有个点为了实现粗体
# 将该点的后一位也用点画出来。
# 比较上面的两个图)
substr($b, $n, 1) = "1"; # 将当前位变成点从而实现加粗效果。
}
# Now we are ready with the draft of current line.
}
for ($n = 0; $n<2*int(($w+7)/8); ++$n) { # 将已加粗的2进制表示
}
print "n";
print $hexdig{substr($b, $n*4, 4)};
}
}
从新转换成16进制表示。
2023年12月2日发(作者:朱绮烟)
昨天说到bdf这种字体表示方式和一个加粗脚本,本文对其做了进一步分析。。。[@more@]
bdf文件解构:
--------------------
文件描述
包括字体名称/大小/
字数/编码等信息
--------------------
单个的字体点阵信息
STARTCHAR - ENDCHAR
.....
--------------------
例如:
1、terminus的6x12点阵字(常规)
//字体头部描述文
STARTFONT 2.1
COMMENT ter-u12n
FONT -xos4-Terminus-Medium-R-Normal--12-120-72-72-C-60-ISO10646-1
SIZE 12 72 72
FONTBOUNDINGBOX 6 12 0 -2
STARTPROPERTIES 19
FOUNDRY "xos4"
FAMILY_NAME "Terminus"
WEIGHT_NAME "Medium"
SLANT "R"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
PIXEL_SIZE 12
POINT_SIZE 120
RESOLUTION_X 72
RESOLUTION_Y 72
SPACING "C"
AVERAGE_WIDTH 60
CHARSET_REGISTRY "ISO10646"
CHARSET_ENCODING "1"
MIN_SPACE 0
FONT_ASCENT 10
FONT_DESCENT 2
DEFAULT_CHAR 65533
COPYRIGHT "Copyright (C) 2005 Dimitar Toshkov Zhekov"
ENDPROPERTIES
CHARS 603
....
//字体“A”点阵描述单元 STARTCHAR A
ENCODING 65
SWIDTH 500 0
DWIDTH 6 0
BBX 6 12 0 -2 //字体点阵大小6为宽12为高,见下面贴图中红框框
BITMAP
00 //字体第1行 00:为16进制 表示成2进制为:00000000
00 //字体第2行 00:为16进制 表示成2进制为:00000000
70 //字体第3行 70:为16进制 表示成2进制为:01110000
88 //字体第4行 88:为16进制 表示成2进制为:10001000
88 //字体第5行 88:为16进制 表示成2进制为:10001000
88 //字体第6行 88:为16进制 表示成2进制为:10001000
F8 //字体第7行 F8:为16进制 表示成2进制为:11111000
88 //字体第8行 88:为16进制 表示成2进制为:10001000
88 //字体第9行 88:为16进制 表示成2进制为:10001000
88 //字体第10行 88:为16进制 表示成2进制为:10001000
00 //字体第11行 00:为16进制 表示成2进制为:00000000
00 //字体第12行 00:为16进制 表示成2进制为:00000000
ENDCHAR
^
看出来了没?这里刚好组成一个向左对齐的大写的A字。
是的,BITMAP后面的16进制中用2进制表示话,1表示一个点/0表示空白,通过点和空白表示的就是一个点阵字。
2、terminus的6x12点阵字(粗体,由从上文转换)
//字体头部描述文
STARTFONT 2.1
COMMENT ter-u12n
FONT -xos4-Terminus-Bold-R-Normal--12-120-72-72-C-60-ISO10646-1
SIZE 12 72 72
FONTBOUNDINGBOX 7 12 0 -2
STARTPROPERTIES 19
FOUNDRY "xos4"
FAMILY_NAME "Terminus"
WEIGHT_NAME "Bold"
SLANT "R"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
PIXEL_SIZE 12
POINT_SIZE 120
RESOLUTION_X 72
RESOLUTION_Y 72
SPACING "C"
AVERAGE_WIDTH 60
CHARSET_REGISTRY "ISO10646"
CHARSET_ENCODING "1"
MIN_SPACE 0
FONT_ASCENT 10
FONT_DESCENT 2
DEFAULT_CHAR 65533
COPYRIGHT "Copyright (C) 2005 Dimitar Toshkov Zhekov"
ENDPROPERTIES
CHARS 603
....
//字体粗体“A”点阵描述单元
STARTCHAR A
ENCODING 65
SWIDTH 583 0
DWIDTH 7 0
BBX 7 12 0 -2 //字体点阵大小7为宽12为高,见下面贴图中红框框
BITMAP
00 //字体第1行 00:为16进制 表示成2进制为:00000000
00 //字体第2行 00:为16进制 表示成2进制为:00000000
78 //字体第3行 00:为16进制 表示成2进制为:01111000
CC //字体第4行 00:为16进制 表示成2进制为:11001100
CC //字体第5行 00:为16进制 表示成2进制为:11001100
CC //字体第6行 00:为16进制 表示成2进制为:11001100
FC //字体第7行 00:为16进制 表示成2进制为:11111100
CC //字体第8行 00:为16进制 表示成2进制为:11001100
CC //字体第9行 00:为16进制 表示成2进制为:11001100
CC //字体第10行 00:为16进制 表示成2进制为:11001100
00 //字体第11行 00:为16进制 表示成2进制为:00000000
00 //字体第12行 00:为16进制 表示成2进制为:00000000
ENDCHAR
^
跟上面比较这个是不是一个左对齐大写的粗体A字?
两个字体的xmbdfed中的表示,贴图:
下面来分析一下这个脚本到底做了什么
#!/usr/bin/perl -w
#
# Convert bdf fonts to bold style.
# Copyright (C) 1994-95 Cronyx Ltd.
# Author: Serge Vakulenko,
# Changes Copyright (C) 1995-1997 by Andrey A. Chernov, Moscow, Russia.
# # This software may be used, modified, copied, distributed, and sold,
# in both source and binary form provided that the above copyright
# and these terms are retained. Under no circumstances is the author
# responsible for the proper functioning of this software, nor does
# the author assume any responsibility for damages incurred with its use.
#
# Changes (C) 2000 by Serge Winitzki: speeded up algorithm by 2x.
#
# 下面这几个hash标量是用来做16进制到2进制表示转换的
# 从16进制到2进制
$pattern{"0"} = "0000";
$pattern{"1"} = "0001";
$pattern{"2"} = "0010";
$pattern{"3"} = "0011";
$pattern{"4"} = "0100";
$pattern{"5"} = "0101";
$pattern{"6"} = "0110";
$pattern{"7"} = "0111";
$pattern{"8"} = "1000";
$pattern{"9"} = "1001";
$pattern{"a"} = "1010"; $pattern{"A"} = "1010";
$pattern{"b"} = "1011"; $pattern{"B"} = "1011";
$pattern{"c"} = "1100"; $pattern{"C"} = "1100";
$pattern{"d"} = "1101"; $pattern{"D"} = "1101";
$pattern{"e"} = "1110"; $pattern{"E"} = "1110";
$pattern{"f"} = "1111"; $pattern{"F"} = "1111";
$pattern{"n"} = ""; $pattern{"r"} = "";
# 从2进制到16进制
$hexdig{"0000"} = "0";
$hexdig{"0001"} = "1";
$hexdig{"0010"} = "2";
$hexdig{"0011"} = "3";
$hexdig{"0100"} = "4";
$hexdig{"0101"} = "5";
$hexdig{"0110"} = "6";
$hexdig{"0111"} = "7";
$hexdig{"1000"} = "8";
$hexdig{"1001"} = "9";
$hexdig{"1010"} = "A";
$hexdig{"1011"} = "B";
$hexdig{"1100"} = "C";
$hexdig{"1101"} = "D";
$hexdig{"1110"} = "E"; $hexdig{"1111"} = "F";
$swidth = $dwidth = -1;
# 首先处理字体头部描述文
while () {
if (/^WEIGHT_NAMEs/) {
s/"Medium"/"Bold"/; # 将字体描述从Medium替换为Bold说明该字体是粗体
print;
} elsif (/^FONTs/) {
s/-Medium-/-Bold-/; # 同上
print;
} elsif (/^FONTBOUNDINGBOXs/) {
@r = split;
$h = $r[2];
$w = $r[1] + 1; # 将字体点阵宽度加1,因为要对字体做加粗处理。 printf "FONTBOUNDINGBOX %d %d %d %dn", $w, $h, $r[3], $r[4];
} elsif (/^CHARSs/) {
print;
last;
} else {
print;
}
}
while () {
if (/^STARTCHARs/) {
print;
} elsif (/^ENDCHAR/) {
print;
} elsif (/^ENCODINGs/) {
print;
} elsif (/^SWIDTHs/) {
@r = split;
$swidth = $r[1];
} elsif (/^DWIDTHs/) {
@r = split;
$dwidth = $r[1];
} elsif (/^BBXs/) {
@r = split;
$h = $r[2];
$w = $r[1];
# 以下为对dwidth和swidth做处理???
}
print "ENDFONTn";
# 加粗处理函数
sub makechar {
for ($i=0; $i<$h; ++$i) { # 按行循环单行单行处理
$b = "";
foreach $c (split(//,)) { # 读当前列的一个16进制表示
}
$b .= "0" x 8; # 后面追加8个bit位,这里已经将$b .= $pattern{$c}; # 通过上面的转换表将16进制转换
}
$h = int (($dwidth * 1000 / $swidth) + 0.5)
if ($h == 0 && $dwidth >= 0 && $swidth >= 0);
if ($dwidth < 0);
$dwidth = $w
$dwidth++; # dwidth 加1
$w++; # 点阵宽度加1
printf "SWIDTH %d 0n", int (($dwidth * 1000 / $h) + 0.5);
printf "DWIDTH %d 0n", $dwidth;
$w = 0
$h = 0
if ($r[2] == 0);
printf "BBX %d %d %d %dn", $w, $h, $r[3], $r[4];
$swidth = $dwidth = -1;
print "BITMAPn";
&makechar; # 调用该函数做加粗处理
if ($r[1] == 0 && $r[2] == 0);
} elsif (/^BITMAP/) { # 对BITMAP段的字体点阵描述表进行加粗处理
成2进制
16进制的描
# 述位转换成了0/1的二进制表示了。
for ($n=$w-1; $n>=1; --$n) { # 按列从右到前进行处理
if (substr($b, $n-1, 2) eq "10") { # 如果发现当前位是0而前一位为1
# (0表示空白,1表示点,所以10
# 表示前一位有个点为了实现粗体
# 将该点的后一位也用点画出来。
# 比较上面的两个图)
substr($b, $n, 1) = "1"; # 将当前位变成点从而实现加粗效果。
}
# Now we are ready with the draft of current line.
}
for ($n = 0; $n<2*int(($w+7)/8); ++$n) { # 将已加粗的2进制表示
}
print "n";
print $hexdig{substr($b, $n*4, 4)};
}
}
从新转换成16进制表示。