Creating PDf consisting of multiple Pages with itext 7 - html

i am using itext 7 to create a multi Pages PDf out of a Html file.
MemoryStream finalDocumenStream = new MemoryStream();
StampingProperties documentProperties = new StampingProperties();
documentProperties.UseAppendMode();
PdfDocument finalPDfDocument = new PdfDocument(new PdfWriter(finalDocumenStream),
documentProperties);
I am looping in an foreach over an array and call this method to create the document:
CustomTagWorkerFactory customTagWorkerFactory = new CustomTagWorkerFactory(page);
Document pDFdocument = HtmlConverter.ConvertToDocument(htmltext, new PdfWriter(stream),
converterProperties);
I want to save the Documents to finalPdfDocumet
pDFdocument.GetPdfDocument().CopyPagesTo(1,
pDFdocument.GetPdfDocument().GetNumberOfPages(), finalPDfDocument);
After foreach() iam returning the finalDocumenStream; I was expecting to get all the documents in here.
I want to return the Pdf Stream from my .Net Api Controller:
return File(pdfStream, "application/pdf");
I am not able to combine the streams of inside the iteration and return the documents to client.
What iam doing wrong? Any advises?
Thanks for your help?

First of all please be aware that PdfDocument instances created with a PdfWriter usually on one hand contain unfinished objects and on the other hand already have data written out to the PdfWriter. Thus, you cannot cleanly copy pages from them to other documents.
When you try to copy from then, usually even an exception is thrown that says so. Do you probably catch and ignore such exceptions?
Thus, to combine such documents, initially target them to a MemoryStream, close them when they are finished, and construct a new PdfDocument based on only a PdfReader initialized with that MemoryStream.
I.e.
PdfDocument fullDocument = new PdfDocument(...);
...
MemoryStream ms = new MemoryStream();
PdfDocument partialDoc = new PdfDocument(new PdfWriter(ms));
[... add content to partialDoc ...]
partialDoc.Close();
partialDoc = new PdfDocument(new PdfReader(ms.ToArray()));
partialDoc.CopyPagesTo(1, partialDoc.GetNumberOfPages(), fullDocument);
partialDoc.Close();
...
fullDocument.Close();

Related

An error occurred while parsing EntityName. Line 119, position 40

Although I find similar questions as mine, the answers to those questions don't answer my question. I'm trying to convert XML and XSLT into HTML so it can get converted to a PDF.
I have an HTML page (249 lines) that gets converted to XSLT:
`string filePath = hostURL + "path/to/somefile.htm";`
`xslt = client.DownloadData(filePath);`
The corresponding XML gets generated with XmlDocument xmlDoc = new XmlDocument();
then XmlElement nodes are added and MemoryStream xmlStream is returned where xslt and xmlStream are passed to
`string html = Helper.GenerateHTML(xmlStream, xslt);`
In Helper.GenerateHTML(this MemoryStream xmlStream, byte[] xsltByte) this occurs:
`XmlReaderSettings settings = new XmlReaderSettings();
settings.XmlResolver = null;
settings.DtdProcessing = DtdProcessing.Parse;`
`using (var xsltMemoryStream = new MemoryStream(xsltByte))
using (var xmlReader = XmlReader.Create(xsltMemoryStream, settings))
using (var xmlMemoryStream = new MemoryStream())`
`using (var xmlTextWriter = new XmlTextWriter(xmlMemoryStream, null))
{
var xct = new XslCompiledTransform();
xct.Load(xmlReader);
...
}`
but I get the error at xct.Load(xmlReader); and the Create PDF button click that invoked this code does not result in a PDF being created nor displayed.
Neither the XSL nor XML have symbol-related ("&" vs. "&", etc.) issues. For what it's worth, there is another process that extracts XSLT from the database (instead of an HTML file), generates its corresponding XML with XMLGenerator xgen = new XMLGenerator() then calls Helper.GenerateHTML(xmlStream, xslt) but does not choke at the xct.Load(xmlReader); line of code and a resulting PDF is displayed.
Why does the parsing error occur?

AS3 SharedObject read/write file location change

I’m using the following AS3 code to write and read data in two arrays to a local file, using Animate CC 2019 on Windows 10 and AIR 30.0 for Desktop/Flash (.swf) publishing settings. I use two input text boxes, input1 & input2, to add new data to the arrays.
When I test the FLA, the data file created has a .sol extension and is placed in a folder path:
C:\Users\username\AppData\Roaming\FLA filename\Local Store#SharedObjects\FLA filename.swf\
If I publish and install the program using an .air installer package, the exact same file, in the same folder path, is also accessed by the installed version of the program. Same location is used if I install on another computer running Windows 7, so the file location seems pretty consistent.
Question:
How can I force the code to save to a different location on the local hard drive on Windows? For example, in the documents folder or to create a new folder on the system drive and save the file there? Or, even better, prompt the user to choose the folder and file himself?
Please consider I’m looking for an answer using SharedObject, if possible, and not alternative methods like URLLoader, File, FileStream, FileMode. The reason is this way I can store multiple array contents in a file, without having to deal with the in-file data arrangement. So, I can read back the data for each array easily as shown below.
Thanks in advance
This is the code I use to access the local file:
var datavariable:SharedObject = SharedObject.getLocal("filiename");
var data1:Array = new Array ();
var data2:Array = new Array ();
btn_read.addEventListener(MouseEvent.CLICK, readfromfile);
btn_write.addEventListener(MouseEvent.CLICK, writetofile);
btn_new.addEventListener(MouseEvent.CLICK, newentry);
//To add new data from input text boxes to the arrays:
function newentry(e:Event):void
{
data1.push(input1.text);
data2.push(input2.text);
}
//To write to the local file:
function readfromfile(e:Event):void
{
data1 = datavariable.data.d1
data2 = datavariable.data.d2
}
//To read from the local file:
function writetofile(e:Event):void
{
datavariable.data.d1 = data1
datavariable.data.d2 = data2
datavariable.flush();
}
I don't know of a way of changing the shared object storage location. That mechanism is designed to be abstracted out from the developer.
Since you are using AIR, you can actually forget shared objects, and just write your own files anywhere your app has permission to do so. You can do this using the same format as shared object and don't have to worry about in file data arrangement (you save an object, you read back an object - just like Shared Object does), the only difference is you load/save the file where you choose.
Here is an example:
function writetofile(e:Event):void
{
//create an object that holds your data, this will act the same as the 'data' value of a shared object
var saveObject = {
d1: data1,
d2: data2
}
//using the File and FileStream classes to read/save files
var file:File = File.applicationStorageDirectory.resolvePath("saveData.data"); //or where and whatever you want to store and call the save file
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.WRITE);
fileStream.writeObject(saveObject); //write the object to this file
fileStream.close(); //close the File Stream
}
function readfromfile(e:Event):void
{
var file:File = File.applicationStorageDirectory.resolvePath("saveData.data");
var fileStream:FileStream = new FileStream();
fileStream.open(file, FileMode.READ);
var savedObject = fileStream.readObject();
fileStream.close();
data1 = savedObject.d1;
data2 = savedObject.d2;
}
If you want to save complex objects (objects that aren't primitives), you need to register the class first. This goes for shared objects as well. See this answer for example of that.

Any function or method by which I can save the new modified data to the xml file from which it is retrieved or loaded?

How can I save the modified data to the same xml file after loading from that external xml file in ActionScript3.
Is there exist any function or method or any way to save the modified data again in the same file from which it was loaded.
import flash.net.URLRequest;
var myXML:XML = new XML();
var XML_URL:String = "sample.xml";
var myXMLURL:URLRequest = new URLRequest(XML_URL);
var myLoader:URLLoader = new URLLoader(myXMLURL);
myLoader.addEventListener("complete", xmlLoaded);
function xmlLoaded(event:Event):void
{
myXML = XML(myLoader.data);
trace("Data loaded.");
trace(myXML); //showing output of just loaded xml file.
//process of adding new child node or property.
var newnode:XML = new XML();
newnode =
<student >
<sname srno="2">mm</sname>
<father tax="no">
<fname>Ratan</fname>
<focc>business man</focc>
<mobno>9928946899</mobno>
</father>
</student>;
myXML = myXML.appendChild(newnode);
trace(myXML); //showing o/p after being the child-node appended.
}
where the sample.xml file located in the same working path, contains only the following data.-
<data>
<student srno="1" class="5" rollno="1">
<sname>Rohan Jain</sname>
<father tax="yes">
<fname>Ronak Jain</fname>
<focc>teacher</focc>
<mobno>9928946899</mobno>
</father>
</student>
</data>
If you're building a browser based application; nothing you can do on the client will save the file to a specific name and location. You'll have to send your updated doc to the server for saving. It is easy to write a service to do this in most server side languages I have dealt with.
If you want to save the file to the client machine; you can do so using FileReference.save(). However, this requires user input and there is no way to guarantee what the user will name the file or where they'll put it.

creating pdf with itextsharp with images from database

I have a process where the html is stored in database with image links. the images are also stored in db as well. I've created a controller action which reads the image from database. the path I'm generating is something like /File/Image?path=Root/test.jpg.
this image path is embedded in html in img tag like <img alt="logo" src="/File/Image?path=Root/001.jpg" />
I'm trying to use itextsharp to read the html from the database and create a pdf document
string _html = GenerateDocumentHelpers.CommissioningSheet(fleetId);
string _html = GenerateDocumentHelpers.CommissioningSheet(fleetId);
Document _document = new Document(PageSize.A4, 80, 50, 30, 65);
MemoryStream _memStream = new MemoryStream();
PdfWriter _writer = PdfWriter.GetInstance(_document, _memStream);
StringReader _reader = new StringReader(_html);
HTMLWorker _worker = new HTMLWorker(_document);
_document.Open();
_worker.Parse(_reader);
_document.Close();
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=Commissioning.pdf");
Response.ContentType = "application/pdf";
Response.Buffer = true;
Response.OutputStream.Write(_memStream.GetBuffer(), 0, _memStream.GetBuffer().Length);
Response.OutputStream.Flush();
Response.End();
return new FileStreamResult(Response.OutputStream, "application/pdf");
This code gives me an illegal character error. this comes from the image tag, it is not recognizing ? and = characters, is there a way I can render this html with img tag so that when I create a pdf it renders the html and image from the database and creates a pdf or if itextsharp can't do it, can you provide me with any other third party open source tools that can accomplish this task?
If the image source isn't a fully qualified URL including protocol then iTextSharp assumes that it is a file-based URL. The solution is to just convert all image links to absolute in the form http://YOUR_DOMAIN/File/Image?path=Root/001.jpg.
You can also set a global property on the parser that works pretty much the same as the HTML <BASE> tag:
//Create a provider collection to set various processing properties
System.Collections.Generic.Dictionary<string, object> providers = new System.Collections.Generic.Dictionary<string, object>();
//Set the image base. This will be prepended to the SRC so watch your forward slashes
providers.Add(HTMLWorker.IMG_BASEURL, "http://YOUR_DOMAIN");
//Bind the providers to the worker
worker.SetProviders(providers);
worker.Parse(reader);
Below is a full working C# 2010 WinForms app targeting iTextSharp 5.1.2.0 that shows how to use a relative image and set its base using the global provider. Everything is pretty much the same as your code, although I through in a bunch of using statements to ensure proper cleanup. Make sure to watch the leading and trailing forward slashes on everything, the base URL gets prepended directly only the SRC attribute and you might end up with double-slashes if its not done correctly. I'm hard-balling a domain in here but you should be able to easily use the System.Web.HttpContext.Current.Request object.
using System;
using System.IO;
using System.Windows.Forms;
using iTextSharp.text;
using iTextSharp.text.html.simpleparser;
using iTextSharp.text.pdf;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string html = #"<img src=""/images/home_mississippi.jpg"" />";
string outputFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "HtmlTest.pdf");
using (FileStream fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
using (Document doc = new Document(PageSize.TABLOID)) {
using (PdfWriter writer = PdfWriter.GetInstance(doc, fs)) {
doc.Open();
using (StringReader reader = new StringReader(html)) {
using (HTMLWorker worker = new HTMLWorker(doc)) {
//Create a provider collection to set various processing properties
System.Collections.Generic.Dictionary<string, object> providers = new System.Collections.Generic.Dictionary<string, object>();
//Set the image base. This will be prepended to the SRC so watch your forward slashes
providers.Add(HTMLWorker.IMG_BASEURL, "http://www.vendiadvertising.com");
//Bind the providers to the worker
worker.SetProviders(providers);
worker.Parse(reader);
}
}
doc.Close();
}
}
}
this.Close();
}
}
}

Flex: Export Excel via Servlet

I want a user to press an excel button and get prompted to download an excel file. I normally do it like this:
var dest:String = excelEndpoint;
var request:URLRequest = new URLRequest();
request.url = dest;
fr.download( request,'Locates.xls' );
fr.addEventListener(HTTPStatusEvent.HTTP_STATUS, handleStatus);
fr.addEventListener(IOErrorEvent.IO_ERROR, handleErr);
However, now I need to pass an object to the servlet. Seeing that you can't do that with URLRequest I tried using HTTPService:
var service:HTTPService = new HTTPService();
service.url = excelEndpoint;
service.method = "POST";
service.showBusyCursor = true;
service.addEventListener("result", httpResult);
service.addEventListener("fault", httpFault);
service.send( myObject);
Now I can get my data (myObject) to the servlet successfully, but I don't get prompted for a download.
How can I do that? Is it even possible with HTTPService?
Thanks for any helpful tips.
I don't think there is anything you can do w/ a remote request from the Flash Player to prompt the user to download something. The way I have done this in the past is two fold:
Remote request pings server that generates the excel file and saves it to a temporary directory. The request returns a URL to the Flex app as the result of the call.
When Flex app gets the result--a URL--it creates a URL request and pops it open in a new window, prompting the user to download the generated excel sheet.
I don't see a way to do this in one shot; because the return value from the Flex HTTPService call goes to the Flash Player, not the browser.
SOLVED:
I wanted to accomplish this with 1 remote call and the way I found to do this while passing an object that contained collections is this:
var uv:URLVariables = new URLVariables();
uv.typesColl = myObj.types.toString();
uv.partiesColl = myObj.parties.toString();
uv.statuses = myObj.statuses.toString();
Basically, create a property on the URLVariables object for each collection and then set all collections toString();
Hope that helps someone.