单位正在组织人员用phpcms2008进行二次开发,建立门户网站。为了方便编辑人员制做头条新闻的大标题,做了一个文字转图片的功能,实现编辑人员在后台录入文字标题,发布首页后则按设定的参数自动生成图片大标题。
乙方人员很快就做出了该功能,但在使用中一直有问题。主要表现为一些汉字,如“日”字,在使用方正大黑简体时会出现文字间距严重不均匀的现象。乙方采取的补救措施是对我们在工作中发现的会导致异常的汉字,进行逐个特殊处理。但治标不治本,而且这种方法的成本也相当高。责成乙方分析问题根源,一直没有结果。
寻求解决:
在编辑人员的再三抱怨下,只好越俎代庖。首先了解一下同行,大部分地方报社和广电的门户网站,在这个问题上是手工制做标题图片,然后上传,包括宁波网也是这样,他们用的是北方网的后台。有个别网站用了自动生成的功能,也是PHP调用GD库实现的,他们也有在调用某些字体时有个别汉字偏移的现象,解决的方法是统一采用方正超粗黑。后来发现phpcms v9也提供了相应的功能,但是也有同样的bug,而且也可以通过使用方正超粗黑来规避。在网上找了一些示例代码,比较著名的有一个老外Stewart Rosenberger 和国内一位macleo的,macleo的代码还将汉字逐个输出,但是两位的代码都有上述的bug。
看来重视这个问题并加以解决的人不多。前阵子在一个年会上碰见钟胜辉,他已经离开了phpcms,现在做了一个新的产品cmstop,我在车上看了他的演示,功能很好。我讲了遇到的问题,用他的系统试一下,居然完全正常。回单位后以又发了一些文字和字体文件给他,他那边测试都正常。问一下他的实现思路,只说也是GD库,具体实现,是其他人在做。所以不好意思再多问。
于是利用周末在家的时间,将常出问题的汉字,使用方正大黑简体在word和photoshop中进行了详细的测试,又用GD库输出各字的宽度和占位,经过比对分析,发现了部分规律,并解决了文字偏移的问题,效果可以接受,但没有word的处理方案完美。解释如下:
GD库输出汉字基本策略分析:
1.每个汉字所占的版心(可用imagettfbbox()函数获得)不是完全相同的。
2.每个汉字所占的画布也不是完全相同的。观测结果为当版心小于某个值时,画布大小固定;当版心超出时,画布会扩充。但是在word中,各汉字所占宽度是相同的。
3.整串输出时,第一个汉字书写的起始点可以在magettftext()函数中指定,即版心的左下角,但第二个汉字的起始点目前不清楚。
4.整串输出时,imagettftext()书写时,汉字之间是否有间距,大小如何确定,是在版心之间计算还是在画布之间计算,目前不明。
5.单字输出时,每个字的左起座标都是-1。底线座标不确定,中点的横座标确定,纵座标不确定。但总体上,字的高度越小,顶线及中点纵座标越低,底线纵座标越高。
解决思路:
1.以常见字,如“点”字的版心宽度为基准,设为常量NormalWidth。
2.字符串进数组,为每个字符分配版心宽度。如果不是汉字,直接用imagettfbbox()函数获得。如果是汉字,获得后在返回值与NormalWidth之间取Max。
3.字符逐个输出,并校正各字版心的起始横座标,按居中(或留白左0.6右0.4)策略,纵座标保持不变。横座标递进量为上一个字符的宽度加上预设的间隔。在word中,不是居中,而是各个字不同,但视觉效果最佳。初步推测是GD库imagettfbbox()函数获得的汉字座标被整体平移过,字体中的部分座标信息丢失,导致每个字的左起座标都是-1,而word则取出了字体中各个汉字的横向偏移值,该值是与各个汉字一一对应的。
方正超粗黑与其他字体(如方正大黑简体 )的不同:
上面提到,一些系统可以用方正超粗黑来规避上述问题。原理是方正超粗黑输出的文字,一方面各个汉字的版心宽度差别很小,各字宽度相似,另一方面版心宽度绝对值较大,与各字所占画布的宽度差别较小。所以按相同的原始策略输出,使用方正超粗黑,看起来效果不错,但用方正大黑,因为各字的宽度差别明显,加上字宽与画布差别较大,所以效果就会难以接受。
附测试返回值:
$FontName = 'fzdhj.ttf';
$FontSize = 50;
$FontAngle = 0;
"中":
font_coordinate[0] = -1
font_coordinate[1] = 7
font_coordinate[2] = 52
font_coordinate[3] = 7
font_coordinate[4] = 52
font_coordinate[5] = -54
font_coordinate[6] = -1
font_coordinate[7] = -54
FontWidth = 53
FontHeight = 61
FontMiddleH = 25.5
FontMiddleV = -23.5
"日":
font_coordinate[0] = -1
font_coordinate[1] = 5
font_coordinate[2] = 39
font_coordinate[3] = 5
font_coordinate[4] = 39
font_coordinate[5] = -49
font_coordinate[6] = -1
font_coordinate[7] = -49
FontWidth = 40
FontHeight = 54
FontMiddleH = 19
FontMiddleV = -22
"皮":
font_coordinate[0] = -1
font_coordinate[1] = 8
font_coordinate[2] = 60
font_coordinate[3] = 8
font_coordinate[4] = 60
font_coordinate[5] = -55
font_coordinate[6] = -1
font_coordinate[7] = -55
FontWidth = 61
FontHeight = 63
FontMiddleH = 29.5
FontMiddleV = -23.5
"满":
font_coordinate[0] = -1
font_coordinate[1] = 7
font_coordinate[2] = 59
font_coordinate[3] = 7
font_coordinate[4] = 59
font_coordinate[5] = -55
font_coordinate[6] = -1
font_coordinate[7] = -55
FontWidth = 60
FontHeight = 62
FontMiddleH = 29
FontMiddleV = -24
// *************************************************************************************************************
// 只交流实现思路,不提供程序代码。而且这个代码也不复杂,最好自己动手试一下。
//**************************************************************************************************************
评论