My Portfolio
Posting a HTML5 Canvas image to Facebook and Twitter
Scroll down to discover
Back to Blog

Posting a HTML5 Canvas image to Facebook and Twitter

2 years agoCategory : CodingTutorialsWeb
Posting a HTML5 Canvas image to Facebook and Twitter

Update #1 - June 8, 2019

Due to changes to their API, Canvas image sharing to Facebook is not possible at this time.


Part of a recent project was to take an HTML 5 Canvas Image and post it to Facebook and Twitter. Although this sounds pretty straightforward, the challenge was that there would be no image saved to the server. I couldn't just slap share buttons on the page, because share dialogs expect content that already exists on a server. Using Facebook's API and Twitter's API we are able to share rich dynamic content. Here's a guide on what I did... (PHP, Javascript, jQuery, TwitterOAuth)

Code on Github

Canvas Image

Lets create a simple canvas element and add an image of a panda (we all like pandas, right?).

HTML

1<canvas id="canvas" style="border:1px solid black;" width="256" height="256"></canvas>

JavaScript

1// Canvas Object
2var canvas = document.getElementById('canvas');
3var ctx = canvas.getContext('2d');
4
5// load image from data url
6var imageObj = new Image();
7imageObj.onload = function() {
8ctx.drawImage(this, 0, 0);
9};
10
11imageObj.src = 'panda_dark.png';

Resulting Canvas

Canvas to Base64 to Blob/Binary String to Social Media

In the following steps we will convert the canvas image to base64 by using .toDataURL() which is part of the Canvas API.

HTMLCanvasElement.toDataURL() Returns a data-URL containing a representation of the image in the format specified by the type parameter.

The function below will take the base64 string and convert it to a Blob/Binary String that will be sent to the Facebook and Twitter APIs. This function will be referenced later in the code.

Blob(blobParts[, options]) Returns a newly created Blob object whose content consists of the concatenation of the array of values given in parameter.

1function dataURItoBlob(dataURI) {
2    var byteString = atob(dataURI.split(',')[1]);
3    var ab = new ArrayBuffer(byteString.length);
4    var ia = new Uint8Array(ab);
5    for (var i = 0; i < byteString.length; i++) {
6        ia[i] = byteString.charCodeAt(i);
7    }
8    return new Blob([ab], {type: 'image/png'});
9}

Posting to Facebook

Posting the image to Facebook will require creating a Facebook app which you will also need to request the 'publish_actions' permission when making the app live.  Now we create a 'Post to Facebook' button and link a click handler for the logic. Below you can see that we grab the base64 encoding of the canvas image that has been returned in the format of a .png image. We then try to convert the base64 string into a Blob. Using the Facebook JS SDK, after the user has logged in and given the app permission, the 'postImageToFacebook' function is called and passed several arguments.

1$('#shareFB').click(function () {
2    var data = $('#canvas')[0].toDataURL("image/png");
3    try {
4        blob = dataURItoBlob(data);
5    } catch (e) {
6        console.log(e);
7    }
8    FB.getLoginStatus(function (response) {
9        console.log(response);
10        if (response.status === "connected") {
11            postImageToFacebook(response.authResponse.accessToken, "Canvas to Facebook/Twitter", "image/png", blob, window.location.href);
12        } else if (response.status === "not_authorized") {
13            FB.login(function (response) {
14                postImageToFacebook(response.authResponse.accessToken, "Canvas to Facebook/Twitter", "image/png", blob, window.location.href);
15            }, {scope: "publish_actions"});
16        } else {
17            FB.login(function (response) {
18                postImageToFacebook(response.authResponse.accessToken, "Canvas to Facebook/Twitter", "image/png", blob, window.location.href);
19            }, {scope: "publish_actions"});
20        }
21    });
22});

Posting to the blob to facebook requires the use of FormData. The function first uploads the picture to facebook without creating a story on the user's timeline. Then it retrieves the saved image and creates a story on the user's timeline using the fields provided. NOTE: The 'message' field must be left blank unless you provide the user a way to add one.

1function postImageToFacebook(token, filename, mimeType, imageData, message) {
2    var fd = new FormData();
3    fd.append("access_token", token);
4    fd.append("source", imageData);
5    fd.append("no_story", true);
6
7    // Upload image to facebook without story(post to feed)
8    $.ajax({
9        url: "https://graph.facebook.com/me/photos?access_token=" + token,
10        type: "POST",
11        data: fd,
12        processData: false,
13        contentType: false,
14        cache: false,
15        success: function (data) {
16            console.log("success: ", data);
17
18            // Get image source url
19            FB.api(
20                "/" + data.id + "?fields=images",
21                function (response) {
22                    if (response && !response.error) {
23                        //console.log(response.images[0].source);
24
25                        // Create facebook post using image
26                        FB.api(
27                            "/me/feed",
28                            "POST",
29                            {
30                                "message": "",
31                                "picture": response.images[0].source,
32                                "link": window.location.href,
33                                "name": 'Look at the cute panda!',
34                                "description": message,
35                                "privacy": {
36                                    value: 'SELF'
37                                }
38                            },
39                            function (response) {
40                                if (response && !response.error) {
41                                    /* handle the result */
42                                    console.log("Posted story to facebook");
43                                    console.log(response);
44                                }
45                            }
46                        );
47                    }
48                }
49            );
50        },
51        error: function (shr, status, data) {
52            console.log("error " + data + " Status " + shr.status);
53        },
54        complete: function (data) {
55            //console.log('Post to facebook Complete');
56        }
57    });
58}

Resulting Post to Facebook

Posting to Twitter

Posting the image to twitter will also require you to create a Twitter App. Twitter still uses OAuth 1.0, so you will either need to use server-side code or a service such as ouath.io. Unless requested I'll skip the authentication process here for TwitterOAuth which I'm using. The functions used below handle the popup that communicates with server-side code Credits to https://github.com/nobuf/jQuery-OAuth-Popup.

1// Twitter oauth handler
2$.oauthpopup = function (options) {
3    if (!options || !options.path) {
4        throw new Error("options.path must not be empty");
5    }
6    options = $.extend({
7        windowName: 'ConnectWithOAuth' // should not include space for IE
8        , windowOptions: 'location=0,status=0,width=800,height=400'
9        , callback: function () {
10            debugger;
11            //window.location.reload();
12        }
13    }, options);
14
15    var oauthWindow = window.open(options.path, options.windowName, options.windowOptions);
16    var oauthInterval = window.setInterval(function () {
17        if (oauthWindow.closed) {
18            window.clearInterval(oauthInterval);
19            options.callback();
20        }
21    }, 1000);
22};
23// END Twitter oauth handler
24
25//bind to element and pop oauth when clicked
26$.fn.oauthpopup = function (options) {
27    $this = $(this);
28    $this.click($.oauthpopup.bind(this, options));
29};

Posting to Twitter is similar to Facebook in the case that you use FormData, but this is sent to your server-side handler or service instead. You can send the image as a Blob but this is not necessary. The variable window.twit contains authentication data sent from the popup window back to the parent webpage/tab.

1$('#shareTW').click(function () {
2    var dataURL = $('#canvas')[0].toDataURL("image/png");
3    $.oauthpopup({
4        path: '/auth/twitter.php',
5        callback: function () {
6            console.log(window.twit);
7            var data = new FormData();
8            // Tweet text
9            data.append('status', "Look at the cute panda! " + window.location.href + " @jerezb31");
10            // Binary image
11            data.append('image', dataURL);
12            // oAuth Data
13            data.append('oauth_token', window.twit.oauth_token);
14            data.append('oauth_token_secret', window.twit.oauth_token_secret);
15            // Post to Twitter as an update with
16
17            return $.ajax({
18                url: '/auth/share-on-twitter.php',
19                type: 'POST',
20                data: data,
21                cache: false,
22                processData: false,
23                contentType: false,
24                success: function (data) {
25                    console.log('Posted to Twitter.');
26                    console.log(data);
27                }
28            });
29        }
30    });
31});

Here is the snippet of server-side code that handles the FormData to be sent to twitter using TwitterOAuth. The credentials are verified then the base64 image is uploaded to Twitter's API 'upload/image' endpoint. The object returned is then added to the list of parameters for posting a status.

1// '/auth/share-on-twitter.php'
2
3require_once '../vendor/abraham/twitteroauth/autoload.php';
4use Abraham\TwitterOAuth\TwitterOAuth;
5
6session_start();
7
8define('CONSUMER_KEY', '*************');
9define('CONSUMER_SECRET', '************');
10define('OAUTH_CALLBACK', '*****************');
11
12//echo '<pre>'.print_r($_REQUEST).'</pre>';
13//exit;
14
15$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $_REQUEST['oauth_token'], $_REQUEST['oauth_token_secret']);
16$twitterUser = $connection->get("account/verify_credentials");
17
18$media1 = $connection->upload('media/upload', ['media' => $_REQUEST['image']]);
19$parameters = [
20    'status' => $_REQUEST['status'],
21    'media_ids' => implode(',', [$media1->media_id_string]),
22];
23$result = $connection->post('statuses/update', $parameters);
24echo json_encode($result);

Resulting post to Twitter

View the working Demo!

Code on Github

© Jerez Bain 2020 / All rights reserved.
To top