java – 使用iTextPDF修剪页面的空白

我有一个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.

上一篇:iText导出PDF(图片,水印,页眉,页脚)


下一篇:java – PDF页面使用itext重新排序