I need to have a table with multiple columns where I have different coloured circles in different cells with a number in the middle of the circle.
Similar to the mockup below but with everything centralized and equal.
I have tried the following:
PdfContentByte canvas = writer.DirectContent;
PdfTemplate template = canvas.CreateTemplate(40, 40);
template.SetLineWidth(1f);
template.Circle(15f, 15f, 15);
template.Stroke();
iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance(template);
img.Alignment = iTextSharp.text.Image.UNDERLYING | iTextSharp.text.Image.ALIGN_CENTER;
Phrase imgPhrase = new Paragraph(new Chunk(img, 1f, 1f));
PdfPCell meAnswerCell = new PdfPCell();
meAnswerCell.Colspan = 1;
meAnswerCell.BorderWidthBottom = 0;
meAnswerCell.HorizontalAlignment = Element.ALIGN_CENTER;
string meAnswerText = "1;
Phrase phrase = new Phrase(meAnswerText, questionFont);
Paragraph para = new Paragraph();
para.Add(imgPhrase);
para.Add(phrase);
para.Alignment = Element.ALIGN_CENTER;
meAnswerCell.AddElement(para);
answersTable.AddCell(meAnswerCell);
but I end up with something like this. (I haven't tried setting the colour yet). I cannot get the image and the text to sit in the same place.
I have also tried following this post:
iTextSharp - Text overlapping image
which explains how to put an event on the cell to set the background image of the cell but my circle appears half way down the page.
Has anyone go an example of this working?
There are many different ways to achieve what you want.
Actually, I just voted to close a question https://stackoverflow.com/questions/28066639/how-to-get-text-on-image-in-itext-using-java because it was a duplicate of How to add text to an image?
In your case, you may also benefit from the documentation. There are some examples in The Best iText Questions on StackOverflow that explain how to use cell events, but your requirement is very similar to what was done in a couple of examples from the book iText in Action - Second Edition.
You could use cell events to draw the background of a cell, as shown in the Calendar examples: calendar.pdf, but your requirement can also be met using a generic tag event: movie_years.pdf
Do you see how the word IMDB nicely fits inside an ellipse? You could fit a number inside a circle in the exact same way.
With this code, one draws an ellipse (changing it into a circle is fairly easy):
class GenericTags : PdfPageEventHelper {
public override void OnGenericTag(
PdfWriter writer, Document pdfDocument, Rectangle rect, String text) {
PdfContentByte content = writer.DirectContentUnder, rect);
content.SaveState();
content.SetRGBColorFill(0x00, 0x00, 0xFF);
content.Ellipse(
rect.Left - 3f, rect.Bottom - 5f,
rect.Right + 3f, rect.Top + 3f
);
content.Fill();
content.RestoreState();
}
}
With this snippet, you introduce this event:
GenericTags gevent = new GenericTags();
writer.PageEvent = gevent;
With this snippet, you mark a Chunk with the generic tag:
chunk.SetGenericTag("circle");
Related
I want to add a link to a document without underline or border.
Based on the documentation I expected the first example below to result in no border around the link. That did not work so I found this post which I adapted to the second example. Using this method I am able to replace the border with an underline, but not to get rid of both.
PdfDocument pdfDoc = new PdfDocument(new PdfWriter("links.pdf"));
Document d = new Document(pdfDoc);
// example 1
Paragraph p = new Paragraph()
.Add(new Link("Link with border", PdfAction.CreateURI("http://www.google.com")).SetBorder(Border.NO_BORDER))
.SetBorder(Border.NO_BORDER); // no border on the paragraph
d.Add(p);
// example 2
PdfLinkAnnotation linkA = new PdfLinkAnnotation(new Rectangle(0, 0, 0, 0));
linkA.SetHighlightMode(PdfLinkAnnotation.HIGHLIGHT_INVERT);
//This would give underline instead of borders
//linkA.SetBorderStyle(PdfLinkAnnotation.STYLE_UNDERLINE);
linkA.SetAction(PdfAction.CreateURI("http://www.google.com"));
Link link = new Link("Please no borders", linkA);
d.Add(new Paragraph(link));
pdfDoc.Close();
In order to get no borders in your second example you need to specify borders via PdfLinkAnnotation#SetBorder(PdfAnnotationBorder) method instead of the SetBorderStyle.
Here is a code snippet of yours slightly modified example:
PdfDocument pdfDoc = new PdfDocument(new PdfWriter("links.pdf"));
Document d = new Document(pdfDoc);
Link link = new Link("Please no borders", PdfAction.CreateURI("http://www.google.com"));
link.GetLinkAnnotation().SetBorder(new PdfAnnotationBorder(0, 0, 0));
d.Add(new Paragraph(link));
pdfDoc.Close();
You can find more info about this method call in javadocs: http://itextsupport.com/apidocs/itext7/latest/com/itextpdf/kernel/pdf/annot/PdfAnnotation.html#getBorder--
Some background
By default iText doesn't specify any specific border properties for link annotations. And as per PDF specification default value for annotations is to have borders:
ISO32000-1 12.5.2 "Annotation Dictionaries" Table 164 – "Entries common to all annotation dictionaries":
Border - An array specifying the characteristics of the annotation’s border, which shall be drawn as a rounded rectangle.
The array consists of three numbers defining the horizontal corner radius, vertical corner radius, and border width, all in default user space units. If the corner radii are 0, the border has square (not rounded) corners; if the border width is 0, no border is drawn.
[...]
Default value: [0 0 1].
here's a simple code:
var w = Utilities.MillimetersToPoints(420);
var h = Utilities.MillimetersToPoints(210);
var doc1 = new Document(new Rectangle(w, h));
PdfWriter writer = PdfWriter.GetInstance(doc1, new FileStream("Doc1.pdf", FileMode.Create));
doc1.Open();
PdfContentByte cb = writer.DirectContent;
var rect = new Rectangle(200, 200, 100, 100);
and now, if I do the following:
cb.Rectangle(200, 200, 100, 100);
cb.Stroke();
then I see the rectangle. But I need to set its border width, so I do
rect.BorderWidth = 5;
rect.BorderColor = new BaseColor(0,0,0);
cb.Rectangle(rect);
cb.Stroke();
and now the rectangle is not visible. Why ?
The Rectangle() method on PdfContentByte has a couple of overloads and they behave quite differently depending on what you pass in.
Your first example is using the very simple overload that just takes 4 floats. If you look at the source for that you'll see that beyond some sanity checking it just writes those coordinates directly to the PDF stream and no actual Rectangle objects are created in the process. Later when you call Stroke() iText writes the stroke command to the stream and that's it. When a PDF renderer (like Adobe's) actually parses the stroke command it looks backwards in the buffer and sees the coordinates that it needs to stroke and performs the action.
Your second example uses the much more complex overload that you can see here which takes an actual Rectangle object. Besides representing four points in space a Rectangle has concepts like background colors and borders and, most importantly for you, these borders can be drawn per side and you need to tell it which sides to draw on.
For instance, for just left and right you'd do:
var rect = new iTextSharp.text.Rectangle(200, 200, 100, 100);
rect.Border = iTextSharp.text.Rectangle.LEFT_BORDER | iTextSharp.text.Rectangle.RIGHT_BORDER;
rect.BorderWidth = 5;
rect.BorderColor = new BaseColor(0, 0, 0);
cb.Rectangle(rect);
And for all borders you'd change it to:
rect.Border = iTextSharp.text.Rectangle.BOX;
Also, when calling this overload it is actually incorrect to call Stroke() immediately after because this overload takes care of that for you (and might have done it more than once, actually.)
(an Addendum to #Chris' answer)
If you want to implement your task (to set its border width) using the simple means of the first example, you can explicitly set the width of lines to stroke:
cb.SetLineWidth(5);
cb.Rectangle(200, 200, 100, 100);
cb.Stroke();
You may want to envelope these lines in cb.SaveState() ... cb.RestoreState() to prevent the changed line width to influence later operations.
Document document = new Document(PageSize.A4, 25, 25, 30, 30);
PdfContentByte cb = writer.DirectContent;
cb.Rectangle(30,660, 280,80);
cb.Stroke();
the function writer is start to write in pdf and rectangle function is create rectangle and stroke is to draw above rectangle specification. so you have to write the stroke() function.
PdfContentByte cb = pdfwrite.DirectContent;
var Rectangular = new Rectangle(55, 620, 540,375);
Rectangular.BorderWidthLeft = 0.1f;
Rectangular.BorderWidthRight = 0.1f;
Rectangular.BorderWidthTop = 0.1f;
Rectangular.BorderWidthBottom = 0.1f;
cb.Rectangle(Rectangular);
cb.Stroke();
I'm using iTextSharp to create a PDF using an HTML page as an example. I am trying to put a border around text to highlight certain items. Using methods from these posts (Draw Rect at curr position, and Add Text over image ) I have used OnGenericTag events to create the rectangle for each Chunk that matches certain criteria. The event fires correctly and the rectangles are drawn on the correct elements. However the problem occurs when I add the background for the tablecell, it appears on top of the Chunk rectangles. Is there a way to make the rectangle drawn from the OnGenericTag event drawn above the table cell background?
OnGenericTags Method:
public class GenericTags : PdfPageEventHelper
{
public override void OnGenericTag(PdfWriter writer, Document pdfDocument, iTextSharp.text.Rectangle rect, String text)
{
if ("ellipse".Equals(text)) //I know it's not needed.
ellipse(writer.DirectContent, rect);
}
public void ellipse(PdfContentByte content, iTextSharp.text.Rectangle rect)
{
content.SaveState();
content.SetRGBColorStroke(0x00, 0x00, 0xFF);
content.SetLineWidth(2);
content.Rectangle(rect.Left - 2f, rect.Bottom - 3f, rect.Width, rect.Height + 3f);
content.Stroke();
content.RestoreState();
}
}
Each PdfPCell is defined as:
PdfPCell med = new PdfPCell(ph[4])
{
HorizontalAlignment = Element.ALIGN_CENTER,
VerticalAlignment = Element.ALIGN_CENTER,
BackgroundColor = hm_yellow //this draws above rect from onGenericTag()
};
The Chunks are created and assign via a foreach loop:
ph[j] = new Phrase();
foreach (var x in p.Risks)
{
c[i] = new Chunk("R" + x.APP_RISK_ID.ToString() + ", ");
if (x.RISK_STATUS_CD == "57")
{
//c[i].SetBackground(hm_top_tier); // still shows behind table cell background
c[i].SetGenericTag("ellipse");
}
ph[j].Add(c[i]);
}
This is the HTML page I'm trying to turn into a PDF. It shows the table cell background colors and the values that need to have a rectangle around them to highlight them.
This is the result when rendering a PDF. The highlighted R#'s match, however, when I apply a background color to the PdfPCell it is drawn over the rectangle from the Chunk
Draw the table using the layer writer.DirectContentUnder to make sure that the rectangle stays on top (writer.DirectContent).
I have a columntext that comes before a pdftable, how do I stop the two elements from overlapping?
ColumnText addressHeader = new ColumnText(cb);
Phrase addressText = new Phrase("Lorem ipsum");
addressHeader.SetSimpleColumn(addressText, 34, 750, 580, 317, 15, Element.ALIGN_LEFT);
addressHeader.FollowingIndent = 10f;
addressHeader.Go();
PdfPTable contactTable = new PdfPTable(2);
float[] contactWidths = new float[] { 1f, 1f };
contactTable.TotalWidth = 400f;
contactTable.LockedWidth = true;
contactTable.SpacingBefore = 10f;
contactTable.SetWidths(contactWidths);
PdfPCell contactInfoCell = new PdfPCell();
contactInfoCell.AddElement(new Chunk("Date Requested));
doc.Add(contactTable);
ColumnText.SetSimpleColumn() is used to absolutely position things whereas the Document.Add() method is used to relatively position things. Absolute and relative objects aren't aware of each other, that's just their nature.
So if you can use relative positioning then get rid of the ColumnText and add the Phrase to the document normally.
If you need absolute positioning then you'll need to absolutely position the table as well. This can be done using the table's WriteSelectedRows() method where you tell how many rows to write and what's the upper left corner to start drawing at.
A third possible option is that if you're using the ColumnText.SetSimpleColumn() to draw a page header then you can just change the document's margins. You can still absolutely position things outside of the margins but when you use Document.Add() it will respect those margins.
I'm trying to offset the position of an image within a table-cell in ITextSharp. Below is some pseudo-code outlining some of my attempts, none of which seem to affect the positioning of the image. I'd specifically like to align the middle of the image with the left border of the cell, but I can't even seem to figure out how to move the image at all.
doc.Open();
var table = new PdfPTable(1);
var cell = new PdfPCell();
var image = Image.GetInstance(); //etc
image.SetAbsolutePosition(-10, 0); //no effect
image.Left -= 10; //no effect
image.IndentationRight = 10; // no effect
cell.AddElement(image);
table.Rows.Add(new PdfPRow(new PdfPCell[] { cell }));
doc.Add(table);
When adding an image to a cell, using an absolute position or changing the properties of the image won't have an effect. If I interpret your question correctly, you want to define a padding for the cell so that there's 10pt of space to the left. Just use the appropriate padding method on the cell object (in iText, that would be cell.setPaddingLeft(10);).