Generate PDF using EVOPdf, WebAPI and AngularJS

2.1k Views Asked by At

I'm having an issue rendering a PDF using EVOPdf from a WebAPI controller to an AngularJS app.

This is my code so far:

Angular call:

var url = 'api/form/build/' + id;

$http.get(url, null, { responseType: 'arraybuffer' })
.success(function (data) {
    var file = new Blob([data], { type: 'application/pdf' });

    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
        window.navigator.msSaveOrOpenBlob(file);
    }
    else {
        var objectUrl = URL.createObjectURL(file);
    window.open(objectUrl);
    }
});

APIController method:

var url = "http://localhost/index.html#/form/build/" + id;

#region PDF Document Setup
HtmlToPdfConverter htmlToPdfConverter = new HtmlToPdfConverter();

htmlToPdfConverter.LicenseKey = "4W9+bn19bn5ue2B+bn1/YH98YHd3d3c=";
//htmlToPdfConverter.HtmlViewerWidth = 1024; //default
htmlToPdfConverter.PdfDocumentOptions.PdfPageSize = PdfPageSize.A4;
htmlToPdfConverter.PdfDocumentOptions.PdfPageOrientation = PdfPageOrientation.Portrait;
htmlToPdfConverter.ConversionDelay = 3;
htmlToPdfConverter.MediaType = "print";

htmlToPdfConverter.PdfDocumentOptions.LeftMargin = 10;
htmlToPdfConverter.PdfDocumentOptions.RightMargin = 10;
htmlToPdfConverter.PdfDocumentOptions.TopMargin = 10;
htmlToPdfConverter.PdfDocumentOptions.BottomMargin = 10;
htmlToPdfConverter.PdfDocumentOptions.TopSpacing = 10;
htmlToPdfConverter.PdfDocumentOptions.BottomSpacing = 10;
htmlToPdfConverter.PdfDocumentOptions.ColorSpace = ColorSpace.RGB;

// Set HTML content destination in PDF page
htmlToPdfConverter.PdfDocumentOptions.Width = 640;

htmlToPdfConverter.PdfDocumentOptions.FitWidth = true;
htmlToPdfConverter.PdfDocumentOptions.StretchToFit = true; 
#endregion

byte[] outPdfBuffer = htmlToPdfConverter.ConvertUrl(url);

string outPdfFile = @"c:\temp\forms\" + id + ".pdf";
System.IO.File.WriteAllBytes(outPdfFile, outPdfBuffer);


HttpResponseMessage result = null;
result = Request.CreateResponse(HttpStatusCode.OK);
result.Content = new ByteArrayContent(outPdfBuffer.ToArray());
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = "filename.pdf";
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");

return result;

When I check the PDF that I write out using WriteAllBytes, it renders perfectly but when it is returned via the Angular call and opened in Adobe Reader, I get an "Invalid Color Space" error message that pops up quite a few times, but the document is not opened. When I change the colorspace to GrayScale, the PDF opens but it's blank.

I have a feeling that it's the ByteArrayContent conversion that's causing the issue, seen as that's the only thing that happens between the actual creation of the PDF and sending it back to the Angular call, but I've hit a brick wall and can't figure out what the problem is.

I'd really appreciate any help you guys can offer because I'm so close to sorting this out and I just need the document to "convert" properly when returned from the call.

Thanks in advance for any help.

Regards, Johann.

3

There are 3 best solutions below

0
On

Install puppeteer-core npm package cmd using npm i puppeteer-core or yarn add puppeteer-core

example.js start

const puppeteer = require('puppeteer');
(async () => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto('https://example.com');
    await page.screenshot({ path: 'example.png' });
          
    await browser.close();
})();

Execute script on the command line node example.js

Puppeteer sets an initial page size to 800×600px, which defines the screenshot size. The page size can be customized with Page.setViewport().

Example - create a PDF and Save file as hn.js

const puppeteer = require('puppeteer');
     
(async () => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto('https://news.ycombinator.com', {
        waitUntil: 'networkidle2',
    });
    await page.pdf({ path: 'hn.pdf', format: 'a4' });  
    await browser.close();
})();

Now, execute script on the command line node hn.js

See Page.pdf() for more information about creating pdfs.

Example - evaluate script in the context of the page

Save file as get-dimensions.js

const puppeteer = require('puppeteer');
 
(async () => {
   const browser = await puppeteer.launch();
   const page = await browser.newPage();
   await page.goto('https://example.com');
 
   // Get the "viewport" of the page, as reported by the page.
   const dimensions = await page.evaluate(() => {
   return {
       width: document.documentElement.clientWidth,
       height: document.documentElement.clientHeight,
       deviceScaleFactor: window.devicePixelRatio,
       };
   });
   console.log('Dimensions:', dimensions);
     
   await browser.close();
})();

Execute script on the command line node get-dimensions.js

See Page.evaluate() for more information on evaluate and related methods like evaluateOnNewDocument and exposeFunction.

0
On

Have you tried Headless Chrome? Here is a nice article about this topic. I was using https://github.com/puppeteer/puppeteer for this purpose and it was an easily integrated solution.

0
On

The problem seems to like on the client side, the characters are not properly parsed in the response. For anyone strugling with this i found my solution here: SO Question