問題:
使用Adobe Reader將一份pdf文件通過我的虛擬打印機輸出后(輸出的是中間文件,等同於EMF文件),查看的時候發現有時候是亂碼。最簡單的必現步驟:
1、使用Adobe Reader打開pdf文件,選擇我的虛擬打印機打印(取消掉adobe打印高級選項中“作為圖像打印”),生成中間文件。
2、此時可以通過工具查看這個中間文件(EMF),發現並沒有亂碼。
3、關閉剛才打印的Adobe Reader打開的Pdf文件,再次查看中間文件,這時候就亂碼了。
分析:
根據上面的必現步驟,再測試使用FoxitReader、JisuPdf打開pdf文件然后選擇我的虛擬打印機打印,都沒有復現。此外,生成中間文件后,即使重新用Adobe Reader打開pdf,查看中間文件的時候,仍然是亂碼。
根據上述現象,去對比使用JisuPdf和Adobe Reader執行打印后生成的中間文件的區別,發現存在比較大的區別。猜測Adobe Reader在打印輸出的時候為不存在的字體創建了臨時字體文件,所以Adobe Reader在沒關閉的時候查看不會亂碼,一旦關閉了就刪掉了臨時文件,所以就亂碼了。
比如我第一次輸出的是中文文件A,不關閉Adobe Reader,查看A正常。關閉Adobe Reader查看A亂碼,再次打開Adobe Reader並打印出B,查看A亂碼,B不亂碼。由此說明,創建的這個臨時字體文件,還是和對應的中間文件相關聯的,並不是所有的都一樣。
我分別比較上述A和B文件內容上的區別,發現其中一個區別就是EMR_EXTCREATEFONTINDIRECTW結構中的字段不一樣,而且有個比較明顯的字段內容lfFaceName不一樣。
查看MSDN上對EMR_EXTCREATEFONTINDIRECTW的介紹,基本可以確定就是Adobe Reader在打印輸出這個pdf文件的時候創建了臨時字體文件,所以一旦Adobe Reader進程關閉了,就會刪除臨時字體文件導致中間文件亂碼。這也說明了為什么直接輸出到打印機時不會,而通過我的虛擬打印機輸出中間文件,如果在同一台機器上不關閉Adobe Reader進程時將中間文件輸出到真實打印機不會亂碼,而在另一台機器上輸出會亂碼。
為了確認這個問題,我使用JisuPdf和FoxitReader再分別打印出中間文件C和D。用A和C、A和D比較,發現C和D中都不存在EXTCREATEFONTINDIRECTW這個記錄,由此證明以上結論。
也就是說,我這個pdf文件中使用了非內嵌並且系統尚未安裝的字體,pdf閱讀器在打開的時候使用了相關的字體去替換顯示。
進一步分析:
現在問題轉變成,為什么Adobe Reader在打印時會調用CreateFontIndirect(生成EXTCREATEFONTINDIRECTW記錄),而JisuPdf和FoxitReader卻不會?
另外如果生成的EMF中有EXTCREATEFONTINDIRECTW記錄,如何根據這個記錄創建好需要的字體從而不亂碼顯示呢?
經過自己解析EMF中的記錄進行繪制,發現是可以通過調用CreateFontIndirect函數去實現這條EXTCREATEFONTINDIRECTW記錄的,但是仍然是亂碼,也就是說無法找到實際能與之匹配上的字體。
解決方案:
問題拖了比較久,最終也沒找到好的解決方案,目前采用的辦法是對於這種情況,要么直接使用勾選上adobe reader的矢量圖打印(這種方式比較萬能,原理是將每頁文檔都轉變成一張圖片,相應的占據的空間也大,並且慢很多),要么就干脆換一個pdf閱讀器,比如國產的foxit。