私のチームと私は、SafariとAppEngineの制限の組み合わせが原因で、すばらしいアニメーションアプリがSafariで動作しないことに不満を持っています。私たちはあなたの一人がそれを解決するための「魔法の呪文」を見つけるのを手伝ってくれることを望んでいます。
これは解決するのが非常に簡単な問題かもしれませんが、これはほとんど文書化されていない珍しい(非常に便利ですが)シナリオであるため、2日後にレンガの壁にぶつかっただけです。
問題の詳細を説明させてください。
私たちのアプリは、キャンバスデータをblobstore(ユーザーがアニメーション用に描画した画像)に保存する必要があります。通常、これを行うには、画像データを含むバイナリフィールドを持つajaxを介してWebフォームを動的に投稿します。これを行う1つの方法は、ArrayBufferとBlobBuilderを使用することです。これはChromeで機能します。
dataURItoBlob = function(dataURI, callback) {
var ab, bb, byteString, i, ia, mimeString, _ref;
if (!(typeof ArrayBuffer != "undefined" && ArrayBuffer !== null)) {
return null;
}
byteString = atob(dataURI.split(',')[1]);
mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
ab = new ArrayBuffer(byteString.length);
ia = new Uint8Array(ab);
for (i = 0, _ref = byteString.length; (0 <= _ref ? i < _ref : i > _ref); (0 <= _ref ? i += 1 : i -= 1)) {
ia[i] = byteString.charCodeAt(i);
}
bb = window.BlobBuilder ? new BlobBuilder() : window.WebKitBlobBuilder ? new WebKitBlobBuilder() : window.MozBlobBuilder ? new MozBlobBuilder() : void 0;
if (bb != null) {
bb.append(ab);
return bb.getBlob(mimeString);
} else {
return null;
}
};
postCanvasToBlobstore = function(url, name, canvas) {
blob = dataURItoBlob(canvas.toDataURL());
formData = new FormData();
formData.append("file", blob);
xhr = new XMLHttpRequest();
xhr.open("POST", url);
return xhr.send(formData);
}
バイナリ形式のデータを保存する別の方法は、xhr.sendAsBinary()を使用することです。これはFirefoxで機能します。
postCanvasToBlobstore = function(url, name, canvas) {
type='image/png'
var arr, boundary, data, j, xhr;
data = canvas.toDataURL(type);
data = data.replace('data:' + type + ';base64,', '');
xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
boundary = 'imaboundary';
xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
arr = ['--' + boundary, 'Content-Disposition: form-data; name="' + name + '"; filename="' + name + '"', 'Content-Type: ' + type, '', atob(data), '--' + boundary + '--'];
j = arr.join('\r\n');
return xhr.sendAsBinary(j);
}
これらの可能性はどちらもSafariには存在しないようです(可能性は非常に高いですが、それを理解するのに十分なほど賢くはありません)。1つの代替方法は、base64でエンコードされたデータを使用することです。これはSafariで確実に実行できます。これは次のようになります。
postCanvasToBlobstore = function(url, name, canvas, type) {
type='image/png'
var arr, boundary, data, j, xhr;
data = canvas.toDataURL(type);
data = data.replace('data:' + type + ';base64,', '');
xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
boundary = 'imaboundary';
xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
arr = ['--' + boundary, 'Content-Disposition: form-data; name="' + name + '"; filename="' + name + '"', 'Content-Transfer-Encoding: base64','Content-Type: ' + type, '', data, '--' + boundary + '--'];
j = arr.join('\r\n');
return xhr.send(j);
}
今、これは実際に機能します!ただし、既知のblobstoreバグのため、AppEngineツールの開発バージョンでのみ機能します。アプリを本番環境にデプロイするとすぐに機能しなくなります。もちろん、POSTコードをどこかで微調整することで、blobstoreがデータを解釈する際の問題を解決できる可能性があります。この問題に関連するblobstoreの問題と思われるものについては、 http: //code.google.com/p/googleappengine/issues/detail?id=4265を参照してください。
上記の3つのコードサンプルのいずれかを編集コントロールに貼り付けて、postCanvasToBlobstore関数の各バージョンで何が起こるかを確認できます。最初のサンプルはChromeで機能し、2番目のサンプルはFirefoxで機能します(これはデバッグアプリのデフォルトのバージョンです)。 to)、そして3番目は3つすべてから機能するはずです(ただし、おそらくblobstoreのバグが原因で、この本番Webサイトを使用する場合はいずれも機能しません)。