Level 3: Application Integration • Chapter 3.3 Linux/Docker Font Extensions & HarfBuzz Complex Text Shaping
คำถาม: ในสถาปัตยกรรม Direct Socket Streaming ของบทที่ 3.2 หากรายงานที่กำลังเรนเดอร์มีการใช้ฟอนต์ TrueType ที่ไม่ได้ติดตั้งใน OS ของ Production Docker Container (Linux Alpine/Debian) และไม่มี Font Extension JAR ใน Classpath จะเกิดความเสียหายใดในระดับ Engine และ JVM?
-Djava.awt.headless=true JVM AWT Engine จะพังด้วย HeadlessException ทันที 2) หากขาด Font Extension แต่ AWT ทำงานได้ JasperReports จะตกไปสู่ Fallback Font (เช่น Helvetica หรือ Dialog) ซึ่งไม่มีฟอนต์ Glyph ภาษาไทย ทำให้สระลอย สระจม กลายเป็นกล่องสี่เหลี่ยมเต๋า (Tofu Characters □) หรือพังด้วย JRFontNotFoundException และขนาดความกว้างข้อความที่เปลี่ยนไปจะทำลาย Typographic Grid จนข้อความล้น Band (Stretch Overflow)
The "Why" & Real-world Problem: The Silent Container Typography Disaster
บ่อยครั้งที่นักพัฒนาทดสอบบน Windows หรือ macOS ซึ่งมีระบบปฏิบัติการที่พ่วงฟอนต์ลิขสิทธิ์และ Font Rasterizer มาให้ครบ รายงานจึงเรนเดอร์สวยงาม แต่เมื่อ Deploy เป็น Docker Container บน Kubernetes (Ubuntu/Alpine Linux) กลับพบหายนะ 3 ชั้น:
แยกไฟล์ TrueType (`.ttf`) บรรจุร่วมกับ `jasperreports_extension.properties` และ XML Font Families เป็น Extension JAR เอกเทศ บรรจุเข้า Classpath ของแอปพลิเคชัน ตัดการพึ่งพา OS-level Fonts 100%
ใช้ HarfBuzz Engine ควบคู่กับ AWT Layout Engine เพื่อคำนวณ Glyph Substitution (GSUB) และ Glyph Positioning (GPOS) จัดสระและวรรณยุกต์ภาษาไทย/Indic ให้อยู่ในระดับพิกัดที่สมบูรณ์แบบ ไร้ปัญหาสระลอย
บังคับ `pdfEmbedded="true"` และ `pdfEncoding="Identity-H"` ใน Font Family Definition เพื่อฝัง Subset ของ Unicode Font เข้าไปใน PDF Stream โดยตรง แสดงผลถูกต้องทุกอุปกรณ์แม้อุปกรณ์ผู้ใช้ไม่มีฟอนต์นั้น
ติดตั้ง Package พื้นฐานที่จำเป็นของ Native Library (`libfontconfig1`, `libfreetype6`) ใน Dockerfile พร้อมตั้ง JVM Flag `-Djava.awt.headless=true` เพื่อให้ AWT FontMetrics คำนวณพิกัดข้อความได้แม่นยำ 100%
| Failure Pattern | Engine & JVM Mechanics | Architectural Defense (Standard 7.0.x) |
|---|---|---|
| HeadlessException Crash | เมื่อไม่มี Display Device (X11) AWT Graphics2D ของ JVM จะโยน Exception ทันทีที่สั่งคำนวณ FontMetrics | กำหนดตัวแปร JVM Flag -Djava.awt.headless=true ใน Container Entrypoint และติดตั้ง libfontconfig1 |
| Tofu Characters (□□□) | PDF Exporter ไม่พบ Glyph สำหรับรหัส Unicode ภาษาไทยในฟอนต์มาตรฐาน (Helvetica/Times) จึงวาดเป็น Missing Glyph Box | ประกาศ Font Extension JAR กำหนด pdfEncoding="Identity-H" และ pdfEmbedded="true" |
| Floating Vowels (สระลอย) | Text Layout ทั่วไปขาด HarfBuzz OpenType Shaping ทำให้ไม่สามารถทำ Contextual Ligature และ Mark-to-Base Attachment ได้ | เปิดใช้งาน JasperReports HarfBuzz Shaper integration และใช้ฟอนต์ OpenType/TrueType ที่มีตาราง GPOS/GSUB สมบูรณ์ (เช่น Sarabun) |
| JRFontNotFoundException | ตัวแปรคอนฟิก net.sf.jasperreports.awt.ignore.missing.font=false ทำงานเมื่อระบบมองไม่เห็นฟอนต์ที่ระบุใน JRXML |
ใช้ Font Extension Name เป็น Logical Font Name ที่แมปเข้ากับ Physical TTF File อย่างแม่นยำ |
สลับแท็บเพื่อศึกษาและทดสอบทั้ง 3 ส่วน: Lab 3.3.1 (Font Extension XML & Config), Lab 3.3.2 (Production Dockerfile Hardening), และ Lab 3.3.3 (Unified JRXML Template 7.0.x)
| รหัสหลักทรัพย์ | ชื่อรายการหลักทรัพย์ | จำนวนหน่วย | ราคาเฉลี่ย | มูลค่าสุทธิ (บาท) |
|---|---|---|---|---|
| PTT | บมจ. ปตท. (หุ้นสามัญ) | 10,000 | 34.50 | 345,000.00 |
| KBANK | บมจ. ธนาคารกสิกรไทย | 3,500 | 148.00 | 518,000.00 |
| ADVANC | บมจ. แอดวานซ์ อินโฟร์ เซอร์วิส | 2,200 | 285.00 | 627,000.00 |
| AOT | บมจ. ท่าอากาศยานไทย | 5,000 | 63.25 | 316,250.00 |
ทดสอบความเข้าใจเชิงลึกเกี่ยวกับ Linux Headless AWT, Font Extensions, TrueType Embedding, HarfBuzz Text Shaping, และ Docker Container Environments
# jasperreports_extension.properties (วางไว้ที่ root ของ JAR ใน Classpath)
net.sf.jasperreports.extension.registry.factory.fonts=net.sf.jasperreports.engine.fonts.SimpleFontExtensionsRegistryFactory
net.sf.jasperreports.extension.fonts.families.sarabun=fonts/fonts.xml
# เปิดใช้งาน HarfBuzz Complex Text Shaper เพื่อจัดสระวรรณยุกต์ภาษาไทย
net.sf.jasperreports.default.font.name=Sarabun
net.sf.jasperreports.text.layout.complex=true