当前位置: 首页 > 知识库问答 >
问题:

使用iTextPDF修剪页面的空格

锺博耘
2023-03-14

我有一个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许可优先)

共有1个答案

陆飞龙
2023-03-14

由于还没有发布实际的解决方案,这里有一些来自附带的itext-questions邮件列表线程的指针:

>

  • 因为您只想修剪页面,所以这不是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方法(带有附加的page参数)可能如下所示:

    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中使用此方法会得到以下结果:

    正如您所看到的,代码根据页面上的文本(和位图图像)内容进行修剪。

    如果要修剪的PDF不是太通用,但可以强制在相关位置包含一些文本或位图图形,那么无论如何,您可以使用上面的示例代码(可能只需稍作改动)。

    例如。如果您的PDF总是以顶部的文本开始,底部的文本结束,您可以更改getOutputPageSize以创建结果矩形,如下所示:

    Rectangle result = new Rectangle(pageSize.getLeft(), finder.getLly(), pageSize.getRight(), finder.getUry());
    

    这只会修剪顶部和底部的空空间:

    根据您的输入数据池和需求,这可能就足够了。

    或者,根据您对输入数据的了解,您可以使用一些其他的启发式方法。如果您对文本的定位有所了解(例如,标题始终居中,其他一些文本始终从左边开始),则可以轻松地扩展TextMarginFinder来利用这些知识。

    当前的开发版本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)

    使用该类修剪空白会导致

    这正是人们所希望的。

    注意:上面的实现远非最佳。它甚至是不正确的,因为它包括所有的曲线控制点,这是太多了。此外,它会忽略线宽或楔形类型等内容。它实际上只是一个概念的证明。

  •  类似资料:
    • 问题内容: 是否有一个框架可以删除图像的空白区域(矩形)。我们很遗憾地从技术图纸中创建了图像缩略图。我们将PDF转换为SVG,然后转换为JPG。技术图纸通常很小,现在放在缩略图的左上角: 那么,如何轻松删除空白区域并缩小JPG文件? 问题答案: 如该线程所示,可以在JAI中完成。或者这是我刚刚编写的一些Java代码,可用于执行此操作:

    • 本文向大家介绍JavaScript 修剪空白,包括了JavaScript 修剪空白的使用技巧和注意事项,需要的朋友参考一下 示例 要从字符串的边缘修剪空格,请使用String.prototype.trim: 许多JavaScript引擎(而非Internet Explorer)实现了非标准trimLeft和trimRight方法。目前,在该过程的第1阶段,有一项提议是标准化trimStart和tr

    • 问题内容: 如何在Django中charField的末尾去除空格(trim)? 这是我的模型,如您所见,我已经尝试过使用干净的方法,但是这些方法永远不会运行。 我也尝试过这样做,但是这些也不起作用。 有没有办法强制为我自动修剪charField? 谢谢。 编辑:将代码更新为我的最新版本。我不确定我在做什么错,因为它仍然没有剥离空白(修剪)名称字段。 问题答案: 必须调用模型清洗(这不是自动的),因

    • 问题内容: 是否有Python函数可以从字符串中修剪空白(空格和制表符)? 例如:→ 问题答案: 对于两侧的空格,请使用: 对于右侧的空格,请使用: 对于左侧的空格: 正如thedz所指出的,您可以提供一个参数来将任意字符剥离到以下任何函数中: 这将去除任何空间,,,或从左侧字符,右手侧,或该字符串的两侧。 上面的示例仅从字符串的左侧和右侧删除字符串。如果还要从字符串中间删除字符,请尝试: 那应该

    • 问题内容: 我有一个PDFReader,其中包含横向模式的某些页面和纵向模式的其他页面。 我需要区分它们以进行一些处理…但是,如果我调用getOrientation或getPageSize,则该值始终是相同的(pagesize为595,方向为0)。 为什么横向页面的值没有不同? 我试图找到其他方法来检索页面宽度/方向,但没有任何效果。 这是我的代码: 谢谢 ! 问题答案: 解决: 用 代替

    • 问题内容: 我有一个PDFReader,其中包含横向模式的某些页面和纵向模式的其他页面。 我需要区分它们以进行一些处理…但是,如果我调用getOrientation或getPageSize,则该值始终是相同的(pagesize为595,方向为0)。 为什么横向页面的值没有不同? 我试图找到其他方法来检索页面宽度/方向,但没有任何效果。 这是我的代码: 谢谢 ! 问题答案: 解决: 用 代替