iTextSharp creation of a pdf from a list of byte arrays
I've got a list of byte[] which i'd like to concatenate into one byte[] which will be the final PDf.
On the "page = copy.GetImportedPage(new PdfReader(p), i); " i'm getting an "object reference not set to an instance error.
I've got no clue of what's going on, i've already checked every object and there's no null.
Any ideas on this, or another piece of code that could make the trick?!
I've got this method:
EDIT
public static byte[] concatAndAddContent(List<byte[]> pdf)
{
byte [] todos;
using(MemoryStream ms = new MemoryStream())
{
Document doc = new Document();
doc.Open();
PdfCopy copy = new PdfCopy(doc, ms);
PdfCopyFields copy2 = new PdfCopyFields(ms);
PdfReader reader;
foreach (byte[] p in pdf)
{
reader = new PdfReader(p);
int pages = reader.NumberOfPages;
// loop over document pages
for (int i = 1; i < pages; i++)
{
PdfImportedPage page = copy.GetImportedPage(reader, i);
PdfCopy.PageStamp stamp = copy.CreatePageStamp(page);
PdfContentByte cb = stamp.GetUnderContent();
cb.SaveState();
stamp.AlterContents();
copy.AddPage(page);
}
}
doc.Close();
todos = ms.GetBuffer();
ms.Flush();
ms.Dispose();
}
return todos;
}
Stack Trace:
[NullReferenceException: Object reference not set to an instance of an object.]
iTextSharp.text.pdf.PdfImportedPage..ctor(PdfReaderInstance readerInstance, PdfWriter writer, Int32 pageNumber) +45
开发者_如何学Python iTextSharp.text.pdf.PdfReaderInstance.GetImportedPage(Int32 pageNumber) +175
iTextSharp.text.pdf.PdfCopy.GetImportedPage(PdfReader reader, Int32 pageNumber) +256
SAM.Web.Classes.UtileriasReportes.concatAndAddContent(List`1 pdf) in \Classes\UtileriasReportes.cs:199
SAM.Web.Classes.UtileriasReportes.ObtenReporteOdt(Int32 ordenTrabajoID, Boolean caratula, Boolean juntas, Boolean cortes, Boolean materiales, Boolean resumenMateriales)
in D:\MIMOSS\Desarrollo\SAM 2.0\Desarrollo\WebSolution\SAM.Web\Classes\UtileriasReportes.cs:168
SAM.Web.Produccion.PopupImpresionOdt.btnImprimir_Click(Object sender, EventArgs e) in \PopupImpresionOdt.aspx.cs:44
System.Web.UI.WebControls.Button.OnClick(EventArgs e) +118
System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +112
System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +10
System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +13
System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +36
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +5563
thanks for your time!
I've figured it out, just so everbody can have the solution: here it is:
public static byte[] concatAndAddContent(List<byte[]> pdf)
{
byte [] all;
using(MemoryStream ms = new MemoryStream())
{
Document doc = new Document();
PdfWriter writer = PdfWriter.GetInstance(doc, ms);
doc.SetPageSize(PageSize.LETTER);
doc.Open();
PdfContentByte cb = writer.DirectContent;
PdfImportedPage page;
PdfReader reader;
foreach (byte[] p in pdf)
{
reader = new PdfReader(p);
int pages = reader.NumberOfPages;
// loop over document pages
for (int i = 1; i <= pages; i++)
{
doc.SetPageSize(PageSize.LETTER);
doc.NewPage();
page = writer.GetImportedPage(reader, i);
cb.AddTemplate(page, 0, 0);
}
}
doc.Close();
all = ms.GetBuffer();
ms.Flush();
ms.Dispose();
}
return all;
}
Hope that helps!
This works:
used iTextSharp-LGPL 4.1.6:
public static byte[] ConcatenatePdfs(IEnumerable<byte[]> documents)
{
using (var ms = new MemoryStream())
{
var outputDocument = new Document();
var writer = new PdfCopy(outputDocument, ms);
outputDocument.Open();
foreach (var doc in documents)
{
var reader = new PdfReader(doc);
for (var i = 1; i <= reader.NumberOfPages; i++)
{
writer.AddPage(writer.GetImportedPage(reader, i));
}
writer.FreeReader(reader);
reader.Close();
}
writer.Close();
outputDocument.Close();
var allPagesContent = ms.GetBuffer();
ms.Flush();
return allPagesContent;
}
}
This solution works in iText 7.1.8:
It is based in previous answers and the new API Examples
public static byte[] MergePDFs(List<byte[]> lPdfByteContent)
{
using (MemoryStream oMemoryStream = new MemoryStream())
{
using (PdfWriter oWriter = new PdfWriter(oMemoryStream))
{
oWriter.SetSmartMode(true);
using (PdfDocument oMergedPdf = new PdfDocument(oWriter))
{
PdfMerger oMerger = new PdfMerger(oMergedPdf, false, false);
for (int i = 0; i < lPdfByteContent.Count; i++)
{
PdfDocument oPdfAux = new PdfDocument(new PdfReader(new MemoryStream(lPdfByteContent[i])));
oMerger.SetCloseSourceDocuments(true).Merge(oPdfAux, 1, oPdfAux.GetNumberOfPages());
}
}
}
return oMemoryStream.ToArray();
}
}
Not sure if this will fix it for you, but try initializing GetImportedPage starting at page 1, not zero but usng int i = 1
in your for loop. Like this:
// loop over document pages
//was (int i = 0; i < pages; i++) {
for (int i = 1; i < pages; i++) {
page = copy.GetImportedPage(new PdfReader(p), i);
stamp = copy.CreatePageStamp(page);
PdfContentByte cb = stamp.GetUnderContent();
cb.SaveState();
stamp.AlterContents();
copy.AddPage(page);
}
Looking though the itextsharp code its possible that it doesn't always work well with multiple readers on the same content.
I suggest you try
page = copy.GetImportedPage(reader, i);
rather than create a new reader for each page you're trying to read.
UPDATE: I don't know if the helps but
I copied and pasted your code and I get a NullReferenceException but only on this line
stamp.AlterContents();
Which is strange because that's after where you are getting it.+
When passing in bad contents in the List I was able to produce Missing PDF header, Trailer Not found etc., so I don't think its a difference in the content of p
I'm using version 5.0.4 with the source code version built in VS 2008. The client is vs 2010. Perhaps these account for the difference.
I had initially used the answer above and the PDF's were very large.. I thought it would be helpful to come back and offer up this link which completely solved this issue along with the LARGE PDF issue for me.
https://stackoverflow.com/a/6752769
精彩评论