itex7: Add link to PDF without border or underline - c#

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

Related

iTextSharp watermark not appearing on a scanned PDF

I have some code used to watermark PDFs using iTextSharp. The code works fine for most PDFs, but there has been one test case where the watermark is not visible on a PDF of a scanned document. (I have other scanned documents where it does appear though).
I am using the GetOverContent() method.
This is my code for adding the watermark;
using (PdfReader reader = new PdfReader(this.inputFilename))
{
// Set transparent - 1
PdfGState gstate = new PdfGState();
gstate.FillOpacity = 0.4f;
gstate.StrokeOpacity = 0.5f;
// 2
BaseFont baseFont = BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, Encoding.ASCII.EncodingName, false);
using (var stream = new MemoryStream())
{
var pdfStamper = new PdfStamper(reader, stream);
// Must start at 1 because 0 is not an actual page.
for (int i = 1; i <= reader.NumberOfPages; i++)
{
Rectangle pageSize = reader.GetPageSizeWithRotation(i);
// Gets the content ABOVE the PDF, Another option is GetUnderContent(...)
// which will place the text below the PDF content.
PdfContentByte pdfPageContents = pdfStamper.GetOverContent(i);
pdfPageContents.BeginText(); // Start working with text.
// 1
pdfPageContents.SaveState();
pdfPageContents.SetGState(gstate);
float hypotenuse = (float)Math.Sqrt(Math.Pow(pageSize.Width, 2) + Math.Pow(pageSize.Height, 2));
float glyphWidth = baseFont.GetWidth("My watermark text");
float fontSize = 1000 * (hypotenuse * 0.8f) / glyphWidth;
float angle = (float)(Math.Atan(pageSize.Height / pageSize.Width) * (180 / Math.PI));
// Create a font to work with
pdfPageContents.SetFontAndSize(baseFont, fontSize);
pdfPageContents.SetRGBColorFill(128, 128, 128); // Sets the color of the font, GRAY in this instance
// Note: The x,y of the Pdf Matrix is from bottom left corner.
// This command tells iTextSharp to write the text at a certain location with a certain angle.
// Again, this will angle the text from bottom left corner to top right corner and it will
// place the text in the middle of the page.
pdfPageContents.ShowTextAligned(PdfContentByte.ALIGN_CENTER, "My watermark text", pageSize.Width / 2, pageSize.Height / 2, angle);
pdfPageContents.EndText(); // Done working with text
pdfPageContents.RestoreState();
}
pdfStamper.FormFlattening = true; // enable this if you want the PDF flattened.
pdfStamper.FreeTextFlattening = true; // enable this if you want the PDF flattened.
pdfStamper.Close(); // Always close the stamper or you'll have a 0 byte stream.
return stream.ToArray();
}
}
Does anyone have any ideas as to why the watermark may not be appearing and what I can try to fix it?
Kind regards.
The code is based on an assumption it even documents as a fact:
// Note: The x,y of the Pdf Matrix is from bottom left corner.
// This command tells iTextSharp to write the text at a certain location with a certain angle.
// Again, this will angle the text from bottom left corner to top right corner and it will
// place the text in the middle of the page.
pdfPageContents.ShowTextAligned(PdfContentByte.ALIGN_CENTER, "My watermark text", pageSize.Width / 2, pageSize.Height / 2, angle);
The assumption that the x,y of the Pdf Matrix is from bottom left corner unfortunately is wrong: While it indeed is very often the case that the origin of the PDF coordinate system (the default user space coordinate system, to be more precise) is in the lower left corner of the page, this is not required, the origin actually can be literally anywhere (within reasonable limits).
Thus, one has to take the lower left coordinates of the Rectangle pageSize into consideration, too.
The OP meanwhile has confirmed:
I had assumed that the bottom left of the page would have co-ordinates of (0,0) but for this document the co-ordinates were (0, 7022).

How do you change the icon size of a PDF sticky note placed via iTextSharp?

I'm trying to enlarge the icon of a PDF sticky note. Here's an image showing the sticky icon that I've stamped on the first page of the PDF for context:
I was under the impression the icon was guided by a rectangle that could be manipulated. Here's my code that has not been effective yet:
using (PdfStamper stamp = new PdfStamper(reader, fs))
{
PdfWriter attachment = stamp.Writer;
foreach (string file in files_to_attach)
{
PdfFileSpecification pdfAttch = PdfFileSpecification.FileEmbedded(attachment, file, file, null);
stamp.AddFileAttachment(file, pdfAttch);
}
//Create Note for first page
Rectangle rect = new Rectangle(850, 850, 650, 650);
PdfAnnotation annotation = PdfAnnotation.CreateText(stamp.Writer, rect, "TITLE OF NOTE", "Body text of the note", false, "Comment");
//Enlarge the Sticky Note icon
PdfDictionary page = reader.GetPageN(1);
PdfArray annots = page.GetAsArray(PdfName.ANNOTS);
PdfDictionary sticky = annots.GetAsDict(0);
PdfArray stickyRect = sticky.GetAsArray(PdfName.RECT);
PdfRectangle stickyRectangle = new PdfRectangle(
stickyRect.GetAsNumber(0).FloatValue - 50, stickyRect.GetAsNumber(1).FloatValue - 20,
stickyRect.GetAsNumber(2).FloatValue, stickyRect.GetAsNumber(3).FloatValue - 30);
sticky.Put(PdfName.RECT, stickyRectangle);
//Apply the Note to the first page
stamp.AddAnnotation(annotation, 1);
stamp.Close();
}
I thought I could change the float values and that would change the shape of the icon but so far it has not effected it all. Thank you for any suggestions.
You can't. The icon that is displayed for the "Comment" annotation is supplied by the viewer. The rect property is only used to define the lower left corner of where the icon gets placed on the page by the viewer. According to the PDF specification for annotations with the type "Text", "Conforming readers shall provide predefined icon appearances for at least the following standard names: Comment, Key, Note, Help, NewParagraph, Paragraph, Insert.
You can, however, create your own image, of any size, and use it as the appearance for a "Stamp" annotation. It can even look exactly like a "Comment" icon, just bigger. It would end up functioning in the same way for the end user.

iTextSharp - draw rectangle - border width issue

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

itextsharp add text over a circle image in a table cell

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

ITextSharp Image Positioning within Cell

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

Categories

Resources