You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何获取PDPage/PDDocument的DPI以精准计算PDF页面尺寸?

获取PDF各页面尺寸与DPI(PDFBox实现)

首先得明确一个关键知识点:PDF页面本身并没有内置的DPI属性——PDF是矢量优先的格式,页面尺寸用用户单位定义(默认1用户单位 = 1/72英寸),DPI更多是和"将PDF渲染为像素图像"或者"页面内的光栅图像"相关的概念。下面分两部分帮你完善代码:

一、完善页面尺寸获取(支持mm转换)

你已经用MediaBox拿到了页面的宽高(用户单位),可以直接转换成毫米(1英寸=25.4毫米,1用户单位=1/72英寸)。先把这部分代码补全:

public static ArrayList<float[]> getDimensionsAndDpi(PDDocument document) {
    ArrayList<float[]> dimensions = new ArrayList<>();
    // 单位转换系数:1用户单位 = (25.4 / 72) 毫米
    final float USER_UNIT_TO_MM = 25.4f / 72f;

    for (int i = 0; i < document.getNumberOfPages(); i++) {
        PDPage currentPage = document.getPage(i);
        PDRectangle mediaBox = currentPage.getMediaBox();
        if (mediaBox == null) {
            // 极端情况:页面没有MediaBox,用默认A4尺寸兜底
            mediaBox = PDRectangle.A4;
        }
        
        // 获取用户单位下的宽高
        float widthUserUnit = mediaBox.getWidth();
        float heightUserUnit = mediaBox.getHeight();
        
        // 转换为毫米
        float widthMm = widthUserUnit * USER_UNIT_TO_MM;
        float heightMm = heightUserUnit * USER_UNIT_TO_MM;

        // 存储页面数据:宽(mm), 高(mm), 渲染目标DPI, 页面内嵌图像平均DPI
        float[] pageData = new float[4]; 
        pageData[0] = widthMm;
        pageData[1] = heightMm;

        // --- 处理DPI相关逻辑 ---
        // 1. 渲染时的目标DPI(如果是要转图片,这个是你主动设定的参数)
        float targetRenderDpi = 300f; // 示例值,可根据需求调整
        pageData[2] = targetRenderDpi;

        // 2. 提取页面内光栅图像的实际DPI(如果页面包含图片)
        float avgImageDpi = getAverageImageDpi(currentPage);
        pageData[3] = avgImageDpi;

        dimensions.add(pageData);
    }
    return dimensions;
}

二、处理DPI的两种场景

场景1:计算渲染为像素图像时的DPI

如果你是要把PDF页面转换成位图,DPI是你主动设定的参数,用来计算输出图像的像素尺寸:

像素宽度 = (页面宽度用户单位 / 72) * DPI
像素高度 = (页面高度用户单位 / 72) * DPI

比如300DPI下,A4页面(595x842用户单位)的像素尺寸约为2480×3508px。

场景2:提取页面内光栅图像的DPI

如果页面包含光栅图像,这些图像有自己的DPI(图像分辨率),可以遍历页面内的图像资源计算:

private static float getAverageImageDpi(PDPage page) {
    List<PDImageXObject> images = new ArrayList<>();
    try {
        // 遍历页面内的所有图像资源
        page.getResources().getXObjectNames().forEach(name -> {
            try {
                PDXObject xobj = page.getResources().getXObject(name);
                if (xobj instanceof PDImageXObject) {
                    images.add((PDImageXObject) xobj);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    } catch (IOException e) {
        e.printStackTrace();
    }

    if (images.isEmpty()) {
        return 0f; // 页面无内嵌图像,返回0
    }

    // 计算所有图像的平均DPI
    float totalDpi = 0f;
    for (PDImageXObject img : images) {
        // 图像像素尺寸 / (页面显示尺寸用户单位 / 72) = DPI
        float imageWidthPx = img.getWidth();
        float imageHeightPx = img.getHeight();
        
        // 获取图像在页面上的缩放比例
        PDMatrix matrix = img.getMatrix();
        float displayWidthUserUnit = matrix.getScalingFactorX();
        float displayHeightUserUnit = matrix.getScalingFactorY();

        // 取宽高方向DPI的平均值
        float dpiX = (imageWidthPx / displayWidthUserUnit) * 72f;
        float dpiY = (imageHeightPx / displayHeightUserUnit) * 72f;
        totalDpi += (dpiX + dpiY) / 2f;
    }

    return totalDpi / images.size();
}

补充说明

  • 若要获取页面的可见区域尺寸,可将MediaBox替换为currentPage.getCropBox()
  • PDF的用户单位默认比例是1/72英寸,这是PDF规范明确规定的,可放心用于单位转换。
  • 页面本身没有全局DPI,只有当涉及渲染或内嵌图像时,DPI才有实际参考价值。

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

火山引擎 最新活动