I made some file merging using PDFsharp before, and now I'm trying to change several files (insert or remove some pages) and I faced with problem, that the library does not see pages. It says that PageCount == 0 and I cannot find pages in object (while debugging). And sure, I cannot do my current work. I use this very simple code:
var destinationPdf = new PdfDocument(destinationFilePath);
Int32 count = destinationPdf.PageCount;
And also, here is the code, that I used to merge files to one PDF before:
public class PdfCreator
{
private PdfDocument document;
public PdfCreator()
{
this.document = new PdfDocument();
}
public void AddImage(String imageFilePath)
{
PdfPage newPage = this.document.AddPage();
XGraphics xGraphics = XGraphics.FromPdfPage(newPage);
XImage image = XImage.FromFile(imageFilePath);
xGraphics.DrawImage(image, 0, 0);
}
public void AddPdfFile(String pdfFilePath)
{
PdfDocument inputDocument = PdfReader.Open(pdfFilePath, PdfDocumentOpenMode.Import);
Int32 count = inputDocument.PageCount;
for (Int32 currentPage = 0; currentPage < count; currentPage++)
{
PdfPage page = inputDocument.Pages[currentPage];
this.document.AddPage(page);
}
}
public void AddTextFile(String txtFilePath)
{
PdfPage newPage = this.document.AddPage();
XGraphics xGraphics = XGraphics.FromPdfPage(newPage);
var xFont = new XFont("Times New Roman", 12, XFontStyle.Bold);
var xTextFormatter = new XTextFormatter(xGraphics);
var rect = new XRect(30, 30, 540, 740);
xGraphics.DrawRectangle(XBrushes.Transparent, rect);
xTextFormatter.Alignment = XParagraphAlignment.Left;
xTextFormatter.DrawString(File.ReadAllText(txtFilePath), xFont, XBrushes.Black, rect, XStringFormats.TopLeft);
}
public void Save(String destinationFilePath)
{
if (this.document.Pages.Count > 0)
{
this.document.Save(destinationFilePath);
this.document.Close();
}
}
}
Your code
var destinationPdf = new PdfDocument(destinationFilePath);
Int32 count = destinationPdf.PageCount;
creates a new document in memory - and surely this document is empty.
Use PdfReader.Open to create a document in memory from an existing file.
When I place the mouse cursor over PdfDocument in your code I get this tooltip:
Creates a new PDF document with the specified file name. The file is
immediately created and keeps locked until the document is closed, at
that time the document is saved automatically. Do not call Save() for
documents created with this constructor, just call Close(). To open an
existing PDF file and import it, use the PdfReader class.
Related
I have 3 PDFs, I want to add the pages from them to an output PDF file. What I’m trying to do is: import first PDF -> create new PDF document -> add pages -> draw in certain page and finally I want to add the pages from that document to the main PDF document that will be exported. Proceed to do the same with the second PDF file if needed.
ERROR: A PDF document must be opened with PdfDocumentOpenMode.Import to import pages from it.
From the main class I call the method that processes the PDF:
Pdftest pdftest = new Pdftest();
PdfDocument pdf = PdfReader.Open(#"C:\Users\pdf_file.pdf", PdfDocumentOpenMode.Import);
pdftest.CreatePages(pdf_file);
Pdftest class:
public class Pdftest
{
PdfDocument PDFNewDoc = new PdfDocument();
XFont fontChico = new XFont("Verdana", 8, XFontStyle.Bold);
XFont fontGrande = new XFont("Verdana", 12, XFontStyle.Bold);
XBrush fontBrush = XBrushes.Black;
public void CreatePages(PdfDocument archivoPdf)
{
PdfDocument NuevoDoc = new PdfDocument();
for (int Pg = 0; Pg < archivoPdf.Pages.Count; Pg++)
{
PdfPage pp = NuevoDoc.AddPage(archivoPdf.Pages[Pg]);
}
XGraphics Graficador = XGraphics.FromPdfPage(NuevoDoc.Pages[0]);
XPoint coordinate = new XPoint();
coordinate.X = XUnit.FromInch(1.4);
coordinate.Y = XUnit.FromInch(1.8);
graficador.DrawString("TEST", fontChico, fontBrush, coordinates);
for (int Pg = 0; Pg < NuevoDoc.Pages.Count; Pg++)
{
PdfPage pp = PDFNewDoc.AddPage(NuevoDoc.Pages[Pg]); //Error mentioned.
}
}
}
The error message relates to NuevoDoc. You have to save NuevoDoc in a MemoryStream and re-open it in Import mode to get your code going.
I do not understand why you try to copy pages from NuevoDoc to PDFNewDoc- so most likely you can avoid the MemoryStream when optimising the code.
I am trying to overlay two PDF files using iText7/C#.
The first one is kind of background and the second one is containing form fields.
Everything works fine and only problem is that I lose fonts from the second file.
I try as follows:
static public bool Overlay(string back_path, string front_path, string merge_path)
{
PdfReader reader;
PdfDocument pdf = null, front;
try
{
reader = new PdfReader(back_path);
pdf = new PdfDocument(reader, new PdfWriter(merge_path));
front = new PdfDocument(new PdfReader(front_path));
var form = PdfAcroForm.GetAcroForm(front, false);
PdfAcroForm dform = PdfAcroForm.GetAcroForm(pdf, true);
IDictionary<String, PdfFormField> fields = form.GetFormFields();
// copy styles
dform.SetDefaultResources(form.GetDefaultResources());
dform.SetDefaultAppearance(form.GetDefaultAppearance().GetValue());
// do overlay
foreach (KeyValuePair<string, PdfFormField> pair in fields)
{
try
{
var field = pair.Value;
PdfPage page = field.GetWidgets().First().GetPage();
int pg_no = front.GetPageNumber(page);
if (pg_no < front_start_page || pg_no > front_end_page)
continue;
PdfObject copied = field.GetPdfObject().CopyTo(pdf, true);
PdfFormField copiedField = PdfFormField.MakeFormField(copied, pdf);
// The following returns null. If it returns something, I think I could use copiedField.setFont(font).
// var font = field.GetFont();
dform.AddField(copiedField, pdf.GetPage(pg_no));
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Overlaying field {pair.Key} failed. ({ex.Message})");
}
}
pdf.Close();
return true;
}
catch (Exception ex)
{
throw new OverlayException(ex.Message);
}
}
public static PdfDictionary get_font_dict(PdfDocument pdfDoc)
{
PdfDictionary acroForm = pdfDoc.GetCatalog().GetPdfObject().GetAsDictionary(PdfName.AcroForm);
if (acroForm == null)
{
return null;
}
PdfDictionary dr = acroForm.GetAsDictionary(PdfName.DR);
if (dr == null)
{
return null;
}
PdfDictionary font = dr.GetAsDictionary(PdfName.Font);
return font;
}
So basically I get all fonts from the second PDF and copy them to the final PDF.
But it does not work.
Logically, I think setting font of the original field to the copied one is the right way.
I mean PdfFormField.GetFont() and SetFont().
But it always returns null.
In a comment you clarified:
the background PDF can be assumed not to have form fields or annotations. I mean we can assume background PDF only contains static content (scanned form) and the front PDF only contains formfields.
In that case the easiest way to implement your method is to add the background as xobject to the form PDF instead of adding the form to the background PDF.
You can simply do that like this:
PdfReader formReader = new PdfReader(front_path);
PdfReader backReader = new PdfReader(back_path);
PdfWriter writer = new PdfWriter(merge_path);
using (PdfDocument source = new PdfDocument(backReader))
using (PdfDocument target = new PdfDocument(formReader, writer))
{
PdfFormXObject xobject = source.GetPage(1).CopyAsFormXObject(target);
PdfPage targetFirstPage = target.GetFirstPage();
PdfStream stream = targetFirstPage.NewContentStreamBefore();
PdfCanvas pdfCanvas = new PdfCanvas(stream, targetFirstPage.GetResources(), target);
Rectangle cropBox = targetFirstPage.GetCropBox();
pdfCanvas.AddXObject(xobject, cropBox.GetX(), cropBox.GetY());
}
Depending on the exact static contents of the background and the form PDF, you might want to use NewContentStreamAfter instead of NewContentStreamBefore or even to use some nifty blend mode to get the exact static content look you want.
I am trying to add two pages in one document. These two pages are generated from HTML.
Info : HTML Renderer for PDF using PDFsharp, HtmlRenderer.PdfSharp 1.5.0.6
var config = new PdfGenerateConfig
{
PageOrientation = PageOrientation.Portrait,
PageSize = PageSize.A4,
MarginBottom = 0,
MarginLeft = 0,
MarginRight = 0,
MarginTop = 0
};
string pdfFirstPage = CreateHtml();
string pdfsecondPage = CreateHtml2();
PdfDocument doc=new PdfDocument();
doc.AddPage(new PdfPage(PdfGenerator.GeneratePdf(pdfFirstPage, config)));
doc.AddPage(new PdfPage(PdfGenerator.GeneratePdf(pdfsecondPage, config)));
I tried few ways, but the most given error is Import Mode. This is the last test, but it is not successful .How can I combine two pages generated from HTML strings as 2 pages in 1 document and download it?
Here is code that works:
static void Main(string[] args)
{
PdfDocument pdf1 = PdfGenerator.GeneratePdf("<p><h1>Hello World</h1>This is html rendered text #1</p>", PageSize.A4);
PdfDocument pdf2 = PdfGenerator.GeneratePdf("<p><h1>Hello World</h1>This is html rendered text #2</p>", PageSize.A4);
PdfDocument pdf1ForImport = ImportPdfDocument(pdf1);
PdfDocument pdf2ForImport = ImportPdfDocument(pdf2);
var combinedPdf = new PdfDocument();
combinedPdf.Pages.Add(pdf1ForImport.Pages[0]);
combinedPdf.Pages.Add(pdf2ForImport.Pages[0]);
combinedPdf.Save("document.pdf");
}
private static PdfDocument ImportPdfDocument(PdfDocument pdf1)
{
using (var stream = new MemoryStream())
{
pdf1.Save(stream, false);
stream.Position = 0;
var result = PdfReader.Open(stream, PdfDocumentOpenMode.Import);
return result;
}
}
I save the PDF document to a MemoryStream and open them for import. This allows to add the pages to a new PdfDocument. Only the first page of the documents is used for simplicity - add loops as needed.
For the past week or so this exception is causing me a headache, I can't for the life of me fix it. I'm using iTextSharp to merge PDF files and add a watermark on them if the user chooses to do so.
Here's the code for merging :
private void CreateMergedPdf(object sender, DoWorkEventArgs e)
{
using (FileStream stream = new FileStream(pdfname, FileMode.Create)) {
Document pdfDoc = new Document(PageSize.A4);
PdfCopy pdf = new PdfCopy(pdfDoc, stream);
pdfDoc.Open();
int i = 0;
foreach (File_class newpdf in AddedPDFs)
{
(sender as BackgroundWorker).ReportProgress(i++);
if (newpdf.toMerge)
{
PdfReader reader = new PdfReader(newpdf.file_path);
pdf.AddDocument(reader); //<!> Exception here
this.Dispatcher.Invoke(() => progBtxt.Text = "Merging file #" + newpdf.file_id + "..."); //Dispatcher.Invoke since UI is on seperate thread
if (add_wtrmk)//This is called for every FILE
{
AddWatermark(reader, stream);
}
}
}
}
}
And here's the code for the watermark:
private void AddWatermark(PdfReader reader, FileStream stream)
{
using (PdfStamper pdfStamper = new PdfStamper(reader, stream))//This is called for every PAGE of the file
{
for (int pgIndex = 1; pgIndex <= reader.NumberOfPages; pgIndex++)
{
Rectangle pageRectangle = reader.GetPageSizeWithRotation(pgIndex);
PdfContentByte pdfData; //Contains graphics and text content of page returned by pdfstamper
if (this.Dispatcher.Invoke(() => dropdown.Text == "Under Content"))
{
pdfData = pdfStamper.GetUnderContent(pgIndex);
}
else if (this.Dispatcher.Invoke(() => dropdown.Text == "Over Content"))
{
pdfData = pdfStamper.GetOverContent(pgIndex);
}
else//Just in case
{
MessageBox.Show("Something went wrong when adding the watermark");
return;
}
//Set font
pdfData.SetFontAndSize(BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 40);
//Create new graphics state and assign opacity
PdfGState graphicsState = new PdfGState();
graphicsState.FillOpacity = 0.25F;
//Set graphics state to pdfcontentbyte
pdfData.SetGState(graphicsState);
//Color of watermark
pdfData.SetColorFill(BaseColor.GRAY);
pdfData.BeginText();
//Show text as per position and rotation
this.Dispatcher.Invoke(() => pdfData.ShowTextAligned(Element.ALIGN_CENTER, WtrmkTextbox.Text, pageRectangle.Width / 2, pageRectangle.Height / 2, 45));
pdfData.EndText();
}
}
}
The error appears on the code for merging, specifically the line " pdf.AddDocument(reader);" BUT I get this error only if I try to add watermarks on more than one files (with just one file it works perfectly).
I'm thinking either I am closing something too early, or addWatermark() does - I've tried changing our the using statemets to no avail. I must be missing something
Okay, it seems PdfStamper was the culprit, i passed the necessary arguements to AddWatermark() and added a simple if statement. Now everything works perfectly.
BIG thanks to Mark Rucker
I'm using iTextSharp 5.5 to construct PDF documents. The documents start with text information and end with imported JPEG images and multi-page PDF files. Some of the PDFs contain annotations, specifically 3D models.
Edit (3/21/2014): Here is a complete, simplified example that illustrates what I'm trying to accomplish, and where the error occurs in AddPdf().
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
namespace PdfTest
{
class Program
{
private const string path = "w:\\tmp\\pdf";
static void Main(string[] args)
{
using (var ms = new MemoryStream())
{
var document = new Document(PageSize.LETTER, 40, 40, 30, 30);
var writer = PdfWriter.GetInstance(document, ms); // Without this, I get a zero-length file
document.Open();
AddText(document, "TEST");
AddImage(document, Path.Combine(path, "import1.jpg"));
AddPdf(document, ms, Path.Combine(path, "import2.pdf"));
document.Close();
File.WriteAllBytes(Path.Combine(path, "test.pdf"), ms.ToArray());
}
}
private static void AddText(Document document, string text)
{
document.Add(new Paragraph(text, FontFactory.GetFont(FontFactory.HELVETICA_BOLD, 12f)));
}
private static void AddImage(Document document, string sourcePath)
{
var pic = Image.GetInstance(sourcePath);
var maxWidth = document.PageSize.Width - 72f;
var maxHeight = document.PageSize.Height - 150f;
if (pic.Width > maxWidth || pic.Height > maxHeight)
{
pic.ScaleToFit(maxWidth, maxHeight);
}
document.NewPage();
document.Add(pic);
}
private static void AddPdf(Document document, Stream stream, string sourcePath)
{
var copy = new PdfCopy(document, stream);
// Read the source PDF
var reader = new PdfReader(sourcePath);
var pageCount = reader.NumberOfPages;
// Import each page
for (var i = 0; i < pageCount; i++)
{
var pageNum = i + 1;
document.SetPageSize(reader.GetPageSizeWithRotation(pageNum));
document.NewPage(); // <--- "Document is not open" error here
var page = copy.GetImportedPage(reader, pageNum);
copy.AddPage(page);
}
}
}
}
What is the correct way to construct a document by adding elements and imported pages?