Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用iTextPDF修剪页面';s空格_Java_Pdf Generation_Itext_Itextpdf - Fatal编程技术网

Java 使用iTextPDF修剪页面';s空格

Java 使用iTextPDF修剪页面';s空格,java,pdf-generation,itext,itextpdf,Java,Pdf Generation,Itext,Itextpdf,我有一个由一些数据组成的pdf,后面是一些空白。我不知道数据有多大,但我想删掉数据后面的空白 PdfReader reader = new PdfReader(PDFLOCATION); Rectangle rect = new Rectangle(700, 2000); Document document = new Document(rect); PdfWriter writer = PdfWriter.getInstance(document, new Fi

我有一个由一些数据组成的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();
PdfReader阅读器=新的PdfReader(PDFLOCATION);
矩形rect=新矩形(7002000);
文件=新文件(rect);
PdfWriter writer=PdfWriter.getInstance(文档,新文件输出流(savelAction));
document.open();
int n=reader.getNumberOfPages();
PDF导入页面;

对于(int i=1;i,由于没有发布实际的解决方案,以下是随附的一些指针:

  • 由于您只想修剪页面,因此这不是使用
    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(); 
    
    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;
    }
    
    对文件使用此方法会导致:

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

  • 要找到关于矢量图形的边界框,基本上也必须这样做,但必须扩展此处使用的解析器框架,以通知其侦听器(
    TextMarginFinder
    本质上是从解析器框架发送的绘图事件的侦听器)关于矢量图形操作,这是非常重要的,特别是如果你还不知道PDF的语法

  • 但是,如果要修剪的PDF不是太通用,但可能会被迫在相关位置包含一些文本或位图图形,那么无论如何,您都可以使用上面的示例代码(可能会有一些小的更改)

    例如,如果PDF始终以文本开头,以文本结尾,则可以更改getOutputPageSize以创建如下结果矩形:

    Rectangle result = new Rectangle(pageSize.getLeft(), finder.getLly(), pageSize.getRight(), finder.getUry());
    
    @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)
    {
    }
    
    这只会修剪顶部和底部的空白空间:

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

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


  • 最近(2015年4月,iText 5.5.6-SNAPSHOT)的改进 当前的开发版本5.5.6-SNAPSHOT扩展了解析器包,还包括矢量图形解析。这允许扩展iText的原始
    TextMarginFinder
    类,实现新的
    ExtRenderListener
    方法,如下所示:

    Rectangle result = new Rectangle(pageSize.getLeft(), finder.getLly(), pageSize.getRight(), finder.getUry());
    
    @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)
    {
    }
    
    @覆盖
    公共void修改路径(PathConstructionRenderInfo renderInfo)
    {
    列表点=新的ArrayList();
    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);
    加(新向量(x,y,1));
    添加(新向量(x+w,y,1));
    加(新向量(x,y+h,1));
    添加(新向量(x+w,y+h,1));
    }
    else if(renderInfo.getSegmentData()!=null)
    {
    对于(int i=0;i
    (完整来源:)

    使用此类修剪空白会导致

    这正是人们所希望的

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


    所有测试代码都在中。

    您的PDF是否包含矢量图形?还是仅包含文本和位图图像?它包含矢量图形?嗯,好吧,这很不幸。我之所以问这个问题,是因为itext中包含一个示例类,用于确定页面上所有文本和位图的边界框。不幸的是,它还没有将矢量图形nto account.Thank.我最后只是在图的右下角添加了一个字符串(您的第四条建议)这使得TextMarginFinder在处理
    MarginFinder
    中的一个bug时能够找到图形元素周围的边距,出现了
    renderPath
    中的
    NullPointerException
    情况,现在已经修复了。itext7中有没有类似的东西?itext7没有IExtRenderListener接口眼,有;itext7有通用的接口眼将事件侦听器机制稍微简化一点,您不需要实现不同的接口,只需注册其他事件类型。@JIemON您可以在和中找到
    MarginFinder
    的端口。