pdfbox 和 itext 以不正确的 dpi 提取图像
pdfbox and itext extracting image with incorrect dpi
当我使用 pdfbox 提取图像时,某些 PDF 的图像 dpi 不正确。当我使用 Photoshop 或 Acrobat Reader Pro 提取图像时,使用 windows 照片查看器可以看到图像的 dpi 是 200,但是当我使用 pdfbox 提取图像时,dpi 是 72。
为了提取图像,我使用以下代码:
当我检查日志时,我看到一个不寻常的条目:
2015-01-23-main--DEBUG-org.apache.pdfbox.util.TIFFUtil:
<?xml version="1.0" encoding="UTF-8"?><javax_imageio_jpeg_image_1.0>
<JPEGvariety>
<app0JFIF majorVersion="1" minorVersion="2" resUnits="0" Xdensity="1" Ydensity="1" thumbWidth="0" thumbHeight="0"/>
</JPEGvariety>
<markerSequence>
<dqt>
<dqtable elementPrecision="0" qtableId="0"/>
<dqtable elementPrecision="0" qtableId="1"/>
</dqt>
<dht>
<dhtable class="0" htableId="0"/>
<dhtable class="0" htableId="1"/>
<dhtable class="1" htableId="0"/>
<dhtable class="1" htableId="1"/>
</dht>
<sof process="0" samplePrecision="8" numLines="0" samplesPerLine="0" numFrameComponents="3">
<componentSpec componentId="1" HsamplingFactor="2" VsamplingFactor="2" QtableSelector="0"/>
<componentSpec componentId="2" HsamplingFactor="1" VsamplingFactor="1" QtableSelector="1"/>
<componentSpec componentId="3" HsamplingFactor="1" VsamplingFactor="1" QtableSelector="1"/>
</sof>
<sos numScanComponents="3" startSpectralSelection="0" endSpectralSelection="63" approxHigh="0" approxLow="0">
<scanComponentSpec componentSelector="1" dcHuffTable="0" acHuffTable="0"/>
<scanComponentSpec componentSelector="2" dcHuffTable="1" acHuffTable="1"/>
<scanComponentSpec componentSelector="3" dcHuffTable="1" acHuffTable="1"/>
</sos>
</markerSequence>
</javax_imageio_jpeg_image_1.0>
我尝试 google 但我可以通过此日志找出 pdfbox 的含义。这是什么意思?
您可以从这个 link 下载关于这个问题的示例 pdf:
http://myslams.com/test/1.pdf
我什至尝试过 itext,但它正在以 96 dpi 提取图像。
我做错了什么吗?或者pdfbox和itext有这个限制?
经过一番挖掘,我找到了你的 1.pdf。因此,...
PDFBox
在 @Tilman and you were discussing this older answer in which @Tilman pointed towards the PrintImageLocations PDFBox 示例的注释中。我 运行 它为您的文件并得到:
Processing page: 0
*******************************************************************
Found image [Im0]
position = 0.0, 0.0
size = 1704px, 888px
size = 613.44, 319.68
size = 8.52in, 4.44in
size = 216.408mm, 112.776mm
Processing page: 1
*******************************************************************
Found image [Im0]
position = 0.0, 0.0
size = 1704px, 2800px
size = 613.44, 1008.0
size = 8.52in, 14.0in
size = 216.408mm, 355.6mm
Processing page: 2
*******************************************************************
Found image [Im0]
position = 0.0, 0.0
size = 1704px, 2800px
size = 613.44, 1008.0
size = 8.52in, 14.0in
size = 216.408mm, 355.6mm
Processing page: 3
*******************************************************************
Found image [Im0]
position = 0.0, 0.0
size = 1704px, 1464px
size = 613.44, 527.04
size = 8.52in, 7.3199997in
size = 216.408mm, 185.928mm
在所有页面上,这在 x 和 y 方向上均为 200 dpi (1704px / 8.52in = 888px / 4.44in = 2800px / 14.0in = 1464px / 7.32in = 200 dpi)。
因此 PDFBox 会为您提供所需的 dpi 值。
(@Tilman:该示例的当前 2.0.0-SNAPSHOT 版本 returns 完全是胡说八道;您可能需要解决这个问题。)
iText
该 PDFBox 示例的简化 iText 版本如下:
public void printImageLocations(InputStream stream) throws IOException
{
PdfReader reader = new PdfReader(stream);
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
ImageRenderListener listener = new ImageRenderListener();
for (int page = 1; page <= reader.getNumberOfPages(); page++)
{
System.out.printf("\nPage %s:\n", page);
parser.processContent(page, listener);
}
}
static class ImageRenderListener implements RenderListener
{
public void beginTextBlock() { }
public void renderText(TextRenderInfo renderInfo) { }
public void endTextBlock() { }
public void renderImage(ImageRenderInfo renderInfo)
{
try
{
PdfDictionary imageDict = renderInfo.getImage().getDictionary();
float widthPx = imageDict.getAsNumber(PdfName.WIDTH).floatValue();
float heightPx = imageDict.getAsNumber(PdfName.HEIGHT).floatValue();
float widthUu = renderInfo.getImageCTM().get(Matrix.I11);
float heigthUu = renderInfo.getImageCTM().get(Matrix.I22);
System.out.printf("Image %.0fpx*%.0fpx, %.0fuu*%.0fuu, %.2fin*%.2fin\n", widthPx, heightPx, widthUu, heigthUu, widthUu/72, heigthUu/72);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
(注意:我假设图像没有旋转和倾斜。)
您的文件的结果:
Page 1:
Image 1704px*888px, 613uu*320uu, 8,52in*4,44in
Page 2:
Image 1704px*2800px, 613uu*1008uu, 8,52in*14,00in
Page 3:
Image 1704px*2800px, 613uu*1008uu, 8,52in*14,00in
Page 4:
Image 1704px*1464px, 613uu*527uu, 8,52in*7,32in
所以一直都是200dpi。所以 iText 也为您提供了您所追求的 dpi 值。
您的代码
显然 没有机会报告在 PDF 上下文中合理的 dpi 值,因为它只提取 资源中找到的图像 但忽略了如何在页面上使用相应的图像资源。
图像资源可以拉伸、旋转、倾斜……作者在页面内容中使用它时喜欢的任何方式。
顺便说一句,只有在作者没有倾斜并且仅旋转 90° 的倍数时,dpi 值才有意义。
当我使用 pdfbox 提取图像时,某些 PDF 的图像 dpi 不正确。当我使用 Photoshop 或 Acrobat Reader Pro 提取图像时,使用 windows 照片查看器可以看到图像的 dpi 是 200,但是当我使用 pdfbox 提取图像时,dpi 是 72。
为了提取图像,我使用以下代码:
当我检查日志时,我看到一个不寻常的条目: 2015-01-23-main--DEBUG-org.apache.pdfbox.util.TIFFUtil:
<?xml version="1.0" encoding="UTF-8"?><javax_imageio_jpeg_image_1.0> <JPEGvariety> <app0JFIF majorVersion="1" minorVersion="2" resUnits="0" Xdensity="1" Ydensity="1" thumbWidth="0" thumbHeight="0"/> </JPEGvariety> <markerSequence> <dqt> <dqtable elementPrecision="0" qtableId="0"/> <dqtable elementPrecision="0" qtableId="1"/> </dqt> <dht> <dhtable class="0" htableId="0"/> <dhtable class="0" htableId="1"/> <dhtable class="1" htableId="0"/> <dhtable class="1" htableId="1"/> </dht> <sof process="0" samplePrecision="8" numLines="0" samplesPerLine="0" numFrameComponents="3"> <componentSpec componentId="1" HsamplingFactor="2" VsamplingFactor="2" QtableSelector="0"/> <componentSpec componentId="2" HsamplingFactor="1" VsamplingFactor="1" QtableSelector="1"/> <componentSpec componentId="3" HsamplingFactor="1" VsamplingFactor="1" QtableSelector="1"/> </sof> <sos numScanComponents="3" startSpectralSelection="0" endSpectralSelection="63" approxHigh="0" approxLow="0"> <scanComponentSpec componentSelector="1" dcHuffTable="0" acHuffTable="0"/> <scanComponentSpec componentSelector="2" dcHuffTable="1" acHuffTable="1"/> <scanComponentSpec componentSelector="3" dcHuffTable="1" acHuffTable="1"/> </sos> </markerSequence> </javax_imageio_jpeg_image_1.0>
我尝试 google 但我可以通过此日志找出 pdfbox 的含义。这是什么意思?
您可以从这个 link 下载关于这个问题的示例 pdf: http://myslams.com/test/1.pdf
我什至尝试过 itext,但它正在以 96 dpi 提取图像。
我做错了什么吗?或者pdfbox和itext有这个限制?
经过一番挖掘,我找到了你的 1.pdf。因此,...
PDFBox
在
Processing page: 0
*******************************************************************
Found image [Im0]
position = 0.0, 0.0
size = 1704px, 888px
size = 613.44, 319.68
size = 8.52in, 4.44in
size = 216.408mm, 112.776mm
Processing page: 1
*******************************************************************
Found image [Im0]
position = 0.0, 0.0
size = 1704px, 2800px
size = 613.44, 1008.0
size = 8.52in, 14.0in
size = 216.408mm, 355.6mm
Processing page: 2
*******************************************************************
Found image [Im0]
position = 0.0, 0.0
size = 1704px, 2800px
size = 613.44, 1008.0
size = 8.52in, 14.0in
size = 216.408mm, 355.6mm
Processing page: 3
*******************************************************************
Found image [Im0]
position = 0.0, 0.0
size = 1704px, 1464px
size = 613.44, 527.04
size = 8.52in, 7.3199997in
size = 216.408mm, 185.928mm
在所有页面上,这在 x 和 y 方向上均为 200 dpi (1704px / 8.52in = 888px / 4.44in = 2800px / 14.0in = 1464px / 7.32in = 200 dpi)。
因此 PDFBox 会为您提供所需的 dpi 值。
(@Tilman:该示例的当前 2.0.0-SNAPSHOT 版本 returns 完全是胡说八道;您可能需要解决这个问题。)
iText
该 PDFBox 示例的简化 iText 版本如下:
public void printImageLocations(InputStream stream) throws IOException
{
PdfReader reader = new PdfReader(stream);
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
ImageRenderListener listener = new ImageRenderListener();
for (int page = 1; page <= reader.getNumberOfPages(); page++)
{
System.out.printf("\nPage %s:\n", page);
parser.processContent(page, listener);
}
}
static class ImageRenderListener implements RenderListener
{
public void beginTextBlock() { }
public void renderText(TextRenderInfo renderInfo) { }
public void endTextBlock() { }
public void renderImage(ImageRenderInfo renderInfo)
{
try
{
PdfDictionary imageDict = renderInfo.getImage().getDictionary();
float widthPx = imageDict.getAsNumber(PdfName.WIDTH).floatValue();
float heightPx = imageDict.getAsNumber(PdfName.HEIGHT).floatValue();
float widthUu = renderInfo.getImageCTM().get(Matrix.I11);
float heigthUu = renderInfo.getImageCTM().get(Matrix.I22);
System.out.printf("Image %.0fpx*%.0fpx, %.0fuu*%.0fuu, %.2fin*%.2fin\n", widthPx, heightPx, widthUu, heigthUu, widthUu/72, heigthUu/72);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
(注意:我假设图像没有旋转和倾斜。)
您的文件的结果:
Page 1:
Image 1704px*888px, 613uu*320uu, 8,52in*4,44in
Page 2:
Image 1704px*2800px, 613uu*1008uu, 8,52in*14,00in
Page 3:
Image 1704px*2800px, 613uu*1008uu, 8,52in*14,00in
Page 4:
Image 1704px*1464px, 613uu*527uu, 8,52in*7,32in
所以一直都是200dpi。所以 iText 也为您提供了您所追求的 dpi 值。
您的代码
显然
图像资源可以拉伸、旋转、倾斜……作者在页面内容中使用它时喜欢的任何方式。
顺便说一句,只有在作者没有倾斜并且仅旋转 90° 的倍数时,dpi 值才有意义。