私はHTML5画像アップローダを再実装しようとしています Mozilla Hacks サイトの上にありますが、それはWebKitブラウザで動作します。タスクの一部は、canvas
オブジェクトからイメージファイルを抽出し、それをアップロード用に FormData オブジェクトに追加することです。
問題は、canvas
には画像ファイルの表現を返すtoDataURL
関数があるのに対し、FormDataオブジェクトは File API からのFileまたはBlobオブジェクトしか受け付けないことです。
Mozillaソリューションはcanvas
に対して次のFirefox専用の関数を使用しました。
var file = canvas.mozGetAsFile("foo.png");
...これはWebKitブラウザでは利用できません。考えられる最善の解決策は、Data URIをFileオブジェクトに変換する方法を見つけることです。これはFile APIの一部と考えられますが、それを実現するための何かを見つけることはできません。
出来ますか?そうでない場合は、代替案はありますか?
ありがとう。
いくつかのことで遊んだ後、私はこれを自分で理解することができました。
まず最初に、これはdataURIをBlobに変換します。
function dataURItoBlob(dataURI) {
// convert base64/URLEncoded data component to raw binary data held in a string
var byteString;
if (dataURI.split(',')[0].indexOf('base64') >= 0)
byteString = atob(dataURI.split(',')[1]);
else
byteString = unescape(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to a typed array
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], {type:mimeString});
}
そこから、ファイルとしてアップロードされるようにデータをフォームに追加するのは簡単です。
var dataURL = canvas.toDataURL('image/jpeg', 0.5);
var blob = dataURItoBlob(dataURL);
var fd = new FormData(document.forms[0]);
fd.append("canvasImage", blob);
BlobBuilderとArrayBufferは廃止予定となりました。Blobコンストラクタで更新されたトップコメントのコードは次のとおりです。
function dataURItoBlob(dataURI) {
var binary = atob(dataURI.split(',')[1]);
var array = [];
for(var i = 0; i < binary.length; i++) {
array.Push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
}
これはiOSとSafariで動作します。
StoiveのArrayBufferソリューションを使用する必要がありますが、vava720が示すようにBlobBuilderを使用することはできません。そのため、両方のマッシュアップを次に示します。
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/jpeg' });
}
Firefoxには canvas.toBlob() および canvas.mozGetAsFile() メソッドがあります。
しかし、他のブラウザはそうではありません。
キャンバスからdataurlを取得してから、dataurlをBLOBオブジェクトに変換できます。
これが私のdataURLtoBlob()
関数です。とても短いです。
function dataURLtoBlob(dataurl) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {type:mime});
}
キャンバスまたはデータを処理するには、FormDataとともにこの関数を使用します。
例えば:
var dataurl = canvas.toDataURL('image/jpeg',0.8);
var blob = dataURLtoBlob(dataurl);
var fd = new FormData();
fd.append("myFile", blob, "thumb.jpg");
また、非geckoエンジンのブラウザ用にHTMLCanvasElement.prototype.toBlob
メソッドを作成することもできます。
if(!HTMLCanvasElement.prototype.toBlob){
HTMLCanvasElement.prototype.toBlob = function(callback, type, encoderOptions){
var dataurl = this.toDataURL(type, encoderOptions);
var bstr = atob(dataurl.split(',')[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
var blob = new Blob([u8arr], {type: type});
callback.call(this, blob);
};
}
canvas.toBlob()
はFirefoxだけでなく最近のすべてのブラウザで動作します。例えば:
canvas.toBlob(
function(blob){
var fd = new FormData();
fd.append("myFile", blob, "thumb.jpg");
//continue do something...
},
'image/jpeg',
0.8
);
私の好きな方法は canvas.toBlob()
しかし、とにかく、ここでもfetchを使ってbase64をBLOBに変換するもう1つの方法があります^^、
var url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
fetch(url)
.then(res => res.blob())
.then(blob => {
var fd = new FormData()
fd.append('image', blob, 'filename')
console.log(blob)
// Upload
// fetch('upload', {method: 'POST', body: fd})
})
@Stoiveと@ vava720のおかげで、この2つを組み合わせて、廃止予定のBlobBuilderとArrayBufferを使用しないようにしました。
function dataURItoBlob(dataURI) {
'use strict'
var byteString,
mimestring
if(dataURI.split(',')[0].indexOf('base64') !== -1 ) {
byteString = atob(dataURI.split(',')[1])
} else {
byteString = decodeURI(dataURI.split(',')[1])
}
mimestring = dataURI.split(',')[0].split(':')[1].split(';')[0]
var content = new Array();
for (var i = 0; i < byteString.length; i++) {
content[i] = byteString.charCodeAt(i)
}
return new Blob([new Uint8Array(content)], {type: mimestring});
}
Mozillaの推測では危険にさらされているため、進化する標準は canvas.toBlob() canvas.getAsFile()ではないようです。
私はまだそれをサポートしているブラウザを見ていません:(
この素晴らしいスレッドをありがとう!
また、支持を限定的(そして名前空間付き)にしているので、受け入れられた答えを試みる人は誰でもBlobBuilderに注意するべきです:
var bb;
try {
bb = new BlobBuilder();
} catch(e) {
try {
bb = new WebKitBlobBuilder();
} catch(e) {
bb = new MozBlobBuilder();
}
}
BlobBuilderに別のライブラリのポリフィルを使用しましたか?
var BlobBuilder = (window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder);
try catchなしで使用できます。
Check_caに感謝します。すごい仕事。
Stoiveによる最初の答えは、最後の行をBlobに合わせて変更することで簡単に修正できます。
function dataURItoBlob (dataURI) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs
var byteString;
if (dataURI.split(',')[0].indexOf('base64') >= 0)
byteString = atob(dataURI.split(',')[1]);
else
byteString = unescape(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
// write the ArrayBuffer to a blob, and you're done
return new Blob([ab],{type: mimeString});
}
これは、ES6版の Stoive's answer :です。
export class ImageDataConverter {
constructor(dataURI) {
this.dataURI = dataURI;
}
getByteString() {
let byteString;
if (this.dataURI.split(',')[0].indexOf('base64') >= 0) {
byteString = atob(this.dataURI.split(',')[1]);
} else {
byteString = decodeURI(this.dataURI.split(',')[1]);
}
return byteString;
}
getMimeString() {
return this.dataURI.split(',')[0].split(':')[1].split(';')[0];
}
convertToTypedArray() {
let byteString = this.getByteString();
let ia = new Uint8Array(byteString.length);
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return ia;
}
dataURItoBlob() {
let mimeString = this.getMimeString();
let intArray = this.convertToTypedArray();
return new Blob([intArray], {type: mimeString});
}
}
使用法:
const dataURL = canvas.toDataURL('image/jpeg', 0.5);
const blob = new ImageDataConverter(dataURL).dataURItoBlob();
let fd = new FormData(document.forms[0]);
fd.append("canvasImage", blob);
ありがとうございます。この解決策については@steovi。
ES6バージョンへのサポートを追加し、unescapeからdataURIに変更しました(unescapeは廃止予定です)。
converterDataURItoBlob(dataURI) {
let byteString;
let mimeString;
let ia;
if (dataURI.split(',')[0].indexOf('base64') >= 0) {
byteString = atob(dataURI.split(',')[1]);
} else {
byteString = encodeURI(dataURI.split(',')[1]);
}
// separate out the mime component
mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to a typed array
ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], {type:mimeString});
}
簡単にする:D
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;
}