บทความนี้เกิดจากคำถามในกลุ่ม Laravel Thailand ซึ่งพบบ่อยพอสมควรว่าจะสร้าง PDF ภาษาไทยยังไง ก็เลยเขียนขึ้นมาซะเลย โดยในบทความนี้จะใช้ laravel-dompdf เป็นหลัก
วิธีการเพิ่ม font ภาษาไทยลง laravel-dompdf
เตรียมโปรเจคสำหรับทดสอบ
ส่วนนี้จะสอนลง laravel-dompdf กับสร้าง PDF แบบพังๆขึ้นมา 1 ตัวเพื่อใช้ทดสอบ ถ้าทำเป็นแล้วข้ามไปได้เลยครับ
- ก่อนอื่นก็ต้องลง Laravel แบบปกติก่อน (ไม่สอนนะ น่าจะทำกันเองเป็น) ในเวอร์ชันนี้ผมใช้ Laravel 5.4 แต่คิดว่าตระกูล 5.x สามารถใช้ได้เหมือนกันหมด
- สร้างโฟลเดอร์ storage/fonts และแก้ไข permission ให้สามารถเขียนได้ (โดยทั่วไปคือ 0777)
- ติดตั้ง laravel-dompdf โดยมีขั้นตอนดังนี้
- สั่ง
composer require barryvdh/laravel-dompdf
- แก้ไขไฟล์ config/app.php โดยเพิ่ม
Barryvdh\DomPDF\ServiceProvider::class,
ลงไปในส่วนของ providers
และเพิ่ม
'PDF' => Barryvdh\DomPDF\Facade::class,
ลงในส่วนของ aliases
- สั่ง
- สร้างหน้าทดลองสำหรับใช้ PDF (ในขั้นนี้ต้องประยุกต์เอาเองตามความต้องการ หากมีอยู่แล้วข้ามไปข้อ 4 ได้เลย)
- สร้าง view สำหรับทดสอบ โดยในตัวอย่างของผมคือ invoice.blade.php ใน resources/views/pdf โดยมีเนื้อหาดังนี้
<html> <head> </head> <body> <h1>ใบแจ้งหนี้สำหรับ คุณ{{ $name }}</h1> ขอขอบคุณในการสั่งซื้อ </body> </html>
- สร้าง route หรือ controller ในการสร้าง pdf (เนื่องจากเป็นตัวอย่าง เลยทำเป็น route ง่ายๆ)
<?php Route::get('/pdf', function () { $data = [ 'name'=>'อะไรสักอย่าง ไม่รู้นามสกุลอะไร' ]; $pdf = PDF::loadView('pdf.invoice', $data); return @$pdf->stream(); });
ในบรรทัดที่ 8 จำเป็นต้องใส่ @ นำหน้า เพื่อปิด error บางตัว ที่อาจจะเกิดจากการหา fonts ไม่เจอ
- หลังจากที่ทำตามข้างบนแล้วจะพบว่าเมื่อเข้าไปภาษาไทยยังเป็นเครื่องหมายตกใจอยู่ เพราะข้างบนนั้นยังไม่ได้ทำให้รองรับภาษาไทย
- สร้าง view สำหรับทดสอบ โดยในตัวอย่างของผมคือ invoice.blade.php ใน resources/views/pdf โดยมีเนื้อหาดังนี้
ปรับ laravel dompdf ให้สามารถใช้งาน font ภาษาไทยได้
ในขั้นนี้จะเป็นขั้นตอนจริงๆ เพื่อทำให้ laravel-dompdf รองรับภาษาไทยในการ render ต้องทำตามขั้นตอนต่อไปนี้เพื่อให้รองรับภาษาไทย โดยขั้นตอนนี้เป็นแบบง่าย ซึ่งในการสร้าง pdf ครั้งแรกสุดอาจจะทำให้ช้าได้ โดย font ไทยในครั้งนี้ผมเลือกใช้ THSarabunNew ครับ (ถ้าอยากดาวโหลดมาทำการทดสอบ สามารถดาวโหลดได้จากที่นี่)
- ให้สร้างโฟลเดอร์ชื่อ fonts ใน public และนำ font ทั้งหมดไปใส่ไว้ ดังรูป
- แก้ไขในส่วนของ views โดยเพิ่ม tag meta ลงไปใน head ของ invoice.blade.php จะได้เป็น
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> </head> <body> <h1>ใบแจ้งหนี้สำหรับ {{ $name }}</h1> ขอขอบคุณในการสั่งซื้อ </body> </html>
- เพิ่ม tag style เพื่อประกาศ fonts แบบ runtime และบอกให้ทั้งเอกสารใช้ fonts นั้น วิธีการคือให้แก้ไข invoice.blade.php ให้เป็นดังนี้
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <style> @font-face { font-family: 'THSarabunNew'; font-style: normal; font-weight: normal; src: url("{{ public_path('fonts/THSarabunNew.ttf') }}") format('truetype'); } body { font-family: "THSarabunNew"; } </style> </head> <body> <h1>ใบแจ้งหนี้สำหรับ {{ $name }}</h1> ขอขอบคุณในการสั่งซื้อ </body> </html>
โดยส่วนของการประกาศ fonts คือบรรทัดที่ 6 – 10 ส่วนสำคัญคือบรรทัดที่ 10 ที่เป็นการบอกว่า fonts อยู่ที่ไหน
และส่วนที่บอกว่า ให้ใช้ fonts ทั้งเอกสารคือบรรทัดที่ 12 – 14 โดยเราสามารถแก้ไขได้เหมือน css ปกติเลยว่าส่วนไหนใช้ fonts ไหน
โดยเมื่อเราทำตามขั้นตอนด้านบนแล้วจะได้ดังภาพ
ปัญหาที่พบบ่อย
- จากข้อก่อนหน้าจะเห็นได้ว่า เราได้ว่ามีบางส่วนมาเป็นภาษาไทยแล้ว แต่บางส่วนยังเป็นเครื่องหมายตกใจอยู่ สาเหตุเป็นเพราะตอนประกาศ font ในข้อก่อนหน้านั้น เราประกาศว่าใช้เฉพาะกับข้อความปกติเท่านั้น (บรรทัด 7-8 ในข้อก่อนหน้า) แต่ h1 นั้นจะให้ข้อความที่เป็นตัวหนา (font-weight: bold;) ดังนั้นเราจึงต้องประกาศเพิ่มให้ครบครับ จึงต้องแก้ invoice.blade.php เป็นดังนี้
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <style> @font-face { font-family: 'THSarabunNew'; font-style: normal; font-weight: normal; src: url("{{ public_path('fonts/THSarabunNew.ttf') }}") format('truetype'); } @font-face { font-family: 'THSarabunNew'; font-style: normal; font-weight: bold; src: url("{{ public_path('fonts/THSarabunNew Bold.ttf') }}") format('truetype'); } @font-face { font-family: 'THSarabunNew'; font-style: italic; font-weight: normal; src: url("{{ public_path('fonts/THSarabunNew Italic.ttf') }}") format('truetype'); } @font-face { font-family: 'THSarabunNew'; font-style: italic; font-weight: bold; src: url("{{ public_path('fonts/THSarabunNew BoldItalic.ttf') }}") format('truetype'); } body { font-family: "THSarabunNew"; } </style> </head> <body> <h1>ใบแจ้งหนี้สำหรับ {{ $name }}</h1> ขอขอบคุณในการสั่งซื้อ </body> </html>
ทีนี้พอเราสร้าง pdf ใหม่จะเห็นว่า สามารถใช้ภาษาไทยได้สมบูรณ์แล้ว
ข้อควรระวัง
ในการสร้าง pdf ครั้งแรกมันจะสร้างได้ช้าพอสมควรเนื่องจากมันต้องไป download font มา (จากเครื่องตัวเองนั่นแหละ) จากนั้นมาแปลง fonts เป็น format ของมัน และ cache ลงใน storage/fonts ทำให้ครั้งแรกช้ากว่าปกติพอสมควร แต่หลังจากนั้นจะความเร็วปกติ (เพราะ cache ไว้แล้ว)
ข้อแนะนำอื่นๆ
- หากนำไปใช้จริง ตัวเซิฟเวอร์ควรจะลง OPCache ไว้ด้วย เพื่อความรวดเร็วในการสร้าง PDF