itext7 CopyPagesTo not opening PDF - c#

I am trying to add a Cover Page PDF file to another PDF file. I am using CopyPagesTo method. CoverPageFilePath will go before any pages in the pdfDocumentFile. I then need to rewrite that new file to the same location. When I run the code and open the new pdf file I get an error about it being damaged.
public static void iText7MergePDF()
{
byte[] modifiedPdfInBytes = null;
string pdfCoverPageFilePath = #"PathtoCoverPage\Cover Page.pdf";
PdfDocument pdfDocumentCover = new PdfDocument(new iText.Kernel.Pdf.PdfReader(pdfCoverPageFilePath));
string pdfDocumentFile =#"PathtoFullDocument.pdf";
var buffer = File.ReadAllBytes(pdfDocumentFile);
using (var originalPdfStream = new MemoryStream(buffer))
using (var modifiedPdfStream = new MemoryStream())
{
var pdfReader = new iText.Kernel.Pdf.PdfReader(originalPdfStream);
var pdfDocument = new PdfDocument(pdfReader, new PdfWriter(modifiedPdfStream));
int numberOfPages = pdfDocumentCover.GetNumberOfPages();
pdfDocumentCover.CopyPagesTo(1, numberOfPages, pdfDocument);
modifiedPdfInBytes = modifiedPdfStream.ToArray();
pdfDocument.Close();
}
System.IO.File.WriteAllBytes(pdfGL, modifiedPdfInBytes);
}

Whenever you have some other type, like a StreamWriter, or here a PdfWriter writing to a Stream, it may not write all the data to the Stream immediately.
Here you Close the pdfDocument for all the data to be written to the MemoryStream.
ie this
modifiedPdfInBytes = modifiedPdfStream.ToArray();
pdfDocument.Close();
Should be
pdfDocument.Close();
modifiedPdfInBytes = modifiedPdfStream.ToArray();

Related

iTextSharp (version 4.1.6) - add text/table at top of existing PDF

I have a pdf document (created by iTextSharp - free version 4.1.6) and I want to add text / table at the top of this pdf. I have tried to create two memory streams from iTextSharp Documents and combine them to one, see my code below. But the new PDF file cannot be opened. Any ideas what I am doing wrong? Any other ideas to add text / table at the top of an existing PDF? Thanks in advance!
public void CreateTestPDF(string _pathOfOriginalPDF, string _pathOfModifiedPDF)
{
string oldFile = _pathOfOriginalPDF;
string newFile = pathOfModifiedPDF;
byte[] bytesHeader;
byte[] bytesBody;
byte[] bytesCombined;
using (MemoryStream ms = new MemoryStream())
{
Document doc = new Document();
doc.Open();
doc.Add(new Paragraph("This is my header paragraph"));
if (doc.IsOpen())
{
doc.Close();
}
bytesHeader = ms.ToArray();
}
using (MemoryStream ms = new MemoryStream())
{
Document doc = new Document();
//doc.Open();
PdfWriter writer = PdfWriter.GetInstance(doc, new FileStream(oldFile, FileMode.Create));
if (doc.IsOpen())
{
doc.Close();
}
bytesBody = ms.ToArray();
}
IEnumerable<byte> iCombined = bytesHeader.Concat(bytesBody);
bytesCombined = iCombined.ToArray();
string testFile = _pathOfModifiedPDF;
using (FileStream fs = File.Create(testFile))
{
fs.Write(bytesBody, 0, (int)bytesBody.Length);
}
}

How to Create a pdf using syncfusion in c# .net

I am trying to create a pdf with syncfusion and using the example shown on this link:
https://www.syncfusion.com/kb/10673/how-to-create-a-pdf-document-in-aws-lambda
I have created a small console app and I am having issues reading the data on the line with the HELP comment. It is looking for a path rather than reading the string as shown in the example link.
Anyone who has used similar who can suggest a fix? Thanks
using System;
using Syncfusion.Pdf;
using Syncfusion.Pdf.Graphics;
using Syncfusion.Drawing;
using System.IO;
using System.Text.Json;
using Newtonsoft.Json;
namespace pdf
{
class Program
{
static void Main(string[] args)
{
var result = GetData();
var stream = new StreamReader(result); //----> How do I read this? HELP
JsonReader reader = new JsonTextReader(stream);
var serilizer = new Newtonsoft.Json.JsonSerializer();
var responseText = serilizer.Deserialize(reader);
//Convert Base64String into PDF document
byte[] bytes = Convert.FromBase64String(responseText.ToString());
FileStream fileStream = new FileStream("Sample.pdf", FileMode.Create);
BinaryWriter writer = new BinaryWriter(fileStream);
writer.Write(bytes, 0, bytes.Length);
writer.Close();
System.Diagnostics.Process.Start("Sample.pdf");
}
static string GetData()
{
//Create a new PDF document
PdfDocument document = new PdfDocument();
//Add a page to the document
PdfPage page = document.Pages.Add();
//Create PDF graphics for the page
PdfGraphics graphics = page.Graphics;
//Set the standard font
PdfFont font = new PdfStandardFont(PdfFontFamily.Helvetica, 20);
//Draw the text
graphics.DrawString("Hello World!!!", font, PdfBrushes.Black, new PointF(0, 0));
string imagePath = Path.GetFullPath(#"Data\logo.png");
//Load the image from the disk
FileStream imageStream = new FileStream(imagePath, FileMode.Open, FileAccess.Read);
PdfBitmap image = new PdfBitmap(imageStream);
//Draw the image
graphics.DrawImage(image, 30, 30, 100, 25);
//Save the document into stream
MemoryStream stream = new MemoryStream();
//Save the PDF document
document.Save(stream);
document.Close();
return (Convert.ToBase64String(stream.ToArray()));
}
}
}
What about returing directly the stream by GetData method and pass the stream to StreamReader.
static Stream GetData()
{
...
// remove return (Convert.ToBase64String(stream.ToArray()));
return stream;
}

iText7 create a document from IFormFile

I want to insert image to the user upload file, when I tried to create pdfDocument from the stream I got the "You can't read from OutputStream" error
public ActionResult GetTemplate(IFormFile template)
{
byte[] pdfBytes;
using (var memoryStream = new MemoryStream())
{
template.CopyTo(memoryStream);
var writer = new PdfWriter(memoryStream);
PdfDocument pdfDocument = new PdfDocument(new PdfReader(memoryStream));
var document = new Document(pdfDocument);
var pageCount = pdfDocument.GetNumberOfPages();
ImageData imageData = ImageDataFactory.CreatePng(System.Convert.FromBase64String(//));
var img = new Image(imageData).Scale(200, 100).SetFixedPosition(pageCount, 50, 120);
document.Add(img);
document.Close();
pdfBytes = memoryStream.ToArray();
}
return new FileContentResult(pdfBytes, "application/pdf");
}
If I changed it to new PdfDocument(new PdfReader(writer)); I got "PDF header not found" error instead.
This is my first time using iText, most of the answers I found on their website only worked with java. Any suggestion or help would be great, thank you for your time.

Generate one pdf document with multiple pages converting from html using IText 7

I'm working with IText 7, I've been able to get one html page and generate a pdf for that page, but I need to generate one pdf document from multiple html pages and separated by pages. For example: I have Page1.html, Page2.html and Page3.html. I will need a pdf document with 3 pages, the first page with the content of Page1.html, second page with the content of Page2.html and like that...
This is the code I have and it's working for one html page:
ConverterProperties properties = new ConverterProperties();
PdfWriter writer = new PdfWriter(pdfRoot, new WriterProperties().SetFullCompressionMode(true));
PdfDocument pdfDocument = new PdfDocument(writer);
pdfDocument.AddEventHandler(PdfDocumentEvent.END_PAGE, new HeaderPdfEventHandler());
HtmlConverter.ConvertToPdf(htmlContent, pdfDocument, properties);
Is it possible to loop against the multiple html pages, add a new page to the PdfDocument for every html page and then have only one pdf generated with one page per html page?
UPDATE
I've been following this example and trying to translate it from Java to C#, I'm trying to use PdfMerger and loop around the html pages... but I'm receiving the Exception Cannot access a closed stream, on this line:
temp = new PdfDocument(
new PdfReader(new RandomAccessSourceFactory().CreateSource(baos), rp));
It looks like is related to the ByteArrayOutputStream baos instance. Any suggestions? This is my current code:
foreach (var html in htmlList)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfDocument temp = new PdfDocument(new PdfWriter(baos));
HtmlConverter.ConvertToPdf(html, temp, properties);
ReaderProperties rp = new ReaderProperties();
temp = new PdfDocument(
new PdfReader(new RandomAccessSourceFactory().CreateSource(baos), rp));
merger.Merge(temp, 1, temp.GetNumberOfPages());
temp.Close();
}
pdfDocument.Close();
You are using RandomAccessSourceFactory and passing there a closed stream which you wrote a PDF document into. RandomAccessSourceFactory expects an input stream instead that is ready to be read.
First of all you should use MemoryStream which is native to .NET world. ByteArrayOutputStream is the class that was ported from Java for internal purposes (although it extends MemoryStream as well). Secondly, you don't have to use RandomAccessSourceFactory - there is a simpler way.
You can create a new MemoryStream instance from the bytes of the MemoryStream that you used to create a temporary PDF with the following line:
baos = new MemoryStream(baos.ToArray());
As an additional remark, it's better to close PdfMerger instance directly instead of closing the document - closing PdfMerger closes the underlying document as well.
All in all, we get the following code that works:
foreach (var html in htmlList)
{
MemoryStream baos = new MemoryStream();
PdfDocument temp = new PdfDocument(new PdfWriter(baos));
HtmlConverter.ConvertToPdf(html, temp, properties);
ReaderProperties rp = new ReaderProperties();
baos = new MemoryStream(baos.ToArray());
temp = new PdfDocument(new PdfReader(baos, rp));
pdfMerger.Merge(temp, 1, temp.GetNumberOfPages());
temp.Close();
}
pdfMerger.Close();
Maybe not so succinctly. I use "using". Similar answer
private byte[] CreatePDF(string html)
{
byte[] binData;
using (var workStream = new MemoryStream())
{
using (var pdfWriter = new PdfWriter(workStream))
{
//Create one pdf document
using (var pdfDoc = new PdfDocument(pdfWriter))
{
pdfDoc.SetDefaultPageSize(iText.Kernel.Geom.PageSize.A4.Rotate());
//Create one pdf merger
var pdfMerger = new PdfMerger(pdfDoc);
//Create two identical pdfs
for (int i = 0; i < 2; i++)
{
using (var newStream = new MemoryStream(CreateDocument(html)))
{
ReaderProperties rp = new ReaderProperties();
using (var newPdf = new PdfDocument(new PdfReader(newStream, rp)))
{
pdfMerger.Merge(newPdf, 1, newPdf.GetNumberOfPages());
}
}
}
}
binData = workStream.ToArray();
}
}
return binData;
}
Create pdf
private byte[] CreateDocument(string html)
{
byte[] binData;
using (var workStream = new MemoryStream())
{
using (var pdfWriter = new PdfWriter(workStream))
{
using (var pdfDoc = new PdfDocument(pdfWriter))
{
pdfDoc.SetDefaultPageSize(iText.Kernel.Geom.PageSize.A4.Rotate());
ConverterProperties props = new ConverterProperties();
using (var document = HtmlConverter.ConvertToDocument(html, pdfDoc, props))
{
}
}
binData = workStream.ToArray();
}
}
return binData;
}

itextsharp PDF concatenation not working

i have a webapi where i have route to concatenate pdfs and return the byte array using memorystream
public HttpResponseMessage ConcatPDFs(string id, ICollection<int> pdfs) {
using (var db = new ApplicationDbContext())
using (MemoryStream stream = new MemoryStream())
using (Document doc = new Document())
using (PdfCopy pdf = new PdfCopy(doc, stream))
{
doc.Open();
PdfReader reader = null;
PdfImportedPage page = null;
db.PDFForms.Where(p => pdfs.Contains(p.Id)).ToList().ForEach(file =>
{
var filePath = Path.Combine(System.Web.Hosting.HostingEnvironment.MapPath("~/" + string.Format("Content/Uploads/PDFForms/")), file.FileName);
reader = new PdfReader(filePath);
for (int i = 0; i < reader.NumberOfPages; i++)
{
page = pdf.GetImportedPage(reader, i + 1);
pdf.AddPage(page);
}
pdf.FreeReader(reader);
reader.Close();
});
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new ByteArrayContent(stream.ToArray());
result.Content.Headers.ContentType =
new MediaTypeHeaderValue(string.Format("{0}", "application/pdf"));
return result;
}
}
this is my code, however when i stream the data back to the client the browser give me the error, failed to load pdf document. Any idea what i might be doing wrong? thank you.
Edit:
This works if i create a physical file and not use MemoryStream
Perhaps you can debug your application using wireshark?
Get the bytes from the response, paste them in a document and see whether that document can be read with something like Adobe Reader.
From the looks of it though, this does not seem like an iText issue, since you have confirmed that you can create a physical file.
So either it is the implementation of MemoryStream, or some other step that comes in between the creation of the document and sending the get response.
At any rate, I think the first step in solving this problem is storing the bytes you do get back, and comparing them against the physical file.

Categories

Resources