【Py】 KSTストロークフォントを展開

[pukiwiki]
-[[無料で使えるストロークフォント KST32b, KST32ZX(作者 坂 直純さん):http://www.vector.co.jp/vpack/browse/person/an018977.html]]
–[[KST32B 極めてコンパクトなJIS第1水準漢字他のStrokeFont(KST):http://www.vector.co.jp/soft/data/writing/se119277.html]]
–[[KST32ZX 篆文,篆書風(Zhuanwen,Zhongwen-Like),漢字StrokeFont(KST):http://www.vector.co.jp/soft/win95/writing/se256880.html]]

独自形式のデータなので、Pythonへ読み込むためのモジュールを作ってみました。

サンプル
http://boxheadroom.com/wp/wp-content/uploads/2009/06/goodmorning.gif

スプラインで補間してみました。
[/pukiwiki]


[pukiwiki]
-kst.pyとして保存
-同じフォルダに、[[KST32B:http://www.vector.co.jp/soft/data/writing/se119277.html]] のデータファイルKST32B.TXTを置いてください。
-標準モジュールしか使ってないので、多分、クロスプラットフォームかと。
[/pukiwiki]

# -*- coding: utf8 -*-

"""
kst.py

KSTストロークフォントデータを変換します

必要なファイル

KST32B
極めてコンパクトなJIS第1水準漢字他のStrokeFont(KST)
http://www.vector.co.jp/soft/data/writing/se119277.html


KST32ZX
篆文,篆書風(Zhuanwen,Zhongwen-Like),漢字StrokeFont(KST)

http://www.vector.co.jp/soft/win95/writing/se256880.html

書庫中のデータファイルKST32B.TXT KST_ZX.TXTを、
このモジュールと同じフォルダに置いてください

ex)

import kst

kstfont=KST( kst.FONT_KST32B または kst.FONT_KST32ZX,size=32)
stroke=kstfont.getstroke()

stroke  ... [ [[x00,y00], [x01,y01],[x02,y02]...],
              [[x10,y10], [x11,y11],[x12,y12]...], ...] 

http://boxheadroom.com/blender

****  Font_format(=CSF1:CompactStrokeFont/1): 
****    20(Hex)     : Terminator 
****    21-26,28-3F : Move to X=0--29 
****    40-5B,5E-5F : Draw to X=0--29 
****    60-7D       : Next X to 0--29 
****    7E,A1-BF    : Move to Y=0--31 
****    C0-DF       : Draw to Y=0--31 
****    27,5C,5D    : Reserved(else=Term);Init=(0,0) 
****  Record_format<+Column#>: 
****  < 1..4 6.........max=155 > 
****    9999 (font-def) : 9999=HexAddr, (font-def)=CSF1 
"""
import os,sys
import copy

FONT_KST32B="KST32B.TXT"
FONT_KST32ZX="KST_ZX.TXT"

def fopen(fname,mode="rb"):
    if os.path.exists(fname):
        return open(fname)
    else :
        p,b=os.path.split(__file__)
        return open(os.path.join(p,os.path.split(fname)[-1]))
W,H=30,32        
class KST(object):
    
    def __init__(self,fname=FONT_KST32B,size=32):
        self.size=size
        lines=fopen(fname).read().splitlines()
        self.debug=False
        self.cacheflag=False
        self.kst_dic=dict()
        for i in lines :
            if not i.startswith("*"):
                try:
                    code,stroke=i.split()
                    self.kst_dic[int(code,16)]=stroke
                except:
                    pass

    def getstroke(self,ch,size=None):
        if not size :
            size=self.size
        #sc=size/32.
        debug=self.debug
        cacheflag=self.cacheflag
        if cacheflag:
            stroke=self.cache.get(ch,[])
            if stroke :
                print "cache"
                return stroke
        else :
            stroke=Stroke()
        dat=self.kst_dic.get(utf2jis(ch),"!~")
        #dat=kst_dic.get(ch[0],[])
        if dat and debug :print dat.encode("hex")
        x=y=x0=y0=0
        for j in dat:
            c=ord(j)
            if debug :print hex(c),
            if c in [0x27,0x5c,0x5d] : #Reserved
                continue
            elif 0x21<=c<=0x26 or  0x28<=c<=0x3f : 
                #21-26,28-3F : Move to X=0--29
                
                x0=x=c-0x21
                if c>0x26 :x-=1
                
                if debug :
                    print "x=%02x"%x
            elif 0x40<=c<=0x5b or 0x5e<=c<0x5f : 
                #40-5B,5E-5F : Draw to X=0--29  
                x0=x
                x=c-0x40
                if c>0x5b : x-=2

                self._draw(stroke,x0,y0,x,y)
                x0,y0=x,y
                if debug :
                    print "draw x=%02x"%x
                            
            elif 0x60<=c<=0x7d : 
                #60-7D : Next X to 0--29 
                x0=x
                x=c-0x60
                if debug :
                    print "next x=%02x"%x
                            
            elif c==0x7e : 
                #7E,A1-BF : Move to Y=0--31
                
                y0=y=H-1
                if debug :
                    print "y=%02x"%y
            elif 0xa1<=c<=0xbf : 
                #7E,A1-BF : Move to Y=0--31
                
                y=(c-0xa1+1)
                y0=y=H-y-1
                if debug :
                    print "y=%02x"%y

            elif 0xc0<=c<=0xdf : 
                #C0-DF  : Draw to Y=0--31 
                y0=y

                y=c-0xc0
                y=H-y-1
                self._draw(stroke,x0,y0,x,y)
                x0,y0=x,y
                if debug :
                    print "draw y=%02x"%y
        stroke=resize(stroke,size)
        if debug :print stroke
        if cacheflag:
            cache[ch]=stroke
        if debug:
            print ch,getwidth(stroke)
        return stroke
    def _draw(self,stroke,x0,y0,x,y):
        if not stroke :
            stroke.append([ [x0,y0],[x,y]])
        else :
            px0,py0=stroke[-1][-1]
            if [x0,y0]==[px0,py0]:
                stroke[-1].append([x,y])
            else :
                stroke.append([[x0,y0],[x,y]])
    def resize(self,stroke,size=32):
        sc=size/float(self.size)
        return scale(stroke,sc)

class Stroke(list):
    def __new__(self):
        return list.__new__(self)
    def __init__(self,s=[],size=32):
        self.size=size
        list.__init__(self,s)
    def  copy(self):
        return copy.deepcopy(self)
    def move(self,dx,dy):
        return move(self,dx,dy)
    def resize(self,size=32):
        return resize(self,size)
    def scale(self,scale_=(1.,1.)):
        return scale(self,scale_)
    def getwidth(self):
        return getwidth(self)
def move(stroke,dx,dy):
    stroke=stroke.copy()
    for s in stroke :
        for i,(x,y) in enumerate(s) :
            s[i]=[x+dx,y+dy]
    return stroke
def resize(stroke,size=32):
    sc=size/stroke.size
    ret=scale(stroke,sc)
    ret.size=size
    return ret
def scale(stroke,scale=(1.,1.)):
    "scale=n  or scale=(m,n)"
    stroke0=stroke
    stroke=stroke.copy()
    t=type(scale)
    if t==int or t==float :
        scx=scy=scale
    elif t==tuple or t==list:
        scx,scy=scale
    for s in stroke :
        for i,(x,y) in enumerate(s) :
            #s[i]=int(x*scx),int(y*scy)
            s[i]=x*scx,y*scy
    stroke.size=stroke0.size*scy
    return stroke
def getwidth(stroke):

    try:
        px=[ p[0] for plist in stroke for p in plist]
        w=max(px)
        #w-=min(px)
    except:
        w=16
    w= 16 if w<=0 else w
    return w
debug=True    





def utf2jis(s):
    """http://www.unixuser.org/~euske/doc/kanjicode/index.html
    EUC 漢字コードは JIS 漢字コードの 2バイトのそれぞれの 第7ビット目を
    1にしてある だけなので (0x21 → 0xA1, 0x7E → 0xFE となる)、
    第7ビット目を 立てれば EUC になるし、おろせば JIS になるのである。
    ただし例外は EUC で使われている半角カナ

    """
    jislist=[ord(i)&0x7f for i in s.encode("euc-jp")]
    c=0
    for i in jislist:
        c<<=8
        c+=i
    return c
last=""
idx=0
                                                                        
def testtk():
    kst=KST("KST32B.TXT",size=1.)
    
    repr(u"あ".encode("sjis").encode("hex"))
    last=""
    def drawtext(event):
        
        global last,idx

        
        s=entry.get()
        if not s :
            last=""
            cv.delete("line%s"%idx)
            return 
        if last==s :
            return
        
        cv.delete("line%s"%idx)
        idx+=1
        x_=y_=10
        for  c in s:
        
            stroke=kst.getstroke(c,size=1.)
            stroke=scale(stroke,(32,32))
            sw=getwidth(stroke)+4
            stroke=move(stroke,x_,y_)
            for ln in stroke:
                if not ln : continue
                x0,y0=ln[0]

                if False :
                  for x,y in ln[1:] :
                    cv.create_line(10+x0,y0,10+x,y,
                                   tags ="line%s"%idx,smooth=True )
                cv.create_line(*ln,**dict(tags ="line%s"%idx,
                                    width=1,smooth=True))
            x_+=sw
        last=s                                

    root=tk.Tk()
    label0 = tk.Label(root, text=u'ここに入力')
    entry=tk.Entry(root)

    entry.bind("<KeyRelease>",drawtext)
    cv=tk.Canvas(width=640,height=400,background="white")
    for i in label0,entry,cv :
        i.pack()
    return root


if __name__=="__main__":

    import Tkinter as tk
    root=testtk()
        

    root.mainloop()
    
    


なんか、汚いコードですが、紛失しないようにblogにもメモ
[pukiwiki]
オマケ

http://boxheadroom.com/wp/wp-content/uploads/2009/06/x3.gif

ネタ元 [[スコトプリゴニエフスク通信:http://d.hatena.ne.jp/perezvon/20090601/1243872974]]
[/pukiwiki]

コメントを残す

メールアドレスが公開されることはありません。