I have a PDF file and I want to add a simple number on each page.
Here is my code:
reader = new PdfReader(fileOut);
Document final = new Document(reader.GetPageSize(1));
PdfWriter w = PdfWriter.GetInstance(final, new FileStream(finalFile, FileMode.Create, FileAccess.Write));
w.SetFullCompression();
final.Open();
for (int i = 1; i <= reader.NumberOfPages; i++)
{
final.NewPage();
PdfContentByte cb = w.DirectContent;
ControlNumberTimes(cb, "C"+i, 560, 725, 270, Element.ALIGN_LEFT);
cb.AddTemplate(w.GetImportedPage(reader, i), 0, 0);
}
final.Close();
reader.Close();
private static void ControlNumberTimes( PdfContentByte cb1, string control, int x, int y, int rotation, int allign )
{
cb1.BeginText();
cb1.SetColorFill(BaseColor.BLACK);
cb1.SetFontAndSize(BaseFont.CreateFont("C:\\windows\\Fonts\\times.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED), 7.5f);
cb1.ShowTextAligned(allign, control, x, y, rotation);
cb1.EndText();
}
Before adding this text, PDF file size is 3.6 Mb, after the size is 11 Mb.
What I am doing wrong?
This is my code now:
string finalFile = System.IO.Path.GetDirectoryName(fileOut) + "\\" +
System.IO.Path.GetFileNameWithoutExtension(fileOut) + "_num.pdf";
reader = new PdfReader(fileOut);
using (FileStream fs = new FileStream(finalFile, FileMode.Create, FileAccess.Write, FileShare.None))
{
using (PdfStamper stamper = new PdfStamper(reader, fs))
{
int pageCount = reader.NumberOfPages;
for (int i = 1; i <= pageCount; i++)
{
ColumnText.ShowTextAligned(stamper.GetUnderContent(i), Element.ALIGN_CENTER, new Phrase(
$"C{i}"), 560, 725, 0);
}
}
}
The pdf file I can't share due of the confidential information.
This is completely wrong:
reader = new PdfReader(fileOut);
Document final = new Document(reader.GetPageSize(1));
PdfWriter w = PdfWriter.GetInstance(final, new FileStream(finalFile, FileMode.Create, FileAccess.Write));
w.SetFullCompression();
final.Open();
for (int i = 1; i <= reader.NumberOfPages; i++)
{
final.NewPage();
PdfContentByte cb = w.DirectContent;
ControlNumberTimes(cb, "C"+i, 560, 725, 270, Element.ALIGN_LEFT);
cb.AddTemplate(w.GetImportedPage(reader, i), 0, 0);
}
final.Close();
Saying "I am copying a file using Document, PdfWriter, PdfImportedPage and AddTemplate, why does my file size increase?" is like asking "I've stabbed myself in the belly with a sharp knife, why do I bleed?"
If you want to add page numbers to an existing document, you have to use PdfStamper as explained in chapter 6 of my book.
You want to manipulate an existing PDF, more specifically, you want to add page numbers in the footer. That is done like this:
PdfReader reader = new PdfReader(outputFile);
using (FileStream fs = new FileStream(secondFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
using (PdfStamper stamper = new PdfStamper(reader, fs)) {
int PageCount = reader.NumberOfPages;
for (int i = 1; i <= PageCount; i++) {
ColumnText.ShowTextAligned(stamper.GetOverContent(i), Element.ALIGN_CENTER, new Phrase(String.Format("Page {0} of {1}", i, PageCount)), 560, 725, 270);
}
}
}
Some remarks:
You are using absolute coordinates (X = 560, Y = 725). It would be better to use coordinates relative to the page size as described in the official documentation: How to position text relative to page?
You are using BeginText() ... EndText(), but it might be easier for you to use ColumnText.ShowTextAligned().
You think you are using a font that isn't embedded when you create a BaseFont like this BaseFont.CreateFont("C:\\windows\\Fonts\\times.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED). That's not true. As documented, BaseFont.NOT_EMBEDDED is ignored when using BaseFont.IDENTITY_H. See Why is iText embedding a font even when I specify not to embed? If a small file size is desired, I suggest you don't embed the font.
The main problem with your code, is the fact that you aren't manipulating a file the correct way. I think this is caused by the fact that you copy/pasted your code from a badly written tutorial. Please don't copy code from people who don't know what they're doing.
Related
I am currently trying to iterate over an existing PDF and stamp each page with some footer text using the OnPageEnd event as detailed in the iText documentation, Chapter 5: Table, cell, and page events.
When I assign my new custom event class to the PdfCopy instance, I receive this exception:
"Operation is not valid due to the current state of the object" at
iTextSharp.text.pdf.PdfCopy.set_PageEvent(IPdfPageEvent value)
Below is the code I have written to preform the operation:
PdfReader pdf = new PdfReader(file.Value);
int pages = pdf.NumberOfPages;
pdf.SelectPages(string.Format("0 - {0}", pages));
using (MemoryStream stream = new MemoryStream())
{
Document doc = new Document();
PdfCopy copy = new PdfCopy(doc, stream) { PageEvent = new PdfFooterStamp() };
doc.Open();
for (int x = 0, y = pages; x < y; x++)
{
copy.AddPage(copy.GetImportedPage(pdf, x + 1));
}
doc.Close();
copy.Flush();
copy.Close();
collection[file.Key] = stream.ToArray();
}
And this is my custom event class definition:
public class PdfFooterStamp : PdfPageEventHelper
{
public override void OnEndPage(PdfWriter writer, Document document)
{
Rectangle rect = writer.PageSize;
ColumnText.ShowTextAligned(writer.DirectContent,
Element.ALIGN_CENTER, new Phrase("PERSONALISED DOCUMENT"),
(rect.Left + rect.Right) / 2, rect.Bottom - 18, 0);
base.OnEndPage(writer, document);
}
}
Is there anyone that might have an idea as to what might be going wrong?
Following #BrunoLowagie's advice, I went with the former option to create a PageStamp from an imported page and alter it's content as I iterated over the collection of imported PDF.
You can keep on using PdfCopy and use PageStamp to add the text to
each page that is added. Or you can create the PDF in two passes:
first create the concatenated PDF in memory with PdfCopy; then add the
footer with PdfStamper in a second pass.
The reason my previous attmepts had not worked was due to the fact that,
PdfPageEventHelper and PdfCopy are mutually exclusive. You can't
define a page event when using PdfCopy - #BrunoLowagie
The following code is an example of the preferred solution and tests have proven it to work as intended.
Document doc = new Document();
PdfCopy copy = new PdfCopy(doc, stream);
doc.Open();
for (int x = 0, y = pages; x < y; x++)
{
PdfImportedPage import = copy.GetImportedPage(pdf, x + 1);
PageStamp stamp = copy.CreatePageStamp(import);
Rectangle rect = stamp.GetUnderContent().PdfWriter.PageSize;
ColumnText.ShowTextAligned(stamp.GetUnderContent(),
Element.ALIGN_CENTER, new Phrase(User.Identity.Name, font),
(rect.Bottom + rect.Top) / 2, rect.Bottom + 8, 0);
stamp.AlterContents();
copy.AddPage(import);
}
For Bruno
{
This is not a duplicate of "I have normal PDF file, i want to insert blank pages at the end of PDF using itext LIBRARY, without disturbing the PDF contents."
I'm trying to add a blank page after each page in the source PDF - not just 1 blank page at the end of the source PDF document.
}
Using C# (NOT Java) - Does anyone know how to insert a blank page (preferably A4 - Portrait 8.5 x 11) After each page in a PDF using iTextSharp regardless of the page size and orientation of the Source PDF? Each page of the Source PDF can have a different size and orientation.
I've tried the following. It seems to make the blank page following each page the orientation and size of the Source PDF Page but the page from the Source PDF seems to be the orientation and size of the previous blank page:
private string DocumentWithBlankPagesInserted(string fileName, string userComments)
{
string outputFileName = v.tmp + #"\" + v.tmpDir + #"\" + Guid.NewGuid().ToString() + ".pdf";
Document document = new Document();
try
{
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(outputFileName, FileMode.Create));
document.Open();
PdfContentByte cb = writer.DirectContent;
PdfReader reader = new PdfReader(fileName);
for (int pageNumber = 1; pageNumber < reader.NumberOfPages + 1; pageNumber++)
{
document.SetPageSize(reader.GetPageSizeWithRotation(pageNumber));
Chunk fileRef = new Chunk();
fileRef.SetLocalDestination(fileName);
PdfImportedPage page1 = writer.GetImportedPage(reader, pageNumber);
Rectangle psize = reader.GetPageSizeWithRotation(pageNumber);
switch (psize.Rotation)
{
case 0:
cb.AddTemplate(page1, 1f, 0, 0, 1f, 0, 0);
break;
case 90:
cb.AddTemplate(page1, 0, -1f, 1f, 0, 0, psize.Height);
break;
case 180:
cb.AddTemplate(page1, -1f, 0, 0, -1f, 0, 0);
break;
case 270:
cb.AddTemplate(page1, 0, 1.0F, -1.0F, 0, psize.Width, 0);
break;
default:
break;
}
document.NewPage();
document.Add(fileRef);
document.NewPage();
}
}
catch (Exception e)
{
throw e;
}
finally
{
document.Close();
}
return outputFileName;
}
As I explained in the comments, this question is a duplicate of How to add blank pages to an existing PDF in java?
You should use PdfStamper instead of PdfWriter (this has been explained a zillion times before in different answers on StackOverflow). Using the InsertPage() method you can add pages of any size you want:
PdfReader reader = new PdfReader(src);
PdfStamper stamper=new PdfStamper(reader, new FileStream(dest, FileMode.Create));
int total = reader.NumberOfPages + 1
for (int pageNumber = total; pageNumber > 0; pageNumber--) {
stamper.InsertPage(pageNumber, PageSize.A4);
}
stamper.Close();
reader.Close();
Note that I add the pages in reverse order. This is elementary logic: adding a page changes the page count and it is harder to keep track of pageNumber if you go from page 1 to total. It's easier do go in the reverse direction.
This question already has an answer here:
Tile PDF pages vertically with iTextSharp
(1 answer)
Closed 8 years ago.
I am trying to divide a PDF into exactly 2 equal halves, saving them as "LeftPDF.pdf" and "RightPDF.pdf".
I tried the code below but it doesn't work:
PdfReader reader = new PdfReader(filepath);
int n = reader.NumberOfPages;
iTextSharp.text.Rectangle psize = reader.GetPageSize(1);
float width = psize.Width/2;
float height = psize.Height;
Document document = new Document(psize);
// target.pdf is A5 Portrait format
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(splitpath, FileMode.Create));
document.Open();
PdfContentByte cb = writer.DirectContent;
document.NewPage();
PdfImportedPage page1 =writer.GetImportedPage(reader, 1);
cb.AddTemplate(page1, 1, 0, 0, 1, 0, 0);
document.Close();
How can I do this?
As I indicated in my comment, your question has been posted and answered before. This is yet another duplicate of your question: Divide one page PDF file in two pages PDF file
Take a closer look at the TileInTwo example:
public void manipulatePdf(String src, String dest)
throws IOException, DocumentException {
// Creating a reader
PdfReader reader = new PdfReader(src);
int n = reader.getNumberOfPages();
// step 1
Rectangle mediabox = new Rectangle(getHalfPageSize(reader.getPageSizeWithRotation(1)));
Document document = new Document(mediabox);
// step 2
PdfWriter writer
= PdfWriter.getInstance(document, new FileOutputStream(dest));
// step 3
document.open();
// step 4
PdfContentByte content = writer.getDirectContent();
PdfImportedPage page;
int i = 1;
while (true) {
page = writer.getImportedPage(reader, i);
content.addTemplate(page, 0, -mediabox.getHeight());
document.newPage();
content.addTemplate(page, 0, 0);
if (++i > n)
break;
mediabox = new Rectangle(getHalfPageSize(reader.getPageSizeWithRotation(i)));
document.setPageSize(mediabox);
document.newPage();
}
// step 5
document.close();
reader.close();
}
public Rectangle getHalfPageSize(Rectangle pagesize) {
float width = pagesize.getWidth();
float height = pagesize.getHeight();
return new Rectangle(width, height / 2);
}
In this example, we ask the PdfReader instance for the page size of the first page and we create a new rectangle with the same width and only half the height.
We then import each page in the document, and we add it twice on different pages:
once on the odd pages with a negative y value to show the upper half of the original page,
once on the even pages with y = 0 to show the lower half of the original page.
As every page in the original document can have a different size, we may need to change the page size for every new couple of pages.
This example cuts a page in two with an upper part and a lower part. Use simple math and you can adapt the example to cut it in two with a left and a right part. This is done in the example TileInTwo2:
For instance:
public void manipulatePdf(String src, String dest)
throws IOException, DocumentException {
// Creating a reader
PdfReader reader = new PdfReader(src);
int n = reader.getNumberOfPages();
// step 1
Rectangle mediabox = new Rectangle(getHalfPageSize(reader.getPageSizeWithRotation(1)));
Document document = new Document(mediabox);
// step 2
PdfWriter writer
= PdfWriter.getInstance(document, new FileOutputStream(dest));
// step 3
document.open();
// step 4
PdfContentByte content = writer.getDirectContent();
PdfImportedPage page;
int i = 1;
while (true) {
page = writer.getImportedPage(reader, i);
content.addTemplate(page, 0, 0);
document.newPage();
content.addTemplate(page, -mediabox.getWidth(), 0);
if (++i > n)
break;
mediabox = new Rectangle(getHalfPageSize(reader.getPageSizeWithRotation(i)));
document.setPageSize(mediabox);
document.newPage();
}
// step 5
document.close();
reader.close();
}
public Rectangle getHalfPageSize(Rectangle pagesize) {
float width = pagesize.getWidth();
float height = pagesize.getHeight();
return new Rectangle(width / 2, height);
}
You should have no problem to adapt this example so that different PDF documents are created instead of the one containing the left and right part. If that is problematic for you, please post another question.
I have pdf files exported as legal format and want to convert them to letter format (basically shrink them), each file may have 1 to 3 pages, below is the code I tried but I have these problems:
the page size is reduced which is good, but I can't use the margin properties to put the page at the correct borders of the container (the page I kind of shrinked but drawn somewhere at the bottom of the resulted pdf file)
I couldn't increment the number of pages so the code draws both pages, one on top of the other.
Here's the code
PdfImportedPage page;
PdfReader reader = new PdfReader(#"C:\pdf\legalFormat.pdf");
Document doc = new Document(PageSize.A4, 0, 0, 0, 0);
PdfWriter writer = PdfWriter.GetInstance(doc, new FileStream(#"C:\pdf\letterFormat.PDF", FileMode.Create));
doc.Open();
PdfContentByte cb = writer.DirectContent;
for (int i = 1 ; i < reader.NumberOfPages + 1; i++){
page = writer.GetImportedPage(reader, i); // i is the number of page
float Scale = 0.67f;
cb.AddTemplate(page, Scale, 0, 0, Scale, 0, 0);
}
doc.Close();
Problem solved:
in a main proc run this for test.
string original = args[0];
string inPDF = original;
string outPDF = Directory.GetDirectoryRoot(original) + "temp.pdf";
PdfReader pdfr = new PdfReader(inPDF);
Document doc = new Document(PageSize.LETTER);
Document.Compress = true;
PdfWriter writer = PdfWriter.GetInstance(doc, new FileStream(outPDF, FileMode.Create));
doc.Open();
PdfContentByte cb = writer.DirectContent;
PdfImportedPage page;
for (int i = 1; i < pdfr.NumberOfPages + 1; i++)
{
page = writer.GetImportedPage(pdfr, i);
cb.AddTemplate(page, PageSize.LETTER.Width / pdfr.GetPageSize(i).Width, 0, 0, PageSize.LETTER.Height / pdfr.GetPageSize(i).Height, 0, 0);
doc.NewPage();
}
doc.Close();
//just renaming, conversion / resize process ends at doc.close() above
File.Delete(original);
File.Copy(outPDF, original);
Hi
I want to add a text in persian language (a right to left language) to the top of an existing pdf file, using iTextSharp Version 5.0.0.0 library.
I use this code:
public static void InsertText(string SourceFileName, string TargetFileName, string Text, int x, int y)
{
PdfReader reader = new PdfReader(SourceFileName);
Document document = new Document(PageSize.A4, 0, 0, 0, 0); // open the writer
FileStream fs = new FileStream(TargetFileName, FileMode.Create, FileAccess.Write);
PdfWriter writer = PdfWriter.GetInstance(document, fs);
document.Open();
PdfContentByte cb = writer.DirectContent; // select the font properties
FontFactory.RegisterDirectories();
Font fTahoma = FontFactory.GetFont("Tahoma", BaseFont.IDENTITY_H, 10, Font.NORMAL, BaseColor.RED);
writer.SetMargins(0, 0, 0, 0);
ColumnText ct = new ColumnText(writer.DirectContent);
ct.RunDirection = PdfWriter.RUN_DIRECTION_RTL;
Phrase p = new Phrase(Text, fTahoma);
ct.SetText(p);
ct.SetSimpleColumn(x, y, x + 350, y + 20);
ct.Go();
for (int i = 1; i <= reader.NumberOfPages; i++)
{
PdfImportedPage page = writer.GetImportedPage(reader, i);
cb.AddTemplate(page, 0, 0); // close the streams and voilá the file should be changed :)
document.NewPage();
}
document.Close();
fs.Close();
writer.Close();
}
I call InsertText("Source.pdf", "Target.pdf", "Persian message", 10, 800);
My source.pdf page size is: height: 842, width: 595
Unfortunately i get target.pdf with only half of my message! The other vertical half is hidden!
Now the question is: How i can add a right to left language text to the top of an existing pdf file?
Problem: The imported page is probably overwriting the text.
Solution: Add your PdfImportedPage, THEN add the text.