Pdfmake: .download() and .open() throws error "images dictionary should contain dataURL entries" in Chrome

Created on 13 Mar 2017  路  10Comments  路  Source: bpampuch/pdfmake

I am using pdfmake.min and vfs_fonts in my application to print a 4 page pdf document. The document contains 17 tables, and 18 images. All the images are converted into base64 and used in the application. I convert the images using a javascript function.
Currently am using 0.1.26 version of pdfmake.
I can download the pdf file without any problem using firfox. But when I test it with Chrome I get the error Uncaught invalid image, images dictionary should contain dataURL entries (or local file paths in node.js) for both .download() and .open()

Also when I am using .open() in Chrome a window will open and vanish suddenly.

How to solve this issue?

Most helpful comment

Having a similar issue.
I need to add a single image to a document. In my case i'm using the image path and i get the following error every time i try to download the document:

invalid image, images dictionary should contain dataURL entries (or local file paths in node.js)

Here's a sample of my code:

var docDefinition =
{
    pageSize: 'A4',
    content:
    [
        {
            margin: [cmToPoints(3.6), cmToPoints(1.5), 0, cmToPoints(1)],
            image: 'img/myImage.jpg',
            fit: [cmToPoints(6.5), cmToPoints(7.7)]
        }
    ]
};


pdfMake.createPdf(docDefinition).download('test.pdf');

How could i resolve my issue without convert the image to base64? As a note, i'm using AngularJS and Electron in my project.

All 10 comments

Do you have any simple example, executable on http://pdfmake.org/playground.html?

Well Its a small part of a big application. I will explain it like this.

I included the pdfmake.min.js and vfs_font.js in my src/js folder. And then shim them in main.js.

d1

Then I defined it globally in the js file that I want to generate the pdf.

define([
    'jquery',
    'views/base/view',
    'config/config',
    'config/Queries',
    'config/events',
    'i18n!nls/countryProfiles',
    'text!templates/countryProfiles/profile.hbs',
    'handlebars',
    'fx-chart/start',
    'pdfmake',
    'amplify'
], function ($,View, C, Q, E, i18nLabels, template,Handlebars,Chart,pdfMake) {

One picture that is using in the application is a country flag. I convert it to base64 using the following function. Same with the other 17 images.

toDataUrl(flag,function(base64Image){
                 flag_pdf.push(base64Image);
              });
var image = _.range(1,18,1);
_.each(image,function(obj){
                  var goal_image = 'src/images/escap/'+obj+'.png';
                  toDataUrl(goal_image,function(base64Image){
                     flag_pdf.push(base64Image);
                  });
          });

The function toDataUrl is:

function toDataUrl(file,callback) {
           var xhr = new XMLHttpRequest();
              xhr.responseType = 'blob';
              xhr.onload = function() {
             var reader = new FileReader();
             reader.onloadend = function() {
              callback(reader.result);
           }
             reader.readAsDataURL(xhr.response);
          };
           xhr.open('GET', file);
           xhr.send();
           }

Then the data required for the tables are read through an ajax call and assigned to 17 arrays.

var dataUrl = baseUrl+"SDG_PROFILE_"+self.country_id+".json";
                $.ajax({
                  async: false,
                  dataType: 'json',
                  url: dataUrl,
                  contentType: "application/json; charset=utf-8",
                  type: 'get',
                  success:function(res){
                    Goal1 = res.Goal1.data;}
            });

The json data is:

    "Goal1" : {
        "data" : [
            {
                "Indicator_id" : "1.1.1",
                "Indicator_name" : "Population living in poverty at $1.90 a day in 2011 PPP 2016 (% of population)",
                "Earliest" : "-",
                "Latest" : "-"
            },
            {
                "Indicator_id" : "1.1.1",
                "Indicator_name" : "Share of extremely poor living on less than  US$1.90 a day in total employment, total (% of total employment), 2005",
                "Earliest" : "78.56",
                "Latest" : "-"
            },
            {
                "Indicator_id" : "1.2.1",
                "Indicator_name" : "Population living below the national poverty line 2016 (% of population), 2007, 2011",
                "Earliest" : "36.3",
                "Latest" : "35.8"
            },
            {
                "Indicator_id" : "1.3.1",
                "Indicator_name" : "Social health protection (% of population)",
                "Earliest" : "-",
                "Latest" : "-"
            },
            {
                "Indicator_id" : "1.5.1+",
                "Indicator_name" : "Disasters, people affected (Thousands per annum), 2000, 2015",
                "Earliest" : "2582",
                "Latest" : "26.57"
            },
            {
                "Indicator_id" : "1.5.1+",
                "Indicator_name" : "Disasters, deaths (Per million population), 2000, 2016",
                "Earliest" : "30.15",
                "Latest" : "2.008"
            },
            {
                "Indicator_id" : "1.a.2",
                "Indicator_name" : "Public expenditure on education (% of total government expenditure), 2010, 2014",
                "Earliest" : "22.24",
                "Latest" : "18.4"
            },
            {
                "Indicator_id" : "1.a.2+",
                "Indicator_name" : "General government health expenditure (% of government expenditure), 2002, 2014",
                "Earliest" : "8.987",
                "Latest" : "12"
            }
        ]
    }

A separate array is created for each table that will be used in the pdfmake document definition.

  $('#goal1_table').html('<tr><td class="col-md-1"></td><td class="col-md-3"></td><td class="col-md-1" style="text-align: right;">'+
              'Earliest</td><td class="col-md-1" style="text-align: right;">Latest</td></tr>').show();
              var goal1_data = [['','','Earliest','Latest']];

              _.each(Goal1,function(obj){
                var Indicator_id = obj.Indicator_id;
                var Indicator_name = obj.Indicator_name;
                if(obj.Earliest != '-'){
                  var earliest_data = parseFloat(obj.Earliest).toFixed(1);
                }else{
                  var earliest_data = obj.Earliest;
                }
                if(obj.Latest != '-'){
                  var latest_data = parseFloat(obj.Latest).toFixed(1);
                }else{
                  var latest_data = obj.Latest;
                }

                $('#goal1_table').append('<tr><td>'+Indicator_id+'</td><td>'+Indicator_name+
                '<td style="text-align: right;">' +earliest_data+ '</td><td style="text-align: right;"> '+latest_data+' </td></td></tr>').show();

                goal1_data.push([Indicator_id, Indicator_name,{text: earliest_data, alignment:'right'},{text: latest_data, alignment:'right'}]);
              });

goal1_data is the array that is used in the document definition. And my document definition is:

          var docDefinition = {
            info: {
              title: 'Country Profile',
              author: 'UNESCAP Statistics Division'
            },
            footer: function(currentPage, pageCount) { return currentPage.toString() + ' of ' + pageCount},
            header: function() {
                  return { text: '2017 Asia-Pacific SDG Partnership',
                  alignment: 'right',
                  italics: true,
                  fontSize: 6,
                  margin: 10};
              },
              content: [
              {columns:[
                {
                  width:'*',
                  text: 'SDG Profile - '+ self.country_name , style: 'header',margin: 5
                },
                {
                  width:50,
                  height:28,
                  alignment:'right',
                  image: 'flag'
                }
              ]},
              {
                columns:[
                  {
                    width:30,
                    height:30,
                    alignment:'left',
                    image:'goal1'
                  },
                  {
                    width:'*',
                    text: 'Goal 1 : No Poverty',
                    style: 'goalheader'
                  }
                ]},
              {
                table: {
                  headerRows: 1,
                  widths: [ '10%', '*','15%', '15%'],
                  body: goal1_data
                }
              }
            ],
images: {
              flag: flag_pdf[0],
              goal1:flag_pdf[1],
              },
              styles: {
                header: {
                fontSize: 22,
                bold: true
              },
              goalheader:{
                fontSize: 18,
                margin:5
              },
              tableHeader: {
                fontSize: 8
              }
            }
        }

Finally I call the .download() method in a on.('click') event of a button.

$('#profile').on('click',function(){
           pdfMake.createPdf(docDefinition).download('SDGProfile.pdf');
           /*if(isFirefox == true){
             pdfMake.createPdf(docDefinition).download('SDGProfile.pdf');
           }else{
             pdfMake.createPdf(docDefinition).open();
           }*/

      });

In the code sinnept in comments I tried to detect the browser type and then vary the function .dowload() and .open(). The final output that I get from FF is look like follows.

d3

I hope this explains you how I used pdfmake in my application.

Having a similar issue.
I need to add a single image to a document. In my case i'm using the image path and i get the following error every time i try to download the document:

invalid image, images dictionary should contain dataURL entries (or local file paths in node.js)

Here's a sample of my code:

var docDefinition =
{
    pageSize: 'A4',
    content:
    [
        {
            margin: [cmToPoints(3.6), cmToPoints(1.5), 0, cmToPoints(1)],
            image: 'img/myImage.jpg',
            fit: [cmToPoints(6.5), cmToPoints(7.7)]
        }
    ]
};


pdfMake.createPdf(docDefinition).download('test.pdf');

How could i resolve my issue without convert the image to base64? As a note, i'm using AngularJS and Electron in my project.

As far as I experienced with the library you have to convert the image to base64. You can simply use the javascript function given below to convert it.

function toDataUrl(file,callback) {
           var xhr = new XMLHttpRequest();
              xhr.responseType = 'blob';
              xhr.onload = function() {
             var reader = new FileReader();
             reader.onloadend = function() {
              callback(reader.result);
           }
             reader.readAsDataURL(xhr.response);
          };
           xhr.open('GET', file);
           xhr.send();
           }

I referred This Stack Overflow Question to get an understanding about the different methods that can be used.

In the demos page (http://pdfmake.org/playground.html) they have examples using base64 images and image paths. So there must be a way to do this without converting the images to base64.
If i could do this without converting the image to base64, would be great.

The issue Insert images by URL #170 as well as the Stackoverflow question Image not showing when generating pdf in angularjs using pdfmake specifies that you need to convert the image to base64.

Thanks for referencing those issues. In the official documentation there is this option:

{
      // under NodeJS (or in case you use virtual file system provided by pdfmake)
      // you can also pass file names here
      image: 'myImageDictionary/image1.jpg'
} 

In my case i'm using AngularJS and Electron, which is based on NodeJS. So it might be indeed possible.
How can accomplish inserting an image by its path using NodeJS or virtual file system?

I have the same problem as @bhagyamaheshi on Chrome. Works fine on Firefox.
Do we have any further informations about this issue ? Thanks

EDIT: I tried to run my code and open a PDF on Chrome with several builds of the library. After build 0.1.20 Chrome does not open the file. It would be great if somebody else could confirm.

I solved the problem. The problem was with the docDefinition.image object. In chrome the docDefinition object is initiated before the image URLs being created. So I tracked the browser type and assigned the image URI in a callback function. Then it works for all .open, .download() and .print() methods. Am adding the modifications I used in case some one wants to refer.

var isFirefox = typeof InstallTrigger !== 'undefined';
var flag ='src/images/cou_flag.png';

toDataUrl(flag,function(base64Image){
       if(isFirefox == true){
          flag_pdf.push(base64Image);
       }else{
          docDefinition.images.flag = base64Image;
       }
     });
var docDefinition = {
content: [
              {columns:[
                {
                  width:'*',
                  text: 'Statistical Profile - '+ self.country_name , style: 'header',margin: 5
                },
                {
                  width:50,
                  height:28,
                  alignment:'right',
                  image: 'flag'
                }
              ]}
],
images: {
            flag: flag_pdf[0]
}
};


Having a similar issue.I just want to convert html to pdf.

               $scope.export = function(){
            /* console.log(canvas);*/
             html2canvas(document.getElementById('exportthis'), {
                onrendered: function (canvas) {
                    var data = canvas.toDataURL();
                    var docDefinition = {
                        content: [{
                            image: data,
                            width: 763,
                            /*height:500*/
                        }]
                    };
                    pdfMake.createPdf(docDefinition).download("web.pdf");
                }
            });
         }
Was this page helpful?
0 / 5 - 0 ratings

Related issues

svenyonson picture svenyonson  路  3Comments

dgrice picture dgrice  路  3Comments

einfallstoll picture einfallstoll  路  3Comments

kamilkp picture kamilkp  路  3Comments

jkd003 picture jkd003  路  3Comments