Aymen
Aymen

Reputation: 133

cell background image with text itextsharp

Thanks in advance , I know that you're busy .. so I edited this based on the code you gave me ... first I want you to see what I got when I tried you code ..

enter image description here

and the picture I used as a background is :

enter image description here

as you see I got several problems :

1- the image is not a background to the cells and I want it to be stretched .

2- I tried to put the text in different positions but I failed .

3 - also i got a missing cell that not showed.

the code I used is :

1- the ImageEvent class :

 class ImageEvent : IPdfPCellEvent
{
protected Image img;
public ImageEvent(Image img) {
    this.img = img;
}
 void IPdfPCellEvent.CellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases)
{
    img.ScaleToFit(position.Width, position.Height);

    img.SetAbsolutePosition(position.Left + (position.Width - img.Width) / 2,
            position.Bottom + (position.Height - img.ScaledHeight / 2));
    PdfContentByte canvas = canvases[PdfPTable.BACKGROUNDCANVAS];
    try {
        canvas.AddImage(img);
    } catch (DocumentException ex) {
        // do nothing
    }
}

}

2- The position class :

 class PositionEvent : IPdfPCellEvent
{
    protected Phrase content;
    protected string pos;

    public PositionEvent(Phrase content, string pos)
    {
        this.content = content;
        this.pos = pos;
    }

     void IPdfPCellEvent.CellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases)
    {
        PdfContentByte canvas = canvases[PdfPTable.TEXTCANVAS];
        float x = 0;
        float y = 0;
        int alignment = 0;
        switch (pos)
        {
            case "TOP_LEFT":
                x = position.GetLeft(3);
                y = position.GetTop(content.Leading);
                alignment = Element.ALIGN_LEFT;
                break;
            case "TOP_RIGHT":
                x = position.GetRight(3);
                y = position.GetTop(content.Leading);
                alignment = Element.ALIGN_RIGHT;
                break;
            case "BOTTOM_LEFT":
                x = position.GetLeft(3);
                y = position.GetBottom(3);
                alignment = Element.ALIGN_LEFT;
                break;
            case "BOTTOM_RIGHT":
                x = position.GetRight(3);
                y = position.GetBottom(3);
                alignment = Element.ALIGN_RIGHT;
                break;
            case "CENTER_TOP":
                x = position.GetRight(3) + position.GetLeft(3) / 2; 
                y = position.GetTop(3);
                alignment = Element.ALIGN_RIGHT;
                break;
            case "CENTER_BOTTOM":
                x = position.GetRight(3) + position.GetLeft(3) / 2;
                y = position.GetBottom(3);
                alignment = Element.ALIGN_RIGHT;
                break;
            case "CENTER_MIDDLE":
                x = position.GetRight(3) + position.GetLeft(3) / 2;
                y = x;
                alignment = Element.ALIGN_RIGHT;
                break;
        }
        ColumnText.ShowTextAligned(canvas, alignment, content, x, y, 0);
    }
}

3- The method :

  public void createPdf(string dest)
    {
        // 1. Create a Document which contains a table:
        Document document = new Document();
        PdfWriter.GetInstance(document, new FileStream(dest, FileMode.Create));

        document.Open();
        PdfPTable table = new PdfPTable(3);
        table.WidthPercentage = 100f;
        PdfPCell cell1 = new PdfPCell();
        PdfPCell cell2 = new PdfPCell();
        PdfPCell cell3 = new PdfPCell();
        PdfPCell cell4 = new PdfPCell();
        PdfPCell cell5 = new PdfPCell();
        PdfPCell cell6 = new PdfPCell();
        PdfPCell cell7 = new PdfPCell();
        // 2. Inside that table, make each cell with specific height:
        cell1.FixedHeight=50;
        cell2.FixedHeight = 50;
        cell3.FixedHeight = 50;
        cell4.FixedHeight = 50;
        cell5.FixedHeight = 50;
        cell6.FixedHeight = 50;
        cell7.FixedHeight = 50;
        // 3. Each cell has the same background image
        string path = string.Concat(this.openFileDialog_pic.FileName);
        string imageFilePath = string.Concat(Environment.GetEnvironmentVariable("."), path);
        iTextSharp.text.Image IMG = iTextSharp.text.Image.GetInstance(imageFilePath);

        ImageEvent imgEvent = new ImageEvent(iTextSharp.text.Image.GetInstance(IMG));
        cell1.CellEvent=imgEvent;
        cell2.CellEvent = imgEvent;
        cell3.CellEvent = imgEvent;
        cell4.CellEvent = imgEvent;
        cell5.CellEvent = imgEvent;
        cell6.CellEvent = imgEvent;
        cell7.CellEvent = imgEvent;
        // 4. Add text in front of the image at specific position
        cell1.CellEvent= new PositionEvent(new Phrase("Top left"), "TOP_LEFT");
        cell2.CellEvent=new PositionEvent(new Phrase("Top right"), "TOP_RIGHT");
        cell3.CellEvent=new PositionEvent(new Phrase("Bottom left"), "BOTTOM_LEFT");
        cell4.CellEvent=new PositionEvent(new Phrase("Bottom right"), "BOTTOM_RIGHT");
        cell5.CellEvent = new PositionEvent(new Phrase("Center Top"), "CENTER_TOP");
        cell6.CellEvent = new PositionEvent(new Phrase("Center Bottom"), "CENTER_BOTTOM");
        cell7.CellEvent = new PositionEvent(new Phrase("Center Middle"), "CENTER_MIDDLE");
        // Wrap it all up!
        table.AddCell(cell1);
        table.AddCell(cell2);
        table.AddCell(cell3);
        table.AddCell(cell4);
        table.AddCell(cell5);
        table.AddCell(cell6);
        table.AddCell(cell7);
        document.Add(table);
        document.Close();
    }

Upvotes: 1

Views: 5258

Answers (1)

Bruno Lowagie
Bruno Lowagie

Reputation: 77528

In an additional comment, you clarify your requirements:

  1. I want to create a document which contains one table. Inside that table, cells
  2. I want to make each cell with specific height
  3. each cell have the same background image
  4. I want to put a text in front the image in the position I want inside the cell. For example: top left of the cell, bottom right of the cell

In other words: you want something like this: position_content_in_cell.pdf

enter image description here

There is more than one way to do this. I don't understand the code sample you use in your question. It uses nested tables and I don't understand why you'd need nested tables.

In the PositionContentInCell example, I used a method that allows you to really fine-tune the exact position of the text. I created an ImageEvent to scale and center the image:

class ImageEvent implements PdfPCellEvent {
    protected Image img;
    public ImageEvent(Image img) {
        this.img = img;
    }
    public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) {
        img.scaleToFit(position.getWidth(), position.getHeight());
        img.setAbsolutePosition(position.getLeft() + (position.getWidth() - img.getScaledWidth()) / 2,
                position.getBottom() + (position.getHeight() - img.getScaledHeight()) / 2);
        PdfContentByte canvas = canvases[PdfPTable.BACKGROUNDCANVAS];
        try {
            canvas.addImage(img);
        } catch (DocumentException ex) {
            // do nothing
        }
    }
}

I created a PositionEvent to add the text inside the cell:

class PositionEvent implements PdfPCellEvent {
    protected Phrase content;
    protected POSITION pos;

    public PositionEvent(Phrase content, POSITION pos) {
        this.content = content;
        this.pos = pos;
    }

    public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) {
        PdfContentByte canvas = canvases[PdfPTable.TEXTCANVAS];
        float x = 0;
        float y = 0;
        int alignment = 0;
        switch (pos) {
            case TOP_LEFT:
                x = position.getLeft(3);
                y = position.getTop(content.getLeading());
                alignment = Element.ALIGN_LEFT;
                break;
            case TOP_RIGHT:
                x = position.getRight(3);
                y = position.getTop(content.getLeading());
                alignment = Element.ALIGN_RIGHT;
                break;
            case BOTTOM_LEFT:
                x = position.getLeft(3);
                y = position.getBottom(3);
                alignment = Element.ALIGN_LEFT;
                break;
            case BOTTOM_RIGHT:
                x = position.getRight(3);
                y = position.getBottom(3);
                alignment = Element.ALIGN_RIGHT;
                break;
        }
        ColumnText.showTextAligned(canvas, alignment, content, x, y, 0);
    }
}

This is how I use these events:

public void createPdf(String dest) throws IOException, DocumentException {
    // 1. Create a Document which contains a table:
    Document document = new Document();
    PdfWriter.getInstance(document, new FileOutputStream(dest));
    document.open();
    PdfPTable table = new PdfPTable(2);
    PdfPCell cell1 = new PdfPCell();
    PdfPCell cell2 = new PdfPCell();
    PdfPCell cell3 = new PdfPCell();
    PdfPCell cell4 = new PdfPCell();
    // 2. Inside that table, make each cell with specific height:
    cell1.setFixedHeight(50);
    cell2.setFixedHeight(50);
    cell3.setFixedHeight(50);
    cell4.setFixedHeight(50);
    // 3. Each cell has the same background image
    ImageEvent imgEvent = new ImageEvent(Image.getInstance(IMG));
    cell1.setCellEvent(imgEvent);
    cell2.setCellEvent(imgEvent);
    cell3.setCellEvent(imgEvent);
    cell4.setCellEvent(imgEvent);
    // 4. Add text in front of the image at specific position
    cell1.setCellEvent(new PositionEvent(new Phrase("Top left"), POSITION.TOP_LEFT));
    cell2.setCellEvent(new PositionEvent(new Phrase("Top right"), POSITION.TOP_RIGHT));
    cell3.setCellEvent(new PositionEvent(new Phrase("Bottom left"), POSITION.BOTTOM_LEFT));
    cell4.setCellEvent(new PositionEvent(new Phrase("Bottom right"), POSITION.BOTTOM_RIGHT));
    // Wrap it all up!
    table.addCell(cell1);
    table.addCell(cell2);
    table.addCell(cell3);
    table.addCell(cell4);
    document.add(table);
    document.close();
}

Normally, I would write this code in a more efficient way, but I order the code lines in a way so that they reflect your requirements 1, 2, 3 and 4 literally.

Update:

In the comments, you asked several additional questions. For instance: how to stretch the image:

enter image description here

You were able to answer most of these questions, for instance based on my hint to use ScaleAbsolute:

public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) {
    img.scaleAbsolute(position.getWidth(), position.getHeight());
    img.setAbsolutePosition(position.getLeft(), position.getBottom());
    PdfContentByte canvas = canvases[PdfPTable.BACKGROUNDCANVAS];
    try {
        canvas.addImage(img);
    } catch (DocumentException ex) {
        // do nothing
    }
}

You had one more question that required an extra example (it was hard to explain it in a comment box). I named that example PositionContentInCell2

Instead of using the POSITION enumeration, you asked if it was possible to pass x and y values. You could do that, but you probably won't always know the width and the height of the cells, so why not define percentages such as wPct and hPct, along with an alignment:

class PositionEvent implements PdfPCellEvent {
    protected Phrase content;
    protected float wPct;
    protected float hPct;
    protected int alignment;

    public PositionEvent(Phrase content, float wPct, float hPct, int alignment) {
        this.content = content;
        this.wPct = wPct;
        this.hPct = hPct;
        this.alignment = alignment;
    }

    public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) {
        PdfContentByte canvas = canvases[PdfPTable.TEXTCANVAS];
        float x = position.getLeft() + wPct * position.getWidth();
        float y = position.getBottom() + hPct * (position.getHeight() - content.getLeading());
        ColumnText.showTextAligned(canvas, alignment, content, x, y, 0);
    }
}

Now you can add these events like this:

cell1.setCellEvent(new PositionEvent(new Phrase(14, "Top left"), 0, 1, Element.ALIGN_LEFT));
cell2.setCellEvent(new PositionEvent(new Phrase(14, "Top right"), 1, 1, Element.ALIGN_RIGHT));
cell3.setCellEvent(new PositionEvent(new Phrase(14, "Top center"), 0.5f, 1, Element.ALIGN_CENTER));
cell4.setCellEvent(new PositionEvent(new Phrase(14, "Bottom center"), 0.5f, 0, Element.ALIGN_CENTER));
cell5.setCellEvent(new PositionEvent(new Phrase(14, "Middle center"), 0.5f, 0.5f, Element.ALIGN_CENTER));
cell6.setCellEvent(new PositionEvent(new Phrase(14, "Middle center"), 0.5f, 0.5f, Element.ALIGN_CENTER));
cell7.setCellEvent(new PositionEvent(new Phrase(14, "Bottom left"), 0, 0, Element.ALIGN_LEFT));
cell8.setCellEvent(new PositionEvent(new Phrase(14, "Bottom right"), 1, 0, Element.ALIGN_RIGHT));

Of course, if you prefer passing x and y (after all: you do know the height, because you are defining a fixed height, the code can be made even simpler: you don't multiple the variables with position.getWidth and position.getHeight().

Upvotes: 2

Related Questions