Rectangular header and footer block on every page of PDF using OpenPDF - pdf

I am generating a PDF invoice report using OpenPDF. On the PDF, I have to set a rectangular block for header/footer on every page. I have used the HeaderFooter class to add header/footer on every page but this works only for a Phrase.
HeaderFooter header = new HeaderFooter(new Phrase("This is a Header."), false);
Is there any way to set a rectangular block with height and width for header/footer using HeaderFooter class?
This is what I am expecting on every page:

You can do this by creating your custom PdfPageEvent where you add the elements whenever a new page is finished (onEndPage-event). The simplest way of doing this is by extending PdfPageEventHelper in a standalone class or in an anonymous class. First, define and style your rectangles. Second, add them to the page using the PdfWriter inside the callback.
Here is a demo showing how to do it:
Document document = new Document(PageSize.A4, 40, 40, 200, 200);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("output.pdf"));
// footer
final Rectangle footer = new Rectangle(30, 30, PageSize.A4.getRight(30), 180);
footer.setBorder(Rectangle.BOX);
footer.setBorderColor(Color.BLACK);
footer.setBorderWidth(2);
// header
final Rectangle header = new Rectangle(footer);
header.setTop(PageSize.A4.getTop(30));
header.setBottom(PageSize.A4.getTop(180));
// content-box
final Rectangle box = new Rectangle(footer);
box.setTop(document.top());
box.setBottom(document.bottom());
// create and register page event to add the rectangles
writer.setPageEvent(new PdfPageEventHelper() {
#Override
public void onEndPage(PdfWriter writer, Document document) {
PdfContentByte cb = writer.getDirectContent();
cb.rectangle(header);
cb.rectangle(footer);
cb.rectangle(box);
}
});
document.open();
document.add(new Paragraph(LOREM_IPSUM)); // just some constant filler text
document.close();
The result looks like this:

Related

Extracting portion of a PDF

I'm trying to extract a portion of a pdf (the coordinates of the section will always remain constant) using PDF Sharp. Then I will resize the portion to 4" x 6" for printing onto a sticky back label. How would I extract the portion of the PDF? This is in a console application, C#.
There is no easy way to extract parts from a PDF file.
A possible workaround: create a new page in label size, then draw the existing page onto the new page so that the required rectangle is visible on the new page.
If needed, draw white rectangles to hide information that is not part of the section you need, but that is visible on the new page.
So here was how I managed to do this, not a perfect solution (you do loose some quality). This uses Spire.PDF, not PDF Sharp as I originally planned. I got fairly lucky in that the output size was nearly 4" X 6". So I just used shrink to fit on print options.
static void Main(string[] args)
{
ConvertPDFToBmp("FilePathOfPDF");
CropAtRect("FilePathOfConvertedImage");
ConvertToPDF("FilePathOfCroppedImage");
}
public static void ConvertPDFToBmp(string filePath)
{
PdfDocument document = new PdfDocument();
document.LoadFromFile(filePath);
Image emf = document.SaveAsImage(0, Spire.Pdf.Graphics.PdfImageType.Bitmap, 400, 400);
emf.Save("FilePath", ImageFormat.Jpeg);
}
public static void CropAtRect(string filePath)
{
Bitmap b = (Bitmap)Bitmap.FromFile(filePath);
Rectangle r = new Rectangle(new /*Where the rectangle starts*/Point(/*Width*/, /*Height*/), (new /*How big is the rectangle*/Size(/*Width*/, /*Height*/)));
Bitmap nb = new Bitmap(r.Width, r.Height);
nb.SetResolution(400, 400); //Scale to keep quality
Graphics g = Graphics.FromImage(nb);
g.DrawImage(b, -r.X, -r.Y);
nb.Save("FilePath", ImageFormat.Jpeg);
}
public static void ConvertToPDF(string filePath)
{
Bitmap b = (Bitmap)Bitmap.FromFile(filePath);
PdfDocument doc = new PdfDocument();
PdfImage pdfImage = PdfImage.FromImage(b);
PdfUnitConvertor uinit = new PdfUnitConvertor();
PdfPageBase page = doc.Pages.Add(new /*Size of PDF Page*/SizeF(585, 365), new PdfMargins(0f));
page.Canvas.DrawImage(pdfImage, new /*Where the image starts*/PointF(0, 0));
doc.SaveToFile("FilePath");
}

write lines on PDF

I want to write line by line on a pdf document
the code I have is writing the text in the center of the page
how can I write line by line?
// Create a new PDF document
PdfDocument document = new PdfDocument();
document.Info.Title = "Created with PDFsharp";
// Create an empty page
PdfPage page = document.AddPage();
// Get an XGraphics object for drawing
XGraphics gfx = XGraphics.FromPdfPage(page);
// Create a font
XFont font = new XFont("Verdana", 20, XFontStyle.BoldItalic);
// Draw the text
gfx.DrawString("Hello, World!", font, XBrushes.Black,
new XRect(0, 0, page.Width, page.Height),
XStringFormats.TopCenter);
With new XRect(0, 0, page.Width, page.Height) you specify where text will be drawn.
Use a smaller rectangle and increase the second value from line to line.
PDFsharp includes several examples:
http://pdfsharp.net/wiki/PDFsharpSamples.ashx
Especially check Text Layout. Sample code included with the source package of PDFsharp.
Also check out MigraDoc as it adds pagebreaks automatically.
http://pdfsharp.net/wiki/MigraDocSamples.ashx

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

chart location of pie chart in iText pdf in java

I'm creating a pie chart using jFreechart and add the chart in pdf created in iText. The problem is chart is always added at the bottom of the page and not after the last line.
A sample code for regenrating the error is:
Document document = new Document();
PdfWriter writer;
File file = new File("c:/myPdf.pdf");
writer = PdfWriter.getInstance(document, new FileOutputStream(file));
document.open();
try {
DefaultPieDataset pieDataset = new DefaultPieDataset();
pieDataset.setValue("OPT 1", 10);
pieDataset.setValue("OPT 2", 0);
pieDataset.setValue("OPT 3", 17);
pieDataset.setValue("OPT 4", 11);
JFreeChart chart = ChartFactory.createPieChart3D("Option click count",
pieDataset, true, false, false);
final PiePlot3D plot = (PiePlot3D) chart.getPlot();
plot.setNoDataMessage("No data to display");
chart.setTitle(new TextTitle("Option Click Count", new Font("Times New Roman", Font.PLAIN, 14)));
PdfContentByte pdfContentByte = writer.getDirectContent();
PdfTemplate pdfTemplateChartHolder = pdfContentByte.createTemplate(225,225);
Graphics2D graphicsChart = pdfTemplateChartHolder.createGraphics(225,225,new DefaultFontMapper());
Rectangle2D chartRegion =new Rectangle2D.Double(0,0,225,225);
chart.draw(graphicsChart,chartRegion);
graphicsChart.dispose();
pdfContentByte.addTemplate(pdfTemplateChartHolder,0,0);
} catch (Exception e) {
e.printStackTrace();
}
document.close();
Here the options are fetched from database so not sure on the count of the option. I want to show chart right to the table. How can I do this?
You are adding the chart as a template, and per definition they are added with absolute coordinates.
If you are using floating elements, as I assume you are, you can use com.lowagie.itext.Image (version 2.1), and in newer versions com.itextpdf.text.Image.
You can use the Image class to create the template, and add it as a Element:
See here (iText API).
PdfContentByte pdfContentByte = writer.getDirectContent();
PdfTemplate pdfTemplateChartHolder = pdfContentByte.createTemplate(225,225);
Graphics2D graphicsChart = pdfTemplateChartHolder.createGraphics(225,225,new DefaultFontMapper());
Rectangle2D chartRegion = new Rectangle2D.Double(0,0,225,225);
chart.draw(graphicsChart,chartRegion);
graphicsChart.dispose();
Image chartImage = Image.getInstance(pdfTemplateChartHolder);
document.add(chartImage);
The code example above shows the gist of it. You should as often as possible use Element objects such as Image if you don't want to handle heights and positions absolutely.

ITextSharp - text field in PdfPCell

I'm using iTextSharp to create a PDF, how can I add a textField into PdfPCell?
You wouldn't really add a 'text field' to a PdfPCell, you'd create a PdfPCell and add text (or other stuff) to that.
mikesdotnetting.com might have the clearest example and there's always the iTextSharp tutorial.
Give this a try. It works for me.
Document doc = new Document(PageSize.LETTER, 18f, 18f, 18f, 18f);
MemoryStream ms = new MemoryStream();
PdfWriter writer = PdfWriter.GetInstance(doc, ms);
doc.Open();
// Create your PDFPTable here....
TextField tf = new TextField(writer, new iTextSharp.text.Rectangle(67, 585, 140, 800), "cellTextBox");
PdfPCell tbCell = new PdfPCell();
iTextSharp.text.pdf.events.FieldPositioningEvents events = new iTextSharp.text.pdf.events.FieldPositioningEvents(writer, tf.GetTextField());
tbCell.CellEvent = events;
myTable.AddCell(tbCell);
// More code...
I adapted this code from this post.
Edit:
Here is a full working console application that puts a TextBox in a table cell. I tried to keep the code to a bare minimum.
using System;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
namespace iTextSharpTextBoxInTableCell
{
class Program
{
static void Main(string[] args)
{
// Create a PDF with a TextBox in a table cell
BaseFont bfHelvetica = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1250, false);
Font helvetica12 = new Font(bfHelvetica, 12, Font.NORMAL, Color.BLACK);
Document doc = new Document(PageSize.LETTER, 18f, 18f, 18f, 18f);
FileStream fs = new FileStream("TextBoxInTableCell.pdf", FileMode.Create);
PdfWriter writer = PdfWriter.GetInstance(doc, fs);
doc.Open();
PdfPTable myTable = new PdfPTable(1);
myTable.TotalWidth = 568f;
myTable.LockedWidth = true;
myTable.HorizontalAlignment = 0;
TextField tf = new TextField(writer, new iTextSharp.text.Rectangle(67, 585, 140, 800), "cellTextBox");
PdfPCell tbCell = new PdfPCell(new Phrase(" ", helvetica12));
iTextSharp.text.pdf.events.FieldPositioningEvents events =
new iTextSharp.text.pdf.events.FieldPositioningEvents(writer, tf.GetTextField());
tbCell.CellEvent = events;
myTable.AddCell(tbCell);
doc.Add(myTable);
doc.Close();
fs.Close();
Console.WriteLine("End Of Program Execution");
Console.ReadLine();
}
}
}
Bon chance
DaveB's answer works, but the problem is that you have to know the coordinates to place the textfield into, the (67, 585, 140, 800). The more normal method of doing this is to create the table cell and add a custom event to the cell. When the table generation calls the celllayout event it passes it the dimensions and coordinates of the cell which you can use to place and size the textfield.
First create this call, which is the custom event
public class CustomCellLayout : IPdfPCellEvent
{
private string fieldname;
public CustomCellLayout(string name)
{
fieldname = name;
}
public void CellLayout(PdfPCell cell, Rectangle rectangle, PdfContentByte[] canvases)
{
PdfWriter writer = canvases[0].PdfWriter;
// rectangle holds the dimensions and coordinates of the cell that was created
// which you can then use to place the textfield in the correct location
// and optionally fit the textfield to the size of the cell
float textboxheight = 12f;
// modify the rectangle so the textfield isn't the full height of the cell
// in case the cell ends up being tall due to the table layout
Rectangle rect = rectangle;
rect.Bottom = rect.Top - textboxheight;
TextField text = new TextField(writer, rect, fieldname);
// set and options, font etc here
PdfFormField field = text.GetTextField();
writer.AddAnnotation(field);
}
}
Then in your code where you create the table you'll use the event like this:
PdfPCell cell = new PdfPCell()
{
CellEvent = new CustomCellLayout(fieldname)
// set borders, or other cell options here
};
If you want to different kinds of textfields you can either make additional custom events, or you could add extra properties to the CustomCellLayout class like "fontsize" or "multiline" which you'd set with the class constructor, and then check for in the CellLayout code to adjust the textfield properties.