fonts: TrueType Hinting Instruction

ศึกษาการทำ TrueType Hinting Instruction

ลิงก์

การทำ Truetype Hinting Instructions

ตัวอย่างไฟล์

ไฟล์ DejaVuSansThai.tar.gz

Topic: 

fonts: บันทึก DroidSans+Thai+Lao

ฟอนต์รุ่นนี้เป็นรุ่นลัดคิว

  1. งานคือเอาฟอนต์ DroidSansThai ของกูเกิล รุ่นที่เป็นแอนดรอยด์ 2.2 ลงไป (อาจจะเป็นชื่อ DroidSansThai.ttf หรือ DroidThai-Regular.ttf) มาทำตัวหนาเพิ่มแบบหยาบ ๆ โดยมีการดัดแปลงสคริปต์ 'ccmp' Glyph Composition/Decomposition in Thai lookup 2" เล็กน้อย เพื่อให้แสดงระดับวรรณยุกต์ได้ถูกต้อง เราจะให้อยู่ในชื่อ DroidSansThai
    รุ่นนี้ เนื่องจากมีเแต่ภาษาไทย ดังนั้นถ้านำมาใช้ในลินุกซ์จะต้องสร้างไฟล์ fontconfig ประมาณนี้ (ยังไม่ได้ทดสอบ)

    ...
      <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>
    ...
  2. อีกงานนึงคือเอาอักขระไทยจาก DroidSansThai สอดเข้าไปในฟอนต์ DroidSans เพื่อให้โทรศัพท์แอนดรอยด์ใช้งานฟอนต์ตัวนี้ได้ อันนี้จะอยู่ในชื่อ DroidSans (เสียดายที่แอนดรอยด์ไม่รองรับตาราง OpenType การแสดงวรรณยุกต์จึงยังลอยอยู่)

ดาวน์โหลดไฟล์ฟอนต์ (ล่าสุดคือ 20100812)

  1. DroidSansThai-ttf.tar.gz
  2. DroidSans-ttf.tar.gz (สำหรับใช้กับโทรศัพท์แอนดรอยด์)
ข้อความด้านล่างเป็นการแสดงผลจากหน้าเว็บด้วยฟอนต์นี้ (จากความสามารถของ css3)

ดาวน์โหลดไฟล์ซอร์ส

ทดสอบภาษาลาว

  • ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝ
  • ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝ

ภาพตัวอย่าง
ภาพจากบราวเซอร์ epiphany
ตัวธรรมดา

ตัวหนา

Topic: 

fonts: บันทึก DroidSansMono+Thai+Lao

ลัดคิว #3
ทำฟอนต์ DroidSansMono เพิ่ม โดยทำทั้งภาษาไทยและลาว เสียดายที่ต้นฉบับไม่มีตัวหนา เลยทำแค่ตัวธรรมดาอย่างเดียว
ทำเป็นฟอนต์แบบ Monospace แท้ ๆ โดยใช้ต้นแบบตาราง Lookup จากฟอนต์ TlwgTypo

ดาวน์โหลดไฟล์ฟอนต์ (ล่าสุดคือ 20100917)

ข้อความด้านล่างเป็นการแสดงผลจากหน้าเว็บด้วยฟอนต์นี้ (จากความสามารถของ css3)

ดาวน์โหลดไฟล์ซอร์ส

ทดสอบภาษาลาว

  • ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝ

ภาพตัวอย่าง
ภาพจากบราวเซอร์ epiphany
ตัวธรรมดา

fonts: บันทึก DroidSerif+Thai+Lao

ลัดคิว #2
ทำฟอนต์ DroidSerif เพิ่ม ถึงจะมีที่ใช้น้อย แต่ก็ทำไว้เพื่อให้แสดงผลได้สมบูรณ์ ทำทั้งภาษาไทยและลาว

update

  • 561227: Google เปลี่ยนชื่อฟอนต์ Droid Serif เป็น Noto Serif ไฟล์ต้นฉบับเป็นภาษาอังกฤษ+ละติน และแยกไฟล์ออกมาอีกหลายภาษา (รวมทั้งไทยและลาว) ดาวน์โหลดได้ที่ code.google.com:noto
  • 561228: เปลี่ยน Droid Serif เป็น Droid Serif Web ป้องกันการสับสน มี อังกฤษ ละติน ไทย ลาว และปรับ Glyph ใหม่หมด
  • 570219:
    • เอาฐานฟอนต์ Droid Serif ของกูเกิลรุ่นล่าสุด คือ 1.0.3 มาทำ Droid Serif Web
    • เอาฐานฟอนต์ Noto Sans Thai มาทำ Droid Serif ThaiLao โดยให้ชื่อ font family เป็น Droid Serif ThaiLao และ font family preferred เป็น Droid Serif ดังนั้น ถ้าเราติดตั้งฟอนต์ fonts-droid จะสามารถใช้ภาษาไทยและลาวจากฟอนต์ Droid Serif ThaiLao ได้ภายใต้ชื่อ Droid Serif (ยกเว้น Inkscape ต้องใช้ Droid Serif Web แทน)

Droid Serif (ต้นฉบับ+ไทย+ลาว) - เลิกทำแล้ว (จริง ๆ คือเปลี่ยนชื่อเป็น Droid Serif Web แทน ป้องกันสับสน)

ดาวน์โหลดไฟล์ฟอนต์ (ล่าสุดคือ 20100914)
DroidSerif-ttf.tar.gz
ดาวน์โหลดไฟล์ซอร์ส
  • รุ่นร่าง ยังไม่ได้ทำ hint : DroidSerif-src-20100823.tar.gz
  • เสร็จแบบยังไม่มี hint ลดความกว้างลงเล็กน้อย : DroidSerif-src-20100914.tar.gz
  • ตัวอย่าง

    24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
    aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
    ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ

    24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
    aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
    ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ


    Droid Serif ThaiLao (มีเฉพาะภาษาไทย+ลาว)

    ดาวน์โหลดไฟล์ฟอนต์ (ล่าสุดคือ 20140219)
    DroidSerifThaiLao-ttf.tar.gz
    ดาวน์โหลดไฟล์ซอร์ส
  • ปรับ glyph ใหม่หมดให้ดูสง่าขึ้น ลดช่องไฟตัวหนาให้ดูกระชับ เพิ่ม glyph ภาษาลาว (ขมุ-ก และ ขมุ-ญ) รุ่นนี้มีการเปลี่ยนความกว้างฟอนต์หลายตัว จึงไม่ compat กับของเก่าเลย : DroidSerifThaiLao-src-20131227.tar.gz
  • แต่งตัวเลขไทย : DroidSerifThaiLao-src-20140104.tar.gz
  • ปรับฐานใหม่ ให้ใช้งานภายใต้ชื่อ Droid Serif ได้ : DroidSerifThaiLao-src-20140219.tar.gz
  • ตัวอย่าง

    24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
    aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
    ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ

    24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
    aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
    ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ


    Droid Serif Web (อังกฤษ+ละติน+ไทย+ลาว)

    ดาวน์โหลดไฟล์ฟอนต์ (ล่าสุดคือ 20140219)
    DroidSerifWeb-ttf.tar.gz
    ดาวน์โหลดไฟล์ซอร์ส
  • DroidSerifWeb-src-20131227.tar.gz
  • แต่งตัวเลขไทย : DroidSerifWeb-src-20140104.tar.gz
  • ปรับฐานเป็นรุ่นล่าสุด : DroidSerifWeb-src-20140219.tar.gz
  • ตัวอย่าง

    24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
    aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
    ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ

    24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
    aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
    ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ

    Topic: 

    fonts: บันทึก Lomaputta

    เอา Lomaputta - โลมาบุตร ซึ่งเอามาจากฟอนต์โลมาของ ltn: ThaiFonts-Scalable มาทำเรื่อง hinting

    ตอนทำ hinting จริง ๆ ต้องปรับลายเส้นจากเดิมเยอะเหมือนกัน

    ดาวน์โหลดไฟล์ฟอนต์(20100602)

    ดาวน์โหลดไฟล์ซอร์ส

    • รุ่นเริ่มต้น ยังไม่มีตัวหนา ฟอนต์ไทย hint ด้วยมือ ส่วนฟอนต์อังกฤษ ใช้ Auto-Instruction แบบช่วยปรับแต่งเล็กน้อย (การปรับแต่งยังไม่ดีนัก เพราะโค๊ด dfont.py ยังไม่เข้าที่ รอรุ่นหน้าต่อไป :) Lomaputta-src-520501.tar.gz
    • ตัวหนาเกือบเสร็จ เปลี่ยนการเดินจุดให้อัตโนมัติมากขึ้น ด้วยคำสั่ง SROUND Lomaputta-src-20090506.tar.gz
    • ตัวหนาเสร็จแล้ว Lomaputta-src-20090511.tar.gz
    • แก้บั๊กสระ 'แ' ใน openoffice.org-3.0.1 พิมพ์ไม่ออก Lomaputta-src-20090518.tar.gz - แก้โดยการเติมจุดเปล่าที่ช่อง uni0E00 (ข้างหน้า 'ก') แล้ว copy reference มาผสมลงในช่องสระแอ (วิธีพิสดารหน่อย อนาคตอาจเอาออก) เป็นบั๊กทางโปรแกรมมิ่งของผมเอง แก้ไขเรียบร้อยแล้วครับ
    • ปรับปรุงสระและวรรณยุกต์เหนืออักษรมีหางบน (ป ฝ ฟ ฬ) ให้แยกจากตัวอักษรมากขึ้น Lomaputta-src-20100119.tar.gz
    • ทำ hinting ภาษาอังกฤษเพิ่ม Lomaputta-src-20100531.tar.gz
    • ปรับ hint ให้เส้นนอนนุ่มนวลขึ้น แก้ปาก ก.ไก่ ให้หนาขึ้น แก้เส้นหลัง ร.เรือ ให้คมขึ้น Lomaputta-src-20100602.tar.gz

    ภาพตัวอย่าง
    จากบราวเซอร์ epiphany
    ตัวธรรมดา

    ตัวหนา

    Topic: 

    fonts: บันทึก Norasiputta

    เอาฟอนต์นรสีห์จาก ltn: ThaiFonts-Scalable มาทำเรื่อง hinting

    แทบไม่เปลี่ยนลายเส้นเลย คงรูปเดิมให้มากที่สุด แปลงแต่จุด เพื่อให้เหมาะกับการทำ hinting

    ดาวน์โหลดไฟล์ฟอนต์ (20100625)

    ข้อความด้านล่างเป็นการแสดงผลจากหน้าเว็บด้วยฟอนต์นี้ (จากความสามารถของ css3)

    ดาวน์โหลดไฟล์ซอร์ส

    • รุ่นเริ่มต้น ยังไม่มีตัวหนา ฟอนต์ไทย hint ด้วยมือ ส่วนฟอนต์อังกฤษ ใช้ Auto-Instruction แบบช่วยปรับแต่งเล็กน้อย Norasiputta-src-520702.tar.gz
    • ตัวหนาเสร็จแบบยังไม่ได้เกลา Norasiputta-src-520707.tar.gz
    • รื้อมาทำใหม่ จุดประสงค์คือต้องการทำเป็นฟอนต์สำหรับดูหน้าจอภาพ ด้วยการเพิ่มความหนา stem ไทย เปลี่ยน glyph ภาษาอังกฤษ โดยเอาฐานมาจากฟอนต์ Dustismo Roman และ Droid Serif เพื่อให้ดูกลมกลืนกับ glyph ไทย รุ่นนี้จึงถือเป็นรุ่นร่าง ยังไม่มี hint - Norasiputta-src-20100610.tar.gz
    • ตัวธรรมดา hint หยาบเสร็จ - Norasiputta-src-20100618.tar.gz
    • ตัวหนาเสร็จ ตรวจสอบการแสดงผลไปเรื่อย ๆ - Norasiputta-src-20100625.tar.gz

    ภาพตัวอย่าง
    จาก Epiphany Browser
    ตัวธรรมดา

    ตัวหนา

    Topic: 

    fonts: บันทึก Roboto

    เอาฟอนต์ Roboto มาใส่ภาษาไทย โดยเอาโครงฟอนต์ Roboto (20%) + Droid Sans (30%) + Garuda (50%)

    จุดประสงค์คือจะนำไปใช้ทดสอบ Android ICS

    Update

    • 20140220
      • เลิกทำภายใต้ชื่อ Roboto เฉย ๆ แต่เปลี่ยนเป็น Roboto Web แทน ซึ่งจะมีภาษาอังกฤษ, ละติน, ไทย และลาว ใช้งานภายใต้ชื่อ Roboto Web
      • ทำรุ่นที่มีเฉพาะไทยกับลาวภายใต้ชื่อ Roboto ThaiLao โดยตึ้งค่า perferred family เป็น Roboto ใช้งานภายใต้ชื่อ Roboto แต่ต้องมีการลงแพ็กเกจหรือปรับตั้งอื่น ดังนี้
        • สำหรับเดสก์ทอป ลงแพ็กเกจชื่อ fonts-roboto แล้วสามารถใช้งานผ่านชื่อฟอนต์ Roboto ได้เลย (ยกเว้น Inkscape ให้ใช้ Roboto Web แทน)
        • สำหรับโทรศัพท์แอนดรอยด์ ให้นำ RobotoThaiLao-*.ttf ใส่ใน /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>
          ...
          

    Roboto (ต้นฉบับ+ไทย+ลาว) - เลิกทำแล้ว (จริง ๆ คือเปลี่ยนชื่อเป็น Roboto Web แทน ป้องกันสับสน)

    ดาวน์โหลดไฟล์ฟอนต์ (ล่าสุดคือ 20121003)
    Roboto-ttf.tar.gz
    ดาวน์โหลดไฟล์ซอร์ส
  • รุ่นร่างเริ่มต้น ยังไม่ได้ทำ hint ยังไม่ได้ทำภาษาลาว (ใช้ของเดิมที่เป็นของ Droid Sans ที่ทำไว้ก่อนแล้ว) เพิ่มการรองรับภาษาบาลี (lang="pi"): Roboto-src-20121003.tar.gz
  • ตัวอย่าง

    24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
    aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
    ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ

    24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
    aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
    ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ


    Roboto ThaiLao (มีเฉพาะภาษาไทย+ลาว)

    ดาวน์โหลดไฟล์ฟอนต์ (ล่าสุดคือ 20140225)
    RobotoThaiLao-ttf.tar.gz
    ดาวน์โหลดไฟล์ซอร์ส
  • ใช้ฐานฟอนต์ของ Noto Sans Thai และ Roboto ต้นฉบับ เกลาภาษาไทยเล็กน้อย ทำ Glyph ภาษาลาวใหม่ให้สอดคล้องกับรูปแบบของ Roboto (ภาษาลาวมีการเปลี่ยนความกว้าง ไม่คอมแพตกับของเดิม) : RobotoThaiLao-src-20140221.tar.gz
  • เพิ่ม Light : RobotoThaiLao-src-20140225.tar.gz
  • ตัวอย่าง

    24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
    aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
    ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ

    24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
    aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
    ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ

    24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
    aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
    ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ


    Roboto Web (อังกฤษ+ละติน+ไทย+ลาว)

    ดาวน์โหลดไฟล์ฟอนต์ (ล่าสุดคือ 20140225)
    RobotoWeb-ttf.tar.gz
    ดาวน์โหลดไฟล์ซอร์ส
  • รุ่นแรก ใส่ตัวละตินยังไม่ครบ : RobotoWeb-src-20140221.tar.gz
  • เพิ่ม Light : RobotoWeb-src-20140225.tar.gz
  • ตัวอย่าง

    24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
    aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
    ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ

    24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
    aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
    ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ

    24!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_` Aabcdefghijklmnopqrstuvwxyz{|}~ mrnrtodocode ṃāñūṭḍṇṅ
    aกัขิฃีคึฅืฆุงูจฺฉ็ช่ซ้ฌ๊ญ๋ญุฎ์ฏํฐ๎ฐูฑั่ฒิ้ณี๊ดื๋ติ์ถะทาธำน่ำเบี่แปิํโผใฝ่ไพฟ้ภมยรฤๅลฦวศษสหฬอฮฯๆ ฿๏๐๑๒๓๔๕ ๖๗๘๙๚๛ ก่ป่ฝ้ฟ๊ฬ๋ คฅศ ดตฒ ญฐญานํ ญฐญานํ โสตฺถิํ
    ກະຂັຄາງ່ຳຈິ່ຊີ້ຍຶ໊ດື໋ຕຸ່ຖູ້ທົ໊ນຼ໋ເບແປໂຜໃຝໄພຟ່ມ້ຢ໊ຣ໋ລ໌ວໍສຫອຮຯຽໆ ໐໑໒໓໔໕໖໗໘໙ ໜໝໞໟ

    Topic: 

    fonts: บันทึก Taeyhom

    ทำฟอนต์เพื่อทดแทน Tahoma ตั้งชื่อว่า "เตยหอม" (Taeyhom)

    พยายามทำให้คอมแพตกับ Tahoma 100% ยกเว้นตัวเลขไทย ของเดิมความกว้างไม่เท่ากัน แต่ของเราทำให้เท่ากันตามมาตรฐาน

    ดาวน์โหลดไฟล์ฟอนต์ (ล่าสุดคือ 20100531)

    ดาวน์โหลดไฟล์ซอร์ส

    • รุ่นร่างเริ่มต้น ยังไม่ได้ทำ hint ยังไม่ได้เกลาละเอียด Taeyhom-src-20100305.tar.gz
    • ทำ hint ตัวธรรมดาเสร็จ Taeyhom-src-20100327.tar.gz บันทึก - ลองเพิ่มจุดอ้างอิงเพื่อมัดติดกับจุดสมอ แต่พบว่าจุดสมอไม่เลื่อนไปตามจุดอ้างอิงที่ถูก hint เราต้องเผื่อเอาเอง
    • รุ่นพักเหนื่อย - ทำ hint ตัวหนาเสร็จ และกลับมาเกลาตัวธรรมดาจนเกือบเสร็จ Taeyhom-src-20100410.tar.gz
      บันทึก - ทดลองใช้ฟังก์ชั่นใหม่ ๆ หลายตัว (MD, MPPEM, SDPVTL, MUL, DIV, IF, EIF) ยังงง ๆ อยู่
    • รุ่นพักยก - เปลี่ยนการวางอักขระยึดตาม tlwg เพื่อให้เข้ากันได้กับเอกสารทั่วไป ตัวธรรมดาเกลาจนดีแล้ว แต่พบปัญหาว่าตัวบางเกินไป จึงเก็บโค๊ดไว้ก่อน รุ่นหน้าจะทำตามมาตรฐานที่ควรเป็นเสียที Taeyhom-src-20100413.tar.gz
      บันทึก
      • ปรับโค๊ด dfont.py หลายจุด ตอนนี้สามารถถอดโค๊ดฟอนต์ทั่วไปได้แล้ว
      • การ hint ที่ผ่านมา เดินเส้น stem แบบไม่ปัดให้เต็ม จุดประสงค์คือให้ดูนุ่มนวล แต่พบปัญหาคือ เราไม่สามารถเติมเส้นให้เต็มในขนาด ppem วิกฤต (14,15,16ppem) คือไม่ขาดนิดนึงก็เกินนิดนึง ถ้าขาด ฟอนต์จะดูบาง ถ้าเกิน ฟอนต์จะดูฟุ้ง รุ่นต่อไปจะปัดให้เส้นเต็มจนถึง 32 ppem แล้วจึงปล่อย น่าจะทำให้ดูดีขึ้น
    • รุ่นพักยก2 - ตัวธรรมดาเปลี่ยนเยอะมาก แต่ตัวหนายังไม่ได้เปลี่ยน รอดูผลสักพัก Taeyhom-src-20100417.tar.gz
      บันทึก
      • เริ่มใช้ function call
      • เปลี่ยนการ hint มาเป็นแบบเต็มเส้นจนถึง 42ppem แล้วจึงปล่อย
      • เริ่มใช้ตาราง prep โดยส่วนใหญ่จะใช้ในการแทนค่า cvt เพื่อให้ขนาดเส้นดูสม่ำเสมอ จนถึง 42ppem (DELTAC)
    • รุ่นอีกนิดเดึยว - ออกเพื่อพักเหนื่อย เหลือเกลาตัวหนา และปรับให้กลไกมาเหมือนกับตัวธรรมดา Taeyhom-src-20100421.tar.gz
      บันทึก
      • สงสัยว่าทำไม่ใช้กับวินโดวส์ไม่สวยเลย
    • เสร็จแล้วครับ - แต่คงยังมีบั๊กอีกเยอะ Taeyhom-src-20100423.tar.gz
    • แก้บั๊กหลายจุด และปรับปรุงความฟุ้ง Taeyhom-src-20100428.tar.gz
    • รุ่นทดลอง - สร้างฟังก์ชั่นหาจุดลงตัวของ stem หน้าหลัง และฟังก์ชั่นปรับเปลี่ยนค่า SROUND ไปตามขนาด ppem ต่าง ๆ ทำให้ไม่จำเป็นต้องกำหนดค่า cvt ของกั้นหน้ากั้นหลังและความกว้างตัวอักษร (ถ้าใช้ได้ผลจะได้เอาไปใช้ในการสร้างฟอนต์ตัวต่อ ๆ ไป งานจะลดลงมาก) Taeyhom-src-20100503.tar.gz
    • รุ่นทดลองที่เริ่มลงตัว - ทำกับตัวหนาอย่างเดียว Taeyhom-src-20100511.tar.gz
    • เสร็จ - รอตรวจบั๊กไปเรื่อย ๆ Taeyhom-src-20100512.tar.gz
    • เปลี่ยนเทคนิกลดความฟุ้งที่หัวอักษร ย้ายการลดความฟุ้งจากเส้นตั้งเป็นเส้นนอน ทำให้ได้ความกลมและแยกแยะอักขระได้ดีขึ้น ความเปรียบต่างสูงขึ้น Taeyhom-src-20100516.tar.gz
    • เก็บรายละเอียด 9-16 ppem และเก็บรายละเอียดอื่น ๆ Taeyhom-src-20100518.tar.gz
    • แก้ไขตัว พ ฟ ให้ชัดขึ้นที่ 11,12,13 ppem Taeyhom-src-20100524.tar.gz
    • แก้ไขปากตัว ก.ไก่ และตัวอื่น ๆ ให้โค้งเล็กน้อยเพื่อให้รับกับตัว ร.เรือ (ทำให้เริ่มไม่เหมือน Tahoma แล้ว) Taeyhom-src-20100531.tar.gz

    ภาพตัวอย่าง
    ภาพจากบราวเซอร์ epiphany และ oo.o
    ตัวธรรมดาที่ hint แล้ว

    ตัวธรรมดา

    ตัวหนาที่ hint แล้ว

    ตัวหนา

    Topic: 

    fonts: บันทึก TlwgTypott

    เอา TlwgTypo จาก ltn: ThaiFonts-Scalable มาทำเรื่อง hinting
    พอจะเริ่ม hint จริง ๆ พบว่าลายเส้นของไทยไม่เข้ากับของฝรั่ง ซึ่งจะทำให้การ hint ยุ่งยาก จึงตัดสินใจสร้างลายเส้นไทยขึ้นมาใหม่ และตั้งชื่อใหม่ว่า TlwgTypott

    ดาวน์โหลดไฟล์ฟอนต์(520421)

    ดาวน์โหลดไฟล์ซอร์ส

    • รุ่นเริ่มต้น ยังไม่มีตัวหนา ยังไม่ได้ปรับละเอียด ฟอนต์ไทย hint ด้วยมือ ส่วนฟอนต์อังกฤษ ใช้ Auto-Instruction TlwgTypott-src-520408.tar.gz (พบว่า Auto-Instruction ของ Fontforge มีประสิทธิภาพดีขึ้นมาก ฟอนต์อังกฤษสวยงามมาก แต่กับฟอนต์ไทย ผลยังแย่อยู่จึง hint เองด้วยมือ)
    • ทำตัวหนา ตัวเอียง และตัวหนาเอียง แต่ใช้ Auto-Instruction ทั้งหมด TlwgTypott-src-520415.tar.gz (รุ่นนี้เอาไฟล์ฟอนต์ต้นฉบับของ Freefont มาใช้ ทำให้ได้รหัสอักขระเพิ่มขึ้น แต่พบบั๊กใน Abiword แสดงผลเพี้ยน ๆ แต่กับ gedit และ Epiphany แสดงปกติ)
    • hint ตัวหนาเสร็จ (เฉพาะตัวอักษรหลัก สระและวรรณวุกต์ไม่ได้ทำ) ใช้วิธี hint แบบไม่ลงจุด เพื่อให้เข้ากันได้กับอักขระโรมันที่ hint ด้วย Auto-Instruction TlwgTypott-src-520421.tar.gz (รุ่นนี้แก้บั๊กของรุ่นก่อนเรื่องการแสดงผลเพี้ยน โดยเอาซอร์สของ TlwgTypo กลับมาทำแทน บั๊กรุ่นก่อนเกิดจากต้นฉบับของ GNU ทำเรื่อง OpenType ไว้ยังไม่สมบูรณ์)
    • แก้บั๊ก konsole แสดงวรรณยุกต์เพี้ยน และบั๊กการ hint อื่นเล็กน้อย TlwgTypott-src-520423.tar.gz

    ภาพตัวอย่าง
    จาก abiword (openoffice แสดงผลเพี้ยน)
    ตัวธรรมดา

    ตัวหนา

    ความรู้ที่ได้

    • Auto-Instruction ใช้ได้ดีกับฟอนต์ที่มีเส้นบาง ๆ แต่ก็ต้องเพิ่ม/ลด Hhint Vhint ช่วยด้วย จึงจะได้ผลดี ลำพังใช้ AutoHint เฉย ๆ ไม่ไหว ประกอบกับการสร้างจุด ต้องแม่นจริง ๆ จึงจะทำให้งานออกมาดูกลมกลืน ซึ่งหลาย ๆ อย่างรวมกันแล้วอาจทำให้เสียเวลามากกว่าการเขียนโปรแกรม hint ด้วยซ้ำไป
    Topic: 

    fonts: บันทึก Waree Sans

    เอาฟอนต์ Waree - วารี จาก ltn: ThaiFonts-Scalable มาทำเรื่อง hinting

    ต้องขออภัยที่ต้องปรับความกว้างฟอนต์จากเดิม เพื่อให้เหมาะกับการทำ hinting ดังนั้นจึงไม่สามารถใช้แทนกันได้อย่างสนิท

    ดาวน์โหลดไฟล์ฟอนต์(รุ่น 20090603)

    ดาวน์โหลดไฟล์ซอร์ส

    • รุ่นเริ่มต้น ยังไม่มีตัวหนา ฟอนต์ไทย hint ด้วยมือ ส่วนฟอนต์อังกฤษ ใช้ของเดิมคือฟอนต์ Bitstream Vera Sans ซึ่ง hint stem ด้วยการทดลงจุด (ของเขาดูนุ่ม แต่ของเราดูแข็งหน่อย) : WareeSans-src-20090517.tar.gz
    • เกลาตัวธรรมดาเสร็จ พยัญชนะตัวหนาเสร็จ freeze เพื่อดูผล : WareeSans-src-20090520.tar.gz
    • ปรับลายเส้นให้ดูนุ่มนวลขึ้น เกลาตัวหนาเสร็จ : WareeSans-src-20090523.tar.gz
    • เกลาส่วนฟุ้ง ปรับช่องไฟให้หลวมขึ้น : WareeSans-src-20090527.tar.gz
    • เกลาละเอียด WareeSans-src-20090603.tar.gz

    ภาพตัวอย่าง
    จาก openoffice.org รุ่น 3.0.1
    ตัวธรรมดา

    ตัวหนา

    Topic: 

    fonts: บันทึก Waree Sans Mono

    เอาลายเส้นจาก Waree Sans มาทำเป็น Monospace แต่ทำเป็นแบบไม่ใช่ความกว้างคงที่แท้ ๆ คือสระและวรรณยุกต์ทำเป็นแบบความกว้างเป็นศูนย์ เพื่อให้ใช้งานกับ Openoffice.org ได้

    ทำแล้วดูแล้วยังไม่ค่อยสวย เพราะความกว้างฟอนต์อังกฤษเดิมแคบไป จึงทำให้สัดส่วนฟอนต์ไทยดูสูงชลูดไปหน่อย

    ดาวน์โหลดไฟล์ฟอนต์(รุ่น 20090613)

    ดาวน์โหลดไฟล์ซอร์ส

    • รุ่นเริ่มต้น ยังไม่มีตัวหนา เอา hint เดิมจาก Waree Sans มาใช้ทั้งหมด ดูหยาบสักหน่อย เพราะเริ่มเหนื่อยแล้ว ;D : WareeSansMono-src-20090609.tar.gz
    • ตัวหนาเสร็จแล้ว แต่เสร็จแบบไม่ดีเลย เนื่องจากความกว้างของภาษาอังกฤษแคบมาก ทำให้ hint ยากมาก WareeSansMono-src-20090613.tar.gz

    ภาพตัวอย่าง
    จาก openoffice.org รุ่น 3.0.1
    ตัวธรรมดา

    ตัวหนา

    Topic: 

    fonts: บันทึก Waree Serif

    เอาภาษาไทยจากฟอนต์ 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
    ตัวธรรมดา

    ตัวหนา

    Topic: 

    fonts: บันทึกการทดลองทำ DejaVuSansMonoThai

    เพิ่งเริ่มทำนะครับ

    ขั้นตอน

    • เอาซอร์สของ DejaVu รุ่น 2.28
    • เอาลายเส้นจาก DejaVuSansThai มาปรับ
    • ทำด้วย fontforge รุ่น 0.0.20080429-1 20081224

    งาน
    งานของฟอนต์ตัวนี้คือ เริ่มศึกษาการทำ ตาราง Lookups - GPOS โดยใช้ภาษาลาวเป็นต้นแบบ คือ

    • การวางสระบนอักษร ป ฟ ฬ จะไม่ได้ใช้ตัวหลบแล้ว
    • ความกว้างสระ ใช้แบบความกว้างคงที่ แต่ใช้ตาราง Lookups - GSUB ดันกลับให้มีความกว้างเป็นศูนย์

    download ttf

    download src

    • DejaVuSansMonoThai-src-520127.tar.gz
      • รุ่นแรก ยังไม่ได้ทำ Instruction ยังไม่มีตัวหนา
      • ลบสระเยื้องซ้ายออก
    • DejaVuSansMonoThai-src-520207.tar.gz
      • ลบสระหลบออกทั้งหมด กลับมาใช้ตาราง GPOS อย่างเดียว (คงเหลือแค่ "ฐ" กับ "ญ" ไม่มีเชิง ที่ยังอยู่ในช่วง private area #F700)
      • ทำ Instruction แล้ว รวมทั้งอักขระลาวตัวที่ยังไม่ได้ทำในไฟล์ต้นฉบับ (แต่สำหรับอักขระลาว เนื่องจากไม่ต้องการดัดแปลง spline ต้นฉบับที่ยังวางจุดไม่สมบูรณ์ จึงยังมีข้อจำกัดในการทำ Instruction เล็กน้อย) การทำ Instruction ในรุ่นนี้ ใช้วิธีคล้ายของ DejaVu แต่จะเขียนโค๊ดลงจุดให้น้อยที่สุดเท่าที่จำเป็นเท่านั้น เพื่อให้พัฒนาได้เร็ว และรูปร่างอักขระเพี้ยนน้อย จึงอาจเห็นการฟุ้งอยู่บ้าง
      • ดัดแปลงตัวอักขระ "บ" "ป" "อ" และ "ฮ" ให้มีเชิงเล็กน้อย เพื่อให้ดูเต็มช่องกับขนาดความกว้างอักขระคงที่
      • ช่วงบ่าย ปรับช่องไฟละเอียดแล้ว (ฝากดาวน์โหลดใหม่ด้วย)

    screenshot
    OpenOffice.org-2.4 แสดงผลที่ ppem ต่าง ๆ
    DejaVuSansMonoThai in OpenOffice.org

    รุ่นล่าสุด 520207
    DejaVuSansMonoThai latest screenshot

    รุ่นแรก
    DejaVuSansMonoThai before instruct

    Topic: 

    fonts: บันทึกการทดลองทำ DejaVuSansThai รุ่นแรก

    บันทึกการแปลงฟอนต์ Waree เป็น DejaVuSansThai รุ่นแรก

    • ใช้หลักการ instruct โดยพยายามยึดตามแนวของ DejaVu เท่าที่พอแกะออก
    • ยังขาดการทำ delta hint เพราะยังทำไม่เป็น ดังนั้นการออกแบบฟอนต์และการ instruct จึงพยายามปรับ เพื่อเลี่ยงการทำ delta hint ซึ่งต้องรอศึกษาต่อไป
      ทำ delta hint ได้แล้ว แต่เสียเวลาและสายตามากเกินไป จึงพยายามออกแบบโค๊ดให้ลดการทำ delta hint ให้มากที่สุด
      ล่าสุดเปลี่ยนแนวคิดการออกแบบเป็น กำหนดจุดให้น้อยที่สุดเพื่อให้ฟอนต์เพี้ยนน้อยที่สุด จึงจำเป็นต้องพึ่งการใช้ delta hint อย่างมาก
    • ลดความสูงของฟอนต์ไทย ให้เท่ากับอังกฤษตัวเล็ก แล้วพยายามย่นความสูงของสระและพยัญชนะลงมา แต่กระนั้นก็ยังล้นระยะห่างระหว่างบรรทัดของ DejaVu อยู่ดี
    • ค่า cvt ของ DejaVu Sans เต็ม 256 ค่าแล้ว แต่มีความจำเป็นต้องเพิ่มค่าของเราเข้าไป ทำให้ต้องอ้างค่าเป็น word แทน byte โค๊ดจึงอาจดูยากขึ้นเล็กน้อย
    • เขียนสคริปต์ไพธอน เล็ก ๆ ชื่อ dfont.py เอาไว้คลี่และเรียงสแต็ก ใช้ได้ผลดีพอควร แต่สคริปต์ยังขาดการตรวจสอบความถูกต้องของ instructing code ซึ่งถ้าใช้ด้วยพารามิเตอร์ --all อาจทำให้ fontforge หยุดการทำงานได้ - รอปรับปรุงต่อไป
    • ยังเหลือบั๊กอีกหลายจุด ตัว ค.ควาย จ.จาน ย.ยักษ์ ยังออกแบบไม่ดี ตัว ร.เรือ ธ.ธง ยัง instruct ได้ไม่ดี และยังไม่ได้ทำตัวหนา ตัวเอียง และตัวหนาเอียง แต่มีความจำเป็นต้องเว้นวรรคนาน จึงบันทึกไว้เพื่อให้จำได้

    ความรู้ที่ได้

    • การทำ TrueType Hinting Instruction ตัวอักษรจะเพี้ยนเสมอ ทั้งนี้เนื่องมาจากการบังคับให้ลงจุดในจอมอนิเตอร์ ดังนั้น การ instruct ก็คือการบอกว่าจะให้เพี้ยนยังไง จึงจะทำให้ดูคมชัด
    • การเคลื่อนจุดด้วยวิธี indirect เช่นคำสั่ง MIRP (ซึ่งต้องอ้างค่าจาก cvt - Control Value Table) มีความแม่นยำแน่นอนกว่าการเคลื่อนค่าแบบ direct (เช่นคำสั่ง MDRP)
    • คำสั่ง ip (Interpolate) จะทำให้ฟอนต์ดูฟุ้ง แต่ระยะที่ได้ แน่นอนกว่าการเคลื่อนจุดแบบ direct (เว้นเสียแต่ถ้าไม่มีการทดลงจุด คืออาร์กิวเมนต์ rnd ควรใช้ MDRP เสมอ ไม่งั้นบางทีอาจเพี้ยน)
    • ถ้ามีความจำเป็นต้องใช้การ Interpolate อาจทำแค่แกนเดียว ส่วนอีกแกนนึงให้ใช้การเคลื่อนแบบ direct แทน
    • พยายามยึดแนวแกนซ้ายขวาและความสูงเฉลี่ยของตัวอักษรไว้ ดังนั้นจึงควรบรรจุค่าความสูงและความกว้างของตัวอักษรในตาราง cvt เสมอ
    • ควรออกแบบความกว้างของตัวอักษรให้ดูสม่ำเสมอ แล้วเขียนโค๊ดโดยดูจากตาราง cvt เป็นสำคัญ แต่จะมีข้อยกเว้นเป็นบางตัวอักษรที่มีหัวอักษรอยู่ตรงกลางฟอนต์ เช่น ค.ควาย หรือ ด.เด็ก อาจต้องยอมทิ้งค่าความกว้างจาก cvt โดยต้องไล่จุดไปตามแนวที่ผ่านหัวอักษรไปเรื่อย ๆ ไม่งั้นเวลาแสดงผลที่ขนาดปอยต์ต่าง ๆ หัวอักษรอาจเยื้องไปทางซ้ายบ้างขวาบ้าง บางครั้งอาจดูลีบติดไปทางแกนอักษรข้างใดข้างหนึ่งบ้าง - อาจแก้ได้ด้วย delta hint
    • การทำ delta hint หรือ grid fitting โดยกำหนดให้เป็น version 1 จะได้ฟอนต์ที่ดูนุ่มนวลดีกว่า version 0
    • ถ้าไม่ทดลงจุดด้วยอาร์กิวเมนต์ rnd ห้ามใช้คำสั่ง SHPIX ที่จุดนั้นเด็ดขาด จะมีปัญหาเลอะตอนพิมพ์ โดยเฉพาะในแนวแกน Y

    ผลการทดลอง - บนลินุกซ์ ความละเอียดจอภาพ 85 dpi

    • ดูดีที่ 12 และ 13 ปอยต์
    • ตั้งแต่ 7 ปอยต์ลงไป อ่านไม่ได้
    • ตั้งแต่ 18 ปอยต์ขึ้นไป ไม่มีปัญหาเรื่องการ hint
    • แย่สุดที่ 14 ปอยต์ ที่เหลือนอกจากนี้ พอดูได้
    • รุ่นล่าสุด (510519) ปรับด้วย delta shift hint พยายามทำให้ดูดีในทุก ๆ ppem แต่ปรับละเอียดที่ 14,15 และ 16 ppem
    • ความกระชับของโค๊ด ขึ้นกับแนวคิดในการไล่เส้นทางเดินของฟอนต์
    • ความสวยของฟอนต์ขึ้นกับความเพียรในการทำ delta hint

    ดาวน์โหลดไฟล์ฟอนต์ ttf ล่าสุด (รุ่น 520401)

    ดาวน์โหลดไฟล์ซอร์ส

    • DejaVuSansThai-src-510331.tar.gz
    • ปรับปรุงช่องไฟ (ยังไม่ดี) ปรับปรุงเรื่องหัวเล็กน้อย (ดีขึ้น) และปรับหลัก instruction บางส่วน (ดีขึ้น)
      DejaVuSansThai-src-510408.tar.gz
    • รุ่นสุดท้ายก่อนทำ delta hint DejaVuSansThai-src-510415.tar.gz
    • เริ่มทำ delta hint (gridfit) ของตัว ค.ควาย ด.เด็ก และปรับปรุงตัว ร.เรือ DejaVuSansThai-src-510416.tar.gz
    • ทำตัวหนาเพิ่ม DejaVuSansThai-src-510420.tar.gz
    • ปรับวิธี hint ใหม่หมด เลียนแบบจาก Serif ซึ่งพยายามเลียนจาก Tahoma อีกที โดยปรับละเอียดที่ 16 ppem และปรับหัวให้ดูนุ่มขึ้น ที่ 14,15 และ 16 ppem
      DejaVuSansThai-src-510519.tar.gz
    • ทำตัวหนาเสร็จ ปรับวิธี hint อีกเล็กน้อย โดยใช้หลัก hint เท่าที่จำเป็น
      รุ่นนี้คิดว่าสมบูรณ์พอจะเอาไปใช้งานได้แล้ว DejaVuSansThai-src-510523.tar.gz
    • ทำรุ่นใหม่ โดยใช้ฟังก์ชั่น SHPIX บีบหัวให้ฟุ้งน้อยลง จึงทำให้ดูเหมือนกับคมขึ้น ตามไปช่วย hint ให้ภาษาลาวเล็กน้อย แต่ยังไม่เสร็จ DejaVuSansThai-src-510612.tar.gz
    • hint ภาษาลาวเสร็จ ปรับแก้เรื่องเส้นขีดฆ่า ตามคำแนะนำของคุณเทพ (แต่ตัวหนายังไม่ได้แก้ คิดว่าจะแก้ใหญ่ในภายหลังครับ) DejaVuSansThai-src-510618.tar.gz
    • เพิ่มตาราง open type (แก้ปัญหา OpenOffice-2.4 "สระอำ" เพี้ยน) และตรวจแก้ข้อมูลตาราง lookup gsub ขาดไป : DejaVuSansThai-src-510823.tar.gz
    • เริ่มการใช้ตาราง GPOS ลดสระหลบทั้งหมด ย้าย ฐ และ ญ ไม่มีฐานขึ้นข้างบน ดัดแปลงลายเส้นเล็กน้อย hint แบบให้กลมกลึง (คมชัดน้อยลง) : DejaVuSansThai-src-520218.tar.gz
    • hint ตัวหนา(เกือบ)เสร็จ (พักไปงานอื่นก่อน) รุ่นนี้พยายามทดลองเขียนโค๊ดไพธอนแบบนำมาใช้ใหม่ แต่เวลากระชั้นมาก โค๊ดข้างในจึงเลอะเทอะมาก (ตัวหนา) : DejaVuSansThai-src-520303.tar.gz
    • เกลา hint ตัวธรรมดาใหม่ โค๊ดเป็นฟังก์ชั่นเพื่อให้การ hint ไปในแนวเดียวกันทุก ๆ อักขระ แก้ปัญหาหัวบางที่ 9-12 ppem ทำให้อ่านง่ายขึ้น ลบการฟุ้งมากไปหน่อยจนทำให้ฟอนต์ดูแห้ง พยายามทำให้ขนาดเส้นตั้งกับเส้นนอนไม่ต่างกันมากนัก ที่ 17-19 ppem ยังไม่ได้แยกวรรณยุกต์เป็น 2 ระดับ (โค๊ดที่เป็นฟังก์ชั่นยังเลอะเทอะอยู่) : DejaVuSansThai-src-520322.tar.gz
    • ทำวรรณยุกต์ระดับสอง ปรับช่องไฟและความกว้างฟอนต์ขนาดเล็ก : DejaVuSansThai-src-520401.tar.gz

    งานที่เหลือ และที่ตั้งใจจะทำ

    • เกลาช่องไฟละเอียด
    • ดูเส้นขาดฟอนต์ขาวพื้นหลังดำ
    • ทำตัวหนาให้มาแนวเดียวกัน

    ภาพตัวอย่างของรุ่นล่าสุด

    ตัวหนา

    ภาพจาก OpenOffice.org รุ่นล่าสุด

    oo ตัวหนา

    ภาพตัวอย่าง รุ่นแรก (จากจอภาพขนาด 85 dpi)








    Topic: 

    fonts: โค๊ดไพธอนที่ใช้ช่วยทำงาน

    สรุปรวมจาก python: เขียนโค๊ดคลี่แสต็กฟอนต์ และ python: โค๊ดฟอนต์ย้อนกลับ
    รวมเป็นไฟล์เดียว ตั้งชื่อว่า dfont.py การทำงานแค่คลี่และเรียงแสต็กใหม่
    เวลาใช้งาน จะต้องเขียนสคริปต์ไพธอนเพิ่มสำหรับฟอนต์แต่ละตัว เพื่อมาเรียกใช้ dfont เป็นมอดูล ปรับปรุง
    • 51-05-06 เพิ่มฟังก์ชั่นการทำ grid fitting ทำให้การเขียนโค๊ดง่ายขึ้น
      เช่นต้องการขยับจุด 20 ไป +8 ที่ฟอนต์ขนาด 9, 10 และ 11 ppem
      เดิมเขียนโค๊ดเป็น
      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))
    
    Topic: 

    บันทึกการ instruct ฟอนต์

    เที่ยวนี้ไม่มีอะไร บันทึกตัวอย่างการ 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
    
    Topic: 

    fonts: ตัวอย่างการ hint ก.ไก่

    มีค่า cvt ของฟอนต์ 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 เป็นต้นไป
    ค่า cvt ของ ก.ไก่ข้างต้น คือ กำหนดให้ลำดับที่ 11 (ซึ่งมีค่า 113) เป็นระยะช่องไฟด้านหน้า เป็นต้น โครง ก.ไก่ ตัวอย่างจะเริ่มด้วยการ hint ในแนวแกน X ก่อน (เป็นค่าปริยาย) จะแสดงเป็นโค๊ด instruction แบบจำลอง เพื่อให้ดูง่าย เวลาใช้งานจริง ก็นำไปเขียนเป็นโค๊ดในไพธอน โปรแกรม dfont.py จะคลี่แสต็กและเรียงออกมาเป็นโค๊ดจริง ๆ อีกที แนวแกน X
    เส้นทาง hint ในแนวแกน X จุดเริ่มต้นคือจุดที่ 26 (จุดสุดท้ายคือ 25 + 1)
    srp0                26
    
    จากจุดเริ่มต้น จะเคลื่อนจุดอ้างอิง rp0 ไปยังจุดที่ใกล้ขอบซ้ายที่สุด คือจุด 18 เพื่อกั้นเป็นระยะช่องไฟด้านหน้า ด้วยค่า cvt คือ front_kai
    การเคลื่อนด้วยการอ้างอิงค่า คำสั่งคือ MIRP
    การเคลื่อนจุดอ้างอิงไปด้วย ใช้อาร์กิวเมนต์ rp0
    การปัดเศษให้ลงจุด (round) ใช้อาร์กิวเมนต์ rnd
    การแรเงาพื้นที่ ใช้อาร์กิวเมนต์ grey (ปกติควรเป็น white แต่ DejaVu ใฃ้ grey เสมอ จึงใช้ตาม เพื่อกันสับสน)
    ค่า cvt ที่ใช้ คือ front_kai
    จุดที่จะเคลื่อนไป คือ 18
    mirp[rp0,min,rnd,grey]  front_kai 18
    
    จุดที่จะไปต่อคือ จุด 8 แต่เนื่องจากเมื่อเคลื่อนไปแล้ว ไม่มีจุดที่จะไปต่อ เราจึงไม่ต้องเคลื่อนจุด rp0 ไปด้วย จึงไม่ต้องใส่อาร์กิวเมนต์ rp0
    ระยะของปาก ก.ไก่ ไม่จำเป็นต้องเป็นค่าที่แน่นอนนัก เราจึงไม่ต้องอ้างค่า cvt จึงใช้คำสั่ง MDRP
    ปัดเศษด้วย ใช้ rnd
    แรเงา ใช้ grey
    จุดที่เคลื่อนไปคือ 8
    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 เสมอ
    ต้องอ้างอิงจาก cvt คำสั่งคือ MIRP
    ไม่ต้องย้าย rp0 ไปด้วย เพราะไม่มีจุดที่จะไปต่อ จึงไม่ต้องใช้อาร์กิวเมนต์ rp0
    ถึงแม้ขนาดเส้นจะบางอย่างไร การแสดงผลต้องกำหนดค่าให้อย่างน้อย 1 จุดเสมอ ใช้อาร์กิวเมนต์ min
    แรเงาใช้ grey
    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
    เส้นทาง hint ในแนวแกน Y เริ่มย้ายมาแกน 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]
    จบแล้วครับ
    Topic: 

    fonts: ตัวอย่างการ hint ข.ไข่

    ค่า cvt ที่เกี่ยวข้องคือ
    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
        ...
    }
    ภาพลายเส้น
    โครง ข.ไข่ แนวแกน X
    เส้นทาง hint ในแนวแกน X ตัวอย่างนี้เริ่มซับซ้อน เนื่องจากช่วงหัวของ ข.ไข่ มีทางเดินที่ต้องการทดลงจุดมาก ทำให้ระยะที่ได้มีค่าไม่แน่นอนตามขนาดฟอนต์ที่เปลี่ยนไป ผลที่ได้คือ
    ถ้าเราทำให้ฟอนต์มีขนาดคงที่ จะทำให้บางครั้งหัวดูลีบหรือใหญ่เกินไป
    ถ้าเราทำให้หัวดูสวยงาม บางครั้งฟอนต์จะดูกว้างหรือลีบเกินไป
    ทางแก้คือเราจะ hint ให้ช่วงหัวให้ดูสวยงามก่อน แล้วโยงไปเส้น stem ด้านหลัง แล้วจึงโยงกลับมาที่ stem ด้านหน้าอีกครั้ง โดยใช้ตรงโค้งช่วงคอของอักษรเป็นช่วงที่รับระยะการเปลี่ยนแปลง วิธีนี้ทำให้เกิดผลข้างเคียงน้อยที่สุด (แต่ก็ยังมีอยู่ดี ต้องแก้ต่อไปด้วย delta hint สำหรับขนาดฟอนต์ที่ดูไม่งาม) เริ่มต้นที่จุด 53
    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
    เส้นทาง hint ในแนวแกน Y ทำงานในแกน 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]
    
    เสร็จแล้ว
    ถอดด้วย dfont.py จะได้โค๊ด instruction ดังนี้
    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]
    
    Topic: 

    fonts: ตัวอย่างการ hint ค.ควาย

    ค่า cvt ที่เกี่ยวข้องคือ
    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
        ...
    }
    ภาพลายเส้น
    โครง ค.ควาย แนวแกน X
    เส้นทาง hint ในแนวแกน X เริ่มที่จุด 52
    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
    เส้นทาง hint ในแนวแกน Y ทำงานในแกน 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
    (เหตุที่ใช้จุด 36 แทนที่จะเป็นจุด 1 หรือ จุด 0 ในการอ้างอิงสำหรับหัวอักษร ค.ควาย เนื่องจากความสวยงามในการวาดหัวอักษร จะขึ้นกับโค้งด้านบนมากว่าฐานด้านล่าง)
    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]
    
    เสร็จแล้ว
    แต่ถึงแม้จะป้องกันอย่างไร รูปร่างฟอนต์แบบตัว ค.ควาย จะยังมีปัญหาในตอนทดจุดอยู่ดี
    คือที่ขนาด 17 ppem หัวอักษรจะชิดติดกับแกนขวาของอักษร
    (สรุปเป็นปอยต์ตามความละเอียดของจอภาพคือ 72dpi=17pt, 85dpi=14.5pt, 96dpi=13pt)
    ดูจากเมนู View -> Grid Fit -> Show Grid Fit -> 17pt 72dpi ได้ภาพดังนี้
    17ppem gridfit แก้ด้วยการขยับจุดจำนวน 8 จุด ในแนวแกน X คือ
    จุด 2 ขยับไปทางขวา 8px คือ +8px ที่ 17ppem สูตรคือ
    +8px ค่าในตาราง delta hint คือ 15
    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
    17ppem นำมาลบด้วย 9 (ลบด้วย 9 เสมอ) คือ 6
    ค่า 6 จะเป็น 4 บิตบน และค่า 15 คือ 4 บิตล่าง รวมกันคือ 6*16+15=143
    จะได้คู่ของการทำ delta hint คือ จุด 2 และค่าผลรวม 143 เขียนสรุปย่อดังนี้
    ที่ 17 ppem
    จุด 2 ขยับ +8 = 2 143
    จุด 39 ขยับ +8 = 39 143
    จุด 0 ขยับ +8 = 0 143
    จุด 1 ขยับ +8 = 1 143
    จุด 3 ขยับ +6 = 1 141
    จุด 38 ขยับ +6 = 38 141
    จุด 37 ขยับ +4 = 37 139
    จุด 4 ขยับ +4 = 4 139
    นับรวมได้ 8 คู่ จะได้โค๊ดจำลองดังนี้ กำหนดการทำงานในแกน X
    SVTCA[x-axis]
    
    ใส่ delta hint โดยใส่จำนวนคู่ไว้เป็นค่าแรก
    deltap1             8 2 143 39 143 0 143 1 143 3 141 38 141 37 139 4 139
    
    ภาพหลังการขยับแล้วจะป็นดังนี้
    17ppem after gridfit เสร็จแล้ว
    เมื่อนำมาถอดด้วย dfont.py จะได้โค๊ด instruction ดังนี้
    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
    
    Topic: 

    fonts: บันทึกการทดลองทำ DejaVuSerifThai อีกรุ่น

    บันทึกการสร้างฟอนต์ DejaVu Serif Thai

    • ตัวนี้ทดลองทำ hinting เลียนแบบวิธีของ Tahoma คือ
      คงระยะคงที่ช่องไฟหน้าและหลังไว้ และให้ความกว้างของตัวอักษรเป็นตัวรองรับระยะการทดจุดที่เปลี่ยนไปมา ซึ่งบังคับว่าต้องทำ grid fitting (delta hint) เพื่อกำหนดความกว้างของฟอนต์ก่อน แล้วจึงเริ่มเดินจุด
      การทำ delta hint ก่อน จำเป็นมากสำหรับฟอนต์ขนาดเล็ก ซึ่งมีอัตราการเพี้ยนของความกว้างของอักษรมาก ไหน ๆ ก็ต้องทำ delta hint อยู่แล้ว เที่ยวนี้จึงพยายามลงลึกไปทำถึงขนาดหัวอักษรด้วย ผลที่ได้คืออ่านง่ายขึ้น โดยเฉพาะกับฟอนต์ขนาดเล็ก ๆ แต่ก็ต้องแลกมาด้วยการเสียเวลาและสายตาเป็นอย่างมาก
      (การทำงานต้องปรับขนาดจอภาพให้มีความละเอียด 72 dpi เพื่อให้รองรับขนาดฟอนต์ได้ทุก ๆ ppem บวกกับการเพ่งกำหนดจุดที่เปลี่ยน จึงเปลืองสายตามาก)
    • รูปแบบฟอนต์ของ DejaVu Serif ดูไม่เป็น serif จัดนัก จึงนำเอาฟอนต์ Angsima มาแปลงใส่เข้าไป
      เนื่องจากเห็นว่า ภาษาไทยทำ serif แท้ ๆ ไม่สวย จึงพยายามทำเท่าที่ทำได้ คือ hint เฉพาะพยัญชนะ ส่วนสระบนและล่างไม่ hint และไม่แปลงรูปแบบเลย

    ผลการทดลอง

    • เนื่องจากมีการทำ grid fitting (เกือบ)เต็มที่ จึงดูดีที่ฟอนต์ขนาดเล็ก ๆ ด้วย (หรือเปล่า?)
    • สระบนล่าง ทำ hint แล้วไม่สวย จึงตัดสินใจไม่ hint เพียงแค่กำหนดระยะในแกน Y เล็กน้อย ผลที่ได้คือแนวเส้นบรรทัดที่เป็นพญัญชนะจะดูคมชัดกว่าแนวสระบนล่าง - ไม่รู้ว่าดีหรือเปล่า รอดูผลการใช้งานต่อไป
    • แบบอักษรดูคล้าย sans ไปหน่อย โดยเฉพาะกับฟอนต์ขนาดเล็ก ยกเว้นสระบนล่างที่เป็นแบบของ Angima ชัดเจน ซึ่งอาจทำให้ดูไม่กลมกลืน

    ปรับปรุง
    (เนื่องจากเป็นการทำงานไปด้วย ศึกษาไปด้วย การทำ hinting จึงไม่เป็นอันหนึ่งอันเดียวกันในทุก ๆ ฟอนต์ที่ทำ ต้องขออภัยด้วย)

    • 51-05-06 ทำตัวหนาเพิ่มเสร็จแล้ว ตัวหนาที่ทำ ใช้เทคนิก hint เท่าที่จำเป็น จึงอาจดูไม่คมชัดนัก แต่ฟอนต์น่าจะอ่านง่ายขึ้นและผิดรูปน้อยลง
    • เขียนฟังก์ชั่นให้ทำ grid fitting ง่ายขึ้น งานของตัวหนาจึงเพิ่มเรื่อง grid fitting มากขึ้นมาก
    • 51-05-31 ปรับละเอียด เริ่มใช้ฟังก์ชั่น SHPIX ในการปรับหัวไม่ให้คมแข็ง พยายามปรับฟอนต์ให้ดูนิ่มนวลขึ้น ทำให้ดูดีขึ้นสำหรับการแสดงผลพื้นขาวตัวดำ แต่ยังมีปัญหากับพื้นหลังที่เข้มไม่มาก แต่ตัวหนังสือสีขาว (เช่นเว็บ pantip.com) ยังดูยากหน่อย พยายามปรับระดับความสูงวรรณยุกต์ระดับ 2 ไม่ให้เหลื่อม (ยังไม่ได้ทำตัวหนา เพราะยังไม่แน่ใจผล)

    ดาวน์โหลดไฟล์ฟอนต์ ttf

    ดาวน์โหลดซอร์ส

    • รุ่นแรกยังไม่มีตัวหนา DejaVuSerifThai-src-510502.tar.gz
    • รุ่นสองเพิ่มตัวหนาแล้ว DejaVuSerifThai-src-510506.tar.gz
    • ทำเลขไทยเสร็จแล้ว hint สระแล้ว DejaVuSerifThai-src-510508.tar.gz
    • รุ่นใหม่ ปรับให้ดูนุ่มนวล DejaVuSerifThai-src-510531.tar.gz
    • ทำตัวหนาเสร็จ แต่ตัวหนาไม่ได้ปรับหัว เพราะความจำเป็นน้อย สิ่งที่ปรับปรุงคือปรับการ hint โดยใช้แนวคิดว่าไม่จำเป็นต้องปัดเศษให้ลงจุดในทุกจุด ซึ่งจะทำให้ดูนุ่มนวลขึ้น เว้นเสียแต่ว่าระบบไม่มีการทำ Anti-Alias เช่นวินโดวส์รุ่นเก่า อาจทำให้ฟอนต์ดูเพี้ยน DejaVuSerifThai-src-510606.tar.gz
    • แก้บั๊กตาราง Lookups/GSUB ให้เรียบร้อย ทำตาราง OpenType เพื่อแก้ปัญหา "สระอำ" ใน OpenOffice : DejaVuSerifThai-src-510824.tar.gz

    ภาพตัวอย่าง (จากขนาดจอภาพ 72 dpi จึงกำหนดระยะเป็น ppem แทนเพื่อป้องกันสับสน)
    DejaVu Serif Thai

    Topic: 

    fonts: บันทึกฟอนต์อุโฆษ (Ukhosa)

    ต้องการทำฟอนต์ที่ใช้ในงานโฆษณา แต่ไม่แปลงรูปฟอนต์มากนัก ให้มีหัวบาง ๆ อยู่ทุกตัว ตั้งชื่อว่า อุโฆษ (Ukhosa) สร้างโดยเอาโครงฟอนต์โลมาบุตรมาแปลง

    ดาวน์โหลดไฟล์ฟอนต์ (20100707)

    ข้อความด้านล่างเป็นการแสดงผลจากหน้าเว็บด้วยฟอนต์นี้ (จากความสามารถของ css3)

    ดาวน์โหลดไฟล์ซอร์ส

    • รุ่นร่าง ยังไม่มีตัวหนา ยังไม่มี hint (รุ่นนี้อาจไม่ทำ hinting) Ukhosa-src-20100626.tar.gz
    • ยังไม่เสร็จ แต่จะเปลี่ยนลายเส้นภาษาอังกฤษเป็นแบบโลโกอูบุนตู - Ukhosa-src-20100629.tar.gz
    • อาจเว้นยาวหลายวัน โพสต์แปะไว้ก่อน - Ukhosa-src-20100630.tar.gz
    • ร่างตัวหนาเสร็จ - Ukhosa-src-20100707.tar.gz

    ภาพตัวอย่าง
    จาก Epiphany Browser
    ตัวธรรมดา

    ตัวหนา

    Topic: 

    python: เขียนโค๊ดคลี่แสต็กฟอนต์

    เหตุมาจากต้องการดูการ instruct ของฟอนต์ DejaVu Sans
    แต่โค๊ดอ่านยากเหลือเกิน เพราะเขียนข้อมูลเป็นสแต็กไว้ก่อน แล้วจึงเขียนโค๊ดตามหลัง ทำให้ดูยาก จึงเขียนสคริปต์แบบหยาบ ๆ มาคลี่ข้อมูลเรียงต่อท้ายคำสั่ง เพื่อให้ดูง่ายขึ้น ตั้งชื่อชั่วคราวว่า dfont.py
    $ 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
    
    Topic: 

    python: โค๊ดฟอนต์ย้อนกลับ

    เพื่อให้ครบกระบวน ต่อด้วยโค๊ดย้อนกลับอีกที
    ต่อจาก python: เขียนโค๊ดคลี่แสต็กฟอนต์ ที่ผ่านมานะครับ $ 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
    
    ไม่เหมือนเป๊ะ แต่น่าจะทำงานได้เหมือนกัน
    Topic: