我有一个pdf,其中包含一些数据,后跟一些空格.我不知道数据有多大,但我想在数据之后删除空白
PdfReader reader = new PdfReader(PDFLOCATION);
Rectangle rect = new Rectangle(700, 2000);
Document document = new Document(rect);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(SAVELCATION));
document.open();
int n = reader.getNumberOfPages();
PdfImportedPage page;
for (int i = 1; i <= n; i++) {
document.newPage();
page = writer.getImportedPage(reader, i);
Image instance = Image.getInstance(page);
document.add(instance);
}
document.close();
有没有办法剪切/修剪新文档中每个页面的空白?
此PDF包含矢量图形.
我使用iTextPDF,但可以切换到任何Java库(mavenized,Apache许可首选)
解决方法:
由于没有发布实际的解决方案,这里附带itext-questions mailing list thread的一些指示:
>由于您只想修剪页面,这不是PdfWriter getImportedPage用法的情况,而是PdfStamper的使用情况.使用PdfStamper的主代码可能如下所示:
PdfReader reader = new PdfReader(resourceStream);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("target/test-outputs/test-trimmed-stamper.pdf"));
// Go through all pages
int n = reader.getNumberOfPages();
for (int i = 1; i <= n; i++)
{
Rectangle pageSize = reader.getPageSize(i);
Rectangle rect = getOutputPageSize(pageSize, reader, i);
PdfDictionary page = reader.getPageN(i);
page.put(PdfName.CROPBOX, new PdfArray(new float[]{rect.getLeft(), rect.getBottom(), rect.getRight(), rect.getTop()}));
stamper.markUsed(page);
}
stamper.close();
如您所见,我还为您的getOutputPageSize方法添加了另一个参数.这是页码.毕竟,要修剪的空白区域在不同的页面上可能会有所不同.
>如果源文档不包含矢量图形,您可以简单地使用iText解析器包类.甚至已经有一个基于它们的TextMarginFinder.在这种情况下,getOutputPageSize方法(带有附加页面参数)可能如下所示:
private Rectangle getOutputPageSize(Rectangle pageSize, PdfReader reader, int page) throws IOException
{
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
TextMarginFinder finder = parser.processContent(page, new TextMarginFinder());
Rectangle result = new Rectangle(finder.getLlx(), finder.getLly(), finder.getUrx(), finder.getUry());
System.out.printf("Text/bitmap boundary: %f,%f to %f, %f\n", finder.getLlx(), finder.getLly(), finder.getUrx(), finder.getUry());
return result;
}
将此方法与您的文件test.pdf一起使用会导致:
如您所见,代码根据页面上的文本(和位图图像)内容进行修剪.
>要找到关于矢量图形的边界框,你基本上也必须这样做,但是你必须扩展这里使用的解析器框架来通知它的监听器(TextMarginFinder本质上是一个监听器,用于绘制从解析器框架发送的事件).矢量图形操作也是如此.这是非常重要的,特别是如果您还不熟悉PDF语法的话.
>如果要剪裁的PDF不是太通用但可以强制在相关位置包含一些文本或位图图形,但是,无论如何,您可以使用上面的示例代码(可能稍有更改).
例如.如果您的PDF始终以文本开头并以文本底部结尾,则可以更改getOutputPageSize以创建结果矩形,如下所示:
Rectangle result = new Rectangle(pageSize.getLeft(), finder.getLly(), pageSize.getRight(), finder.getUry());
这只会修剪顶部和底部的空白区域:
根据您的输入数据池和要求,这可能就足够了.
或者,您可以根据您对输入数据的了解使用其他一些启发式方法.如果您对文本的位置有所了解(例如,标题始终居中,而其他文本始终从左侧开始),则可以轻松扩展TextMarginFinder以利用此知识.
最近(2015年4月,iText 5.5.6-SNAPSHOT)的改进
当前的开发版本5.5.6-SNAPSHOT扩展了解析器包,还包括矢量图解析.这允许扩展iText的原始TextMarginFinder类,实现新的ExtRenderListener方法,如下所示:
@Override
public void modifyPath(PathConstructionRenderInfo renderInfo)
{
List<Vector> points = new ArrayList<Vector>();
if (renderInfo.getOperation() == PathConstructionRenderInfo.RECT)
{
float x = renderInfo.getSegmentData().get(0);
float y = renderInfo.getSegmentData().get(1);
float w = renderInfo.getSegmentData().get(2);
float h = renderInfo.getSegmentData().get(3);
points.add(new Vector(x, y, 1));
points.add(new Vector(x+w, y, 1));
points.add(new Vector(x, y+h, 1));
points.add(new Vector(x+w, y+h, 1));
}
else if (renderInfo.getSegmentData() != null)
{
for (int i = 0; i < renderInfo.getSegmentData().size()-1; i+=2)
{
points.add(new Vector(renderInfo.getSegmentData().get(i), renderInfo.getSegmentData().get(i+1), 1));
}
}
for (Vector point: points)
{
point = point.cross(renderInfo.getCtm());
Rectangle2D.Float pointRectangle = new Rectangle2D.Float(point.get(Vector.I1), point.get(Vector.I2), 0, 0);
if (currentPathRectangle == null)
currentPathRectangle = pointRectangle;
else
currentPathRectangle.add(pointRectangle);
}
}
@Override
public Path renderPath(PathPaintingRenderInfo renderInfo)
{
if (renderInfo.getOperation() != PathPaintingRenderInfo.NO_OP)
{
if (textRectangle == null)
textRectangle = currentPathRectangle;
else
textRectangle.add(currentPathRectangle);
}
currentPathRectangle = null;
return null;
}
@Override
public void clipPath(int rule)
{
}
(完整来源:MarginFinder.java)
使用此类修剪空白会导致
这几乎是人们所希望的.
注意:上面的实现远非最佳.它甚至不正确,因为它包括太多的所有曲线控制点.此外,它忽略了线宽或楔形类型之类的东西.它实际上只是一个概念验证.
所有测试代码均在TestTrimPdfPage.java.