Closed lp20010415 closed 1 month ago
Your code has a few bugs:
FT_LOAD_RENDER | FT_LOAD_TARGET_MONO
, nor check font.glyph.format
. Thus some glyphs have bitmap and return bitmap, some don't and just return garbage.set_char_size
and set_pixel_sizes
- the 2nd one takes effect.bitmap.pitch
.Here is the corrected code:
import freetype
font = freetype.Face(r"simsun.ttc")
# 绘制字符
font.set_pixel_sizes(19, 19)
font.load_char('1', freetype.FT_LOAD_RENDER | freetype.FT_LOAD_TARGET_MONO)
#font.load_char('字', freetype.FT_LOAD_RENDER | freetype.FT_LOAD_TARGET_MONO)
bitmap = font.glyph.bitmap
print(bitmap.rows, bitmap.width, bitmap.pitch)
assert(font.glyph.format == freetype.FT_GLYPH_FORMAT_BITMAP)
assert(font.glyph.bitmap.pixel_mode == freetype.FT_PIXEL_MODE_MONO)
print(bitmap.buffer)
print(len(bitmap.buffer))
left = []
right = []
for b, j in enumerate(bitmap.buffer):
b_res = list(format(j, "08b"))
for r in b_res:
if r == "1":
print("\033[1;30;46m \033[0m", end="")
else:
print("\033[1;30;40m \033[0m", end="")
if (b + 1) % bitmap.pitch == 0 and b > 0:
right.append(format(j, "02X"))
print()
else:
left.append(format(j, "02X"))
print(' '.join(left))
print(' '.join(right))
Your code also has the unfortunate problem of using pixel size 16. This particular font has some embedded bitmaps at size 12 to 17. Thus some glyph returns the embedded bitmap without needing FT_LOAD_RENDER
, some without embedded bitmp just return garbage. Anyway, it has multiple problems, and it would have save both you and me a lot of time if you start from one of the examples in the example directory... (most of them have FT_LOAD_RENDER, except those which draws outlines and obviously want the outlines returned rather than a rendered bitmap!).
I have put the code under https://github.com/rougier/freetype-py/blob/master/examples/user-code-from-issue-193.py
As for your question in #191, you can modify the 'load_chars' line in the example to do this (it just encode from utf-8 to gb18030 then decode it back... obviously you can decode directly if your input is in gb18030):
gb18030code='字'.encode('gb18030')
print(gb18030code) # b'\xd7\xd6' , as below
font.load_char(b'\xd7\xd6'.decode('gb18030'), freetype.FT_LOAD_RENDER | freetype.FT_LOAD_TARGET_MONO)
As for your question in #191, you can modify the 'load_chars' line in the example to do this (it just encode from utf-8 to gb18030 then decode it back... obviously you can decode directly if your input is in gb18030):
gb18030code='字'.encode('gb18030') print(gb18030code) # b'\xd7\xd6' , as below font.load_char(b'\xd7\xd6'.decode('gb18030'), freetype.FT_LOAD_RENDER | freetype.FT_LOAD_TARGET_MONO)
Oh,Jesus.I can't believe you also linked the issue with 191, thank you so much!
As for your question in #191, you can modify the 'load_chars' line in the example to do this (it just encode from utf-8 to gb18030 then decode it back... obviously you can decode directly if your input is in gb18030):
gb18030code='字'.encode('gb18030') print(gb18030code) # b'\xd7\xd6' , as below font.load_char(b'\xd7\xd6'.decode('gb18030'), freetype.FT_LOAD_RENDER | freetype.FT_LOAD_TARGET_MONO)
In the latest version, "freetype.FT_LOAD_TARGETS['FT_LOAD_TARGET_MONO']" is used.
freetype.FT_LOAD_TARGETS['FT_LOAD_TARGET_MONO']
is a bit confusing - that argument is a bit-field, so you set them by doing a | b | c | d
. Combo flags for commonly used flags are nice, but it hides the fact that it is a bit field. For example, you can disable usage of embedded bitmaps with FT_LOAD_NO_BITMAP | otherflags
to force it to ignore embedded bitmaps. In which case, any character (Chinese and ascii) in your original code would return a garbage bitmap at size 16, rather than just the ascii characters returning garbage.
freetype.FT_LOAD_TARGETS['FT_LOAD_TARGET_MONO']
有点令人困惑 - 该参数是一个位字段,因此您可以通过执行来设置它们a | b | c | d
。常用标志的组合标志很好,但它隐藏了它是一个位字段的事实。例如,您可以禁用嵌入位图的使用,以FT_LOAD_NO_BITMAP | otherflags
强制它忽略嵌入位图。在这种情况下,原始代码中的任何字符(中文和 ascii)都会返回大小为 16 的垃圾位图,而不仅仅是返回垃圾的 ascii 字符。
I use python 3.9
In my version, the correct way to writefreetype.FT_LOAD_RENDE
is freetype.FT_LOAD_FLAGS['FT_LOAD_RENDER']
, and the correct way to write freetype.FT_LOAD_TARGET_MONO
is freetype.FT_LOAD_TARGETS['FT_LOAD_TARGET_MONO']
.
However, only IDLE raises an error. In practice, you can still use freetype.FT_LOAD_RENDER
and freetype.FT_LOAD_TARGET_MONO
despite the error.
As for your question in #191, you can modify the 'load_chars' line in the example to do this (it just encode from utf-8 to gb18030 then decode it back... obviously you can decode directly if your input is in gb18030):
gb18030code='字'.encode('gb18030') print(gb18030code) # b'\xd7\xd6' , as below font.load_char(b'\xd7\xd6'.decode('gb18030'), freetype.FT_LOAD_RENDER | freetype.FT_LOAD_TARGET_MONO)
I have a question: how should I use Set_Charmap? This piece of code doesn't seem to work:
def control_size(res):
surplus = 16 - len(res) // 2
if surplus % 2 == 0 and surplus > 0:
add_num = surplus // 2
for j in range(add_num):
res.insert(0, 0)
res.insert(0, 0)
res.append(0)
res.append(0)
elif surplus % 2 != 0 and surplus > 0:
add_num = surplus // 2
for j in range(add_num):
res.insert(0, 0)
res.insert(0, 0)
res.append(0)
res.append(0)
res.append(0)
res.append(0)
font = freetype.Face(r"C:\Windows\Fonts\simsun.ttc")
font.set_charmap(freetype.FT_ENCODINGS['FT_ENCODING_BIG5'])
# 绘制字符
font.set_pixel_sizes(16, 16)
font.load_char('2', freetype.FT_LOAD_RENDER | freetype.FT_LOAD_TARGETS['FT_LOAD_TARGET_MONO'])
bitmap = font.glyph.bitmap
left = []
right = []
b_b = bitmap.buffer
control_size(b_b)
for i in range(len(b_b) // bitmap.pitch):
res = b_b[i * 2] << 8 | b_b[i * 2 + 1]
# print(b_b[i], b_b[i + 1])
b_res = list(format(res >> 5, "016b"))
for r in b_res:
if r == "1":
print("\033[1;30;43m \033[0m", end="")
else:
print("\033[1;30;40m \033[0m", end="")
print()
print(' '.join(left))
print(' '.join(right))
Already answered the set_chairmap
question in #191 - there are two example scripts in the example directory, one called font-info.py, one called ftdump
. Both of them display font file info. Both of them show you what charmaps simsun.ttc
was shipped with. It was shipped with two unicode charmaps only (one for apple, one for microsoft). Hence you cannot set charmap to a big5 one, since there isn't one for that encoding.
You need to do the same as above: "big5input".decode('big5')
.
Your IDE is broken/buggy if it doesn't show freetype.FT_LOAD_RENDER
... even python's own repr gives you that..
Already answered the
set_chairmap
question in #191 - there are two example scripts in the example directory, one called font-info.py, one calledftdump
. Both of them display font file info. Both of them show you what charmapssimsun.ttc
was shipped with. It was shipped with two unicode charmaps only (one for apple, one for microsoft). Hence you cannot set charmap to a big5 one, since there isn't one for that encoding. You need to do the same as above:"big5input".decode('big5')
.Your IDE is broken/buggy if it doesn't show
freetype.FT_LOAD_RENDER
... even python's own repr gives you that..
:) No problem, I just noticed it myself. Thank you!
code is
num is incorrect(Maybe the ascii is incorrect?):![image](https://github.com/rougier/freetype-py/assets/56969920/d9026d7c-ce18-4bed-b285-8816819c62fe)
Chinese input is correct:![image](https://github.com/rougier/freetype-py/assets/56969920/65fe8834-0151-4432-a9ef-2fce99424269)