iText7 Create PDF in memory instead of physical file - c#

How do one create PDF in memorystream instead of physical file using itext7?
I have no idea how to do it in the latest version, any help?
I tried the following code, but pdfSM is not properly populated:
string filePath = "./abc.pdf";
MemoryStream pdfSM = new ByteArrayOutputStream();
PdfDocument doc = new PdfDocument(new PdfReader(filePath), new PdfWriter(pdfSM));
.......
doc.close();
The full testing code as below for your reference, it worked when past filePath into PdfWriter but not for the memory stream:
public static readonly String sourceFolder = "../../FormTest/";
public static readonly String destinationFolder = "../../Output/";
static void Main(string[] args)
{
String srcFilePattern = "I-983";
String destPattern = "I-129_2014_";
String src = sourceFolder + srcFilePattern + ".pdf";
String dest = destinationFolder + destPattern + "_flattened.pdf";
MemoryStream returnSM = new MemoryStream();
PdfDocument doc = new PdfDocument(new PdfReader(src), new PdfWriter(returnSM));
PdfAcroForm form = PdfAcroForm.GetAcroForm(doc, false);
foreach (PdfFormField field in form.GetFormFields().Values)
{
var fieldName = field.GetFieldName();
var type = field.GetType();
if (fieldName != null)
{
if (type.Name.Equals("PdfTextFormField"))
{
field.SetValue("T");
}
}
}
form.FlattenFields();
doc.Close();
}

This works for me.
public byte[] CreatePdf()
{
var stream = new MemoryStream();
var writer = new PdfWriter(stream);
var pdf = new PdfDocument(writer);
var document = new Document(pdf);
document.Add(new Paragraph("Hello world!"));
document.Close();
return stream.ToArray();
}

I needed the same thing. Got it working like this:
(I included some settings which improve performance)
string HtmlString = "<html><head></head><body>some content</body></html>";
byte[] buffer;
PdfDocument pdfDoc = null;
using (MemoryStream memStream = new MemoryStream())
{
using(PdfWriter pdfWriter = new PdfWriter(memStream, wp))
{
pdfWriter.SetCloseStream(true);
using (pdfDoc = new PdfDocument(pdfWriter))
{
ConverterProperties props = new ConverterProperties();
pdfDoc.SetDefaultPageSize(PageSize.LETTER);
pdfDoc.SetCloseWriter(true);
pdfDoc.SetCloseReader(true);
pdfDoc.SetFlushUnusedObjects(true);
HtmlConverter.ConvertToPdf(HtmlString, pdfDoc, props));
pdfDoc.Close();
}
}
buffer = memStream.ToArray();
}
return buffer;

iText7、C# Controller
Error:
public ActionResult Report()
{
//...
doc1.Close();
return File(memoryStream1, "application/pdf", "pdf_file_name.pdf");
}
Work:
public ActionResult Report()
{
//...
doc1.Close();
byte[] byte1 = memoryStream1.ToArray();
return File(byte1, "application/pdf", "pdf_file_name.pdf");
}
I don't know why... but, it's working!
another: link

Related

Converting FlowDocument to XPS messes up page contents

I am trying to convert a FlowDocument to XPS. Here is how the FlowDocument is defined:
<FlowDocument PageHeight="29.7cm" PageWidth="21cm" PagePadding="2cm,2cm,2cm,2cm">
</FlowDocument>
It is inside a RichTextBox and is populated by a user. It is saved as a .rtf file (.xamlgave me the same results).
Here is the method I am using to save the doc:
public void UploadTemplate(TextRange content, string filename)
{
string destPath = Path.Combine(default_template_path, filename + ".rtf");
if (content.CanSave(DataFormats.Rtf))
{
using (var stream = new FileStream(destPath, FileMode.Create))
{
content.Save(stream, DataFormats.Rtf);
stream.Close();
}
}
}
And here is how I load the doc:
public void LoadTemplate(string template_path, TextRange content)
{
if (content.CanLoad(DataFormats.Rtf))
{
using (var stream = new FileStream(template_path, FileMode.Open))
{
content.Load(stream, DataFormats.Rtf);
stream.Close();
}
}
}
Finally this is the code I use for converting the FlowDocument to XPS:
public static MemoryStream FlowDocumentToXPS(FlowDocument flowDocument)
{
MemoryStream stream = new MemoryStream();
using (Package package = Package.Open(stream, FileMode.Create, FileAccess.ReadWrite))
{
using (XpsDocument xpsDoc = new XpsDocument(package, CompressionOption.Maximum))
{
XpsSerializationManager rsm = new XpsSerializationManager(new XpsPackagingPolicy(xpsDoc), false);
DocumentPaginator paginator = ((IDocumentPaginatorSource)flowDocument).DocumentPaginator;
paginator.PageSize = new Size(flowDocument.PageWidth, flowDocument.PageHeight);
rsm.SaveAsXaml(paginator);
rsm.Commit();
}
}
stream.Position = 0;
Console.WriteLine(stream.Length);
Console.WriteLine(stream.Position);
return stream;
}
After saving this stream to a .xps file the document pages seem like they are divided in 2 columns. This is what I get from that export. Can someone help me figure this out ?
For anyone that might stumble upon this. You must set the FlowDocument.ColumnWidth property when converting to XPS. In this case it would need to be something like this:
public static MemoryStream FlowDocumentToXPS(FlowDocument flowDocument)
{
flowDocument.ColumnWidth = (int)YourColumnWidth; // THIS IS THE KEY LINE
MemoryStream stream = new MemoryStream();
using (Package package = Package.Open(stream, FileMode.Create, FileAccess.ReadWrite))
{
using (XpsDocument xpsDoc = new XpsDocument(package, CompressionOption.Maximum))
{
XpsSerializationManager rsm = new XpsSerializationManager(new XpsPackagingPolicy(xpsDoc), false);
DocumentPaginator paginator = ((IDocumentPaginatorSource)flowDocument).DocumentPaginator;
paginator.PageSize = new Size(flowDocument.PageWidth, flowDocument.PageHeight);
rsm.SaveAsXaml(paginator);
rsm.Commit();
}
}
stream.Position = 0;
Console.WriteLine(stream.Length);
Console.WriteLine(stream.Position);
return stream;
}

How to convert XML to Byte to File/PDF

I have successfully done "find and replace" which created an xml. Now I want to convert the newly created xml file to pdf which will be attached as a file and sent in a mail.
The result of the Base64String was tested on a base64 pdf file converter but the pdf cannot be opened. Got this error: Something went wrong couldn't open the file
HOW CAN I MAKE THIS WORK?
public async Task<string> CreateDocument(string PolicyNumber)
{
var policy = await _context.Policy.SingleOrDefaultAsync(p => p.PolicyNumber == PolicyNumber);
ArgumentNullException.ThrowIfNull(policy, "Policy Not Available");
//CreatePolicyDocument
//create policy document
var files = #"C:\Users\PATHTODOCUMENT\holderTest.docx";
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(files, true))
{
string docText;
using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
{
docText = sr.ReadToEnd();
}
Regex regexText = new Regex("XCONCLUSION_DATEX");
var newWordText = regexText.Replace(docText, "Hi Everyone!");
using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
{
sw.Write(newWordText);
Encoding encoding = Encoding.UTF8;
byte[] docAsBytes = encoding.GetBytes(newWordText);
File.WriteAllBytes("hello.pdf", docAsBytes);
var file = Convert.ToBase64String(docAsBytes);
}
}
//send message
//
return "";
}
PDF file has its own construct,so you can't generate a pdf file with the contentstring of xml file dirctly.
If you really want to convert xml contentstring to PDF,you could try iTextSharp.
I tried with a simple demo,and here's the code:
[HttpPost]
public IActionResult XMLtoPDF([FromForm] Try T1)
{
var streamContent = new StreamContent(T1.file.OpenReadStream());
var filestring = streamContent.ReadAsStringAsync().Result;
MemoryStream outputStream = new MemoryStream();
Document doc = new Document();
PdfWriter writer = PdfWriter.GetInstance(doc, outputStream);
//PDF settings
PdfDestination pdfDest = new PdfDestination(PdfDestination.XYZ, 0, doc.PageSize.Height, 1f);
doc.Open();
var paragraph = new Paragraph(filestring);
doc.Add(paragraph);
doc.Close();
outputStream.Close();
var pdfArray = outputStream.ToArray();
return File(pdfArray, "application/pdf");
}
Result:

ITextsharp: Error reading a pdf file in Byte[] content (PdfReader)

I'm trying to merge several PDFs into a single file through a list that contains their content in byte[]. When opening a document from the Byte[] list with PdfReader, the program launches the following exception: "the document has no pages". When I review the contents of the Byte[] list there are complete, but the exception is always launched.
I try to download the content of that single page separately and the generated document launches error when opening it. The division of the pdf does well because it generates each document in physical and makes it perfect for each page of the PDF.
I appreciate your help or opinions in this situation.
This is the code I use to split and merge documents:
public List<byte[]> SplitPDF(byte[] contentPdf)
{
try
{
var listBythe = new List<byte[]>();
PdfImportedPage page = null;
PdfCopy PdfCopy = null;
PdfReader reader = new PdfReader(contentPdf);
for (int numPage = 1; numPage <= reader.NumberOfPages; numPage++)
{
Document doc = new Document(PageSize.LETTER);
var mStream = new MemoryStream();
PdfCopy = new PdfCopy(doc, mStream);
doc.Open();
page = PdfCopy.GetImportedPage(reader, numPage);
PdfCopy.AddPage(page);
listBythe.Add(mStream.ToArray());
doc.Close();
}
MergePdfToPage(listBythe);
return listBythe;
}
catch (Exception ex)
{
throw ex;
}
}
private byte[] MergePdfToPage(List<byte[]>contentPage)
{
byte[] docPdfByte = null;
var ms = new MemoryStream();
using (Document doc = new Document(PageSize.LETTER))
{
PdfCopy copy = new PdfCopy(doc, ms);
doc.Open();
var num = doc.PageNumber;
foreach (var file in contentPage.ToArray())
{
using (var reader = new PdfReader(file))
{
copy.AddDocument(reader);
}
}
doc.Close();
docPdfByte = ms.ToArray();
}
return docPdfByte;
In your loop you do
Document doc = new Document(PageSize.LETTER);
var mStream = new MemoryStream();
PdfCopy = new PdfCopy(doc, mStream);
doc.Open();
page = PdfCopy.GetImportedPage(reader, numPage);
PdfCopy.AddPage(page);
listBythe.Add(mStream.ToArray());
doc.Close();
In particular you retrieve the mStream bytes before closing doc. But before doc is closed, the pdf is incomplete in mStream!
To get a complete pdf from mStream, please change the order of instructions an do
Document doc = new Document(PageSize.LETTER);
var mStream = new MemoryStream();
PdfCopy = new PdfCopy(doc, mStream);
doc.Open();
page = PdfCopy.GetImportedPage(reader, numPage);
PdfCopy.AddPage(page);
doc.Close();
listBythe.Add(mStream.ToArray());
instead.
I created something for you, hopefully it will work as well as it did for me.
Class :
public class PDFFactory
{
public PDFFactory()
{
PdfDocument = new Document(iTextSharp.text.PageSize.A4, 65, 65, 60, 60);
}
private Document _pdfDocument;
public Document PdfDocument
{
get
{
return _pdfDocument;
}
set
{
_pdfDocument = value;
}
}
private MemoryStream _pdfMemoryStream;
public MemoryStream PDFMemoryStream
{
get
{
return _pdfMemoryStream;
}
set
{
_pdfMemoryStream = value;
}
}
private string _pdfBase64;
public string PDFBase64
{
get
{
if (this.DocumentClosed)
return _pdfBase64;
else
return null;
}
set
{
_pdfBase64 = value;
}
}
private byte[] _pdfBytes;
public byte[] PDFBytes
{
get
{
if (this.DocumentClosed)
return _pdfBytes;
else
return null;
}
set
{
_pdfBytes = value;
}
}
public byte[] GetPDFBytes()
{
PDFDocument.Close();
return PDFMemoryStream.GetBuffer();
}
public void closeDocument()
{
PDFDocument.Close();
PDFBase64 = Convert.ToBase64String(this.PDFMemoryStream.GetBuffer());
PDFBytes = this.PDFMemoryStream.GetBuffer();
}
}
Service:
public byte[] ()
{
PDFFactory pdf_1 = new PDFFactory();
PDFFactory pdf_2 = new PDFFactory();
List<byte[]> sourceFiles = new List<byte[]>();
sourceFiles.Add(pdf_1.GetPDFBytes);
sourceFiles.Add(pdf_2.GetPDFBytes);
PDFFactory pdfFinal = new PDFFactory();
for (int fileCounter = 0; fileCounter <= sourceFiles.Count - 1; fileCounter += 1)
{
PdfReader reader2 = new PdfReader(sourceFiles[fileCounter]);
int numberOfPages = reader2.NumberOfPages;
for (int currentPageIndex = 1; currentPageIndex <= numberOfPages; currentPageIndex++)
{
// Determine page size for the current page
pdfFinal.PDFDocument.SetPageSize(reader2.GetPageSizeWithRotation(currentPageIndex));
// Create page
pdfFinal.PDFDocument.NewPage();
PdfImportedPage importedPage = pdfFinal.PDFWriter.GetImportedPage(reader2, currentPageIndex);
// Determine page orientation
int pageOrientation = reader2.GetPageRotation(currentPageIndex);
if ((pageOrientation == 90) || (pageOrientation == 270))
pdfFinal.PDFWriter.DirectContent.AddTemplate(importedPage, 0, -1.0F, 1.0F, 0, 0, reader2.GetPageSizeWithRotation(currentPageIndex).Height);
else
pdfFinal.PDFWriter.DirectContent.AddTemplate(importedPage, 1.0F, 0, 0, 1.0F, 0, 0);
}
}
pdfFinal.closeDocument();
return pdfFinal.PDFBytes;
}
Let me know if it helped.

How to convert a byte array to pdf

I am building an app that modifies a word 2010 document and it should be downloaded as pdf.I write a code to convert word to pdf but it is converting the document I upload not the modified word. How can I convert modified word to PDF.Below is the function which is not converting modified word.
protected void btnUpload_Click(object sender, EventArgs e)
{
if (FileUploadControl.HasFile)
{
string fileNameFromUser = FileUploadControl.FileName;
var fiFileName = new System.IO.FileInfo(fileNameFromUser);
using (MemoryStream ms = new MemoryStream())
{
ms.Write(FileUploadControl.FileBytes, 0, FileUploadControl.FileBytes.Length);
using (WordprocessingDocument sDoc = WordprocessingDocument.Open(ms, true))
{
}
lblMessage.Text = "Dokumenti u ngarkua me sukses!";
Session["ByteArray"] = FileUploadControl.FileBytes;
Session["fileNameFromUser"] = fileNameFromUser;
}
}
byte[] byteArray = (byte[])(Session["ByteArray"]);
if (byteArray != null)
{
try
{
using (MemoryStream ms = new MemoryStream())
{
ms.Write(byteArray, 0, byteArray.Length);
using (WordprocessingDocument wDoc = WordprocessingDocument.Open(ms, true))
{
var body = wDoc.MainDocumentPart.Document.Body;
var lastParagraf = body.Elements<Paragraph>().LastOrDefault();
var newParagraf = new Paragraph(
new Run(
new Text("Perdoruesi:" + " " + User.Identity.Name)));
var newParagraf2 = new Paragraph(
new Run(
new Text("Data dhe ora:" + " " + DateTime.Now.ToString())));
var newParagraf3 = new Paragraph(
new Run(
new Text("Kodi unik:" + " " + randomstring(14))));
var newParagraf4 = new Paragraph(
new Run(
new Text("Shifra:" )));
lastParagraf.InsertAfterSelf(newParagraf);
lastParagraf.InsertAfterSelf(newParagraf2);
lastParagraf.InsertAfterSelf(newParagraf3);
lastParagraf.InsertAfterSelf(newParagraf4);
}
Session["ByteArray"] = ms.ToArray();
lblMessage.Text = "U ngarkua dhe u vulos dokumenti!";
Guid pdfFileGuid = Guid.NewGuid();
var filePath = Path.GetTempFileName();
FileUploadControl.SaveAs(filePath);
var appWord = new Microsoft.Office.Interop.Word.Application();
var wordDoc = appWord.Documents.Open(filePath);
var convertedFilePath = Path.GetTempFileName();
wordDoc.ExportAsFixedFormat(convertedFilePath, Microsoft.Office.Interop.Word.WdExportFormat.wdExportFormatPDF);
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=Converted.Pdf");
Response.AddHeader("content-type", "application/pdf");
Response.TransmitFile(convertedFilePath);
File.Delete(filePath);
File.Delete(convertedFilePath);
}
}
catch (Exception ex)
{
lblMessage.Text = "ERROR:" + ex.Message.ToString();
}
}
else
{
lblMessage.Text = "Nuk e keni zgjedhur dokumentin apo formati i dokumentit nuk pershtatet!";
}
}
Currently, here you load the data from the FileUploadControl into session:
Session["ByteArray"] = FileUploadControl.FileBytes;
You then load the data from session into a MemoryStream that you use to open the document for editing:
byte[] byteArray = (byte[])(Session["ByteArray"]);
if (byteArray != null)
{
try
{
using (MemoryStream ms = new MemoryStream())
{
ms.Write(byteArray, 0, byteArray.Length);
using (WordprocessingDocument wDoc = WordprocessingDocument.Open(ms, true))
At the end of this, after your edits, you copy the updated content back to session:
lastParagraf.InsertAfterSelf(newParagraf3);
lastParagraf.InsertAfterSelf(newParagraf4);
}
Session["ByteArray"] = ms.ToArray();
but; that's the last time we see session used; you then write the uploaded file to a temporary file, and use that to perform Word automation:
var filePath = Path.GetTempFileName();
FileUploadControl.SaveAs(filePath);
var appWord = new Microsoft.Office.Interop.Word.Application();
var wordDoc = appWord.Documents.Open(filePath);
So yes: this will convert the original file as uploaded, because FileUploadControl is unrelated to the changes you made. Instead, perhaps try:
var filePath = Path.GetTempFileName();
File.WriteAllBytes(filePath, (byte[])Session["ByteArray"]);
var appWord = new Microsoft.Office.Interop.Word.Application();
var wordDoc = appWord.Documents.Open(filePath);
This should then include the changes.
Additional side observations:
Word automation is unsupported and not recommended on web-servers; if it works for you: great, but just be aware that if it suddenly breaks you'll be on your own
be careful that you're not leaving files scattered on disk, or lots of open Word instances / files; basically: check you're not "leaking" (appWord, wordDoc, filePath, convertedFilePath etc - all probably need some finally love)
putting Word files into session-state (Session) probably isn't a good or necessary idea; I would recommend just using a local byte[] or similar throughout in this method, and remove Session["ByteArray"] completely

How to create a copy of a PDF file in ASP.NET MVC

I'm reading a PDF file for writing a string on it like this :
public ActionResult Index(HttpPostedFileBase file)
{
byte[] pdfbytes = null;
BinaryReader rdr = new BinaryReader(file.InputStream);
pdfbytes = rdr.ReadBytes((int)file.ContentLength);
PdfReader myReader = new PdfReader(pdfbytes);
and I'm trying to pass a new file to FileStream like this :
FileStream fs = new FileStream(newFile, FileMode.Create, FileAccess.Write);
But I don't know how to pass the copied new file to fs object. Can you help me with that? Thanks.
If you have access to updated byte array pass it to File.WriteAllBytes. Or you might have an instance of PdfDocument or PdfWriter which usually allow saving the document to file on disk too. Hope it helps!
Here is example which is reading existing pdf file, copying it to new one and adding new string line:
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.IO;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string originalFile = "c:\\Users\\Admin\\Desktop\\receipt mod 3.pdf";
string copyOfOriginal = "c:\\Users\\Admin\\Desktop\\newFile.pdf";
using (var reader = new PdfReader(originalFile))
{
using (var fileStream = new FileStream(copyOfOriginal, FileMode.Create, FileAccess.Write))
{
var document = new Document(reader.GetPageSizeWithRotation(1));
var writer = PdfWriter.GetInstance(document, fileStream);
document.Open();
for (var i = 1; i <= reader.NumberOfPages; i++)
{
document.NewPage();
var baseFont = BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
var importedPage = writer.GetImportedPage(reader, i);
var contentByte = writer.DirectContent;
contentByte.BeginText();
contentByte.SetFontAndSize(baseFont, 12);
var LineString = "Hello World!";
contentByte.ShowTextAligned(10,LineString,50,50,0);
contentByte.EndText();
contentByte.AddTemplate(importedPage, 0, 0);
}
document.Close();
writer.Close();
}
}
}
}
}
Try this.
This program copies all pdf files from one location to another.
protected void Button1_Click(object sender, EventArgs e)
{
string sourceDirectory = #"D:\project training\source";
string targetDirectory = #"D:\project training\destiny";
Copy(sourceDirectory, targetDirectory);
}
public static void Copy(string sourceDirectory, string targetDirectory)
{
DirectoryInfo diSource = new DirectoryInfo(sourceDirectory);
DirectoryInfo diTarget = new DirectoryInfo(targetDirectory);
CopyAll(diSource, diTarget);
}
public static void CopyAll(DirectoryInfo source, DirectoryInfo target)
{
Directory.CreateDirectory(target.FullName);
foreach (FileInfo fi in source.GetFiles())
{
if (fi.Extension.Equals(".pdf"))
{
fi.CopyTo(Path.Combine(target.FullName, fi.Name), true);
}
}
foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
{
DirectoryInfo nextTargetSubDir =
target.CreateSubdirectory(diSourceSubDir.Name);
CopyAll(diSourceSubDir, nextTargetSubDir);
}
}

Categories