如何获取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




