บันทึกการแปลงฟอนต์ Waree เป็น DejaVuSansThai รุ่นแรก
dfont.py
เอาไว้คลี่และเรียงสแต็ก ใช้ได้ผลดีพอควร แต่สคริปต์ยังขาดการตรวจสอบความถูกต้องของ instructing code ซึ่งถ้าใช้ด้วยพารามิเตอร์ --all
อาจทำให้ fontforge หยุดการทำงานได้ - รอปรับปรุงต่อไปความรู้ที่ได้
MIRP
(ซึ่งต้องอ้างค่าจาก cvt - Control Value Table) มีความแม่นยำแน่นอนกว่าการเคลื่อนค่าแบบ direct (เช่นคำสั่ง MDRP
)ip
(Interpolate) จะทำให้ฟอนต์ดูฟุ้ง แต่ระยะที่ได้ แน่นอนกว่าการเคลื่อนจุดแบบ direct (เว้นเสียแต่ถ้าไม่มีการทดลงจุด คืออาร์กิวเมนต์ rnd
ควรใช้ MDRP
เสมอ ไม่งั้นบางทีอาจเพี้ยน)rnd
ห้ามใช้คำสั่ง SHPIX
ที่จุดนั้นเด็ดขาด จะมีปัญหาเลอะตอนพิมพ์ โดยเฉพาะในแนวแกน Yผลการทดลอง - บนลินุกซ์ ความละเอียดจอภาพ 85 dpi
ดาวน์โหลดไฟล์ฟอนต์ ttf ล่าสุด (รุ่น 520401)
ดาวน์โหลดไฟล์ซอร์ส
งานที่เหลือ และที่ตั้งใจจะทำ
ภาพตัวอย่างของรุ่นล่าสุด
ตัวหนา
ภาพจาก OpenOffice.org รุ่นล่าสุด
oo ตัวหนา
ภาพตัวอย่าง รุ่นแรก (จากจอภาพขนาด 85 dpi)
dfont.py
การทำงานแค่คลี่และเรียงแสต็กใหม่deltap1 3 20 15 20 31 20 47
เปลี่ยนเป็นf_deltap 20 9+8 20 10+8 20 11+8
$ vi dfont.py
#!/usr/bin/env python
"""
This file is only stack render engine.
Usage:
1. Decode from instucted code
./dfont.py -d INST_CODE.txt > PSEUDO_CODE.txt
2. Encode from pseudo_code
./dfont.py -e PSEUDO_CODE.txt > INST_CODE.txt
Implement:
1 Create FONTNAME.py contain code as followed:
1.1 import dfont, sys, os
1.2 cvt_dict = {"NAME": VALUE, ... }
1.3 pseudo_code_dict = {"CHARACTER_NAME": "PSEUDO CODE TRUETYPE INSTRUCTION", ...}
1.4 if __name__ == "__main__":
if sys.argv[1] == "--all":
#$0 --all = ENCODE ALL CHARS
sfd_file = os.path.basename(sys.argv[0]).split('.',1)[0] + '.sfd'
print "Encoding all character in %s" % (sfd_file)
dfont.inst_encode_all( sfd_file, pseudo_code_dict, cvt_dict )
else:
#$0 uni0E01 > x.txt = PRINT INSTRUCTION CODE OF uni0E01 TO x.txt
print '\n'.join(dfont.inst_encode( pseudo_code_dict[sys.argv[1]], cvt_dict ))
2 Encode:
2.1 Process all character, this script will modify FONTNAME.sfd
Usage: ./FONTNAME.py --all
2.2 Encode each character, for example KO_KAI="uni0E01"
Usage: ./FONTNAME.py uni0E01 > INSTRUCTED.TXT
"""
import sys
import os
# put cvt_dict and pseudo_code_dict varirable in FONTNAME.py
# cvt value example:
#cvt_dict = {
# "base": 10, #0
# "hstem": 8, #184
# "vstem": 96, #154
# "vstem_small": 27, #135
# "headstem_small": 11, #113 =kho
# "headdia_small": 180, #377 =kho
# "headhole_small": 254, #150 =kho
# "headneck_kho": 39, #180 =kho
# "hwidth_ko": 164, #987 =ko,tho
# "hwidth_kho": 14, #690 =ko,tho
# "hwidth_sho": 108, #772 =sho
# "vheight": 49, #1208
# "vheight_hi": 54, #1208 =ko
# "vheight_hi_kho": 54, #1229 =kho
# "vheight_lo": 88, #20
# "vheight_lo_sho": 256, #6 *** NEWVALUE
# "head_diff": 131, #254 =head of character: bo,po
# "beak_diff": 9, #102 =beak of ko,tho
# "front_space_ko": 65, #201 =front spacing of ko,tho
# "front_space_kho": 38, #340 =front spacing of kho
#}
# pseudo_code example:
#pseudo_code_dict = {
# #ko_kai
# "uni0E01": """
#srp0 26
#mirp[rp0,min,rnd,grey] front_kai 14
#mirp[min,rnd,grey] hstem 12
#mirp[rp0,rnd,grey] hwidth_14 25
#mirp[min,rnd,grey] hstem 1
#mdrp[min,rnd,grey] 27
#srp0 14
#mdrp[rp0,rnd,grey] 18
#mdrp[min,rnd,grey] 8
#mdrp[rp0,rnd,grey] 17
#mdrp[min,rnd,grey] 10
#iup[x]
#svtca[y-axis]
#mdap[rnd] 1
#ALIGNRP 13
#mirp[rp0,rnd,grey] vheight_shoot 22
#mirp[min,rnd,grey] vstem_curve 5
#srp1 5
#srp2 13
#sloop 10
#ip 19 8 18 9 17 10 2 25 15 12
#iup[y]
#""",
#}
#BEGIN
# inst_dict = { "COMMAND" : ("Description",diff,pops,push), ... }
# diff: 0=NOOP, 1=1BYTE, 2=2BYTE, ...
# -1=FIRST BYTE IS ONE BYTE COUNTER,
# -2=FIRST BYTE IS TWO BYTE COUNTER,
# -3=CLEAR STACK
# -4=REQUIRE SOME PROCESSING
inst_dict = {
"AA" : ("Adjust Angle", 1, 1, 0),
"ABS" : ("ABSolute value", 0, 1, 1),
"ADD" : ("ADD", 1, 2, 1),
"ALIGNPTS" : ("ALIGN Points", 2, 2, 0),
"ALIGNRP" : ("ALIGN to Reference Point", 1, 1, 0),
"AND" : ("logical AND", 1, 2, 1),
"CALL" : ("CALL function", 1, 1, 0),
"CEILING" : ("CEILING", 0, 1, 1),
"CINDEX" : ("Copy the INDEXed element to the top of the stack", 1, 1, -4),
"CLEAR" : ("CLEAR the stack", -3, 0, 0),
"DEBUG" : ("DEBUG call", 1, 1, 0),
"DELTAC1" : ("DELTA exception C1", -2, 0, 0),
"DELTAC2" : ("DELTA exception C2", -2, 0, 0),
"DELTAC3" : ("DELTA exception C3", -2, 0, 0),
"DELTAP1" : ("DELTA exception P1", -2, 0, 0),
"DELTAP2" : ("DELTA exception P2", -2, 0, 0),
"DELTAP3" : ("DELTA exception P3", -2, 0, 0),
"DEPTH" : ("DEPTH of the stack", 0, 0, 1),
"DIV" : ("DIVide", 1, 2, 1),
"DUP" : ("DUPlicate top stack element", 0, 1, 1),
"EIF" : ("End IF", 0, 0, 0),
"ELSE" : ("ELSE clause", 0, 0, 0),
"ENDF" : ("END Function definition", 0, 0, 0),
"EQ" : ("EQual", 1, 2, 1),
"EVEN" : ("EVEN", 0, 1, 1),
"FDEF" : ("Function DEFinition", 1, 1, 0),
"FLIPOFF" : ("set the auto FLIP Boolean to OFF", 0, 0, 0),
"FLIPON" : ("set the auto FLIP Boolean to ON", 0, 0, 0),
"FLIPPT" : ("FLIP PoinT", 1, 1, 0),
"FLIPRGOFF" : ("FLIP RanGe OFF", 2, 2, 0),
"FLIPRGON" : ("FLIP RanGe ON", 2, 2, 0),
"FLOOR" : ("FLOOR", 2, 2, 0),
"GC" : ("Get Coordinate projected onto the projection vector", 0, 1, 1),
"GETINFO" : ("GET INFOrmation", 0, 1, 1),
"GFV" : ("Get Freedom Vector", 0, 0, 2),
"GPV" : ("Get Projection Vector", 0, 0, 2),
"GT" : ("Greater Than", 1, 2, 1),
"GTEQ" : ("Greater Than or EQual", 1, 2, 1),
"IDEF" : ("Instruction DEFinition", 1, 1, 0),
"IF" : ("IF test", 1, 1, 0),
"INSTCTRL" : ("INSTRuction execution ConTRoL", 2, 2, 0),
"IP" : ("Interpolate Point", 1, 1, 0),
"ISECT" : ("moves point p to the InterSECTion of two lines", 5, 5, 0),
"IUP" : ("Interpolate Untouched Points through the outline", 0, 0, 0),
"JMPR" : ("JuMP Relative", 1, 1, 0),
"JROF" : ("Jump Relative On False", 1, 1, 0),
"JROT" : ("Jump Relative On True", 3, 3, 0),
"LOOPCALL" : ("LOOP and CALL function", 2, 2, 0),
"LT" : ("Less Than", 1, 2, 1),
"LTEQ" : ("Less Than or Equal", 1, 2, 1),
"MAX" : ("MAXimum of top two stack elements", 1, 2, 1),
"MD" : ("Measure Distance", 1, 2, 1),
"MDAP" : ("Move Direct Absolute Point", 1, 1, 0),
"MDRP" : ("Move Direct Relative Point", 1, 1, 0),
"MIAP" : ("Move Indirect Absolute Point", 2, 2, 0),
"MIN" : ("MINimum of top two stack elements", 1, 2, 1),
"MINDEX" : ("Move the INDEXed element to the top of the stack", 1, 1, 3),
"MIRP" : ("Move Indirect Relative Point", 2, 2, 0),
"MPPEM" : ("Measure Pixels Per EM", 0, 0, 1),
"MPS" : ("Measure Point Size", 0, 0, 1),
"MSIRP" : ("Move Stack Indirect Relative Point", 1, 1, 0),
"MUL" : ("MULtiply", 1, 2, 1),
"NEG" : ("NEGate", 0, 1, 1),
"NEQ" : ("Not EQual", 1, 2, 1),
"NOT" : ("logical NOT", 0, 1, 1),
"NPUSHB" : ("PUSH N Bytes", -1, 0, 0),
"NPUSHW" : ("PUSH N Words", -1, 0, 0),
"NROUND" : ("No ROUNDing of value", 0, 1, 1),
"ODD" : ("ODD", 0, 1, 1),
"OR" : ("logical OR", 1, 2, 1),
"POP" : ("POP top stack element", 1, 1, 0),
"PUSHB" : ("PUSH Bytes", -4, 0, 0),
"PUSHW" : ("PUSH Words", -4, 0, 0),
"RCVT" : ("Read Control Value Table entry", 0, 1, 1),
"RDTG" : ("Round Down To Grid", 0, 0, 0),
"ROFF" : ("Round OFF", 0, 0, 0),
"ROLL" : ("ROLL the top three stack elements", 0, 3, 3),
"ROUND" : ("ROUND value", 0, 1, 1),
"RS" : ("Read Store", 0, 1, 1),
"RTDG" : ("Round To Double Grid", 0, 0, 0),
"RTG" : ("Round To Grid", 0, 0, 0),
"RTHG" : ("Round To Half Grid", 0, 0, 0),
"RUTG" : ("Round Up To Grid", 0, 0, 0),
"S45ROUND" : ("Super ROUND 45 degrees", 1, 1, 0),
"SANGW" : ("Set Angle Weight", 1, 1, 0),
"SCANCTRL" : ("SCAN conversion ConTRoL", 1, 1, 0),
"SCANTYPE" : ("SCANTYPE", 1, 1, 0),
"SCFS" : ("Sets Coordinate From the Stack using projection vector and freedom vector", 2, 2, 0),
"SCVTCI" : ("Set Control Value Table Cut-In", 1, 1, 0),
"SDB" : ("Set Delta Base in the graphics state", 1, 1, 0),
"SDPVTL" : ("Set Dual Projection Vector To Line", 2, 2, 0),
"SDS" : ("Set Delta Shift in the graphics state", 1, 1, 0),
"SFVFS" : ("Set Freedom Vector From Stack", 2, 2, 0),
"SFVTCA" : ("Set Freedom Vector To Coordinate Axis", 0, 0, 0),
"SFVTL" : ("Set Freedom Vector To Line", 2, 2, 0),
"SFVTP" : ("Set Freedom Vector To Projection Vector", 0, 0, 0),
"SHC" : ("SHift Contour using reference point", 1, 1, 0),
"SHP" : ("SHift Point using reference point", 1, 1, 0),
"SHPIX" : ("SHift point by a PIXel amount", 2, 2, 0),
"SHZ" : ("SHift Zone using reference point", 1, 1, 0),
"SLOOP" : ("Set LOOP variable", 1, 1, 0),
"SMD" : ("Set Minimum Distance", 1, 1, 0),
"SPVFS" : ("Set Projection Vector From Stack", 2, 2, 0),
"SPVTCA" : ("Set Projection Vector To Coordinate Axis", 0, 0, 0),
"SPVTL" : ("Set Projection Vector To Line", 2, 2, 0),
"SROUND" : ("Super ROUND", 1, 1, 0),
"SRP0" : ("Set Reference Point 0", 1, 1, 0),
"SRP1" : ("Set Reference Point 1", 1, 1, 0),
"SRP2" : ("Set Reference Point 2", 1, 1, 0),
"SSW" : ("Set Single Width", 1, 1, 0),
"SSWCI" : ("Set Single Width Cut-In", 1, 1, 0),
"SUB" : ("SUBtract", 1, 2, 1),
"SVTCA" : ("Set freedom and projection Vectors To Coordinate Axis", 0, 0, 0),
"SWAP" : ("SWAP the top two elements on the stack", 0, 2, 2),
"SZP0" : ("Set Zone Pointer 0", 1, 1, 0),
"SZP1" : ("Set Zone Pointer 1", 1, 1, 0),
"SZP2" : ("Set Zone Pointer 2", 1, 1, 0),
"SZPS" : ("Set Zone PointerS", 1, 1, 0),
"UTP" : ("UnTouch Point", 1, 1, 0),
"WCVTF" : ("Write Control Value Table in Funits", 1, 1, 0),
"WCVTP" : ("Write Control Value Table in Pixel units", 2, 2, 0),
"WS" : ("Write Store", 2, 2, 0),
}
stack1_command = ("NPUSHB", "NPUSHW")
stack2_command = ("PUSHB", "PUSHW")
arg_1_command = ("MDAP", "MDRP")
arg_2_command = ("MIAP", "MIRP")
delta_command = ("F_DELTA",)
#step_list USE IN SPECIAL PSUEDO FUNCTION f_delta
step_list = [-8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8]
normal_command = []
for i in range(6):
normal_command.append( [ j for j in inst_dict.keys() if inst_dict[j][1]==i ] )
# -1=FIRST BYTE IS ONE BYTE COUNTER,
# -2=FIRST BYTE IS TWO BYTE COUNTER,
# -3=CLEAR STACK
# -4=REQUIRE PROCESS
pop_command = []
pop_command.append([])
for i in range(-1, -4, -1):
pop_command.append( [ j for j in inst_dict.keys() if inst_dict[j][1]==i ] )
def usage(prog_name):
print """\
Usage: %s [-d CODE | [-e] PSUEDO_CODE]
""" % (prog_name)
return
def line_format(cmd,stack,desc):
#STRING, LIST, STRING
return "%-24s %-10s ;%10s" % (cmd, " ".join(stack), desc,)
def f_delta(first_cmd, l):
#PSUEDO COMMAND TO PROCESS DELTA FUNCTION
#
#first_cmd = PSUEDO COMMAND, ex: f_deltap1 = deltap1
#l = LIST OF ARGUMENT (INCLUDE SELF UN-UPPERCASE COMMAND IN FIRST ARGUMENT)
#
#usage:
# f_deltap 0 16+8 #deltap1 MOVE POINT 0 AT 16 PPEM +8
#real code will be:
# DELTAP1 1 0 127
#
d1_list = []
d2_list = []
d3_list = []
first_cmd = first_cmd[2:] #TRIM F_ OUT
l.pop(0)
while len(l) > 0:
point = l.pop(0)
pstep = l.pop(0)
if '+' in pstep or '-' in pstep:
if '+' in pstep:
ppem, no_of_step = pstep.split('+')
ppem = int(ppem)
no_of_step = int(no_of_step)
else:
ppem, no_of_step = pstep.split('-')
ppem = int(ppem)
no_of_step = -int(no_of_step)
if ppem < 9:
raise ValueError('ppem must greater than 9, %s: %s %s' % (first_cmd, point, pstep,))
if abs(no_of_step) > 8:
raise ValueError('no_of_step must be between +8 and -8, %s: %s %s' % (first_cmd, point, pstep,))
if no_of_step == 0:
raise ValueError('no_of_step must not be 0, %s: %s %s' % (first_cmd, point, pstep,))
num = (ppem-9)*16 + step_list.index(no_of_step)
if num < 256:
d1_list.extend([point,str(num)])
elif num < 512:
d2_list.extend([point,str(num)])
elif num < 1024:
d3_list.extend([point,str(num)])
else:
raise ValueError('Number of delta point exceed 1024, %s' % (num,))
else:
raise SyntaxError('Please use + or - in f_delta second argument, %s %s' % (point, pstep,))
new_l = []
if d1_list:
new_l.append(first_cmd+'1')
new_l.append(str(len(d1_list)/2))
new_l.extend(d1_list)
if d2_list:
new_l.append(first_cmd+'2')
new_l.append(str(len(d2_list)/2))
new_l.extend(d2_list)
if d3_list:
new_l.append(first_cmd+'3')
new_l.append(str(len(d3_list)/2))
new_l.extend(d3_list)
return new_l[0], new_l
def inst_decode(txt):
"""Decode TrueType Instruction code into simpler code"""
txt_list = txt.split("\n")
new_list = []
commentlist = []
stack_list = []
sloop = 0
i = 0
while i < len(txt_list):
if "[" in txt_list[i]:
c1,c2 = txt_list[i].strip().split("[",1)
else:
c1,c2 = txt_list[i].strip(), ""
#SKIP EMPTY LINE
if c1 == "":
i += 1
continue
#STACK: NPUSHB, NPUSHW
if c1 in stack1_command:
i += 1
n = int(txt_list[i].strip())
i += 1
while n > 0:
stack_list.append(txt_list[i].strip())
i += 1
n -= 1
continue
#STACK2: PUSHB, PUSHW
if c1[:5] in stack2_command:
n = int(txt_list[i].strip()[6:])
i += 1
while n > 0:
stack_list.append(txt_list[i].strip())
i += 1
n -= 1
continue
temp_list = []
#POP ONE
if c1 in pop_command[1]:
idx = stack_list.pop()
temp_list = [idx]
for j in range(int(idx)):
temp_list.append(stack_list.pop())
new_list.append(line_format(txt_list[i],temp_list,inst_dict[c1][0]))
i += 1
continue
#POP PAIR
elif c1 in pop_command[2]:
idx = stack_list.pop()
temp_list = [idx]
for j in range(int(idx)):
temp_list.append(stack_list.pop())
temp_list.append(stack_list.pop())
new_list.append(line_format(txt_list[i],temp_list,inst_dict[c1][0]))
i += 1
continue
#POP ALL (CLEAR STACK)
elif c1 in pop_command[3]:
stack_list = []
new_list.append(line_format(txt_list[i],temp_list,inst_dict[c1][0]))
i += 1
continue
#NORMAL COMMAND
if c1 in normal_command[0]:
count = 0
elif c1 in normal_command[1]:
count = 1
elif c1 in normal_command[2]:
count = 2
elif c1 in normal_command[3]:
count = 3
elif c1 in normal_command[4]:
count = 4
elif c1 in normal_command[5]:
count = 5
else:
count = -1
#print 'count-1:',c1
new_list.append('count-1:%s' % (c1,))
if count > 0:
if sloop > 0:
count += sloop-1
sloop = 0
while count > 0:
if stack_list == []:
#print temp_list
new_list.extend(temp_list)
break
cnum = stack_list.pop()
temp_list.append(cnum)
if c1 == 'SLOOP':
sloop = int(cnum)
count -= 1
new_list.append(line_format(txt_list[i],temp_list,inst_dict[c1][0]))
i += 1
return new_list
def stack_format(stack_list):
def flush(new_list, cmd_list, ind, cur_ind):
#if len(cmd_list)==0: return [], [], cur_ind
if ind == 0:
temp = ['PUSHB_','NPUSHB']
else:
temp = ['PUSHW_','NPUSHW']
if len(cmd_list) < 8:
new_list.append('%s%s' % (temp[0],len(cmd_list),))
else:
new_list.append(temp[1])
new_list.append(' %s' % (len(cmd_list),))
new_list.extend(cmd_list)
return new_list, [], cur_ind
if len(stack_list)==0: return []
n = 0
new_list = []
cmd_list = []
stack_list.reverse()
if int(stack_list[n]) < 256:
ind = 0 #BYTE
else:
ind = 1 #WORD
while n < len(stack_list):
if int(stack_list[n]) < 256:
cur_ind = 0 #BYTE
else:
cur_ind = 1 #WORD
if ind == cur_ind:
cmd_list.append(' %s' % (stack_list[n],))
else:
new_list, cmd_list, ind = flush(new_list, cmd_list, ind, cur_ind) #FLUSH
cmd_list.append(' %s' % (stack_list[n],))
n += 1
new_list, cmd_list, ind = flush(new_list, cmd_list, ind, cur_ind) #FLUSH
return new_list
def inst_encode(txt,cvt_dict={}):
"""Encode simple code into TrueType Instruction code"""
if cvt_dict == {}:
print "WARNING: cvt_dict is empty, please supply cvt_dict argument"
comment_list = ['#',';'] #COMMENT CHARACTER
flush_list = ['SVTCA'] #FLUSH STACK
stack_list = []
new_list = []
cmd_list = []
txt_list = txt.split('\n')
for line in txt_list:
line = line.replace("\t"," ")
if " " in line:
l = line.split(" ")
else:
l = [line]
l = [ j for j in l if j != "" ]
if l == []:
continue
if l[0][0] in comment_list: #BYPASS COMMENT
continue
for f in flush_list: #?FLUSH STACK
if f == l[0][:len(f)]:
new_list.extend(stack_format(stack_list))
stack_list = []
new_list.extend(cmd_list)
cmd_list = []
break
if '[' in l[0]: #TO UPPERCASE
ltemp = l[0].split('[',1)
first_cmd = ltemp[0].upper()
first_word = first_cmd+'['+ltemp[1]
else:
first_word = l[0].upper()
first_cmd = first_word
#CHECK SPECIAL COMMAND ---------------------------------------
# f_delta -> f_deltap1 = deltap1, ...
for temp in delta_command:
if temp in first_word:
first_word, l = f_delta(first_word, l)
#END CHECK SPECIAL COMMAND -----------------------------------
cmd_list.append(first_word) #KEEP COMMAND
l.pop(0) #PROCESS REST STACK NUM
#
temp_arg_list = []
for element in l:
if element[0] in comment_list:
break
else:
temp_list = element.split('[',1)
if element in cvt_dict.keys(): #CHECK CVT VALUE
stack_list.append(cvt_dict[element])
temp_arg_list.append(element)
elif temp_list[0].upper() in inst_dict.keys(): #TRAP DELTA COMMAND
temp_list[0] = temp_list[0].upper()
element = '['.join(temp_list)
cmd_list.append(element)
else:
stack_list.append(element)
temp_arg_list.append(element)
#TEST NUMBER OF PARAMETER
if first_cmd in arg_1_command:
if len(temp_arg_list) != 1:
raise ValueError('%s must take 1 argument, %s' % (first_word, temp_arg_list,))
elif first_cmd in arg_2_command:
if len(temp_arg_list) != 2:
raise ValueError('%s must take 2 arguments, %s' % (first_word, temp_arg_list,))
#
if stack_list != []:
new_list.extend(stack_format(stack_list))
new_list.extend(cmd_list)
return new_list
def inst_encode_all(sfd_file, pseudo_code_dict={}, cvt_dict={}):
"""Encode all characters in pseudo_code_dict, modify FONTNAME.sfd."""
if os.path.isfile(sfd_file):
sfd = open(sfd_file).read().split('\n')
sfd_bak = sfd[:]
else:
print "File %s.sfd is not existed, script aborted." % (sfd_file,)
sys.exit[1]
for chr,txt in pseudo_code_dict.iteritems():
search_line = 'StartChar: %s' % (chr,)
if search_line in sfd:
line = sfd.index(search_line)
while line < len(sfd):
if sfd[line] == "TtInstrs:":
temp_sfd = sfd[:line+1]
#print temp_sfd[-2:]
temp_sfd += inst_encode(txt,cvt_dict)
line += 1
while sfd[line] != "EndTTInstrs":
line += 1
temp_sfd += sfd[line:]
sfd = temp_sfd[:]
break
elif sfd[line] in ["Back","Fore"]:
temp_sfd = sfd[:line] \
+ ["TtInstrs:"] \
+ inst_encode(txt,cvt_dict) \
+ ["EndTTInstrs"]+sfd[line:]
sfd = temp_sfd[:]
break
elif sfd[line] == "EndChar":
print "sfd file format error at %s" % (chr,)
break
else:
line += 1
else:
print "Character %s not found, script aborted." % (chr,)
sys.exit(1)
if sfd != sfd_bak:
os.rename(sfd_file, "%s.bak" % (sfd_file,))
f = open(sfd_file,"w")
f.write("\n".join(sfd))
f.close()
print "%s modified." % (sfd_file,)
else:
print "No modified."
if __name__ == "__main__":
if sys.argv[1] == "-d":
#DECODE
#$0 -d x.txt > d.txt = PRINT PSEUDO_CODE FROM x.txt TO d.txt
f = open(sys.argv[2])
txt = f.read()
f.close()
print '\n'.join(inst_decode(txt))
elif sys.argv[1] == "-e":
#ENCODE
#$0 -e d.txt > x.txt = PRINT INSTRUCTED CODE FROM PSEUDO_CODE d.txt TO x.txt
f = open(sys.argv[2])
txt = f.read()
f.close()
print '\n'.join(inst_encode(txt))
else:
#DEFAULT IS ENCODING
#$0 -e d.txt > x.txt = PRINT INSTRUCTED CODE FROM PSEUDO_CODE d.txt TO x.txt
f = open(sys.argv[1])
txt = f.read()
f.close()
print '\n'.join(inst_encode(txt))
เที่ยวนี้ไม่มีอะไร บันทึกตัวอย่างการ instruct เอาไว้ดูเพื่ออ้างอิงเฉย ๆ
ตัวอย่าง DejaVuSans อักขระ n
โค๊ด
NPUSHB 25 3 9 0 3 14 1 6 135 14 17 184 12 188 10 1 2 8 0 78 13 9 8 11 70 20 SRP0 MIRP[rp0,min,rnd,grey] MIRP[min,rnd,grey] SHP[rp2] MIRP[rp0,rnd,grey] MIRP[min,rnd,grey] IUP[x] SVTCA[y-axis] MDAP[rnd] ALIGNRP MIRP[rnd,grey] MIRP[rp0,rnd,grey] MDRP[rnd,grey] MIRP[min,rnd,grey] SRP1 SRP2 SLOOP IP IUP[y] PUSHB_5 96 21 207 21 2 SVTCA[x-axis] DELTAP1
outline
x-direction instruction
y-direction instruction
คลี่สแต็กให้พออ่านง่าย
CODE RP0 STACK DESCRIPTION (x-axis is default direction) SRP0 20 Set Reference Point 0 MIRP[rp0,min,rnd,grey] (20) 70 11 Move Indirect Relative Point MIRP[min,rnd,grey] (11) 8 9 SHP[rp2] (11) 13 SHift Point using reference point MIRP[rp0,rnd,grey] (11) 78 0 MIRP[min,rnd,grey] (0) 8 2 IUP[x] Interpolate Untouched Points through the outline SVTCA[y-axis] Set freedom and projection Vectors To Coordinate Axis MDAP[rnd] 1 Move Direct Absolute Point ALIGNRP (1) 10 ALIGN to Reference Point MIRP[rnd,grey] (1) 188 12 MIRP[rp0,rnd,grey] (1) 184 17 MDRP[rnd,grey] (17) 14 MIRP[min,rnd,grey] (17) 135 6 SRP1 1 Set Reference Point 1 SRP2 14 Set Reference Point 2 SLOOP 3 Set LOOP variable IP 0 9 3 Interpolate Point IUP[y] Interpolate Untouched Points through the outline SVTCA[x-axis] DELTAP1 2 21 207 21 96 DELTA exception P1
อธิบาย deltap
The 8 bit arg component of the DELTA instructions decomposes into two parts. The first 4 bits represent the relative number of pixels per em at which the exception is applied. The second 4 bits represent the magnitude of the change to be made. The structure of the arg is shown in FIGURE 26. ppem = pointSize * dpi / 72 207 = 1100 1111 1100=12 (9+12=21ppem) 1111=15 = 8step = 8/64 of pixel (0=-8, 1=-7, ... 14=+7, 15=+8) 96 = 0110 0000 0110=6 (9+6=15ppem) 0000=0 = -8step = -8/64 of pixel
แปลว่า
1.เลื่อนจุด 21 ไป 8step ที่ขนาดฟอนต์ 21 ppem (จอ Mac75dpi=21pt Windows96dpi~16pt Linux(จอผม85dpi)~18pt)
2. เลื่อนจุด 21 ไป -8step ที่ขนาดฟอนต์ 15 ppem (จอ Mac75dpi=15pt Windows96dpi~11pt Linux(จอผม85dpi)~13pt)
ตาราง cvt
ITEM VALUE DESCRIPTION 8 184 stem width 70 186 left spacing 78 938 outer width 135 156 top stem thick 184 1147 straight vertical height 188 1120 outer height
DejaVu Sans
ที่เกี่ยวข้อง ทำเป็นตัวแปรแบบดิกชันนารีในไพธอน คือ
cvt_dict = {
...
"front_kai": 11, #113 =front spacing of ko_kai
"hstem": 8, #184 =horizontal stem width
"w_881": 163, #881 =width of ko kai
"vheight_shoot": 184, #1147 =overshoot height
"vstem_curve": 185, #156 =curve vertical stem width
...
}
ค่า cvt ของฟอนต์ ดูได้จากเมนูของ FontForge คือ Hints -> Edit 'cvt' ...
โดยจะเรียงตั้งแต่ลำดับที่ 0 เป็นต้นไปsrp0 26จากจุดเริ่มต้น จะเคลื่อนจุดอ้างอิง rp0 ไปยังจุดที่ใกล้ขอบซ้ายที่สุด คือจุด 18 เพื่อกั้นเป็นระยะช่องไฟด้านหน้า ด้วยค่า cvt คือ front_kai
mirp[rp0,min,rnd,grey] front_kai 18จุดที่จะไปต่อคือ จุด 8 แต่เนื่องจากเมื่อเคลื่อนไปแล้ว ไม่มีจุดที่จะไปต่อ เราจึงไม่ต้องเคลื่อนจุด rp0 ไปด้วย จึงไม่ต้องใส่อาร์กิวเมนต์ rp0
mdrp[min,rnd,grey] 8ตอนนี้ rp0 ยังอยู่ที่เดิม คือ จุด 18 เราต้องเคลื่อนไปต่อที่จุด 17 และ 10 ตามลำดับ แต่หากเราเคลื่อนไปจุด 17 ก่อน แล้วต่อไปที่ 10 จะทำให้ระยะที่ถูกทด (round) แล้ว มีค่ามากเกินไป ทำให้ปาก ก.ไก่ ไม่สวยงาม เราจึงใช้การเคลื่อนไปที่จุด 10 ก่อน แล้วจึงย้อนมาที่ 17 อีกครั้งหนึ่ง ทำให้ได้ภาพที่สวยงามกว่า
mdrp[rp0,rnd,grey] 10 mdrp[min,rnd,grey] 17จุดที่จะไปต่อคือจุด 14 แต่ตอนนี้จุดอ้างอิง rp0 มาอยู่ที่จุด 10 แล้ว หากเราเคลื่อนจากจุดนี้ไปเลย จะทำให้ระยะทดไม่แน่นอน จึงควรย้อนกลับไปที่จุดแรกคือ 18 จะดีกว่า
srp0 18 mdrp[rp0,rnd,grey] 14ต่อไปเป็นการกำหนดความหนาของเส้นตั้ง (hstem) ต้องใช้ค่า cvt เสมอ
mirp[min,rnd,grey] hstem 12ต่อไปเป็นการกำหนดความกว้างของตัวอักษร ต้องใช้ cvt เสมอ โดยต้องย้ายจุด rp0 ไปด้วย เพื่อไปทำงานต่อ โดยจะกำหนดขนาดให้คลุมความกว้างรวมก่อน แล้วจึงย้อนมากำหนดความหนาของเส้นตั้งตัวหลังอีกครั้งหนึ่ง
mirp[rp0,rnd,grey] w_881 25 mirp[min,rnd,grey] hstem 1กั้นเป็นฃ่องไฟด้านหลัง โดยไม่ต้องกำหนดระยะ min และเผื่อการแรเงาเป็น white เพื่อให้มีช่องว่างอย่างน้อย 1 จุดคั่นกับอักษรตัวถัดไป มีประโยชน์สำหรับฟอนต์ที่มีการทดลงจุดในแนวแกน X มาก ๆ ซึ่งจะทำให้ล้นความกว้างที่มีอยู่ (คำสั่งนี้คิดเอง เพื่อให้ไม่ต้องทำ delta hint ตามแบบของ DejaVu)
mdrp[rnd,white] 27เกลี่ยจุดที่เรายังไม่ได้อ้างอิงในแนวแกน X ซึ่งจะใช้คำสั่งสี้ปิดท้ายเสมอ (IUP คือ Interpolate Untouched Point)
IUP[x]แนวแกน Y
SVTCA[y-axis]จะเริ่มต้นที่จุด 1 ในแนวแกน Y นี้ เรายังไม่ได้ทำอะไรเลย จึงควรปัดให้ลงจุดเสียก่อน
mdap[rnd] 1บอกว่าจุด 13 อยู่ในระดับเดียวกับจุด 1
alignrp 13กำหนดความสูงของฟอนต์
mirp[rp0,rnd,grey] vheight_shoot 22กำหนดความหนาของเส้นในแนวนอน
mirp[min,rnd,grey] vstem_curve 5กำหนดให้ rp1 เป็นจุด 5 และ rp2 เป็นจุด 13 เพื่อจะเกลี่ยจุดที่สำคัญอื่น ๆ โดยใช้ rp1 และ rp2 เป็นจุดอ้างอิงในการเฉลี่ยค่า
srp1 5 srp2 13 sloop 10 ip 19 8 18 9 17 10 2 25 15 12เกลี่ยจุดที่เหลือ ในแนวแกน Y
IUP[y]เมื่อนำโค๊ดที่เขียนมาถอดด้วยสคริปต์ dfont.py จะได้โค๊ด instruction ดังนี้
NPUSHB 15 27 1 8 25 163 12 8 14 18 17 10 8 18 11 26 SRP0 MIRP[rp0,min,rnd,grey] MDRP[min,rnd,grey] MDRP[rp0,rnd,grey] MDRP[min,rnd,grey] SRP0 MDRP[rp0,rnd,grey] MIRP[min,rnd,grey] MIRP[rp0,rnd,grey] MIRP[min,rnd,grey] MDRP[rnd,white] IUP[x] NPUSHB 19 12 15 25 2 10 17 9 18 8 19 10 13 5 5 185 22 184 13 1 SVTCA[y-axis] MDAP[rnd] ALIGNRP MIRP[rp0,rnd,grey] MIRP[min,rnd,grey] SRP1 SRP2 SLOOP IP IUP[y]จบแล้วครับ
cvt_dict = {
...
"w_690": 14, #690 =width of kho_khai
"hstem": 8, #184 =horizontal stem
"vstem": 96, #154 =vertical stem
"headstem": 258, #116 =head stem
"headstem_plus_hole": 259, #268 =head stem + hole width
"headdia": 257, #384 =head diameter
"vheight": 188, #1120 =normal height
"vheight_shoot": 184, #1147 =overshoot height
"front_khai": 32, #51 =front spacing of kho_khai
...
}
ภาพลายเส้นsrp0 53เคลื่อนไปจุดใกล้ทีสุดด้วยระยะ front_khai
mirp[rp0,min,rnd,grey] front_khai 21จัดการหัวก่อน ด้วยการกำหนดขนาดเส้นหัว เคลือนไปอีกด้านหนึ่ง แล้วกำหนดขนาดย้อนกลับอีกครั้ง
mirp[min,rnd,grey] headstem 50 mirp[rp0,rnd,grey] headdia 15 mirp[min,rnd,grey] headstem 44กำหนดจุดคอดที่จุด 12
mdrp[rnd,grey] 12เคลื่อนไปที่จุด 7 ด้วยการแรเงาแบบ white เพื่อแยกหัวออกจากคออักษรให้ชัดเจน
mdrp[rp0,rnd,white] 7เคลื่อนไปต่อ เพื่อกำหนดความกว้างของคอ ให้เท่ากับระยะ vstem (ยืมค่า vstem ซึ่งน้อยกว่า hstem มาใช้สำหรับคออักษร)
mirp[rp0,rnd,grey] vstem 27เคลื่อนไปต้อ ด้วยการแรเงาแบบ white เพื่อแยกเส้นหน้าและเส้นหลังจากกัน
mdrp[rp0,rnd,white] 36เคลื่อนต่อ กำหนดขนาดของเส้นหลัง
mirp[rp0,min,rnd,grey] hstem 38กำหนดระยะกั้นหลัง
mdrp[rnd,white] 54เคลื่อนย้อนกลับมาที่จุด 1 เพื่อกำหนดความกว้างหลักของอักษร ให้เท่ากับระยะ w_690
mirp[rp0,rnd,grey] w_690 1กำหนดความกว้างของเส้นหน้า
mirp[min,rnd,grey] hstem 32เกลี่ยจุดที่เหลือ จบการทำงานในแกน X
IUP[x]แนวแกน Y
SVTCA[y-axis]ปัดเศษลงจุด 1
mdap[rnd] 1กำหนดความสูงปกติของเส้นหลัง
mirp[rnd,grey] vheight 38กำหนดความหนาของเส้นแนวนอนให้เท่ากับระยะ vstem
mirp[min,rnd,grey] vstem 33เคลื่อนไปเพื่อกำหนดความสูงหลอกตา (overshoot) ของหัว
mirp[rp0,rnd,grey] vheight_shoot 24เคลื่อนจุด กำหนดความหนาของคอแนวนอน โดยกำหนดให้เท่ากับความหนาของหัว คือ headstem
mirp[rp0,rnd,grey] headstem 10ย้ายมากำหนดส่วนคอด
mdrp[rp0,rnd,white] 12ตรงนี้ เราจะเคลื่อนลงไปใต้สุดของหัวเลย เพื่ออาศัยพื้นที่ส่วนบนของหัว เป็นระยะรองรับการทดจุด (มีพื้นที่ดำมากกว่าส่วนอื่น) แล้วจึงกำหนดจุดของความหนาหัวและรูของหัวอักษรจากด้านล่าง
mdrp[rp0,rnd,grey] 18 mirp[min,rnd,grey] headstem 41 mirp[rnd,grey] headstem_plus_hole 47เกลี่ยจุดเป็นคำสั่งสุดท้าย
IUP[y]เสร็จแล้ว
NPUSHB 12 32 8 1 14 54 38 8 36 27 96 7 44 PUSHW_1 258 PUSHB_2 12 15 PUSHW_1 257 PUSHB_1 50 PUSHW_1 258 PUSHB_3 21 32 53 SRP0 MIRP[rp0,min,rnd,grey] MIRP[min,rnd,grey] MIRP[rp0,rnd,grey] MDRP[rnd,grey] MIRP[min,rnd,grey] MDRP[rp0,rnd,white] MIRP[rp0,rnd,grey] MDRP[rp0,rnd,white] MIRP[rp0,min,rnd,grey] MDRP[rnd,white] MIRP[rp0,rnd,grey] MIRP[min,rnd,grey] IUP[x] PUSHB_1 47 PUSHW_1 259 PUSHB_1 41 PUSHW_1 258 PUSHB_3 18 12 10 PUSHW_1 258 PUSHB_7 24 184 33 96 38 188 1 SVTCA[y-axis] MDAP[rnd] MIRP[rnd,grey] MIRP[min,rnd,grey] MIRP[rp0,rnd,grey] MIRP[rp0,rnd,grey] MDRP[rp0,rnd,white] MDRP[rp0,rnd,grey] MIRP[min,rnd,grey] MIRP[rnd,grey] IUP[y]
cvt_dict = {
...
"w_1001": 71, #1001 =width of kho_kwai
"w_690": 14, #690 =
"front_kai": 11, #113 =front spacing of ko_kai
"hstem": 8, #184 =horizontal stem thick
"headstem": 258, #116 =head stem thick
"headstem_plus_hole": 259, #268 =head stem thick + head hole width
"vheight_shoot": 184, #1147 =overshoot height
"vstem_curve": 185, #156 =curve range vertical stem
...
}
ภาพลายเส้นsrp0 52เคลื่อนไปที่จุดใกล้สุด 33 ด้วยระยะ front_kai
mirp[rp0,min,rnd,grey] front_kai 33กำหนดความหนาของเส้นหน้า ที่จุด 8
mirp[min,rnd,grey] hstem 8เคลื่อนไปกำหนดความกว้างของตัวอักษรที่จุดขวาสุด 39 ด้วยความกว้าง w_1001
mirp[rp0,rnd,grey] w_1001 39กำหนดช่องไฟหลัง
mdrp[rnd,white] 53กำหนดความหนาของเส้นหลัง ที่จุด 1
mirp[min,rnd,grey] hstem 1มาเริ่มกันใหม่ที่จุด 8
srp0 8เคลื่อนลงข้างล่าง สู่จุด 11 (เพื่อจะนำไปสู่ฐานของเส้นหน้า) ให้การแรเงาเป็น white เพื่อแยกเส้นหน้ากับคอของหัวอักษร
mdrp[rp0,rnd,white] 11เนื่องจากเส้นตรงนี้บางมาก จึงกำหนดจุดเพื่อคงระยะอย่างน้อย ที่จุด 27 กำหนดเป็น min
mdrp[min,rnd,grey] 27จากจุด 11 เคลื่อนไปลงจุด 30
mdrp[rp0,rnd,grey] 30กำหนดความหนาของฐาน ที่จุด 29
mirp[min,rnd,grey] hstem 29กลับไปที่จุด 11
srp0 11เคลื่อนไปที่จุด 14 ด้วยการแรเงา white อีกครั้ง เพื่อแยกเส้นให้เด็ดขาด
mdrp[rp0,rnd,white] 14คงความหนาของส่วนคอดไว้
mdrp[min,rnd,grey] 25ย้อนกลับไปตั้งต้นที่จุด 33 อีกครั้งหนึ่ง เพื่อจะสร้างหัวอักษร โดยให้ระยะ จาก 14-49 เป็นตัวรองรับการทดจุด
srp0 33เพื่อความแน่นอนแม่นยำ เราจะเคลื่อนจุดไปหาจุดขวาสุดของหัวอักษร โดยกำหนดค่าเป็น w_690
mirp[rp0,rnd,grey] w_690 20 mirp[min,rnd,grey] headstem 43 mirp[rnd,grey] headstem_plus_hole 49เกลี่ยจุดเป็นคำสั่งสุดท้าย
IUP[x]แนวแกน Y
SVTCA[y-axis]เริ่มที่จุด 0
MDAP[rnd] 0บอกว่าจุด 29 อยู่ในระดับเดียวกัน
ALIGNRP 29เคลื่อนไปกำหนดจุดสูงสุดด้วยค่า vheight_shoot
mirp[rp0,rnd,grey] vheight_shoot 36กำหนดความหนาตรงส่วนนี้ด้วยค่า vstem_curve
mirp[min,rnd,grey] vstem_curve 5จากจุด 36 เดิม เคลื่อนไปส่วนบนของหัวอักษรที่จุด 17 เนื่องจากไม่กังวลระยะมากนัก จึงใช้การเคลื่อนแบบไม่อ้างค่า cvt คือคำสั่ง MDRP
mdrp[rp0,rnd,grey] 17กำหนดขนาดหัวโดยใช้เทคนิกเหมือนเดิม คือกำหนดความหนาด้านบน เคลื่อนไปกำหนดขนาดรวม และกำหนดความหนาด้านล่าง
mirp[min,rnd,grey] headstem 46 mirp[rp0,rnd,grey] headdia 23 mirp[min,rnd,grey] headstem 40ย้ายมาที่จุด 29 เพื่อมากำหนดความหนาตรงจุดนั้น
srp0 29 mdrp[min,rnd,grey] 11เกลี่ยจุดสำคัญ โดยให้ท้องตัวอักษรเป็นจุดเริ่มต้น คือจุด 5 และความหนาของฐานเป็นจุดสิ้นสุด คือจุด 11
srp1 5 srp2 11 sloop 4 ip 33 8 2 39เกลี่ยจุดที่เหลือ
IUP[y]เสร็จแล้ว
View -> Grid Fit -> Show Grid Fit -> 17pt 72dpi
ได้ภาพดังนี้No.of step | -8 | -7 | -6 | -5 | -4 | -3 | -2 | -1 | +1 | +2 | +3 | +4 | +5 | +6 | +7 | +8 |
Selector | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
SVTCA[x-axis]ใส่ delta hint โดยใส่จำนวนคู่ไว้เป็นค่าแรก
deltap1 8 2 143 39 143 0 143 1 143 3 141 38 141 37 139 4 139ภาพหลังการขยับแล้วจะป็นดังนี้
PUSHB_1 49 PUSHW_1 259 PUSHB_1 43 PUSHW_1 258 NPUSHB 22 20 14 33 25 14 11 29 8 30 27 11 8 1 8 53 39 71 8 8 33 11 52 SRP0 MIRP[rp0,min,rnd,grey] MIRP[min,rnd,grey] MIRP[rp0,rnd,grey] MDRP[rnd,white] MIRP[min,rnd,grey] SRP0 MDRP[rp0,rnd,white] MDRP[min,rnd,grey] MDRP[rp0,rnd,grey] MIRP[min,rnd,grey] SRP0 MDRP[rp0,rnd,white] MDRP[min,rnd,grey] SRP0 MIRP[rp0,rnd,grey] MIRP[min,rnd,grey] MIRP[rnd,grey] IUP[x] NPUSHB 10 39 2 8 33 4 11 5 11 29 40 PUSHW_1 258 PUSHB_1 23 PUSHW_1 257 PUSHB_1 46 PUSHW_1 258 PUSHB_7 17 5 185 36 184 29 0 SVTCA[y-axis] MDAP[rnd] ALIGNRP MIRP[rp0,rnd,grey] MIRP[min,rnd,grey] MDRP[rp0,rnd,grey] MIRP[min,rnd,grey] MIRP[rp0,rnd,grey] MIRP[min,rnd,grey] SRP0 MDRP[min,rnd,grey] SRP1 SRP2 SLOOP IP IUP[y] NPUSHB 17 139 4 139 37 141 38 141 3 143 1 143 0 143 39 143 2 8 SVTCA[x-axis] DELTAP1