I want to add an image to a pdf file. the position of the image should be just above the last line in a pdf file.
How do I get the x,y position of the last line in the pdf or the x,y position of the end of the last text block.
Look for an object named TextMarginFinder and use it like is done in this Java example: ShowTextMargins
public void addMarginRectangle(String src, String dest)
throws IOException, DocumentException {
PdfReader reader = new PdfReader(src);
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(RESULT));
TextMarginFinder finder;
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
finder = parser.processContent(i, new TextMarginFinder());
PdfContentByte cb = stamper.getOverContent(i);
cb.rectangle(finder.getLlx(), finder.getLly(),
finder.getWidth(), finder.getHeight());
cb.stroke();
}
stamper.close();
reader.close();
}
Related
When i generates a PDF file from an existing PDF file with itextsharp,my work code is
The soruce pdf
string sourceFile = "a4.pdf", targetFile = "processed.pdf";
PdfReader reader = new PdfReader(sourceFile);
Document doc = new Document();
PdfWriter writer = PdfWriter.GetInstance(doc, new FileStream(targetFile, FileMode.Create));
doc.Open();
PdfContentByte cb = writer.DirectContent;
PdfImportedPage page;
for (int pageNumber = 1; pageNumber <= reader.NumberOfPages; pageNumber++)
{
doc.SetPageSize(reader.GetPageSizeWithRotation(pageNumber));
doc.NewPage();
page = writer.GetImportedPage(reader, pageNumber);
//Write a PageIndex
ColumnText.ShowTextAligned(cb, PdfContentByte.ALIGN_CENTER, new Phrase(pageNumber.ToString()), 100, 0, 0);
cb.AddTemplate(page, 0, 0);
}
doc.Close();
The problem is, when i get a PdfImportedPage from reader,page = writer.GetImportedPage(reader, pageNumber); the content in sourceFile's hidden layer will display.The processed.pdf has none layer.
How can i get a PdfImportedPage without hidden layer context use Itextsharp.
I have a landscaped form lay on a top half of A4 page, I want it to be rotated and enlarge to a portrait layout size fill up the A4 then saved before it is faxed out. Otherwise, the fax service program will fax it out with only partial info. Here is my attempt, result is the same as the input pdf. This is my first day on programming using iText, all the google not getting me what I want. Please let me know if you can help. Thanks,
public class CopeALandscapePdfFiletoPortraitPdfFile {
//public static final String SRC = "resources/pdfs/landscapeForm.pdf";
public static final String SRC = "resources/pdfs/potraitForm.pdf";
public static final String DEST = "results/stamper/portraitFormAfterCopy.pdf";
public static void main(String[] args) throws IOException, DocumentException
{
copyPdf();
}
private static void copyPdf() throws IOException, DocumentException
{
Document document = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(DEST));
document.open();
PdfContentByte cb = writer.getDirectContent();
PdfReader reader = new PdfReader(SRC);
document.newPage();
int n = reader.getNumberOfPages();
PdfDictionary page;
PdfNumber rotate;
for (int p = 1; p <= n; p++) {
page = reader.getPageN(p);
rotate = page.getAsNumber(PdfName.ROTATE);
if (rotate == null) {
page.put(PdfName.ROTATE, new PdfNumber(90));
} else {
page.put(PdfName.ROTATE, new PdfNumber((rotate.intValue() + 90) % 360));
}
}
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(DEST));
stamper.close();
PdfImportedPage ipage = writer.getImportedPage(stamper.getReader(), 1);
cb.addTemplate(ipage, 0, 0);
document.close();
}
}
As you want to enlarge the PDF anyways, I would put enlarging and rotating into one afine transformation. Thus:
PdfReader reader = new PdfReader(SOURCE);
Document document = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.getInstance(document, RESULT);
document.open();
double sqrt2 = Math.sqrt(2);
Rectangle pageSize = reader.getPageSize(1);
PdfImportedPage importedPage = writer.getImportedPage(reader, 1);
writer.getDirectContent().addTemplate(importedPage, 0, sqrt2, -sqrt2, 0, pageSize.getTop() * sqrt2, -pageSize.getLeft() * sqrt2);
document.close();
(EnlargePagePart.java)
E.g. for this page
it generates
I have a PDF form with filled out fields. If I try to read the acrofields they are empty. But in the PDF I can change the values and save them.
private static string GetFormFieldNamesWithValues(PdfReader pdfReader)
{
return string.Join("\r\n", pdfReader.AcroFields.Fields
.Select(x => x.Key + "=" +
pdfReader.AcroFields.GetField(x.Key))
.ToArray());
}
var reader = new PdfReader((DataContext as PDFContext).Datei);
AcroFields form = reader.AcroFields;
txt.Text = GetFormFieldNamesWithValues(reader);
How to read the fields?
Clearly your PDF is broken. The fields are defined as widget annotations on the page level, but they aren't referenced in the /AcroForm fields set on the document root level.
You can fix your PDF using the FixBrokenForm code sample:
PdfReader reader = new PdfReader(src);
PdfDictionary root = reader.getCatalog();
PdfDictionary form = root.getAsDict(PdfName.ACROFORM);
PdfArray fields = form.getAsArray(PdfName.FIELDS);
PdfDictionary page;
PdfArray annots;
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
page = reader.getPageN(i);
annots = page.getAsArray(PdfName.ANNOTS);
for (int j = 0; j < annots.size(); j++) {
fields.add(annots.getAsIndirectObject(j));
}
}
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
stamper.close();
reader.close();
You should inform the creators of the tool that was used to produce the form that their PDFs aren't compliant with the PDF reference.
Here is my c#-Code:
PdfReader reader = new PdfReader(src);
PdfDictionary root = reader.Catalog;
PdfDictionary form = root.GetAsDict(PdfName.ACROFORM);
PdfArray fields = form.GetAsArray(PdfName.FIELDS);
PdfDictionary page;
PdfArray annots;
for (int i = 1; i <= reader.NumberOfPages; i++)
{
page = reader.GetPageN(i);
annots = page.GetAsArray(PdfName.ANNOTS);
for (int j = 0; j < annots.Size; j++)
{
fields.Add(annots.GetAsIndirectObject(j));
}
}
PdfStamper stamper = new PdfStamper(reader, new FileStream(dest, FileMode.Create));
stamper.Close();
reader.Close();
C# version
public void FixBrokenForm(string src, string dest)
{
PdfReader reader = new PdfReader(src);
PdfDictionary root = reader.Catalog;
PdfDictionary form = root.GetAsDict(PdfName.ACROFORM);
PdfArray fields = form.GetAsArray(PdfName.FIELDS);
PdfDictionary page;
PdfArray annots;
for (int i = 1; i <= reader.NumberOfPages; i++)
{
page = reader.GetPageN(i);
annots = page.GetAsArray(PdfName.ANNOTS);
for (int j = 0; j < annots.Size; j++)
{
fields.Add(annots.GetAsIndirectObject(j));
}
}
PdfStamper stamper = new PdfStamper(reader, new FileStream(dest, FileMode.Create));
stamper.Close();
reader.Close();
}
You will need Itextsharp to make the above code work.
The answers with the FixBrokenForm code are good, but don't forget to call fields.setGenerateAppearances(true) or you'll lose the fields if you call stamper.setFormFlattening(true).
You can do like this:
PdfStamper stamper = new PdfStamper(reader, new FileStream(dest, FileMode.Create));
// Add these 2 lines ***************************
AcroFields acrofields = stamper.getAcroFields();
acrofields.setGenerateAppearances(true);
// *********************************************
stamper.Close();
reader.Close();
Is the correct way to add items to an existing PDF? The method GetFileBytes
reads a PDF from disk and converts to an array, this works fine, however the
resultant file NP.PDF is exactly the same as the original. I actually want to
add barcodes but thought to try get it working with a simple item first.
Byte[] bytes = GetFileBytes();
Document document = new Document();
MemoryStream ms = new MemoryStream(bytes);
PdfWriter writer = PdfWriter.GetInstance(document, ms);
document.Open();
document.Add(new Paragraph("First Paragraph"));
document.Add(new Paragraph("Second Paragraph"));
//document.Close();
ms.Position = 0;
File.WriteAllBytes(#"e:\NP.pdf", (Byte[])ms.ToArray());
This is how I have done it in the past. You need to use a new stream for the PDF writer, and add your original PDF contents to the new document. This may not be the best or most efficient way of performing this, it's just what I found works.
This is working with my original PDF coming from a Stream, and producing the merged output as another Stream, however you should be able to adapt it to your needs.
var originalPdfStream = GetOriginalPdfStream();
var pdfDocument = Document();
var finalPdfStream = new MemoryStream();
var pdfWriter = PdfWriter.GetInstance(pdfDocument, finalPdfStream);
pdfDocument.Open();
// Add the originalPdfStream into the pdfDocument
var originalPdfReader = new PdfReader(originalPdfStream);
AddPdf(document, writer, reader);
// Code to add other items to the pdfDocument.
pdfWriter.CloseStream = false;
pdfDocument.Close();
finalPdfStream.Position = 0;
return finalPdfStream;
The following method then takes your document and writer, and a reader to the document you want to add.
/// <summary>
/// Merge a PDF file into a PDF document.
/// </summary>
/// <param name="document">The PDF document.</param>
/// <param name="writer">The PDF writer.</param>
/// <param name="reader">A PDF reader.</param>
private static void AddPdf(Document document, PdfWriter writer, PdfReader reader)
{
if (document == null) throw new ArgumentNullException("document");
if (writer == null) throw new ArgumentNullException("writer");
if (reader == null) throw new ArgumentNullException("reader");
var numberOfPages = reader.NumberOfPages;
var originalPageSize = document.PageSize;
// Iterate through all pages
for (var currentPageIndex = 1; currentPageIndex <= numberOfPages; currentPageIndex++)
{
// Determine page size for the current page
document.SetPageSize(reader.GetPageSizeWithRotation(currentPageIndex));
// Create page
document.NewPage();
var importedPage = writer.GetImportedPage(reader, currentPageIndex);
// Determine page orientation and add page.
var pageRotation = reader.GetPageRotation(currentPageIndex);
var pageWidth = reader.GetPageSizeWithRotation(currentPageIndex).Width;
var pageHeight = reader.GetPageSizeWithRotation(currentPageIndex).Height;
switch (pageRotation)
{
case 0:
writer.DirectContent.AddTemplate(importedPage, 1f, 0, 0, 1f, 0, 0);
break;
case 90:
writer.DirectContent.AddTemplate(importedPage, 0, -1f, 1f, 0, 0, pageHeight);
break;
case 180:
writer.DirectContent.AddTemplate(
importedPage, -1f, 0, 0, -1f, pageWidth, pageHeight);
break;
case 270:
writer.DirectContent.AddTemplate(importedPage, 0, 1f, -1f, 0, pageWidth, 0);
break;
default:
throw new Exception("Unexpected page rotation: [{0}].", pageRotation);
}
}
document.SetPageSize(originalPageSize);
}
As long as the added content shall be on new pages only (as your sample code seems to indicate), you can create the additions as if creating a new intermediate PDF (if not too big, it can reside in memory) and then concatenate the PDFs using PdfCopy:
using (MemoryStream ms = new MemoryStream()) {
// step 1
using (Document document = new Document()) {
// step 2
using (PdfCopy copy = new PdfCopy(document, ms)) {
// step 3
document.Open();
// step 4
for (int i = 0; i < pdf.Count; ++i) {
PdfReader reader = ...;// retrieve a PdfReader for the i'th PDF to concatenate
// loop over the pages in that document
int n = reader.NumberOfPages;
for (int page = 0; page < n; ) {
copy.AddPage(copy.GetImportedPage(reader, ++page));
}
}
}
}
byte[] data = ms.ToArray();
...
}
(Shamelessly copied from the Webified iTextSharp Example Concatenate.cs)
If, on the other hand, you want to stamp something on an existing page, you more likely need a PdfStamper:
PdfReader reader = new PdfReader(resource);
using (var ms = new MemoryStream()) {
using (PdfStamper stamper = new PdfStamper(reader, ms)) {
PdfContentByte canvas = stamper.GetOverContent(1);
ColumnText.ShowTextAligned(
canvas,
Element.ALIGN_LEFT,
new Phrase("Hello people!"),
36, 540, 0
);
}
byte[] data = ms.ToArray();
...
}
(Also shamelessly copied from the Webified iTextSharp Example StampText.cs)
For additional background information, read the free sample chapter 6 of iText in Action — 2nd Edition.
I have a PDF file which I need to insert an image on the 1st page and then resize the original size from A4 to some other size.
I manage to add an image into the PDF but not resizing it with the following code:
string pdfFile = #"C:\Temp\a.pdf";
PdfReader reader = new PdfReader(pdfFile);
PdfStamper stamper = new PdfStamper(reader, new FileStream(#"C:\Temp\out.pdf", FileMode.Create), PdfWriter.VERSION_1_5);
PdfContentByte writer = stamper.GetOverContent(1);
stamper.FormFlattening = true;
stamper.SetFullCompression();
Image topImage = Image.GetInstance(#"C:\Temp\c.jpg");
topImage.ScalePercent(19f);
topImage.SetAbsolutePosition(142, 700);
writer.AddImage(topImage);
Document myPDF = writer.PdfDocument;
myPDF.SetPageSize(PageSize.A3);
stamper.Close();
stamper = null;
Is there anything wrong or missing in my code?
Below is how a PDF can be resized:
private string PdfResize(string tmpPdfFilename, string resultRootName)
{
try
{
string newPdfFilename = resultRootName + ".pdf";
PdfReader resizeReader = new PdfReader(tmpPdfFilename);
Rectangle newRect = new Rectangle(0, 0, Convert.ToSingle(_pdfNewSizeW), Convert.ToSingle(_pdfNewSizeH));
Document doc = new Document(newRect);
Document.Compress = true;
PdfWriter resizeWriter = PdfWriter.GetInstance(doc, new FileStream(newPdfFilename, FileMode.Create));
doc.Open();
PdfContentByte cb = resizeWriter.DirectContent;
for (int pageNumber = 1; pageNumber <= resizeReader.NumberOfPages; pageNumber++)
{
PdfImportedPage page = resizeWriter.GetImportedPage(resizeReader, pageNumber);
cb.AddTemplate(page, newRect.Width / resizeReader.GetPageSize(pageNumber).Width, 0, 0,
newRect.Height / resizeReader.GetPageSize(pageNumber).Height, 0, 0);
doc.NewPage();
}
doc.Close();
doc = null;
return newPdfFilename;
}
catch (Exception exp)
{
return String.Empty;
}
}
Despite being an older thread the original question & thread was very helpful recently.
Here's another version that processes the Pdf input as a byte array instead of file path (more helpful for web app environment), and handles all IDisposable references...
public static byte[] ResizePdfPageSize(byte[] pdfBytes, Rectangle pageSize)
{
Document.Compress = true;
using (var outputMemoryStream = new MemoryStream())
using (var targetDoc = new Document(pageSize))
using (var pdfReader = new PdfReader(pdfBytes))
using (var pdfWriter = PdfWriter.GetInstance(targetDoc, outputMemoryStream))
{
targetDoc.Open();
PdfContentByte pdfContentByte = pdfWriter.DirectContent;
var pageCount = pdfReader.NumberOfPages;
for (int pageNumber = 1; pageNumber <= pageCount; pageNumber++)
{
PdfImportedPage page = pdfWriter.GetImportedPage(pdfReader, pageNumber);
var currentPageSize = pdfReader.GetPageSize(pageNumber);
var scaledPageWidth = pageSize.Width / currentPageSize.Width;
var scaledPageHeight = pageSize.Height / currentPageSize.Height;
pdfContentByte.AddTemplate(
page,
scaledPageWidth,
0, 0,
scaledPageHeight,
0, 0
);
//Move document cursor to next Page!
targetDoc.NewPage();
}
targetDoc.Close();
byte[] finalFileBytes = outputMemoryStream.ToArray();
return finalFileBytes;
}
}
Usage with pre-set PageSizes from iTextSharp is very handy:
var originalPdfBytes = File.ReadAllBytes(fileInfo.FullName);
var resizedBytes = PdfHelper.ResizePdfPageSize(originalPdfBytes, PageSize.A4);
File.WriteAllBytes(fileName, resizedBytes);
EDIT: The above method answers the core question and got me where I needed to get for my issues. However, after working on this and ironing out numerous issues and shortcomings of the above simplified method, I've now put the whole helpful code base on github to share for anyone else interested. The github PdfHelpers project now handle aspect ratio better, page margins, rotation of content for better scaling as landscape, content that's already rotated (in my limited test cases), etc. while also providing other helpful code for simple Pdf tasks.
https://github.com/cajuncoding/PdfHelpers