How to absolute position the paragraph in pdf using iTextSharp? - c#

I am using ASP.NET,C# and iTextSharp for creating the pdf dynamically from scratch.
I am using this.
Phrase ph = new Phrase(text);
Paragraph p = new Paragraph(ph);
p.Alignment = Element.ALIGN_JUSTIFIED;
p.SpacingBefore = spaceBefore;
p.FirstLineIndent = 170;
p.IndentationLeft = 30;
p.IndentationRight = 50;
doc.Add(p)
So as you know i thought of using paragraph.spacebefore. But i need to position three paragraph in pdf and i am getting the text for the paragraphs from the user. So now based on the number of lines of the previous paragraph the next paragraph will vary with height that i don't want.
Then i thought of using this.
ColumnText ct = new ColumnText(cb);
ct.AddText(p);
ct.SetSimpleColumn(100, 100, 500, 500);
ct.Go();
But in this case i want the starting point of first and second line to be different, like this
p.FirstLineIndent = 170;
p.IndentationLeft = 30;
p.IndentationRight = 50;
Edit:
When i try this,the properties are does not affect these paragraphs just all the lines are starting from the same point.
Is it possible?

I found the answer it is simple. We can set the columntext property.
columntext.SetIndent(100, false);
It will add the space to only firstline.Then for linespacing I used this.
columntext.Leading = 31;
So if use the columntext for absolute position of paragraph then the paragraph property wont work. But we can use the columntext property.

Related

iText 7 - Center align text and paragraphs

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);

How to generate text box with max height in iTextSharp (auto-grow?)

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!

Adding text to a pdf after an image

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();

Insert Word shape at cursor position

Im looking for a way to insert an MS Word Shape at cursor position. At the moment I have the following code which inserts a shape at a predetermined location:
Microsoft.Office.Interop.Word.Range CurrRange = Globals.ThisAddIn.Application.Selection.Range;
//Get the id of the MS Word shape to be inserted
int shapeId = (int)MsoAutoShapeType.msoShapeRoundedRectangle;
//Get the value of the name attribute from the selected tree view item
string nodeText = treeViewItem.GetAttribute("name");
//Add a new shape to the MS Word designer and set shape properties
var shape = CurrRange.Document.Shapes.AddShape(shapeId, 170, 200, 100, 20);
shape.AlternativeText = String.Format("Alt {0}", nodeText);
shape.TextFrame.ContainingRange.Text = nodeText;
shape.TextFrame.ContainingRange.Font.Size = 8;
The location where the shape gets inserted is hardcoded:
This can be seen from the 2nd and 3rd parameters of the AddShape() method:
170 = position measured in points to the left edge of the autoshape
200 = position measured in points to the top edge of the autoshape
I've had a look at the properties and methods of my Range object but cannot seem to find any which store the position values which I require.
The final parameter to AddShape is an Anchor, which expects a range object. Try passing your range into that:
var shape = CurrRange.Document.Shapes.AddShape(shapeId, 0, 0, 100, 20,CurrRange);
Update: It looks like there is a bug in Word 2010 documents that it doesn't respect the Anchor. Save the document as a .doc file and test again, it does anchor it to the beginning of the paragraph if you do that. The link above is just to the microsoft forums, I could not find the connect bug report for the issue.
A workaround would be to specify the top and left based on the location of the selection:
Microsoft.Office.Interop.Word.Range CurrRange = Globals.ThisAddIn.Application.Selection.Range;
//Get the id of the MS Word shape to be inserted
int shapeId = (int)MsoAutoShapeType.msoShapeRoundedRectangle;
//Get the value of the name attribute from the selected tree view item
string nodeText = "Hello World";
var left = Globals.ThisAddIn.Application.Selection.get_Information(Microsoft.Office.Interop.Word.WdInformation.wdHorizontalPositionRelativeToPage);
var top = Globals.ThisAddIn.Application.Selection.get_Information(Microsoft.Office.Interop.Word.WdInformation.wdVerticalPositionRelativeToPage);
//Add a new shape to the MS Word designer and set shape properties
var shape = CurrRange.Document.Shapes.AddShape(shapeId, left, top, 100, 20);
shape.AlternativeText = String.Format("Alt {0}", nodeText);
shape.TextFrame.ContainingRange.Text = nodeText;
shape.TextFrame.ContainingRange.Font.Size = 8;

adding limitless text area to a PDF document

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.

Categories