簡體   English   中英

用PIL剪切字體

[英]fonts clipping with PIL

此圖像是使用PIL創建的。 看看這張圖片中的g和y是如何被截斷的? 我怎么能阻止這個?

http://img109.imageshack.us/img109/8874/screenshotep.png

創建此圖像的代碼非常簡單(縮寫):

import Image, ImageDraw, ImageFont

im = Image.new("RGBA", (200, 200), 'white')
draw = ImageDraw.Draw(im)

font = ImageFont.truetype("VeraSe.ttf", 12)

draw.text(
           (1, 1),
           " %s: " % "ggjyfFwe__",
           font=font,
           fill='black'
)

draw.text(
           (1, 30),
           " %s" % 15,
           font=font,
           fill='black'
)

im.show()

我嘗試使用幾種不同的字體,它總是被剪裁。 令人驚訝; y,googleing“PIL字體剪輯”返回很少有用的命中...我在Ubuntu 9.10上使用python 2.6.4和PIL 1.1.6

對於這個較老的問題,這是一個遲到的答案。

問題似乎是PIL和Pillow將剪切渲染文本的邊緣。 這通常顯示在尾隨的寬字符和下行部分(如'y')。 這也可以出現在某些字體的頂部。 這已成為至少十年的問題 無論調用text()的圖像大小如何,都會發生這種情況。 沖突似乎選擇邊界矩形為“font.size * number_chars”而不是“我實際需要渲染的任何東西”,這發生在堆棧的深處( _imagingft.c )。 修復此問題會導致其他問題,例如排列逐字母呈現的文本。

一些解決方案包括

  • 在字符串末尾附加一個空格。 im.text(xy, my_text + ' ', ...)
  • 對於高度問題,獲取文本的寬度( font.getsize() ),第二次渲染文本加上一個好的上升和下降,將渲染的文本切割為第一個報告的寬度和第二個實際高度。
  • 使用不同的庫,如AggDrawpyvips

這在各種問題中被引用, 使用PIL剪切字體PIL剪切字母頂部, 在Python中正確渲染具有給定字體的文本並准確地檢測其邊界 這些問題引用了相同的基本問題,但並不重復

我無法使用到目前為止提到的方法解決某些字體的問題,所以我最終使用aggdraw作為PIL文本繪制方法的透明替代品。

你的代碼被重寫為aggdraw看起來像:

import Image
import aggdraw

im = Image.new("RGBA", (200, 200), 'white')
draw = aggdraw.Draw(im)

# note that the color is specified in the font constructor in aggdraw
font = aggdraw.Font((0,0,0), "VeraSe.ttf", size=12, opacity=255)

draw.text((1, 1), " %s: " % "ggjyfFwe__", font) # no color here
draw.text((1, 30), " %s" % 15, font)

draw.flush() # don't forget this to update the underlying PIL image!

im.show()

我的建議是,在創建圖像對象之前,獲取文本所需的大小。

這是使用font.getsize("text")文檔 )完成的。

在我制作的圖像生成腳本中,我首先通過調用font.getsize("Åj")的等值來font.getsize("Åj")一行文本的最大高度(如果你只需要US-ASCII,你可以找到"Aj"的高度"Aj"相反)。 然后我計算了所需的圖像高度和線偏移,包括邊距和行間距。

這是一個適合我的kludge。 它是gnud答案的變種。 (差異足以得到一個單獨的答案與評論我希望。)我測試了很多單詞的位置,這已經表現得一致。

在未完全達到字體的完整高度的情況下繪制文本時,可能會發生剪切。 正如gnud所說,通過使用諸如“Aj”(我使用“Fj”)之類的字符,你可以避免這個錯誤。

每當放置一個單詞時:

1)用你想要的單詞做draw.textsize(text,font = font)。 存儲高度/寬度。

2)將'Fj'(spaceFJ)添加到單詞的末尾,並重做文本大小並存儲第三個高度/寬度。

4)您將使用第2項中的單詞(最后帶有'Fj')進行實際文本繪制。 使用此附錄將保持字體不被剪裁。

4)在進行實際文本繪制之前,裁剪'Fj'將要着陸的圖像(需要crop.load()以避免延遲復制)。 然后繪制文本,然后將裁剪后的圖像移回'Fj'。

這個過程避免了剪輯,似乎具有合理的性能,並產生完整的,未剪輯的文本。 下面是我用於此的Python代碼部分的復制/粘貼。 部分示例,但希望它增加了一些見解。

    # note: xpos & ypos were previous set = coordinates for text draw 
    #       the hard-coded addition of 4 to c_x likely will vary by font
    #       (I only use one font in this process, so kludged it.)
    width, height = draw.textsize(word, font=font)
    word2 = word + ' Fj'
    width2, height2 = draw.textsize(word2, font=font)
    # crop to overwrite ' Fj' with previous image bits
    c_w = width2 - width
    c_h = height2
    c_x = xpos + width + 4
    c_y = ypos
    box = (c_x, c_y, c_x + c_w, c_y + c_h)
    region = img.crop(box)
    region.load()
    draw.text((xpos, ypos), word2, (0,0,0), font=font)
    img.paste(region, box)

使用Ubuntu 11.10,2012年仍然存在“bug”。 字體大小11,12,13和15完全剪切下划線。

#!/usr/bin/env python
""" demonstrates clipping of descenders for certain font sizes """
import Image, ImageDraw, ImageFont
fontPath = "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans-Bold.ttf"
im = Image.new('L', (256, 256))
ys=15
for i in range(10,21):
    fh = ImageFont.truetype(fontPath, i)
    sometext="%dgt_}" % (i)
    ImageDraw.Draw(im).text((10, ys ),sometext , 254, fh)
    ys+=i+5
im.show()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM