JFreeChart 默認渲染中文標題、軸標籤、圖例時常出現字體模糊、鋸齒明顯、筆畫粘連,嚴重影響圖表專業度與可讀性。網上常見「修改字體」方案效果有限,本文提供關閉文字抗鋸齒 + 優化字體選擇的徹底解決方案。
默認渲染 (模糊)
僅換黑體 (略有改善)
關閉抗鋸齒 + 宋體 12-14pt (清晰銳利)
JFreeChart chart = ChartFactory.createPieChart3D(...); // 或其他圖表創建方式
// 核心:獲取 RenderingHints 並關閉文字抗鋸齒
chart.getRenderingHints().put(
RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF
);
// 推薦字體設置:12-14pt 宋體/微軟雅黑
Font labelFont = new Font("宋體", Font.PLAIN, 12); // 或 "微軟雅黑"
Font titleFont = new Font("宋體", Font.BOLD, 14);
// 應用到標題
chart.getTitle().setFont(titleFont);
// 應用到圖表區域 (以 PiePlot 為例)
Plot plot = chart.getPlot();
if (plot instanceof PiePlot) {
PiePlot piePlot = (PiePlot) plot;
piePlot.setLabelFont(labelFont);
piePlot.setLegendLabelFont(labelFont);
} else if (plot instanceof CategoryPlot) {
CategoryPlot catPlot = (CategoryPlot) plot;
catPlot.getDomainAxis().setLabelFont(labelFont);
catPlot.getDomainAxis().setTickLabelFont(labelFont);
catPlot.getRangeAxis().setLabelFont(labelFont);
catPlot.getRangeAxis().setTickLabelFont(labelFont);
catPlot.getRenderer().setDefaultEntityFont(labelFont);
}
| Key | Value 選項 | 效果 |
|---|---|---|
| KEY_TEXT_ANTIALIASING | VALUE_TEXT_ANTIALIAS_ON (默認) | 啟用抗鋸齒,邊緣平滑但中文筆畫易模糊 |
| VALUE_TEXT_ANTIALIAS_OFF | 關閉抗鋸齒,像素級銳利,中文筆畫清晰分離 | |
| VALUE_TEXT_ANTIALIAS_DEFAULT | 由平台決定 | |
| KEY_ANTIALIASING | VALUE_ANTIALIAS_ON/OFF | 控制圖形(線條/形狀)抗鋸齒,不影響文字 |
| KEY_RENDERING | VALUE_RENDER_QUALITY/SPEED | 渲染質量/速度權衡 |
英文、數字、簡單符號建議開啟抗鋸齒,圓弧、斜線會更平滑。可考慮混合策略:
// 僅對中文標籤關閉抗鋸齒 (需自定義繪製邏輯)
// 或者全局關閉,英文接受輕微鋸齒換取中文清晰
public class ChartUtils {
// 推薦字體常量
public static final Font CHINESE_FONT_12 = new Font("宋體", Font.PLAIN, 12);
public static final Font CHINESE_FONT_14_BOLD = new Font("微軟雅黑", Font.BOLD, 14);
public static final Font CHINESE_FONT_14 = new Font("微軟雅黑", Font.PLAIN, 14);
// 統一配置圖表渲染提示
public static void applyChineseOptimization(JFreeChart chart) {
// 1. 關閉文字抗鋸齒
chart.getRenderingHints().put(
RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF
);
// 2. 保持圖形抗鋸齒 (線條圓滑)
chart.getRenderingHints().put(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON
);
// 3. 設置標題字體
chart.getTitle().setFont(CHINESE_FONT_14_BOLD);
// 4. 根據圖表類型配置軸/標籤/圖例字體
Plot plot = chart.getPlot();
configurePlotFonts(plot);
}
private static void configurePlotFonts(Plot plot) {
if (plot instanceof PiePlot) {
PiePlot p = (PiePlot) plot;
p.setLabelFont(CHINESE_FONT_12);
p.setLegendLabelFont(CHINESE_FONT_12);
} else if (plot instanceof CategoryPlot) {
CategoryPlot p = (CategoryPlot) plot;
Font f = CHINESE_FONT_12;
p.getDomainAxis().setLabelFont(f);
p.getDomainAxis().setTickLabelFont(f);
p.getRangeAxis().setLabelFont(f);
p.getRangeAxis().setTickLabelFont(f);
p.getRenderer().setDefaultEntityFont(f);
} else if (plot instanceof XYPlot) {
XYPlot p = (XYPlot) plot;
Font f = CHINESE_FONT_12;
p.getDomainAxis().setLabelFont(f);
p.getDomainAxis().setTickLabelFont(f);
p.getRangeAxis().setLabelFont(f);
p.getRangeAxis().setTickLabelFont(f);
}
// 遞歸處理子圖 (CombinedDomainXYPlot 等)
if (plot instanceof CombinedDomainXYPlot) {
for (Plot subplot : ((CombinedDomainXYPlot) plot).getSubplots()) {
configurePlotFonts(subplot);
}
}
}
}
// 生成高 DPI 圖片
int width = 800, height = 600;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = image.createGraphics();
// 設置高質量渲染
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 圖形抗鋸齒
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); // 文字不抗鋸齒
g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); // 字體微調
chart.draw(g2, new Rectangle2D.Double(0, 0, width, height));
ImageIO.write(image, "PNG", new File("chart_hq.png"));
// 使用 Batik 輸出 SVG (無限縮放不模糊)
SVGGraphics2D svgGenerator = new SVGGraphics2D(width, height);
chart.draw(svgGenerator, new Rectangle2D.Double(0, 0, width, height));
svgGenerator.stream(new FileOutputStream("chart.svg"), true);
// 或使用 iText + JFreeChart 輸出 PDF
// 檢查字體可用性,提供回退
public static Font getAvailableChineseFont(int size, boolean bold) {
String[] candidates = {"微軟雅黑", "宋體", "SimSun", "PingFang SC", "Heiti TC", "Noto Sans CJK SC"};
int style = bold ? Font.BOLD : Font.PLAIN;
for (String name : candidates) {
Font font = new Font(name, style, size);
if (font.canDisplay('中') && font.canDisplay('文')) {
return font;
}
}
return new Font(Font.DIALOG, style, size); // 最後回退
}
| 誤區 | 正確做法 |
|---|---|
| 只換字體不關抗鋸齒 | 必須設置 KEY_TEXT_ANTIALIASING = OFF |
| 全局關閉所有抗鋸齒 | 保持 KEY_ANTIALIASING = ON 讓線條圓滑 |
| 字號過大 (16pt+) | 中文小字號 (12-14pt) 關抗鋸齒效果最佳 |
| 使用無襯線字體顯示數字/英文 | 數字/英文建議用等寬字體 (Consolas/Monospaced) 且開啟抗鋸齒 |
| 忽略圖例/工具提示字體 | 統一設置 setLegendLabelFont、setToolTipFont |
JFreeChart 中文模糊的根因是默認文字抗鋸齒算法不適合中文筆畫特點。通過 RenderingHints.KEY_TEXT_ANTIALIASING = VALUE_TEXT_ANTIALIAS_OFF 關閉文字抗鋸齒,配合 12-14pt 宋體/微軟雅黑,可獲得銳利清晰的中文渲染效果。對於高質量輸出需求,建議採用 SVG/PDF 矢量格式 徹底解決分辨率依賴問題。掌握 RenderingHints 微調技巧,是製作專業級 Java 圖表的必備技能。