Theppitak's blog

My personal 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 ในลำดับต่อไป

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

16 กันยายน 2562

Thanks

ขอขอบคุณ ท่านที่ได้ สนับสนุน งานพัฒนาซอฟต์แวร์เสรีของผมในช่วงที่ผ่านมาครับ

นับจาก ครั้งที่แล้ว ขอขอบคุณผู้สนับสนุนงานของผมดังนี้:

  • เดือนกุมภาพันธ์ 2562
    • คุณวิทยา ไตรสารวัฒนะ
  • เดือนสิงหาคม 2562
    • ผู้ไม่ประสงค์จะออกนาม 1 ท่าน

ขอให้ทั้งสองท่านประสบความสำเร็จในหน้าที่การงาน สุขภาพแข็งแรงครับ

ปีนี้อาจเป็นปีที่งานพัฒนาซอฟต์แวร์ของผมขาดช่วงไปบ้าง เนื่องจากรับงานสอนพิเศษนักเรียนอยู่ช่วงหนึ่ง แต่ก็พอสรุปงานตั้งแต่ต้นปีได้ดังนี้:

  • งานแปล
    • ระดมแปล Xfce เพื่อเตรียมพร้อมสำหรับ Xfce 4.14 ซึ่งก็ได้ออกรุ่นไปแล้วเมื่อ 12 สิงหาคมที่ผ่านมา
  • Fonts-Arundina (ยังไม่ release):
    • ตรวจสอบปัญหา build reproducibility ต่อ สุดท้ายพบว่าเป็นปัญหาของ FontForge ใน Debian ที่ยังอัปเดตไม่ครบสำหรับฟอนต์ PostScript จึงคอมเมนต์ไปใน Debian #774274 เพื่อขออัปเดต
    • ทยอยปรับ quadratic spline ในเลเยอร์ Quad ต่อ (ยังไม่เสร็จ งานนี้เป็นงานมาราธอน)
  • งานต้นน้ำ:
    • release gtk-im-libthai 0.2.2 เพื่อปล่อยสิ่งที่ค้างอยู่ใน repository ถึงเกือบ 8 ปี โดยสิ่งเปลี่ยนแปลงหลัก ๆ คือการกำจัดการใช้ GTK+ API ที่ deprecated
  • Debian packaging:
    • ย้ายไป debhelper level 12 พร้อมกับใช้ debhelper-compat dependency แทน debian/compat และแก้ปัญหาที่เกิดกับ dh_missing ใน level 12 นี้
    • ปรับโครงสร้าง Git repository ตาม DEP-14 ครบทุกแพกเกจในความดูแล (แต่ยังรออัปโหลดอยู่ 2 แพกเกจ)
    • ปรับแพกเกจที่สร้าง udeb โดยให้ dh_makeshlibs สแกนหา udeb โอยอัตโนมัติแทนการใช้ option --add-udeb สำหรับ debhelper รุ่น 12.3 ขึ้นไป
    • ตรวจสอบและตัดสิ่งที่เก่าเกินไปจนไม่จำเป็นสำหรับ Bullseye แล้ว
    • อัปเดตทั่วไป
  • Debian อื่น ๆ:
    • file Debian #934804 สำหรับ bsdmainutils เพื่อขอปรับข้อมูลวันหยุดของไทยเพิ่มเติมในคำสั่ง calendar อันเนื่องมาจากพระราชพิธีบรมราชาภิเษก
  • OpenStreetMap
    • ปรับข้อมูลแผนที่ในตัวเมืองขอนแก่น
    • เป็นวิทยากรฝึกอบรมการสร้างแผนที่ OSM ที่ Thailand ICT Camp 2019 (ชะอำ) ร่วมกับคุณ Mishari Muqbil
    • เริ่มทดลองเก็บข้อมูล Mapillary ในตัวเมืองขอนแก่นตามคำแนะนำของคุณ Mishari
    • ปรับข้อมูลแผนที่รายทางที่ชะอำ และแผนที่อุทยานสิ่งแวดล้อมนานาชาติสิรินธร
    • ปรับข้อมูลแผนที่บริเวณ ต.นาจอมเทียน อ.สัตหีบ จ.ชลบุรี
    • เริ่มทำแผนที่จุดรับขยะอันตรายในเขตเทศบาลนครขอนแก่น

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

06 พฤศจิกายน 2561

Fonts-TLWG 0.7.0 and 0.7.1

Fonts-TLWG 0.7.0 ออกไปแล้วเมื่อปลายตุลาที่ผ่านมา หลังจากสะสมงานพัฒนามาได้ครึ่งปี โดยมีการเปลี่ยนแปลงตามลำดับเวลาดังนี้:

  • Issue #7: แก้ที่ผิดใน GSUB rules ของทุกฟอนต์ซึ่งทำให้แสดงข้อความที่มีพินทุตามด้วย Macron Below เป็นพินทุซ้อนกันสองตัว ปัญหาเกิดจากข้อผิดพลาดในกฎจัดการลำดับ คุณ @Richard57 ได้รายงานเข้ามาพร้อมวิเคราะห์สาเหตุให้ด้วย
  • Norasi:
    • แก้ warning จาก Fontforge เกี่ยวกับการอ้างถึง glyph ที่ไม่มีในฟอนต์ในกฎ 'liga'
    • แก้กฎ 'liga' ให้รองรับลำดับ space + combining character ในทุกกรณี
    • ตัดกฎ T + M → ™ เพื่อไม่ให้รบกวนกรณีที่ไม่ใช่ เช่น ATM
  • Issue #6: จัดเตรียมฟอนต์ OpenType ในแพกเกจ LaTeX (fonts-tlwg) ตามคำแนะนำของคุณ Abhabongse Janthong เพื่อให้บริการอย่าง ShareLaTeX และ Overleaf สามารถใช้ฟอนต์ไทยกับ XeLaTeX ได้โดยไม่ต้องอัปโหลดฟอนต์ร่วมกับเอกสาร ซึ่งข้อนี้ผมคิดไม่ถึง เพราะคิดแค่กรณีของผู้ใช้ XeTeX ในเครื่องส่วนตัว ซึ่งสามารถใช้ฟอนต์จากระบบได้อยู่แล้ว แต่สำหรับบริการออนไลน์ หรือแม้แต่เครื่องที่ผู้ใช้ไม่มีสิทธิ์ติดตั้งฟอนต์ในระบบแล้ว การจัดเตรียมฟอนต์ OpenType มากับชุด TeX distribution เลยย่อมอำนวยความสะดวกได้ดีกว่า
  • จัดการเรื่อง reproducibility ของการ build ฟอนต์ หลังจากที่ Debian รายงานมานาน และเขาได้ข้อยุติเรื่องการแก้ปัญหาใน Fontforge กันไปแล้ว โดยที่ Fonts-TLWG ของเราก็ยังไม่ reproducible อยู่ดี จึงคิดว่าควรได้ฤกษ์จัดการในฝั่งของเราเสียที ซึ่งในการแก้ก็ต้องจัดโครงสร้างของซอร์สและการ build ใหม่ จึงได้ขึ้นเลขรุ่นเป็น 0.7.x

หลังจาก อัปโหลด แพกเกจเข้า Debian ไปแล้ว ก็รอตรวจสอบหน้า reproducible build ของ fonts-tlwg ใน unstable ปรากฏว่ายังไม่ผ่าน ยังคงมีประเด็นตกค้างอยู่ ซึ่งเมื่อตรวจสอบ diff ดูแล้ว พบว่ามาจาก date stamp ที่เกิดจากฟิลด์ UniqueID ใน TTF Names ที่ Fontforge เติมให้โดยอัตโนมัติสำหรับฟอนต์ที่ไม่ได้จัดเตรียมไว้

(สังเกตที่คำว่า date stamp ซึ่งเป็นสาเหตุที่ทำให้มันหลุดรอดการทดสอบก่อนออกรุ่น 0.7.0 เพราะผมไม่ได้ทดสอบแบบข้ามวัน ทดสอบกี่รอบ date stamp มันก็ไม่เปลี่ยน)

Fonts-TLWG 0.7.1 จึงเกิดขึ้นตามมาเพื่ออุดช่องโหว่ดังกล่าว โดยเติมฟิลด์ UniqueID ใน TTF Names ให้ครบทุกฟอนต์เสีย

ขณะเดียวกัน เป็นธรรมเนียมของ Fonts-TLWG ที่จะ release พร้อมกับฟอนต์ OTF, TTF, WOFF ที่ build สำเร็จรูปแล้ว นอกเหนือจากซอร์สของฟอนต์ เพื่ออำนวยความสะดวกผู้ใช้ฟอนต์ทั่วไปที่ไม่สะดวกจะ build ฟอนต์เอง ซึ่งในทุกรุ่นที่ผ่านมา ผมสร้าง tarball เหล่านี้แบบ manual ด้วยการ configure และ build สามแบบเพื่อเก็บเข้า tarball ทีละก้อน ซึ่งถ้านาน ๆ ทำทีก็ไม่รู้สึกลำบาก แต่พอออกรุ่นนี้ไล่หลังรุ่นที่แล้วแบบค่อนข้างกระชั้นชิด เลยรู้สึกว่ามันควร automate มาตั้งนานแล้ว

จึงได้เป็น automation สำหรับการ build font tarballs โดยอิงอาศัย make rule ชุดเดิมที่เคยใช้ build ZIP file สำหรับ CTAN upload

พร้อมกันนี้ ในรุ่นนี้ผมเริ่มเผยแพร่ฟอนต์สำเร็จรูปในรูปแบบ ZIP file นอกเหนือจาก tarball ด้วย เพื่อส่งเสริมการใช้งานในวินโดวส์หรือแฟลตฟอร์มอื่นด้วย เพราะที่ผ่านมา Fonts-TLWG ถูกมองจากผู้ใช้ทั่วไปว่าเป็น ฟอนต์สำหรับ LaTeX บ้าง ฟอนต์สำหรับลินุกซ์ บ้าง ทั้งที่มันใช้ได้ในแพลตฟอร์มทั่วไป

upload เข้า Debian แล้ว ต่อไปก็รอดู reproducibility test ต่อไป

ทางด้าน CTAN ก็ได้ upload ไล่หลัง Debian แล้วทั้งสองรุ่น

ป้ายกำกับ: ,

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 ต่อไปในอนาคตได้

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

25 เมษายน 2561

Fonts-TLWG 0.6.5

Fonts-TLWG 0.6.5 ออกแล้ว โดยมีความเปลี่ยนแปลงที่สำคัญคือการแก้บั๊กของฟอนต์ Laksaman เมื่อใช้กับเอกสาร LaTeX โดยผมได้รับรายงานปัญหานี้จาก อ. กิตติพิชญ์ มีสวาสดิ์ ในการประชุม โสเหล่ ของ KKLUG เมื่อเดือนมีนาคมที่ผ่านมา

อาการคือ คำที่มี ff, ffi, ffl จะไม่มี ligature สามชุดนี้ปรากฏ ผมสร้างเอกสารทดสอบ โดยในข้อความแต่ละชุด บรรทัดแรกจะป้อนข้อความปกติ ส่วนบรรทัดที่สองจะเลี่ยง ligature:

if iff film flow difficult affluent

if if{}f f{}ilm f{}low dif{}f{}icult af{}f{}luent

ผลลัพธ์คือ:

Laksaman bug on LaTeX

สังเกต ligature ที่หายไปในบรรทัดแรกของข้อความแต่ละชุด

ในฟอนต์ต้นทาง คือ TH Sarabun New นั้น มี ligature ของละตินมาให้เพียงสองตัว คือ fi และ fl แต่ในกฎ LIGKERN ของ TeX จะใช้ทั้งหมด 5 ตัว โดยอีก 3 ตัวที่ยังขาดคือ ff ffi และ ffl เมื่อสร้าง glyph ทั้งสามตัวเพิ่มเข้าไปก็จะได้ผลลัพธ์ที่ควรจะเป็น:

Laksaman fixed for LaTeX

ผลข้างเคียงก็คือ ฟอนต์ Laksaman เมื่อใช้บนเดสก์ท็อปหรือบนเว็บจะมี ligature ครบกว่า TH Sarabun New ซึ่งความแตกต่างนี้ต้องสังเกตใกล้ ๆ อย่างละเอียดพอสมควร

ก่อนแก้:

Laksaman on Firefox, before

หลังแก้:

Laksaman on Firefox, after

ขอขอบคุณ อ. กิตติพิชญ์ ผู้ใช้ LaTeX ตัวจริงคนหนึ่งมา ณ ที่นี้ ที่จับบั๊กนี้ได้ครับ

นอกจากนี้ยังมีความเปลี่ยนแปลงอื่น ๆ คือ:

  • แปลงแฟ้มต้นฉบับของฟอนต์เป็นฟอร์แมตของ Fontforge รุ่นล่าสุด
  • ปรับ configure script ให้ตรวจรุ่นของ fontforge ตามรูปแบบเลขรุ่นที่เปลี่ยนไป จากแบบตัวเลขมาเป็นแบบวันที่
  • ย้ายที่ติดตั้งแฟ้ม fontconfig template ทั้งหลาย จาก /etc/fonts ไปไว้ที่ /usr/share/fontconfig ตามการเปลี่ยนแปลงใน fontconfig ล่าสุด
  • ปรับค่า TTFWeight ของฟอนต์น้ำหนักปกติทุกฟอนต์ให้เป็นค่า 400 (Regular) ทั้งหมด เนื่องจากบางฟอนต์ที่ยังมีค่าเป็น 500 (Medium) นั้น ทำให้แอปบางตัว (เช่นที่รายงานใน Issue #5 คือ EditPad) จัดฟอนต์ให้ไปอยู่ในกลุ่มตัวหนา

ได้อัปโหลดฟอนต์รุ่นใหม่ขึ้น CTAN ไว้แล้ว รอสักระยะถึงจะมาถึงดิสโทรต่าง ๆ เพื่อให้ใช้กับเอกสาร LaTeX ได้

ส่วนบนเดสก์ท็อปนั้น ก็ได้อัปโหลด 1:0.6.5-1 เข้า Debian เรียบร้อยแล้วครับ

ป้ายกำกับ: ,

20 ตุลาคม 2560

Fonts-SIPA-Arundina 0.2.2

Fonts-SIPA-Arundina 0.2.2 ออกแล้ว รุ่นนี้ปรับปรุงความสามารถของ LaTeX package โดยดึงมาจาก Fonts-TLWG 0.6.4 สองเรื่อง คือ

  • ตัวเลือก sans เพื่อกำหนดให้ใช้ฟอนต์ sans-serif เป็นฟอนต์ปริยายของเอกสาร
  • ตัวเลือก scale=value เพื่อกำหนดอัตราย่อ-ขยายของตัวอักษร

นอกจากนี้ ยังมีรายการเปลี่ยนแปลงเล็กน้อยเกี่ยวกับ CTAN คือผมพยายามจะเปลี่ยนชื่อแพกเกจจาก fonts-sipa-arundina ให้เป็น fonts-arundina เพื่อความกระชับในการเรียก โดยได้ทำไปแล้วสองส่วน คือ ชื่อโครงการที่ GitHub และในชื่อแพกเกจ LaTeX ซึ่งผู้ใช้สามารถเรียกใช้ด้วยคำสั่ง \usepackage{fonts-arundina} ได้

ส่วนที่ทำเพิ่มในรุ่นนี้ก็คือ การเปลี่ยนชื่อไดเรกทอรีที่ CTAN จาก /fonts/thai/fonts-sipa-arundina ให้เป็น /fonts/thai/fonts-arundina เฉย ๆ เพื่อให้สอดคล้องกับชื่อแพกเกจจริง รวมทั้งเปลี่ยนชื่อ source directory ใน CTAN ZIP file ด้วย

ส่วนที่ยังเหลือ คือ ชื่อ Debian package และ ชื่อ FTP directory ที่ LTN ซึ่งทั้งสองส่วนยังเกี่ยวพันกันอยู่ และการเปลี่ยนชื่อแพกเกจใน Debian จะมีรายละเอียดให้ทำพอสมควร เช่น การรอคิว NEW, การทำ package transition, การ clean config file เก่า ฯลฯ จึงยังคงชะลอไว้ก่อน จนกว่าจะมีเวลาเป็นเรื่องเป็นราวกว่านี้

เนื่องจาก LaTeX package ของฟอนต์ Arundina ยังไม่ได้เป็นส่วนหนึ่งของ TeXLive เหมือนกับชุด fonts-tlwg และเสิร์ฟให้ผู้ใช้ Debian ผ่านแพกเกจ latex-fonts-sipa-arundina โดยตรง ผู้ใช้ LaTeX ผ่าน Debian unstable จึงสามารถอัปเกรดและทดลองใช้ได้ทันที

ป้ายกำกับ: ,

06 ตุลาคม 2560

Fonts-TLWG 0.6.4

Fonts-TLWG 0.6.4 ออกแล้วเมื่อวันก่อน โดยรุ่นนี้เป็นผลงานของคุณ Abhabongse Janthong ที่ได้รายงานบั๊ก 1 รายการ และขอเพิ่มฟีเจอร์อีก 1 รายการ ซึ่งเป็นเรื่องเกี่ยวกับ LaTeX ทั้งสองรายการ

Issue #1 เป็นปัญหาความไม่สมบูรณ์ของการกำหนดตระกูลฟอนต์เมื่อสลับภาษาใน Babel ทำให้คำสั่ง \normalfont ทำงานผิดพลาดเมื่อใช้ร่วมกับตัวเลือก sans ของแพกเกจ ซึ่งคุณ Abhabongse ก็ได้เสนอ Pull Request #2 เพื่อแก้ปัญหานี้

กล่าวคือ รุ่นนี้จะแก้ปัญหากรณีเช่นนี้:

\usepackage[sans]{fonts-tlwg}

...

ข้อความก่อน \normalfont ข้อความหลัง

ทั้ง ข้อความก่อน และ ข้อความหลัง ควรเป็นฟอนต์ sans-serif ทั้งคู่ ซึ่งรุ่นก่อนหน้านี้จะจัด ข้อความหลัง ด้วยฟอนต์ serif ซึ่งไม่ถูกต้อง

ส่วนอีกรายการหนึ่งคือ Pull Request #3 เพื่อเพิ่มตัวเลือก scale สำหรับกำหนดอัตราย่อ-ขยายของตัวอักษรตามต้องการ ซึ่งจะเป็นประโยชน์ในกรณีที่ใช้ฟอนต์ชุดนี้ร่วมกับภาษาอื่นที่ฟอนต์ขนาดไม่สมส่วนกัน กล่าวคือ ในรุ่นนี้ ผู้ใช้จะสามารถใช้ตัวเลือกเช่นนี้เพื่อขยายขนาดตัวอักษรขึ้น 30% :

\usepackage[scale=1.3]{fonts-tlwg}

เนื่องจากในรุ่นนี้ไม่มีความเปลี่ยนแปลงในเนื้อหาส่วนอื่นอีกนอกจากการรองรับ LaTeX ผู้ใช้จะได้พบสิ่งที่เปลี่ยนแปลง ก็จากแพกเกจ fonts-tlwg บน CTAN เท่านั้น ส่วน Debian upload นั้น ก็เป็นไปตามภาคบังคับเพื่ออัปเดตรุ่นและซอร์สโค้ด ผู้ใช้ Debian สามารถติดตามได้จากแพกเกจ texlive-lang-other ว่าจะดึง fonts-tlwg ตัวใหม่จาก CTAN มาเสิร์ฟเมื่อไร

สุดท้ายนี้ ขอขอบคุณคุณ Abhabongse Janthong สำหรับความคืบหน้าที่เกิดขึ้นในรุ่นนี้ครับ

ป้ายกำกับ: ,

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 หรือเปล่าก็ไม่ทราบได้ แต่การแก้ในฟอนต์ที่ผมทำไปก็เท่ากับทำให้มันทำงานบนวินโดวส์ได้ด้วย

ป้ายกำกับ: ,

08 กรกฎาคม 2557

Fonts-TLWG 0.6.1

Fonts-TLWG 0.6.1 ออกไปแล้วเมื่อวานนี้ สรุปความเปลี่ยนแปลงในรุ่นนี้คือ:

  • ฟอนต์ใหม่: ลักษมัณ (Laksaman) ซึ่งดัดแปลงจากฟอนต์ TH Sarabun New ของคุณศุภกิจ เฉลิมลาภ และ SIPA
  • แตกแฟ้ม fontconfig จากแฟ้มเดี่ยวๆ เป็นแฟ้มย่อย เพื่อให้สามารถเลือกติดตั้งฟอนต์เพียงบางส่วนได้ ซึ่งเป็นสิ่งที่ดัดแปลงไว้ในแพกเกจของ Debian ก็เพียงแต่ merge เข้ามาที่ต้นน้ำเท่านั้น
  • Option ใหม่สำหรับ LaTeX เพื่อให้สามารถกำหนดฟอนต์ปริยายของเอกสารได้โดยสะดวก

มีผลข้างเคียงอีกเรื่องหนึ่งที่ไม่ได้กล่าวไว้ใน blog ก่อน ๆ คือเรื่องการตัดการวาด ฤา เป็น ฤๅ ของฟอนต์สารบรรณออกในฟอนต์ลักษมัณ ซึ่งการวาดดังกล่าวผมถือว่าผิดหลักการ เพราะสตริงทั้งสองถือว่าเป็นสตริงที่ต่างกันทั้งในรหัส มอก.620-2533 และในยูนิโค้ด ผู้ใช้ควรสามารถแยกความแตกต่างได้ว่าเป็นสตริงที่ต่างกัน

พฤติกรรมนี้อาจมาจากการพยายามแก้การพิมพ์ผิดอย่างกลาดเกลื่อนของผู้ใช้ทั่วไป ที่มักจะพิมพ์ ฤๅ และ ฦๅ โดยใช้สระอาแทนลากข้างยาว แต่การแก้ที่ฟอนต์ถือว่าไม่ถูกต้อง เพราะเป็นการอำพรางความแตกต่างของข้อมูลจริง หากจะแก้ปัญหาให้ถูก ควรแก้ที่ input method ซึ่งประเด็นที่คล้ายกันนี้ผมเคยเขียนถึงไปแล้วใน กรณีฟอนต์ Sarabun IT9 การแก้ปัญหาที่ฟอนต์จะยิ่งเป็นการส่งเสริมการป้อนข้อมูลที่ผิดให้กว้างขวางยิ่งขึ้น ดังนั้นผมจึงตัดกฎข้อนี้ออกในฟอนต์ลักษมัณ และถ้าเป็นไปได้ก็อยากให้แก้ในฟอนต์มาตรฐานราชการไทยทั้ง 13 ฟอนต์ด้วย

ได้อัปโหลด Debian package เข้า sid ไปแล้ว แต่ยังรออยู่ในคิว NEW เนื่องจากมีแพกเกจใหม่ของฟอนต์ลักษมัณเพิ่มเข้ามา พร้อมกันนี้ก็ได้อัปโหลดแพกเกจ LaTeX ไปที่ CTAN แล้วด้วย ผู้ใช้ TeXLive ก็รอพบได้จากแพกเกจ texlive-lang-other รุ่นถัดไปครับ

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

01 กรกฎาคม 2557

Laksaman Font

จาก แผนการ ที่วางไว้สำหรับการดัดแปลงฟอนต์สารบรรณเพื่อผลักดันเข้า Debian ว่าจะตกลงใช้ Fonts-TLWG เป็นฐาน ก็ได้ใช้เวลาว่างทำเก็บเล็กผสมน้อยวันละนิด ขณะนี้ก็เริ่มเป็นรูปเป็นร่างแล้ว

สรุปสิ่งที่ปรับจาก TH Sarabun New

  • เปลี่ยนชื่อฟอนต์เป็น Laksaman (ลักษมัณ) โดยอิงตามชื่อที่ใช้ในฟอนต์ชุด Siampradesh แต่ตัด prefix SP ออก
  • ขยายตัวอักษรเป็น 150.42% เพื่อให้ match กับฟอนต์ตะวันตก และเข้ากันกับฟอนต์อื่นในชุด Fonts-TLWG
  • แปลง spline จาก quadratic เป็น cubic พร้อมทำความสะอาด spline
  • เพิ่ม Postscript hints
  • โละ GSUB rules ที่เกี่ยวกับภาษาไทยทิ้งทั้งหมด แล้วเพิ่ม GPOS, GSUB ตามแบบของ Fonts-TLWG
  • เพิ่ม glyph บางส่วนเพื่อรองรับภาษาชาติพันธุ์
  • เพิ่มการรองรับ LaTeX (pdfTeX) โดยเพิ่มเข้าในแพกเกจ fonts-tlwg
  • เพิ่มการสังเคราะห์ฟอนต์ TH Sarabun{PSK, New} บนเดสก์ท็อปผ่าน fontconfig

หลังจากตรวจความเรียบร้อยต่าง ๆ แล้ว คงสามารถออกรุ่นใหม่ได้เร็ว ๆ นี้ครับ

ป้ายกำกับ: ,

08 มีนาคม 2555

ThaiLaTeX Hyphenation

จากที่ได้ blog ครั้งล่าสุด เกี่ยวกับ ThaiLaTeX ผมก็ได้ออกรุ่นซอฟต์แวร์ทั้งหมดที่เกี่ยวข้องไปแล้วตั้งแต่กลางเดือนกุมภา คือ Fonts-TLWG 0.5.0 และ Fonts-SIPA-Arundina 0.2.0 ซึ่งได้เปลี่ยนชื่อโครงการด้วย แล้วก็ตามด้วย ThaiLaTeX 0.4.7 ในคราวเดียวกัน เผอิญว่าติดธุระส่วนตัวมากจนไม่สามารถหาเวลานั่งเขียน blog ได้

เกี่ยวกับการเปลี่ยนชื่อโครงการฟอนต์ทั้งสองนี้ ก็ด้วยเหตุว่ามีการเปลี่ยนชื่อที่ปลายน้ำหลายจุดไปในทางเดียวกัน ไม่ว่าจะเป็นที่ Debian หรือ CTAN โดยสำหรับ Debian นั้น กลุ่มผู้ดูแลแพกเกจฟอนต์ของ Debian ได้กำหนดวิธีการตั้งชื่อแพกเกจฟอนต์ใหม่ ซึ่งก็ได้รับแรงบันดาลใจมาจาก Fedora อีกต่อหนึ่ง ส่วนที่ CTAN นั้น เขาต้องการชื่อแพกเกจที่สอดคล้องกันกับชื่อ style file ที่ติดตั้ง และไดเรกทอรีที่ติดตั้ง ควรมีเอกภาพเป็นชื่อเดียว ซึ่งก็ได้เลือกชื่อ fonts-tlwg สำหรับโครงการ ThaiFonts-Scalable อีกอย่าง ตอนนี้ linux.thai.net ก็ได้โฮสต์โครงการฟอนต์หลายโครงการ การตั้งชื่อที่กว้างเกินไปอย่าง ThaiFonts-Scalable ย่อมไม่เหมาะสมอีกต่อไป จึงได้เปลี่ยนชื่อเป็น Fonts-TLWG และฟอนต์ชุด Arundina ก็เปลี่ยนเป็น Fonts-SIPA-Arundina ในทำนองเดียวกัน

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

แนวทางที่คุยกันไว้นั้น เป็นไปได้หลายวิธี:

  • ทำ hyphenation pattern สำหรับ TeX โดยใช้ patgen
  • ปรับ swath ให้แทรก soft hyphen (\- สำหรับ TeX) ด้วย

สำหรับทางเลือกแรกที่ทำ pattern สำหรับ TeX นั้น หากทำสำเร็จจะสามารถใช้กับโครงการอื่น เช่น FOP ของ Apache รวมถึง LibreOffice ด้วย

ผมเริ่มจากทางแรกก่อน โดยอาศัย word list ของ libthai มาแทรกยัติภังค์ที่จุดที่เป็นไปได้ แล้วป้อนเข้า patgen สร้างเป็น hyphenation pattern ออกมา แล้วติดตั้งลงใน TeX ปรากฏว่าผลที่ได้เป็นที่น่าพอใจพอสมควร ดังตัวอย่างเปรียบเทียบการจัดย่อหน้าโดยใช้และไม่ใช้ยัติภังค์:

เปรียบเทียบผลจาก hyphenation

จะเห็นว่าช่องไฟที่โบ๋ ๆ ลดน้อยลง และทำให้ย่อหน้ากระชับเข้ามาอีก เมื่อสังเกตจุดตัดบรรทัดก็จะพบว่า TeX คำนวณจุดแบ่งบรรทัดโดยมองภาพรวมทั้งย่อหน้า ไม่ใช่คำนวณทีละบรรทัด

นี่เป็นผลในขั้นแรก ซึ่งได้ commit เข้าใน trunk ของ SVN ของ thailatex แล้ว โดยที่ผมยืมค่าพารามิเตอร์สำหรับ patgen มาจาก วิทยานิพนธ์ชิ้นหนึ่ง โดยยังไม่ได้ปรับละเอียดเองตามข้อมูลที่มี ซึ่งตรงนี้คงหาเวลาทำในโอกาสต่อไป

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

27 ตุลาคม 2554

ThaiLaTeX 0.4.6 Refactored

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

จาก แผนงาน ThaiLaTeX ที่ได้วางไว้ ตอนนี้ก็ได้ดำเนินการสองขั้นแรกเสร็จแล้ว คือการออก ThaiFonts-Scalable 0.4.16 และ ThaiLaTeX 0.4.6 โดยได้ย้ายฟอนต์จาก ThaiLaTeX มาไว้ทางฝั่ง ThaiFonts-Scalable เรียบร้อยแล้ว

ใครที่ใช้ Debian sid ก็คงได้เห็นการเปลี่ยนแปลงแล้วเมื่อเช้านี้ ส่วน distro อื่น รวมถึงผู้ใช้ MikTeX ที่ติดตั้งแพกเกจผ่าน CTAN ก็อดใจรอสักนิด

การย้ายฟอนต์ในครั้งนี้ ปรากฏว่าเมื่อลงมือทำจริง มีบางส่วนที่ไม่เป็นไปตามคาด คือไม่ได้ทำ automake snippet ไว้ให้แพกเกจฟอนต์ดึงไปใช้ เนื่องจาก:

  • ไม่มีวิธีง่าย ๆ ในการพิจารณาตำแหน่งของ include file โดยถ้าเป็น make ธรรมดานั้น คำสั่ง include สามารถไปค้นหาไฟล์จากไดเรกทอรี /usr[/local]/include ได้เลย แต่ automake กลับมา override คำสั่งนี้ และสามารถ include ไฟล์ได้แค่จากภายใน source tree หรือระบุพาธเต็มเท่านั้น ซึ่งถ้าจะใช้ข้ามแพกเกจก็ต้องเพิ่มสคริปต์ configure มาตรวจสอบยุ่งยากอีก
  • เมื่อพิจารณาแพกเกจฟอนต์อื่นที่การใช้ฟอนต์ TrueType อาจจะเหมาะกว่า Type 1 เช่น ThaiFonts-Arundina สุดท้ายก็คงได้ไปปรับกฎใหม่อีกอยู่ดี

พิจารณาแล้ว ได้ไม่คุ้มเสีย จึงเลือกตัดความยุ่งยากทั้งหลาย ใช้วิธีตัดแปะกฎเอา คงมีแต่ซอร์สที่ใช้ build ส่วน LIGKERN เท่านั้นที่จะติดตั้งให้ใช้ร่วมกัน

ในการ refactor ครั้งนี้ มีจุดหนึ่งที่ถือเป็นก้าวกระโดดสำคัญ คือการปลดพันธนาการระหว่างฟอนต์กับข้อกำหนดภาษาใน babel จากเดิมที่ thai.ldf จะกำหนดฟอนต์หลักสามแบบ คือ roman, san-serif, teletype สำหรับภาษาไทยไว้ด้วย ทำให้ข้อกำหนดภาษาจำเป็นต้องมีฟอนต์ติดพ่วงไปด้วย สร้างความลำบากใจในการส่งโค้ดเข้ารวมใน babel แต่เมื่อได้สำรวจภาษาอื่น ก็ได้พบวิธีการที่เขาทำกัน คือจะกำหนดแค่ font encoding เท่านั้น ไม่ได้กำหนด family แล้ว LaTeX จะไปหาฟอนต์ตัวใดตัวหนึ่งที่มี encoding ตามที่กำหนดนี้มาใช้ให้เอง (ซึ่งวิธีเลือกนั้นผมยังไม่ได้ค้น) จากนั้น ถ้าผู้ใช้จะใช้ฟอนต์อะไร ถ้าไม่ใช้วิธีกำหนด \usefont ตรง ๆ ก็จะไป \usepacakge ของฟอนต์นั้น ๆ แล้วตัว style ของแพกเกจก็จะกำหนดฟอนต์หลักให้อีกที

ก็เป็นวิธีที่ดี เพราะถ้าต่อไปเราเพิ่มฟอนต์ไทยชุดอื่น ถ้าผู้ใช้ต้องการเลือกใช้ฟอนต์ชุดไหน ก็ไป \usepackage ชุดที่ต้องการเอา ไม่ต้องมีอะไรผูกพ่วงกับข้อกำหนดภาษา

เมื่อแยกขาดออกจากกันได้อย่างนี้ ก็ทำให้ thai.ldf ของเราเบาสบายคล่องตัวขึ้นมาก ขอแค่มาตรวจทานให้ดีสักหน่อย ก็น่าจะส่งเข้ารวมใน babel ได้เลย (โดยอาจจะส่ง lthuni.enc เข้าไปอีกไฟล์หนึ่งด้วย แต่ต้องสำรวจอีกที) และเมื่อพิจารณาสิ่งที่เหลืออยู่นอกจากฟอนต์กับ babel แล้ว ก็เหลือเพียง Emacs macro เล็ก ๆ กับคำสั่งเชลล์เล็ก ๆ เท่านั้น จนทำให้ไม่ต้องมีแพกเกจ ThaiLaTeX อีกต่อไปก็ได้ และนั่นคือสิ่งที่ผมคิดจะทำในขั้นต่อไปหลังจากเสร็จงานครั้งนี้ ThaiLaTeX must die!

สำหรับผู้ใช้ เดิมจะมีแพกเกจ thswitch เพื่อใช้สลับชุดฟอนต์ระหว่างไทย-ละตินอยู่ นอกเหนือจากค่าปริยายในข้อกำหนดภาษา ซึ่งแพกเกจนี้จะยังคงมีผลอยู่ในรุ่นใหม่ที่ได้ตัดฟอนต์ออกไปแล้ว เพื่อเป็นการรักษาความเข้ากันได้กับเอกสารเดิมที่มีอยู่ โดยจะอ้างอิงไปถึงฟอนต์ชุดเดิมที่ได้แยกออกไปเหมือนเดิม ถ้าเอกสารของคุณใช้แพกเกจนี้อยู่แล้ว ก็ไม่มีปัญหา คุณสามารถสลับฟอนต์ในเอกสารด้วยคำสั่ง \rmfamily (หรือ \textrm{}), \sffamily (หรือ \textsf{}) และ \ttfamily (หรือ \texttt{}) ได้ตามปกติ แต่ถ้าไม่ได้ใช้ คำสั่งสลับฟอนต์เหล่านี้จะไม่มีผลในรุ่นใหม่ คือมันจะใช้ฟอนต์ปริยายที่ตรวจพบเพียงฟอนต์เดียวไปตลอดเอกสาร

ถ้าคุณต้องการสลับฟอนต์ในเอกสาร ขอแนะนำให้ใช้แพกเกจ fonts-tlwg ดังนี้:

\usepackage{fons-tlwg}

ซึ่งในขณะนี้ คำสั่งด้านบนมีผลเทียบเท่ากับ \usepackage{thswitch} ทุกประการ และขอแนะนำให้เอกสารใหม่ ๆ ใช้วิธีการนี้แทน thswitch ที่อาจจะถูกตัดออกในอนาคต

ขั้นต่อไป ผมคิดว่าจะทำแบบนี้กับฟอนต์ชุด Arundina เป็นรายต่อไป และผู้ใช้คงเริ่มเห็นภาพ ว่าทำไมต้อง deprecate แพกเกจ thswitch นี้

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

hacker emblem