讓我們進入中文的處理過程吧。

原本看到 ReportLab 的 test 目錄下有一個 test_multibyte_chs.py ,試了試效果不錯,就以為中文問題照貓畫虎應該沒什麼問題呀。但等我再仔細深入後,發現問題不那麼簡單。

問題一:無法使用Paragraph。因示例中使用的是底層的API,因此對於字型要求不高。而使用Paragraph需要知道粗體、斜體、粗斜體這些字型,而示例中並沒有這樣的處理。

問題二:在解了上面的問題之後,發現中文只有一種字型,實現不了斜體和粗體效果。

現在我已經基本解決了上面的問題,但是無法實現斜體和粗斜體,這個以後再看一看吧。

中文處理方法一

這種方法採用示例中的方式,即使用CID字型,程式碼如下:

#coding=gbk
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.cidfonts import CIDFont, CIDTypeFace, findCMapFile
enc = ‘GB-EUC-H’
findCMapFile(enc)
face = CIDTypeFace(‘STSong-Light’)
pdfmetrics.registerTypeFace(face)
pdfmetrics.registerFont(CIDFont(‘STSong-Light’,enc))
from reportlab.lib import fonts
fonts.addMapping(‘STSong-Light’, 0, 0, ‘STSong-Light’)
fonts.addMapping(‘STSong-Light’, 0, 1, ‘STSong-Light’)
fonts.addMapping(‘STSong-Light’, 1, 0, ‘STSong-Light’)
fonts.addMapping(‘STSong-Light’, 1, 1, ‘STSong-Light’)

import copy

from reportlab.platypus import Paragraph, SimpleDocTemplate, PageBreak
from reportlab.lib.styles import getSampleStyleSheet
stylesheet=getSampleStyleSheet()
normalStyle = copy.deepcopy(stylesheet['Normal'])
normalStyle.fontName =’STSong-Light-GB-EUC-H’
normalStyle.fontSize = 20
story = []
story.append(Paragraph("<b>你好</b>,中文", normalStyle))
doc = SimpleDocTemplate(‘hello.pdf’)
doc.build(story)


使用CID字型只有STSong-Light一種字型可用,而我檢視資料看到其它的如Big5都有兩種字型,真是氣人。前面說到問題一,需要使用fonts.addMapping來解決,即分別註冊四種字形。addMapping共有四個引數,第一個是以後引用的字型名,第二個是粗體標誌,第三個是斜體標誌,第四個是對應的字型名稱。因此上面增加了四種字形。而所用到的字型應該呼叫pdfmetrics.registerFont()進行字型的註冊。而且在實際執行時發現,光註冊字型還不夠,還要註冊TypeFace。在所有字型註冊完畢後,下面可以真正中文的測試了。
normalStyle = copy.deepcopy(stylesheet['Normal']) 
normalStyle.fontName =’STSong-Light-GB-EUC-H’ 
normalStyle.fontSize = 20


這裡是設定段落將使用的字型名稱。很奇怪,字型名稱是前面註冊的字形名與編碼的合併。

執行上面的示例中文檔案就生成了。但如果加入英文,也是使用中文字元進行顯示的。注意,上面的檔案編碼設定為gbk

這種方法目前來說我認為並不好,那麼好在還有第二種方法。

中文處理的第二種方法

這種方法使用直接處理TrueType字型的方法,但在測試過程中速度有些慢。但好處是可以使用中文的字型檔案,當然需要是ttf格式的檔案。這樣可以引入更多的字型了。程式碼如下:

#coding=utf-8
import reportlab.rl_config
reportlab.rl_config.warnOnMissingFontGlyphs = 0
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfgen import canvas
pdfmetrics.registerFont(TTFont(’song’, ‘SURSONG.TTF’))
pdfmetrics.registerFont(TTFont(‘hei’, ‘SIMHEI.TTF’))

from reportlab.lib import fonts
fonts.addMapping(’song’, 0, 0, ’song’)
fonts.addMapping(’song’, 0, 1, ’song’)
fonts.addMapping(’song’, 1, 0, ‘hei’)
fonts.addMapping(’song’, 1, 1, ‘hei’)

import copy

from reportlab.platypus import Paragraph, SimpleDocTemplate, PageBreak
from reportlab.lib.styles import getSampleStyleSheet
stylesheet=getSampleStyleSheet()
normalStyle = copy.deepcopy(stylesheet['Normal'])
normalStyle.fontName =’song’
normalStyle.fontSize = 20
story = []
story.append(Paragraph(‘<b>你好</b>,中文’, normalStyle))
doc = SimpleDocTemplate(‘hello.pdf’)
doc.build(story)


處理方法與方法一差不多,主要差別在紅色的字部分。檔案編碼注意是utf-8,而不是gbk了。我是在執行時發現的,使用utf-8,然後直接使用中文就可以,不然就沒東西。字型還是要註冊,但不是使用CIDFont了,而是使用TTFont來處理了。而且不需要註冊TypeFace了。再註冊字形,這裡我對於粗體字形使用了黑體字。最後對於樣式使用字型時,只要使用簡單的字形名即可,不再象第一種方法還需要加入編碼名稱。

上面的處理可以解決正常和粗體的字形,但斜體還是無法支援,但已經好多了。而且好處是可以使用其它的中文字型比如仿宋了,彩雲體了。

不過在處理英文時還是存在問題。如果不加特殊處理英文會轉變為漢字,的確不好看。那麼你可以在段落中加入<font>標籤,設定name為想用的英文字型即可。與HTML的標籤差不多。但發現所有英文自動變成斜體了。不知道為什麼。現在知道一個解決的方法就是不修改樣式中的字型名,而是在文字中加入<font>標籤來設定中文字型,但這樣就比較麻煩。當然通過程式來做麻煩也不怕。比如:

normalStyle = copy.deepcopy(stylesheet['Normal'])
#normalStyle.fontName =’song’
normalStyle.fontSize = 20
story = []
story.append(Paragraph(‘<font name="hei">你好</font>,<font name="song">中文</font>’, normalStyle))
doc = SimpleDocTemplate(‘hello.pdf’)
doc.build(story)

大家有興趣可以試一試。

採用的第二種方法,測試成功,需要下載TTF檔案