iTextSharp returns a pdf that can not be opened - asp.net-mvc

I have followed the answer in this question and tried to output a pdf from an MVC view with iTextSharp to test the rendering fidelity.
I have the following code:
var ms = new MemoryStream();
var document = new Document(PageSize.A4, 10, 10, 10, 10);
var writer = PdfWriter.GetInstance(document, ms);
document.Open();
var html = this.RenderView(GetViewName(), reportVM);
var css = System.IO.File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(), "\\Content\\site.css"));
var msCss = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(css));
var msHtml = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(html));
XMLWorkerHelper.GetInstance().ParseXHtml(writer, document, msHtml, msCss);
document.Close();
return File(ms, "application/pdf");
Unfortunately it returns a window in the browser with the message:
Failed to load PDF
What are the main causes of this behavior?
Note: I have produced a pdf from the same html with PdfSharp which is based on iTextSharp too, so I guess I am not using iTextSharp properly.
EDIT:
I have followed Bruno's suggestion in the comments, so I changed the return to :
bytes = ms.ToArray();
return File(new MemoryStream(bytes), "application/pdf");
And now the result is a 2 pages empty pdf, so it is better, but is it possible to make it more accurate, since the content of the pdf should have some text inside?

After I saw the answer in this question and removed the width tags inside divs, and also ran an online XHtml validator to adjust everything else, I was able to generate a pdf relatively according to the coresponding HTML.

Related

pdf.js rendering as PDF with base64

I am stuck at last point of my application, i am supposed to display user form in PDF which works fine on desktop browsers as they has pdf viewer built in, but for Android / iOS its not working as pdf viewer is missing.
So i was trying to use PDF.js to display it, (to be honest, this is very widely used but documentation is lacking), only catch is i am getting data in base64 format. PDF.js has example on site which shows how to render the base64 data but its not PDF, for that displaying PDF as "PDF" i need to user their "viewer.html" but that does not take base64 data?
closest i have come to Pdf.js: rendering a pdf file using base64... on stack overflow, but i dont know how to use it after PDFJS.getDocument(pdfAsArray)?.
Other link that came across was other link
I dont want to rely on Google / Third party PDF viewer as i dont know how long they will support this.
There are no end-to-end answers on this topic in community so here is my attempt to put something here. (maybe it will help others)
Okay, PDF.js is one way of showing PDF in browser, specially when you don't want to rely on PDF plugin to be installed. In my case, my application generates report in PDF and that can be viewed before downloading but on handheld devices it was not working because of missing PDF viewer plugin.
In my case PDF was sent to browse in base64 string, that I can use to display PDF with <object src="base64-data"...></object>. This works like charm on Chrome / FF but switch to mobile view and it stops working.
<object type="application/pdf" id="pdfbin" width="100%" height="100%" title="Report.pdf">
<p class="text-center">Looks like there is no PDF viewer plugin installed, try one of the below approach...</p>
</object>
In above code it will try to show the PDF or fall back to <p> and show error message. And I Was planning to add the PDF viewer at this point, PDF.js was the choice but was not able to display it. One example on PDF.js with Base64 data shows how to do this but that renders it as an Image not PDF, and I was not able to find solution for that and hence the question, here is what I did,
First add the JavaScript code to convert base64 to array
convert to blob and use viewer.html file packaged with PDF.js to display it as PDF
In case if you are wondering why base64 data, then answer is simple I can create the PDF, read it, send the data to client and delete the file, I don't have to run any cleaner service/cron job to delete generated PDF files
Few Things To Note
Below code is using Flask + Jinja2, change the way base64 is read in html if you are using something else
viewer.html needs to be changed to have required js & css files in proper location (by default their location is relative; you need them to be referred from static folder)
viewer.js looks for pdf.worker.js in predefined location, change that in case its throwing error as above file not found.
viewer.js might throw file origin does not match viewer error in that case as a quick fix comment the code which throws this error and see if that solves the issue (look for that error in viewer.js)
I am not the author of below code, I have just put it together from different places.
Now to the code (so PDF will be displayed when user clicks on button with id="open_id")
Jquery
var pdfDataX = '{{ base64Pdf }}';
var BASE64_MARKER = ';base64,';
PDFJS.workerSrc = "{{ url_for('static', filename='js/pdf.worker.js') }}";
$('#open_id').click(function() {
PDFJS.disableWorker = true;
var pdfAsDataUri = "data:application/pdf;base64," + pdfDataX ;
PDFJS.workerSrc = "{{ url_for('static', filename='js/pdf.worker.js') }}";
// Try to show in the viewer.html
var blob = base64toBlob(pdfDataX, 'application/pdf');
var url = URL.createObjectURL(blob);
var viewerUrl = "{{ url_for('static', filename='viewer.html') }}" + '?file=' + encodeURIComponent(url);
$('#pdfViewer').attr('src', viewerUrl);
// Finish
var mdObj = $('#pdfbin');
mdObj.hide();
mdObj.attr('data', pdfAsDataUri);
mdObj.show();
$('#myModal').modal();
});
var base64toBlob = function(b64Data, contentType, sliceSize) {
contentType = contentType || '';
sliceSize = sliceSize || 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i=0; i<slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
var blob = new Blob(byteArrays, {type: contentType});
return blob;
}
$('.save').click(function(e) {
e.preventDefault();
var blob = base64toBlob(pdfDataX, 'application/pdf');
saveAs(blob, 'abcd.pdf'); // requires https://github.com/eligrey/FileSaver.js/
return false;
});
HTML
<object type="application/pdf" id="pdfbin" width="100%" height="100%" title="Resume.pdf">
<p class="text-center">Looks like there is no PDF viewer plugin installed, try one of the below approach...</p>
<iframe id="pdfViewer" style="width: 100%; height: 100%;" allowfullscreen="" webkitallowfullscreen=""></iframe>
</object>
Hope this will be useful for others in future.

Asp .net core how to display RTF document file in page view cshtml

Please I need some help.
I want to build an online exam web application, so the question files as .rtf stored in database, then when the exam held, us as participant can see the questions by the button list in page.
How I can show/display any .RTF file document (from my database) to page view (.cshtml) ?
public class Exam_Question
{
....
public byte[] Question_File { get; set; }
}
I have stored the file in database.
Then in controller I call the model.
public async Task<IActionResult> Details(int? id)
{
var exam_Question = await _context.Question.SingleOrDefaultAsync(m => m.ID == id);
return View(exam_Question);
}
Then in page view I did try this.
<iframe src="data:#Model.Question_File; base64, #Convert.ToBase64String(Model.Question_File)"></iframe>
the result like this image : IFrame tag with base64 file
I want to display at least at same bold, size, paragraph, equation, etc format like in Word App.
I think one option will be to convert the RTF into HTML at server side and then rendering.
You could either use a paid library as below
SautinSoft
Or build your own RTF to HTML converter. Here is a link to CodeProject which provides pretty detailed breakdown
CodeProject
Sorry I cant think of a simpler solution at the moment
As a variant: Load RTF file and then to open in HTML.
string inpFile = #"..\..\..\..\example.rtf";
string outfile = Path.GetFullPath("Result.html");
RtfToHtml r = new RtfToHtml();
r.Convert(inpFile, outfile, new HtmlFixedSaveOptions() {Title = "Show the RTF." });

No pdf generated

i use jsPDF and plugin jsPDF-AutoTable
I have a html table i want to print
$('#printFreeRoom').on('click', function (e) {
freeRoomAvailableReport($("#freeRoomTableResult"));
});
function freeRoomAvailableReport(tableId) {
var doc = new jsPDF('p', 'pt');
doc.text("From HTML", 40, 50);
var res = doc.autoTableHtmlToJson(tableId);
doc.autoTable(res.columns, res.data, {
startY: 60
});
doc.output('dataurlnewwindow');
doc.save('test.pdf');
}
nothing is generated when i click on the button.
I created a example on jsfiddle
http://jsfiddle.net/8da5e1fj/
seem like a chrome problem...
tried other example: http://jsfiddle.net/8tLt9yof/10/ and get same result.
You need to add FileSaver.js to use doc.save() also, Chrome has issues with doc.output('dataurlnewwindow')
Hence, here is a working fiddle for doc.save fiddle
And, to open the PDF in new window try this -
var blob = doc.output("blob");
window.open(URL.createObjectURL(blob));
Just an additional "Enter" on the browser address bar will show the PDF in chrome.
UPDATE
Longer URL's are not supported by Chrome as per this. Canvas in the fiddle is generating base64 URL which Chrome fails to load.

Kendo Chart Export to JPG or PNG

I have been researching this topic for awhile now. I know there are other questions relating this topic but a lot of the answers I haven't gotten to work or lead to 404 Not Found Webpages like this one http://www.kendoui.com/code-library/dataviz/chart/kendo-ui-chart-export.aspx. Does anyone have a current way to export a Kendo Chart to JPG or PNG? I have tried looking to Inkscape but I am not familiar with it at all.
Using the nuGet library svg and posting a tidbit that might be useful for you. You can obtain the svgFileContents from and chart.
public BitMap RenderReportFromSVG(string svgFileContents)
{
System.Drawing.Bitmap _bitmap=null;
byte[] byteArray = Encoding.ASCII.GetBytes(svgFileContents);
using (var stream = new MemoryStream(byteArray))
{
XmlDocument xdoc=new XmlDocument();
xdoc.LoadXml(svgFileContents);
var svgDocument = SvgDocument.Open(xdoc);
_bitmap = svgDocument.Draw();
}
return _bitmap;
}

How can I take a screenshot of a website with MVC?

I am struggling to find a way to take a screenshot of a website in MVC4. I have seen two potential solutions, which neither work well for MVC.
The first is using the WebBrowser, tutorial found here, but this gives me a ActiveX control '8856f961-340a-11d0-a96b-00c04fd705a2' cannot be instantiated because the current thread is not in a single-threaded apartment error.
The other is using a 3rd party called Grabz.It, but I haven't found a way to integrate it into MVC.
Any other ideas/solutions?
Thanks.
Given your additional details, you should be able to do this with any number of tools. CodeCaster's idea is fine, and PhantomJS also offers similar webkit-based image generation of an arbitrary url (https://github.com/ariya/phantomjs/wiki/Screen-Capture). It offers several output format options, such as PNG, JPG, GIF, and PDF.
Since PhantomJS is using WebKit, a real layout and rendering engine, it can capture a web page as a screenshot. Because PhantomJS can render anything on the web page, it can be used to convert contents not only in HTML and CSS, but also SVG and Canvas.
You would need to execute the phantomjs.exe app from your MVC app, or probably even better by some service that is running behind the scenes to process a queue of submitted urls.
Why do you want to integrate this in MVC? Is it your website's responsibility to take screenshots of other websites? I would opt to create the screenshot-taking-logic in a separate library, hosted as a Windows Service for example.
The WebBrowser control needs to run on an UI thread, which a service (like IIS) doesn't have. You can try other libraries though.
You could for example write some code around wkhtmltopdf, which renders (as the name might suggest) HTML to PDF using the WebKit engine.
You need to specify that the thread is in STA (single threaded apartment mode in order to instantiate the web browser).
public ActionResult Save()
{
var url = "http://www.google.co.uk";
FileContentResult result = null;
Bitmap bitmap = null;
var thread = new Thread(
() =>
{
bitmap = ExportUrlToImage(url, 1280, 1024);
});
thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
thread.Start();
thread.Join();
if (bitmap != null)
{
using (var memstream = new MemoryStream())
{
bitmap.Save(memstream, ImageFormat.Jpeg);
result = this.File(memstream.GetBuffer(), "image/jpeg");
}
}
return result;
}
private Bitmap ExportUrlToImage(string url, int width, int height)
{
// Load the webpage into a WebBrowser control
WebBrowser wb = new WebBrowser();
wb.ScrollBarsEnabled = false;
wb.ScriptErrorsSuppressed = true;
wb.Navigate(url);
while (wb.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
// Set the size of the WebBrowser control
wb.Width = width;
wb.Height = height;
Bitmap bitmap = new Bitmap(wb.Width, wb.Height);
wb.DrawToBitmap(bitmap, new System.Drawing.Rectangle(0, 0, wb.Width, wb.Height));
wb.Dispose();
return bitmap;
}

Resources