How can I insert an image or stamp into a pdf where there is free space like a density scanner

I have a pdf file where I add a stamp to all its pages.

But the problem is that the mark is added to the upper left corner of each page. If the page has text in this part, a stamp appears in the text.

My question is, is there any method by which I can read every page, and if there is no text in this part, add a stamp to still look for the nearest available free space, just like a density scanner?

I am using IText and Java 1.7.

The mean free path and distance calculation function are the same as in the accepted answer.

Below is the edited code I'm using:

    // 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;
   }
0
2

, .. .

, OP , .

.

.

  • .

    :

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

    OP i, n. .

  • , .

    :

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

    Rectangle2D getX getY ; PdfPTable writeSelectedRows, , . , getMaxY getY.

+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:

Sample invoice

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

, , :

Sample Invoice with free rectangles at least 200x50 in size marked

, , .

, PDF, , , , , ...

, , 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 .

, , :

Sample Invoice with free rectangles at least 200x50 in size marked and best rectangles filled

EDIT TWO​​strong >

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)

,

Sample Invoice with free rectangles at least 200x50 in size marked and best rectangles filled, extended render listener

, .

+2

All Articles