Python 使用枕头绘制TrueType小大写文字
我正在使用枕头在图像上绘制文本:Python 使用枕头绘制TrueType小大写文字,python,python-imaging-library,Python,Python Imaging Library,我正在使用枕头在图像上绘制文本: from PIL import Image, ImageDraw, ImageFont im = Image.new("L", (400, 50), color="black") draw = ImageDraw.Draw(im) font = ImageFont.truetype("Roboto-Medium.ttf", 28) draw.text((0, 0), "How To Get Small Caps?", font=font, fill="whit
from PIL import Image, ImageDraw, ImageFont
im = Image.new("L", (400, 50), color="black")
draw = ImageDraw.Draw(im)
font = ImageFont.truetype("Roboto-Medium.ttf", 28)
draw.text((0, 0), "How To Get Small Caps?", font=font, fill="white")
im.save('small_caps.png')
但是我不知道如何用小写字母而不是普通字符来绘制字符串。最新版本的Roboto Medium确实包含按大小绘制的小写字母,但它们没有映射到Unicode码点。这意味着在简单字符串中指定字符的常规方法将无法工作 OpenType感知软件可以通过OpenType功能访问字形
c2sc
(用大写字母替换其等效的小写字母)和smcp
(其功能相同,但仅适用于小写字母)。这些翻译表位于TrueTypeGSUB
表中的字体内,它们以一种特别不规则的格式编码。这可能就是为什么PIL程序员从不费心去实现它(以及其他可能有用的OpenType特性,如每种语言的超级和订阅、紧排和本地化字母形式)
Python模块freetype
可以访问原始图示符。但是,类似地,FreeType开发人员也曾短暂考虑过将OpenType功能解析添加到他们的库中,但最终决定不这样做,并且FreeType只关注绘图。尽管如此,您仍然可以使用freetype
获取并光栅化所有字体中的任何字形。唯一的问题是,您将对glyph索引进行硬编码
“字形索引”只不过是“什么编码值对应于哪个图像”,从0开始,一直到最后一个字形。字体的可能编码位于字体数据的其他位置;它可能包含确定的Windows编码(ol的“代码页”东西——但更大)、完整的Unicode编码、MacRoman和少量其他编码。您只需选择一种编码并告诉您需要该编码中的字符代码,freetype
将为您查找正确的字形
但是OpenType特性可以推翻这一点。这是一组独立的翻译,由您选择的功能(以及脚本,甚至是语言)驱动。一个完全支持OpenType的界面将看到您的glyph,使用所需的特性提高赌注,并返回原始glyph索引
由于单个字体文件中可能有许多原始字形,因此并非每个编码都指向字体中的每个字形。例如,想象一下可怜的老麦克罗曼,他只有256个可能的字符。你不可能用这个来处理所有机器人的1294个铭文。就Unicode而言,即使有成千上万个已定义的条目,Unicode也无法解决所有这些问题,因为可以为某些字符(如花式大写字母)创建与原始字符相同的样式替代,以及用作连字的字符组合,其中一个完整的序列,如Zapfino
被绘制为一个复杂的字形(该字形为“Zapfino”;非常棒)
一些字体设计师允许通过“私有”Unicode代码点(意思是“每个人都可以自由定义”)访问特殊字符,但我认为Roboto没有这个功能
您可以向FreeType索取完整的GSUB
表格,然后对其进行解析,以找到适合小写字母的翻译,如果您这样做,您将很高兴发现您的代码可以使用任何真正大写字母的字体(!),但这是一项巨大的工作
所以我作弊了。一些软件允许每个字形检查字体,我使用Adobe InDesign查找所有大写字母A..Z
的字形索引
不过,这确实有一个缺点。它只能(可靠地)在Roboto Medium的一个特定版本中工作,因为设计者可以为每个新版本随意添加、删除和移动标志符号。请记住,这对其他软件处理字体的方式没有任何影响!编码表和OpenType表被调整为匹配,因此软件不需要知道任何关于每个字体字形索引的信息。也不能保证这些相同的索引将与Roboto系列中的其他字体一起使用。设计师可能使用了完全相同的布局,但可能没有。实际上,如上所述,他们甚至不必关心它 我已下载最新版本2.137;2017; 如果你没有,先下载吧 下面是一些示例代码,用于按顺序打印所有小写标志符号的灰度值,以及它们相对于标志符号起点的水平偏移(左偏移)和从基线测量的垂直高度(以像素为单位)。随意调整以匹配PIL自己的文本绘制程序;可能要花些功夫才能把它做好™. (对于这个相当基本的代码示例,我深表歉意。我成功地将Python2.7和3的PIL安装搞砸了。(有些东西),因此我无法以图形方式显示一些东西;幸运的是,
freetype
模块仍然工作。)
如果你没有一个小大写版本的字体,这将是理想的,你似乎可以简单地改变所有的字母大写,并使用一个稍微小一点的字体大小来绘制它们-没有任何内置的,这样做很好。请注意,如果做我在前面的评论中建议的,每封信都需要单独处理。您可以使用Pillow的方法来确定下一个字符的放置位置,以查看每个字符占用的空间。Jonathan,仅供参考:我已经使用一个OpenType解析器创建了一个解析器,我在过去一直在使用该解析器–嗯,month@usr2564301这将非常有用。我设法从您的代码片段中获得了所需的内容(并检查了glyphs)。然而,令人惊讶的是,没有一个Python库来解析这一点。
import freetype
import os.path
smcapGlyphs = [563,562,561,560,552,486,485,484,483,482,481,480,479,
478,477,476,475,474,473,472,471,470,469,468,467,466]
def dump_bytes(buf,wide,high):
for y in range(high):
for x in range(wide):
print ('%02x ' % buf[y*wide+x], end='')
print ()
face = freetype.Face(os.path.expanduser('~')+"/Library/Fonts/Roboto-Medium.ttf")
face.set_char_size( 48*64 )
for index,i in enumerate(smcapGlyphs):
face.load_glyph(i)
print (chr(65+index))
bitmap = face.glyph.bitmap
width = face.glyph.bitmap.width
rows = face.glyph.bitmap.rows
pitch = face.glyph.bitmap.pitch
print (face.glyph.bitmap_left)
print (face.glyph.bitmap_top)
dump_bytes (bitmap.buffer, pitch,rows)
print ()