rougier / freetype-py

Python binding for the freetype library
Other
300 stars 87 forks source link

access violation writing error in Face.__del__() #44

Open fhfuih opened 7 years ago

fhfuih commented 7 years ago

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?

rougier commented 7 years ago

Could you write a minimal script that show the problem ?

fhfuih commented 7 years ago

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()
fhfuih commented 7 years ago

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))
rougier commented 7 years ago

Sorry Im' lost, you get an access violation with the first script but not with the second, is that right ?

fhfuih commented 7 years ago

Ah, yes.

rougier commented 7 years ago

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.

fhfuih commented 7 years ago

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.

HinTak commented 7 years ago

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...

golightlyb commented 6 years ago

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
rougier commented 6 years ago

So maybe we should get rid of the __del__ method (plus I don't remember why I've used it in the first place).