ศึกษาการทำ TrueType Hinting Instruction
การทำ Truetype Hinting Instructions
$ ttx FONT.ttf
ฟอนต์รุ่นนี้เป็นรุ่นลัดคิว
'ccmp' Glyph Composition/Decomposition in Thai lookup 2"
เล็กน้อย เพื่อให้แสดงระดับวรรณยุกต์ได้ถูกต้อง เราจะให้อยู่ในชื่อ DroidSansThai... <match target="scan"> <test name="family"> <string>Droid Sans Thai</string> </test> <edit name="family"> <string>Droid Sans</string> </edit> <edit name="fullname"> <string>Droid Sans</string> </edit> </match> ... <alias binding="same"> <family>Droid Sans Thai</family> <accept> <family>Droid Sans</family> </accept> </alias> ...
ดาวน์โหลดไฟล์ฟอนต์ (ล่าสุดคือ 20100812)
ดาวน์โหลดไฟล์ซอร์ส
ทดสอบภาษาลาว
ภาพตัวอย่าง
ภาพจากบราวเซอร์ epiphany
ตัวธรรมดา
ตัวหนา
ลัดคิว #3
ทำฟอนต์ DroidSansMono เพิ่ม โดยทำทั้งภาษาไทยและลาว เสียดายที่ต้นฉบับไม่มีตัวหนา เลยทำแค่ตัวธรรมดาอย่างเดียว
ทำเป็นฟอนต์แบบ Monospace แท้ ๆ โดยใช้ต้นแบบตาราง Lookup จากฟอนต์ TlwgTypo
ดาวน์โหลดไฟล์ฟอนต์ (ล่าสุดคือ 20100917)
ดาวน์โหลดไฟล์ซอร์ส
ทดสอบภาษาลาว
ภาพตัวอย่าง
ภาพจากบราวเซอร์ epiphany
ตัวธรรมดา
ลัดคิว #2
ทำฟอนต์ DroidSerif เพิ่ม ถึงจะมีที่ใช้น้อย แต่ก็ทำไว้เพื่อให้แสดงผลได้สมบูรณ์ ทำทั้งภาษาไทยและลาว
Droid Serif ThaiLao
และ font family preferred เป็น Droid Serif
ดังนั้น ถ้าเราติดตั้งฟอนต์ fonts-droid จะสามารถใช้ภาษาไทยและลาวจากฟอนต์ Droid Serif ThaiLao ได้ภายใต้ชื่อ Droid Serif (ยกเว้น Inkscape ต้องใช้ Droid Serif Web แทน)24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ
24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ
24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ
24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ
24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ
24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ
เอา Lomaputta - โลมาบุตร ซึ่งเอามาจากฟอนต์โลมาของ ltn: ThaiFonts-Scalable มาทำเรื่อง hinting
ตอนทำ hinting จริง ๆ ต้องปรับลายเส้นจากเดิมเยอะเหมือนกัน
ดาวน์โหลดไฟล์ฟอนต์(20100602)
ดาวน์โหลดไฟล์ซอร์ส
SROUND
Lomaputta-src-20090506.tar.gzภาพตัวอย่าง
จากบราวเซอร์ epiphany
ตัวธรรมดา
ตัวหนา
เอาฟอนต์นรสีห์จาก ltn: ThaiFonts-Scalable มาทำเรื่อง hinting
แทบไม่เปลี่ยนลายเส้นเลย คงรูปเดิมให้มากที่สุด แปลงแต่จุด เพื่อให้เหมาะกับการทำ hinting
ดาวน์โหลดไฟล์ฟอนต์ (20100625)
ดาวน์โหลดไฟล์ซอร์ส
ภาพตัวอย่าง
จาก Epiphany Browser
ตัวธรรมดา
ตัวหนา
เอาฟอนต์ Roboto มาใส่ภาษาไทย โดยเอาโครงฟอนต์ Roboto (20%) + Droid Sans (30%) + Garuda (50%)
จุดประสงค์คือจะนำไปใช้ทดสอบ Android ICS
Roboto
ใช้งานภายใต้ชื่อ Roboto แต่ต้องมีการลงแพ็กเกจหรือปรับตั้งอื่น ดังนี้fonts-roboto
แล้วสามารถใช้งานผ่านชื่อฟอนต์ Roboto ได้เลย (ยกเว้น Inkscape ให้ใช้ Roboto Web แทน)/system/fonts
แล้วแก้ไขไฟล์ /system/etc/fallback_fonts.xml
เพิ่มบรรทัดดังนี้
... <family> <fileset> <file>RobotoThaiLao-Regular.ttf</file> <file>RobotoThaiLao-Bold.ttf</file> </fileset> </family> ...ยกเว้น RobotoThaiLao-Light และ RobotoThaiLao-Thin ต้องแก้
/system/etc/system_fonts.xml
โดยตรง ดังนี้
... <family> <nameset> <name>sans-serif-light</name> </nameset> <fileset> <file>Roboto-Light.ttf</file> <file>Roboto-LightItalic.ttf</file> <file>RobotoThaiLao-Light.ttf</file> </fileset> </family> <family> <nameset> <name>sans-serif-thin</name> </nameset> <fileset> <file>Roboto-Thin.ttf</file> <file>Roboto-ThinItalic.ttf</file> <file>RobotoThaiLao-Thin.ttf</file> </fileset> </family> ...
24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ
24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ
24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ
24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ
24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ
24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ
24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ
24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ
ทำฟอนต์เพื่อทดแทน Tahoma ตั้งชื่อว่า "เตยหอม" (Taeyhom)
พยายามทำให้คอมแพตกับ Tahoma 100% ยกเว้นตัวเลขไทย ของเดิมความกว้างไม่เท่ากัน แต่ของเราทำให้เท่ากันตามมาตรฐาน
ดาวน์โหลดไฟล์ฟอนต์ (ล่าสุดคือ 20100531)
ดาวน์โหลดไฟล์ซอร์ส
MD, MPPEM, SDPVTL, MUL, DIV, IF, EIF
) ยังงง ๆ อยู่DELTAC
)SROUND
ไปตามขนาด ppem ต่าง ๆ ทำให้ไม่จำเป็นต้องกำหนดค่า cvt ของกั้นหน้ากั้นหลังและความกว้างตัวอักษร (ถ้าใช้ได้ผลจะได้เอาไปใช้ในการสร้างฟอนต์ตัวต่อ ๆ ไป งานจะลดลงมาก) Taeyhom-src-20100503.tar.gzภาพตัวอย่าง
ภาพจากบราวเซอร์ epiphany และ oo.o
ตัวธรรมดาที่ hint แล้ว
ตัวธรรมดา
ตัวหนาที่ hint แล้ว
ตัวหนา
เอา TlwgTypo จาก ltn: ThaiFonts-Scalable มาทำเรื่อง hinting
พอจะเริ่ม hint จริง ๆ พบว่าลายเส้นของไทยไม่เข้ากับของฝรั่ง ซึ่งจะทำให้การ hint ยุ่งยาก จึงตัดสินใจสร้างลายเส้นไทยขึ้นมาใหม่ และตั้งชื่อใหม่ว่า TlwgTypott
ดาวน์โหลดไฟล์ฟอนต์(520421)
ดาวน์โหลดไฟล์ซอร์ส
ภาพตัวอย่าง
จาก abiword (openoffice แสดงผลเพี้ยน)
ตัวธรรมดา
ตัวหนา
ความรู้ที่ได้
เอาฟอนต์ Waree - วารี จาก ltn: ThaiFonts-Scalable มาทำเรื่อง hinting
ต้องขออภัยที่ต้องปรับความกว้างฟอนต์จากเดิม เพื่อให้เหมาะกับการทำ hinting ดังนั้นจึงไม่สามารถใช้แทนกันได้อย่างสนิท
ดาวน์โหลดไฟล์ฟอนต์(รุ่น 20090603)
ดาวน์โหลดไฟล์ซอร์ส
ภาพตัวอย่าง
จาก openoffice.org รุ่น 3.0.1
ตัวธรรมดา
ตัวหนา
เอาลายเส้นจาก Waree Sans มาทำเป็น Monospace แต่ทำเป็นแบบไม่ใช่ความกว้างคงที่แท้ ๆ คือสระและวรรณยุกต์ทำเป็นแบบความกว้างเป็นศูนย์ เพื่อให้ใช้งานกับ Openoffice.org ได้
ทำแล้วดูแล้วยังไม่ค่อยสวย เพราะความกว้างฟอนต์อังกฤษเดิมแคบไป จึงทำให้สัดส่วนฟอนต์ไทยดูสูงชลูดไปหน่อย
ดาวน์โหลดไฟล์ฟอนต์(รุ่น 20090613)
ดาวน์โหลดไฟล์ซอร์ส
ภาพตัวอย่าง
จาก openoffice.org รุ่น 3.0.1
ตัวธรรมดา
ตัวหนา
เอาภาษาไทยจากฟอนต์ DejaVu Serif Thai และภาษาอังกฤษจาก Bitstream Vera Serif มาทำใหม่ ให้ความสูงฟอนต์ไทยเท่ากับ Waree Sans
ภาษาไทยดั้งเดิม เอาแบบมาจาก JS-Saksit (คล้าย Angsana New) จึงพยายามปรับให้หน้าตาออกมาระหว่าง JS-Saksit กับ Bitstream Vera Serif
เนื่องจากเห็นเลขไทยของเก่าสวยมากอยู่แล้ว จึงต้องการคงลักษณะเดิมไว้ แต่มีปัญหาว่าลายเส้นมีความซับซ้อนและมีหลายความหนา hint ออกมาแล้วไม่สวย จึงแก้ปัญหาด้วยการ hint แบบไม่ลงจุด ดังนั้นฟอนต์ชุดนี้จะมี hinting แปลกแยกตรงเลขไทยจะดูนุ่มหน่อยครับ
ดาวน์โหลดไฟล์ฟอนต์(รุ่น 20091124)
ดาวน์โหลดไฟล์ซอร์ส
ภาพตัวอย่าง
จาก openoffice.org รุ่น 3.0.1
ตัวธรรมดา
ตัวหนา
เพิ่งเริ่มทำนะครับ
ขั้นตอน
งาน
งานของฟอนต์ตัวนี้คือ เริ่มศึกษาการทำ ตาราง Lookups - GPOS โดยใช้ภาษาลาวเป็นต้นแบบ คือ
download ttf
download src
screenshot
OpenOffice.org-2.4 แสดงผลที่ ppem ต่าง ๆ
รุ่นล่าสุด 520207
รุ่นแรก
บันทึกการแปลงฟอนต์ 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
บันทึกการสร้างฟอนต์ DejaVu Serif Thai
ผลการทดลอง
ปรับปรุง
(เนื่องจากเป็นการทำงานไปด้วย ศึกษาไปด้วย การทำ hinting จึงไม่เป็นอันหนึ่งอันเดียวกันในทุก ๆ ฟอนต์ที่ทำ ต้องขออภัยด้วย)
ดาวน์โหลดไฟล์ฟอนต์ ttf
ดาวน์โหลดซอร์ส
ภาพตัวอย่าง (จากขนาดจอภาพ 72 dpi จึงกำหนดระยะเป็น ppem แทนเพื่อป้องกันสับสน)
ต้องการทำฟอนต์ที่ใช้ในงานโฆษณา แต่ไม่แปลงรูปฟอนต์มากนัก ให้มีหัวบาง ๆ อยู่ทุกตัว ตั้งชื่อว่า อุโฆษ (Ukhosa) สร้างโดยเอาโครงฟอนต์โลมาบุตรมาแปลง
ดาวน์โหลดไฟล์ฟอนต์ (20100707)
ดาวน์โหลดไฟล์ซอร์ส
ภาพตัวอย่าง
จาก Epiphany Browser
ตัวธรรมดา
ตัวหนา
$ touch dfont.py; chmod 755 dfont.py; vi dfont.py
#!/usr/bin/env python import sys # ins_dict = { "COMMAND" : ("Description",pops,push), ... } # pops,push: 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 ins_dict = { "AA" : ("Adjust Angle", 1, 0), "ABS" : ("ABSolute value", 1, 1), "ADD" : ("ADD", 2, 1), "ALIGNPTS" : ("ALIGN Points", 2, 0), "ALIGNRP" : ("ALIGN to Reference Point", 1, 0), "AND" : ("logical AND", 2, 1), "CALL" : ("CALL function", 1, 0), "CEILING" : ("CEILING", 1, 1), "CINDEX" : ("Copy the INDEXed element to the top of the stack", 1, -1), "CLEAR" : ("CLEAR the stack", -3, 0), "DEBUG" : ("DEBUG call", 1, 0), "DELTAC1" : ("DELTA exception C1", -2, 0), "DELTAC2" : ("DELTA exception C2", -2, 0), "DELTAC3" : ("DELTA exception C3", -2, 0), "DELTAP1" : ("DELTA exception P1", -2, 0), "DELTAP2" : ("DELTA exception P2", -2, 0), "DELTAP3" : ("DELTA exception P3", -2, 0), "DEPTH" : ("DEPTH of the stack", 0, 1), "DIV" : ("DIVide", 2, 1), "DUP" : ("DUPlicate top stack element", 1, 1), "EIF" : ("End IF", 0, 0), "ELSE" : ("ELSE clause", 0, 0), "ENDF" : ("END Function definition", 0, 0), "EQ" : ("EQual", 2, 1), "EVEN" : ("EVEN", 1, 1), "FDEF" : ("Function DEFinition", 1, 0), "FLIPOFF" : ("set the auto FLIP Boolean to OFF", 0, 0), "FLIPON" : ("set the auto FLIP Boolean to ON", 0, 0), "FLIPPT" : ("FLIP PoinT", 1, 0), "FLIPRGOFF" : ("FLIP RanGe OFF", 2, 0), "FLIPRGON" : ("FLIP RanGe ON", 2, 0), "FLOOR" : ("FLOOR", 2, 0), "GC" : ("Get Coordinate projected onto the projection vector", 1, 1), "GETINFO" : ("GET INFOrmation", 1, 1), "GFV" : ("Get Freedom Vector", 0, 2), "GPV" : ("Get Projection Vector", 0, 2), "GT" : ("Greater Than", 2, 1), "GTEQ" : ("Greater Than or EQual", 2, 1), "IDEF" : ("Instruction DEFinition", 1, 0), "IF" : ("IF test", 1, 0), "INSTCTRL" : ("INSTRuction execution ConTRoL", 2, 0), "IP" : ("Interpolate Point", 1, 0), "ISECT" : ("moves point p to the InterSECTion of two lines", 5, 0), "IUP" : ("Interpolate Untouched Points through the outline", 0, 0), "JMPR" : ("JuMP Relative", 1, 0), "JROF" : ("Jump Relative On False", 1, 0), "JROT" : ("Jump Relative On True", 3, 0), "LOOPCALL" : ("LOOP and CALL function", 2, 0), "LT" : ("Less Than", 2, 1), "LTEQ" : ("Less Than or Equal", 2, 1), "MAX" : ("MAXimum of top two stack elements", 2, 1), "MD" : ("Measure Distance", 2, 1), "MDAP" : ("Move Direct Absolute Point", 1, 0), "MDRP" : ("Move Direct Relative Point", 1, 0), "MIAP" : ("Move Indirect Absolute Point", 2, 0), "MIN" : ("MINimum of top two stack elements", 2, 1), "MINDEX" : ("Move the INDEXed element to the top of the stack", 1, 3), "MIRP" : ("Move Indirect Relative Point", 2, 0), "MPPEM" : ("Measure Pixels Per EM", 0, 1), "MPS" : ("Measure Point Size", 0, 1), "MSIRP" : ("Move Stack Indirect Relative Point", 1, 0), "MUL" : ("MULtiply", 2, 1), "NEG" : ("NEGate", 1, 1), "NEQ" : ("Not EQual", 2, 1), "NOT" : ("logical NOT", 1, 1), "NPUSHB" : ("PUSH N Bytes", -1, 0), "NPUSHW" : ("PUSH N Words", -1, 0), "NROUND" : ("No ROUNDing of value", 1, 1), "ODD" : ("ODD", 1, 1), "OR" : ("logical OR", 2, 1), "POP" : ("POP top stack element", 1, 0), "PUSHB" : ("PUSH Bytes", -4, 0), "PUSHW" : ("PUSH Words", -4, 0), "RCVT" : ("Read Control Value Table entry", 1, 1), "RDTG" : ("Round Down To Grid", 0, 0), "ROFF" : ("Round OFF", 0, 0), "ROLL" : ("ROLL the top three stack elements", 3, 3), "ROUND" : ("ROUND value", 1, 1), "RS" : ("Read Store", 1, 1), "RTDG" : ("Round To Double Grid", 0, 0), "RTG" : ("Round To Grid", 0, 0), "RTHG" : ("Round To Half Grid", 0, 0), "RUTG" : ("Round Up To Grid", 0, 0), "S45ROUND" : ("Super ROUND 45 degrees", 1, 0), "SANGW" : ("Set Angle Weight", 1, 0), "SCANCTRL" : ("SCAN conversion ConTRoL", 1, 0), "SCANTYPE" : ("SCANTYPE", 1, 0), "SCFS" : ("Sets Coordinate From the Stack using projection vector and freedom vector", 2, 0), "SCVTCI" : ("Set Control Value Table Cut-In", 1, 0), "SDB" : ("Set Delta Base in the graphics state", 1, 0), "SDPVTL" : ("Set Dual Projection Vector To Line", 2, 0), "SDS" : ("Set Delta Shift in the graphics state", 1, 0), "SFVFS" : ("Set Freedom Vector From Stack", 2, 0), "SFVTCA" : ("Set Freedom Vector To Coordinate Axis", 0, 0), "SFVTL" : ("Set Freedom Vector To Line", 2, 0), "SFVTP" : ("Set Freedom Vector To Projection Vector", 0, 0), "SHC" : ("SHift Contour using reference point", 1, 0), "SHP" : ("SHift Point using reference point", 1, 0), "SHPIX" : ("SHift point by a PIXel amount", 2, 0), "SHZ" : ("SHift Zone using reference point", 1, 0), "SLOOP" : ("Set LOOP variable", 1, 0), "SMD" : ("Set Minimum Distance", 1, 0), "SPVFS" : ("Set Projection Vector From Stack", 2, 0), "SPVTCA" : ("Set Projection Vector To Coordinate Axis", 0, 0), "SPVTL" : ("Set Projection Vector To Line", 2, 0), "SROUND" : ("Super ROUND", 1, 0), "SRP0" : ("Set Reference Point 0", 1, 0), "SRP1" : ("Set Reference Point 1", 1, 0), "SRP2" : ("Set Reference Point 2", 1, 0), "SSW" : ("Set Single Width", 1, 0), "SSWCI" : ("Set Single Width Cut-In", 1, 0), "SUB" : ("SUBtract", 2, 1), "SVTCA" : ("Set freedom and projection Vectors To Coordinate Axis", 0, 0), "SWAP" : ("SWAP the top two elements on the stack", 2, 2), "SZP0" : ("Set Zone Pointer 0", 1, 0), "SZP1" : ("Set Zone Pointer 1", 1, 0), "SZP2" : ("Set Zone Pointer 2", 1, 0), "SZPS" : ("Set Zone PointerS", 1, 0), "UTP" : ("UnTouch Point", 1, 0), "WCVTF" : ("Write Control Value Table in Funits", 1, 0), "WCVTP" : ("Write Control Value Table in Pixel units", 2, 0), "WS" : ("Write Store", 2, 0), } stack1_command = ("NPUSHB", "NPUSHW") stack2_command = ("PUSHB", "PUSHW") normal_command = [] for i in range(6): normal_command.append( [ j for j in ins_dict.keys() if ins_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 ins_dict.keys() if ins_dict[j][1]==i ] ) def line_format(cmd,stack,desc): #STRING, LIST, STRING return "%-24s %-10s ;%10s" % (cmd, " ".join(stack), desc,) def ins_decode(txt): txtlist = txt.split("\n") newlist = [] commentlist = [] stacklist = [] sloop = 0 i = 0 while i < len(txtlist): if "[" in txtlist[i]: c1,c2 = txtlist[i].strip().split("[",1) else: c1,c2 = txtlist[i].strip(), "" #SKIP EMPTY LINE if c1 == "": i += 1 continue #STACK: NPUSHB, NPUSHW if c1 in stack1_command: i += 1 n = int(txtlist[i].strip()) i += 1 while n > 0: stacklist.append(txtlist[i].strip()) i += 1 n -= 1 continue #STACK2: PUSHB, PUSHW if c1[:5] in stack2_command: n = int(txtlist[i].strip()[6:]) i += 1 while n > 0: stacklist.append(txtlist[i].strip()) i += 1 n -= 1 continue temp_list = [] #POP ONE if c1 in pop_command[1]: idx = stacklist.pop() temp_list = [idx] for j in range(int(idx)): temp_list.append(stacklist.pop()) newlist.append(line_format(txtlist[i],temp_list,ins_dict[c1][0])) i += 1 continue #POP PAIR elif c1 in pop_command[2]: idx = stacklist.pop() temp_list = [idx] for j in range(int(idx)): temp_list.append(stacklist.pop()) temp_list.append(stacklist.pop()) newlist.append(line_format(txtlist[i],temp_list,ins_dict[c1][0])) i += 1 continue #POP ALL (CLEAR STACK) elif c1 in pop_command[3]: stacklist = [] newlist.append(line_format(txtlist[i],temp_list,ins_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 if count > 0: if sloop > 0: count += sloop-1 sloop = 0 while count > 0: cnum = stacklist.pop() temp_list.append(cnum) if c1 == 'SLOOP': sloop = int(cnum) count -= 1 newlist.append(line_format(txtlist[i],temp_list,ins_dict[c1][0])) i += 1 print '--------------------------------------' print '\n'.join(newlist) if __name__ == "__main__": txt = sys.argv[1] ins_decode(txt)เนื่องจากทำแบบหยาบ ๆ ใช้ลำบากหน่อย
$ ./dfont.py "
แปะด้วยโค๊ดที่คัดลอกมาจากฟอนต์ อักขระ n
"
ได้ผลเป็น
SRP0 20 ;Set Reference Point 0 MIRP[rp0,min,rnd,grey] 70 11 ;Move Indirect Relative Point MIRP[min,rnd,grey] 8 9 ;Move Indirect Relative Point SHP[rp2] 13 ;SHift Point using reference point MIRP[rp0,rnd,grey] 78 0 ;Move Indirect Relative Point MIRP[min,rnd,grey] 8 2 ;Move Indirect Relative Point 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 10 ;ALIGN to Reference Point MIRP[rnd,grey] 188 12 ;Move Indirect Relative Point MIRP[rp0,rnd,grey] 184 17 ;Move Indirect Relative Point MDRP[rnd,grey] 14 ;Move Direct Relative Point MIRP[min,rnd,grey] 135 6 ;Move Indirect Relative Point 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] ;Set freedom and projection Vectors To Coordinate Axis DELTAP1 2 21 207 21 96 ;DELTA exception P1ทดสอบอีกอันนึง เป็นอักขระ a
SRP0 38 ;Set Reference Point 0 MIRP[rp0,min,rnd,grey] 69 20 ;Move Indirect Relative Point MIRP[min,rnd,grey] 8 3 ;Move Indirect Relative Point MDRP[min,rnd,grey] 31 ;Move Direct Relative Point MDRP[rp0,rnd,grey] 11 ;Move Direct Relative Point MIRP[min,rnd,grey] 8 9 ;Move Indirect Relative Point SHP[rp2] 13 ;SHift Point using reference point SHP[rp2] 24 ;SHift Point using reference point SRP1 3 ;Set Reference Point 1 IP 23 ;Interpolate Point IP 0 ;Interpolate Point IUP[x] ;Interpolate Untouched Points through the outline SVTCA[y-axis] ;Set freedom and projection Vectors To Coordinate Axis MDAP[rnd] 12 ;Move Direct Absolute Point MDRP[rnd,grey] 23 ;Move Direct Relative Point MIRP[rnd,grey] 140 17 ;Move Indirect Relative Point MIRP[rp0,rnd,grey] 184 35 ;Move Indirect Relative Point MIRP[rp0,min,rnd,grey] 185 28 ;Move Indirect Relative Point MIRP[rp0,rnd,grey] 186 31 ;Move Indirect Relative Point MIRP[min,rnd,grey] 134 32 ;Move Indirect Relative Point SRP0 17 ;Set Reference Point 0 MDRP[rnd,white] 14 ;Move Direct Relative Point MIRP[min,rnd,white] 185 6 ;Move Indirect Relative Point SRP0 23 ;Set Reference Point 0 MIRP[min,rnd,white] 169 0 ;Move Indirect Relative Point SRP1 14 ;Set Reference Point 1 IP 9 ;Interpolate Point SRP1 23 ;Set Reference Point 1 IP 11 ;Interpolate Point SRP2 31 ;Set Reference Point 2 IP 25 ;Interpolate Point IUP[y] ;Interpolate Untouched Points through the outline DELTAP1 24 33 128 32 128 31 128 30 128 33 112 32 112 31 112 30 112 33 96 32 96 31 96 30 96 33 80 32 80 31 80 30 80 33 64 32 64 31 64 30 64 33 48 32 48 31 48 30 48 ;DELTA exception P1 SVTCA[x-axis] ;Set freedom and projection Vectors To Coordinate Axis DELTAP1 30 39 240 39 160 39 144 34 133 33 135 32 135 31 135 30 135 29 133 39 112 39 80 34 80 33 80 32 80 31 80 30 80 29 80 34 64 33 64 32 64 31 64 30 64 29 64 39 63 34 48 33 48 32 48 31 48 30 48 29 48 ;DELTA exception P1
$ vi dfont.py
... def stack_format(stacklist): def flush(newlist, templist, ind, cur_ind): if ind == 0: newlist.append('NPUSHB') else: newlist.append('NPUSHW') newlist.append(' %s' % len(templist)) newlist.extend(templist) return newlist, [], cur_ind if len(stacklist)==0: return [] n = 0 newlist = [] templist = [] if int(stacklist[0]) < 256: ind = 0 else: ind = 1 while n < len(stacklist): if int(stacklist[n]) < 256: cur_ind = 0 else: cur_ind = 1 if ind == cur_ind: templist.insert(0,' '+stacklist[n]) else: newlist, templist, ind = flush(newlist, templist, ind, cur_ind) #FLUSH n += 1 newlist, templist, ind = flush(newlist, templist, ind, cur_ind) #FLUSH return newlist def ins_encode(txt): """Encode simple code into TrueType Instruction code""" comment_list = ['#',';'] #COMMENT CHARACTER flush_list = ['SVTCA'] #FLUSH STACK stacklist = [] newlist = [] templist = [] txtlist = txt.split('\n') for line in txtlist: 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)]: newlist.extend(stack_format(stacklist)) stacklist = [] newlist.extend(templist) templist = [] break if '[' in l[0]: #TO UPPERCASE ltemp = l[0].split('[',1) temp = ltemp[0].upper()+'['+ltemp[1] else: temp = l[0].upper() templist.append(temp) #KEEP COMMAND l.pop(0) #PROCESS REST STACK NUM for element in l: if element[0] in comment_list: break else: stacklist.append(element) if stacklist != []: newlist.extend(stack_format(stacklist)) newlist.extend(templist) print '===Encode===============================' print '\n'.join(newlist) if __name__ == "__main__": txt = sys.argv[1] #ins_decode(txt) ins_encode(txt)ทดสอบด้วยตัวอย่าง n เมื่อกี้นี้
$ dfont.py "
แปะด้วยโค๊ดเทียมที่ถูกคลี่แล้ว จากตัวอย่าง n
"
===Encode=============================== NPUSHB 10 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] NPUSHB 15 3 9 0 3 14 1 6 135 14 17 184 12 188 10 1 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] NPUSHB 5 96 21 207 21 2 SVTCA[x-axis] DELTAP1ไม่เหมือนเป๊ะ แต่น่าจะทำงานได้เหมือนกัน