星期三, 3月 21, 2007

JasperReports中使用標楷體字型與變體字型(粗體, 斜體)研究...

在使用JasperReports產生的報表中, 使用者要求使用標楷體字型, 且有些欄位必須使用斜體.
於是做了以下的研究...

在jrxml設計檔內, 設定要使用標楷體之字型.

<font fontName="標楷體" pdfFontName="kaiu.ttf" size="14" pdfEncoding ="Identity-H"/>


若是使用 iReport 設計時, 先將 kaiu.ttf 放入 classpath 中, 再啟動 iReport, 並在字型頁將 fontName 與 pdfFontName 設為標楷體, 且將pdfEncoding 設為 Identity-H.

JasperReports 提供很多的 API, 可以用很多種方式來產生 PDF.
例如使用下列的程式來產生PDF(必須將 kaiu.ttf 放入 classpath 中):

InputStream is = FontReport.class.getResourceAsStream("font.jasper");
JasperRunManager.runReportToPdfFile("font.jasper", "font.pdf", new HashMap(), new JREmptyDataSource());

如此產生之 PDF 即可看到標楷體.
不過, 當我們設定要產生斜體, 粗體, 斜粗體時, 會發現通通沒有效.都以一般字體顯示.

追蹤了 JasperReports1.2.7 的程式碼中, 發現在 net.sf.jasperreports.engine.export.JRPdfExporter.java 程式的1340~1351行中有以下幾行:

Font font = null;
PdfFont pdfFont = null;
FontKey key = new FontKey(jrFont.getFontName(), jrFont.isBold(), jrFont.isItalic());
if (fontMap != null && fontMap.containsKey(key))
{
pdfFont = (PdfFont) fontMap.get(key);
}
else
{
pdfFont = new PdfFont(jrFont.getPdfFontName(), jrFont.getPdfEncoding(), jrFont.isPdfEmbedded());
}

以上程式 1350 行可以看到在產生 pdfFont 的時後, 並沒有把斜體與粗體的資訊傳入, 導致後面產生字型的程式碼得不到粗體與斜體的資訊. 於是, 我們可以將 1350 修改如下(多傳入兩個參數):

pdfFont = new PdfFont(jrFont.getPdfFontName(), jrFont.getPdfEncoding(), jrFont.isPdfEmbedded(), jrFont.isBold(), jrFont.isItalic());

重新打包 JasperReports 之後, 再次執行產生 PDF 的程式, 就如我們所預期的, 可以印出正常,粗體,斜體,粗斜體的標楷體字型了.

若不想去修改 JasperReports 的程式碼的話, 那又該怎麼做呢?
仔細看到上述 JasperReports 的程式碼, 其會先去看 fontMap 是否有該字型, 若有該字型則直接使用(即讓1344行條件成立).

所以我們可以改成如下..
在jrxml設計檔內, 設定要使用標楷體之字型.

<font fontName="標楷體B" pdfFontName="kaiu.ttf" size="14" isBold="true" pdfEncoding ="Identity-H"/>

上面我們以粗體為例, 給一個虛設的 fontName, "標楷體B".
接著我們要在程式中, 告訴 JasperReports, "標楷體B" 真正對應到的字型, 如下:
 
InputStream is = FontReport.class.getResourceAsStream("font.jasper");
JasperPrint jasperPrint = JasperFillManager.fillReport(is, new HashMap(), new JREmptyDataSource());
JRPdfExporter exporter = new JRPdfExporter();
Map fontsMap = new HashMap();
fontsMap.put(new FontKey("標楷體B", true, false), new PdfFont("kaiu.ttf", "Identity-H", false, true, false));
exporter.setParameter(JRExporterParameter.FONT_MAP, fontsMap);
exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
FileOutputStream fos = new FileOutputStream("font.pdf");
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, fos);
exporter.exportReport();

如此也能在不改 JasperReports 的情況下, 達到產生標楷體粗體的字型(其餘的依此類推)...
不過用此方法, 並不能用 iReport 編譯 jasper 檔(否則也會沒有效果),
我都是額外使用程式來編譯成 jasper 檔.

用使用第一種改 JasperReports 程式碼的做法時, 有些地方要注意的是,
英文字型通常都會提供這些變體字的字型檔. 而中文字型因為太大,
所以必須用模擬的方式來處理.
而使用 iReport 時, 若選粗體, 則 iReport 會將 pdf font name 改為粗體的字型,
如 pdf font name: Helvetica, 再勾選粗體時會變成 Helvetica-Bold
即使用的字型檔已經有粗體的效果, 再加上模擬的效果, 會讓結果更加的粗.
所以需要將 pdf font name 手動改回 Helvetica, 一律使用非粗體的字型, 讓程式去模擬粗體.

或是將 isBold="true" 改成 isBold="false", pdf font name 維持 "Helvetica-Bold".
不過若是使用此方式, 則轉成其他格式時, 如 html, 粗體就會不見了...

不知各位先進有沒有更好的處理方法可供參考?


0 Comments:

張貼留言

<< Home