Downloading an image using XMLHttpRequest in a userscript

前端 未结 4 2183
走了就别回头了
走了就别回头了 2020-12-05 05:34

First of all there is a question with the same title here on SO but its not what I\'m looking for and it doesn\'t have a complete answer either.

So here\'s my questi

4条回答
  •  情歌与酒
    2020-12-05 05:58

    XMLHttpRequest will not work cross-domain, but since this is a userscript Chrome now supports GM_xmlhttpRequest() in userscripts only.

    Something like this should work, note that it is asynchronous:

    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);
                        }
    } );
    




    As for getting and using the actual image data, that is a major pain to work out.

    • You can use the new .responseType = "blob"; functionality in Firefox but Chrome does not yet support it.

    • In Chrome or Firefox, for the same domain only, you can use the new XHR2 like so:
      See it in action at 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 ('

      New image:

      ') }; reader.readAsDataURL (blob); }


    • Unfortunately, GM_xmlhttpRequest() does not (yet) support setting responseType.


    So, for GM script or userscript applications, we have to use a custom base64 encoding scheme like in "Javascript Hacks: Using XHR to load binary data".

    The script code becomes something like:

    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: ';
                            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;
    }
    

提交回复
热议问题