I created a PDF document with images, I am trying to add text under each image keep in mind that the template for the page is different depending on how many images the user wants on the page. My problem is I am having problems adding and position the text.
Code for adding images:
int count = 0;
imageStartX = (docSize.Width / 100) * marginSizeProcent;
float imageMaxHeight = 0;
float imageMaxWidth = 0;
iTextSharp.text.Image image = null;
switch (pageLayout)
{
case PageLayoutEnum.SingleImage:
imageMaxWidth = docSize.Width - ((docSize.Width/100) * (2 * (float)marginSizeProcent));
imageMaxHeight = imageStartY - ((docSize.Width/100) * (float)marginSizeProcent);
foreach (PDFObject o in pdfObjects)
{
if (count > 0)
AddPageWithHeader(false);
image = iTextSharp.text.Image.GetInstance(o.File);
image.ScaleToFit(imageMaxWidth, imageMaxHeight);
image.SetAbsolutePosition(imageStartX + (imageMaxWidth - image.ScaledWidth) / 2, imageStartY - image.ScaledHeight - (imageMaxHeight - image.ScaledHeight) / 2);
image.Border = Rectangle.BOX;
image.BorderWidth = 2f;
image.BorderColor = BaseColor.DARK_GRAY;
document.Add(image);
count++;
}
break;
case PageLayoutEnum.TwoImages:
code for adding text:
MemoryStream memoryStream = new MemoryStream();
PdfReader pdfReader = new PdfReader(documentStream.ToArray());
PdfStamper stamper = new PdfStamper(pdfReader, memoryStream);
PdfContentByte contentbyte = stamper.GetUnderContent(1);
ColumnText dispalyIdText = new ColumnText(contentbyte);
Paragraph idText;
int counter = 0;
switch (pageLayout)
{
case PageLayoutEnum.SingleImage:
foreach (PDFObject item in pdfObjects)
{
dispalyIdText.SetSimpleColumn(200, 200, 200, 200, 200, Element.ALIGN_LEFT);
idText = new Paragraph(new Chunk(item.DisplayId, FontFactory.GetFont("Arial", 20, Font.BOLD, BaseColor.RED)));
dispalyIdText.AddElement(idText);
}
break;
case PageLayoutEnum.TwoImages:
You don't say what your actual problems are, only that you're having them.
If I were to guess, one of your problems is that text isn't actually being displayed on your PDFs. There are three distinct reasons for this. The first is this line:
dispalyIdText.SetSimpleColumn(200, 200, 200, 200, 200, Element.ALIGN_LEFT);
The first four parameters to this method are the coordinates of the rectangle that you want to constrain your drawing to. The first parameter is the lower left x, the second is the lower left y, the third is the upper right x and the fourth is the upper right y. In your code you are saying to bind your text to a rectangle with lower left coordinates of 200,200 and upper right coordinates of 200,200. This means your rectangle has zero width and height. To fix this you need to give a rectangle that actually works. In a PDF, the lower left corner is 0,0 so to draw text in a rectangle in the lower left corner that's 20 pixels (not actually pixels but that's another story) high and 200 wide you'd do:
dispalyIdText.SetSimpleColumn(0, 0, 200, 20, 200, Element.ALIGN_LEFT);
Your second problem is that you are setting the leading (line-height) to 200. Depending on the object you are creating this may or may not blow text way out. You should set this to something more sane, possibly the font's height. This doesn't affect AddElement but it does affect SetText.
dispalyIdText.SetSimpleColumn(0, 0, 200, 20, 12, Element.ALIGN_LEFT);
The last problem is that when using ColumnText you are now in "text" mode and have to tell the system when you are ready to start processing. You do this by issuing the Go() command:
dispalyIdText.Go();
Related
I'm trying to center align a block of text, however getting inconsistent results. Here is a rough idea of my code:
baseCanvas.ShowTextAligned("Header 1", 555, 839, TextAlignment.CENTER, 0);
baseCanvas.ShowTextAligned("Test test test ...", 240, 809, TextAlignment.CENTER, 0);
Here is the PDF Output:
However I'm trying to achieve the following:
I've checked the iText documentation, but is there a way to do this without having to create tables and cells?
When you do:
baseCanvas.ShowTextAligned("Some text", x, y, TextAlignment.CENTER, 0);
Then you want the coordinate (x, y) to coincide with the middle of the text "some text".
In your code snippet, you are centering some text around the coordinate (555, 839) and some text around the coordinate (40, 809) which explains the difference.
Since you are using iText 7, why don't you take advantage of the fact that you can now easily position Paragraph objects at absolute positions? The iText 7 jump-start tutorial for .NET already introduces some of the basic building blocks, but the Building blocks tutorial goes into more depth.
Take a look at the first example of chapter 2 and adapt it like this:
PdfPage page = pdf.AddNewPage();
PdfCanvas pdfCanvas = new PdfCanvas(page);
Rectangle rectangle = new Rectangle(36, 650, 100, 100);
Canvas canvas = new Canvas(pdfCanvas, pdf, rectangle);
PdfFont font = PdfFontFactory.createFont(FontConstants.TIMES_ROMAN);
PdfFont bold = PdfFontFactory.createFont(FontConstants.TIMES_BOLD);
Text title =
new Text("The Strange Case of Dr. Jekyll and Mr. Hyde").SetFont(bold);
Text author = new Text("Robert Louis Stevenson").SetFont(font);
Paragraph p = new Paragraph().Add(title).Add(" by ").Add(author);
p.SetTextAlignment(iText.Layout.Properties.TextAlignment.CENTER);
canvas.Add(p);
canvas.Close();
This should add the text inside the rectangle (36, 650, 100, 100) and center all content.
I do it like this. Where the document is created, get the width of the document.
var document = new Document(pdfDoc);
var pageSize = pdfDoc.GetDefaultPageSize();
var width = pageSize.GetWidth() - document.GetLeftMargin() - document.GetRightMargin();
Then create the paragraph with this function.
private Paragraph CenteredParagraph(Text text, float width)
{
var tabStops = new List<TabStop> { new TabStop(width / 2, TabAlignment.CENTER) };
var output = new Paragraph().AddTabStops(tabStops);
output.Add(new Tab())
.Add(text);
return output;
}
After that just add the paragraph to the document.
document.Add(CenteredParagraph("All the text to add that is centered.");
Div div2 = new Div();
div2.setPaddingLeft(35);
div2.setPaddingRight(35);
div2.setPaddingBottom(5);
div2.add(new Paragraph().add(new Paragraph("Hola Mundo")
.setFontSize(12)
.setTextAlignment(TextAlignment.JUSTIFIED)
.setPaddingLeft(10)
)
.setPaddingBottom(4));
document.add(div2);
I'm trying to design a footer, but the footer needs to be absolute on every single page.
Is there a function to grab the bottom of the page? afterward I could just subtract a few pixels and add my footer there.
int bottom = document.GetBottom():
ct.SetSimpleColumn(20, 20, 0, bottom - 20);
something along that line? Thats just pseudo code though.
the iTextSharp document provides document.Bottom which returns the bottom x value (atleast thats what worked for me)
using that I implemented a relative footer
PdfContentByte cb = wri.DirectContent;
ColumnText ct = new ColumnText(cb);
Phrase myText = new Phrase("footer data here", FontFactory.GetFont("Arial Bold", 10.0f, Font.BOLD, BaseColor.BLACK));
float textWidth = myText.Font.GetCalculatedBaseFont(false).GetWidthPoint("AASECT • 1444 I Street, NW • Suite 700 • Washington • DC • 20005 • (202) 449.1099 • info#aasect.org", 10.0f);
ct.SetSimpleColumn((doc.Right / 2) - (textWidth / 2), 1, (doc.Right / 2) + (textWidth / 2), doc.Bottom);
ct.AddText(myText);
ct.Go();
It creates the 'Phase' myText and then calculates the base font to gain access to the .GetWidthPoint to measure the size of the text. figures out the left most x coord by calculating the center of the document and subracting half of the width and repeats the reverse for the right most x coord by adding half of the width of the text
I hope this helps somebody, I found a lot of different 'Methods' of creating a footer and none of them worked, hopefully this meets someones needs.
I am creating a round corner table into the footer of my PDF using iTextSharp.
I can do it by this code:
PdfPTable tabFot = new PdfPTable(new float[] { 1F });
tabFot.TotalWidth = 300F;
tabFot.DefaultCell.Border = PdfPCell.NO_BORDER;
tabFot.DefaultCell.CellEvent = new RoundedBorder();
tabFot.AddCell("Footer");
And this is the code of my RoundBorder class:
class RoundedBorder : IPdfPCellEvent
{
public void CellLayout(PdfPCell cell, iTextSharp.text.Rectangle rect, PdfContentByte[] canvas)
{
/* PdfContentByte is an object containing the user positioned text and graphic contents of a page.
* It knows how to apply the proper font encoding
*/
PdfContentByte cb = canvas[PdfPTable.BACKGROUNDCANVAS];
// Adds a round rectangle to the current path: roundRectangle(float x, float y, float w, float h, float r)
cb.RoundRectangle(
rect.Left + 1.5f, // x: x-coordinate of the starting point
rect.Bottom + 1.5f, // y: y-coordinate of the starting point
rect.Width - 3, // w: width
rect.Height - 3, // h: height
4 // r: radius of the arc corner
);
cb.Stroke();
}
}
This work fine and I obtain the following result:
As you can see I obtain that the string "Footer" appear on the left of the cell (as required by the common behavior)
My problem is that I want have something like the following example:
As you can see I want to have some information text on the left and some other text (the page number) on the right of my cell.
Can I do it in some way?
I was reasoning about the fact that I pass a PdfPCell object to my CellLayout() method and that maybe I can put text in this cell whene the CellLayout() is executed. But what can I do to put some text on the left of the cell and some other text on its right?
Alternatively can I put all the text in the center of my cell?
Tnx
These are two questions in one ;-)
First question: you want text to the left and text to the right. This can be done like this:
Phrase phrase = new Phrase();
phrase.add(new Chunk("Left"));
phrase.add(new Chunk(new VerticalPositionMark()));
phrase.add(new Chunk("Right"));
PdfPCell cell = new PdfPCell(phrase);
The trick is where we add a new Chunk(new VerticalPositionMark()).
Second question: you want to center content in a cell.
This is trickier because there are two different modes: text mode and composite mode.
In text mode, you set the alignment at the level of the cell:
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
In your case:
tabFot.DefaultCell.setHorizontalAlignment(Element.ALIGN_CENTER);
In composite mode, you set the alignment at the level of the content you're adding.
We have a vehicle "Description" that could be anywhere from a few words to a few paragraphs. It needs to not go beyond a certain height (like 100px or whatever). Perfect solution would allow the text box to auto-grow (i.e. be as small as possible, but be able to grow up to a max height). There doesn't seem to be a way to restrict the height of a Paragraph or Phrase or anything. I have been messing with ColumnText but I can't seem to figure out how to make a ColumnText go into the flow of the document, so the next element after the Description goes below it and not on top of it. I have also seen ct.SetTextMatrix(xPos, yPos), but that still doesn't get me a max height box. Have I just not found what I'm needing yet, or does it not exist in iTextSharp?
Thank you so much, #Chris Haas! My solution was eventually found by the link he posted.
First, at the top of the page, we do the table height calculation:
PdfPTable tempTable = new PdfPTable(1);
tempTable.SetTotalWidth(new float[] { 540 }); //540 is width of PageSize.LETTER minus 36*2 for margins
string itemDescription = item.Description;
tempTable.AddCell(itemDescription);
float descriptionTableHeight = CalculatePdfPTableHeight(tempTable);
Then, the code for actually generating the PDF:
using (MemoryStream ms = new MemoryStream())
{
using (Document document = new Document(PageSize.LETTER))
{
using (PdfWriter writer = PdfWriter.GetInstance(document, ms))
{
document.Open();
//document properties
float margin = 36f;
document.SetMargins(margin, margin, margin, margin);
document.NewPage();
//description
customFont = FontFactory.GetFont("Helvetica", 10);
Phrase description = new Phrase(itemDescription, customFont);
table = new PdfPTable(1);
table.WidthPercentage = 100;
cell = new PdfPCell(description);
cell.Border = 0;
float maxHeight = 98f;
if (descriptionTableHeight > maxHeight)
cell.FixedHeight = maxHeight;
table.AddCell(cell);
document.Add(table);
}
}
}
So since we now have the table's height, we can check to see if it is greater than a maximum value and set the FixedHeight of the cell if so. And since we are able to add the table to the document, it goes in the normal flow of the page.
Thanks to the commenters for the leads!
I am trying to add a block of text to an existing PDF template.
I want to be able to set the left margin and right margin, but the amount of text is undetermined, so I need the box to expand in relation to the input text.
I have managed to position the text area on the template and insert text, but doing it this way needs me to explicitly set the bottom line location of the text area.
Here's the code I have so far (pdfStamper is pre-defined):
BaseFont bf = BaseFont.CreateFont(BaseFont.COURIER, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
Font font = new Font(bf, 11, Font.NORMAL);
Phrase unicodes = new Phrase(reports.StringText, font);
PdfContentByte over;
over = pdfstamper.GetOverContent(1);
ColumnText ct = new ColumnText(over);
ct.SetSimpleColumn(unicodes, 19, **80**, 575, 335, 10, Element.ALIGN_LEFT);
ct.Go();
OK, I've had a go at other solutions (which don't work). Here they are:
PdfPTable table = new PdfPTable(1);
string text = "blab balba b balbala ";
string finalText = "TestTitle1\r\n\r\n";
for (int i = 0; i < 200; ++i)
{
finalText += text;
}
table.AddCell(finalText);
table.TotalWidth = 300;
table.WriteSelectedRows(0, -1, 20, 325, pdfstamper.GetUnderContent(1));
This out puts a table in the desired place, with the desired width. But if there is too much text to fit on that one page I want it to extend to the next - which it doesn't. I have tried passing WriteSelectedRows an optional array of canvases (pdfstamper.GetUnderContent(1) and pdfstamper.GetUnderContent(2)), but this just throws an Index was outside the bounds of the array exception - but I even if that did work I don't know if it would be doing what I want.
Or there's this one:
PdfContentByte over;
over = pdfstamper.GetOverContent(1);
over.BeginText();
over.SetTextMatrix(20, 300);
over.ShowText(report.AutonomyText);
over.EndText();
But the text just goes off the side of the page.