freetype-py

http://code.google.com/p/freetype-py/

pythonfreetypeラッパ。ctypesで実装されているので別途freetypeのバイナリが必要となる。Windowsの場合、
http://gnuwin32.sourceforge.net/packages/freetype.htm
からバイナリを入手して、中の
bin/freetype6.dll
をPATHの通ったところにfreetype.dllという名前でコピーする。

examplesを動かすには
http://ja.fonts2u.com/download/bitstream-vera-sans.%E3%83%95%E3%82%A1%E3%83%9F%E3%83%AA%E3%83%BC
をダウンロードしてカレントディレクトリに展開する。

C:/Pytnon27/freetype.dllを使いたかったので・・・

freetype/__init__.pyに以下を追加した。

if not FT_Library_filename:
    try:
        __dll__ = ctypes.CDLL('libfreetype.so.6')
    except OSError:
        __dll__ = None
# 追加 #
if not FT_Library_filename:
    try:
        __dll__ = ctypes.CDLL('freetype')
    except OSError:
        __dll__ = None
# 追加おわり #

ctypes.util.find_library('freetype')だとPATHの通ったところしか探してくれないらしい。

日本語フォントでテクスチャを作るメモ

examples/opengl.pyは、1枚のテクスチャにアスキー文字を全部出力してからUVを変えて1文字ずつ出力する例。
それを改造してunicodeを1文字ずつ出力するようにした。

# coding: utf-8
import numpy
from freetype import *
from OpenGL.GL import *
from OpenGL.GLUT import *


class MultibyteFont(object):
    def __init__(self, fontfile, size, text):
        assert(isinstance(text, unicode))
        # Load font  and check it is monotype
        face = Face(fontfile)
        face.set_char_size( size*64 )

        # Determine largest glyph size
        width, height, ascender, descender = 0, 0, 0, 0
        for c in text:
            face.load_char(c, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT )
            bitmap    = face.glyph.bitmap
            width     = max( width, bitmap.width )
            ascender  = max( ascender, face.glyph.bitmap_top )
            descender = max( descender, bitmap.rows-face.glyph.bitmap_top )
        height = ascender+descender

        # size
        lines=1
        cols=len(text)+1
        self.texture_width=width*cols
        self.texture_height=height*lines

        # Generate texture data
        Z = numpy.zeros((self.texture_height, self.texture_width), dtype=numpy.ubyte)
        j=0
        for i, c in enumerate(text):
            face.load_char(c, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT )
            bitmap = face.glyph.bitmap
            x = i*width  + face.glyph.bitmap_left
            y = j*height + ascender - face.glyph.bitmap_top
            print y, y+bitmap.rows, x, x+bitmap.width
            Z[y:y+bitmap.rows,x:x+bitmap.width].flat = bitmap.buffer
        print Z

        # Bound texture
        self.texid = glGenTextures(1)
        glBindTexture( GL_TEXTURE_2D, self.texid )
        glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR )
        glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR )
        glTexImage2D( GL_TEXTURE_2D, 0, GL_ALPHA, Z.shape[1], Z.shape[0], 0,
                         GL_ALPHA, GL_UNSIGNED_BYTE, Z )


    def draw(self):
        glPushMatrix()
        glBindTexture(GL_TEXTURE_2D, self.texid)
        glColor(1,1,1,1)
        glEnable( GL_TEXTURE_2D )
        glBegin( GL_QUADS )
        glTexCoord2f( 0, -1 ), glVertex( 0,     self.texture_height )
        glTexCoord2f( 0, 0 ), glVertex( 0,     0 )
        glTexCoord2f( 1, 0 ), glVertex( self.texture_width, 0 )
        glTexCoord2f( 1, -1 ), glVertex( self.texture_width, self.texture_height )
        glEnd( )
        glPopMatrix()


class Controller(object):
    def __init__(self):
        self.is_initialized=False

    def onResize(self, w, h):
        glViewport(0, 0, w, h)
        glMatrixMode( GL_PROJECTION )
        glLoadIdentity( )
        glOrtho( 0, w, 0, h, -1, 1 )
        glMatrixMode( GL_MODELVIEW )
        glLoadIdentity( )

    def onLeftDown(self, x, y): print 'onLeftDown', x, y
    def onLeftUp(self, x, y): print 'onLeftUp', x, y
    def onMiddleDown(self, x, y): print 'onMiddleDown', x, y
    def onMiddleUp(self, x, y): print 'onMiddleUp', x, y
    def onRightDown(self, x, y): print 'onRightDown', x, y
    def onRightUp(self, x, y): print 'onRightUp', x, y
    def onMotion(self, x, y): print 'onMotion', x, y
    def onWheel(self, d): print 'onWheel', d
    def onKeyDown(self, keycode): print 'onKeyDown', keycode
    def onUpdate(self, d): print 'onUpdate', d

    def onInitialize(self):
        glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE )
        glEnable( GL_DEPTH_TEST )
        glEnable( GL_BLEND )
        glEnable( GL_COLOR_MATERIAL )
        glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE )
        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA )
        self.mb=MultibyteFont('C:/Windows/fonts/msgothic.ttc', 32, u'日本語フォント')
        self.is_initialized=True

    def draw(self):
        if not self.is_initialized:
            self.onInitialize()
        glClearColor(0.9, 0.5, 0.0, 0.0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        self.mb.draw()
        glFlush()


if __name__=="__main__":
    controller=Controller()
    import glglue.glut
    glglue.glut.mainloop(controller, 400, 60, b"Freetype OpenGL")