I have PDF where some of the text are very closed to the left and right border and I would like to add more white space at the border, top bottom left and right, for each pages in the PDF using iTextSharp.
Is this possible using iTextSharp or there is a better way?
I managed to find the answer. The code below adjusts the size of the pages:
var inputPdf = new PdfReader(inputFile); // Get input document
int pageCount = inputPdf.NumberOfPages;
if (end < start || end > pageCount)
end = pageCount;
var inputDoc = new Document(inputPdf.GetPageSizeWithRotation(1));
using (var fs = new FileStream(outputFile, FileMode.Create))
{
var outputWriter = PdfWriter.GetInstance(inputDoc, fs);
inputDoc.Open();
PdfContentByte cb1 = outputWriter.DirectContent;
// Copy pages from input to output document
for (int i = start; i <= end; i++)
{
var existingRec = inputPdf.GetPageSizeWithRotation(i);
var newRec = new Rectangle(0.0f, 0.0f, existingRec.Width + 50, existingRec.Height + 25, 0);
inputDoc.SetPageSize(newRec);
inputDoc.NewPage();
PdfImportedPage page = outputWriter.GetImportedPage(inputPdf, i);
int rotation = inputPdf.GetPageRotation(i);
if (rotation == 90 || rotation == 270)
cb1.AddTemplate(page, 0, -1f, 1f, 0, 0, inputPdf.GetPageSizeWithRotation(i).Height);
else cb1.AddTemplate(page, 1f, 0, 0, 1f, 25, 13);
}
inputDoc.Close();
}
Hope this helps someone.
Related
I am using this code to merge a pdf file to the start of pdf but want to set it to the 2nd page of existing pdf.
How do I do that ? How to go with this?
I have spent days on it but no luck.
public static string MergeFiles(string destinationFile, string[] sourceFiles)
{
try
{
string NewFileName = "InspectionReport" + DateTime.Now.ToString("ddMMMyyyy HHmmss").Replace(" ", "");
destinationFile = HostingEnvironment.MapPath(#"/Downloads/Files/" + NewFileName + ".pdf");
int f = 0;
PdfReader reader = new PdfReader(sourceFiles[f]);
int n = reader.NumberOfPages;
Document document = new Document(reader.GetPageSizeWithRotation(1));
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(destinationFile, FileMode.Create));
document.Open();
PdfContentByte cb = writer.DirectContent;
PdfImportedPage page;
int rotation;
while (f < sourceFiles.Length)
{
int i = 0;
while (i < n)
{
i++;
document.SetPageSize(reader.GetPageSizeWithRotation(i));
document.NewPage();
page = writer.GetImportedPage(reader, i);
rotation = reader.GetPageRotation(i);
if (rotation == 90 || rotation == 270)
{
cb.AddTemplate(page, 0, -1f, 1f, 0, 0, reader.GetPageSizeWithRotation(i).Height);
}
else
{
cb.AddTemplate(page, 1f, 0, 0, 1f, 0, 0);
}
}
f++;
if (f < sourceFiles.Length)
{
reader = new PdfReader(sourceFiles[f]);
n = reader.NumberOfPages;
}
}
document.Close();
}
catch (Exception e)
{
string strOb = e.Message;
}
return destinationFile;
}
Now, it only appends at the top and I can think of no way of adding to the 2nd page of the existing pdf.
I am trying to merge two PDF in this method but after successfully adding, I am unable to convert iTextSharp.text.Document into byte array . Please help me.
protected byte[] MergePDFs(byte[] First, byte[] Second, string RptTitle)
{
iTextSharp.text.Document doc = new iTextSharp.text.Document();
iTextSharp.text.pdf.PdfReader reader = null;
int numberOfPages = 0;
int currentPageNumber = 0;
iTextSharp.text.pdf.PdfWriter writer = iTextSharp.text.pdf.PdfWriter.GetInstance(doc, MemStream);
doc.Open();
iTextSharp.text.pdf.PdfContentByte cb = writer.DirectContent;
iTextSharp.text.pdf.PdfImportedPage page = null;
//Third, append all the PDFs--THIS IS THE MAGIC PART
if (First != null)
{
reader = new iTextSharp.text.pdf.PdfReader(First);
numberOfPages = reader.NumberOfPages;
currentPageNumber = 0;
while ((currentPageNumber < numberOfPages))
{
currentPageNumber += 1;
doc.SetPageSize(iTextSharp.text.PageSize.A4);
doc.NewPage();
page = writer.GetImportedPage(reader, currentPageNumber);
//we know that the page would always be in Potrait Format
cb.AddTemplate(page, 1f, 0, 0, 1f, 0, 1);
}
}
if (Second != null)
{
reader = new iTextSharp.text.pdf.PdfReader(Second);
numberOfPages = reader.NumberOfPages;
currentPageNumber = 0;
while ((currentPageNumber < numberOfPages))
{
currentPageNumber += 1;
doc.SetPageSize(iTextSharp.text.PageSize.A4.Rotate());
//.Rotate());
doc.NewPage();
page = writer.GetImportedPage(reader, currentPageNumber);
//we know that the page would always be in LandScape Format
// cb.AddTemplate(page,0, -1f, 1f, 0,0, reader.GetPageSizeWithRotation(currentPageNumber).Height+300);
cb.AddTemplate(page, 1, 0, 0, 1, 0, 0);
}
}
doc.Close();
byte[] cc = StringToByteArray(doc.ToString());
return cc;
I don't know where you people get this examples, they are completely wrong.
First, use PdfCopy, not PdfWriter. That way the correct page size and orientation will be correctly imported.
Second, if your MemStream is a MemoryStream you would use MemStream.ToArray() to get the PDF bytes.
PS: Where did that invention of doc.ToString() come from? It's completely rubbish.
I am using acrobat 8.0 professional for cropping text from a PDF.
One page of Original pdf is
After cropping pdf above page is
In mine project i am using cropped pdf and extract individual pages from it by following code
private void ExtractPages(string inputFile, string outputFile, int start, int end)
{
// get input document
PdfReader inputPdf = new PdfReader(inputFile);
// retrieve the total number of pages
int pageCount = inputPdf.NumberOfPages;
if (end < start || end > pageCount)
{
end = pageCount;
}
//var pgSize = new iTextSharp.text.Rectangle(myWidth, myHeight);
//var doc = new iTextSharp.text.Document(pgSize, leftMargin, rightMargin, topMargin, bottomMargin);
// load the input document
Document inputDoc = new Document(inputPdf.GetPageSizeWithRotation(1));
// create the filestream
using (FileStream fs = new FileStream(outputFile, FileMode.Create))
{
// create the output writer
PdfWriter outputWriter = PdfWriter.GetInstance(inputDoc, fs);
inputDoc.Open();
PdfContentByte cb1 = outputWriter.DirectContent;
// copy pages from input to output document
for (int i = start; i <= end; i++)
{
inputDoc.SetPageSize(inputPdf.GetPageSizeWithRotation(i));
inputDoc.NewPage();
PdfImportedPage page = outputWriter.GetImportedPage(inputPdf, i);
int rotation = inputPdf.GetPageRotation(i);
if (rotation == 90 || rotation == 270)
{
cb1.AddTemplate(page, 0, -1f, 1f, 0, 0, inputPdf.GetPageSizeWithRotation(i).Height);
}
else
{
cb1.AddTemplate(page, 1f, 0, 0, 1f, 0, 0);
}
}
inputDoc.Close();
}
}
Problem is that after page extraction cropping information is not retained in extracted pdf. Extracted pdf is same as original pdf with extra text in it.
How to retained cropped information in extracted pdf ?
I have the following simplified code for pulling existing 8x10 PDFs from multiple locations, rotating them if need be (almost all need to be), then writing them to a single 11x17 PDF page by page...
while (Page < StackOne.Length)
{
Files++;
using (var strm = new FileStream(RenderPath + "Test_" + Page + ".pdf", FileMode.Create, FileAccess.Write, FileShare.Read))
{
using (var MasterReport = new iTextSharp.text.Document(iTextSharp.text.PageSize._11X17))
{
using (var writer = PdfWriter.GetInstance(MasterReport, strm))
{
MasterReport.Open();
MasterReport.NewPage();
var cb = writer.DirectContent;
for (; Page <= NumPages * Files && Page < StackOne.Length; Page++)
{
var ProductionEntry = StackOne[Page - 1];
var filepath = NetPath + ProductionEntry.UniqueProductId + ".pdf";
if (File.Exists(filepath))
{
var reader = new PdfReader(filepath);
var pagesize = reader.GetPageSize(1);
if (pagesize.Height > pagesize.Width)
{
var ExistingPage = reader.GetPageN(1);
var rotation = ExistingPage.GetAsNumber(PdfName.ROTATE);
int desiredrot = 90;
if (rotation != null)
{
desiredrot += rotation.IntValue;
desiredrot %= 360;
}
ExistingPage.Put(PdfName.ROTATE, new PdfNumber(desiredrot));
}
cb.AddTemplate(writer.GetImportedPage(reader, 1), 50, 50);
}
MasterReport.NewPage();
}
}
}
}
}
However the page rendered doesn't have the pages rotated as they should be, I've verified the height > width branch is indeed being taken but the pages returned are still 8x10 instead of 10x8 written on each 11x17 page.
I searched around for a question this specific but couldn't find one that wasn't just writing to another file or the entire page instead of to a specific location on an 11x17 sheet.
EDIT: So with a little experimenting and looking at other examples I'm able to rotate the 8x10 page and write it to my 11x17 but unfortunately I can't seem to find a way to place it exactly where I want it here's the relevant code snippet:
var reader = new PdfReader(filepath);
var tm = new AffineTransform(1.0F, 0, 0, 1.0F, x, y);
if (reader.GetPageSize(1).Height > reader.GetPageSize(1).Width)
tm.SetTransform(0, -1f, 1f, 0, 0, reader.GetPageSize(1).Height);
writer.DirectContent.AddTemplate(writer.GetImportedPage(reader, 1), tm);
Okay so after tons of searching and sifting through code it appears the answer was quite simple (as usual), as shown above my initial problem was putting a rotate tag on the page didn't actually rotate the page as I expected. After learning about the option of specifying a matrix for the pdftemplate it was pretty simple here's the working code:
var reader = new PdfReader(filepath);
var tm = new AffineTransform();
if (reader.GetPageSize(1).Height > reader.GetPageSize(1).Width)
tm.SetTransform(0, -1f, 1f, 0, 0, reader.GetPageSize(1).Height);
tm.Concatenate(new AffineTransform(1f, 0, 0, 1f, y, x));
writer.DirectContent.AddTemplate(writer.GetImportedPage(reader, 1), tm);
P.S. http://partners.adobe.com/public/developer/en/pdf/PDFReference.pdf P: 162 (143 in physical form) for those who aren't fresh out of algebra
EDIT: As #mkl has stated below the following is really only applicable for rotate entries of 0° or 90° if you have pages at 180° or 270° this code will need some modifications. Also any annotations in the original will be lost.
You may simple add affine transform into AddTemplate procedure.
Like this:
PdfContentByte cb = stamper.getOverContent(pageNumber);
int rotation = reader.getPageRotation(pageNumber);
PdfImportedPage page = stamper.getImportedPage(reader, pageNumber);
if (rotation == 270)
cb.addTemplate(page, 0, 1f, -1f, 0, reader.getPageSizeWithRotation(pageNumber).getWidth(), 0);
else if (rotation == 90) {
cb.addTemplate(page, 0, -1f, 1f, 0, 0, reader.getPageSizeWithRotation(pageNumber).getHeight());
} else {
cb.addTemplate(page, 0, 0);
}
Its java, but I think it is not a problem.
So, I'm trying to simply add a text annotation to a pdf at the top left corner of a pdf document. Current code is like this:
public static byte[] StampPDFDocument(byte[] pdf, string stampString) {
using (var ms = new MemoryStream()) {
var reader = new iTextSharp.text.pdf.PdfReader(pdf);
var stamper = new iTextSharp.text.pdf.PdfStamper(reader, ms);
var box = reader.GetCropBox(1);
var left = box.Left;
var top = box.Top;
iTextSharp.text.Rectangle newRectangle = new iTextSharp.text.Rectangle(left + 20, top - 20, left + 250, top - 40);
var pcb = new iTextSharp.text.pdf.PdfContentByte(stamper.Writer);
pcb.SetColorFill(iTextSharp.text.BaseColor.RED);
var annot = iTextSharp.text.pdf.PdfAnnotation.CreateFreeText(stamper.Writer, newRectangle, stampString, pcb);
annot.Flags = iTextSharp.text.pdf.PdfAnnotation.FLAGS_PRINT;
annot.BorderStyle = new iTextSharp.text.pdf.PdfBorderDictionary(0, 0);
stamper.AddAnnotation(annot, 1);
stamper.Close();
return ms.ToArray();
}
}
Now, original code was just using box = reader.GetPageSize(1). Well, that I soon realized causes problems if the document has been rotated. Ok. No problem, there is a function called reader.GetPageSizeWithRotation. That worked like a charm. However, now I'm getting documents that have a different cropbox. So the annotation that I was adding was outside the cropbox area. So this current code only works for non rotated documents. The question is, how does one get the top left corener in a pdf document regardless of whether the document is rotated or contains a different cropbox than the document?
Here's what I ended up with.
public static byte[] StampPDFDocument(byte[] pdf, string stampString) {
using (var ms = new MemoryStream()) {
var reader = new iTextSharp.text.pdf.PdfReader(pdf);
var stamper = new iTextSharp.text.pdf.PdfStamper(reader, ms);
int rotation = reader.GetPageRotation(1);
var box = reader.GetPageSizeWithRotation(1);
var cropbox = reader.GetCropBox(1);
float left = cropbox.Left;
float top = cropbox.Top;
if (rotation == 90) {
left = cropbox.Bottom;
top = box.Height - cropbox.Left;
cropbox = new iTextSharp.text.Rectangle(left, top, left + cropbox.Height, top - cropbox.Width);
}
else if (rotation == 180) {
left = box.Width - cropbox.Left - cropbox.Width;
top = box.Height - cropbox.Bottom;
cropbox = new iTextSharp.text.Rectangle(left, top, left + cropbox.Width, top - cropbox.Height);
}
else if (rotation == 270) {
left = box.Width - cropbox.Top;
top = cropbox.Right;
cropbox = new iTextSharp.text.Rectangle(left, top, left + cropbox.Height, top - cropbox.Width);
}
iTextSharp.text.Rectangle newRectangle = new iTextSharp.text.Rectangle(left + 20, top - 20, left + 250, top - 40);
var pcb = new iTextSharp.text.pdf.PdfContentByte(stamper.Writer);
pcb.SetColorFill(iTextSharp.text.BaseColor.RED);
var annot = iTextSharp.text.pdf.PdfAnnotation.CreateFreeText(stamper.Writer, newRectangle, stampString, pcb);
annot.Flags = iTextSharp.text.pdf.PdfAnnotation.FLAGS_PRINT;
annot.Rotate = reader.GetPageRotation(1);
annot.BorderStyle = new iTextSharp.text.pdf.PdfBorderDictionary(0, 0);
stamper.AddAnnotation(annot, 1);
stamper.Close();
return ms.ToArray();
}
}
Here's the source for getPageSizeWithRotation:
public Rectangle getPageSizeWithRotation(int index) {
return getPageSizeWithRotation(pageRefs.getPageNRelease(index));
}
public Rectangle getPageSizeWithRotation(PdfDictionary page) {
Rectangle rect = getPageSize(page);
int rotation = getPageRotation(page);
while (rotation > 0) {
rect = rect.rotate();
rotation -= 90;
}
return rect;
}
So all you need to do to roll your own is to write a function that calls getCropBox() instead of getPageSize().
PS: getCropBox() will return the media box if there's no crop box, so you don't have to call getCropBox and getPageSize separately.