Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Upload Base64 Image Facebook Graph API

I'm trying to upload a base64 image to a FaceBook page using Node.js. I have managed to get the upload working with all the multipart data etc should I read the file from the filesystem (ie. using fs.readFileSync('c:\a.jpg')

However, should I use the base64 encoded image and try upload it, it give me the following error : {"error":{"message":"(#1) An unknown error occurred","type":"OAuthException","code":1}}

I have tried converting it to binary by new Buffer(b64string, 'base64'); and uploading that, but no luck.

I have been struggling with this for 3 days now, so anyhelp would be greatly appreciated.

Edit : If anyone also knows how I could convert the base64 to binary and successfully upload it, that would also work for me.

Edit : Code Snippet

var postDetails = separator + newlineConstant + 'Content-Disposition: form-data;name="access_token"' + newlineConstant + newlineConstant + accessToken + newlineConstant + separator;

postDetails = postDetails + newlineConstant + 'Content-Disposition: form-data; name="message"' + newlineConstant + newlineConstant + message + newlineConstant;

//Add the Image information
var fileDetailsString = '';
var index = 0;
var multipartBody = new Buffer(0);
images.forEach(function (currentImage) {
    fileDetailsString = fileDetailsString + separator + newlineConstant + 'Content-Disposition: file; name="source"; filename="Image' + index + '"' + newlineConstant + 'Content-Type: image/jpeg' + newlineConstant + newlineConstant;
    index++;

    multipartBody = Buffer.concat([multipartBody, new Buffer(fileDetailsString), currentImage]); //This is what I would use if Bianry data was passed in 

    currentImage = new Buffer (currentImage.toString('base64'), 'base64'); // The following lines are what I would use for base64 image being passed in (The appropriate lines would be enabled/disabled if I was using Binary/base64)
    multipartBody = Buffer.concat([multipartBody, new Buffer(fileDetailsString), currentImage]);
});

multipartBody = Buffer.concat([new Buffer(postDetails), multipartBody, new Buffer(footer)]);
like image 995
Mauro Avatar asked Apr 25 '13 12:04

Mauro


7 Answers

I hope this will be useful. By doing photo upload to FB only with the help of javascript you can use the following method. Required thing here are imageData(which is base64 format of image) and the mime type.

try {
    blob = dataURItoBlob(imageData,mimeType);
} catch (e) {
    console.log(e);
}

var fd = new FormData();
fd.append("access_token",accessToken);
fd.append("source", blob);
fd.append("message","Kiss");

try {
   $.ajax({
        url:"https://graph.facebook.com/" + <<userID received on getting user details>> + "/photos?access_token=" + <<user accessToken>>,
        type:"POST",
        data:fd,
        processData:false,
        contentType:false,
        cache:false,
        success:function(data){
            console.log("success " + data);
        },
        error:function(shr,status,data){
            console.log("error " + data + " Status " + shr.status);
        },
        complete:function(){
            console.log("Ajax Complete");
        }
   });

} catch(e) {
    console.log(e);
}

function dataURItoBlob(dataURI,mime) {
    // convert base64 to raw binary data held in a string
    // doesn't handle URLEncoded DataURIs

    var byteString = window.atob(dataURI);

    // separate out the mime component


    // write the bytes of the string to an ArrayBuffer
    //var ab = new ArrayBuffer(byteString.length);
    var ia = new Uint8Array(byteString.length);
    for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }

    // write the ArrayBuffer to a blob, and you're done
    var blob = new Blob([ia], { type: mime });

    return blob;
}

//EDIT AJAX SYNTAX

like image 191
Brune Avatar answered Sep 26 '22 23:09

Brune


The code above didn't quite work for me (Missing comma after type:"POST", and data URI to blob function reported errors. I got the following code to work in Firefox and Chrome:

function PostImageToFacebook(authToken)
{
    var canvas = document.getElementById("c");
    var imageData  = canvas.toDataURL("image/png");
    try {
        blob = dataURItoBlob(imageData);
    }
    catch(e) {
        console.log(e);
    }
    var fd = new FormData();
    fd.append("access_token",authToken);
    fd.append("source", blob);
    fd.append("message","Photo Text");
    try {
        $.ajax({
            url:"https://graph.facebook.com/me/photos?access_token=" + authToken,
            type:"POST",
            data:fd,
            processData:false,
            contentType:false,
            cache:false,
            success:function(data){
                console.log("success " + data);
            },
            error:function(shr,status,data){
                console.log("error " + data + " Status " + shr.status);
            },
            complete:function(){
                console.log("Posted to facebook");
            }
        });
    }
    catch(e) {
        console.log(e);
    }
}

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

Here's the code at GitHub https://github.com/DanBrown180/html5-canvas-post-to-facebook-base64

like image 28
Dan Brown Avatar answered Sep 29 '22 23:09

Dan Brown


Dan's Answer works the best. Something else that might be helpful in this scenario is the optional argument for posting photos: 'no_story'. This arg defaults to true forcing the photo-post to skip the user's wall. By adding

fd.append("no_story", false);

you can update the user's wall with the photo-post.

I would have just left this as a comment but... 50 Rep for comments.

like image 27
Schenn Avatar answered Sep 25 '22 23:09

Schenn


We can simplify image recoding by usage of the modern Fetch API instead of Uint8Array.

 var url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="

 fetch(url)
  .then(res => res.blob())
  .then(blob => console.log(blob))`
like image 40
Max Prokopov Avatar answered Sep 26 '22 23:09

Max Prokopov


I did something very similar to your question. I had a webcam-snapshot that needed to be POSTed to a Facebook Fan Page. The setup was in a restaurant where people could take a picture and it would be posted onto the Restaurants Page. People would then see a QR code to the posted facebook-photo which they could choose to share on their own profile. Hope this can help somebody because I searched a lot to get to this working SOLUTION

Note: My image is BASE64 encoded already.

//imageData is a base64 encoded JPG
function postSocial(imageData, message){       
        var ia = toUInt8Array(imageData);
        postImageToFacebook(mAccessTokenPage, "imageName", "image/jpeg",ia, message);
}

function toUInt8Array(dataURI) {
        // convert base64 to raw binary data held in a string
        // doesn't handle URLEncoded DataURIs
        var byteString = window.atob(dataURI);

        // write the bytes of the string to an ArrayBuffer
        //var ab = new ArrayBuffer(byteString.length);
        var ia = new Uint8Array(byteString.length);
        for (var i = 0; i < byteString.length; i++) {
            ia[i] = byteString.charCodeAt(i);
        }
        return ia;
    }

function postImageToFacebook( authToken, filename, mimeType, imageData, message ) {        
        // this is the multipart/form-data boundary we'll use
        var boundary = '----ThisIsTheBoundary1234567890';

        // let's encode our image file, which is contained in the var
        var formData = '--' + boundary + '\r\n'
        formData += 'Content-Disposition: form-data; name="source"; filename="' + filename + '"\r\n';
        formData += 'Content-Type: ' + mimeType + '\r\n\r\n';
        for ( var i = 0; i < imageData.length; ++i )
        {
            formData += String.fromCharCode( imageData[ i ] & 0xff );
        }
        formData += '\r\n';
        formData += '--' + boundary + '\r\n';
        formData += 'Content-Disposition: form-data; name="message"\r\n\r\n';
        formData += message + '\r\n'
        formData += '--' + boundary + '--\r\n';

        var xhr = new XMLHttpRequest();
        xhr.open( 'POST', https://graph.facebook.com/ + {PAGE_ID} + "/photos?access_token=" + authToken, true );
        xhr.onload = function() {
            // ... Fill in your own
            //Image was posted 
           console.log(xhr.responseText);
        };
        xhr.onerror = function(){
            console.log("Error while sending the image to Facebook");
        };
        xhr.setRequestHeader( "Content-Type", "multipart/form-data; boundary=" + boundary );
        xhr.sendAsBinary( formData );
    }
like image 42
timr Avatar answered Sep 25 '22 23:09

timr


Here is how I was able to post an image to facebook using the facebook JS API. I am using the canvas HTML5 functionality. It's not fully supported by every browser.

You need first to get the image data. Then to encapsulate it in a form data. I then use the FB.login API in order to retrieve the access token and the userID.

          var data = $('#map >> canvas').toDataURL('image/png');
          var blob;
          try {
            var byteString = atob(data.split(',')[1]);
            var ab = new ArrayBuffer(byteString.length);
            var ia = new Uint8Array(ab);
            for (var i = 0; i < byteString.length; i++) {
              ia[i] = byteString.charCodeAt(i);
            }
            blob = new Blob([ab], {type: 'image/png'});
          } catch (e) {
            console.log(e);
          }
          var fd = new FormData();
          fd.append("source", blob);
          fd.append("message", "Photo Text");
          FB.login(function(){
            var auth = FB.getAuthResponse();
            $.ajax({
              url:"https://graph.facebook.com/"+auth.userID+"/photos?access_token=" + auth.accessToken,
              type:"POST",
              data:fd,
              processData:false,
              contentType:false,
              cache:false,
              success:function(data){
                console.log("success " + data);
              },
              error:function(shr,status,data){
                console.log("error " + data + " Status " + shr.status);
              },
              complete:function(){
                console.log("Ajax Complete");
              }
            });
          }, {scope: 'publish_actions'});
like image 24
Alexandre Mélard Avatar answered Sep 27 '22 23:09

Alexandre Mélard


Here is an example that does not need jQuery or other libraries, just the native Fetch API:

const dataURItoBlob = (dataURI) => {
    let byteString = atob(dataURI.split(',')[1]);
    let ab = new ArrayBuffer(byteString.length);
    let ia = new Uint8Array(ab);
    for (let i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }
    return new Blob([ia], {
        type: 'image/jpeg'
    });
}
const upload = async (response) => {
    let canvas = document.getElementById('canvas');
    let dataURL = canvas.toDataURL('image/jpeg', 1.0);
    let blob = dataURItoBlob(dataURL);
    let formData = new FormData();
    formData.append('access_token', response.authResponse.accessToken);
    formData.append('source', blob);

    let responseFB = await fetch(`https://graph.facebook.com/me/photos`, {
        body: formData,
        method: 'post'
    });
    responseFB = await responseFB.json();
    console.log(responseFB);
};
document.getElementById('upload').addEventListener('click', () => {
    FB.login((response) => {
        //TODO check if user is logged in and authorized publish_actions
        upload(response);
    }, {scope: 'publish_actions'})
})

Source: http://www.devils-heaven.com/facebook-javascript-sdk-photo-upload-from-canvas/

like image 44
andyrandy Avatar answered Sep 25 '22 23:09

andyrandy