最新消息: USBMI致力于为网友们分享Windows、安卓、IOS等主流手机系统相关的资讯以及评测、同时提供相关教程、应用、软件下载等服务。

bdfbold.pl中有趣的字体加粗算法

IT圈 admin 57浏览 0评论

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进制表示。

发布评论

评论列表 (0)

  1. 暂无评论