freetype-py
freetype-py copied to clipboard
access violation writing error in Face.__del__()
Hi, I'm learning to use Freetype recently, and I encounter an exception when I'm using freetype module in python:
Exception ignored in: <bound method Face.__del__ of <freetype.Face object at 0x000001AFDAC06860>>
Traceback (most recent call last):
File "C:\Users\Xiaoqin\AppData\Local\Programs\Python\Python35\lib\site-packages\freetype\__init__.py", line 989, in __del__
OSError: exception: access violation writing 0x0000000000000054
I'm running Python 3 on Windows 64-bit and using the latest freetype-py and a homemade 64-bit freetype DLL found in a previous issue post. I have tried in 2 computers in the same environment above, with a simple single-character rendering program, and have the same exception. Any idea how to deal with it?
Could you write a minimal script that show the problem ?
Sorry for the late reply! So here's part of a program I wrote:
# -*- coding: utf-8 -*-
from freetype import *
class Font(object):
def __init__(self, filename, size, mono = True):
self._face = Face(filename)
self._face.set_pixel_sizes(size, 0)
self._slot = self._face.glyph
self._flags = (FT_LOAD_RENDER | FT_LOAD_TARGET_MONO) if mono else FT_LOAD_RENDER
self.is_mono = mono
self.name = ' '.join([self._face.family_name.decode('utf-8'), self._face.style_name.decode('utf-8')])
def load_char(self, char):
self._face.load_char(char, self._flags)
def get_data(self):
return bytes(self._slot.bitmap.buffer)
def get_size(self):
if self.is_mono:
return (self._slot.bitmap.pitch * 8, self._slot.bitmap.rows)
else:
return (self._slot.bitmap.width, self._slot.bitmap.rows)
def get_index(self, charcode):
return self._face.get_char_index(charcode)
if __name__ == '__main__':
from PIL import Image
fnt = Font(r'C:\Windows\Fonts\arial.ttf', 16)
fnt.load_char(chr(1))
im = Image.frombytes('1', fnt.get_size(), fnt.get_data())
im.show()
But your example code works fine. Did a little change:
from PIL import Image
from freetype import *
def bits(x):
data = []
for i in range(8):
data.insert(0, int((x & 1) == 1) * 255)
x = x >> 1
return data
face = Face(r'C:\Windows\fonts\BKANT.TTF')
face.set_pixel_sizes(16, 0)
face.load_char('#', FT_LOAD_RENDER | FT_LOAD_TARGET_MONO)
slot = face.glyph
bitmap = slot.bitmap
data = []
for i in range(bitmap.rows):
row = []
for j in range(bitmap.pitch):
row.extend(bits(bitmap.buffer[i*bitmap.pitch+j]))
data.extend(row[:bitmap.width])
print(len(bitmap.buffer), bitmap.buffer)
print(len(data), data)
data = bytes(data)
im = Image.frombytes('L', (bitmap.width, bitmap.rows), data)
im.show()
print(bitmap.width, bitmap.rows, bitmap.pitch, len(bitmap.buffer))
Sorry Im' lost, you get an access violation with the first script but not with the second, is that right ?
Ah, yes.
I get the same segfault. I think there is a problem with the face "destructor". If you add self._face = None
in your Font init class, there is no more segfault (but it doesn't work of course). I need to investigate but most likely I'm trying to close twice the library hence the segfault.
I've just found that explicitly del fnt
instance or define a __del__()
with del self._face
can solve this exception, but I have no idea why.
No, I think the segfault happens because the library handle's destructor is called before the face handle's. I found that when I was looking at the "memory leak" - ( https://github.com/rougier/freetype-py/issues/51 ) - almost all the examples are "leaking" face handle: by the time the library handle's destructor being called, the face handle is still around - to be honest, I think relying on automatic garbage collection to happen in the right order is a user programming style/education problem...
fwiw I'm currently having the same error on Linux, e.g.
Exception ignored in: <bound method Face.__del__ of <freetype.Face object at 0x7f5d21ba6898>>
Traceback (most recent call last):
File "/usr/local/lib/python3.4/dist-packages/freetype_py-1.2-py3.4.egg/freetype/__init__.py", line 999, in __del__
TypeError: 'NoneType' object is not callable
So maybe we should get rid of the __del__
method (plus I don't remember why I've used it in the first place).