web-dev-qa-db-fra.com

Télécharger une image à l'aide de XMLHttpRequest dans un script utilisateur

Tout d'abord, il y a une question avec le même titre ici sur SO, mais ce n'est pas ce que je recherche et il n'a pas de réponse complète non plus.

Alors voici ma question. Dites que j'ai cette URL qui dirige vers une image.

https://fbcdn-photos-a.akamaihd.net/hphotos-ak-ash4/299595_10150290138650735_543370734_8021370_355110168_n.jpg

Une fois que je mets ce paramètre ?dl=1 à la fin de l'URL, il devient téléchargeable.

https://fbcdn-photos-a.akamaihd.net/hphotos-ak-ash4/299595_10150290138650735_543370734_8021370_355110168_n.jpg?dl=1

J'essaie de faire cette tâche à l'aide d'un script utilisateur. J'ai donc utilisé XMLHttpRequest pour cela.

var url = "https://fbcdn-photos-a.akamaihd.net/hphotos-ak-ash4/299595_10150290138650735_543370734_8021370_355110168_n.jpg?dl=1";

var request = new XMLHttpRequest();  
request.open("GET", url, false);   
request.send(null);  

if (request.status === 200) 
{  
    alert(request.statusText);
}

Voici un violon .

Mais ça ne marche pas.

15
Isuru

XMLHttpRequest ne fonctionnera pas entre plusieurs domaines, mais puisqu'il s'agit d'un userscript __, Chrome prend désormais en charge GM_xmlhttpRequest() dans les scripts utilisateur uniquement.

Quelque chose comme cela devrait fonctionner, notez qu'il est asynchrone:

GM_xmlhttpRequest ( {
    method:         'GET',
    url:            'https://fbcdn-photos-a.akamaihd.net/hphotos-ak-ash4/299595_10150290138650735_543370734_8021370_355110168_n.jpg?dl=1',
    onload:         function (responseDetails) {
                        alert(responseDetails.statusText);
                    }
} );




En ce qui concerne obtenir et utiliser les données d’image réelles , il s’agit d’une tâche ardue.

  • Vous pouvez utiliser la nouvelle fonctionnalité .responseType = "blob"; dans Firefox, mais Chrome ne la prend pas encore en charge .

  • Dans Chrome ou Firefox, pour le même domaine uniquement , vous pouvez utiliser le nouveau XHR2 comme ceci:
    Voyez-le en action à jsBin.

    BlobBuilder             = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder;
    
    var url                 = "http://jsbin.com/images/gear.png";
    var request             = new XMLHttpRequest();
    request.open ("GET", url, false);
    request.responseType    = "arraybuffer";
    request.send (null);
    
    if (request.status === 200) {
        var bb              = new BlobBuilder ();
        bb.append (request.response); // Note: not request.responseText
    
        var blob            = bb.getBlob ('image/png');
        var reader          = new FileReader ();
        reader.onload       = function (zFR_Event) {
            $("body").prepend ('<p>New image: <img src="' + zFR_Event.target.result + '"></p>')
        };
    
        reader.readAsDataURL (blob);
    }
    


  • Malheureusement, GM_xmlhttpRequest() ne prend pas (encore) en charge la configuration de responseType.


Ainsi, pour GM script ou applications usercript, nous devons utiliser un schéma de codage base64 personnalisé comme dans "Javascript Hacks: utiliser XHR pour charger des données binaires" .

Le code de script devient quelque chose comme:

var imgUrl              = "http://jsbin.com/images/gear.png";

GM_xmlhttpRequest ( {
    method:         'GET',
    url:            imgUrl,
    onload:         function (respDetails) {
                        var binResp     = customBase64Encode (respDetails.responseText);

                        /*-- Here, we just demo that we have a valid base64 encoding
                            by inserting the image into the page.
                            We could just as easily AJAX-off the data instead.
                        */
                        var zImgPara    = document.createElement ('p');
                        var zTargetNode = document.querySelector ("body *"); //1st child

                        zImgPara.innerHTML = 'Image: <img src="data:image/png;base64,'
                                           + binResp + '">';
                        zTargetNode.parentNode.insertBefore (zImgPara, zTargetNode);
                    },
    overrideMimeType: 'text/plain; charset=x-user-defined'
} );


function customBase64Encode (inputStr) {
    var
        bbLen               = 3,
        enCharLen           = 4,
        inpLen              = inputStr.length,
        inx                 = 0,
        jnx,
        keyStr              = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
                            + "0123456789+/=",
        output              = "",
        paddingBytes        = 0;
    var
        bytebuffer          = new Array (bbLen),
        encodedCharIndexes  = new Array (enCharLen);

    while (inx < inpLen) {
        for (jnx = 0;  jnx < bbLen;  ++jnx) {
            /*--- Throw away high-order byte, as documented at:
              https://developer.mozilla.org/En/Using_XMLHttpRequest#Handling_binary_data
            */
            if (inx < inpLen)
                bytebuffer[jnx] = inputStr.charCodeAt (inx++) & 0xff;
            else
                bytebuffer[jnx] = 0;
        }

        /*--- Get each encoded character, 6 bits at a time.
            index 0: first  6 bits
            index 1: second 6 bits
                        (2 least significant bits from inputStr byte 1
                         + 4 most significant bits from byte 2)
            index 2: third  6 bits
                        (4 least significant bits from inputStr byte 2
                         + 2 most significant bits from byte 3)
            index 3: forth  6 bits (6 least significant bits from inputStr byte 3)
        */
        encodedCharIndexes[0] = bytebuffer[0] >> 2;
        encodedCharIndexes[1] = ( (bytebuffer[0] & 0x3) << 4)   |  (bytebuffer[1] >> 4);
        encodedCharIndexes[2] = ( (bytebuffer[1] & 0x0f) << 2)  |  (bytebuffer[2] >> 6);
        encodedCharIndexes[3] = bytebuffer[2] & 0x3f;

        //--- Determine whether padding happened, and adjust accordingly.
        paddingBytes          = inx - (inpLen - 1);
        switch (paddingBytes) {
            case 1:
                // Set last character to padding char
                encodedCharIndexes[3] = 64;
                break;
            case 2:
                // Set last 2 characters to padding char
                encodedCharIndexes[3] = 64;
                encodedCharIndexes[2] = 64;
                break;
            default:
                break; // No padding - proceed
        }

        /*--- Now grab each appropriate character out of our keystring,
            based on our index array and append it to the output string.
        */
        for (jnx = 0;  jnx < enCharLen;  ++jnx)
            output += keyStr.charAt ( encodedCharIndexes[jnx] );
    }
    return output;
}
22
Brock Adams

Vous essayez de demander une ressource utilisant XHR qui se trouve sur un domaine différent et est donc bloquée. Utilisez CORS pour la messagerie interdomaine à l'aide de XHR.

4
Klemen Slavič

Krof Drakula a raison, vous ne pouvez pas charger une image d'un autre domaine, mais avez-vous vraiment besoin de le faire? Vous pouvez créer et ajouter une balise img et attendre son chargement (avec quelque chose comme jQuery load()).

var img = document.createElement( 'img' );
img.setAttribute( 'src', url );
document.getElementsByTagName('body')[0].appendChild( img );
0
Daniel J F

Les navigateurs modernes ont le Blob object:

GM_xmlhttpRequest({
  method: "GET",
  url: url,
  headers: { referer: url, Origin: url },
  responseType: 'blob',
  onload: function(resp) {
    var img = document.createElement('img');
    img.src = window.URL.createObjectURL(resp.response);
    document.body.appendChild(img);
  }
});

Le paramètre headers définira le référent afin que vous puissiez charger les images verrouillées du référent.

0
ariel