pdfbox快照2.0中PDFTextStripper的等价物是什么
What is the equivalent of PDFTextStripper in pdfbox snapshot 2.0
我目前正在使用 pdfbox 1.8 来分析 PDF 文档。下面是我正在做的一个非常精简的例子。
import java.util.List;
import java.io.IOException;
import javax.swing.JFileChooser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDStream;
public class Main
{
private static PDDocument reader;
public static void main(String[] args)
{
JFileChooser chooser = new JFileChooser();
int result = chooser.showOpenDialog(null);
if(result == JFileChooser.APPROVE_OPTION)
{
try
{
reader = PDDocument.load(chooser.getSelectedFile());
for(int pagenum = 1; pagenum <= reader.getNumberOfPages(); pagenum++)
{
System.out.println("===== Page:" + pagenum + " ======");
System.out.println(extract(pagenum));
}
}
catch(Exception e) { e.printStackTrace(); }
}
}
public static String extract(int pagenum) throws IOException
{
List allPages = reader.getDocumentCatalog().getAllPages();
PDPage page = (PDPage) allPages.get(pagenum-1);
PDStream contents = page.getContents();
CustomPDFTextStripper stripper = new CustomPDFTextStripper();
if (contents != null)
{
stripper.processStream(page, page.findResources(), page.getContents().getStream());
}
return stripper.getContents();
}
}
和
import org.apache.pdfbox.util.PDFTextStripper;
import java.io.IOException;
import org.apache.pdfbox.util.TextPosition;
public class CustomPDFTextStripper extends PDFTextStripper
{
private final StringBuilder builder;
private float lastBase;
public CustomPDFTextStripper() throws IOException
{
super.setSortByPosition(true);
builder = new StringBuilder();
lastBase = Float.MAX_VALUE;
}
public String getContents() { return builder.toString(); }
@Override
protected void processTextPosition(TextPosition textPos)
{
float ascent = textPos.getY();
if(ascent > lastBase)
builder.append("\n");
lastBase = textPos.getY() + textPos.getHeight();
builder.append(textPos.getCharacter());
// I want to be able to do stuff here and
// I need to read spaces and newline characters
}
}
我似乎无法在 pdfbox 2.0 快照中找到等效的解决方案(我知道它不稳定并且尚未发布)。我尝试使用类似的东西:
CustomPDFTextStripper stripper = new CustomPDFTextStripper();
StringWriter dummy = new StringWriter();
stripper.setPageStart(""+(pagenum-1));
stripper.setPageEnd(""+(pagenum-1));
stripper.writeText(reader, dummy);
但它不处理空格或在 processTextPostion 方法中给出准确的 textPos 数据。
关于如何在 2.0 中获得与 1.8 相同的所有 TextPostion 数据有什么想法吗?
========== 编辑 26JUN2015 8:00 PM CST ===========
好的,我有时间看了一下,发现了问题所在。 getWidthOfSpace() returns 1.8 和 2.0 之间截然不同的结果。
在 1.8 中约为 2.49 - 字符宽度约为 5
在 2.0 中约为 27.5 - 字符宽度约为 5
显然2.0中的27.5是错误的
只需运行下面的测试,你就会看到
@Override
protected void processTextPosition(TextPosition textPos)
{
float spaceWidth = textPos.getWidthOfSpace();
float width = textPos.getWidth();
System.out.println(textPos.getCharacter() + " - Width of Space=" + spaceWidth + " - width=" + width);
builder.append(textPos.getCharacter());
}
(当然 getUnicode() 对于 2.0 而不是 getCharacter())
===== 编辑 2015 年 6 月 27 日 8:00 下午 CST ======
这里是 link PDF 用于测试:
Hello World
当前space的宽度计算确实有误。 PDFTextStreamEngine.showGlyph(Matrix, PDFont, int, String, Vector)
目前(这是一个快照,今晚的情况可能会有所不同)这样计算宽度:
float horizontalScalingText = getGraphicsState().getTextState().getHorizontalScaling()/100f;
[...]
// the space width has to be transformed into display units
float spaceWidthDisplay = spaceWidthText * fontSizeText * horizontalScalingText *
textRenderingMatrix.getScalingFactorX() * ctm.getScalingFactorX();
(PDFTextStreamEngine.java 修订版 1688116)
但是 textRenderingMatrix
是在 PDFStreamEngine.showText(byte[])
中使用以下方法计算的:
float horizontalScaling = textState.getHorizontalScaling() / 100f;
[...]
Matrix parameters = new Matrix(
fontSize * horizontalScaling, 0, // 0
0, fontSize, // 0
0, textState.getRise()); // 1
[...]
Matrix textRenderingMatrix = parameters.multiply(textMatrix).multiply(ctm);
(修订版 1688116 中的PDFStreamEngine.java)
因此,字体大小和水平缩放比例都乘以 space 宽度的两倍。此外,当前变换矩阵既完全乘以textRenderingMatrix
又部分乘以ctm.getScalingFactorX()
;这可以构成最有趣的组合结果。
最有可能从 PDFTextStreamEngine.showGlyph(Matrix, PDFont, int, String, Vector)
中的 spaceWidthDisplay
计算中将这些值作为显式因素删除就足够了
在版本 1.8.9 中文本 space 宽度在 PDFStreamEngine.processEncodedText(byte[])
中计算如下:
float spaceWidthDisp = spaceWidthText * fontSizeText * horizontalScalingText
* textMatrix.getXScale() * ctm.getXScale();
对于有趣的当前转换和文本矩阵,这也会产生有趣的结果,但上述感兴趣的因素并未乘以两次结果。
我目前正在使用 pdfbox 1.8 来分析 PDF 文档。下面是我正在做的一个非常精简的例子。
import java.util.List;
import java.io.IOException;
import javax.swing.JFileChooser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDStream;
public class Main
{
private static PDDocument reader;
public static void main(String[] args)
{
JFileChooser chooser = new JFileChooser();
int result = chooser.showOpenDialog(null);
if(result == JFileChooser.APPROVE_OPTION)
{
try
{
reader = PDDocument.load(chooser.getSelectedFile());
for(int pagenum = 1; pagenum <= reader.getNumberOfPages(); pagenum++)
{
System.out.println("===== Page:" + pagenum + " ======");
System.out.println(extract(pagenum));
}
}
catch(Exception e) { e.printStackTrace(); }
}
}
public static String extract(int pagenum) throws IOException
{
List allPages = reader.getDocumentCatalog().getAllPages();
PDPage page = (PDPage) allPages.get(pagenum-1);
PDStream contents = page.getContents();
CustomPDFTextStripper stripper = new CustomPDFTextStripper();
if (contents != null)
{
stripper.processStream(page, page.findResources(), page.getContents().getStream());
}
return stripper.getContents();
}
}
和
import org.apache.pdfbox.util.PDFTextStripper;
import java.io.IOException;
import org.apache.pdfbox.util.TextPosition;
public class CustomPDFTextStripper extends PDFTextStripper
{
private final StringBuilder builder;
private float lastBase;
public CustomPDFTextStripper() throws IOException
{
super.setSortByPosition(true);
builder = new StringBuilder();
lastBase = Float.MAX_VALUE;
}
public String getContents() { return builder.toString(); }
@Override
protected void processTextPosition(TextPosition textPos)
{
float ascent = textPos.getY();
if(ascent > lastBase)
builder.append("\n");
lastBase = textPos.getY() + textPos.getHeight();
builder.append(textPos.getCharacter());
// I want to be able to do stuff here and
// I need to read spaces and newline characters
}
}
我似乎无法在 pdfbox 2.0 快照中找到等效的解决方案(我知道它不稳定并且尚未发布)。我尝试使用类似的东西:
CustomPDFTextStripper stripper = new CustomPDFTextStripper();
StringWriter dummy = new StringWriter();
stripper.setPageStart(""+(pagenum-1));
stripper.setPageEnd(""+(pagenum-1));
stripper.writeText(reader, dummy);
但它不处理空格或在 processTextPostion 方法中给出准确的 textPos 数据。
关于如何在 2.0 中获得与 1.8 相同的所有 TextPostion 数据有什么想法吗?
========== 编辑 26JUN2015 8:00 PM CST ===========
好的,我有时间看了一下,发现了问题所在。 getWidthOfSpace() returns 1.8 和 2.0 之间截然不同的结果。
在 1.8 中约为 2.49 - 字符宽度约为 5
在 2.0 中约为 27.5 - 字符宽度约为 5
显然2.0中的27.5是错误的
只需运行下面的测试,你就会看到
@Override
protected void processTextPosition(TextPosition textPos)
{
float spaceWidth = textPos.getWidthOfSpace();
float width = textPos.getWidth();
System.out.println(textPos.getCharacter() + " - Width of Space=" + spaceWidth + " - width=" + width);
builder.append(textPos.getCharacter());
}
(当然 getUnicode() 对于 2.0 而不是 getCharacter())
===== 编辑 2015 年 6 月 27 日 8:00 下午 CST ======
这里是 link PDF 用于测试: Hello World
当前space的宽度计算确实有误。 PDFTextStreamEngine.showGlyph(Matrix, PDFont, int, String, Vector)
目前(这是一个快照,今晚的情况可能会有所不同)这样计算宽度:
float horizontalScalingText = getGraphicsState().getTextState().getHorizontalScaling()/100f;
[...]
// the space width has to be transformed into display units
float spaceWidthDisplay = spaceWidthText * fontSizeText * horizontalScalingText *
textRenderingMatrix.getScalingFactorX() * ctm.getScalingFactorX();
(PDFTextStreamEngine.java 修订版 1688116)
但是 textRenderingMatrix
是在 PDFStreamEngine.showText(byte[])
中使用以下方法计算的:
float horizontalScaling = textState.getHorizontalScaling() / 100f;
[...]
Matrix parameters = new Matrix(
fontSize * horizontalScaling, 0, // 0
0, fontSize, // 0
0, textState.getRise()); // 1
[...]
Matrix textRenderingMatrix = parameters.multiply(textMatrix).multiply(ctm);
(修订版 1688116 中的PDFStreamEngine.java)
因此,字体大小和水平缩放比例都乘以 space 宽度的两倍。此外,当前变换矩阵既完全乘以textRenderingMatrix
又部分乘以ctm.getScalingFactorX()
;这可以构成最有趣的组合结果。
最有可能从 PDFTextStreamEngine.showGlyph(Matrix, PDFont, int, String, Vector)
spaceWidthDisplay
计算中将这些值作为显式因素删除就足够了
在版本 1.8.9 中文本 space 宽度在 PDFStreamEngine.processEncodedText(byte[])
中计算如下:
float spaceWidthDisp = spaceWidthText * fontSizeText * horizontalScalingText
* textMatrix.getXScale() * ctm.getXScale();
对于有趣的当前转换和文本矩阵,这也会产生有趣的结果,但上述感兴趣的因素并未乘以两次结果。