0

I've been trying to get a Base64 string from a canvas. But I cannot. The following code does nothing. It should be insert an image into document.body. On the other hand I've tried to get base64 string and converting an image. But again I cannot.

what should I do?

http://jsfiddle.net/27hdp4y6/1/

var image1 = new Image();
image1.src = "http://www.w3.org/html/logo/downloads/HTML5_Logo_128.png";
var image2 = new Image();
image2.src = "http://prismitsolutions.com/images/icons/css3.png";

var canvas = document.createElement('canvas');
canvas.width = 220;
canvas.height= image1.height;
var context = canvas.getContext("2d");

image1.onload = function() {

   context.drawImage(image1, 0, 0); 
   context.drawImage(image2, 80, 0);      
};

var base64 = canvas.toDataURL('image/png');

var img = document.createElement('img');
img.src=base64;
document.body.appendChild(img);

//document.body.appendChild(canvas); 
efkan
  • 12,991
  • 6
  • 73
  • 106

3 Answers3

1

You are getting an empty canvas as your code does not wait for the images to load properly. Image loading is asynchronous.

You are also assuming that both images has loaded when image 1 has finished.

  • You need to wait for both images to load
  • Call toDataURL() from inside the load handler (or call another function to do so) after drawing the images.
  • You are trying to set the height of canvas from an image that is likely not loaded yet. Set it when you have the images loaded
  • You may get CORS restriction triggered here, make sure the images exist on the same server as page or that the server allow cross-origin usage. If not this will throw a security error.

var image1 = new Image();
var image2 = new Image();
var count = 2;             // two images to load, for more use an array instead

image1.onload = image2.onload = function() {
  count--;
  if (!count) {
    var canvas = document.createElement('canvas');
    canvas.width = 220;
    canvas.height = image1.height;
    var context = canvas.getContext("2d");

    context.drawImage(image1, 0, 0);
    context.drawImage(image2, 80, 0);

    // the data-uri, use f.ex. a callback function with this as
    // argument to process it further (not shown here)
    var base64 = canvas.toDataURL('image/png');

    var img = document.createElement('img'); // ideally, use a handler here too
    img.src = base64;
    document.body.appendChild(img);
  }
};

// we need cross-origin in this case/demo as images exists on a different server
// imgur.com allow using cross-origin, not all servers do though...
image1.crossOrigin = image2.crossOrigin = "anonymous";

// set sources after handlers are defined
image2.src = "http://i.imgur.com/bk0rvnj.png";
image1.src = "http://i.imgur.com/wlPnCM1.png";
  • I forgot to add that you should also add an error handler so you can provide feedback to the user (or log) if something unexpected happens. –  Dec 08 '14 at 13:41
  • I'm sorry stackoverflow. I have to thank for this tutorial answers. You saved my maybe 2 days. Ken, thank you very much! – efkan Dec 08 '14 at 13:43
  • @user3765109 glad I could help! Consider an up-vote if you think the answer deserved it :) –  Dec 08 '14 at 13:54
  • 1
    Oh yes, of course.. I've excited and I'm forgot that :) – efkan Dec 08 '14 at 14:11
0

Use appendChild() cf.http://jsfiddle.net/27hdp4y6/1/ Just add :

...
document.body.appendChild(canvas);
var context = canvas.getContext("2d");
...
toto21
  • 612
  • 5
  • 9
  • Hello toto21, I want to get base64 string from canvas. Then I'll try to use as an icon in my app's map plugin. https://github.com/wf9a5m75/phonegap-googlemaps-plugin/wiki/Marker#base64-encoded-icon – efkan Dec 08 '14 at 13:16
0
  1. First of all JS is async! So your images will load async too.
  2. You should append canvas to DOM:

    document.body.appendChild(canvas);

Work example: http://jsfiddle.net/27hdp4y6/2/

sergolius
  • 428
  • 3
  • 8
  • I've trid to get base64 string and I could see on the console. But the string doesn't work. http://jsfiddle.net/27hdp4y6/4/ – efkan Dec 08 '14 at 13:18
  • Here is last version: http://jsfiddle.net/27hdp4y6/5/ And, that trouble is CORS permission deny ;( You must load images from same domain. – sergolius Dec 08 '14 at 13:38
  • Yes Sergolius, you're right. But I haven't any CORS error. And I had tried two different onload method for two images to solve. But I couldn't solve. Ken's answer seems good. I'll try that. – efkan Dec 08 '14 at 13:51
  • I tried Ken's answer too, and catch an error of CORS. (after 'crossOrigin' attribute was add) – sergolius Dec 08 '14 at 17:56
  • @sergolius if, in your actual environment, is loading the images from the same domain you must *not* add crossOrigin (unless the your server support such requests). Also notice that not all servers support cors request - if they don't you will still get a cors error (which is likely the problem in this case). All we can do is to *request* permission to use images outside cors, the server can decline.. (which is why I moved the images to imgur for the demo to work) –  Dec 08 '14 at 18:13
  • Did you use files that are from your local? When I use local files me too get CORS error. But I can use on Android after build my Cordova project. If you couldn't get rid of your problem try to write jsfiddle. I'll try to help you. http://jsfiddle.net/Lcnwebss/ – efkan Dec 08 '14 at 18:15
  • And if you want you can use http://imgur.com/ to test your application. Upload your images and test. I've knew thanks to Ken.. – efkan Dec 08 '14 at 18:17