2009/11/21

[程式] 使用PHP產生UNICODE中文PDF

從晚上九點弄到一點,趕緊把筆記寫起來
應該會很亂,來源處也要慢慢補

前言:
因為工作關係需要能用PHP產生PDF作報名表單,
爬很多文章看人介紹PDF套件後,選擇了FPDI這套工具,
因為FPDI可以匯入已經產生好的PDF檔,在覆蓋一層文字加工,
很適合做成表單類的輸出。(不然整個表格慢慢一行一行刻會掛點 囧)


簡介FPDI
FPDI是繼承於FPDF,FPDF可以說是PHP作PDF的大祖宗,
一堆套件都是基於FPDF而發展的,
而FPDI可以用樣版匯入的功能是繼承自FPDF_TPL,應該也是FPDF的繼承者吧~
繼承連結(箭頭左方繼承自右方):FPDI.php => FPDF_TPL.php => FPDF.php
FPDF http://www.fpdf.org/
FPDI http://www.setasign.de/products/pdf-php-solutions/fpdi/


殘酷的事實,UNICODE的逆襲
從<網站製作學習誌>看到這篇利用 FPDI 製作 PDF 檔案
當中是利用FPDI,再利用圖片輸出UTF8的解決方案
問題來了,原來FDPI不支援UTF8 = =


沙漠中的綠洲? 還是海市蜃樓
於是又再繞一大圈,UFPDF、TCPDF....一堆解決方案,就是沒有可以用樣板匯入的功能。但過程中找到FPDF為了解決中文字體的問題,而有chinese.php的改良版;
這支chinese.php也是繼承至FPDF發展的,可以輸出中文的PDF,
但是還是不支援UNICODE。

於是又有強者發表了chinese-unicode.php的程式,繼承至chinese.php (很繞口吧)。
繼承連結(箭頭左方繼承自右方):chinese-unicode.php => chinese.php => FPDP.php

但是,還是只能一行一行刻= =,已經兩小時了一點進展都沒(嘆)。<<chinese(-unicode).php>>http://www.wretch.cc/blog/evanchen/12079184


一語點醒夢中人
試了許多組的關鍵字去GOOGLE看有沒有其他可用的解決方法,發現有人原本用ZEND PDF產生也遇到中文的問題,改用FPDI與chinese-unicode.php結合!! 好像又露出一線生機。

但是!
要修改chinese-unicode.php,我看不懂原始碼啦= =
又開始CODING地獄
<<有人的BLOG>>http://wlx.westgis.ac.cn/556/

兩套標準,怎麼結合?
FPDI的繼承路線:FPDI.php => FPDF_TPL.php => FPDF.php
Chinese-Uni: chinese-unicode.php => chinese.php => FPDP.php
這讓我傷透腦筋阿~所以又開始亂拼,居然被我拼出來要改的地方還真多

  • 修改FPDI.php 從繼承FPDF_TPL改為PDF_Unicode (在chinese-unicode.php)
  • 修改chinese.php 把 require('fpdf.php') 注解掉 (我已經先引入還是會有問題,乾脆注掉)
  • 修改chinese.php 內 PDF_Chinese 類別從繼承FPDF改為繼承FPDF_TPL
這時候,已經可以由 樣板產生的 中文 UNICODE PDF ,灑花~~~~~~~
對只懂物件導向皮毛的我是一件非常不可能的事情XDD

新細明體真不搭,標楷體怎麼辦?
Google: chinese-unicode 標楷體
BINGO! 有兩篇可以看
原來只要修改chinese-unicode.php內的程式碼即可。

function AddUniCNShwFont ($family='Uni', $name='DFKai-SB') 
// name for Kai font is DFKai-SB "

其實只要修改粗體的地方(原本是 PMingLiU),改為DFKai-SB即可
<<標楷體>>http://www.wretch.cc/blog/evanchen/12079184

ADOBE太肥 我要用FOXIT!
另外的小修正,這樣改可以在ADOBE READER正常顯示標楷體,但是FOXIT不行= =

於是有人提出解決方法,
將DFKai-SB改為DFKaiShu-SB-Estd-BF,
在FOXIT 2.2沒用,更新為3就可以了。

(插曲:我在改用其他方案的時候,因為要製作字型描述檔 就把標楷體移過去,所以我一直試都無法變成標楷體,還以為是被唬爛,沒想到是我自己把標楷體弄不見= =,難怪會無法顯示)
<<FOXIT也是標楷體>>http://www.yces.chc.edu.tw/LifeType/blog/1



UTF測試正常

其實我也不知道要測甚麼字,就丟了"許公蓋烱測試堃",都可以正常顯示(使用FOXIT 3)

2009-11-22_014941.jpg



程式碼
幾乎都是從網站製作學習誌A來的,我只是多REQUIRE一堆東西,
如果不想這麼複雜,可能要自己把相關檔案集合,我是都分資料夾比較不會亂。
error_reporting (E_ALL);
define('FPDF_FONTPATH','font/');
require_once ('fpdi/FPDf.php');
require_once ('FPDI/FPDf_tpl.php');
require_once ('chinese-unicode/chinese-unicode.php');
require_once ('fpdi/FPDI.php');
// 建立 FPDI 物件
$pdf = new FPDI();
// 載入現在 PDF 檔案
$page_count = $pdf->setSourceFile("123.pdf");
// 匯入現在 PDF 檔案的第一頁
$tpl = $pdf->importPage(1);
// 在新的 PDF 上新增一頁
$pdf->addPage();
// 在新增的頁面上使用匯入的第一頁
$pdf->useTemplate($tpl);
$pdf->AddUniCNShwFont('uni');
$pdf->SetFont('uni','',20);
//$pdf->SetFont('Arial');
$pdf->SetTextColor(255,0,0);
$pdf->SetXY(25, 25);
$pdf->Write(0, "許公蓋烱測試堃");
// 輸出成本地端 PDF 檔案
$pdf->output("final.pdf", "D");
// 結束 FPDI 剖析器
$pdf->closeParsers();

目錄結構
/=>
chinese-unicode/ => chinese.php, chinese-unicode.php ...etc
fpdi/ => fpdi.php, fpdf.php...etc
index.php
123.pdf (Template File)

報告完畢,剩下就是喬位子了 Orz...
2011/07/19:關於喬位子,可參考 這篇 補充說明


=== 網友David補充 ===

如使用時會出現類似以下錯誤碼
Deprecated: Assigning the return value of new by reference is deprecated in /var/www/html/work/phppdf/fpdi/fpdi.php on line 88
應為使用PHP 5.3.X 版本,
導致new class function的時候出問題。(本文是在PHP 5.2.10測試),
此時請修改 fpdi.php 內的 '=& new' 改為 '= new'即可,
感謝David!


101.01.17 Update:
這幾天把PHP版本更新為5.3也發生這個問題,補充一下:
要把 =& new 改為 = new 有下列檔案:
  • fpdi.php
  • fpdi.pdf_parser.php
  • pdf_parser.php


===還有這個錯誤訊息===

Message: Function set_magic_quotes_runtime() is deprecated
Filename: chinese-unicode/chinese.php
請搜尋 set_magic_quotes_runtime( 取代為 ini_set("magic_quotes_runtime",

7 則留言:

  1. 應該不是字型的問題, 因為我做到FPDF的chinese-unicode的時候, 已經可以產生有unicode中文字的pdf了, 但是做到了FPDI的時候就發生了上面的錯誤訊息...

    請問您的文章中有一段:
    『改用FPDI與chinese-unicode.php結合!! 好像又露出一線生機

    但是!

    要修改chinese-unicode.php,我看不懂原始碼啦= =』
    說到了要修改chinese-unicode.php, 可是您沒有說到要改哪裡; 請問會是這裡的問題嗎?

    版主回覆:(12/01/2009 03:47:09 PM)


    這樣看起來是FPDI的問題,還是你要不要先拿掉CHINESE這兩個CLASS檔案,直接讓FPDI繼承FPDF_TPL,這樣看輸出有沒有問題(當然只能英文)。武說要修改chinese-unicode是在連結看到的,實際上是要修改chinese.php改繼承FPDF_TPL,讓它支援樣板匯入。
    這樣下去也不是辦法,我把程式壓給你跑跑看 如果還有錯的話....那...加油!
    http://www.badongo.com/cn/file/18764346

    回覆刪除
  2. 板主, 我其實一直懷疑是因為我的php版本是5.3; 所以導致new class function的時候出問題。所以我把原來fpdi內的=& new改為= new就ok了...

    感謝板主的協助!!

    版主回覆:(12/01/2009 04:34:29 PM)


    原來如此,沒考慮到php版本問題 我是在5.2.10測試的。

    回覆刪除
  3. 不好意思,我跟著你一步步做:改的以下地方繼承
    1.修改FPDI.php 從繼承FPDF_TPL改為PDF_Unicode (在chinese-unicode.php)
    2.修改chinese.php 把 require('fpdf.php') 注解掉 (我已經先引入還是會有問題,乾脆注掉)
    3.修改chinese.php 內 PDF_Chinese 類別從繼承FPDF改為繼承FPDF_TPL
    為什麼出來還是亂碼的?

    回覆刪除
  4. 問題解決的。但我遇到另一個問題,請問下,如果我匯入一個PDF模板,那麼我怎樣知道欄位的坐標啊?因為我要出個人資料,
    例如:姓名:王小文 出生日期:1999-9-10
    地址:香港 身份證號碼:99999999

    這些資料(王小文,1999-9-10,香港,9999999)都是讀取數據庫。請板主幫手怎么解決?

    版主回覆:(12/02/2009 05:24:32 AM)


    慢慢TRY....
    感覺是以字元為單位去猜,一張A4大概到兩百多

    回覆刪除
  5. 謝謝的。因為要填個人資料,所以有好多資料。不知道要試多少次。請問版主有沒有其他方法?

    版主回覆:(07/18/2011 10:43:27 AM)


    我是先用迴圈每隔5跑定位點,這樣要抓位置比較快
    如果是表格的資料的話,可以先抓最左上角的X Y 當初始點
    然後設定行距,這樣有幾行就在Y上加幾個行距
    如果資料是亂跑的,也只能慢慢抓定位點

    另外這個方法是不會自動換行的
    要換行請參考fpdf的MultiCell,但是不支援中文= =

    回覆刪除
  6. To RogerWong:
    我寫了一篇我的做法跟提供範例碼,參考看看
    http://asper.pixnet.net/blog/post/29484263

    回覆刪除
  7. 您太神了,這篇!!
    收獲很多QQ
    感謝~

    版主回覆:(07/19/2011 02:27:01 PM)


    有幫到忙就好,我花很多時間在TRY
    希望不要讓別人也浪費時間做一樣的事情就好

    回覆刪除