我如何可以将图像或盖章的一个PDF哪里有可用空间,像一个密度扫描仪我如何可以将图像或盖章的一个PDF

2019-05-12 09:52发布

我在那里,在我增加了邮票给它的所有页面的PDF文件。

但是,问题是,邮票被添加到每个页面的左上角。 如果在页面中出现的那部分文字,邮票上出现的文字。

我的问题是,有没有通过,我可以读取每个页面,如果在这部分没有文字,添加最近的可用空间邮票别的搜索,就像什么密度扫描仪做的任何方法?

我使用iText的和Java 1.7。

自由空间FIDER类和距离计算功能是有在接受的答案是相同的。

以下是我使用了编辑的代码:

    // The resulting PDF file
    String RESULT = "K:\\DCIN_TER\\DCIN_EPU2\\CIRCUIT FROM BRANCH\\RAINBOW ORDERS\\" + jtfSONo.getText().trim() + "\\PADR Release\\Final PADR Release 1.pdf";

    // Create a reader
    PdfReader reader = new PdfReader("K:\\DCIN_TER\\DCIN_EPU2\\CIRCUIT FROM BRANCH\\RAINBOW ORDERS\\" + jtfSONo.getText().trim() + "\\PADR Release\\Final PADR Release.pdf");

    // Create a stamper
    PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(RESULT));

    // Loop over the pages and add a footer to each page
    int n = reader.getNumberOfPages();

    for(int i = 1; i <= n; i++)
    {
          Collection<Rectangle2D> rectangles = find(reader, 300, 100, n, stamper); // minimum width & height of a rectangle

          Iterator itr = rectangles.iterator();

          while(itr.hasNext())
          {
                 System.out.println(itr.next());
          }

          if(!(rectangles.isEmpty()) && (rectangles.size() != 0))
          {
                 Rectangle2D best = null;

                 double bestDist = Double.MAX_VALUE;

                 Point2D.Double point = new Point2D.Double(200, 400);  

                 float x = 0, y = 0;

                 for(Rectangle2D rectangle: rectangles)
                 {
                       double distance = distance(rectangle, point);

                       if(distance < bestDist)
                       {
                              best = rectangle;

                              bestDist = distance;

                              x = (float) best.getX();

                              y = (float) best.getY();

                              int left = (int) best.getMinX();

                              int right = (int) best.getMaxX();

                              int top = (int) best.getMaxY();

                              int bottom = (int) best.getMinY();

                              System.out.println("x : " + x);
                              System.out.println("y : " + y);
                              System.out.println("left : " + left);
                              System.out.println("right : " + right);
                              System.out.println("top : " + top);
                              System.out.println("bottom : " + bottom);

                       }
                }

                getFooterTable(i, n).writeSelectedRows(0, -1, x, y, stamper.getOverContent(i)); // 0, -1 indicates 1st row, 1st column upto last row and last column
        }

        else
             getFooterTable(i, n).writeSelectedRows(0, -1, 94, 140, stamper.getOverContent(i)); // bottom left corner
   }

   // Close the stamper
   stamper.close();

   // Close the reader
   reader.close();

   public Collection<Rectangle2D> find(PdfReader reader, float minWidth, float minHeight, int page, PdfStamper stamper) throws IOException
   {
         Rectangle cropBox = reader.getCropBox(page);

         Rectangle2D crop = new Rectangle2D.Float(cropBox.getLeft(), cropBox.getBottom(), cropBox.getWidth(), cropBox.getHeight());

         FreeSpaceFinder finder = new FreeSpaceFinder(crop, minWidth, minHeight);

         PdfReaderContentParser parser = new PdfReaderContentParser(reader);

         parser.processContent(page, finder);

         System.out.println("finder.freeSpaces : " + finder.freeSpaces);

         return finder.freeSpaces;
    }

    // Create a table with page X of Y, @param x the page number, @param y the total number of pages, @return a table that can be used as footer
   public static PdfPTable getFooterTable(int x, int y)
   {
         java.util.Date date = new java.util.Date();

         SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yyyy");

         String month = sdf.format(date);
         System.out.println("Month : " + month);

         PdfPTable table = new PdfPTable(1);

         table.setTotalWidth(120);
         table.setLockedWidth(true);

         table.getDefaultCell().setFixedHeight(20);
         table.getDefaultCell().setBorder(Rectangle.TOP);
         table.getDefaultCell().setBorder(Rectangle.LEFT);
         table.getDefaultCell().setBorder(Rectangle.RIGHT);
         table.getDefaultCell().setBorderColorTop(BaseColor.BLUE);
         table.getDefaultCell().setBorderColorLeft(BaseColor.BLUE);
         table.getDefaultCell().setBorderColorRight(BaseColor.BLUE);
         table.getDefaultCell().setBorderWidthTop(1f);
         table.getDefaultCell().setBorderWidthLeft(1f);
         table.getDefaultCell().setBorderWidthRight(1f);

         table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);

         Font font1 = new Font(FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.BLUE);

         table.addCell(new Phrase("CONTROLLED COPY", font1));

         table.getDefaultCell().setFixedHeight(20);
         table.getDefaultCell().setBorder(Rectangle.LEFT);
         table.getDefaultCell().setBorder(Rectangle.RIGHT);
         table.getDefaultCell().setBorderColorLeft(BaseColor.BLUE);
         table.getDefaultCell().setBorderColorRight(BaseColor.BLUE);
         table.getDefaultCell().setBorderWidthLeft(1f);
         table.getDefaultCell().setBorderWidthRight(1f);

         table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);

         Font font = new Font(FontFamily.HELVETICA, 10, Font.BOLD, BaseColor.RED);

         table.addCell(new Phrase(month, font));

         table.getDefaultCell().setFixedHeight(20);
         table.getDefaultCell().setBorder(Rectangle.LEFT);
         table.getDefaultCell().setBorder(Rectangle.RIGHT);
         table.getDefaultCell().setBorder(Rectangle.BOTTOM);
         table.getDefaultCell().setBorderColorLeft(BaseColor.BLUE);
         table.getDefaultCell().setBorderColorRight(BaseColor.BLUE);
         table.getDefaultCell().setBorderColorBottom(BaseColor.BLUE);
         table.getDefaultCell().setBorderWidthLeft(1f);
         table.getDefaultCell().setBorderWidthRight(1f);
         table.getDefaultCell().setBorderWidthBottom(1f);

         table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);

         table.addCell(new Phrase("BLR DESIGN DEPT.", font1));

         return table;
   }

Answer 1:

我对方的回答集中在原来的问题,即如何找到一个网页上给出最小尺寸的自由空间。

由于这个问题的答案已经被写入时,OP提供的代码试图利用该原始的答案。

这个答案与该代码交易。

该代码有许多缺点。

  1. 在页面上可用空间的选择取决于文件的页数。

    这样做的原因是在循环一翻开始被发现:

     for(int i = 1; i <= n; i++) { Collection<Rectangle2D> rectangles = find(reader, 300, 100, n, stamper); ... 

    该OP肯定意味着in那里。 正如总是代码看起来在过去的文档页面上可用空间。

  2. 该矩形是低于他们应该是。

    这样做的原因是在检索和使用矩形坐标中找到:

      x = (float) best.getX(); y = (float) best.getY(); ... getFooterTable(i, n).writeSelectedRows(0, -1, x, y, stamper.getOverContent(i)); 

    Rectangle2D方法getXgetY返回左下矩形角的坐标; 在PdfPTable方法writeSelectedRows ,而另一方面,需要左上方的矩形角落。 因此, getMaxY应该用来代替getY



Answer 2:

有没有通过,我可以读取每个页面,如果在这部分没有文字,添加最近的可用空间邮票别的搜索,就像什么密度扫描仪做的任何方法?

iText的不提供该功能的开箱。 根据你想逃避什么样的内容,不过,你可能会考虑要么显示网页,图像,寻找图像中的白色斑点或做文本提取与试图寻找无文本位置的策略。

第一备选方案中,分析所述网页的呈现的版本,将作为图像处理库的单独的问题的重点将必须被首先选择。

还有一些情况,不过,其中,首先选择是不是最好的一段路要走。 例如,如果你只是想逃避的文本,但并不一定图形(如水印),或者如果你也想逃避不可见的文本(通常可以被标记在一个PDF浏览器,因此,干扰你添加)。

第二个选择(使用文本和iText的的图像提取的能力)可以是在这种情况下的更合适的方法。

这里的样本RenderListener这样的任务:

public class FreeSpaceFinder implements RenderListener
{
    //
    // constructors
    //
    public FreeSpaceFinder(Rectangle2D initialBox, float minWidth, float minHeight)
    {
        this(Collections.singleton(initialBox), minWidth, minHeight);
    }

    public FreeSpaceFinder(Collection<Rectangle2D> initialBoxes, float minWidth, float minHeight)
    {
        this.minWidth = minWidth;
        this.minHeight = minHeight;

        freeSpaces = initialBoxes;
    }

    //
    // RenderListener implementation
    //
    @Override
    public void renderText(TextRenderInfo renderInfo)
    {
        Rectangle2D usedSpace = renderInfo.getAscentLine().getBoundingRectange();
        usedSpace.add(renderInfo.getDescentLine().getBoundingRectange());
        remove(usedSpace);
    }

    @Override
    public void renderImage(ImageRenderInfo renderInfo)
    {
        Matrix imageMatrix = renderInfo.getImageCTM();

        Vector image00 = rect00.cross(imageMatrix);
        Vector image01 = rect01.cross(imageMatrix);
        Vector image10 = rect10.cross(imageMatrix);
        Vector image11 = rect11.cross(imageMatrix);

        Rectangle2D usedSpace = new Rectangle2D.Float(image00.get(Vector.I1), image00.get(Vector.I2), 0, 0);
        usedSpace.add(image01.get(Vector.I1), image01.get(Vector.I2));
        usedSpace.add(image10.get(Vector.I1), image10.get(Vector.I2));
        usedSpace.add(image11.get(Vector.I1), image11.get(Vector.I2));

        remove(usedSpace);
    }

    @Override
    public void beginTextBlock() { }

    @Override
    public void endTextBlock() { }

    //
    // helpers
    //
    void remove(Rectangle2D usedSpace)
    {
        final double minX = usedSpace.getMinX();
        final double maxX = usedSpace.getMaxX();
        final double minY = usedSpace.getMinY();
        final double maxY = usedSpace.getMaxY();

        final Collection<Rectangle2D> newFreeSpaces = new ArrayList<Rectangle2D>();

        for (Rectangle2D freeSpace: freeSpaces)
        {
            final Collection<Rectangle2D> newFragments = new ArrayList<Rectangle2D>();
            if (freeSpace.intersectsLine(minX, minY, maxX, minY))
                newFragments.add(new Rectangle2D.Double(freeSpace.getMinX(), freeSpace.getMinY(), freeSpace.getWidth(), minY-freeSpace.getMinY()));
            if (freeSpace.intersectsLine(minX, maxY, maxX, maxY))
                newFragments.add(new Rectangle2D.Double(freeSpace.getMinX(), maxY, freeSpace.getWidth(), freeSpace.getMaxY() - maxY));
            if (freeSpace.intersectsLine(minX, minY, minX, maxY))
                newFragments.add(new Rectangle2D.Double(freeSpace.getMinX(), freeSpace.getMinY(), minX - freeSpace.getMinX(), freeSpace.getHeight()));
            if (freeSpace.intersectsLine(maxX, minY, maxX, maxY))
                newFragments.add(new Rectangle2D.Double(maxX, freeSpace.getMinY(), freeSpace.getMaxX() - maxX, freeSpace.getHeight()));
            if (newFragments.isEmpty())
            {
                add(newFreeSpaces, freeSpace);
            }
            else
            {
                for (Rectangle2D fragment: newFragments)
                {
                    if (fragment.getHeight() >= minHeight && fragment.getWidth() >= minWidth)
                    {
                        add(newFreeSpaces, fragment);
                    }
                }
            }
        }

        freeSpaces = newFreeSpaces;
    }

    void add(Collection<Rectangle2D> rectangles, Rectangle2D addition)
    {
        final Collection<Rectangle2D> toRemove = new ArrayList<Rectangle2D>();
        boolean isContained = false;
        for (Rectangle2D rectangle: rectangles)
        {
            if (rectangle.contains(addition))
            {
                isContained = true;
                break;
            }
            if (addition.contains(rectangle))
                toRemove.add(rectangle);
        }
        rectangles.removeAll(toRemove);
        if (!isContained)
            rectangles.add(addition);
    }

    //
    // members
    //
    public Collection<Rectangle2D> freeSpaces = null;
    final float minWidth;
    final float minHeight;

    final static Vector rect00 = new Vector(0, 0, 1);
    final static Vector rect01 = new Vector(0, 1, 1);
    final static Vector rect10 = new Vector(1, 0, 1);
    final static Vector rect11 = new Vector(1, 1, 1);
}

使用此FreeSpaceFinder你可以找到在这样的方法给定的最小尺寸的空白区域:

public Collection<Rectangle2D> find(PdfReader reader, float minWidth, float minHeight, int page) throws IOException
{
    Rectangle cropBox = reader.getCropBox(page);
    Rectangle2D crop = new Rectangle2D.Float(cropBox.getLeft(), cropBox.getBottom(), cropBox.getWidth(), cropBox.getHeight());
    FreeSpaceFinder finder = new FreeSpaceFinder(crop, minWidth, minHeight);
    PdfReaderContentParser parser = new PdfReaderContentParser(reader);
    parser.processContent(page, finder);
    return finder.freeSpaces;
}

对于你的任务,你现在已经从返回的矩形来选择最适合你的。

当心,这些代码可能还是要被调整到您的要求:

  • 它忽略夹路径,渲染模式,颜色和覆盖对象。 因此,它认为所有文本和所有的位图图像,无论是实际可见或不可见。
  • 它不考虑矢量图形(因为iText的解析器包不考虑它们)。
  • 这是不是很优化。

适用于本PDF页面:

与最小宽度200,高度50,你这些矩形:

x       y       w       h
000,000 000,000 595,000 056,423
000,000 074,423 595,000 168,681
000,000 267,304 314,508 088,751
000,000 503,933 351,932 068,665
164,296 583,598 430,704 082,800
220,803 583,598 374,197 096,474
220,803 583,598 234,197 107,825
000,000 700,423 455,000 102,396
000,000 700,423 267,632 141,577
361,348 782,372 233,652 059,628

或者,更直观,这里为页面上的矩形:

纸面是矢量图形,因此,忽略。

当然,你也可以改变的PDF渲染代码不吸引你要忽略,并画出明显要忽略原本看不见的东西,然后使用位图图像分析尽管如此东西...

编辑

在他的评论中OP问到如何找到返回的矩形集合中的矩形find这是最接近指定的点。

首先出现的也不一定是最近矩形,可能有多个。

这是说,人们可以选择最近的矩形如下:

第一个需要计算点和矩形,例如之间的距离:

double distance(Rectangle2D rectangle, Point2D point)
{
    double x = point.getX();
    double y = point.getY();
    double left = rectangle.getMinX();
    double right = rectangle.getMaxX();
    double top = rectangle.getMaxY();
    double bottom = rectangle.getMinY();

    if (x < left) // point left of rect
    {
        if (y < bottom) // and below
            return Point2D.distance(x, y, left, bottom);
        if (y > top) // and top
            return Point2D.distance(x, y, left, top);
        return left - x;
    }
    if (x > right) // point right of rect
    {
        if (y < bottom) // and below
            return Point2D.distance(x, y, right, bottom);
        if (y > top) // and top
            return Point2D.distance(x, y, right, top);
        return x - right;
    }
    if (y < bottom) // and below
        return bottom - y;
    if (y > top) // and top
        return y - top;
    return 0;
}

使用该距离测量可以使用这样的代码为一选择最近的矩形Collection<Rectangle2D> rectangles和一个Point2D point

Rectangle2D best = null;
double bestDist = Double.MAX_VALUE;

for (Rectangle2D rectangle: rectangles)
{
    double distance = distance(rectangle, point);
    if (distance < bestDist)
    {
        best = rectangle;
        bestDist = distance;
    }
}

在此之后best包含一个最好的矩形。

对于上面所使用的样本文档,这个方法返回的页角和左,右中心彩色矩形:

编辑两个

由于iText的5.5.6,该RenderListener接口已经扩展为ExtRenderListener也可以对信号路径构造和路径绘制操作。 因此, FreeSpaceFinder上述的组合也可以被扩展到处理路径:

//
// Additional ExtRenderListener methods
//
@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)
        remove(currentPathRectangle);
    currentPathRectangle = null;

    return null;
}

@Override
public void clipPath(int rule)
{
    // TODO Auto-generated method stub

}

Rectangle2D.Float currentPathRectangle = null;

( FreeSpaceFinderExt.java )

使用这个类的结果上述改善为

正如你所看到的纸飞机和表格的背景着色如今也被考虑在内。



文章来源: How can I can insert an image or stamp on a pdf where there is free space available like a density scanner
标签: java itext