Esaan Tham Font with GSUB
ทิ้งค้างไว้จาก blog ที่แล้ว เสียนาน ก็เพิ่งได้โอกาสกลับมาทำ โครงการอักษรอีสาน ต่อ โดยหลังจากที่ได้ glyph ต่าง ๆ เรียบร้อยแล้ว ก็ถึงคราวทำเรื่องกฎการแสดงข้อความ
ดังที่ได้อธิบายไว้ ว่าอักษรธรรมในยูนิโค้ดจะลงรหัสในข้อความในลำดับที่เรียกว่า logical order
ตามแบบอักษรอินเดีย (ซึ่งจากการที่โดนกระแนะกระแหนบ่อย ๆ ว่าอักษรไทยกับลาวเป็น ข้อยกเว้น
ของ logical order สำหรับอักษรในตระกูลเดียวกัน ราวกับว่าสองอักษรนี้ไม่ logical
กระนั้น ก็ทำให้ผมอยากจะเรียก logical order
เสียใหม่ว่า phonetic order
) ซึ่งลำดับการเก็บแบบ logical order หรือ phonetic order นี้ แตกต่างจากลำดับที่แสดงผลจริงซึ่งเรียกว่า visual order
ทำให้ต้องมีการเรียงลำดับ glyph เสียใหม่ขณะแสดงผล
เนื่องจากทางเลือกอื่น คือการรอให้ rendering engine รองรับอักษรธรรม หรือการรอให้ไมโครซอฟท์จัดทำข้อกำหนดของการแสดงอักษรธรรมด้วย OpenType เป็นเรื่องที่ไม่สามารถสำเร็จได้ในเวลาอันสั้น ผมจึงจำเป็นต้องใช้วิธีสร้างกฎ GSUB ให้สามารถวาดแสดงได้ในตัวเองโดยไม่พึ่ง preprocessing ใน rendering engine เลย
โจทย์หนักที่สุดคือการสลับลำดับสระหน้า เพราะ GSUB ไม่มีรูปแบบกฎที่ซับซ้อนพอที่จะเขียนการสลับ AB เป็น BA ได้ เครื่องมือที่มีให้คือ:
- Multiple substitution คือการแทน glyph 1 glyph ด้วย glyph string เช่น A → XYZ
- Ligature substitution คือการแทน glyph string ด้วย glyph 1 glyph เช่น XYZ → A
- Contextual substitution คือการกำหนด substitution (multiple หรือ ligature ข้างต้น) ที่จะกระทำเมื่อพบแพตเทิร์นที่กำหนด เช่น ถ้าพบ abc ให้ใช้กฎ P ที่ตำแหน่ง glyph ที่ 2 เป็นต้น
ยังมี substitution แบบอื่นอีกพอประมาณ แต่ก็ไม่ได้มีความสามารถมากไปกว่านี้ ซึ่งจะพบว่าการเขียนกฎง่าย ๆ แค่ AB → BA นั้น ไม่ใช่เรื่องง่ายเอาเสียเลย แต่โชคดีที่เผอิญไปได้เคล็ดวิชาจากเพื่อนชาวพม่ามาว่าเขามีลูกสูตรกันแบบนี้:
AB → BAB [Mul. A → BA]
BAB → BA [Lig. AB → A]
คือใช้ contextual 2 กฎ, multiple 1 กฎ และ ligature อีก 1 กฎ โดย contextual นั้นสามารถกำหนดแพตเทิร์นเป็นคลาสได้ แต่ multiple และ ligature นั้น ต้องลิสต์ทุก combination แบบเรียงตัวเท่านั้น
เนื่องจากรูปแบบระหว่างทาง (คือ BAB ในตัวอย่างข้างต้น) นั้นสุ่มเสี่ยงที่จะไปชนกับข้อความจริง ผมจึงดัดแปลงกฎเสียใหม่เป็นแบบนี้:
AB → BAxB [Mul. A → BAx]
BAxB → BA [Lig. AxB → A]
โดย x เป็น dummy ตัวหนึ่งที่ใส่เข้ามาเพื่อป้องกันการ match กับข้อความจริง จะเลือก glyph อะไรก็ได้ที่ไม่มีที่ใช้ในข้อความจริง
และในบางกฎ ก็เหมาะที่จะทำข้างหลังก่อน ซึ่งจะทำให้ลดจำนวนกฎ contextual ลงได้:
AB → AxBA [Mul. B → xBA]
AxBA → BA [Lig. AxB → B]
ได้สูตรแบบนี้แล้ว ผมก็มานั่งออกแบบกฎ GSUB สำหรับอักษรธรรมอีสานได้แล้ว โดยหลังจากประมวลอักขรวิธีต่าง ๆ แล้ว ก็สรุปเป็นขั้นตอนการทำงานดังนี้:
- สลับลำดับ ไม้อังแล่น (ง สะกดเหนือพยัญชนะ) ในภาษาบาลี
NGA-above + SAKOT + Cons --> Cons + NGA-above
- เปลี่ยนพยัญชนะเป็นรูปตัวห้อย/ตัวเฟื้องเมื่อตามหลัง
SAKOTSAKOT + Cons --> Cons.sub
- สลับลำดับสระหน้า
Cons + [sub|medial-RA] + LV --> LV + Cons + [sub|medial-RA]
- สลับลำดับ ระวง
Cons + medial-RA --> medial-RA + Cons
- จัดการรูปย่อ น + า แบบซับซ้อน
NA + {sub|tone|UV|BV} + AA --> NAA + {sub|tone|UV|BV} - จัดการรูปย่อทั่วไป
NA + AA --> NAA WA + tall-AA --> WAA
หลังจากได้ลำดับกฎแล้ว ก็มา implement กฎแต่ละกฎด้วยสูตรข้างต้น โดยมีเคล็ดในการลดจำนวนกฎอยู่ว่า ให้พยายามเลือกเซ็ตที่ใหญ่ที่สุด (เช่น พยัญชนะ) เป็นตัวแปลง แล้วไปลิสต์รายการในตาราง multiple/ligature substitution เป็นหมวด ๆ เอา จะทำให้ได้จำนวนหมวดน้อย จัดการในระดับบนได้ง่าย ถ้าเราไปเลือกแปลงเซ็ตเล็ก (เช่น สระหน้า) แทน จะทำให้ได้หมวดเล็ก ๆ จำนวนมาก จำนวน contextual substitution มาก จัดการในระดับบนได้ลำบาก
หมายเหตุ: แม้จะลดปริมาณกฎลงแล้ว แต่ก็ยังมากอยู่ดี ทำใน fontforge อย่างเดียวไม่ไหว งานนี้สำเร็จได้ด้วย vim ครับ ;-)
ทำฟอนต์เสร็จแล้ว ก็ทำ หน้าทดสอบฟอนต์ เอาไว้ด้วย โดยฝังฟอนต์ลงในเว็บเลย เปิดด้วย Firefox/Iceweasel ตั้งแต่รุ่น 4 ขึ้นไปได้ผลดี ส่วน Chrome/Chromium หรือเบราว์เซอร์อื่นที่ใช้ WebKit (เช่น Epiphany, Midori) นั้น แสดงอักษรได้อยู่ แต่กฎ GSUB จะไม่ทำงาน ทำให้ลำดับการแสดงไม่ใช่ลำดับสำหรับมนุษย์อ่าน ส่วน IE ไม่มีให้ทดสอบครับ
ป้ายกำกับ: typography








0 ความเห็น:
แสดงความเห็น (มีการกลั่นกรองสำหรับ blog ที่เก่ากว่า 14 วัน)
<< กลับหน้าแรก