Creating a PDF using Xamarin Android - c#

I am trying to create a PDF document that can then be open via an external application. The user is selecting an arbitrary number of images which are stored in a List<byte[]>. Disregarding this, I cannot get the following to even create a blank PDF that can be opened. If I try opening the generated PDF, Adobe Reader says that the file has is not supported or has been damaged. I am not sure where the error is occurring since the PDF seems to be generated. I would imagine the problem occurs when trying to write the PDF to the FileStream. What is the issue with the following code?
private void CreatePDFWithImages(List<byte[]> images)
{
// create PDF
PdfDocument pdf = new PdfDocument();
// create a page description
PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(612, 792, 0).Create();
// draw image to pag
for (int i = 0; i < images.Count; i++)
{
// start page
PdfDocument.Page page = pdf.StartPage(pageInfo);
// create bitmap from each byte[]
byte[] currentByteArray = images[i];
Android.Graphics.BitmapFactory.Options options = new Android.Graphics.BitmapFactory.Options();
options.InMutable = true;
Android.Graphics.Bitmap bitmap = Android.Graphics.BitmapFactory.DecodeByteArray(currentByteArray, 0, currentByteArray.Length, options);
// matrix
Android.Graphics.Matrix matrix = new Android.Graphics.Matrix();
matrix.PreTranslate(300, 300);
matrix.PreScale(2, 2);
// add image to the page
page.Canvas.DrawBitmap(bitmap, matrix, null);
// finish the page
pdf.FinishPage(page);
}
// save PDF
string path = "/mnt/shared/POC_Documents/temp.pdf";
FileStream fileStream = new FileStream(path, FileMode.Create);
pdf.WriteTo(fileStream);
// close PDF
pdf.Close();
// try to open...
this.OpenPDF(path);
}

In the pageInfo you have to pass page number as 1 instead of 0
and
If you add
fileStream.flush();
after this line
pdf.WriteTo(fileStream);
It will create the pdf

Related

How to add an image to whole page with iText 7 C#

I have a .png files which are size of A4. I am adding them to the .pdf. It is working but my image is not covering all .pdf document page and it is leaving the white edges around it. How to cover whole page with my image?
String dest = "C:\\ImagePaged.pdf";
PdfWriter writer = new PdfWriter(dest);
// Creating a PdfDocument
PdfDocument pdfDoc = new PdfDocument(writer);
// Creating a Document
iText.Layout.Document document2 = new iText.Layout.Document(pdfDoc);
// process and save pages one by one
for (int i = 0; i < 10; i++) //count of .png images
{
iText.IO.Image.ImageData imageData = iText.IO.Image.ImageDataFactory.Create($"C:\\ImagePage{i}.png");
Image image = new Image(imageData);
document2.Add(image);
}
document2.Close();
I guess I need somehow to set page edge parameters. But how to do that.
Pretty sure it is this one
pdfDoc.SetMargins(0, 0, 0, 0);

PDFium - create PDF document from image stream without converting to Bitmap in c#

I am working with PDFium c# tool to create PDF document from PNG image stream.
I have an API which gets multiple image stream objects, I should combine the image streams and create a PDF document and PDF stream. I will need to hit another API to save this document.
I went through the PDFium documentation but, the examples shows how load PDF from Images but, not from stream
Do we need to create a image from Stream to load the PDF or is there any alternate?
Any help is highly appreciated
Thank you In advance
Sample Code I created based on the documentation
public void GeneratePdfFromImageStream(List<Stream> imageStreams, String pdfSaveLocation = null)
{
int pageIndex = 0;
//Initialize C# PDF Library
PdfCommon.Initialize();
//Create a PDF document
using (var doc = PdfDocument.CreateNew())
{
foreach (var imageStream in imageStreams)
{
//I am creating a Bitmap image here, is there a way I can achevie the same withrout creating the image
var image = System.Drawing.Bitmap.FromStream(imageStream, true) as System.Drawing.Bitmap;
//Create empty PdfBitmap
using (PdfBitmap pdfBitmap = new PdfBitmap(image.Width, image.Height, true))
{
using (var g = System.Drawing.Graphics.FromImage(pdfBitmap.Image))
{
//Draw image to PdfBitmap
g.DrawImage(image, 0, 0, image.Width, image.Height);
}
//Create Image object
var imageObject = PdfImageObject.Create(doc, pdfBitmap, 0, 0);
//Calculate size of image in PDF points
var size = CalculateSize(pdfBitmap.Width, pdfBitmap.Height, image.HorizontalResolution, image.VerticalResolution);
//Add empty page to PDF document
doc.Pages.InsertPageAt(pageIndex, size);
//Insert image to newly created page
doc.Pages[pageIndex].PageObjects.Add(imageObject);
//set image matrix
imageObject.Matrix = new FS_MATRIX(size.Width, 0, 0, size.Height, 0, 0);
//Generate PDF page content to content stream
doc.Pages[pageIndex].GenerateContent();
pageIndex++;
}
}
// Save PDF document as "saved.pdf" in no incremental mode
if (string.IsNullOrWhiteSpace(pdfSaveLocation))
doc.Save($"saved_{Guid.NewGuid().ToString()}.pdf", SaveFlags.NoIncremental);
}
}

Merging N pdf files, created from html using ITextSharp, to another blank pdf file

I need to merge N PDF files into one. I create a blank file first
byte[] pdfBytes = null;
var ms = new MemoryStream();
var doc = new iTextSharp.text.Document();
var cWriter = new PdfCopy(doc, ms);
Later I cycle through html strings array
foreach (NBElement htmlString in someElement.Children())
{
byte[] msTempDoc = getPdfDocFrom(htmlString.GetString(), cssString.GetString());
addPagesToPdf(cWriter, msTempDoc);
}
In getPdfDocFrom I create pdf file using XMLWorkerHelper and return it as byte array
private byte[] getPdfDocFrom(string htmlString, string cssString)
{
var tempMs = new MemoryStream();
byte[] tempMsBytes;
var tempDoc = new iTextSharp.text.Document();
var tempWriter = PdfWriter.GetInstance(tempDoc, tempMs);
tempDoc.Open();
using (var msCss = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(cssString)))
{
using (var msHtml = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(htmlString)))
{
//Parse the HTML
iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(tempWriter, tempDoc, msHtml, msCss);
tempMsBytes = tempMs.ToArray();
}
}
tempDoc.Close();
return tempMsBytes;
}
Later on I try to add pages from this PDF file to the blank one.
private static void addPagesToPdf(PdfCopy mainDocWriter, byte[] sourceDocBytes)
{
using (var msOut = new MemoryStream())
{
PdfReader reader = new PdfReader(new MemoryStream(sourceDocBytes));
int n = reader.NumberOfPages;
PdfImportedPage page;
for (int i = 1; i <= n; i++)
{
page = mainDocWriter.GetImportedPage(reader, i);
mainDocWriter.AddPage(page);
}
}}
It breaks when it tries to create a PdfReader from the byte array I pass to the function. "Rebuild failed: trailer not found.; Original message: PDF startxref not found."
I used another library to work with PDF before. I passed 2 PdfDocuments as an objects and just added pages from one to another in cycle. It didn't support Css though, so I had to switch to ITextSharp.
I don't quite get the difference between PdfWriter and PdfCopy.
There a logical error in your code. When you create a document from scratch as is done in the getPdfDocFrom() method, the document isn't complete until you've triggered the Close() method. In this Close() method, a trailer is created as well as a cross-reference (xref) table. The error tells you that those are missing.
Indeed, you do call the Close() method:
tempDoc.Close();
But by the time you Close() the document, it's too late: you have already created the tempMsBytes array. You need to create that array after you close the document.
Edit: I don't know anything about C#, but if MemoryStream clears its buffer after closing it, you could use mainDocWriter.CloseStream = false; so that the MemoryStream isn't closed when you close the document.
In Java, it would be a bad idea to set the "close stream" parameter to false. When I read the answers to the question Create PDF in memory instead of physical file I see that C# probably doesn't always require this extra line.
Remark: merging files by adding PdfImportedPage instances to a PdfWriter is an example of bad taste. If you are using iTextSharp 5 or earlier, you should use PdfCopy or PdfSmartCopy to do that. If you use PdfWriter, you throw away a lot of information (e.g. link annotations).

Modify existing pdf (add/remove pages) while preserving metadata

my target is to open an existing pdf, add or remove some pages while preserving the metadata (Author, Subject, ...) in a Windows.Forms C# application.
I use iTextSharp and found examples how to add or remove pages by using the PdfConcatenate class. To keep the metadata I use a PdfStamper afterwards. To speed things up I want to do the modifications in memory before storing the result to disk.
The problem is NOT adding or removing the pages but to keep the metadata in the same step.
So can anybody tell me/giva an example on how to achieve this (better) or am I on the completely wrong track?
Here my current code (see comments for problem related lines):
public void RemovePagesInFile(string documentLocation, int pageIndexFrom, int pageCount)
{
// TB: open the pdf
using (PdfReader sourcePdfReader = new PdfReader(documentLocation))
using (MemoryStream concatenatedTargetStream = new MemoryStream((int)sourcePdfReader.FileLength))
{
// TB: use a concatenator to create a new pdf containing only the desired pages
PdfConcatenate concatenator = new PdfConcatenate(concatenatedTargetStream);
// TB: create a list with the page numbers to keep
List<int> pagesToKeep = new List<int>();
for (int i = 1; i <= pageIndexFrom; i++)
{
pagesToKeep.Add(i);
}
for (int i = pageIndexFrom + pageCount + 1; i <= sourcePdfReader.NumberOfPages; i++)
{
pagesToKeep.Add(i);
}
// TB: execute the page copy
sourcePdfReader.SelectPages(pagesToKeep);
concatenator.AddPages(sourcePdfReader);
// TB: problem(s) here:
// 1. when calling concatenator.Close() the memory stream gets disposed as expected.
// concatenator.Close();
// 2. even when calling concatenator.WriterFlush() the memory stream seems to be missing content (error when creating targetReader (see below)).
// concatenator.Writer.Flush();
// 3. when keeping concatenator open the same error as above occures (I assume not all bytes have been written to the memory stream)
// TB: preserve the meta data from the source document
// => ERROR here: "Rebuild trailer not found. Original Error: PDF startxref not found"
using (PdfReader targetReader = new PdfReader(concatenatedTargetStream))
using (MemoryStream targetStream = new MemoryStream((int)concatenatedTargetStream.Length))
{
using (PdfStamper stamper = new PdfStamper(targetReader, targetStream))
{
stamper.MoreInfo = sourcePdfReader.Info;
// TB: same problem as above with stamper ?
stamper.Close();
}
// TB: close the reader to be able to access the source pdf
sourcePdfReader.Close();
// TB: write the modified pdf to the disk
File.WriteAllBytes(documentLocation, targetStream.ToArray());
}
}
}
Two changes need to be made. Call
concatenator.Writer.CloseStream = false
before calling
concatenator.Close()
Do the same thing for the PdfStamper and you're set.

Use iTextSharp to save a PDF to a SQL Server 2008 Blob, and read that Blob to save to disk

I'm currently trying to use iTextSharp to do some PDF field mapping, but the challenging part right now is just saving the modified file in a varbinary[max] column. Then I later need to read that blob and convert it into a pdf which I save to a file.
I've been all over looking at example code but I can't find exactly what I'm looking for, and can't seem to piece together the [read from file to iTextSharp object] -> [do my stuff] -> [convert to varbinary(max)] pipeline, nor the conversion of that blob back into a savable file.
If anyone has code snippet examples that would be extremely helpful. Thanks!
The need to deal with a pdf in multiple passes was not immediately clear when I first started working them, so maybe this is some help to you.
In the method below, we create a pdf, render it to a byte[], load it for post processing, render the pdf again and return the result.
The rest of your question deals with getting a byte[] into and out of a varbinary[max], saving a byte[] to file and reading it back out, which you can google easily enough.
public byte[] PdfGeneratorAndPostProcessor()
{
byte[] newPdf;
using (var pdf = new MemoryStream())
using (var doc = new Document(iTextSharp.text.PageSize.A4))
using (PdfWriter.GetInstance(doc, pdf))
{
doc.Open();
// do stuff to the newly created doc...
doc.Close();
newPdf = pdf.GetBuffer();
}
byte[] postProcessedPdf;
var reader = new PdfReader(newPdf);
using (var pdf = new MemoryStream())
using (var stamper = new PdfStamper(reader, pdf))
{
var pageCount = reader.NumberOfPages;
for (var i = 1; i <= pageCount; i++)
{
// do something on each page of the existing pdf
}
stamper.Close();
postProcessedPdf = pdf.GetBuffer();
}
reader.Close();
return postProcessedPdf;
}

Categories

Resources