Theppitak's blog

My personal blog.

25 กรกฎาคม 2568

Tai Tham Updated, Thai Noi Revisited

Update งานอักษรอีสาน

Khottabun กับอักษรธรรมแบบไร้ USE

หลังจากการวิเคราะห์ทางเลือกต่างๆ สำหรับอักษรธรรมไป 2 blog (Lao Tham Font vs USE และ To USE or Not to USE for Lao Tham) และได้ตัดสินใจ หลีกเลี่ยง USE โดยยอมทิ้ง MS Word ไว้ข้างหลัง ก็ได้ implement ใน fonts-khottabun ตามนั้น ตั้งแต่ commit a0389bd จนถึง commit 1c73c80 โดยปรับ major version ของฟอนต์ขึ้นเป็นรุ่น 003 สำหรับอักษรธรรมแบบไม่ใช้ USE

Keyboard Layout อักษรธรรมบน Windows

ถัดมาคือ ผังแป้นพิมพ์อักษรธรรมบน Windows ในรูปของซอร์ส KLC สำหรับสร้างเป็นผังแป้นพิมพ์ด้วย Microsoft Keyboard Layout Creator (MSKLC) 1.4 ซึ่งจะ build เป็น DLL พร้อมโปรแกรม setup

ประเด็นปลีกย่อยของผังนี้คือ Windows กำหนดให้ผังแป้นพิมพ์ต้องผูกติดกับโลแคล (locale) ซึ่งกำหนดด้วยภาษาและดินแดน ตรงนี้เป็นปัญหาโดยนิยามอยู่ เพราะอักษรธรรมสามารถใช้เขียนได้หลายภาษา ไม่ว่าจะไทย ลาว ไทลื้อ ไทขึน หรือคาถาบาลี-สันสกฤต แต่ Windows จะบังคับให้เราเลือกเพียงภาษาเดียวมาประกอบกับดินแดนที่เป็นถิ่นของภาษาที่ใช้ โดยห้ามใช้ซ้ำกับผังอื่นในโลแคลนั้นๆ ด้วย ประเด็นคือ:

  • โลแคลต่างๆ มักมีผังแป้นพิมพ์อยู่แล้ว ถ้าไม่ต้องการซ้ำก็ต้องสร้างโลแคลใหม่สำหรับอักษรธรรม แต่จะกำหนดโลแคลด้วยภาษาอะไร ในเมื่ออักษรธรรมสามารถใช้เขียนได้หลายภาษา?
  • สมมุติว่าเราเลือกสร้างโลแคลภาษาลาวถิ่นไทย (lo-TH) ด้วย Microsoft Locale Builder แต่ปัญหาคือ เราไม่สามารถเลือกบล็อคยูนิโคดของอักษรธรรมให้กับโลแคลใหม่นี้ได้ เนื่องจาก Microsoft กำหนดตัวเลข enum ให้กับบล็อคยูนิโคดต่างๆ แต่ยังไม่ได้กำหนดเลขสำหรับอ้างให้กับบล็อคอักษรธรรม!
  • ในเมื่อสร้างโลแคลเองไม่ได้ วิธีแก้ขัดจึงเป็นการเลือกโลแคลอะไรก็ได้ที่ไม่ซ้ำกับชุดผังแป้นพิมพ์ที่เราใช้ เช่น ใช้ th, en ไม่ได้ เพราะจะซ้ำกับสองผังหลักที่เราใช้ และผมก็จิ้มเอาโลแคลมลยาฬัมในอินเดีย (ml-IN) โดยไม่มีเหตุผลใดๆ มากไปกว่าการแก้ขัด เวลาจะป้อนอักษรธรรมบน Windows ผู้ใช้ก็สลับแป้นพิมพ์ไปที่ภาษามลยาฬัม
  • อันที่จริง สิ่งที่เราต้องการมากกว่าในกรณีนี้คือการอ้างถึง อักษร (script) ตรงๆ ไปเลย แต่การออกแบบของ Windows ยังไม่เอื้อขนาดนั้น

อย่างไรก็ดี เราก็ได้ผังแป้นพิมพ์อักษรธรรมที่ทำงานได้บน Windows โดยเป็นเพียงผังปุ่มจริงๆ ยังไม่มีการตรวจหรือสลับลำดับอะไร ผู้ใช้ต้องป้อนตามลำดับยูนิโคดเป๊ะๆ เช่น ᨸᩮᩢ᩠ᨶ (เป็น) ก็ต้องป้อนเป็น ป + เอ + ไม้ซัด + SAKOT + น

อักษรไทยน้อย

แม้อักษรไทยน้อยจะเรียบง่ายกว่าอักษรธรรม แต่กลับมีรายละเอียดปลีกย่อยมากกว่า ทั้งเรื่องความหลากหลายของชุดอักษรที่ใช้ การควบอักษรติดกัน การยืมตัวห้อยตัวเฟื้องจากอักษรธรรมตามแต่ผู้จารึกจะเลือกใช้ ดังที่ผมได้เคย สรุปประเด็น ไว้ โดยยังไม่ตกลงว่าจะเลือก implement แบบไหน

เมื่อหลายปีก่อน ในระหว่างที่ทำไปศึกษาไปนั้น ผมเลือกที่จะเติมอักขระลงในช่องที่ยังว่างอยู่ของบล็อคยูนิโคดอักษรลาว ไม่ว่าจะเป็นตัวเฟื้องหรือตัวควบต่างๆ แต่ยิ่งพบอักขระที่ต้องเพิ่มรหัสมากขึ้นจากการอ่านจารึก ก็ยิ่งเห็นว่ามันไม่ใช่วิธีที่ดีในระยะยาว

ตอนนี้ได้โอกาสมาปัดฝุ่น โดยบล็อคยูนิโคดลาวเองก็มีมีการเพิ่มอักขระสำหรับเขียนภาษาบาลีตามแบบพุทธบัณฑิตสภา จึงได้พิจารณาทางเลือกต่างๆ ใหม่

เริ่มจากตรวจสอบความคืบหน้าใน Unicode ของอักษรไทยน้อย ซึ่ง ข้อมูลใน ScriptSource ของ SIL ได้บันทึกรายละเอียดไว้ โดยสถานะล่าสุดคือ ยังไม่กำหนดใน Unicode ส่วนกระบวนการเท่าที่ผ่านมาคือ

2018-01-02 Request to Add Thai Characters — Nitaya Kanchanawan (WG2 N4927, L2/18-041)
เป็นข้อเสนอขอเพิ่มอักขระไทยน้อยลงในบล็อคอักษรไทย! โดยเป็นงานที่เกี่ยวเนื่องกับการกำหนดมาตรฐานการถอดอักษรไทยน้อยเป็นอักษรโรมันที่ราชบัณฑิตยสภาได้เสนอเข้าสู่ ISO/IEC โดยได้รับความเห็นว่าควรกำหนดรหัสอักขระก่อน แต่ไม่ทราบว่าด้วยเหตุผลใด ราชบัณฑิตยสภาถึงได้เสนอให้เพิ่มอักขระในบล็อคอักษรไทยแทนที่จะเป็นบล็อคอักษรลาวที่อยู่ในสายวิวัฒนาการโดยตรง
2018-01-19 Information and documentation - Transliteration of scripts in use in Thailand - Part 1: Transliteration of Akson-Thai-Noi — TC46 / WG3 (WG2 N4927A, L2/18-042)
เป็นร่างมาตรฐานการถอดอักษรไทยน้อยเป็นอักษรโรมันที่เป็นต้นเรื่อง ตัวเอกสารต้องใช้รหัสผ่านในการเข้าถึง และไม่เกี่ยวข้องกับเรื่องรหัสอักขระโดยตรง ผมจึงไม่ใส่ลิงก์ไว้
2018-01-19 Results on ISO CD 20674-1: Information and documentation - Transliteration of scripts in use in Thailand - Part 1: Transliteration of Akson-Thai-Noi — TC46 Secretatriat (WG2 N4927B, L2/18-043)
ผลการโหวตร่างมาตรฐานการถอดอักษรไทยน้อยของคณะกรรมการ เห็นชอบ 16, เห็นชอบโดยมีข้อคิดเห็น 2, ไม่เห็นชอบ 1, งดออกเสียง 19
2018-02-20 Thai-Noi Transliteration — Martin Hosken (WG2 N4939, L2/18-068)
เป็นความเห็นจากคุณ Martin Hosken ผู้เชี่ยวชาญจาก SIL โดยสรุปเห็นว่าอักษรไทยน้อยเข้ากันได้กับอักษรธรรมมากกว่าอักษรไทย
2018-02-28 Towards a comprehensive proposal for Thai Noi / Lao Buhan script — Ben Mitchell (L2/18-072)
เป็นความเห็นจากคุณ Ben Mitchell ผู้เชี่ยวชาญอีกท่านหนึ่ง โดยมีผู้ร่วมให้ข้อมูลคือ Patrick Chew, ผมเอง และ อ.ประพันธ์ เอี่ยมวิริยะกุล โดยสรุปเห็นว่าควรเพิ่มอักขระไทยน้อยในบล็อคอักษรลาว โดยเพิ่มเติมจากอักษรลาวบาลีของพุทธบัณฑิตสภาอีกที และได้เสนอทางเลือกต่างๆ ดังที่ผมได้สรุปไว้ แต่ยังไม่ระบุว่าจะเลือกวิธีการไหน
Recommendations to UTC #155 April-May 2018 on Script Proposals (L2/18-168) (อยู่ที่ข้อ 6.) และบันทึกการประชุมของ UTC #155 (L2/18-115) (อยู่ที่ข้อ D.8.1 และ D.8.3)
สรุปข้อแนะนำของคณะกรรมการว่าอักษรไทยน้อยไม่ใข่ส่วนขยายของอักษรไทย และผู้เสนอร่างอักษรไทยน้อย (หมายถึง อ.นิตยา กาญจนวรรณ จากราชบัณฑิตยสภา) ควรนำข้อมูลในเอกสารของคุณ Ben Mitchell ข้างต้นไปใช้ประกอบการร่างด้วย โดยมอบให้ Deborah Anderson ร่างเอกสารแจ้งเจ้าของร่าง ซึ่งก็คือเอกสาร L2/18-070

แล้วกระบวนการทั้งหมดก็หยุดอยู่ที่รอการดำเนินการของราชบัณฑิตยสภาต่อจากนั้น

สรุปว่ายังไม่มีมาตรฐาน Unicode อักษรไทยน้อยเกิดขึ้น ถ้าจะ implement ตอนนี้ก็เป็นเพียงตุ๊กตาเท่านั้น

จากทางเลือกต่างๆ ที่มี ผมพิจารณาเลือกเองไปก่อนอย่างนี้:

  • Conjunct หรือการสังโยคพยัญชนะด้วยตัวห้อย/ตัวเฟื้อง ใช้พินทุ (U+0EBA LAO SIGN PALI VIRAMA) ตามด้วยพยัญชนะที่จะสังโยค ยกเว้นกรณีที่มีรหัสอยู่แล้ว คือ ล ห้อย (U+0EBC) และ ย เฟื้อง (U+0EBD) ก็ใช้รหัสนั้นๆ ไปเลย
  • Ligature หรือตัวแฝด หรืออักษรควบ ใช้ U+200D ZERO WIDTH JOINER (ZWJ) เชื่อมพยัญชนะ ยกเว้นกรณีที่มีรหัสอยู่แล้ว คือ U+0EDC (ໜ), U+0EDD (ໝ) ก็ใช้รหัสนั้นๆ ไปเลย
  • สระออย กำหนดอักขระใหม่ในช่องที่ยังว่างอยู่ คือ U+0EBE เพื่อให้เป็นวิธีที่สอดคล้องกับอักษรธรรม (อีกวิธีที่ไม่ต้องกำหนดอักขระใหม่คือใช้ พินทุ + ຢ แต่จะเป็นวิธีที่แปลกแยกจากอักษรธรรม)

เมื่อเลือกวิธีนี้แล้ว ก็ปรับเปลี่ยนทั้งในฟอนต์ Khottabun และในระบบป้อนข้อความ Lanxang ดังนี้:

  • fonts-khottabun: detach glyph ตัวห้อย/ตัวเฟื้องและตัวควบทั้งหมดจากรหัสอักขระ แล้วสร้างกฎ 'ccmp' TN conjuncts และ 'ccmp' TN subjoins เพื่อเข้าถึง glyph เหล่านี้ผ่านพินทุและ ZWJ ตามลำดับ พร้อมกับปรับรุ่น major ของฟอนต์เป็นรุ่น 004 (commit cc4935a)
  • lanxang: ตัดกระบวนการแปลง พินทุ + พยัญชนะ เป็นอักขระตัวห้อย/ตัวเฟื้อง และ พยัญชนะ + ZWJ + พยัญชนะ เป็นอักขระตัวควบ ทั้งหมด (ทิ้ง sequence ประกอบไว้อย่างนั้นในข้อความเลย แล้วให้ฟอนต์จัดการตอน render) ยกเว้นการควบ ໜ,ໝ เพื่ออำนวยความสะดวก (commit f0645b1) แต่ก็ยังป้อน ໜ, ໝ โดยตรงได้ด้วย level 3 เช่นกัน
  • lanxang: เพิ่มผังแป้นพิมพ์อักษรไทยน้อยสำหรับ Windows ด้วย (commit cce81cd)

พร้อมกันนี้ก็แปลงวิธีลงรหัสอักขระไทยน้อยในตัวอย่างการปริวรรตทั้งหลายด้วย (พญาคันคาก, ฮีตคองคะลำ, บูชาพญานาค, นกกระจอก)

ป้ายกำกับ: , , , ,

06 เมษายน 2568

To USE or Not to USE for Lao Tham

จาก blog ที่แล้ว ผมได้เล่าถึงการรองรับอักษรธรรมในปัจจุบันที่ text shaping engine ต่างๆ หันมาใช้ Universal Shaping Engine (USE) ตามข้อกำหนดของไมโครซอฟท์ โดย USE เองเป็น engine ครอบจักรวาลที่มีการจัดการภายในตามคุณสมบัติของอักขระ Unicode เช่น การสลับสระหน้ากับพยัญชนะต้นสำหรับอักษรตระกูลพราหมี และเรียกใช้ OpenType feature ต่างๆ ในฟอนต์ตามลำดับที่กำหนดไว้

และการจัดการภายในของ USE ก็ทำให้มีข้อเสนอที่จะปรับโครงสร้างการลงรหัสข้อความอักษรธรรมเพื่อให้ทำงานกับ USE ได้ แต่มันก็ยังไม่เข้าที่เข้าทางนัก จึงเกิดแนวคิดที่จะหลบเลี่ยง USE แล้วทำทุกอย่างเองในฟอนต์ แต่ไปติดปัญหาที่ MS Word ที่ไม่ยอมให้หลบได้ง่ายๆ ทำให้เราอยู่บนทางแยกที่ต้องเลือกว่าจะใช้ USE ที่ยังไม่เข้าที่ หรือจะเลี่ยง USE ไปทำทุกอย่างเองโดยทิ้ง MS Word ไว้ข้างหลัง

blog นี้ก็จะวิเคราะห์ต่อ ว่าทางเลือกแต่ละทางมีข้อดีข้อเสียอย่างไร

Encoding แบบใหม่

ตามข้อเสนอในเอกสาร Structuring Tai Tham Unicode เมื่อตัดรายละเอียดที่อักษรธรรมลาว/อีสานไม่ใช้ออกไป ก็พอจะสรุปลำดับอักขระในข้อความได้เป็น:

  S ::= CC (Vs | Vf)?

โดยที่ CC คือ consonant cluster พร้อมสระหน้า/ล่าง/บน วรรณยุกต์ สระหรือตัวสะกดปิดท้าย

  CC ::= C M? V? T? F?

  C ::= [<ก>-<ฮ><อิลอย>-<โอลอย><แล><ส_สองห้อง><ตัวเลข>] | <ห><SAKOT>[<ก>-<ม>]

  M ::= <ระวง>? <ล_ล่าง>? (<SAKOT><ว>)? (<SAKOT><ย>)?

  V ::= Vp? Vb? Va? 
  Vp ::= [<เอ>-<ไม้ม้วน>] // สระหน้า
  Vb ::= [<อุ>-<อู><ออ_ล่าง>] // สระล่าง
  Va ::= [<อิ>-<อือ><ไม้กง><ไม้เก๋าห่อนึ่ง>][<ไม้ซัด><ไม้กั๋ง>]? // สระบน

  T ::= [<ไม้เอก>-<ไม้โท>]

  F ::= Fs? [<ละทั้งหลาย><ไม้กั๋งไหล><ง_บน><ม_ล่าง><บ_ล่าง><ส_ล่าง><ไม้กั๋ง>]? (<SAKOT> S)?
  Fs ::= [<อ><ส_สองห้อง><ออย>] | <SAKOT>[<ก>-<ฬ>] // อ ของสระเอือ หรือ ตัวสะกด

สังเกตว่ามี recursion ใน F เพื่อแทนลูกโซ่ของพยางค์ในคำบาลีด้วย

ต่อจาก CC ก็จะตามด้วยสระกินที่ (spacing vowels) ซึ่งแบ่งเป็นสระมีตัวสะกด (Vs) และสระไม่มีตัวสะกด (Vf)

สำหรับสระมีตัวสะกด Vs คือสระอาหรือสระอำ (สระอำในอักษรธรรมไม่ได้มีรหัสอักขระเฉพาะเหมือนอักษรไทย แต่แทนด้วยสระอาตามด้วยไม้กั๋ง (นิคหิต) ความจริงอาจนับไม้กั๋งเป็นตัวสะกดในสระอำก็ได้ แต่กฎนี้พยายามจัดการสระอากับสระอำไปด้วยกัน กลายเป็นว่าสระอำก็ยังมีตัวสะกดได้อีก) พร้อมตัวสะกด Fs (ถ้ามี)

  Vs ::= AV Fs?
  AV ::= [<อา><อาสูง>] <ไม้กั๋ง>? // สระอา สระอำ

ส่วนสระไม่มีตัวสะกด Vf ในตัวเนื้อหาของร่างฯ ได้บรรยายถึงสระเอาะและสระเอือะ แต่ในสรุปส่วนท้ายดูจะลืมสระเอาะไป และยังจัดการ อ ของสระเอือะซ้ำซ้อนกับใน Fs อีก

  Vf ::= <อ>? <อะ> // วิสรรชนีย์ของสระเอือะ

Encoding แบบ USE

แม้ encoding แบบใหม่ที่เสนอมีจุดมุ่งหมายเพื่อให้วาดแสดงด้วย USE แต่เมื่อลองใช้กับ USE จริงกลับยังมี dotted circle เกิดขึ้นในหลายกรณี ซึ่งจากการทดลองก็พอจะสังเกตลักษณะของ USE ที่ต่างจากโครงสร้างที่เสนอในร่างดังนี้:

  • ลำดับสระใน V สระบนมาก่อนสระล่าง ไม่ใช่ตามหลังสระล่างอย่างในร่างฯ ดังนั้นจึงอาจปรับกฎเป็น:
      V ::= Vp? Va? Vb?
    
  • วรรณยุกต์อยู่หน้าสระกินที่ไม่ได้ แต่ตามหลังได้ และต้องอยู่ก่อนตัวสะกด ดูเหมือน USE จะนับ Vs เป็นส่วนหนึ่งของ V:
      V ::= Vp? Va? Vb? Vs?
    
    ซึ่งถ้าเป็นเช่นนั้น ก็หมายความว่า USE ก็ยังต้องการการ reorder ให้วรรณยุกต์ไปอยู่ในตำแหน่งก่อนหน้าสระกินที่เพื่อให้สามารถซ้อนบนพยัญชนะได้ด้วย มันจะกลายเป็นความซับซ้อนเกินจำเป็นน่ะสิ

หลักการสำหรับการป้อนข้อความ

สมมติว่าเราใช้ encoding แบบ USE เราจะมีหลักในใจอย่างไร? เราจะใช้ลำดับการพิมพ์แบบที่เราเคยใช้กับอักษรไทยไม่ได้อีกแล้ว เพราะมันคือการ encode แบบกึ่ง visual ไม่ว่าเขาจะยืนยันที่จะเรียกว่า logical order ยังไงก็ตาม แต่ลำดับการ encode นี้จะไม่ตรงกับลำดับการสะกดคำเสมอไป มันเน้นให้เรียงพิมพ์ได้เป็นหลัก! โดยมีลำดับแบบที่เรียกว่า logical order มาหลอกให้งงเล่น

หลักการคือ

  1. ละทิ้งลำดับการสะกดในใจไว้ก่อน พิจารณารูปร่างของข้อความที่ต้องการ แล้ว encode ตามกฎในข้อถัดๆ ไป
  2. ผสมตัวห้อย ตัวเฟื้อง หรือระวง กับพยัญชนะต้นก่อน โดยมากเป็นตัวควบกล้ำ
  3. ตามด้วยสระ โดยถ้ามีสระหลายตัว ให้วางสระตามลำดับ หน้า, บน, ล่าง, ขวา
  4. ตามด้วยวรรณยุกต์
  5. ตามด้วยตัวสะกด ซึ่งอาจเป็นตัวห้อย, ตัวเฟื้อง, ไม้กั๋ง, ง สะกดบน, หรือไม้กั๋งไหล
  6. ถ้ามีการเชื่อมพยางค์เป็นลูกโซ่แบบบาลี ก็นับตัวสะกดเป็นพยัญชนะต้นของพยางค์ถัดไปแล้วใส่สระตามได้เลย

ความไม่ปกติของลำดับ

หลักการที่ว่าไปก็ดูปกติดีนี่? แต่ความซับซ้อนของอักษรธรรมทำให้มันไม่ตรงไปตรงมาอย่างนั้น ต่อไปนี้คือกรณีต่างๆ ที่ฝืนความรู้สึก อย่างน้อยก็ในระยะแรก

การสะกดแม่กกด้วยไม้ซัด

ไม้ซัดถือว่าเป็นสระบน (Va) ในกฎ ซึ่ง encoding ในร่างฯ สามารถตามหลังสระล่าง (Vb) ได้ แต่ตาม encoding ของ USE ต้องมาก่อนสระล่าง ดังนั้น เมื่อไม้ซัดทำหน้าที่เป็นตัวสะกดแม่กก จึงต้องใช้ลำดับที่ตัวสะกดมาก่อนสระ ไม่ใช่สระมาก่อนตัวสะกด

แต่ก็จะมีกรณีที่ไม่สามารถ encode ได้ ไม่ว่าจะตามร่างฯ หรือตาม USE คือเมื่อเป็นตัวสะกดของสระอา

อาจจะยกเว้นคำว่า นาค ที่สามารถซ่อนลำดับไว้ภายใต้รูปเขียนพิเศษได้

เมื่อมีตัวห้อย/ตัวเฟื้องหรือสระระหว่าง cluster

การเขียนอักษรธรรมในหลายกรณีมีการใช้ตัวห้อย/ตัวเฟื้องเป็นพยัญชนะต้นของพยางค์ถัดไป แทนที่จะใช้ตัวเต็ม ซึ่งในกรณีเหล่านี้ ถ้าวางตัวห้อย/ตัวเฟื้องในตำแหน่งของตัวสะกด ก็จะไม่สามารถวางสระต่อได้อีก เพราะดูเหมือน USE ไม่ได้รองรับ recursion ใน F ตามกฎในร่างฯ และเมื่อแจงต่อไป CC ของพยางค์ถัดไปก็ขาดพยัญชนะต้นตัวเต็ม (C) มาขึ้นต้น CC แต่ถ้า encode โดยเลี่ยงให้ตัวห้อย/ตัวเฟื้องดังกล่าวเป็นส่วนหนึ่งของ CC ของพยางค์ก่อนหน้าก็จะสามารถวางสระต่อได้ แต่ลำดับก็จะดูขัดสามัญสำนึกสักหน่อย

แต่ในบางกรณีก็ไม่เอื้อให้ทำเช่นนั้น เช่น เมื่อมีสระมาคั่นในแบบที่ไม่สามารถสลับลำดับได้

ในคำย่อที่มีการยืมพยัญชนะต้น

บ่อยครั้งที่อักษรธรรมมีการใช้รูปเขียนย่อในลักษณะที่ใช้พยัญชนะต้นตัวเดียวซ้ำในพยางค์มากกว่าหนึ่งพยางค์ ในจำนวนนั้น บางคำอาจสามารถยังจัดลำดับอักขระจนเข้ากับกฎเกณฑ์ของ USE ได้ แม้จะดูเหมือนการเปลี่ยนหน้าที่อักขระ เช่น เปลี่ยนตัวสะกดมาเป็นตัวควบ หรืออาจมีการสลับลำดับสระของพยางค์ต่างๆ

แต่บางกรณีก็ไม่สามารถจัดลำดับให้เข้าเกณฑ์ได้

วิธีหลบเลี่ยง?

อย่างไรก็ดี ปัญหาทั้งหมดนี้สามารถหลบเลี่ยงได้ โดยลบ glyph DOTTED CIRCLE (uni25CC) ออกจากฟอนต์เสีย แล้ว USE ก็จะไม่แสดง dotted circle อีกเลย!

ที่กล่าวมาทั้งหมดนี้คือการทดสอบกับแอปที่ใช้ Harfbuzz แต่สุดท้าย เมื่อนำไปทดสอบกับ MS Word ปรากฏว่ามันก็ยังไม่ยอมง่ายๆ อยู่ดี โดยปัญหาหลักที่พบมีสองข้อ ข้อแรกคือกฎของตัวห้อย/ตัวเฟื้องจะไม่ทำงานถ้าไม่ได้ตามหลังพยัญชนะต้นทันที เช่น เป็นตัวสะกดของสระอา หรือมีสระอื่นมาคั่นกลาง กล่าวคือ blwf ดูจะถูกเรียกเฉพาะในตำแหน่งพยัญชนะซ้อนกันเท่านั้น ไม่เรียกในตำแหน่งตัวสะกด และอีกข้อหนึ่งคือกฎ ligature สำหรับ นา ไม่ทำงานเมื่อมีอักขระซ้อนบน/ล่าง

สรุป

ประเด็นต่างๆ ที่พบ พอจะสรุปได้ตังตาราง

ประเด็น ใช้ USE เลี่ยง USE
วิธีการ
  • lana script tag
  • GSUB ตาม USE
  • ตัด dotted circle
  • DFLT script tag
  • GSUB อย่างละเอียด
  • อาจมี dotted circle ได้
การ encode ข้อความ กึ่ง visual (ขัดสามัญสำนึกนิดหน่อย) ตามหลักการสะกดคำ
แอปที่รองรับ Harfbuzz app*, MS Word (บางส่วน) Harfbuzz app*, Notepad
อาการเมื่อไม่รองรับ
  • MS Word
    • กฎ blwf ในตำแหน่งตัวสะกดไม่ทำงาน
    • กฎ ligature นา ไม่ทำงานถ้ามีอักขระบน/ล่างแทรก
  • Notepad และแอปที่รองรับ OpenType แบบผิวเผิน
    • ไม่มีกฎไหนทำงานเลย
  • ทุกแอป
    • ไม้กั๋งไหลไม่ไหล
  • MS Word
    • ccmp: การ reorder สระหน้า, ระวง ไม่ทำงาน
    • liga: reorder สระหน้าซ้ำสองตำแหน่ง

*Harfbuzz app เช่น LibreOffice, Firefox, Gedit, Mousepad ฯลฯ

จึงพอสรุปได้ว่ายังมีความแตกต่างระหว่างข้อกำหนดในร่างฯ กับสิ่งที่ USE รองรับจริง ทำให้ไม่ว่าจะพยายามอย่างไรก็จะมีข้อบกพร่องเกิดขึ้นเสมอ และแอปที่มีปัญหาเสมอๆ ก็คือ MS Word

หากเลือกใช้ข้อกำหนด USE ทุกแอปที่รองรับ USE ก็จะได้การรองรับแบบ เกือบๆ ครบถ้วน (โดย MS Word จะมีปัญหามากกว่าเพื่อนสักหน่อย) โดยแลกกับลำดับการ encode ที่ผิดธรรมชาติของผู้ใช้ ซึ่งเป็นการแลกที่ผมคิดว่าไม่คุ้ม เพราะจะมีผลให้เกิดเอกสารที่ encode แปลกๆ เกิดขึ้นในระหว่างที่ USE ยังไม่พร้อม แถมสิ่งที่ได้คืนมาก็ยังไม่ใช่สิ่งที่สมบูรณ์เสียด้วย

ในขณะที่หากเลือกหลีกเลี่ยง USE แอปส่วนใหญ่ยกเว้น MS Word ก็จะสามารถจัดแสดงอักษรธรรมได้สมบูรณ์ (ดังกล่าวไว้ใน blog ที่แล้ว) โดยที่ผู้ใช้ก็ยังคงใช้ encoding แบบเก่าได้เช่นเดิม และเมื่อไรที่ USE พร้อม ก็เพียงแปลง encoding ไปเป็นแบบใหม่ (ซึ่งอาจจะอัตโนมัติหรือ manual ก็ค่อยว่ากัน) โดยไม่ต้องมี encoding ชั่วคราวของ USE มาแทรกกลางเป็นชนิดที่สามให้เกิดความสับสนเพิ่ม โดยแลกกับการทิ้ง MS Word ที่ยังไงก็ไม่สมบูรณ์อยู่แล้ว และแนะนำให้ผู้ใช้อักษรธรรมใช้ LibreOffice หรือ Notepad (ซึ่งเป็นผลพลอยได้) ในการเตรียมเอกสารแทน ส่วนเว็บเบราว์เซอร์นั้นไม่เป็นปัญหา เพราะเบราว์เซอร์ส่วนใหญ่ก็ใช้ Harfbuzz เป็นฐานกันอยู่แล้ว การรองรับก็จะเหมือนๆ กับใน LibreOffice นั่นแล

ด้วยเหตุนี้ ผมจึงเลือกที่จะสร้างฟอนต์อักษรธรรมที่ หลีกเลี่ยง USE ต่อไป จนกว่า USE จะพร้อมจริงๆ

ป้ายกำกับ: , ,

01 เมษายน 2568

Lao Tham Font vs USE

บันทึกการกลับมาทำฟอนต์อักษรธรรมอีกครั้ง หลังจาก commit ล่าสุด 4 ปีที่แล้ว โดยในช่วงหลังของการทำงานรอบนั้น มีความเปลี่ยนแปลงสำคัญใน Harfbuzz ก่อนที่ผมจะวางมือไปทำอย่างอื่น คือ มีการใช้ Universal Shaping Engine (USE) ตามข้อกำหนดของไมโครซอฟท์ ทำให้กฎบางข้อหยุดทำงาน เช่น การจัดการไม้กั๋งไหล (ลาวเรียก ไม้อังแล่น) แต่ผมก็ไม่ได้ไปติดตาม

ในเอกสาร Creating and supporting OpenType fonts for the Universal Shaping Engine ของไมโครซอฟท์ ได้อธิบายขั้นตอนต่างๆ ที่ USE จะเรียกใช้กฎในฟอนต์ โดยที่ USE เองก็มีการประมวลผลภายในเองบางส่วนด้วย ตามแต่อักษรที่รองรับ โดยสำหรับอักษรธรรมก็มีเชิงอรรถให้ปวดใจว่า

Note: Tai Tham support is currently limited. Additional encoding work is required for full text representation to be possible.

การรองรับอักษรธรรมยังคงจำกัดอยู่ในตอนนี้ ยังต้องทำงานด้านการกำหนดรหัสกันต่อไปเพื่อจะให้ได้รหัสที่สามารถแทนข้อความได้เต็มที่

ซึ่งเมื่อไปตรวจสอบเอกสารที่เกี่ยวข้อง ก็พบเอกสาร Structuring Tai Tham Unicode (L2/19-365) โดย Martin Hosken ซึ่งเป็นร่างข้อเสนอที่จะปรับลำดับการลงรหัสอักขระอักษรธรรมจาก แบบเริ่มแรก (L2/05-095R) เพื่อการวาดแสดงด้วย USE ซึ่งลำดับแบบใหม่ค่อนข้างแตกต่างจากลำดับการสะกดในใจพอสมควร และข้อเสนอใหม่ก็ยังคงเป็นฉบับร่าง จึงเกิดความไม่แน่นอนว่าแนวทางการลงรหัสปัจจุบันจะเป็นแบบไหน

เนื่องจากพระอาจารย์ชยสิริ ชยสาโร ประสงค์จะให้ผมเพิ่มอักษรธรรมลงในฟอนต์ Laobuhan ของท่าน ผมจึงถือโอกาสทดลองทำตามข้อกำหนดของ USE อันใหม่เสียเลย โดยพยายามทดสอบบน Windows 11 ด้วย นอกเหนือจากที่เคยทดสอบเฉพาะบนลินุกซ์ โดยในข้อกำหนดใหม่ USE มีการ reorder สระหน้าให้ จึงไม่ต้องทำในฟอนต์เองอีกต่อไป สิ่งที่ควรทำ (เรียงตามลำดับการเรียกใช้โดย USE) จึงเป็น:

  • pref (Pre-base forms) เพื่อระบุตำแหน่งของระวง เพื่อที่ USE จะ reorder ไปไว้หน้าพยัญชนะต้นให้ในภายหลัง
  • rphf (Reph forms) ความจริงเป็นกฎสำหรับ reorder เรผะ ของอักษรอินเดีย ที่ดูแล้วน่าจะใช้กับ ไม้กั๋งไหล ของอักษรธรรมได้ แต่เมื่อทดลองทำจริงแล้วไม่เป็นผล ซึ่งในเอกสารของไมโครซอฟท์เองก็ระบุไว้ว่า:
    Note that the category REPHA is not currently supported by USE.
    ซึ่งหมายความว่า rphf เองก็จะยังไม่ทำงาน
  • blwf (Below-base forms) เพื่อทำตัวห้อย ตัวเฟื้อง
  • liga (Standard ligatures) เพื่อทำรูปเขียนพิเศษ เช่น นา

ผลการทดสอบคือ แอปที่ใช้ Harfbuzz (GTK, LibreOffice, Firefox) และ MS Word วาดแสดงอักษรธรรมได้ดี ยกเว้นในบางกรณี เช่น สระอาที่ตามหลังวรรณยุกต์จะมี dotted circle แทรกเข้ามา และตัว ล ห้อย (ที่ไม่ใช้ SAKOT) ที่ใช้ร่วมกับสระหน้าจะแสดงถูกต้องเฉพาะเมื่อลงรหัสด้วยลำดับที่เหมาะสมเท่านั้น กล่าวคือ ถ้าใช้ structure ข้อความแบบใหม่ที่ออกแบบให้รองรับ USE ก็ น่าจะ แสดงได้ถูกต้องเป็นส่วนมาก

อักษรธรรมบน LibreOffice Writer แบบใช้ USE
อักษรธรรมบน MS Word แบบใช้ USE

แต่กับ Notepad บน Windows ดูเหมือนกฎต่างๆ จะไม่ทำงานเลย! สถานการณ์อาจต่างจากลินุกซ์ที่แอปแทบทุกตัวใช้ Harfbuzz กันหมด แต่บน Windows ยังแยก implement กันอยู่

อักษรธรรมบน Windows Notepad แบบใช้ USE
อักษรธรรมบน Linux Mousepad แบบใช้ USE

แต่ปัญหา dotted circle ในบางกรณีของ USE ก็ยังทำให้ผมต้องค้นหาข้อมูลต่อ ทั้งไล่ซอร์สโค้ดของ Harfbuzz ทั้งค้นเว็บ จนไปเจอ โพสต์ของ Richard Wordingham เล่าปัญหาเดียวกันที่เขาเจอ โดยได้พูดถึงวิธีหลบเลี่ยง USE ด้วย โดยในทุกกฎ GSUB, GPOS ไม่ต้องระบุรหัสอักษรเป็น lana เลย เพียงใช้รหัสอักษร DFLT ก็พอ ซึ่งถ้าเป็น Harfbuzz ก็จะไปเรียก default engine แทน USE ซึ่งฟอนต์ก็ต้องเตรียมกฎ GSUB ให้มันทำงานทุกอย่างแทน USE ทั้งหมด ผ่าน OpenType feature เท่าที่ใช้รองรับ Standard Scripts ซึ่งก็จะมี feature จำนวนจำกัดให้ใช้ เช่น ccmp และ liga เป็นต้น

เรื่องกฎไม่ใช่เรื่องยาก เพราะฟอนต์ Khottabun ที่ผมสร้างตั้งแต่ก่อนที่ Harfbuzz จะใช้ USE ก็ทำทุกอย่างเองหมดอยู่แล้ว ก็เลยหยิบมาทดลองได้ทันที โดยตัดรหัสอักษร lana ออกจากกฎ ccmp ที่ใช้ทั้งหมด

ผลปรากฏว่า มันยังคงวาดแสดงได้อย่างสมบูรณ์บน Harfbuzz แต่คราวนี้มันทำงานบน Notepad บน Windows ด้วย! โดยในทั้งสองกรณี กฎที่เขียนไว้สำหรับไม้กั๋งไหลที่เคยไม่ทำงานบน Harfbuzz ก็กลับทำงานเรียบร้อย! (ดูตัวอย่างคำว่า มงฺคล แบบแรก)

อักษรธรรมบน LibreOffice Writer แบบใช้รหัสอักษร DFLT
อักษรธรรมบน Windows Notepad แบบใช้รหัสอักษร DFLT

แต่ข่าวร้ายคือ มันเละบน MS Word

อักษรธรรมบน MS Word แบบใช้รหัสอักษร DFLT

ซึ่งจากการทดลองก็สรุปได้ว่ามันเกิดจาก:

  • ข้อจำกัดของ ccmp บน engine ของ MS Word ที่ดูจะไม่รองรับ contextual substitution ที่ซับซ้อน (เข้าใจว่าทำได้แค่ multiple substitution และ ligature substitution อย่างง่ายเท่านั้น)
  • engine ของ MS Word ยังคงใช้ USE เช่นเดิม ทำให้ถึงแม้จะเปลี่ยนไปใช้ liga ที่สามารถทำ contextual substitution ซับซ้อนได้ ก็จะเกิดการ reorder สระหน้าซ้ำซ้อนกันระหว่างโดยตัว engine เองก้บโดยกฎในฟอนต์จนสระหน้าสามารถเลื่อนข้ามพยัญชนะไปได้ถึง 2 ตำแหน่ง

ถ้าคิดตามหลักเหตุผลแล้ว ถ้า ccmp ที่ USE เรียกใช้ในขั้น preprocessing สามารถทำงานได้อย่างถูกต้อง โดยให้กฎแทรก glyph ผีสักตัว (เช่น ZWNJ) ไว้หน้าสระหน้าที่สลับลำดับแล้ว เพื่อให้มันคั่นระหว่างสระหน้ากับพยัญชนะที่อยู่ก่อนหน้าไว้ ก็ควรจะสามารถป้องกัน USE ไม่ให้ reorder ซ้ำอีกได้ แต่ในเมื่อ DirectWrite engine ที่ MS Word ใช้ไม่รองรับ ccmp ที่ซับซ้อน (แบบที่ Harfbuzz ทำ) มันก็จบเห่ตั้งแต่ต้น ส่วน liga หรือ clig ที่รองรับ contextual substitution แบบซับซ้อนได้ ก็ถูกเรียกทำงานหลังการ reorder ภายในของ USE ไปแล้ว จึงไม่สามารถควบคุมอะไรได้ทันการณ์

ในเมื่อ USE ก็ไม่สมบูรณ์ จะเลี่ยง USE ก็ติดปัญหากับ MS Word ผมจึงอยู่บนทางเลือก:

  1. ใช้ USE ไปเลย แล้วรอให้มีการแก้ปัญหาของ USE อีกที
  2. เลี่ยง USE ต่อไป โดยได้การทำงานของไม้กั๋งไหลเพิ่มมาด้วย แต่ยอมทิ้งการรองรับบน MS Word
  3. เลี่ยง USE แบบต้องปรับฟอนต์ขนานใหญ่ให้ใช้ ccmp ในการ reorder ให้ได้ ผ่าน ligature glyph แล้วค่อยรื้อกลับใหม่อีกทีเมื่อ USE พร้อม

การเลือกครั้งนี้จะไม่ยากเลยถ้าการรองรับอักษรธรรมใน Unicode มีทิศทางที่ชัดเจน แต่ปัญหาคือมันไม่ขยับมา 6 ปีแล้ว

แอปที่ใช้ Harfbuzz นั้นทำงานได้กับทุกทางเลือก ปัญหาอยู่ที่แอปนอกเหนือจากนั้น โดยในที่นี้คือ MS Word กับ Notepad ซึ่งเราต้องเลือกเอาอย่างใดอย่างหนึ่ง ถ้าใช้ USE ก็จะได้ MS Word ที่ทำงานได้เท่าที่ USE รองรับ ถ้าไม่ใช้ USE ก็จะได้ Notepad ที่ทำงานเต็มรูปแบบ

โดย Notepad เองก็ถือเป็นตัวแทนของแอปอื่นๆ ที่รองรับ OpenType แบบผิวเผินด้วย ในขณะที่ MS Word ก็น่าจะเป็นแอปหลักแอปหนึ่งที่ผู้ใช้ฟอนต์จะใช้เตรียมเอกสาร (แต่จะให้ดี LibreOffice เป็นทางเลือกที่เปิดกว้างต่อ solution ต่างๆ มากกว่า)

ผมจะวิเคราะห์ใน blog หน้าว่าจะพิจารณาชั่งน้ำหนักอย่างไรต่อไป

ป้ายกำกับ: ,

23 มิถุนายน 2564

Norasi Small Caps and Old Style Figures

ฟอนต์ Norasi เพิ่มการรองรับการใช้ small caps และ old style figures (ตัวเลขอารบิกแบบหนังสือยุคเก่า) แล้ว ทั้งใน OpenType และ LaTeX

PUA Glyphs

ฟอนต์ Norasi (ฟช ๓ จากโครงการฟอนต์แห่งชาติของเนคเทค) มี PUA glyph สำหรับตัว small caps และตัวเลขอารบิกในหนังสือยุคเก่า (old style figures) มานานแล้ว ผมไม่แน่ใจว่ามีมาตังแต่แรกเริ่มที่นำฟอนต์มาจากโครงการ Omega เลย หรือว่ามาเพิ่มเอาทีหลังใน TLWG เนื่องจากผู้ที่ทำงานกับ Norasi ในช่วงต้นจะเป็นคุณทิม (ชนพ ศิลปอนันต์) เป็นหลัก แต่มันก็อยู่ในรูป glyph ที่มีรหัสยูนิโค้ดในช่วง Private Use Area (PUA) พร้อมกับชื่อ glyph แบบ Postscript ตามอย่าง Adobe Glyph List เช่น เลขศูนย์แบบเก่ามีรหัสยูนิโค้ด U+F730 และมีชื่อ glyph เป็น zerooldstyle และตัว A small caps มีรหัสยูนิโค้ด U+F761 และมีชื่อ glyph เป็น Asmall เป็นต้น

PUA glyph เหล่านี้ โดยปกติจะไม่ใช้ในข้อความ แต่จะใช้เป็นการภายในของตัววาดข้อความ ในทำนองเดียวกับวรรณยุกต์ตัวต่ำ สระบนหลบหาง ป ฝ ฟ และสระอุ อู หลบหาง ฎ ฏ ในอักษรไทยนั่นเอง เท่ากับว่า PUA glyph เหล่านี้มีอยู่ แต่ยังไม่พร้อมใช้ ยกเว้นในระบบที่พยายามจะใช้ PUA เหล่านี้จริงๆ

OpenType

ขณะเดียวกัน เราจะเห็นแอปพลิเคชันสมัยใหม่พยายามรองรับ OpenType feature ต่างๆ ใน UI มากขึ้น จากเดิมที่มีแต่ใน desktop publishing หรูๆ ตอนนี้แม้แต่ word processor อย่าง LibreOffice Writer และ MS Word ก็เริ่มมี UI สำหรับเลือกเปิด/ปิด discretionary feature (ฟีเจอร์ที่กำหนดใน mark up ของเอกสาร และอาจจะผ่าน UI ให้ผู้ใช้เลือก) ของ OpenType แล้ว ซึ่ง small caps (smcp) และ old style figures (onum) ก็เป็นฟีเจอร์ชนิดนี้

หลังจากเพิ่มฟีเจอร์ดังกล่าวในฟอนต์ Norasi แล้วทดลองใช้กับ LibreOffice Writer ก็ได้ผลดังนี้:

  • บรรทัดแรก เป็นตัวเลขแบบเรียงบนบรรทัด (lining figures)
  • บรรทัดที่ 2 เป็นตัวเลขแบบหนังสือยุคเก่า (old style figures)
  • บรรทัดที่ 3 เพิ่มการใช้ small caps จาก glyph ในฟอนต์เอง ผ่าน scmp โดยเลือกฟีเจอร์ Lower case to small capitals ใน character format
  • บรรทัดที่ 4 ใช้ Small capitals จาก text format ของ LibreOffice เอง ซึ่งน่าจะเป็นการสังเคราะห์ small caps ด้วยการย่อส่วนจากตัว capital ปกติ ซึ่งทำให้ได้เส้นที่บางลง และ LibreOffice ก็ได้พยายามลดผลกระทบนี้ด้วยการย่อส่วนแต่เพียงเล็กน้อย ทำให้ได้ตัว small caps ที่ยังสูงกว่าตัว lower case อยู่

สำหรับการใช้ในเว็บ ผมได้ลองทำ หน้าทดสอบ โดยใช้ font-variant: small-caps และ font-variant-numeric: oldstyle-nums ใน CSS

LaTeX

สำหรับผู้ใช้ XeLaTeX และ LuaLaTeX ก็สามารถใช้ OpenType feature ได้โดยตรง แต่สำหรับ pdfLaTeX ซึ่งยังใช้เทคโนโลยี PostScript ธรรมดา ก็จำเป็นต้องมีการรองรับเพิ่มเติมในแพกเกจฟอนต์

Small Caps

LaTeX2e รองรับ small caps ผ่านคำสั่ง \scshape และ \textsc{...} โดยตัว TeX engine จะไปหาการประกาศ sc shape ใน font description (lthnorasi.fd สำหรับฟอนต์ Norasi) เพื่อเชื่อมโยงไปหาไฟล์ TFM (TeX Font Metrics) ของ shape ดังกล่าว

และตรง TFM นี่แหละ ที่เราสามารถ remap อักขระ lower case ไปหา glyph ที่เป็น small caps ได้ ทำให้ TeX เรียงพิมพ์ตัว lower case ด้วยตัว small caps แทน

เท่ากับว่า จากฟอนต์ Norasi ที่เรามีอยู่แล้ว 6 type face (regular, slanted, italic, bold, bold slated, bold italic) เราจะต้องสร้าง face ใหม่อีกหนึ่งชุดที่ remap สำหรับ small caps กลายเป็น 12 type face

แต่เรายังมีรายละเอียดที่ต้องพิจารณาเพิ่มจากการ remap คือ:

  • ต้องตัดกฎ ligature สำหรับ ff, fi, fl, ffi, ffl ออกด้วย เนื่องจากรูป small caps ไม่มี ligature ดังกล่าว
  • ฟอนต์ไทยใช้กฎ ligature ในการจัดเรียงสระ-วรรณยุกต์ที่ไม่ลอยและหลบหางพยัญชนะ (shaping) ซึ่งยังจำเป็นต้องสร้างกฎเหล่านี้สำหรับ small caps อยู่

นั่นจึงนำไปสู่การสร้างไฟล์ .enc ต่างหากที่ remap small caps, ตัดกฎ Latin ligature, คงกฎ ligature สำหรับอักษรไทย พร้อมทั้งเขียน make rules สำหรับสร้าง TFM (สำหรับ TeX) และ VF (virtual font ซึ่งใช้ในขั้น dvi) สำหรับ small caps เพิ่มอีกชุดหนึ่งด้วย

สรุปรวมอยู่ใน GitHub commit นั่นแล

และเมื่อใช้งานผ่านคำสั่ง \textsc{...} ก็ได้ผลดังภาพ:

Small caps in pdfLaTeX

Old Style Figures

ด้วยเทคโนโลยี PostScript ธรรมดา การรองรับตัวเลขแบบหนังสือยุคเก่า (old style figures) ก็ยังคงต้องใช้วิธี remap อักขระตัวเลขไปเป็น PUA glyph ที่เป็น old style ไม่ต่างกับ small caps เพียงแต่ old style figures จะมีประเด็นการใช้งานในทางปฏิบัติที่ต้องพิจารณาเพิ่มเติมด้วย

LaTeX2e มีคำสั่ง \oldstylenums{ตัวเลข) เพื่อแสดง ตัวเลข เป็นแบบ old style ได้ โดยจะใช้ glyph จากฟอนต์ของ Knuth เสมอ แต่ในกรณีที่ต้องการให้ผู้ใช้สามารถใช้ตัวเลข old style จากฟอนต์ของเราได้ ก็จะต้องใช้ช่องทางอื่น

use case ที่น่าจะพบบ่อยในชีวิตจริง คือการใช้ตัวเลข old style ทั้งเอกสาร ทั้งเลขบท เลขหัวข้อ เลขหน้า เลขในข้อความ ฯลฯ ซึ่งตรงนี้จะต่างจาก small caps และแพกเกจฟอนต์มักจะรองรับในรูปของ option ของแพกเกจ

อีก use case หนึ่งคือการใช้ตัวเลข old style เฉพาะที่ ซึ่งมีแพกเกจอย่างน้อยสองตัวที่เตรียมคำสั่งไว้ให้ คือ nfssext-cfr และ fontaxes ซึ่งทั้งสองแพกเกจจัดเตรียมคำสั่งไว้คนละชุด ซึ่งก็ถือเป็นเรื่องปกติ แต่ที่ไม่ปกติคือทั้งสองแพกเกจเรียกใช้ฟอนต์ต่างกันด้วย!

old style figures ไม่ได้ถูกจัดให้เป็น shape หนึ่งของฟอนต์เหมือน small caps เพราะมันมีผลแค่กับตัวเลข ไม่ใช่ทั้งฟอนต์ วิธี implement จึงไม่ใช่การประกาศ shape ใน font description แต่เป็นการสร้าง font family ใหม่ไปเลย! โดยจะมีข้อตกลงบางอย่างในการตั้งชื่อ family ใหม่ที่ว่านั้น และเมื่อผนวกกับคุณสมบัติ proportional/tabular ของตัวเลขเข้าไปด้วยก็กลายเป็นข้อตกลงที่มีรายละเอียดอีกหน่อย

ปัญหาคือ แพกเกจ nfssext-cfr และ fontaxes ใช้ข้อตกลงคนละชุดกัน!

  • nfssext-cfr ใช้ font naming ของ Karl Berry ซึ่งออกแบบมาเพื่อแทนชื่อฟอนต์ให้ได้ใน 8 ตัวอักษร case-insensitive ซึ่งหมายถึงระบบแฟ้มของ DOS นั่นเอง โดยใน 8 ตัวอักษรจะแทนทั้งผู้ผลิต (foundry), ชื่อฟอนต์, ความหนา, variant (เช่น italic, oblique, sans serif, monospace, small caps, old style figures ฯลฯ), encoding, ความกว้าง, ขนาด ซึ่งน่าอัศจรรย์มากกับความพยายามบีบอัดขนาดนั้น แต่ดูไม่ practical เท่าไรกับโลกที่มีฟอนต์มากมายมหาศาล อีกทั้งระบบแฟ้มส่วนใหญ่ในปัจจุบันก็รองรับความยาวเกิน 8 ตัวอักษรกันแทบทั้งสิ้นแล้ว และจะว่าไป ชื่อฟอนต์บางชื่อที่ลงรหัสแบบนี้ก็ยาวเกิน 8 ตัวอักษรไปแล้วด้วย แต่อย่างไรก็ดี มันก็ยังถือเป็นข้อตกลงที่ใช้กันเป็นมาตรฐานของ LaTeX อยู่ และฟอนต์ Norasi ที่ใช้ old style figures ก็จะลงรหัสชื่อ font family (แบบไม่ได้ตรงหลักการเป๊ะ) ได้เป็น norj และ font family แบบปกติก็จะถูกย่อลงเป็น norx (ว่าตามนัยประวัติ ฟอนต์ Norasi ใน ThaiLaTeX ยุคเริ่มแรกก็เคยใช้ชื่อว่า nf3x ก่อนที่จะเปลี่ยนเป็น norasi ในภายหลัง)
  • fontaxes ใช้ข้อตกลงชื่อฟอนต์ของตัวเอง โดยปล่อยชื่อฟอนต์ให้ยาวตามปกติ แล้วเติมท้ายด้วยรหัส variant เช่น Norasi-OsF โดย variant ที่เกี่ยวกับตัวเลขได้แก่
    • OsF = old style figures
    • LF = lining figures
    • TOsF = tabular old style figures
    • TLF = tabular lining figures
    โดยที่ก็ยังรองรับ font naming ของ Karl Berry ด้วย เพียงแต่ไม่ได้บีบความยาวลงเท่านั้น ดังนั้น ตามข้อตกลงนี้ ฟอนต์ Norasi ที่ใช้ old style figures ก็จะใช้ชื่อ font family เป็น norasi-TOsF, norasi-OsF หรือ norasij ก็ได้ เพราะอันที่จริง ตัวเลขในฟอนต์ Norasi เป็น tabular อยู่แล้ว คือกว้างเท่ากันหมด เรียงตรงกันในตารางได้ แต่การใช้ norasi-TOsF จะใช้ได้กับการ mark up ตัวเลขเป็น tabular figures เท่านั้น ใช้ในข้อความธรรมดาไม่ได้ ส่วน norasi-OsF จะใช้ได้ในข้อความธรรมดาและการ mark up เป็น proportional figures เท่านั้น ใช้แบบ tabular ไม่ได้ แต่ norasij จะใช้ได้หมดทุกกรณี ดังนั้น ในกรณีของ Norasi จึงเลือกใช้ชื่อ norasij

จากหลักการทำงานและจากการทดลอง fontaxes ดูจะใช้ได้ในทางปฏิบัติมากกว่า จึงเลือกรองรับ fontaxes เป็นหลัก แต่ก็พยายามรองรับ nfssext-cfr ด้วยตามสมควร

จาก 12 type face ที่ได้จากการทำ small caps มาแล้ว เราก็จะสร้าง font family ใหม่ที่ประกอบด้วย 12 type face นี้ แต่ remap glyph ของตัวเลขไปเป็นแบบ old style เท่ากับว่าเราจะมีทั้งหมด 24 type face แบ่งเป็น 2 family, family ละ 12 type face

เมื่อเขียน make rules เพื่อสร้าง TFM/VF ของ 12 type face ฉบับ old style figures แล้ว เราก็สร้าง LTHnorasij.fd เพื่อประกาศ font family norasij

เพื่อการรองรับ nfssext-cfr เราก็สร้าง LTHnorj.fd ในทำนองเดียวกัน และสร้าง LTHnorx.fd ที่มีเนื้อหาหลักเหมือน LTHnorasi.fd ทุกประการด้วย

ทั้งหมดนี้ก็จะสามารถรองรับใช้ตัวเลขแบบ old style ผ่าน fontaxes และ nfssext-cfr (บางส่วน) ได้แล้ว

Old style figures via fontaxes

Old style figures via nfssext-cfr

สำหรับ use case การใช้ตัวเลข old style ทั้งเอกสาร นั้น เราก็เพิ่ม option norasi-osf และ rmnorasi-osf ใน fonts-tlwg.sty โดยหากเลือกตัวเลือกนี้ก็จะกำหนดฟอนต์ปริยายเป็น norasij แทน norasi เท่านั้นเอง

Old style figures with 'norasi-osf' option

ทั้งหมดนี้อยู่ใน Git แล้ว มีตัวอย่างเอกสารในไดเรกทอรี latex/examples/ คือ:

  • oldnum.tex ใช้ตัวเลขแบบ old style ทั้งเอกสาร และใช้ small caps ในชื่อ section
  • digits-axes.tex ใช้ตัวเลขแบบ old style ผสมกับแบบ lining ผ่าน fontaxes พร้อมทั้งสาธิตการใช้ตัวเลขแบบ tabular/proportional ในตาราง
  • digits-cfr.tex ใช้ตัวเลขแบบ old style ผสมกับแบบ lining ผ่าน nfssext-cfr ซึ่งการใช้ตัวเลขแบบ tabular old style จะยังไม่ทำงาน

หลังจาก make install แล้ว สามารถใช้คำสั่ง make กับไฟล์ PDF ปลายทางได้เลย เช่น make oldnum.pdf

งานนี้สำเร็จลุล่วงได้ ขอให้เครดิตแก่พี่เลี้ยงที่มาช่วยดูแลพ่อ ทำให้ผมสามารถปลีกเวลามานั่งทำงานได้บ้าง

ป้ายกำกับ: , ,

07 มกราคม 2563

Fine-tuning Quadratic Splines in Fontforge

นับจากที่ได้เพิ่ม layer ผสมใน Fonts-TLWG เพื่อแก้ปัญหาเรื่อง build reproducibility ในรุ่น 0.7.0 ก็ได้เปิดช่องทางสำหรับการ fine-tune quadratric spline ของฟอนต์ TrueType เพียงแต่ผมยังไม่ได้ทำกับ Fonts-TLWG ในทันที เพราะได้กลับไปทำ layer ผสมกับ Fonts-Arundina เสียก่อน และได้ถือโอกาสทดลอง fine-tune quadratic spline ต่อด้วย

หลังจากที่เพิ่ม layer ผสมกับทุกฟอนต์ในชุด Arundina แล้ว ก็ได้ทดลอง fine-tune quadratic spline ต่อ ซึ่งก็ทำเสร็จแค่ Arundina Sans เท่านั้น พอมาทำ Arundina Sans Mono ต่อ ปรากฏว่าเกิดเหตุ Fontforge ตายกลางคันขณะ save ทำให้ข้อมูลที่แก้ไขมาได้ครึ่งทางแล้วสูญหายทั้งหมด แม้แต่กระบวนการ recovery ของ Fontforge เองก็กู้ข้อมูลขึ้นมาไม่ได้! ถ้าจะเริ่มใหม่ก็ต้อง check out ฉบับที่ยังไม่ปรับเส้นจาก git ออกมาทำใหม่นั่นแหละ

เป็นอุทาหรณ์ว่าควร commit git ให้บ่อยกว่านี้ ถึงยังไม่เสร็จก็ควร commit ไว้ก่อน แล้วค่อยใช้ option --amend ในครั้งต่อ ๆ ไปก็ยังได้!

ก็เลยตัดสินใจหยุดทำ Arundina ไว้แค่นั้น แล้วเตรียมตัดออกรุ่นใหม่เสียก่อน โดยขอบันทึกสิ่งที่ได้เรียนรู้จากการปรับเส้นฟอนต์ Arundina ไว้ ณ ที่นี้ก่อน ก่อนที่จะนำไปใช้กับ Fonts-TLWG ต่อไป

ปรับ Quadratic และ Cubic Spline ไปด้วยกัน

ในระยะแรกนั้น ผมปรับเฉพาะ quadratic layer เข้าหา cubic layer โดยพยายามให้ curve ทาบกับ cubic layer ได้สนิทด้วยจำนวนจุดที่พอเหมาะ โดยตัดจุดที่ไม่จำเป็นออก และเติมจุดบางจุดที่เห็นว่าน่าจะเป็นประโยชน์ต่อการ hint แต่เมื่อได้ปรับไปเรื่อย ๆ ก็ได้พบกรณีที่ต้องปรับ cubic layer ควบคู่กันมากขึ้นเรื่อย ๆ จนในที่สุดผมก็ปรับทั้งสอง layer ควบคู่กัน ซึ่งปรากฏว่าคุณสมบัติของโค้งทั้งสองแบบได้เสริมกันและกันในการจัด control point ต่าง ๆ ได้เป็นอย่างดี

การปรับทั้งสอง layer ควบคู่กันยังมีข้อดีอีกอย่าง คือเราสามารถลดปริมาณงานในอนาคตหากมีการ copy ข้ามจาก cubic layer มายัง quadratic layer อีกด้วย เพราะจะได้จำนวนจุด quadratic ที่เหมาะสมทันที ไม่ต้องมานั่งปรับใหม่ รวมถึงกรณีที่ต้องการ generate ฟอนต์ TrueType ด้วยการแปลงจาก cubic layer กลางอากาศ (อย่างที่เราเคยทำในสมัยก่อน)

หรือแม้กระทั่งสำหรับการ generate ฟอนต์ PostScript หรือฟอนต์ OpenType ที่ใช้ cubic spline เอง ก็จะได้โค้งที่ได้สมมาตรสวยงาม และยังอาจช่วยให้ rasterize ได้เร็วขึ้นสำหรับบาง engine ได้อีกด้วย (เช่น สำหรับ rasterizer ที่ render Bézier curve ด้วยการแบ่งครึ่ง curve แบบ recursive บนพื้นฐานของ De Casteljau’s algorithm)

ส่วนวิธีการปรับนั้นจะกล่าวถึงต่อไปเป็นลำดับ

Quadratic Spline ใน Fontforge

จากที่ผมเคยเขียนเปรียบเทียบ quadratic และ cubic spline ไว้เมื่อนานมาแล้ว ทั้งในแง่คณิตศาสตร์ การแปลงระหว่างกัน จำนวนจุดที่ใช้แทนโค้ง และการแก้ไข โดยในส่วนของการแก้ไขนั้น ผมได้กล่าวไว้ว่าโค้ง quadratic แก้ไขยากกว่า เพราะการแก้ไขแต่ละจุดจะกระทบถึงจุดข้างเคียงเสมอ แต่ Fontforge มีสิ่งที่ช่วยคลายความอึดอัดตรงนี้ ด้วยจุดต่อโค้งชนิด interpolated ที่ตำแหน่งของจุดต่อโค้งจะคำนวณจากจุดควบคุมข้างเคียง ทำให้ลดการกระทบกระทั่งลงได้

จุด interpolated ในที่นี้ขอเรียกว่า จุดกะ ในโค้ง quadratic เป็นจุดต่อโค้ง (curve point) ที่อยู่กึ่งกลางระหว่างจุดควบคุมสองจุด และในทางกลับกัน จุดต่อโค้งที่มีแขนสองข้างยาวเท่ากันก็จะถือเป็นจุดชนิด interpolated โดยอัตโนมัติใน Fontforge เช่นกัน (ยกเว้นจุดที่ผู้ใช้กำหนดให้ห้าม interpolate)

Quadratic interpolated point

ความพิเศษของจุดกะนี้ก็คือ การแก้ไขจุดควบคุมข้างหนึ่งจะไม่ส่งผลกระทบถึงจุดควบคุมอีกข้างหนึ่ง เพียงแต่จะทำให้ตำแหน่งของจุดกะเองเปลี่ยนไปเป็นจุดกึ่งกลางใหม่ ซึ่งทำให้เกิดผลคล้ายกับการแก้ไข cubic spline โดยไม่ต้องสนใจการมีอยู่ของจุดกะ

Editing with quadratic interpolated point

การประมาณ Cubic Curve ด้วย Quadratic Curve

ดังที่ได้กล่าวไว้ใน blog เดิม ว่าการแปลง quadratic curve เป็น cubic จะเป็นการแปลงแบบแม่นตรง แต่ในทางกลับกัน คือจาก cubic curve เป็น quadratic จะเป็นการประมาณเท่านั้น เนื่องจาก quadratic curve มีความเป็นอิสระ (degree of freedom) น้อยกว่า ดังนั้น เมื่อคุณคัดลอก spline จาก cubic layer มา quadratic layer จึงมีการประมาณค่าเกิดขึ้น

มีอัลกอริทึมจำนวนหนึ่งสำหรับประมาณ cubic curve ด้วย quadratic เช่น แบ่ง curve เป็นส่วนย่อย ๆ ที่เมื่อตัดสัมประสิทธิ์ดีกรีสามออกแล้วได้ quadratic curve ที่ใกล้เคียงพอ (มี paper ที่คล้ายกัน), แบ่งครึ่ง curve ที่ t=0.5 แล้ว solve หาจุดควบคุม quadratic curve ที่ใกล้เคียงของทั้งสองส่วน ฯลฯ

สำหรับ Fontforge แล้ว ใช้การประมาณด้วยจุดกะ โดยอยู่บนพื้นฐานของทฤษฎีซึ่งพบจากการทดลองแต่ยังไม่มีข้อพิสูจน์ทางคณิตศาสตร์ว่า ถ้าแบ่ง cubic curve เป็นช่วง ๆ ด้วย parameter ที่ห่างเท่า ๆ กันแล้ว ปรากฏว่าจุดแบ่งเหล่านั้นจะอยู่กึ่งกลางระหว่างจุดควบคุมข้างเคียงพอดี ซึ่งหมายความว่าสามารถแทนจุดแบ่งทุกจุดด้วยจุดกะได้ ด้วยทฤษฎีนี้ Fontforge จึงประมาณ cubic spline ด้วย quadratic spline ที่เติมจุดกะตามแนวเส้นโค้งเสมอ

Cubic spline approximation with quadratic spline

Fontforge จะพยายามประมาณโค้งโดยเติมจุดกะให้น้อยที่สุด ยิ่งไม่ต้องเติมจุดกะเลยยิ่งดี แต่หากยังคลาดเคลื่อนมากก็ลองเติมหนึ่งจุด สองจุด สามจุด ไปเรื่อย ๆ จนกว่าความคลาดเคลื่อนจะอยู่ในขอบเขตที่กำหนด

การลดจำนวนจุดกะใน Quadratic Curve

การประมาณของ Fontforge คือการประมาณในทางคณิตศาสตร์ที่มีความแม่นยำสูง แต่ในทาง design แล้ว เราอาจยอมรับความคลาดเคลื่อนได้บ้างโดยไม่ทำให้รูปตัวอักษรเพี้ยนไปจากเดิม ซึ่งแน่นอนว่าเรื่องการผ่อนผันที่ต้องใช้วิจารณญาณอย่างนี้ Fontforge จะไม่สู่รู้ตัดสินใจให้ เราจึงต้องปรับเองด้วยมือ

จากภาพในตัวอย่างข้างต้น มีการเติมจุดกะระหว่างกลาง 4 จุดใน quadratic curve แต่เราสามารถลดจำนวนจุดกะนี้ลงได้ ไม่ว่าจะเพื่อความเรียบง่าย เพื่อลดขนาดข้อมูล (ซึ่งสำคัญสำหรับ web font) หรือเพื่อประสิทธิภาพในการ hint และการ rasterize ก็ตาม โดยแนวทางการลดจุดกะที่เป็นไปได้คือ:

  1. ตัดจุดกะด้วยมือ โดยเลือกจุดกะที่ต้องการตัดแล้วสั่ง Merge (Ctrl-M)
  2. ปรับ cubic curve ต้นทางด้วยมือให้สามารถประมาณได้ด้วยจำนวนจุดที่น้อยลง

ทั้งสองวิธีจะได้ quadratic curve ที่คลาดเคลื่อนจาก cubic curve เดิมเล็กน้อย แต่วิธีที่สองจะทำให้ได้ spline สองแบบที่ทาบกันสนิทกว่าแบบแรก เพราะมันถูกปรับไปด้วยกัน

ในฟอนต์ตัวแรก ๆ ที่ทำ ผมใช้วิธีแรก แต่ต่อมาก็ค่อย ๆ เกิดความคิดว่าวิธีที่สองน่าจะเหมาะกว่า และในที่สุดก็เลือกวิธีที่สองเป็นหลัก

แล้ว cubic curve แบบไหนที่จะใช้จำนวนจุดกะน้อยลง?

ก่อนอื่น คนที่เคย edit cubic curve จะรู้ว่าเราสามารถปรับแขนทั้งสองของโค้งได้โดยยังได้โค้งที่ใกล้เคียงกับโค้งเดิม ด้วยการเพิ่มความยาวของแขนข้างหนึ่ง และลดความยาวของแขนอีกข้างหนึ่ง

Cubic curve adjustment

แน่นอนว่าในทางคณิตศาสตร์แล้ว โค้งที่ปรับแล้วถือว่าไม่ใช่โค้งเดียวกับโค้งเดิม แต่ความคลาดเคลื่อนระหว่างโค้งทั้งสองยังอยู่ในขอบเขตที่ยอมรับได้ด้วยสายตามนุษย์ โดยเฉพาะถ้าปรับไม่มาก แต่ถ้าปรับมากเกินไปก็จะเริ่มสังเกตเห็นความแตกต่างเมื่อนำมาทาบกัน (ซึ่งในทาง design เราก็อาจจะยังยอมรับได้อยู่ดี)

สำหรับโค้งในตัวอย่างข้างต้น เมื่อปรับแล้ว copy ข้ามมา quadratic layer เรากลับได้ curve ที่ใช้จุดกะเพียงจุดเดียว จากเดิมที่ใช้ถึง 4 จุด

Quadratic curve of the adjusted cubic curve

ถามว่า cubic curve แบบไหนที่ใช้จุดกะน้อย? แรก ๆ ที่ลองผิดลองถูกน้ัน ผมอาศัย sense เป็นหลัก คือพยายามให้แขนทั้งสองข้างได้ดุลกัน แต่เมื่อทำไปก็เริ่มถามตัวเองถึงคุณสมบัติทางคณิตศาสตร์ที่ชัดเจนกว่าการใช้ sense ซึ่งในที่สุดก็ได้คำตอบที่กลับไปหาพื้นฐานทางคณิตศาสตร์ของ cubic และ quadratic curve นั่นเอง

จาก blog เดิม ผมได้กล่าวไว้ว่า quadratic curve ที่มีจุดควบคุม P0, P1 และ P2 สามารถแทนได้ด้วย cubic curve ที่สมมูลกันโดยมีจุดควบคุม P0, (P0/3 + 2P1/3), (2P1/3 + P2/3), และ P2

Equivalent cubic curve of a quadratic curve

เราสามารถพูดในทางกลับกันได้ว่า cubic curve ที่ว่านี้ เมื่อแปลงเป็น quadratic curve ก็จะใช้จุดควบคุม P0, P1 และ P2 ได้ทันทีโดยไม่ต้องเติมจุดกะ

ถือเป็นอุดมคติของการประมาณโค้ง ยิ่งเราปรับ cubic curve ให้เข้าใกล้อุดมคตินี้มากเท่าไร เมื่อแปลงเป็น quadratic ก็จะใช้จุดกะระหว่างกลางน้อยลงเท่านั้น

อุดมคติที่ว่านี้ มีคุณสมบัติที่เห็นได้จากเรขาคณิตก็คือ เส้นตรงที่เชื่อมระหว่างจุดควบคุมทั้งสองขนานกันกับเส้นตรงที่เชื่อมระหว่างจุดปลายทั้งสอง โดยถ้าความยาวของแขนควบคุมเท่ากับ 2/3 ของระยะไปยังจุดตัดของแขนควบคุมทั้งสองพอดี ก็จะไม่ต้องใช้จุดกะเพิ่มเลย แต่ถ้าไม่ใช่ก็ต้องมีจุดกะเพิ่ม

ฉะนั้น แนวทางโดยทั่วไปก็คือ พยายามเล็งให้ polygon ที่เชื่อมระหว่างจุดปลายและจุดควบคุมของ cubic curve กลายเป็นสี่เหลี่ยมคางหมูหรือใกล้เคียง ซึ่งโดยทั่วไปก็จะทำให้มีจุดกะเพิ่มไม่เกิน 1 จุด

การปรับอื่น ๆ

ในบางกรณี ก่อนที่จะได้ cubic curve ที่สามารถแทนด้วย quadratic curve ที่เติมจุดกะไม่เกิน 1 จุด ก็อาจจำเป็นต้องปรับจุดต่อโค้งต่าง ๆ เพิ่มตามจำเป็น เช่น

  • เติมจุดบิดโค้ง (inflection point) เพื่อแบ่งโค้งที่บิดเป็นรูปตัว S ออกเป็นสองส่วน เนื่องจาก quadratic curve ไม่สามารถบิดเป็นตัว S ได้เหมือน cubic curve
  • เติมจุดต่อโค้งในโค้งที่หักเลี้ยวไม่สมมาตร จนจำเป็นต้องเติมจุดกะมากกว่า 1 จุด เช่น ในฟอนต์ตัวเอียงที่โค้งเดิมกำหนดจุดต่อโค้งที่ extrema เท่านั้น

การเติมจุดเหล่านี้ หากพิจารณาเฉพาะฟอนต์ที่ใช้ cubic spline อาจดูไม่จำเป็น แต่การเติมจุดต่อโค้งนอกจากจะช่วยให้ใช้จุดกะน้อยเมื่อแปลงเป็น quadratic แล้ว ก็ยังมีผลดีต่อการควบคุมความหนาของเส้นหมึกสำหรับ cubic spline เองด้วย เช่น การมีจุดกำกับที่จุดบิดโค้งก็ย่อมเพิ่มโอกาสการ hint หรือตรึงตำแหน่งที่จุดบิดโค้ง แทนที่จะปล่อยให้โค้งลอยไปมาตามผลการขยับจุดปลายระหว่าง apply hint

แผนการต่อไป

ในฟอนต์ชุด Arundina ที่กำลังจะตัดออกรุ่นนี้ ผมได้ปรับ spline เฉพาะฟอนต์ Arundina Sans เท่านั้น โดยใช้วิธีแรก (ยุบจุดกะใน quadratic spline เท่านั้น) และ commit ไปแล้ว ส่วน Arundina Sans Mono ผมเริ่มใช้วิธีที่สอง แต่น่าเสียดายที่ข้อมูลสูญหายไปหมด จึงไม่ได้รวมมาในรุ่นใหม่นี้ แต่จะนำหลักการที่ได้นี้ไปใช้ปรับฟอนต์ชุด Fonts-TLWG ในลำดับต่อไป

ป้ายกำกับ: , ,

21 ตุลาคม 2561

Reproducible Fonts-TLWG

ความเปลี่ยนแปลงล่าสุดใน Fonts-TLWG คือเรื่อง reproducibility คือการ build ที่ให้ผลลัพธ์เป็น binary file ที่เป็นข้อมูลเดิมทุกบิตทุกครั้งที่ build โดยไม่ขึ้นกับสภาวะที่ใช้ในการ build

สำหรับฟอนต์จากโครงการ Fonts-TLWG มีปัญหา reproducibility ตามที่รายงานโดย Debian คือ modification timestamp ที่เกิดจาก Fontforge script ที่ใช้ build โดยมีการเปลี่ยนแปลงข้อมูลของฟอนต์ระหว่างทาง ทำให้ timestamp ของการเปลี่ยนแปลงถูกปรับเป็นเวลาขณะ script ทำงานนั้น และทำให้ข้อมูลฟอนต์ผลลัพธ์แปรเปลี่ยนไปตามเวลาที่ build

Modification กลางอากาศ

script ที่ใช้ generate ฟอนต์ชนิดต่าง ๆ จะมีการเปลี่ยนแปลงข้อมูลฟอนต์กลางอากาศขณะ build ดังนี้

  • OTF และ WOFF จะมีการตัด PUA glyphs สำหรับสระบน-ล่างและวรรณยุกต์ที่เลื่อนหลบหางพยัญชนะ
  • TTF มีการแปลง cubic spline เป็น quadratic ก่อน apply AutoInstr
  • LaTeX fonts (Postscript + TeX virtual fonts) จะไม่มี modification ใด ๆ

PUA Glyphs

PUA (Unicode Private Use Area) glyphs สำหรับสระบน-ล่างและวรรณยุกต์ที่เลื่อนหลบหางพยัญชนะ เป็นสิ่งจำเป็นสำหรับการ render ข้อความในสภาวะที่ไม่มีเทคโนโลยี OpenType เช่น บน Windows XP และการใช้ virtual font ใน TeX engine เก่า (เช่น pdfTeX) ซึ่งเราได้ตัดสินใจยกเลิกการรองรับ TTF แบบเก่าไปนานแล้ว แต่ยังไม่สามารถตัดการรองรับ TeX engine เก่าได้ จึงยังคง PUA glyphs ไว้ใน source ของฟอนต์ แต่ใช้วิธีลบกลางอากาศขณะ gen OTF และ TTF เอา

แต่การลบ glyph กลางอากาศนี่เองที่เป็นสาเหตุหนึ่งที่ทำให้ modification timestamp ของฟอนต์เปลี่ยน และทำให้ได้ไฟล์ฟอนต์ที่ไม่ reproducible

วิธีแก้ปัญหาก็เป็นไปได้สองทาง:

  1. ไม่ต้องตัด PUA glyphs เลย ใส่เกินไว้ในฟอนต์อย่างนั้นแหละ การมีอยู่ของ OpenType tables ต่าง ๆ จะทำให้ shaping engine อย่าง Harfbuzz ไม่ fallback มาใช้ PUA shaping เมื่อเจอ PUA glyphs ในฟอนต์
  2. ตัด PUA glyphs ออกจาก source ไปเลย ซึ่งจะหมายถึงการตัดการรองรับ shaping ผ่าน TeX virtual font ด้วย ผลคือ ตัดการรองรับ pdfTeX ไปเลย และหยุดอัปเดตแพกเกจ fonts-tlwg บน CTAN ไปเสีย

ทางเลือก 2 ดูจะเป็นเรื่องใหญ่ ผมคิดว่าควรชะลอไปก่อน และเลือกทางเลือก 1 ไว้ก่อน และได้ commit ไปตามนี้

TrueType Instructions

เพื่อเพิ่ม hint ให้กับฟอนต์ TrueType ในขณะที่ source ของเราอยู่ในรูป cubic spline ตัว script จึงใช้วิธีแปลง spline ให้เป็น quadratic ก่อน แล้ว apply AutoInstr กลางอากาศก่อน generate TTF

ซึ่งการแปลงและสั่ง AutoInstr ทำให้ modification timestamp ของฟอนต์เปลี่ยน ทำให้ได้ไฟล์ฟอนต์ที่ไม่ reproducible อีกเช่นกัน

ผมค้นคิดวิธีที่จะแก้ปัญหานี้ไปเรื่อย ๆ จนในที่สุดก็ได้ไอเดียการทำ mixed layers โดยมีหลักการคือ:

  • เพิ่ม layer ที่สี่ในไฟล์ SFD เป็นชนิด quadratic แล้ว copy spline ทั้งหมดจาก Front Layer ซึ่งเป็น cubic มายัง qudratic layer นี้ ซึ่ง Fontforge จะแปลง spline ให้ขณะ copy
  • เราสามารถแก้ไข quadratic spline ใน layer ใหม่นี้ได้ หรือหากต้องการ fine-tune TrueType instructions ก็ทำได้ แต่ในเบื้องต้นนี้ยังไม่ edit ใด ๆ และใช้ AutoInstr ไปก่อน
  • ในการ generate TTF ใน dialog box จะสามารถเลือกให้ generate จาก quadratic layer แทน Front Layer ได้ และใน script อัตโนมัติก็สามารถกำหนด layer ที่จะใช้ได้เช่นกัน เพียงแต่การเลือก layer ยังไม่รองรับใน Fontforge native script ด้วยข้อจำกัดเรื่อง syntax แต่ใน Python script สามารถทำได้

เมื่อได้หลักการเช่นนี้แล้ว ก็ได้แตก branch mixed-layer-ttf เพื่อดำเนินการ โดยตั้งชื่อ quadratic layer ให้เหมือนกันทุกฟอนต์ว่า Quad เพื่อจะได้ใช้ชื่อนี้ใน script ให้ทำงานได้ทุกฟอนต์ และเปลี่ยนมาใช้ Python script สำหรับ TTF แทน native script เดิม

ด้วยหลักการเช่นนี้ source สำหรับ TTF ก็จะเตรียมพร้อมอยู่ใน source สำหรับ generate ได้โดยไม่ต้องแก้ไขกลางอากาศอีก

ทำเสร็จหมดแล้ว ก็ merge เข้า master เสีย เป็นอันเสร็จพิธี

ส่วน LaTeX fonts ไม่มีประเด็นอะไรต้องแก้ ผลคือ ขณะนี้ fonts-tlwg สามารถ build แบบ reproducible ได้ทั้งหมดแล้ว

อนาคต

ประเด็นที่น่าจะทำในอนาคต:

  • ตัดสินใจว่าจะทำอย่างไรกับ PUA glyphs เช่น
    • หาวิธี ข้าม PUA glyphs ขณะ generate โดยไม่ต้องลบ glyph เพื่อจะได้หลีกเลี่ยง modification timestamp
    • ตัด PUA glyphs ออกจาก source เลยไหม? ซึ่งจะหมายถึงการตัดการรองรับ shaping ผ่าน TeX virtual font สำหรับ engine เก่าอย่าง pdfTeX ด้วย
  • Quad layer ที่เกิดขึ้นได้ให้อิสระในการปรับแต่ง TrueType spline และ instruction แล้ว สามารถ fine-tune ต่อไปในอนาคตได้

ป้ายกำกับ: , ,

14 มิถุนายน 2559

Fonts-TLWG 0.6.3

Fonts-TLWG 0.6.3 ออกแล้ว เมื่ออาทิตย์ที่แล้ว แต่เพิ่งจะได้เขียน blog บันทึกหลังจากที่เตรียมแพกเกจเพื่ออัปโหลดในที่ต่าง ๆ เสร็จ คือที่ Debian และ CTAN

รุ่นนี้เป็นรุ่นแรกที่ ออกรุ่นจาก GitHub หลังจากที่ ประกาศย้าย repository ของ TLWG ไปที่ GitHub เมื่อเดือนที่แล้ว แต่ยังคงใช้ linux.thai.net เป็นที่ประกาศหลักตามเดิม เพื่อความต่อเนื่องกับรุ่นก่อน ๆ

ความเปลี่ยนแปลงหลักที่เกิดขึ้นในรุ่นนี้ คือการเปลี่ยนให้ฟอนต์ Loma เป็นฟอนต์ UI หลักแทน Waree อันเนื่องมาจาก รายงานบั๊กของพี่สัมพันธ์ พร้อม follow-up ว่าฟอนต์ Waree นั้นตัวสูงเกินไปจนถูกขริบในบางเว็บ เช่น Facebook แต่ Loma นั้นเตี้ยพอที่จะเล็ดรอดมาได้ (เหตุผลก็คือ Waree นั้นออกแบบเพื่อเตรียมเพิ่มอักษรไทยให้กับฟอนต์ DejaVu Sans จึงมี glyph ละตินของ DejaVu Sans ซึ่งตัวสูงอยู่แล้วเป็นตัวตั้ง ส่วน Loma นั้น เข้าใจว่าออกแบบโดยอิสระของตัวเอง) หลังจากทดสอบและฟังความเห็นของหลาย ๆ ท่านที่มาคอมเมนต์ ก็เห็นว่าควรเลื่อนอันดับของฟอนต์ Loma ขึ้นมาสูงกว่า Waree ในการเลือกฟอนต์ sans-serif ของ fontconfig

ในการเลื่อนขั้นนั้น ตามหลักแล้วควรจะทำได้ง่าย ๆ ด้วยการเปลี่ยนลำดับแฟ้ม config ของ fontconfig ให้ Loma ขึ้นก่อน Waree เช่น เปลี่ยนชื่อแฟ้ม /etc/fonts/conf.d/64-12-tlwg-loma.conf ในรุ่น 0.6.2 ให้เป็น 64-10-tlwg-loma.conf แต่ทำแค่นั้นไม่ได้ช่วยให้ Loma มาก่อน Waree ได้ เพราะยังมีกฎชุด synthetic อีกชุดหนึ่งเข้ามามีส่วนด้วย ดังผลลัพธ์หลังเปลี่ยนชื่อแฟ้มดังกล่าว ก็ยังคง match sans-serif ได้ Waree เช่นเดิม (ในรุ่น 0.6.2):

$ cd /etc/fonts/conf.d
$ sudo mv 64-12-tlwg-loma.conf 64-10-tlwg-loma.conf
$ fc-match sans-serif
Waree.otf: "Waree" "Regular"

สาเหตุคือฟอนต์ Waree มีการจำลองตัวเองเพื่อทดแทนฟอนต์ Tahoma ด้วยการห้อยชื่อตัวเองในลำดับต่อจาก Tahoma (ในไฟล์ 89-tlwg-waree-synthetic.conf) แต่ด้วยความที่ Tahoma ได้ถูกกำหนดให้เป็น preferred font ตัวหนึ่งของละติน (ในไฟล์ 60-latin.conf) ซึ่งมาก่อนภาษาอื่น ๆ การจำลอง Tahoma ของ Waree จึงทำให้ Waree กลายเป็นฟอนต์ละตินตัวหนึ่งที่มาก่อนภาษาอื่น ๆ ไปด้วย!

รายละเอียดทางเทคนิคของการตรวจสอบ ผู้ที่สนใจสามารถอ่านได้ที่ส่วนท้ายของ blog

ฉะนั้น การจะเลื่อนขั้น Loma ขึ้น จึงติดที่กฎชุด synthetic ของ Waree นี้

แล้วกฎ synthetic นี้มาจากไหน? มันเริ่มมาจากแนวคิดการจำลองฟอนต์ที่ผู้ใช้นิยมใช้ในเอกสารต่าง ๆ บนวินโดวส์ด้วยฟอนต์ที่มีในชุด Fonts-TLWG เช่น จำลอง Angsana ด้วย Kinnari, จำลอง Browallia ด้วย Garuda ฯลฯ ดังมีบันทึกไว้ใน blog เก่าเมื่อปี 2550 ซึ่งฟอนต์ต่าง ๆ ก็มีเค้าหน้าตาให้จำลองกันได้ จนกระทั่งมาเจอกรณีการใช้ฟอนต์ MS Sans Serif และ Tahoma ในเว็บ จึงได้พยายามทดแทนด้วยฟอนต์ Loma และ Waree ตามลำดับ ดังอ้างถึงใน blog เก่าเมื่อปี 2552 โดยที่ทั้งสองฟอนต์นี้ไม่ได้มีเค้าของฟอนต์ที่จำลองเลย เพียงแต่ต้องการอุดช่องว่างของการแสดงหน้าเว็บเท่านั้น

กฎนี้เคยถูกรายงานว่าสร้างปัญหาให้กับภาษาอื่น เพราะ Waree จะโผล่มาแทน Tahoma ทั้ง ๆ ที่ตัวใหญ่กว่า Tahoma (LP #434054) ทำให้เคยตัดกฏนี้ออกไปชั่วระยะหนึ่ง แต่ก็เพิ่มกลับเข้ามาพร้อมกับการตรวจสอบภาษาเพิ่มเติมเพื่อให้ apply กับภาษาไทยเท่านั้น (LP #539008) ดังบันทึกใน thaifonts-scalable 0.4.14 แต่ในเมื่อมันมารบกวนการจัดอันดับฟอนต์ sans-serif ไทยทั้งระบบ ก็เห็นควรว่าควรตัดกฎ synthetic นี้ออก แล้วปล่อยให้ฟอนต์ sans-serif ที่ได้อันดับสูงสุดมาอุด Tahoma เอา

เมื่อตัดกฎ synthetic ออก ฟอนต์ Loma ก็ได้อันดับสูงกว่า Waree แล้ว

อีกประเด็นหนึ่งที่พบระหว่างทดลองใช้ Loma เป็นฟอนต์ UI หลัก นอกเหนือจากขนาดที่เล็กลงถนัดตาที่ใช้เวลาสักพักก็จะชินแล้ว ก็มีเรื่องความกว้างของอักขระเว้นวรรค (space) ที่กว้างเกินพอดี และเมื่อเทียบกับฟอนต์ทั่วไปก็ยิ่งยืนยันได้ จึงได้ปรับลดความกว้างของอักขระเว้นวรรคให้แคบลง ซึ่งก็ทำให้ย่อหน้าภาษาอังกฤษไม่ดูโหรงเหรงจนเกินไป

ก่อนปรับ:

Loma spacing in 0.6.2

หลังปรับ:

Loma spacing in 0.6.3

ทั้งหมดนั้น เสิร์ฟถึงคุณแล้วในรุ่น 0.6.3 ครับ!


ต่อไปนี้เป็นวิธีตรวจสอบการ apply กฎของ fontconfig ด้วยตัวเอง ซึ่งทำให้เห็นว่ากฎ synthetic ใน 0.6.2 ทำให้ Waree ล้ำหน้าฟอนต์ไทยอื่น ๆ ได้อย่างไร

วิธีตรวจสอบตามที่ เอกสาร fontconfig ได้อธิบายไว้ คือกำหนดตัวแปร environment FC_DEBUG โดยในที่นี้เราสนใจการ edit match pattern ในกฎต่าง ๆ ก็กำหนดค่าเป็น 4 แล้วเรียก fc-match ดังนี้:

$ FC_DEBUG=4 fc-match sans-serif

มันจะพ่นข้อความแสดงการ edit match pattern ในแต่ละขั้นออกมายืดยาว ก็อาจจะ redirect ลงแฟ้มแล้วมาตรวจสอบดู ก็จะพบขั้นตอนที่น่าสนใจคือ:

...

FcConfigSubstitute test pattern any family Equal(ignore blanks) "sans-serif"
Substitute Edit family Prepend "Bitstream Vera Sans" Comma "DejaVu Sans" Comma "
Verdana" Comma "Arial" Comma "Albany AMT" Comma "Luxi Sans" Comma "Nimbus Sans L
" Comma "Helvetica" Comma "Lucida Sans Unicode" Comma "BPG Glaho International" 
Comma "Tahoma"

Prepend list before  "DejaVu Sans"(w) "DejaVu LGC Sans"(w) "DejaVu LGC Sans"(w) 
[marker] "sans-serif"(s) "sans-serif"(w)
Prepend list after  "DejaVu Sans"(w) "DejaVu LGC Sans"(w) "DejaVu LGC Sans"(w) "
Bitstream Vera Sans"(w) "DejaVu Sans"(w) "Verdana"(w) "Arial"(w) "Albany AMT"(w)
 "Luxi Sans"(w) "Nimbus Sans L"(w) "Helvetica"(w) "Lucida Sans Unicode"(w) "BPG 
Glaho International"(w) "Tahoma"(w) "sans-serif"(s) "sans-serif"(w)

...

กฎนี้มาจาก 60-latin.conf ของ fontconfig เอง ที่เพิ่ม prefer list ของ sans-serif โดยมี Tahoma พ่วงอยู่ด้วย

จากนั้น ก็มีการ edit match pattern ต่อ ๆ มา จนมาถึงตรงนี้:

...

FcConfigSubstitute test pattern any family Equal(ignore blanks) "sans-serif"
Substitute Edit family Prepend "Loma"

Prepend list before  "DejaVu Sans"(w) "DejaVu LGC Sans"(w) "DejaVu LGC Sans"(w) 
"Bitstream Vera Sans"(w) "DejaVu Sans"(w) "Verdana"(w) "Arial"(w) "Albany AMT"(w
) "Luxi Sans"(w) "Nimbus Sans L"(w) "Helvetica"(w) "Lucida Sans Unicode"(w) "BPG
 Glaho International"(w) "Tahoma"(w) [marker] "sans-serif"(s) "sans-serif"(w)
Prepend list after  "DejaVu Sans"(w) "DejaVu LGC Sans"(w) "DejaVu LGC Sans"(w) "
Bitstream Vera Sans"(w) "DejaVu Sans"(w) "Verdana"(w) "Arial"(w) "Albany AMT"(w)
 "Luxi Sans"(w) "Nimbus Sans L"(w) "Helvetica"(w) "Lucida Sans Unicode"(w) "BPG 
Glaho International"(w) "Tahoma"(w) "Loma"(w) "sans-serif"(s) "sans-serif"(w)

...

FcConfigSubstitute test pattern any family Equal(ignore blanks) "sans-serif"
Substitute Edit family Prepend "Waree"

Prepend list before  "DejaVu Sans"(w) "DejaVu LGC Sans"(w) "DejaVu LGC Sans"(w) 
"Bitstream Vera Sans"(w) "DejaVu Sans"(w) "Verdana"(w) "Arial"(w) "Albany AMT"(w
) "Luxi Sans"(w) "Nimbus Sans L"(w) "Helvetica"(w) "Lucida Sans Unicode"(w) "BPG
 Glaho International"(w) "Tahoma"(w) "Loma"(w) [marker] "sans-serif"(s) "sans-se
rif"(w)
Prepend list after  "DejaVu Sans"(w) "DejaVu LGC Sans"(w) "DejaVu LGC Sans"(w) "
Bitstream Vera Sans"(w) "DejaVu Sans"(w) "Verdana"(w) "Arial"(w) "Albany AMT"(w)
 "Luxi Sans"(w) "Nimbus Sans L"(w) "Helvetica"(w) "Lucida Sans Unicode"(w) "BPG 
Glaho International"(w) "Tahoma"(w) "Loma"(w) "Waree"(w) "sans-serif"(s) "sans-s
erif"(w)

...

ซึ่งก็ดูเรียบร้อยดี Loma น่าจะ match ก่อน Waree แล้ว จนกระทั่งมาถึงตรงนี้:

...

FcConfigSubstitute test pattern any lang Contains "th"
FcConfigSubstitute test pattern any family Equal "Tahoma"
Substitute Edit family Append "Waree"

Append list before  "DejaVu Sans"(w) "DejaVu LGC Sans"(w) "DejaVu LGC Sans"(w) "
Bitstream Vera Sans"(w) "DejaVu Sans"(w) "Verdana"(w) "Arial"(w) "Albany AMT"(w)
 "Luxi Sans"(w) "Nimbus Sans L"(w) "Helvetica"(w) "Lucida Sans Unicode"(w) "BPG 
Glaho International"(w) "Tahoma"(w) [marker] "Loma"(w) "Waree"(w) "Garuda"(w) "U
mpush"(w) "Laksaman"(w) "Meera"(w) "Khmer OS"(w) "Nachlieli"(w) "Lucida Sans Uni
code"(w) "Yudit Unicode"(w) "Kerkis"(w) "ArmNet Helvetica"(w) "Artsounk"(w) "BPG
 UTF8 M"(w) "Waree"(w) "Loma"(w) "Garuda"(w) "Umpush"(w) "Saysettha Unicode"(w) 
"JG Lao Old Arial"(w) "GF Zemen Unicode"(w) "Pigiarniq"(w) "B Davat"(w) "B Comps
et"(w) "Kacst-Qr"(w) "Urdu Nastaliq Unicode"(w) "Raghindi"(w) "Mukti Narrow"(w) 
"padmaa"(w) "Hapax Berbère"(w) "MS Gothic"(w) "UmePlus P Gothic"(w) "SimSun"(w) 
"PMingLiu"(w) "WenQuanYi Zen Hei"(w) "WenQuanYi Bitmap Song"(w) "AR PL ShanHeiSu
n Uni"(w) "AR PL New Sung"(w) "MgOpen Moderna"(w) "MgOpen Modata"(w) "MgOpen Cos
metica"(w) "VL Gothic"(w) "IPAMonaGothic"(w) "IPAGothic"(w) "Sazanami Gothic"(w)
 "Kochi Gothic"(w) "AR PL KaitiM GB"(w) "AR PL KaitiM Big5"(w) "AR PL ShanHeiSun
 Uni"(w) "AR PL SungtiL GB"(w) "AR PL Mingti2L Big5"(w) "MS ゴシック"(w) "ZYSo
ng18030"(w) "NanumGothic"(w) "UnDotum"(w) "Baekmuk Dotum"(w) "Baekmuk Gulim"(w) 
"KacstQura"(w) "Lohit Bengali"(w) "Lohit Gujarati"(w) "Lohit Hindi"(w) "Lohit Ma
rathi"(w) "Lohit Maithili"(w) "Lohit Kashmiri"(w) "Lohit Konkani"(w) "Lohit Nepa
li"(w) "Lohit Sindhi"(w) "Lohit Punjabi"(w) "Lohit Tamil"(w) "Meera"(w) "Lohit M
alayalam"(w) "Lohit Kannada"(w) "Lohit Telugu"(w) "Lohit Oriya"(w) "LKLUG"(w) "F
reeSans"(w) "Arial Unicode MS"(w) "Arial Unicode"(w) "Code2000"(w) "Code2001"(w)
 "sans-serif"(s) "Arundina Sans"(w) "Roya"(w) "Koodak"(w) "Terafik"(w) "sans-ser
if"(w) "sans-serif"(w) "sans-serif"(w) "sans-serif"(w) "sans-serif"(w) "sans-ser
if"(w) "sans-serif"(w) "sans-serif"(w)
Append list after  "DejaVu Sans"(w) "DejaVu LGC Sans"(w) "DejaVu LGC Sans"(w) "B
itstream Vera Sans"(w) "DejaVu Sans"(w) "Verdana"(w) "Arial"(w) "Albany AMT"(w) 
"Luxi Sans"(w) "Nimbus Sans L"(w) "Helvetica"(w) "Lucida Sans Unicode"(w) "BPG G
laho International"(w) "Tahoma"(w) "Waree"(w) "Loma"(w) "Waree"(w) "Garuda"(w) "
Umpush"(w) "Laksaman"(w) "Meera"(w) "Khmer OS"(w) "Nachlieli"(w) "Lucida Sans Un
icode"(w) "Yudit Unicode"(w) "Kerkis"(w) "ArmNet Helvetica"(w) "Artsounk"(w) "BP
G UTF8 M"(w) "Waree"(w) "Loma"(w) "Garuda"(w) "Umpush"(w) "Saysettha Unicode"(w)
 "JG Lao Old Arial"(w) "GF Zemen Unicode"(w) "Pigiarniq"(w) "B Davat"(w) "B Comp
set"(w) "Kacst-Qr"(w) "Urdu Nastaliq Unicode"(w) "Raghindi"(w) "Mukti Narrow"(w)
 "padmaa"(w) "Hapax Berbère"(w) "MS Gothic"(w) "UmePlus P Gothic"(w) "SimSun"(w)
 "PMingLiu"(w) "WenQuanYi Zen Hei"(w) "WenQuanYi Bitmap Song"(w) "AR PL ShanHeiS
un Uni"(w) "AR PL New Sung"(w) "MgOpen Moderna"(w) "MgOpen Modata"(w) "MgOpen Co
smetica"(w) "VL Gothic"(w) "IPAMonaGothic"(w) "IPAGothic"(w) "Sazanami Gothic"(w
) "Kochi Gothic"(w) "AR PL KaitiM GB"(w) "AR PL KaitiM Big5"(w) "AR PL ShanHeiSu
n Uni"(w) "AR PL SungtiL GB"(w) "AR PL Mingti2L Big5"(w) "MS ゴシック"(w) "ZYS
ong18030"(w) "NanumGothic"(w) "UnDotum"(w) "Baekmuk Dotum"(w) "Baekmuk Gulim"(w)
 "KacstQura"(w) "Lohit Bengali"(w) "Lohit Gujarati"(w) "Lohit Hindi"(w) "Lohit M
arathi"(w) "Lohit Maithili"(w) "Lohit Kashmiri"(w) "Lohit Konkani"(w) "Lohit Nep
ali"(w) "Lohit Sindhi"(w) "Lohit Punjabi"(w) "Lohit Tamil"(w) "Meera"(w) "Lohit 
Malayalam"(w) "Lohit Kannada"(w) "Lohit Telugu"(w) "Lohit Oriya"(w) "LKLUG"(w) "
FreeSans"(w) "Arial Unicode MS"(w) "Arial Unicode"(w) "Code2000"(w) "Code2001"(w
) "sans-serif"(s) "Arundina Sans"(w) "Roya"(w) "Koodak"(w) "Terafik"(w) "sans-se
rif"(w) "sans-serif"(w) "sans-serif"(w) "sans-serif"(w) "sans-serif"(w) "sans-se
rif"(w) "sans-serif"(w) "sans-serif"(w)

...

กลายเป็นว่า Waree กลับมาแซงหน้า Loma อีกครั้งหลังจากกฎใน 89-tlwg-waree-synthetic.conf ผลก็คือ ไม่ว่าฟอนต์ไทยตัวไหนจะพยายามลิสต์ตัวเองขึ้นก่อนอย่างไรก็ตาม ก็จะแพ้ฟอนต์ที่ fallback ให้ Tahoma อยู่วันยังค่ำ และการสังเคราะห์ฟอนต์ Tahoma ด้วย Waree ก็ทำให้ Waree ไม่ยอมลงให้กับใคร!

ป้ายกำกับ: ,

04 กุมภาพันธ์ 2559

Thai Font Metrics

ประเด็นเล็ก ๆ ประเด็นหนึ่งที่ถูกอภิปรายกันในหลายโอกาสในหมู่คนทำฟอนต์ไทย หรือกระทั่งในหมู่ผู้ใช้ที่ต้องเตรียมเอกสารให้เข้ากับข้อกำหนด คือเรื่องขนาดของฟอนต์ไทยที่จะเล็กกว่าฟอนต์ตะวันตกที่ point size เดียวกัน เช่น บทความภาษาอังกฤษอาจกำหนดขนาดฟอนต์เป็น 10 หรือ 11 point แต่ถ้าใช้ฟอนต์ไทยขนาดเดียวกันจะเล็กจนอ่านไม่ออก ต้องปรับขนาดเพิ่มเป็น 14 หรือ 16 point ถึงจะเทียบเคียงกันได้ เรื่องนี้คุณเนยสดได้ เขียนอธิบายไว้แล้วเป็นอย่างดี

ฟอนต์จาก TLWG

สำหรับฟอนต์ชุดต่าง ๆ ที่ TLWG ผมได้ปรับขนาดตัวอักษรให้ใหญ่ขึ้น เพื่อให้เข้ากันกับฟอนต์ตะวันตกทั้งหมด ไม่ว่าจะเป็น Fonts-TLWG, Fonts-SIPA-Arundina หรือ ThaiFonts-Siampradesh ทำให้เกิดความไม่เข้ากันกับฟอนต์ไทยอื่น ๆ ที่มีอยู่ในตลาด

สำหรับที่มาที่ไป ผมตัดสินใจใช้ font metrics ที่เข้ากันกับฟอนต์ตะวันตกหลังจากที่ได้พูดคุยกับผู้ใช้และนักพัฒนาใน thread หนึ่งใน gtk-i18n list เมื่อปี 2547 โดยในขณะนั้น ฟอนต์ต่าง ๆ ที่พัฒนา ปรับปรุง และเผยแพร่โดย TLWG ยังใช้ขนาดเหมือนฟอนต์ไทยในตลาด และมีฝรั่งที่พยายามเรียนภาษาไทยบ่นเข้ามาว่าฟอนต์ไทยตัวเล็กมาก อ่านไม่ออก มีฟอนต์ที่ตัวใหญ่กว่านี้แนะนำไหม ผมพยายามอธิบายเหตุผลที่ฟอนต์ไทยต้องตัวเล็ก ว่าเราต้องเผื่อเนื้อที่ให้กับสระบน-ล่างและวรรณยุกต์ ก็ปรากฏว่านักพัฒนา Pango (Owen Taylor) ได้ แนะนำ ว่าสามารถใช้ขนาดตัวอักษรที่เท่ากับฟอนต์ตะวันตกได้ โดยเพียงแต่ขยายระยะระหว่างบรรทัดให้สูงขึ้น และได้รับการ สำทับ จาก Javier Sola นักพัฒนา Khmer OS ว่าฟอนต์ภาษาเขมรก็ใช้วิธีนี้ และได้ผลดี

ในขณะนั้น เรามีฟอนต์ Loma จาก NECTEC ที่เริ่มบุกเบิกทำฟอนต์ UI โดยใช้ metrics ที่สอดคล้องกับฟอนต์ตะวันตกเป็นตัวอย่างอยู่แล้ว หลังจากที่ในวินโดวส์มีฟอนต์ Tahoma ที่ทำงานในลักษณะนี้มาแล้วระยะหนึ่ง เมื่อนำมาประกอบกับข้อมูลที่ได้จากชุมชน GTK+ ดังกล่าว ผมจึงตัดสินใจปรับขนาดฟอนต์ไทยทั้งหมดในแหล่งของ TLWG ตามฟอนต์ตะวันตกตั้งแต่นั้นมา

Font Metrics แบบไทย

ย้อนกลับไปที่ที่มาของ font metrics แบบไทยที่มีการย่อส่วนลงมา เหตุผลเป็นที่เข้าใจได้ไม่ยาก ว่ามาจากการเผื่อเนื้อที่ให้กับสระบน-ล่างและวรรณยุกต์ ทำให้ต้องย่อขนาดของพยัญชนะลง และเพื่อให้เข้ากันกับตัวโรมัน ก็จำเป็นต้องย่อขนาดของตัวโรมันลงตามด้วย ทำให้ตัวโรมันของฟอนต์ไทยมีขนาดเหลือเพียงประมาณ 70% ของฟอนต์ตะวันตกที่มี point size เท่ากัน

เรื่องนี้มีตัวอย่างอย่างละเอียดในหนังสือ แบบตัวพิมพ์ไทย ที่จัดพิมพ์โดยโครงการฟอนต์แห่งชาติของ NECTEC เมื่อ พ.ศ. 2543

Thai font metrics recommendation

ปัญหา

การใช้ font metrics แบบไทยดูจะทำงานได้ดี และเราก็ใช้งานแบบนี้กันมานาน ตั้งแต่ยุค Windows 3.1 ที่ยังใช้รหัส สมอ. และมี Windows Thai Edition ใช้งานกันอยู่ มาจนถึงยุคเปลี่ยนผ่านสู่ I18N และ Unicode ใน Windows 95, Windows XP แล้วเราก็เริ่มเจออะไรทำนองนี้ในเว็บไซต์:

Mixed Thai/English text

ภาพนี้ผมจำลองขึ้นใหม่ เนื่องจากไม่มีระบบรุ่นเก่าให้จับภาพแล้ว แต่คงจะพอจำความรู้สึกนี้ได้ ที่เวลาอ่านเว็บไซต์ต่าง ๆ แล้ว เจอข้อความที่ภาษาไทยเล็กเท่ามด ภาษาอังกฤษใหญ่เท่าหม้อข้าว เพราะ text rendering engine แบบ multilingual ยุคแรก ๆ พยายามแสดงข้อความโดยแยกฟอนต์ตามภาษาเขียน แต่มันไม่แยกแยะว่าภาษาไทยต้องขยาย หรือภาษาอังกฤษต้องย่อ ส่วนข้อความภาษาเขมรนั้น ผมจำลองใส่เข้าไปด้วยเพื่อเปรียบเทียบให้ดูว่าเขา implement แบบไหน

rendering engine ยุคหลัง ๆ เริ่มฉลาดขึ้น โดยพยายามเลือกฟอนต์ตามภาษาหลักหรือตามโลแคล ถ้าฟอนต์นั้นมีอักษรโรมันให้ก็นำมาใช้เลย ถ้าไม่มีจึงจะไปหาจากฟอนต์อื่น ช่วยบรรเทาปัญหาข้อความผสมภาษาไทย-อังกฤษลงได้

แล้วโลกก็หมุนต่อไป สังคมไทยเริ่มเข้าสู่ยุคที่มีภาษาที่สามที่สี่ เด็ก ๆ เริ่มเรียนภาษาจีน ญี่ปุ่น เกาหลี ฯลฯ กันมากขึ้น ประชาคมเศรษฐกิจอาเซียนเริ่มรวมตัวกัน เริ่มมีข้อความภาษาลาว เขมร พม่า เข้ามามากขึ้น การใช้งานแบบ multilingual เริ่มเข้มข้นขึ้นกว่าแต่ก่อนที่เคยมีแค่ไทย-อังกฤษ

คำถามคือ เราจะจัดการระบบ multilingual นี้อย่างไร? เดิมมีแค่สองภาษา ฟอนต์อังกฤษมันโตเกินไป เราก็เพิ่มอักษรอังกฤษย่อส่วนลงในฟอนต์ไทยเสียก็สิ้นเรื่อง แต่เมื่อมีภาษาจีน ญี่ปุ่น เกาหลี ลาว เขมร พม่า เข้ามาร่วมด้วย เราจะเพิ่มอักษรของภาษาเหล่านั้นลงในฟอนต์ไทยหมดไหม? เอาแค่อักษรจีนอย่างต่ำ 5,000 ตัวก็อ่วมอรไทแล้ว ไหนจะอักษรเขมรที่มีอักษรตัวเชิง ทำให้ต้องเผื่อเนื้อที่บน-ล่างกว้างกว่าอักษรไทยเสียอีก เราจะได้ฟอนต์ตัวเล็กลงไปอีก และถ้าสักวันเราจะเพิ่ม อักษรทิเบต (ไม่แน่นะครับ ก็เราชอบประเทศภูฏานกันมากไม่ใช่หรือ) ที่ซ้อนกันสนุกสนานกว่าอักษรเขมรเสียอีก เราจะยิ่งได้ฟอนต์ที่เล็กกระจิ๋วหลิวเลยทีเดียว

Tibetan sample text

เริ่มเห็นภาพกันไหมครับ ว่าการเผื่อช่องว่างสำหรับการซ้อนอักขระมันไม่ scale ในระบบ multilingual

หรือหากผลักภาระไปให้ rendering engine ที่จะต้องจดจำว่าภาษาแต่ละภาษาต้องย่อ-ขยายด้วยอัตราเท่าไรแล้วปรับขนาดฟอนต์เอา มันก็เป็น workaround ที่ไปเพิ่มความยุ่งยากให้กับการออกแบบฟอนต์คู่สองภาษาอื่น ๆ เช่น การสร้างฟอนต์ที่มีอักษรไทย-ลาว, ไทย-เขมร, ไทย-พม่า, ไทย-ยาวี เพื่อใช้ในบริบทของกลุ่มผู้ใช้ทวิภาษา จะต้องออกแบบฟอนต์ให้อักษรแต่ละภาษามีขนาดไม่เท่ากันในฟอนต์เดียวกัน และถ้าเกิดว่า rendering engine ของแต่ละระบบใช้อัตราย่อ-ขยายของแต่ละภาษาต่างกันอีกล่ะ? คงจะพอจินตนาการถึงความยุ่งยากกันได้ และโชคดีที่ไม่มี rendering engine ไหนคิดทำอะไรทำนองนี้

ถ้าเช่นนั้น แบบไหนล่ะถึงจะ scale?

ทางออก

ระบบที่ดูสมเหตุสมผลกว่าก็คือ ทุกภาษาควรอิงบรรทัดฐานเดียวกัน กล่าวคือ

กำหนดให้ point size คือความสูงของตัวอักษร ไม่ใช่ความสูงของบรรทัด

เมื่อกำหนดอย่างนี้ แล้วไปขยายขนาดตัวอักษรไทยทั้งหมดให้สูงเท่า point size ซึ่งจะทำให้วรรณยุกต์เขยิบขึ้นสูงจนตกขอบด้านบนของ em-box นักพัฒนาฟอนต์ก็อาจเกิดประเด็นคำถามต่อไปนี้:

  • จะกำหนดความสูงของบรรทัดให้สูงกว่า em-box ได้อย่างไร?
  • การที่ glyph ของวรรณยุกต์ตกขอบ em-box ซึ่งเป็น bounding box ออกไป จะไม่ผิดหลักการหรือ?
  • font metrics แบบใหม่ จะขัดกันกับแบบเดิมที่ใช้ในเอกสารต่าง ๆ ไหม?

ก็จะตอบทีละประเด็นนะครับ

การกำหนดความสูงของบรรทัด

โดยปกติที่ผ่านมา ฟอนต์ไทยเคร่งครัดกับเรื่องความสูงของบรรทัดที่จะไม่ให้เกิน em-box ทำให้เราต้องย่อขนาดตัวอักษรทั้งหมดให้เล็กลงเพื่อให้สามารถบรรจุสระบน-ล่างและวรรณยุกต์ลงไปใน em-box ได้

แต่ในการคำนวณระยะระหว่างบรรทัดของโปรแกรมต่าง ๆ ที่ใช้ฟอนต์ TrueType หรือ OpenType จะไม่ได้ใช้ ascender/descender จาก em-box นี้โดยตรง แต่จะใช้ค่า sTypoAscender, sTypoDescender และ sTypoLineGap จาก ตาราง OS/2 & Windows Metrics ในตัวฟอนต์ ซึ่งเราสามารถกำหนดค่า sTypoAscender และ sTypoDescender ให้เลย em-box ออกไปได้ และอาจกำหนดค่า usWinAscent และ usWinDescent ด้วย เพื่อไม่ให้บิตแม็ปของตัวอักษรที่วาดถูกขลิบออก

อย่างไรก็ดี ในทางปฏิบัติแล้ว ค่า usWinAscent และ usWinDescent กลับเป็นค่าที่มีผลต่อการคำนวณระยะระหว่างบรรทัดมากกว่า (app ต่าง ๆ ไม่ได้ทำตาม spec ของไมโครซอฟท์นัก แม้ใน spec ของไมโครซอฟท์จะเขียนไว้ว่า This is strongly discouraged. ก็ตาม

โดยสรุปก็คือ ควรกำหนดค่าทั้ง sTypoAscender, sTypoDescender, usWinAscent, usWinDescent ทั้งหมดไว้ก่อน

หากใช้ Fontforge ก็กำหนดได้ในแท็บ OS/2 Metrics (Element > Font Info > OS/2 > Metrics)

Fontforge OS/2 Metrics dialog

ตำแหน่งของวรรณยุกต์

ในยุคก่อน เรามีการจัดตำแหน่งสระบน-ล่างและวรรณยุกต์เพื่อหลบหางพยัญชนะโดยใช้วิธีสร้าง glyph ชุดพิเศษที่มีการเลื่อนตำแหน่งรอไว้ แล้ว rendering engine จะเลือกใช้ glyph ชุดพิเศษเหล่านั้นตามความเหมาะสม เป็นเทคนิคที่เขาเรียกกันว่า positioning by substitution

glyph ชุดพิเศษต่าง ๆ เหล่านี้ จะเลื่อนระยะไว้เรียบร้อยเพื่อให้นำไปวางซ้อนได้พอดีโดยไม่มีการเลื่อนที่อีก ดังนั้น หากจะใช้เทคนิคนี้กับฟอนต์ที่ขยายขนาดขึ้น glyph ของวรรณยุกต์ที่เลื่อนระยะรอไว้ก็จะต้องตกขอบ em-box อย่างเลี่ยงไม่ได้ (แต่ยังอยู่ภายในความสูงของบรรทัด)

แต่นั่นเป็นข้อจำกัดของระบบเก่าก่อนที่จะมี OpenType

ด้วยเทคโนโลยี OpenType เรามีเครื่องมือจัดตำแหน่งการวางซ้อนอักขระ โดยใช้ข้อมูล GPOS ซึ่งอาศัยการกำหนด anchor สำหรับวาง glyph ซ้อนกันเหมือนการต่อชิ้นส่วนเลโก้ โดย glyph ที่เป็นฐานจะมี base anchor เป็นเหมือนเบ้าเสียบรอไว้ ส่วน glyph ที่จะมาวางซ้อนก็จะมี mark anchor เป็นเหมือนเดือยสำหรับเสียบเข้ากับเบ้า

ในการวาง glyph ที่มาซ้อนนั้น ตำแหน่ง glyph ตัวสวมจะถูกเลื่อนที่ด้วยเวกเตอร์ระหว่าง anchor เสียบกับ anchor เบ้า เพื่อให้ anchor สวมกันได้พอดี ดังนั้น ตำแหน่งเดิมของ glyph จะอยู่ที่ไหนก็ไม่สำคัญ เพราะยังไงก็สามารถคำนวณเวกเตอร์ดังกล่าวได้อยู่แล้ว ทำให้เราสามารถวาง glyph ของวรรณยุกต์ไว้ภายใน em-box ก็ได้ถ้าต้องการ นักพัฒนาฟอนต์ที่เคร่งครัดกับ em-box จึงวางใจได้

Thai composition example

สำหรับผู้ที่สนใจ ไมโครซอฟท์มีเอกสารแนะนำ การสร้างฟอนต์ OpenType สำหรับอักษรไทย โดยเฉพาะ

ความเข้ากันได้กับฟอนต์เดิม

ประเด็นนี้ ตอบได้สั้น ๆ ว่า ไม่เข้ากันแน่นอน หากจะเปลี่ยนมาใช้ metrics ใหม่ จะต้องมีการจัดการกับความเปลี่ยนแปลง และคงไม่ใช่เรื่องที่จะทำได้ชั่วข้ามคืน ผมเองก็ไม่เคยคิดว่ามันจะเกิดในอนาคตอันใกล้ จนกระทั่งเริ่มสังเกตเห็นแนวโน้มความเปลี่ยนแปลงบางอย่าง กล่าวคือ

  • ฟอนต์นานาภาษา ที่มีอักษรของภาษาต่าง ๆ ทั่วโลกเริ่มมีมากขึ้น หลังจากเทคโนโลยี multilingual เริ่มอยู่ตัวและใช้กันเป็นปกติ เช่น
    • Freefont จาก GNU Project (มีอักษรไทย)
    • Noto Fonts จาก Google (มีอักษรไทย)
    • DejaVu fork จาก Bitstream Vera (ยังไม่มีอักษรไทย)
    เฉพาะฟอนต์ที่มีอักษรไทย แน่นอนว่าใช้ font metrics ที่ point size = ขนาดตัวอักษร และใช้ GPOS ในการเลื่อนวรรณยุกต์ขึ้นสูงจาก em-box หรือถ้ายังไม่มีอักษรไทย ดูอักษรภาษาอื่น ๆ ที่มีแล้วต่างก็ใช้แนวทางนี้
  • web font ไทย
    • คัดสรร ดีมาก (Cadson Demak) เท่าที่ตรวจสอบเฉพาะ 3 ฟอนต์ใน Google Fonts พบว่าใช้ font metrics ที่ point size = ขนาดตัวอักษร และใช้ GPOS ในการเลื่อนวรรณยุกต์ขึ้นสูงจาก em-box

หากแนวโน้มการสร้างฟอนต์นานาภาษาเพื่อใช้ในระบบต่าง ๆ มีมากขึ้น (ผมยังไม่ได้ตรวจสอบฟอนต์ที่ใช้ในสมาร์ทโฟนต่าง ๆ) และการใช้ฟอนต์ในเว็บไซต์ต่าง ๆ ก็มีมากขึ้น จึงน่าสนใจว่าแนวโน้มเหล่านี้จะมีผลเปลี่ยนแปลงการใช้ฟอนต์ในเดสก์ท็อปปัจจุบันมากน้อยแค่ไหน คงต้องรอดูกันต่อไป โดยเฉพาะบนวินโดวส์ที่มีฟอนต์ Tahoma ให้ใช้กันเป็นตัวอย่างมานานแล้ว

และสุดท้ายก็อยู่ที่ผู้พัฒนาฟอนต์ทั้งหลายนั่นแหละครับ ว่าจะขยับไปสู่แนวทางนี้กันมากน้อยแค่ไหน

ป้ายกำกับ: ,

13 มกราคม 2559

Fonts-TLWG OTF and WOFF in Debian

ดังที่ได้กล่าวไว้ในท้าย blog ที่แล้ว ว่าผมได้ตัดสินใจที่จะผลักดันการใช้ฟอนต์รูปแบบอื่นนอกจาก TTF ใน Debian ซึ่งล่าสุดก็ได้เตรียมแพกเกจรุ่น 1:0.6.2-2 และได้ ผ่าน NEW queue เข้าสู่ sid แล้ว เมื่อคืนนี้ ก็ขอบันทึกแนวคิดเบื้องหลังไว้สักหน่อย

โครงการ Fonts-TLWG ได้รวบรวมฟอนต์ต่าง ๆ ที่เจ้าของอนุญาตให้เผยแพร่แบบโอเพนซอร์สได้ เพื่อนำมาพัฒนาต่อให้เข้ากับความต้องการและเทคโนโลยีใหม่ ๆ โดยต้นฉบับก็มักจะมาในรูป TrueType (TTF) ซึ่งใช้เส้นโค้ง quadratic Bézier แต่เมื่อ import เข้าสู่โครงการจะถูกแปลงเป็น cubic Bézier ทั้งหมด ด้วยเหตุผลคือ:

  • การใช้งานกับ LaTeX ซึ่งเน้นการรองรับ e-TeX และ pdfTeX engine นั้น การใช้ฟอนต์ Postscript (ซึ่งใช้เส้นโค้ง cubic Bézier) จะจัดการได้ง่ายกว่า
  • เส้นโค้ง cubic Bézier สามารถปรับแก้ไขได้ง่ายกว่า quadratic Bézier (เคยอธิบายไว้ใน blog เก่า)

การใช้ cubic Bézier ทำให้เราสามารถปรับแต่งฟอนต์ได้เต็มที่ โดยที่ยังสามารถ generate ฟอนต์เป็น TrueType ได้เหมือนเดิม โดยใช้สคริปต์แปลงโค้ง cubic เป็น quadratic พร้อมกับ apply auto instruction ด้วย ซึ่งวิธีนี้ก็มีข้อดีข้อเสียเมื่อเทียบกับการทำงานกับ TrueType โดยตรง คือ

ข้อดี:

  • โค้ง cubic ปรับแก้ได้สะดวกกว่ามาก
  • generate ฟอนต์ได้ทั้งฟอร์แมตที่ใช้ cubic และ quadratic Bézier โดยไม่เกิดจุดต่อโค้งส่วนเกินที่เกินความจำเป็น อันจะทำให้ข้อมูลฟอนต์มีขนาดใหญ่ขึ้น (โดยปกติ โค้ง quadratic จะต้องใช้จุดควบคุมมากกว่าโค้ง cubic ในการแทนเส้นโค้งเดียวกัน และเมื่อแปลงโค้ง quadratic เป็น cubic ก็จะเกิดจุดต่อโค้งระหว่างกลางเพิ่มขึ้นอีก ทำให้ข้อมูลของโค้ง cubic เกิดการขยายตัวเกินความจำเป็นถึง 2 ชั้น ในขณะที่การใช้โค้ง cubic เป็นต้นทาง จะได้ข้อมูลของโค้ง cubic ขนาดเล็ก และจะเกิดการขยายตัวของข้อมูลเพียงชั้นเดียวขณะแปลงเป็น quadratic)
  • ทำ hinting ได้ง่าย เนื่องจากฟอนต์ Postscript อาศัย global hint ควบคุมเส้นอักษรเป็นหลัก (ดู blog เก่า เกี่ยวกับ blue zones และ stem hints) ในขณะที่ TrueType ใช้ instruction ควบคุมจุดต่าง ๆ ซึ่งแทบจะไม่ต่างอะไรกับภาษาแอสเซมบลี

ข้อเสีย:

  • การแปลงโค้ง cubic เป็น quadratic จะต้องเกิดการ interpolate จุดเพิ่มเติม เนื่องจากโค้ง quadratic มีความสามารถในการบรรยายโค้งต่ำกว่า ต้องใช้จุดมากกว่า ในขณะที่การแปลงจาก quadratic เป็น cubic จะได้จุดแบบแม่นตรง (ไม่ใช่ interpolate) และเนื่องจากการ interpolate เป็นไปแบบอัตโนมัติ จึงไม่อาจควบคุมจำนวนจุดที่ interpolate ได้เต็มที่นัก
  • คุณภาพของ TrueType instruction ที่สร้างแบบอัตโนมัติอาจไม่สูงนักเมื่อเทียบกับการเขียน instruction ด้วยมือ

เมื่อเทียบข้อดี-ข้อเสียแล้ว ผมยังคงเลือกเอาโค้งแบบ cubic แม้ข้อเสียจะเกิดกับฟอนต์ TrueType ที่มีผู้ใช้มากที่สุด เพราะข้อเสียต่าง ๆ ถือว่ายอมรับได้ ความคลาดเคลื่อนจากการ interpolate ขณะแปลงเส้นโค้งไม่ได้มีนัยสำคัญอะไร ส่วนเรื่องคุณภาพของ TrueType instruction นั้น เราก็ทำอะไรไม่ได้มาก เนื่องจากเป็นเรื่องที่ถ้าจะทำจริงจะต้องอาศัยแรงงานมหาศาล โดยที่ไม่ได้ช่วยเพิ่มคุณภาพให้กับฟอนต์ที่ใช้ cubic Bézier แต่อย่างใด (ในขณะที่การปรับแต่ง hint ของ Postscript สามารถช่วยเพิ่มคุณภาพของ TrueType instruction ที่สร้างแบบอัตโนมัติได้บ้าง)

กล่าวโดยสรุป โค้ง cubic Bézier คือโค้งที่เป็น native ที่ใช้ในการพัฒนา ถ้าสามารถใช้โค้งนี้ได้โดยตรงก็ย่อมควบคุมอะไรต่าง ๆ ได้ดีกว่า อย่างน้อยก็ในทางทฤษฎี

ที่ผ่านมา การใช้งานฟอนต์ที่ดูจะเหมาะสมในทางปฏิบัติก็คือ

  • เดสก์ท็อป ใช้ TrueType (quadratic Bézier)
  • LaTeX ใช้ Type 1 (cubic Bézier)

ที่ผมยังไม่กล้าผลักดันการใช้ฟอนต์ที่ใช้โค้ง cubic บนเดสก์ท็อปในช่วงที่ผ่านมา ก็เนื่องจากรูปแบบการ hint ของ Postscript นั้น อิงอาศัยความฉลาดของ rasterizer ในการใช้ hint ในฟอนต์มาปรับเส้นโค้งต่าง ๆ (ไม่เหมือนกับ TrueType instruction ที่มีคำสั่งครบสำหรับ rasterizer ไม่ว่าใช้ rasterizer ตัวไหนก็ได้คุณภาพใกล้เคียงกัน) ซึ่งในช่วงแรกนั้น Postscript rasterizer ที่มากับ FreeType วาดตัวอักษรได้ดีเฉพาะบางขนาดเท่านั้น แต่พอใช้กับขนาดอื่น เส้นนอนจะเริ่มหนาและเบลอ (เสียดายที่ไม่ได้จับภาพไว้เป็นเรื่องเป็นราว) จนเมื่อ Adobe contribute CFF rasterizer ให้กับ FreeType คุณภาพที่ได้ก็ดีขึ้นอย่างเห็นได้ชัด ซึ่งเริ่มเปิดใช้จริงใน FreeType 2.5.0.1

ในรอบ Debian Jessie นั้น ผมถึงกับเปลี่ยนฟอร์แมตฟอนต์จาก TTF เป็น OTF ในรุ่น 1:0.6.0-2 ซึ่งทำให้ได้ฟอนต์ที่กินเนื้อที่น้อยลงแทบจะครึ่งต่อครึ่งโดยที่คุณภาพก็ไม่ได้ด้อยกว่า TTF เลย แต่ก็ต้องชะงักเมื่อเจอ Debian #730742 ที่มีผู้ร้องเรียนว่า rasterizer ตัวใหม่ทำให้ฟอนต์ Cantarell ไม่สวย ทำให้ผู้ดูแลแพกเกจ FreeType ของ Debian ต้อง disable CFF rasterizer ของ Adobe แล้วกลับไปใช้ rasterizer ตัวเก่า ผมจึงต้องถอยกลับมาใช้ TTF ในรุ่น 1:0.6.1-2

จนกระทั่งเข้าสู่รอบพัฒนา Stretch ฟอนต์ Cantarell ได้รับการแก้ปัญหาแล้ว จึงได้มีผู้ร้องขอเปิดใช้ CFF rasterizer ของ Adobe อีกครั้ง (Debian #795653) และมีผลตั้งแต่รุ่น 2.6-1 หลังจากรอดูอยู่พักหนึ่งจนแน่ใจว่าเขาไม่ disable กลับอีก ผมจึงตั้งใจไว้ว่าจะเริ่มผลักดันฟอนต์ OTF อีกครั้ง แต่ครั้งนี้ตัดสินใจเลือกการเปลี่ยนแปลงที่ใหญ่กว่านั้น ด้วยการ build ทั้ง TTF และ OTF ให้ผู้ใช้เลือกติดตั้งตามชอบ โดยมีโครงสร้างดังนี้:

  • fonts-thai-tlwg (metapackage)
    • fonts-tlwg-kinnari (dependency package + fontconfig stuffs)
      • fonts-tlwg-kinnari-ttf (TTF files), OR
      • fonts-tlwg-kinnari-otf (OTF files)
    • fonts-tlwg-garuda (dependency package + fontconfig stuffs)
      • fonts-tlwg-garuda-ttf (TTF files), OR
      • fonts-tlwg-garuda-otf (OTF files)
    • ...
  • fonts-thai-tlwg-ttf (metapackage สำหรับติดตั้ง fonts-tlwg-*-ttf ทั้งหมด)
  • fonts-thai-tlwg-otf (metapackage สำหรับติดตั้ง fonts-tlwg-*-otf ทั้งหมด)

คราวนี้ถ้าจะ disable rasterizer ของ Adobe อีก ผู้ใช้ก็สามารถเปลี่ยนกลับไปใช้ TTF ได้ทันที โหะ ๆ

พร้อมกันนี้ ก็ได้เพิ่มแพกเกจ fonts-thai-tlwg-web สำหรับติดตั้ง web font ในรูปแบบ WOFF สำหรับเซิร์ฟเวอร์ที่ต้องการใช้ web font ในเว็บไซต์ต่าง ๆ ด้วย

หากคุณใช้ Debian Sid ก็ติดตั้งได้เลยตั้งแต่วันนี้ หากคุณใช้ Debian testing ก็รออีกสักพัก

ป้ายกำกับ: , ,

01 มกราคม 2559

Fonts-TLWG 0.6.2

Fonts-TLWG 0.6.2 ได้ออกไปแล้ว หลังจากใช้เวลาพัฒนาจากรุ่น 0.6.1 อยู่เกือบปีครึ่ง ความเปลี่ยนแปลงหลัก ๆ ของรุ่นนี้คือการรองรับการเขียนภาษามลายูปาตานีด้วยอักษรไทยในฟอนต์ต่าง ๆ แต่ก็มีรายการอื่น ๆ อีกพอประมาณ

สรุปการเปลี่ยนแปลงในรุ่นนี้คือ

  • เพิ่ม Preferred Family/Subfamily (Name ID 16, 17) ในทุกฟอนต์ เพื่อให้ Windows สามารถรองรับ style ได้มากกว่า 4 style ซึ่งจำเป็นสำหรับฟอนต์ Kinnari และ Norasi ซึ่งมีทั้ง Oblique และ Italic และฟอนต์ Umpush ที่มี Light เพิ่มเติมด้วย (ตามคำแนะนำของคุณ Martin Hosken) นอกจากนี้ บางโปรแกรมบนลินุกซ์อย่าง GNOME Software ยังใช้ข้อมูลนี้ในการจัดกลุ่มแพกเกจฟอนต์ให้เป็นกลุ่มเดียวกันด้วย (ตาม รายงานของคุณ Richard Hughes สำหรับฟอนต์ Arundina)
  • กำหนด weight ของฟอนต์น้ำหนักปกติเป็น Regular จากเดิมที่เป็น Regular บ้าง Medium บ้าง Book บ้าง เพื่อให้เป็นไปตามข้อกำหนดของ Name ID 2 เหมือนกันทั้งหมด
  • validate ทุกฟอนต์ พร้อมแก้ปัญหาที่ตรวจพบ ตัวอย่างของปัญหาที่พบก็เช่น จุดต่อโค้งมีความชันเกือบอยู่ในแนวดิ่งหรือราบแต่ไม่ดิ่งหรือราบพอดี (ก็แก้ให้ดิ่งหรือราบพอดี), จุดมีพิกัดไม่เป็นจำนวนเต็ม (ก็ปัดเศษให้เป็นจำนวนเต็ม), Blue zone แคบหรือกว้างเกินไป ฯลฯ
  • เซ็ต OS/2 Version เป็น 4 ทุกฟอนต์ เดิมนั้นกำหนดเป็นค่า Auto ซึ่ง Fontforge จะให้ค่าเป็น Version 1 ตาราง OS/2 & Windows Metrics เป็นตาราง metrics ของฟอนต์ TrueType ซึ่งไมโครซอฟท์ได้พัฒนาเพิ่มจาก spec ของ Apple เพื่อใช้กับ OS/2 และ Windows (อ่านรายละเอียดเพิ่มเติม) ซึ่งมีการปรับปรุงมาเรื่อย ๆ โดยรุ่นล่าสุดคือ version 5 แต่รุ่นที่ Fontforge รองรับสูงสุดคือ version 4 จึงกำหนดเลขรุ่นเพื่อให้ฟอนต์มีข้อมูลตาม spec รุ่นใหม่ ๆ ตามคำแนะนำของคุณ Martin Hosken
  • รองรับการเขียนภาษามลายูปาตานีด้วยอักษรไทย ดังที่เคย บันทึกรายละเอียดไว้ ซึ่งงานส่วนนี้ถือว่ากินเวลาพัฒนานานที่สุด
  • รองรับการสร้าง web font แบบ WOFF ใน configure script เพิ่มเติมจาก Type 1, TTF, OTF
  • เพิ่มบริการ on-line web font เพื่อให้เว็บต่าง ๆ สามารถใช้ฟอนต์ชุด TLWG ในเว็บของตนเองได้ โดยได้เตรียม CSS stylesheet ไว้ ดังรายละเอียดในหน้า TLWG Web Fonts

เนื่องจากรุ่นนี้ไม่ได้มีความเปลี่ยนแปลงในส่วนของ LaTeX มากนัก จึงไม่อัปเดตรุ่นใน CTAN

รุ่นนี้ผมตัดสินใจเริ่มผลักดันการใช้ฟอนต์รูปแบบต่าง ๆ จึงได้เตรียม generated fonts ในรูป OTF และ WOFF เพิ่มเติมจากแบบ TTF ที่เคยทำตามปกติ และมีแผนที่จะเพิ่มรูปแบบ OTF (หรืออาจจะ WOFF ด้วย) ใน Debian ให้ผู้ใช้ได้เลือกใช้ด้วยเร็ว ๆ นี้ หลังจากที่ libfreetype6 ใน Debian ได้ enable CFF rasterizer ของ Adobe ใน FreeType อีกครั้งใน Stretch มาระยะหนึ่งแล้ว (Debian #795653) ซึ่งทำให้คุณภาพการ render ฟอนต์ OTF ดีขึ้นมาก (rasterizer ตัวนี้ควรจะได้ใช้กันตั้งแต่รุ่น Jessie แต่เพราะผู้ใช้บางส่วนไม่ชอบ จึงถูก disable ไป [Debian #730742] จนกระทั่งเริ่มรอบพัฒนา Stretch จึง enable ใหม่อีกครั้ง)

ป้ายกำกับ: ,

14 สิงหาคม 2558

Patani Malay Support in Fonts-TLWG with Teochew Experiment

โครงการ fonts-tlwg กำลังอยู่ระหว่างพัฒนาเพิ่มเติมให้รองรับภาษาชาติพันธุ์ที่เขียนด้วยอักษรไทยได้สมบูรณ์ยิ่งขึ้น โดยรอบนี้เจาะไปที่ภาษามลายูปาตานีที่นอกจากจะต้องผ่อนคลายกฎการซ้อนอักขระต่าง ๆ แล้ว ยังต้องการอักขระเพิ่มเติมจากบล็อคยูนิโค้ดภาษาไทยอีก 4 ตัว เพื่อเป็นเครื่องหมายกำกับเสียงอ่าน กล่าวคือ:

  • U+0303 COMBINING TILDE คือสัญลักษณ์ตัวหนอนที่เขียนกำกับเหนือพยัญชนะเพื่อให้ออกเสียงขึ้นจมูก (เสียงนาสิก) คงได้แนวคิดจากตัว ñ ในภาษาสเปน
  • U+0331 COMBINING MACRON BELOW คือสัญลักษณ์ขีดเส้นใต้พยัญชนะเพื่อตัดเสียงนาสิกออกจากพยัญชนะนาสิกของไทย 4 ตัว คือ ง ญ น ม
  • U+02BC MODIFIER LETTER APOSTROPHE ใช้ในการลดรูปคำให้เหลือจำนวนพยางค์น้อยลง
  • U+02D7 MODIFIER LETTER MINUS ใช้ในการกล้ำสองพยางค์ให้ต่อเนื่องเป็นพยางค์เดียว

สองตัวหลังดูไม่มีอะไรมาก แค่เพิ่ม glyph ให้ก็ดูจะเพียงพอ แต่สองคัวแรกซึ่งเป็นอักขระประกอบ (combining character) ก็เลยมีปฏิสัมพันธ์กับสระบน-ล่าง วรรณยุกต์ และเครื่องหมายกำกับเสียงของไทย ทำให้ต้องมาจัดระเบียบใหม่ ซึ่งปรากฏว่าต้องทั้งขยับอักษรไทย ทั้งเปลี่ยนลำดับ normalization ของยูนิโค้ดด้วย

ตัวหนอนบอกเสียงนาสิกดูจะไม่มีประเด็นอะไรสำหรับภาษามลายูปาตานี เนื่องจากคำที่มีเครื่องหมายนี้จะไม่มีสระบนและวรรณยุกต์กำกับอยู่แล้ว ส่วนตัวขีดเส้นใต้ก็ควรขีดเส้นใต้พยัญชนะที่ความกว้างไม่เท่ากันให้สวยงามทั้งสี่ตัวด้วย (กล่าวคือ ไม่ใช่ใช้อักขระเดียวขีดเส้นใต้อักขระทุกตัว แต่ความยาวของขีดควรปรับตามความกว้างของพยัญชนะด้วย) รวมทั้งต้องตัดเชิง ญ เมื่อขีดเส้นใต้ด้วย

ก็ดูไม่ยุ่งยากอะไร ตัวหนอนก็แค่ทำประหนึ่งมันเป็นสระอิอีอึอือเสียก็จบ ส่วนตัวขีดเส้นใต้ก็สร้าง ligature glyph สำหรับ ง ญ น ม ขีดเส้นใต้สำเร็จรูปเท่านั้นเอง ผลออกมาก็งามน่าแล

Patani Malay text using Garuda

แต่ช้าก่อน ฟีเจอร์ของภาษามลายูปาตานีฟังดูน่าสนใจไม่น้อยสำหรับคนพูดภาษาแต้จิ๋วอย่างผม

  • เสียงนาสิกเป็นตัวแยกความหมายของคำในภาษาแต้จิ๋ว ภาษาไทยมีเสียงนาสิกแค่ไม่กี่เสียง คือ ง ญ ณ น ม ถ้าพยัญชนะต้นไม่ใช่เสียงพวกนี้ก็จะไม่ออกเสียงขึ้นจมูก (ญ ไม่มีเสียงนาสิกในไทยกลาง แต่ยังมีในไทยอีสาน [ดู blog เก่าประกอบ] และอาจจะมี ห ฮ ที่ยังขึ้นจมูกบ้างไม่ขึ้นบ้างแล้วแต่สำเนียง) แต่ภาษาแต้จิ๋วสามารถขึ้นจมูกได้ทุกพยางค์ และยังเป็นตัวแยกความหมายอีกด้วย เช่น คำว่า 碗 ที่แปลว่า ชาม จะออกเสียงเป็น อั้ว พร้อมเสียงขึ้นจมูก ซึ่งจะแตกต่างจากคำว่า 我 ที่เป็นสรรพนามบุรุษที่หนึ่งเอกพจน์ ซึ่งออกเสียงเป็น อั้ว เหมือนกันแต่ไม่ขึ้นจมูก ในเมื่อเสียงนาสิกมีความสำคัญถึงขนาดแยกความหมายของคำในภาษาแต้จิ๋วเช่นนี้ ตัวหนอนกำกับเสียงนาสิกของมลายูปาตานีจึงน่าจะนำมาใช้กับแต้จิ๋วได้
  • พยัญชนะที่ตัดเสียงนาสิกในภาษาแต้จิ๋วก็มี เช่นในคำว่า 牛 ที่แปลว่า วัว จะออกเสียงเป็น ก๎งู๊ คือเป็น ง ที่กล้ำกับเสียง ก ที่คอและไม่ขึ้นจมูก เสียงพยัญชนะนี้ไม่มีในภาษาไทย และมีความยากลำบากในการเขียนด้วยอักษรไทยมาก ตัวขีดเส้นใต้ตัดเสียงนาสิกของมลายูปาตานีก็น่าจะนำมาใช้ได้เช่นกัน

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

ในการทำฟอนต์นั้น ไม่ใช่ว่าเราจะรองรับเฉพาะอักขรวิธีที่กำหนดไว้เท่านั้น แต่ยังควรเตรียม fallback สำหรับรองรับการแสดงผลรูปแบบที่อยู่นอกเหนือจากที่กำหนดด้วยตามสมควร ถึงแม้ไม่มีโจทย์ภาษาแต้จิ๋ว ก็ต้องคิดเผื่ออยู่แล้วว่าจะจัดการกับกรณีทั่วไปที่อยู่นอกเหนือข้อกำหนดของภาษามลายูปาตานีอย่างไร การมีโจทย์สมมุติของภาษาแต้จิ๋วเช่นนี้ก็เท่ากับทำให้เห็นแนวทางชัดเจนยิ่งขึ้น

ประเด็นของโจทย์ก็คือ:

  • ตัวหนอนนาสิก ฐานข้อมูลอักขระยูนิโค้ดกำหนดให้มี combining class 220 ในขณะที่วรรณยุกต์ไทยเป็น class 107 ตามหลัก normalization ของยูนิโค้ด จะเรียงลำดับอักขระที่อยู่ระหว่างอักขระ class 0 (ได้แก่พยัญชนะบนบรรทัด) ตามลำดับ combining class จากน้อยไปหามาก (เรียกว่า canonical order) ผลคือ เมื่อตัวหนอนนาสิกผสมกับวรรณยุกต์ไทย rendering engine จะสลับมันไปอยู่หลังวรรณยุกต์ก่อนส่งให้ฟอนต์แสดงผลเสมอ แต่สิ่งที่เราต้องการคือวางตัวหนอนก่อนวรรณยุกต์ เพื่อให้อยู่ชิดพยัญชนะ แล้วจึงซ้อนวรรณยุกต์ทับทีหลัง ดังนั้น ฟอนต์จะต้องรู้จักกลับลำดับคืนด้วย แต่ถ้ามีสระบนมาคั่นกลางก็ไม่ต้องทำอะไร เพราะสระบน, ไม้ไต่คู้, ทัณฑฆาต, นิคหิต, ยามักการ ต่างถูกกำหนด combining class เป็น 0 เหมือนพยัญชนะบนเส้นบรรทัด จึงเป็นจุดกั้นแบ่งโซนการเรียงลำดับ combining character โดยปริยาย
  • ตัวขีดเส้นใต้ ฐานข้อมูลอักขระยูนิโค้ดกำหนดให้มี combining class 220 ในขณะที่สระอุ สระอู มี combining class เป็น 103 (แต่ Uniscribe และ Harfbuzz แก้เองให้เป็น 3 ด้วยเหตุผลใดไม่อาจทราบได้) และพินทุมี combining class เป็น 9 ทำให้ตัวขีดเส้นใต้จะถูก rendering engine normalize ให้ไปอยู่หลังสระล่างและพินทุเสมอ และถ้ามีวรรณยุกต์ก็จะเลื่อนไปอยู่หลังวรรณยุกต์ด้วย แต่สิ่งที่เราต้องการคือวางตัวขีดเส้นใต้ก่อนเพื่อน เพื่อให้อยู่ชิดพยัญชนะ ดังนั้น ฟอนต์จะต้องรู้จักกลับลำดับคืนด้วย
  • พินทุกับสระล่าง ตาม combining class ในฐานข้อมูลอักขระยูนิโค้ดแล้ว พินทุ (class 9) จะต้องมาก่อนสระล่าง (class 103) ใน canonical order ซึ่งเป็นสิ่งที่ต้องการอยู่แล้วสำหรับภาษามลายูปาตานี แต่ด้วยเหตุผลกลใดไม่ทราบได้ Uniscribe ของไมโครซอฟท์ได้แก้ทับคลาสของสระล่างจาก 103 เป็น 3 ทำให้สระล่างมาก่อนพินทุ และเพื่อความเข้ากันได้กับ Uniscribe ทำให้ Harfbuzz ก็ทำอย่างเดียวกันด้วย สิ่งที่ฟอนต์ต้องทำคือกลับลำดับนี้คืนอีกชั้นหนึ่ง

ปัญหาของตัวหนอนนาสิกไม่มีอะไรซับซ้อน แก้ได้ด้วยการเพิ่มกฎ GSUB สำหรับสลับตัวหนอนนาสิกกับวรรณยุกต์ทั้งสี่ตัวเท่านั้นก็จบ และอาจจะนับตัวหนอนเป็นสระบนอีกหนึ่งตัวในกฎที่ยกไม้ไต่คู้ นิคหิต ยามักการขึ้นสูงและย่อขนาดลงเพื่อความสวยงามสักหน่อยด้วย

แต่ปัญหาของตัวขีดเส้นใต้ซับซ้อนกว่าที่คาดไว้มาก เพราะมีประเด็นอื่นที่ต้องพิจารณาร่วมด้วยอีก 2 ประเด็น คือ

  • การขีดเส้นใต้ ง ญ น ม ซึ่งความกว้างไม่เท่ากัน จัดการได้ด้วยการสร้าง precomposed glyph ที่ขีดเส้นใต้พยัญชนะดังกล่าวเสร็จสรรพ (ตัดเชิงสำหรับ ญ ไปในตัว) พร้อมกฎ ligature สำหรับเปลี่ยนคู่อักขระให้เป็นตัว precomposed กฎนี้ต้องทำงานในขณะที่พยัญชนะดังกล่าวกับตัวขีดเส้นใต้อยู่ติดกัน
  • กฎเดิมที่จัดการกรณีคำว่า ปู่ ซึ่งจะเปลี่ยนวรรณยุกต์ให้เป็นตัวต่ำพร้อมกับสลับสระล่างกับวรรณยุกต์ให้วรรณยุกต์มาก่อน เพื่อจะได้วางหลบหาง ป ฝ ฟ (และอาจจะ ฬ) ด้วย GPOS ได้ กฎนี้ต้องทำงานในขณะที่สระล่างตามหลังด้วยวรรณยุกต์ทันที

การเพิ่มกฎสำหรับกลับลำดับตัวขีดเส้นใต้จึงต้องระวังที่จะไม่ไปกีดขวางการทำงานของกฎดังกล่าวด้วย โดยถ้าทำก่อน ตัวขีดเส้นใต้ก็จะมาขวางกฎ ปู่ ให้ไม่ทำงาน และถ้าทำทีหลัง วรรณยุกต์จากกฎ ปู่ ก็จะมาขวางกฎสร้าง precomposed glyph ให้ไม่ทำงาน

หลังจากคิดและทดลองอยู่หลายตลบ ผมก็ได้ข้อสรุปเป็นลำดับกฎว่าดังนี้ :-

สตริงเริ่มแรก: C + Macron + BV + T
Uniscribe/Harfbuzz: C + BV + T + Macron
1: สลับ T กับ Macron C + BV + Macron + T
2: สลับ BV กับ Macron C + Macron + BV + T
3: ligature C-Macron-lig + BV + T || C + Macron + BV + T
3: สลับ Macron กับ BV C + BV + Macron + T
4: สลับ Macron กับ T C + BV + T + Macron
general composition C + T.low + BV + Macron
5: สลับ BV กับ Macron C + T.low + Macron + BV

กล่าวคือ เริ่มจากเลื่อนตัวขีดเส้นใต้ไปชิดกับพยัญชนะก่อนเพื่อให้กฎ ligature ทำงาน และถ้าตัวขีดเส้นใต้ไม่ได้ทำให้เกิด ligature ก็เลื่อนกลับที่เดิมเพื่อให้กฎ ปู่ ใน general composition ทำงาน จากนั้นจึงสลับตัวขีดเส้นใต้ให้มาก่อนสระล่าง ก็เป็นอันได้ลำดับที่เราต้องการ

กรณีลำดับของพินทุกับสระล่างที่ Uniscribe/Harfbuzz แปลงสารมาก็ทำนองเดียวกัน มีความซับซ้อนเล็กน้อย แต่ก็แค่กับกฎ ปู่ เท่านั้น :-

สตริงเริ่มแรก: C + Ph + BV + T
Uniscribe/Harfbuzz: C + BV + Ph + T
1: สลับพินทุกับ BV C + Ph + BV + T
general composition: C + Ph + T.low + BV
2: สลับพินทุกับ T.low C + T.low + Ph + BV

กล่าวคือ สลับพินทุกับสระล่างกลับให้เป็นเหมือนเดิม แล้วปล่อยให้กฎ ปู่ ใน general composition ทำงาน เสร็จแล้วก็เลื่อนวรรณยุกต์ตัวต่ำให้เข้าไปชิดกับพยัญชนะ

ผลที่ได้ดูจะทำงานได้ดีเมื่อทำ stress test ด้วยภาษาแต้จิ๋ว:

Experimental Teochew text using Garuda

และเนื่องจาก requirement ในเรื่องตัวหนอนนาสิกและตัวขีดเส้นใต้ของภาษาแต้จิ๋ว เป็น superset ของมลายูปาตานี การผ่านการทดสอบด้วยภาษาแต้จิ๋วย่อมถือว่าครอบคลุมภาษามลายูปาตานีโดยปริยาย

สังเกตว่า ในขณะที่ทำภาษามลายูปาตานีในขั้นแรกนั้น ผมลืมกรณีที่พยัญชนะขีดเส้นใต้มีสระล่างไปเสียสนิทด้วยซ้ำ การเล่นกับภาษาแต้จิ๋วยังช่วยจับบั๊กนี้ให้ด้วย

เมื่อทดลองกับฟอนต์ Garuda เป็นที่พอใจแล้ว ก็มาสรุปขั้นตอนทุกอย่างอีกครั้งกับฟอนต์ Kinnari:

Experimental Teochew text using Kinnari

แล้วก็ใช้ฟอนต์ Kinnari เป็นแบบสำหรับฟอนต์อื่น ๆ ต่อไป โดยเริ่มจากฟอนต์ Norasi:

Experimental Teochew text using Norasi

ตอนนี้ทำถึงขั้นนี้เท่านั้นครับ ยังมีฟอนต์อื่น ๆ อีกสิบกว่าฟอนต์ในชุด fonts-tlwg ที่ผมจะค่อยทยอยทำต่อไปเมื่อมีเวลาว่าง คาดว่าคงใช้เวลาอีกหลายเดือน :-P

ผมสร้าง หน้าทดสอบ โดยใช้ web font ที่สร้างจากตัวล่าสุดที่อยู่ระหว่างพัฒนาไว้ด้วย คงจะอัปเดตไปเรื่อย ๆ ตามความคืบหน้าครับ

ในอีกด้านหนึ่ง ก็ได้ อภิปรายและเสนอแพตช์ สำหรับ Harfbuzz เพื่อขอตัดการ override combining class ของสระล่างของไทยเสียด้วย ดูจะได้รับความเห็นชอบ แต่ยังไม่ apply เสียที อาจจะเกรงความไม่เข้ากันกับ Uniscribe หรือเปล่าก็ไม่ทราบได้ แต่การแก้ในฟอนต์ที่ผมทำไปก็เท่ากับทำให้มันทำงานบนวินโดวส์ได้ด้วย

ป้ายกำกับ: ,

hacker emblem