I have the code that I use to add(print) a pdf document inside another with other valuable infos that I need, recently I realized that this won't work with a pdf that has editable fields, the pdf will print but not the filled fields, the first idea that came to my mind was to convert each pdf page to image then print the image to the pdf, I started searching on this but still I couldn't make this work yet, do you guys have any ideas on how i could make this work?
This is some part of my code..
public static void AttachPdfDocument(DruckKontext<DruckDatenOhneErgebnis> druckKontext, string pdfBaseString, string docName,
Dictionary<string, List<KeyValuePair<string, string>>> fieldNamesAndValues)
{
try
{
PdfReader reader = new PdfReader(Convert.FromBase64String(pdfBaseString));
PdfReader.unethicalreading = true;
PdfWriter writer = druckKontext.Writer;
PdfContentByte canvas = writer.DirectContent;
for (int p = 1; p <= reader.NumberOfPages; p++)
{
PdfImportedPage page = canvas.PdfWriter.GetImportedPage(reader, p);
canvas.AddTemplate(page, (PageSize.A4.Width / page.Width) * 0.7, 0, 0, (PageSize.A4.Height / page.Height) * 0.7, 85, BeratungsdokuStyle.DruckhöheMin + 20);
if (p < reader.NumberOfPages)
{
druckKontext.NewPageBeratungsdokumentation();
}
}
}
}
Printed pdf
PDF with editable fields
Related
I have a .pdf document which has for example 7 pages. I split this document into 7 .pdf document, so it means that each document has only one page. But mainly I need to make fit the content of pages. So delete whitespaces, margins, resize. Have you got some simple advice? I add links for images and also code for split pdf document. Thank you for your response.
INPUT:
DESIRED OUTPUT:
CODE:
public void PdfSplitDocument(string filename)
{
String path = "C:/Doc/" + filename;
String result = "d:/output/result";
PdfCopy copy;
PdfReader reader = new PdfReader(path);
for (int i = 1; i <= reader.NumberOfPages; i++)
{
Document document = new Document(PageSize.A4, 0, 0, 0, 0);
copy = new PdfCopy(document, new FileStream(result + i + ".pdf", FileMode.Create));
document.Open();
copy.AddPage(copy.GetImportedPage(reader, i));
document.Close();
}
}
Take a look at the ShowTextMargins example. It uses the TextMarginFinder class to find the margins within which text is found. In this example, taken from my book "iText in Action - Second Edition", I use this class to draw a rectangle:
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();
}
In your case, you want to crop the pages based on the rectangle. You have a finder object that allows you to get the coordinate of the lower-left corner (llx and lly) and the coordinate of the upper-right corner (urx and ury). You can use these coordinates to crop pages as is done in the CropPages example:
public void manipulatePdf(String src, String dest)
throws IOException, DocumentException {
PdfReader reader = new PdfReader(src);
int n = reader.getNumberOfPages();
PdfDictionary pageDict;
PdfRectangle rect = new PdfRectangle(llx, lly, urx, ury);
for (int i = 1; i <= n; i++) {
pageDict = reader.getPageN(i);
pageDict.put(PdfName.CROPBOX, rect);
}
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
stamper.close();
reader.close();
}
Another option is to change the media box instead of the crop box:
pageDict.put(PdfName.MEDIABOX, rect);
The C# version of these examples can be found here:
ShowTextMargins
CropPages
I'm using iTextSharp to handle pdf files. I'd like to know how I can split a page in half and make 2 different pages from the two pieces. I tried a lot but nothing seems to work right now.
First try
iTextSharp.text.Rectangle size = new iTextSharp.text.Rectangle(0, pdfReader.GetPageSize(1).Height / 2, pdfReader.GetPageSize(1).Width, 0);
Second try
iTextSharp.text.Rectangle size = pdfReader.GetPageSizeWithRotation(1);
iTextSharp.text.Document document = new iTextSharp.text.Document(size.GetRectangle(0, size.Height / 2));
And several others. The results are always the same: I have a file with just the second half of the original page.
I don't understand your code snippets, but then again: probably you don't understand them either, so let's not look at what you've written so far, and let's 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.
I'm creating an application for Windows 8.1 in C#. Into Windows.Data.Pdf i've found how use PDF files in my application. But i want to know if i can split one A3 page to multiple PDF files ?
You don't want to split a page, you want to tile it.
This is explained in Chapter 6 of my book (section 6.2.3). Take a look at the TilingHero example (Java / C#). In this example, one large page (hero.pdf) is split into a PDF with several A4 pages (superman.pdf).
This is some code:
PdfReader reader = new PdfReader(resource);
Rectangle pagesize = reader.GetPageSizeWithRotation(1);
using (Document document = new Document(pagesize)) {
// step 2
PdfWriter writer = PdfWriter.GetInstance(document, ms);
// step 3
document.Open();
// step 4
PdfContentByte content = writer.DirectContent;
PdfImportedPage page = writer.GetImportedPage(reader, 1);
// adding the same page 16 times with a different offset
float x, y;
for (int i = 0; i < 16; i++) {
x = -pagesize.Width * (i % 4);
y = pagesize.Height * (i / 4 - 3);
content.AddTemplate(page, 4, 0, 0, 4, x, y);
document.NewPage();
}
}
The math is valid for an A0 page. You need to adapt it for an A3 page (meaning: the math you need is way easier to do).
You need to calculate pagesize so that it results in smaller pages, and then use something like this:
using (Document document = new Document(pagesize)) {
// step 2
PdfWriter writer = PdfWriter.GetInstance(document, ms);
// step 3
document.Open();
// step 4
PdfContentByte content = writer.DirectContent;
PdfImportedPage page = writer.GetImportedPage(reader, 1);
// adding the same page 16 times with a different offset
float x, y;
for (int i = 0; i < 16; i++) {
x = -pagesize.Width * (i % 4);
y = pagesize.Height * (i / 4 - 3);
content.AddTemplate(page, x, y); // we don't scale anymore
document.NewPage();
}
}
Here is known code that splits PDF document:
try
{
FileInfo file = new FileInfo(#"d:\С.pdf");
string name = file.Name.Substring(0, file.Name.LastIndexOf("."));
// we create a reader for a certain document
PdfReader reader = new PdfReader(#"d:\С.pdf");
// we retrieve the total number of pages
int n = reader.NumberOfPages;
int digits = 1 + (n / 10);
System.Console.WriteLine("There are " + n + " pages in the original file.");
Document document;
int pagenumber;
string filename;
for (int i = 0; i < n; i++)
{
pagenumber = i + 1;
filename = pagenumber.ToString();
while (filename.Length < digits) filename = "0" + filename;
filename = "_" + filename + ".pdf";
// step 1: creation of a document-object
document = new Document(reader.GetPageSizeWithRotation(pagenumber));
// step 2: we create a writer that listens to the document
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(name + filename, FileMode.Create));
// step 3: we open the document
document.Open();
PdfContentByte cb = writer.DirectContent;
PdfImportedPage page = writer.GetImportedPage(reader, pagenumber);
int rotation = reader.GetPageRotation(pagenumber);
if (rotation == 90 || rotation == 270)
{
cb.AddTemplate(page, 0, -1f, 1f, 0, 0, reader.GetPageSizeWithRotation(pagenumber).Height);
}
else
{
cb.AddTemplate(page, 1f, 0, 0, 1f, 0, 0);
}
// step 5: we close the document
document.Close();
}
}
catch (DocumentException de)
{
System.Console.Error.WriteLine(de.Message);
}
catch (IOException ioe)
{
System.Console.Error.WriteLine(ioe.Message);
}
Here is left top corner of one splitted page:
You can see here (and in other corners) unexpected lines,rounds.. How can I avoid them?
As explained many times before (ITextSharp include all pages from the input file, Itext pdf Merge : Document overflow outside pdf (Text truncated) page and not displaying, and so on), you should read chapter 6 of my book iText in Action (you can find the C# version of the examples here).
You are using a combination of Document, PdfWriter and PdfImportedPage to split a PDF. Please tell me who made you do it this way, so that I can curse the person who inspired you (because I've answered this question hundreds of times before, and I'm getting tired of repeating myself). These classes aren't a good choice for that job:
you lose all interactivity,
you need to rotate the content yourself if the page is in landscape (you already discovered this),
you need to take the original page size into account,
...
Your problem is similar to this one Itext pdf Merge : Document overflow outside pdf (Text truncated) page and not displaying. Apparently the original document you're trying to split contains a MediaBox and a CropBox. When you look at your original document, only the content inside the CropBox is shown. When you look at your copy, the content inside the MediaBox is shown, unveiling "printer marks". These printer marks show where the page needs to be cut in a publishing environment. When printing books or magazines, the pages on which content is printed are usually bigger than the final page. The extra content is cut off before assembling the book or magazine.
Long story short: read the documentation, replace PdfWriter with PdfCopy, replace AddTemplate() with AddPage().
So, I'm having this problem using C# (.NET 4.0 + WinForms) and iTextSharp 5.1.2.
I have some scanned images stored on a DB and need to build on the fly PDF with those images. Some files have just one page and other ones hundreds. That is working just fine using:
foreach (var page in pages)
{
Image pageImage = Image.GetInstance(page.Image);
pageImage.ScaleToFit(document.PageSize.Width,document.PageSize.Height);
pageImage.Alignment = Image.ALIGN_TOP | Image.ALIGN_CENTER;
document.Add(pageImage);
document.NewPage();
//...
}
The problem is:
I need to add an small table at the bottom of the last page.
I try:
foreach (var page in pages)
{
Image pageImage = Image.GetInstance(page.Image);
pageImage.ScaleToFit(document.PageSize.Width,document.PageSize.Height);
pageImage.Alignment = Image.ALIGN_TOP | Image.ALIGN_CENTER;
document.Add(pageImage);
document.NewPage();
//...
}
Table t = new table....
document.Add(t);
The table is successfully added but IF the size of the image fits the page size of the document then the table is added on the next page.
I need to resize the last image of the document (if it has multiple ones, or the first if has only 1) in order to put the table directly on that page (with the image) and that both ocuppy just one page.
I try to scale the image by percent BUT given that the image size of the image that'll be on the last page is unknow and that it must FILL the biggest portion of the page I need to do that dinamically.
Any idea?
Let me give you a couple of things that might help you and then I'll give you a full working example that you should be able to customize.
The first thing is that the PdfPTable has a special method called WriteSelectedRows() that allows you to draw a table at an exact x,y coordinate. It has six overloads but the most commonly used one is probably:
PdfPTable.WriteSelectedRows(int rowStart,int rowEnd, float xPos, float yPos, PdfContentByte canvas)
To place a table with the upper left corner positioned at 400,400 you would call:
t.WriteSelectedRows(0, t.Rows.Count, 400, 400, writer.DirectContent);
Before calling this method you are required to set the table's width using SetTotalWidth() first:
//Set these to your absolute column width(s), whatever they are.
t.SetTotalWidth(new float[] { 200, 300 });
The second thing is that the height of the table isn't known until the entire table is rendered. This means that you can't know exactly where to place a table so that it truly is at the bottom. The solution to this is to render the table to a temporary document first and then calculate the height. Below is a method that I use to do this:
public static float CalculatePdfPTableHeight(PdfPTable table)
{
using (MemoryStream ms = new MemoryStream())
{
using (Document doc = new Document(PageSize.TABLOID))
{
using (PdfWriter w = PdfWriter.GetInstance(doc, ms))
{
doc.Open();
table.WriteSelectedRows(0, table.Rows.Count, 0, 0, w.DirectContent);
doc.Close();
return table.TotalHeight;
}
}
}
}
This can be called like this:
PdfPTable t = new PdfPTable(2);
//In order to use WriteSelectedRows you need to set the width of the table
t.SetTotalWidth(new float[] { 200, 300 });
t.AddCell("Hello");
t.AddCell("World");
t.AddCell("Test");
t.AddCell("Test");
float tableHeight = CalculatePdfPTableHeight(t);
So with all of that here's a full working WinForms example targetting iTextSharp 5.1.1.0 (I know you said 5.1.2 but this should work just the same). This sample looks for all JPEGs in a folder on the desktop called "Test". It then adds them to an 8.5"x11" PDF. Then on the last page of the PDF, or if there's only 1 JPEG to start with on the only page, it expands the height of the PDF by however tall the table that we're adding is and then places the table at the bottom left corner. See the comments in the code itself for further explanation.
using System;
using System.Text;
using System.Windows.Forms;
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.IO;
namespace Full_Profile1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public static float CalculatePdfPTableHeight(PdfPTable table)
{
//Create a temporary PDF to calculate the height
using (MemoryStream ms = new MemoryStream())
{
using (Document doc = new Document(PageSize.TABLOID))
{
using (PdfWriter w = PdfWriter.GetInstance(doc, ms))
{
doc.Open();
table.WriteSelectedRows(0, table.Rows.Count, 0, 0, w.DirectContent);
doc.Close();
return table.TotalHeight;
}
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
//Create our table
PdfPTable t = new PdfPTable(2);
//In order to use WriteSelectedRows you need to set the width of the table
t.SetTotalWidth(new float[] { 200, 300 });
t.AddCell("Hello");
t.AddCell("World");
t.AddCell("Test");
t.AddCell("Test");
//Calculate true height of the table so we can position it at the document's bottom
float tableHeight = CalculatePdfPTableHeight(t);
//Folder that we are working in
string workingFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Test");
//PDF that we are creating
string outputFile = Path.Combine(workingFolder, "Output.pdf");
//Get an array of all JPEGs in the folder
String[] AllImages = Directory.GetFiles(workingFolder, "*.jpg", SearchOption.TopDirectoryOnly);
//Standard iTextSharp PDF init
using (FileStream fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write, FileShare.None))
{
using (Document document = new Document(PageSize.LETTER))
{
using (PdfWriter writer = PdfWriter.GetInstance(document, fs))
{
//Open our document for writing
document.Open();
//We do not want any margins in the document probably
document.SetMargins(0, 0, 0, 0);
//Declare here, init in loop below
iTextSharp.text.Image pageImage;
//Loop through each image
for (int i = 0; i < AllImages.Length; i++)
{
//If we only have one image or we are on the second to last one
if ((AllImages.Length == 1) | (i == (AllImages.Length - 1)))
{
//Increase the size of the page by the height of the table
document.SetPageSize(new iTextSharp.text.Rectangle(0, 0, document.PageSize.Width, document.PageSize.Height + tableHeight));
}
//Add a new page to the PDF
document.NewPage();
//Create our image instance
pageImage = iTextSharp.text.Image.GetInstance(AllImages[i]);
pageImage.ScaleToFit(document.PageSize.Width, document.PageSize.Height);
pageImage.Alignment = iTextSharp.text.Image.ALIGN_TOP | iTextSharp.text.Image.ALIGN_CENTER;
document.Add(pageImage);
//If we only have one image or we are on the second to last one
if ((AllImages.Length == 1) | (i == (AllImages.Length - 1)))
{
//Draw the table to the bottom left corner of the document
t.WriteSelectedRows(0, t.Rows.Count, 0, tableHeight, writer.DirectContent);
}
}
//Close document for writing
document.Close();
}
}
}
this.Close();
}
}
}
EDIT
Below is an edit based on your comments. I'm only posting the contents of the for loop which is the only part that changed. When calling ScaleToFit you just need to take tableHeight into account.
//Loop through each image
for (int i = 0; i < AllImages.Length; i++)
{
//Add a new page to the PDF
document.NewPage();
//Create our image instance
pageImage = iTextSharp.text.Image.GetInstance(AllImages[i]);
//If we only have one image or we are on the second to last one
if ((AllImages.Length == 1) | (i == (AllImages.Length - 1)))
{
//Scale based on the height of document minus the table height
pageImage.ScaleToFit(document.PageSize.Width, document.PageSize.Height - tableHeight);
}
else
{
//Scale normally
pageImage.ScaleToFit(document.PageSize.Width, document.PageSize.Height);
}
pageImage.Alignment = iTextSharp.text.Image.ALIGN_TOP | iTextSharp.text.Image.ALIGN_CENTER;
document.Add(pageImage);
//If we only have one image or we are on the second to last one
if ((AllImages.Length == 1) | (i == (AllImages.Length - 1)))
{
//Draw the table to the bottom left corner of the document
t.WriteSelectedRows(0, t.Rows.Count, 0, tableHeight, writer.DirectContent);
}
}
Just use a method table.CalculateHeights() if you want to know the height of table.