web-dev-qa-db-ja.com

JavaScriptとXMLHttpRequestを使用してバイナリ画像データをロードするにはどうすればよいですか?

画像をクライアント側にロードし、サーバーから返されたバイトをbase64でエンコードして、処理を実行するために渡しました。 IEには、XMLHttpRequestオブジェクトのRequestBodyプロパティがありますが、使用できないようで、RequestTextが切り捨てられています。Firefoxでは、RequestTextはありますが、壊れているようです。

25
Emil Lerch

ここに私がそれをした方法があります。

この手法は、別のSO質問への回答で提供されていますが、ここでも関連があります。

何かをbase64でエンコードしたくありませんでした。サーバーを特別にエンコードするように変更することなく、Javascriptを介してブラウザーでバイナリファイルをダウンロードして解析したかったのです。 Firefoxでは、overrideMimeType()を介して応答のMIMEタイプを強制することにより、_XMLHttpRequest.responseText_を使用できることがわかりました。 IEでは、次の理由により異なります。

  • responseText on IE最初のゼロで切り捨てます。バイナリストリームの場合、これは大きな問題です。

  • バイナリストリームをテキストとして扱うIEを強制するXMLHttpRequest.overrideMimeType()はありません。

  • バイナリデータストリームで使用するように特別に設計された_XMLHttpRequest.responseBody_(IEのみ!)がありますが、そのプロパティはJavaScriptからは使用できません。

したがって、IEのresponseBodyプロパティを、FireFoxのresponseTextのようなものに、MIMEタイプの強制型変換で変換する必要があります。これは、注入されたVBScriptを使用して可能です。

クロスブラウザーにするためには、ブラウザー固有のロジックを条件付きでパックする必要があります。これは私が使用したものです:

_// one-time code
if(/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
    var IEBinaryToArray_ByteStr_Script =
    "<!-- IEBinaryToArray_ByteStr -->\r\n"+
    "<script type='text/vbscript'>\r\n"+
    "Function IEBinaryToArray_ByteStr(Binary)\r\n"+
    "   IEBinaryToArray_ByteStr = CStr(Binary)\r\n"+
    "End Function\r\n"+
    "Function IEBinaryToArray_ByteStr_Last(Binary)\r\n"+
    "   Dim lastIndex\r\n"+
    "   lastIndex = LenB(Binary)\r\n"+
    "   if lastIndex mod 2 Then\r\n"+
    "       IEBinaryToArray_ByteStr_Last = Chr( AscB( MidB( Binary, lastIndex, 1 ) ) )\r\n"+
    "   Else\r\n"+
    "       IEBinaryToArray_ByteStr_Last = "+'""'+"\r\n"+
    "   End If\r\n"+
    "End Function\r\n"+
    "</script>\r\n";

    // inject VBScript
    document.write(IEBinaryToArray_ByteStr_Script);
}


// each time you make a request for a binary resource:
var req = (function() {
    if (window.XMLHttpRequest) {
        return new window.XMLHttpRequest();
    }
    else {
        try {
            return new ActiveXObject("MSXML2.XMLHTTP");
        }
        catch(ex) {
            return null;
        }
    }
})();

var fileContents = "";
var filesize = -1;
var readByteAt = function(i){
    return fileContents.charCodeAt(i) & 0xff;
};

req.open("GET", url, true);

if(/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
    // IE-specific logic here
    // helper to convert from responseBody to a "responseText" like thing
    var convertResponseBodyToText = function (binary) {
        var byteMapping = {};
        for ( var i = 0; i < 256; i++ ) {
            for ( var j = 0; j < 256; j++ ) {
                byteMapping[ String.fromCharCode( i + j * 256 ) ] =
                    String.fromCharCode(i) + String.fromCharCode(j);
            }
        }
        var rawBytes = IEBinaryToArray_ByteStr(binary);
        var lastChr = IEBinaryToArray_ByteStr_Last(binary);
        return rawBytes.replace(/[\s\S]/g,
                                function( match ) { return byteMapping[match]; }) + lastChr;
    };

    req.setRequestHeader("Accept-Charset", "x-user-defined");
    req.onreadystatechange = function(event){
        if (req.readyState == 4) {
            if (req.status == 200) {
                fileContents = convertResponseBodyToText(req.responseBody);
                fileSize = fileContents.length-1;
                // invoke a callback here, if you like...
            }
            else{
                alert("download failed, status " + req.status);
            }
        }
    };
    req.send();

} else {
    // ff/Gecko/Webkit specific stuff here
    req.onreadystatechange = function(aEvt) {
        if (req.readyState == 4) { // completed
            if(req.status == 200){ // status == OK
                fileContents = binStream.req.responseText;
                filesize = fileContents.length;
                // invoke a callback here, if you like...
            }
            else {
                alert("download failed, status " + req.status);
            }
        }
    };
    // coerce response type
    req.overrideMimeType('text/plain; charset=x-user-defined');
    req.send(null);
}
_

...次にreadByte(i)を呼び出して、バイナリファイルのith位置のバイトを取得します。

幸運を。

Miskunへのクレジット VBScript変換ロジック用。

12
Cheeso

COTSを使用している場合は、常に中間ゲートウェイを設定して、要求が行われ、この場合はbase64でエンコードされたものを、クライアントに返される前に、より適切なものに変換できます。

1
Justin Johnson

エンコードのクライアント側ではなく、サーバーにbase64テキストを返させることができます。

たとえば、(ASP.NETでは)/ImageAsBase64.ashx?file=/images/myimage.pngへのリクエストをコード化して、ファイルを読み取り、base64エンコードして、応答としてストリーミングすることができます。

これは、PHPなどでも、ほぼ同じです。

0
Clyde