如何在PIL.ImageFont中使用我自己的位图字体? [英] How to use my own bitmap font in PIL.ImageFont?

查看:61
本文介绍了如何在PIL.ImageFont中使用我自己的位图字体?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个位图字体,基本上是一个256x256 png图像,其中每个字符占用8x8瓦片.我想将其与Pillow一起用作ImageFont,但Pillow文档中对此没有任何信息.它说我可以加载这样的位图字体

  font = ImageFont.load("arial.pil") 

但是"PIL使用其自己的字体文件格式来存储位图字体."所以我想png文件将无法正常工作.如何告诉PIL使用上述位图以及每个字符在何处?

解决方案

答案不是一个完整的答案,但是对于评论来说太多了,它可能会有用或促使其他人解决另外60%的问题:-)

如果其他人提出更好的建议,我可以将其删除...

您可以转到

顺便说一句,如果要将其分成10x20大小的块,每个块一个字母,则可以在终端机中使用 ImageMagick ,如下所示:

 转换10x20.pbm -crop 10x20 char_%d.png 

,您将获得一堆名为 char_0.png char_1.png 等的文件.前4个如下:


如果您查看 src/PIL/FontFile.py ,则此代码似乎知道如何访问/生成字体指标:

 ##Python影像库#$ Id $##光栅字体文件解析器的基类## 历史:#1997-06-05 fl创建#1997-08-19 fl限制图像宽度##Secret Labs AB版权所有(c)1997-1998#Fredrik Lundh版权所有(c)1997-1998##有关使用和重新分配的信息,请参阅README文件.#从__future__导入print_function导入操作系统从 .导入图片,_binary宽度= 800def puti16(fp,values):#写入网络顺序(大端)16位序列对于v in值:如果v<0:v + = 65536fp.write(_binary.o16be(v))###光栅字体文件处理程序的基类.类FontFile(object):位图=无def __init __():self.info = {}self.glyph = [无] * 256def __getitem __(self,ix):返回self.glyph [ix]def编译(自己):创建指标和位图"如果self.bitmap:返回#创建足够大的位图以容纳所有数据h = w =最大宽度= 0行数= 1对于自身的字形:如果字形:d,dst,src,im =字形h = max(h,src [3]-src [1])w = w +(src [2]-src [0])如果w>宽度:行+ = 1w =(src [2]-src [0])最大宽度=最大(最大宽度,w)xsize =最大宽度ysize =线* h如果xsize == 0和ysize == 0:返回 ""self.ysize = h#将字形粘贴到位图中self.bitmap = Image.new("1",(xsize,ysize))self.metrics = [无] * 256x = y = 0对于我在范围(256)中:字形=自我[i]如果字形:d,dst,src,im =字形xx = src [2]-src [0]#yy = src [3]-src [1]x0,y0 = x,yx = x + xx如果x>宽度:x,y = 0,y + hx0,y0 = x,yx = xxs = src [0] + x0,src [1] + y0,src [2] + x0,src [3] + y0self.bitmap.paste(im.crop(src),s)self.metrics [i] = d,dst,sdef保存(自己,文件名):保存字体"self.compile()#字体数据self.bitmap.save(os.path.splitext(filename)[0] +".pbm","PNG")#字体指标使用open(os.path.splitext(filename)[0] +".pil","wb")作为fp:fp.write(b"PILfont \ n")fp.write((";;;;;;%d; \ n"%self.ysize).encode('ascii'))#H !!!fp.write(b"DATA \ n")对于范围内的ID(256):m = self.metrics [id]如果不是m:puti16(fp,[0] * 10)别的:puti16(fp,m [0] + m [1] + m [2]) 


因此,希望有人有时间/知道如何将这两者放在一起,以使您能够为PNG生成度量标准文件.我认为您只需要为PNG执行该代码的最后10行的代码即可.

似乎有23个字节的标头可以简单地复制,然后有256个条目" ,即256个字形中的每一个为1个.每个条目中都有10个数字,每个数字都是16位大字节序.

让我们看一下标题:

  dd if = 10x20.pil bs = 23 count = 1 |xxd -c23 |更多的00000000:5049 4c66 6f6e 740a 3b3b 3b3b 3b3b 3230 3b0a 4441 5441 0a PILfont.;;;;; 20; .DATA. 

然后,您可以使用以下命令查看条目,以跳过标题并很好地分组:

  dd if = 10x20.pil bs = 23 iseek = 1 |xxd -g2 -c20 

给出:

第1列似乎是字形的宽度.

第7列是图像中字形左边缘的x偏移,第9列是图像中字形右边缘的x偏移.因此,您会看到每行的第7列与前一行的第9列相同,即字形在图像上彼此邻接.

如果从文件的更下方查看此摘录,则可以看到该摘录在摘录中间的输出图像中开始显示新的字形行(标记为红色).这告诉我们位图的宽度不应超过800像素,第8列是位图文件中字形顶部的y偏移,第10列是位图中字形底部的y偏移..您应该看到,当在位图文件中开始一行新的字形行时,x变为零,第8列采用第10列中的前一个值.

I created a bitmap font, basically a 256x256 png image where each character occupies 8x8 tile. I want to use it with Pillow as ImageFont but there's no info on this in Pillow docs. It says I can load bitmap fonts like this

font = ImageFont.load("arial.pil")

but "PIL uses its own font file format to store bitmap fonts." so I guess png file won't work. How can I tell PIL to use said bitmap and where each character is on it?

解决方案

Not a complete answer, but too much for a comment, and it may be useful or spur someone else to work out the other 60% :-)

I may delete it if anyone else comes up with something better...

You can go to the Pillow repository on Github and download a ZIP file of the code.

If you go in there and nose around you will find two things that appear to work hand-in-hand, namely a .PIL file and a .PBM file.


In Tests/fonts there is a file called 10x20.pbm which is actually a PNG file if you look inside it. So, if you change its name to 10x20.png you can view it and it looks like this:

By the way, if you want to split that into 10x20 size chunks with one letter in each, you can use ImageMagick in Terminal like this:

convert 10x20.pbm -crop 10x20 char_%d.png

and you will get a bunch of files called char_0.png, char_1.png etc. The first 4 look like this:


If you look in src/PIL/FontFile.py there is this code that seems to know how to access/generate the metrics for a font:

#
# The Python Imaging Library
# $Id$
#
# base class for raster font file parsers
#
# history:
# 1997-06-05 fl   created
# 1997-08-19 fl   restrict image width
#
# Copyright (c) 1997-1998 by Secret Labs AB
# Copyright (c) 1997-1998 by Fredrik Lundh
#
# See the README file for information on usage and redistribution.
#

from __future__ import print_function

import os
from . import Image, _binary

WIDTH = 800


def puti16(fp, values):
    # write network order (big-endian) 16-bit sequence
    for v in values:
        if v < 0:
            v += 65536
        fp.write(_binary.o16be(v))


##
# Base class for raster font file handlers.

class FontFile(object):

    bitmap = None

    def __init__(self):

        self.info = {}
        self.glyph = [None] * 256

    def __getitem__(self, ix):
        return self.glyph[ix]

    def compile(self):
        "Create metrics and bitmap"

        if self.bitmap:
            return

        # create bitmap large enough to hold all data
        h = w = maxwidth = 0
        lines = 1
        for glyph in self:
            if glyph:
                d, dst, src, im = glyph
                h = max(h, src[3] - src[1])
                w = w + (src[2] - src[0])
                if w > WIDTH:
                    lines += 1
                    w = (src[2] - src[0])
                maxwidth = max(maxwidth, w)

        xsize = maxwidth
        ysize = lines * h

        if xsize == 0 and ysize == 0:
            return ""

        self.ysize = h

        # paste glyphs into bitmap
        self.bitmap = Image.new("1", (xsize, ysize))
        self.metrics = [None] * 256
        x = y = 0
        for i in range(256):
            glyph = self[i]
            if glyph:
                d, dst, src, im = glyph
                xx = src[2] - src[0]
                # yy = src[3] - src[1]
                x0, y0 = x, y
                x = x + xx
                if x > WIDTH:
                    x, y = 0, y + h
                    x0, y0 = x, y
                    x = xx
                s = src[0] + x0, src[1] + y0, src[2] + x0, src[3] + y0
                self.bitmap.paste(im.crop(src), s)
                self.metrics[i] = d, dst, s

    def save(self, filename):
        "Save font"

        self.compile()

        # font data
        self.bitmap.save(os.path.splitext(filename)[0] + ".pbm", "PNG")

        # font metrics
        with open(os.path.splitext(filename)[0] + ".pil", "wb") as fp:
            fp.write(b"PILfont\n")
            fp.write((";;;;;;%d;\n" % self.ysize).encode('ascii'))  # HACK!!!
            fp.write(b"DATA\n")
            for id in range(256):
                m = self.metrics[id]
                if not m:
                    puti16(fp, [0] * 10)
                else:
                    puti16(fp, m[0] + m[1] + m[2])


So hopefully someone has time/knowledge of how to put those two together to enable you to generate the metrics file for your PNG. I think you just need something that does the last 10 lines of that code for your PNG.

There appear to be 23 bytes of header which you can simply replicate, and then there are 256 "entries", i.e. 1 for each of 256 glyphs. Each entry has 10 numbers in it, and each number is 16-bit big endian.

Let's look at the header:

dd if=10x20.pil bs=23 count=1| xxd -c23 | more
00000000: 5049 4c66 6f6e 740a 3b3b 3b3b 3b3b 3230 3b0a 4441 5441 0a  PILfont.;;;;;;20;.DATA.

Then you can see the entries using the command below to skip the header and group nicely:

dd if=10x20.pil bs=23 iseek=1| xxd -g2 -c20

which gives:

Column 1 appears to be the width of the glyph.

Column 7 is the x-offset of the left edge of the glyph in the image and column 9 is the x-offset of the right edge of the glyph in the image. So you will see that column 7 on each line is the same as column 9 on the previous line, i.e. that the glyphs abutt each other going across the image.

If you look at this extract from further down the file, you can see it starts a new row of glyphs in the output image in the middle of the extract (marked in red). That tells us that the bitmap should be no more than 800 pixels wide and that column 8 is the y-offset of the top of the glyph in the bitmap file and column 10 is the y-offset of the bottom of the glyph in the bitmap. You should see that when a new line row of glyphs starts in the bitmap file that x goes to zero and column 8 takes the previous value from column 10.

这篇关于如何在PIL.ImageFont中使用我自己的位图字体?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆