How to Add a link to a PDF with ColdFusion and iText - pdf

I used this technique to insert an image
Adding a dynamic image to a PDF using ColdFusion and iText
Now, I need to insert a link to a external URL at X/Y and text inside with itext and ColdFusion.
Can someone help me do this?
Thanks.

Here is rough example that works with CF9. There are probably more elegant methods, but this should give you the basic idea.
Note - IIRC CF8 uses an earlier version of iText (1.4). CF9 uses 2.1.0. So I am relatively certain it will not run "as is" with CF8. If needed, you can use the JavaLoader.cfc to run a later version.
Update: Modified to show one way of defining a specific font, size and color. The correct settings will vary depending on your system, desired font, encoding, etcetera.
<cfscript>
inputPath = "c:\sourceFile.pdf";
outputPath = "c:\sourceFileWithLink.pdf";
try {
// initialize objects
pdfReader = createObject("java", "com.lowagie.text.pdf.PdfReader").init( inputPath );
outStream = createObject("java", "java.io.FileOutputStream").init( outputPath );
pdfStamper = createObject("java", "com.lowagie.text.pdf.PdfStamper").init( pdfReader, outStream );
// create a chunk with a link to www.google.com
chunk = createObject("java", "com.lowagie.text.Chunk").init("Go To Google");
chunk.setAnchor("http://www.google.com");
//////////////////////////////////////////
// Define embedded font
BaseFont = createObject("java", "com.lowagie.text.pdf.BaseFont");
Font = createObject("java", "com.lowagie.text.Font");
bf = BaseFont.createFont("c:/windows/fonts/Framd.ttf", BaseFont.CP1252, BaseFont.EMBEDDED);
// Create the main font object (size 14)
Color = createObject("java", "java.awt.Color");
textFont = Font.init(bf, 14, Font.UNDERLINE, Color.RED);
// Apply the font to the chunk text
chunk.setFont( textFont );
//////////////////////////////////////////
// prepare to write the link onto the *first* page only
cb = pdfStamper.getOverContent(1); // first page
ct = createObject("java", "com.lowagie.text.pdf.ColumnText").init(cb);
ct.addElement( chunk );
// position towards bottom right of page
page = pdfReader.getPageSize(1);
llx = page.getRight()-200;
lly = page.getBottom();
urx = page.getRight();
ury = page.getBottom() + 36;
// initialize column dimensions
ct.setSimpleColumn(llx, lly, urx, ury);
// write the text
ct.go();
WriteOutput("Finished!");
}
finally
{
// cleanup
if (IsDefined("pdfStamper")) {
pdfStamper.close();
}
if (IsDefined("outStream")) {
outStream.close();
}
}
</cfscript>

Related

Embed pdf content in pdf layer

I just registered. I try to address the following case:
Given a basic pdf (a simple, single raster image), I want to get to:
Create a pdf (empty initially), in which I create a layer, in which I embed the raster image of the input_pdf, and mark said layer as visible and not_printable.
Are there tools to do it?
Thanks for the tips.
Since you do not specify a language or a library you use, here it is a solution in C#:
// Extract the page content from the source file.
FileStream stream = File.OpenRead("input.pdf");
PDFFile source = new PDFFile(stream);
PDFPageContent pageContent = source.ExtractPageContent(0);
stream.Close();
PDFFixedDocument document = new PDFFixedDocument();
document.OptionalContentProperties = new PDFOptionalContentProperties();
PDFPage page = document.Pages.Add();
// Create an optional content group (layer) for the extracted page content.
PDFOptionalContentGroup ocg = new PDFOptionalContentGroup();
ocg.Name = "Embedded page";
ocg.VisibilityState = PDFOptionalContentGroupVisibilityState.AlwaysVisible;
ocg.PrintState = PDFOptionalContentGroupPrintState.NeverPrint;
// Draw the extracted page content in the layer
page.Canvas.BeginOptionalContentGroup(ocg);
page.Canvas.DrawFormXObject(pageContent, 0, 0, page.Width, page.Height);
page.Canvas.EndOptionalContentGroup();
// Build the display tree for the optional content
PDFOptionalContentDisplayTreeNode ocgNode = new PDFOptionalContentDisplayTreeNode(ocg);
document.OptionalContentProperties.DisplayTree.Nodes.Add(ocgNode);
using (FileStream output = File.Create("EmbedPageAsLayer.pdf"))
{
document.Save(output);
}
The output PDF file is available here: https://github.com/o2solutions/pdf4net/blob/master/GettingStarted/EmbedPageAsLayer/EmbedPageAsLayer.pdf

How to add watermark on existing pdf file

I am trying to add watermark on pdf file using PdfSharp, I tried from this link
http://www.pdfsharp.net/wiki/Watermark-sample.ashx
but am not able to get how to get the existing pdf file page object and how to watermark on that page.
Help?
Basically, the samples are only snippets. You can download the source and with that you get a bunch of samples, including this watermark example.
The following comes from PDFSharp-MigraDocFoundation-1_32/PDFsharp/samples/Samples C#/Based on GDI+/Watermark/Program.cs
Quite simple, really ... I am only showing the code up to the for loop that goes over each page. You should have a look at the full file.
[...]
const string watermark = "PDFsharp";
const int emSize = 150;
// Get a fresh copy of the sample PDF file
const string filename = "Portable Document Format.pdf";
File.Copy(Path.Combine("../../../../../PDFs/", filename),
Path.Combine(Directory.GetCurrentDirectory(), filename), true);
// Create the font for drawing the watermark
XFont font = new XFont("Times New Roman", emSize, XFontStyle.BoldItalic);
// Open an existing document for editing and loop through its pages
PdfDocument document = PdfReader.Open(filename);
// Set version to PDF 1.4 (Acrobat 5) because we use transparency.
if (document.Version < 14)
document.Version = 14;
for (int idx = 0; idx < document.Pages.Count; idx++)
{
//if (idx == 1) break;
PdfPage page = document.Pages[idx];
[...]

Add links to PDF programmatically

I have about 180 PDF files that are generated from a geodatabase. I would like to programmatically add links as hot spots (no text) at the top, bottom, left and right as needed to navigate to the adjoining page files. I would also like to add links over a 3x3 grid in the lower left corner of the page for additional navigation. The grid is already in the existing PDF just no links. Total there will be a possible 14 links added to each page
I am open to suggestions as to how to go about this. I am using Acrobat Pro XI, and I am familiar with various programing languages python, vb.net, C#... Just no experience working directly with PDF files.
This is very late answer. Actually I was searching for free alternative to above paid libraries. I found the following links which can be helpful to others.
Apache PDFBox is a vast java library to create pdf programmatically.
TomRoush/PdfBox-Android is it's android implementation. You can find the sample project with this implementation.
I have added the code for creating clickable links in pdf by using above android library and sample project.
public void createPdf(View v) {
PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);
// Create a new font object selecting one of the PDF base fonts
PDFont font = PDType1Font.HELVETICA;
// Or a custom font
//try {
// PDType0Font font = PDType0Font.load(document, assetManager.open("MyFontFile.TTF"));
//} catch(IOException e) {
// e.printStackTrace();
//}
PDPageContentStream contentStream;
try {
// Define a content stream for adding to the PDF
contentStream = new PDPageContentStream(document, page);
String preText = "Icons made by ";
String linkText = "My_Site";
float upperRightX = page.getMediaBox().getUpperRightX();
float upperRightY = page.getMediaBox().getUpperRightY();
// Write linkText in blue text
contentStream.beginText();
contentStream.setNonStrokingColor(15, 38, 192);
contentStream.setFont(font, 18);
contentStream.moveTextPositionByAmount( 0, upperRightY-20);
contentStream.drawString(preText + linkText);
contentStream.endText();
// create a link annotation
PDAnnotationLink txtLink = new PDAnnotationLink();
// set up the markup area
float offset = (font.getStringWidth(preText) / 1000) * 18;
float textWidth = (font.getStringWidth(linkText) / 1000) * 18;
PDRectangle position = new PDRectangle();
position.setLowerLeftX(offset);
position.setLowerLeftY(upperRightY - 24f);
position.setUpperRightX(offset + textWidth);
position.setUpperRightY(upperRightY -4);
txtLink.setRectangle(position);
// add an action
PDActionURI action = new PDActionURI();
action.setURI("https://www.**********.com/");
txtLink.setAction(action);
// and that's all ;-)
page.getAnnotations().add(txtLink);
// load 'Social media' icons from 'vector' resources.
float padding = 5, startX = 5, startY = upperRightY-100, width = 25, height=25;
loadVectorIconWithLink(document, page, contentStream, R.drawable.ic_facebook,
"https://www.facebook.com/My_Name/", startX, startY, width, height);
startX += (width + padding);
loadVectorIconWithLink(document, page, contentStream, R.drawable.ic_instagram,
"https://www.instagram.com/My_Name", startX, startY, width, height);
// Make sure that the content stream is closed:
contentStream.close();
// Save the final pdf document to a file
String path = root.getAbsolutePath() + "/Download/Created.pdf";
document.save(path);
document.close();
tv.setText("Successfully wrote PDF to " + path);
} catch (IOException e) {
e.printStackTrace();
}
}
private void loadVectorIconWithLink( PDDocument theDocument,
PDPage thePage,
PDPageContentStream theContentStream,
#DrawableRes int theDrawableId,
String theUriString,
float x, float y, float width, float height
) throws IOException
{
Bitmap alphaImage = getBitmapFromDrawable(this, theDrawableId);
PDImageXObject alphaXimage = LosslessFactory.createFromImage(theDocument, alphaImage);
theContentStream.drawImage(alphaXimage, x, y, width, height );
// create a link annotation
PDAnnotationLink iconLink = new PDAnnotationLink();
PDRectangle position = new PDRectangle( x, y, width, height );
iconLink.setRectangle(position);
// add an action
PDActionURI action1 = new PDActionURI();
action1.setURI(theUriString);
iconLink.setAction(action1);
// and that's all ;-)
thePage.getAnnotations().add(iconLink);
}
public static Bitmap getBitmapFromDrawable(Context context, #DrawableRes int drawableId) {
Drawable drawable = AppCompatResources.getDrawable(context, drawableId);
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
} else if (drawable instanceof VectorDrawableCompat || drawable instanceof VectorDrawable) {
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
} else {
throw new IllegalArgumentException("unsupported drawable type");
}
}
There are at least three types of links you might want to add: links to pages within the same document, links to pages in other PDF document, links to URLs on the web.
Docotic.Pdf library can add links of any of these types (please note that I am on of the developers of this library). Here are two relevant examples:
Create link to page
Create hyperlink
There are no examples for how to create links to pages in an other PDF document published online, but you can always contact support if you need such an example.
After continuing to search and not finding any other promising open source solutions I went with Debenu Quick PDF Library. The specific functions I used are are noted below:
AddLinkToFile
AddLinkToPage
Other annotations and hotspot links
The time that the two library functions are going to save me weekly is worth the cost alone. I am sure I will find other use for the other 900+ PDF functions

Have 2 bitmap resolutions in a PDF

Is there a way to place 2 instances of a bitmap in a PDF for a single image? One to display when it is viewed on the screen and another when it prints?
The problem we have is rendering a chart to a bitmap. If we do 300 dpi then axis lines, borders, etc. disappear. If we do 96 dpi, then printing it looks bad.
thanks - dave
You can use Optional Content to do this. Supplying the usage application dictionaries with a 'Print' event causes the content to be appropriate for printing. (Note, not all printing applications will honour this).
See The PDF Reference Manual, in my 1.7 edition section 4.10 'Optional Content' beginning on page 364.
You can add an Alternate Image Dictionary (PDF Spec, section 8.9.5.4) which can specify an image to be used for printing.
Yes, there is a way, although I do not know it. We used it as a prank on a coworker, when printing a document, some totally other pictures appeared
You can also use 2 readonly textbox fields and draw the images on the field's appearance. Then for one field you set its visibility to VisibleNonPrintable and for the other HiddenButPrintable.
I implemented this (using iText). For anyone else who needs these here's the code. And you can download the source at my blog.
static void Main(string[] args)
{
Document document = new Document(new Rectangle(0, 0, 8.5f * 72.0f, 11 * 72));
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(Path.GetFullPath(#"..\..\test_dotnet.pdf"), FileMode.OpenOrCreate, FileAccess.ReadWrite));
document.Open();
document.Add(new Paragraph("Visibility test"));
// not displayed on printer
PdfLayer layer = new PdfLayer("screen", writer);
layer.OnPanel = false;
layer.SetPrint("Print", false);
layer.View = true;
PdfContentByte cb = writer.DirectContent;
cb.BeginLayer(layer);
Image img = Image.GetInstance(Path.GetFullPath(#"..\..\building_01.png"));
img.SetAbsolutePosition(72, 72 * 7);
cb.AddImage(img);
cb.EndLayer();
// not displayed on screen
layer = new PdfLayer("print", writer);
layer.OnPanel = false;
layer.SetPrint("Print", true);
layer.View = false;
cb = writer.DirectContent;
cb.BeginLayer(layer);
img = Image.GetInstance(Path.GetFullPath(#"..\..\building_02.png"));
img.SetAbsolutePosition(72, 72 * 3);
cb.AddImage(img);
cb.EndLayer();
document.Close();
Console.Out.WriteLine("all done");
}

How to exactly position an Image inside an existing PDF page using PDFBox?

I am able to insert an Image inside an existing pdf document, but the problem is,
The image is placed at the bottom of the page
The page becomes white with the newly added text showing on it.
I am using following code.
List<PDPage> pages = pdDoc.getDocumentCatalog().getAllPages();
if(pages.size() > 0){
PDJpeg img = new PDJpeg(pdDoc, in);
PDPageContentStream stream = new PDPageContentStream(pdDoc,pages.get(0));
stream.drawImage(img, 60, 60);
stream.close();
}
I want the image on the first page.
PDFBox is a low-level library to work with PDF files. You are responsible for more high-level features. So in this example, you are placing your image at (60, 60) starting from lower-left corner of your document. That is what stream.drawImage(img, 60, 60); does.
If you want to move your image somewhere else, you have to calculate and provide the wanted location (perhaps from dimensions obtained with page.findCropBox(), or manually input your location).
As for the text, PDF document elements are absolutely positioned. There are no low-level capabilities for re-flowing text, floating or something similar. If you write your text on top of your image, it will be written on top of your image.
Finally, for your page becoming white -- you are creating a new content stream and so overwriting the original one for your page. You should be appending to the already available stream.
The relevant line is:
PDPageContentStream stream = new PDPageContentStream( pdDoc, pages.get(0));
What you should do is call it like this:
PDPageContentStream stream = new PDPageContentStream( pdDoc, pages.get(0), true, true);
The first true is whether to append content, and the final true (not critical here) is whether to compress the stream.
Take a look at AddImageToPDF sample available from PDFBox sources.
Try this
doc = PDDocument.load( inputFileName );
PDXObjectImage ximage = null;
ximage = new PDJpeg(doc, new FileInputStream( image )
PDPage page = (PDPage)doc.getDocumentCatalog().getAllPages().get(0);
PDPageContentStream contentStream = new PDPageContentStream(doc, page, true, true);
contentStream.drawImage( ximage, 425, 675 );
contentStream.close();
This prints the image in first page. If u want to print in all pages just put on a for loop with a condition of number of pages as the limit.
This worked for me well!
So late answer but this is for who works on it in 2020 with Kotlin: drawImage() is getting float values inside itself so try this:
val file = File(getPdfFile(FILE_NAME))
val document = PDDocument.load(file)
val page = document.getPage(0)
val contentStream: PDPageContentStream
contentStream = PDPageContentStream(document, page, true, true)
// Define a content stream for adding to the PDF
val bitmap: Bitmap? = ImageSaver(this).setFileName("sign.png").setDirectoryName("signature").load()
val mediaBox: PDRectangle = page.mediaBox
val ximage: PDImageXObject = JPEGFactory.createFromImage(document, bitmap)
contentStream.drawImage(ximage, mediaBox.width - 4 * 65, 26f)
// Make sure that the content stream is closed:
contentStream.close()
// Save the final pdf document to a file
pdfSaveLocation = "$directoryPDF/$UPDATED_FILE_NAME"
val pathSave = pdfSaveLocation
document.save(pathSave)
document.close()
I am creating a new PDF and running below code in a loop - to add one image per page and below co-ordinates and height and width values work well for me.
where out is BufferedImage reference variable
PDPage page = new PDPage();
outputdocument.addPage(page);
PDPageContentStream contentStream = new PDPageContentStream(outputdocument, page, AppendMode.APPEND, true);
PDImageXObject pdImageXObject = JPEGFactory.createFromImage(outputdocument, out);
contentStream.drawImage(pdImageXObject, 5, 2, 600, 750);
contentStream.close();
This link gives you details about Class PrintImageLocations.
This PrintImageLocations will give you the x and y coordinates of the images.
Usage: java org.apache.pdfbox.examples.util.PrintImageLocations input-pdf