web-dev-qa-db-fra.com

Télécharger une API de graphes Facebook sur une image base64

J'essaie de télécharger une image base64 sur une page FaceBook à l'aide de Node.js. J'ai réussi à faire en sorte que le téléchargement fonctionne avec toutes les données multiparties, etc. Si je lis le fichier depuis le système de fichiers (par exemple, en utilisant fs.readFileSync ('c:\a.jpg')

Cependant, si je devais utiliser l'image encodée en base64 et essayer de la télécharger, elle me donnerait l'erreur suivante: {"error":{"message":"(#1) An unknown error occurred","type":"OAuthException","code":1}}

J'ai essayé de le convertir en binaire par new Buffer(b64string, 'base64'); et de le télécharger, mais sans succès.

Cela fait 3 jours que je me bats avec cela, alors toute aide serait grandement appréciée.

Edit: Si quelqu'un sait également comment je peux convertir le base64 en fichier binaire et le télécharger avec succès, cela fonctionnera également pour moi.

Edit: extrait de code

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)]);
20
Mauro

Le code ci-dessus n'a pas fonctionné pour moi (les virgules manquantes après type:"POST", et les erreurs de rapport d'URI de données à blob ont signalé des erreurs. J'ai obtenu le code suivant pour qu'il fonctionne dans Firefox et 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' });
}

Voici le code sur GitHub https://github.com/DanBrown180/html5-canvas-post-to-facebook-base64

14
Dan Brown

J'espère que cela vous sera utile. En téléchargeant des photos sur FB uniquement à l'aide de javascript, vous pouvez utiliser la méthode suivante. Les éléments requis ici sont imageData (format image base64) et le type mime. 

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 SYNTAXE

23
Brune

La réponse de Dan fonctionne le mieux. L'argument facultatif de publication de photos, appelé «no_story», pourrait également être utile dans ce scénario. La valeur par défaut de cette argument est true, ce qui oblige la photo-message à ignorer le mur de l'utilisateur. En ajoutant 

fd.append("no_story", false);

vous pouvez mettre à jour le mur de l'utilisateur avec la photo-post.

Je voudrais juste laisser cela comme un commentaire, mais ... 50 Rep pour les commentaires.

2
Schenn

Nous pouvons simplifier le recodage d'images en utilisant l'API Fetch moderne au lieu de Uint8Array.

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

 fetch(url)
  .then(res => res.blob())
  .then(blob => console.log(blob))`
1
Max Prokopov

J'ai fait quelque chose de très similaire à votre question. J'avais un instantané de la webcam qui devait être posté sur une page fan de Facebook. La configuration était dans un restaurant où les gens pouvaient prendre une photo et celle-ci serait affichée sur la page Restaurants. Les gens verraient alors un code QR sur la photo facebook postée qu'ils pourraient choisir de partager sur leur propre profil. J'espère que cela pourra aider quelqu'un parce que j'ai beaucoup cherché à atteindre cette SOLUTION qui fonctionne.

Remarque: Mon image est déjà encodée en BASE64.

//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 );
    }
1
tim

Voici comment j'ai pu publier une image sur facebook à l'aide de l'API JS de Facebook . J'utilise la fonctionnalité de toile HTML5. Ce n'est pas entièrement supporté par tous les navigateurs. 

Vous devez d'abord obtenir les données de l'image. Ensuite, pour l'encapsuler dans un formulaire de données ..__, j'utilise ensuite l'API FB.login afin de récupérer le jeton d'accès et l'ID utilisateur.

          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'});
1
Alexandre Mélard

Voici un exemple qui n'a pas besoin de jQuery ou d'autres bibliothèques, mais uniquement de l'API Fetch native:

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/

0
luschn