4

I am composing an image in a canvas, I get the base64 image data by using canvas.toDataURL('png') and trimming the additional information.

 var dataUrl = canvas.toDataURL('png');
 var escapedBase64Data = dataUrl.replace("data:image/png;base64,","");

After that I try to post to facebook using:

FB.api('/me/photos', 'post', { source:data});

Photos (https://developers.facebook.com/docs/reference/api/user/) has a source property. This is where you will place the data content (multipart/form-data) of your photo.

I convert my base64 encoded data to multipart/form-data by specifying the headers.

The result looks like this:

--0.2242348059080541
Content-Disposition: file; name="file"; filename="image.png"
Content-Type: image/png
Content-Transfer-Encoding: base64

iVBORw0KGgoAAAANSUhEUgAAAfQAAAH0CAYAAADL1t+KAAAbBElEQVR4Xu3dP4jre0LG4V2xsFVYEKy
...    
QAAAABJRU5ErkJggg==

--0.2242348059080541--

After I complete the FB api call I receive the following error:

Object {message: "(#324) Requires upload file", type: "OAuthException", code: 324} 

Any suggestions?

Thanks

thedev
  • 2,816
  • 8
  • 34
  • 47
  • I haven't worked in facebook graph api. But found a simillar issue http://stackoverflow.com/questions/8639499/posting-photo-to-fb-results-in-requires-upload-file-error. Check if it helps – karthick Apr 01 '13 at 08:02
  • The other question is about img uploading from PHP and the need to enable setFileUpload support, in JS it is not the case. Thanks anyway :) – thedev Apr 01 '13 at 08:15
  • 1
    This answer worked for me: http://facebook.stackoverflow.com/a/16439233/1472477 – Justin McCraw May 14 '13 at 21:01
  • Anybody coming from Google, might find [this answer](http://stackoverflow.com/a/21145106/808734) useful. It worked for me – akotian Dec 26 '14 at 00:44

2 Answers2

1

Here a working code example :

var boundary = '----ThisIsTheBoundary1234567890';
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 += f.message + '\r\n'
formData += '--' + boundary + '--\r\n';

var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://graph.facebook.com/me/photos?access_token=' + authToken, true);
xhr.onload = xhr.onerror = function() {
    // error managment
};
xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);

//Send the request
xhr.sendAsBinary(formData);
TheLazyFox
  • 1,065
  • 3
  • 11
  • 27
  • Did you get this to work? I get an error, and this works on Firefox, but not Chrome, probably because of the sendAsBinary() not being prototyped. Thoughts? – Justin McCraw May 08 '13 at 21:48
  • try to launch chrome like this : cd C:\Program Files (x86)\Google\Chrome\Application chrome.exe "PATHTOYOURPAGE" --allow-file-access-from-files --disable-web-security – TheLazyFox May 23 '13 at 13:35
0

Here is an easy solution:

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/

andyrandy
  • 72,880
  • 8
  • 113
  • 130