You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Apache PDFBox时如何将提取的字形居中放置到目标图像中

Apache PDFBox 字形提取居中问题修复

问题根因

你代码里字形垂直居中失效的核心原因有两个:

  • 垂直偏移硬编码了-50的固定值,不同字形的升部、降部、实际边界高度差异极大,固定偏移不可能适配所有字形
  • 坐标系变换顺序混乱,计算偏移时没有考虑Y轴翻转、缩放系数对坐标的影响,也没有处理字形边界bounds2D的Y轴最小值不为0的情况——很多字形的路径会延伸到Y=0坐标以下(比如g、y这类带下伸部分的字符),不做适配必然出现偏移。

修复代码

直接替换原有renderGlyph方法即可,核心调整:自动计算适配画布的缩放比例,预留内边距避免字形贴边,按正确坐标系顺序计算偏移,无任何硬编码偏移值,所有字形均可自动居中:

private static BufferedImage renderGlyph(GeneralPath path, Rectangle2D bounds2D, int imageWidth, int imageHeight) {
    BufferedImage bim = new BufferedImage(
            imageWidth,
            imageHeight,
            BufferedImage.TYPE_INT_RGB);

    Graphics2D g = (Graphics2D) bim.getGraphics();
    g.setBackground(Color.WHITE);
    g.clearRect(0, 0, bim.getWidth(), bim.getHeight());
    
    // 预留20px内边距,防止字形边缘贴到画布边框
    int padding = 20;
    double availableWidth = imageWidth - padding * 2;
    double availableHeight = imageHeight - padding * 2;

    // 自动计算缩放比,保证字形完整落在可用区域内,替代原固定0.5的缩放值
    double scaleX = availableWidth / bounds2D.getWidth();
    double scaleY = availableHeight / bounds2D.getHeight();
    double scale = Math.min(scaleX, scaleY);

    // 计算缩放后的字形实际尺寸
    double scaledGlyphWidth = bounds2D.getWidth() * scale;
    double scaledGlyphHeight = bounds2D.getHeight() * scale;

    // 计算居中所需的水平、垂直偏移,自动适配字形边界的负Y坐标
    double offsetX = (imageWidth - scaledGlyphWidth) / 2 - bounds2D.getMinX() * scale;
    double offsetY = (imageHeight - scaledGlyphHeight) / 2 + bounds2D.getMinY() * scale;

    // 按正确顺序应用变换:先平移到居中位置,再缩放,最后翻转Y轴(PDF坐标系Y轴向上,AWT画布坐标系Y轴向下)
    g.translate(offsetX, imageHeight - offsetY);
    g.scale(scale, -scale);

    // 配置渲染参数绘制字形
    g.setColor(Color.BLACK);
    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
    g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g.fill(path);
    g.dispose();
    return bim;
}

其他需要修正的问题

你原有代码还有两个会影响运行的bug:

  • 字符串相等判断用了==,Java中字符串值比较必须用equals方法,否则跳过.notdef、space这类字形的逻辑会失效,把对应判断替换为:
if("None".equals(glyphName) || ".notdef".equals(glyphName) || "space".equals(glyphName)){
    continue;
}
  • 代码中重复导入了PDType1CFont类,且引用了不存在的fontPane、fontpane包,如果使用官方发行版的PDFBox依赖,需要把对应类的包路径修正为org.apache.pdfbox.pdmodel.font下的官方路径。

内容的提问来源于stack exchange,提问作者gholamrezaeiPT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 20:09:11