タイトルどおりのことをやった際の実装時メモ。
Canvasから画像を取得
2通りの方法が見つかった。
- Base64への変換
- Blobへの変換
Base64への変換
canvas.toDataURL()
を呼び出すだけで取得可能であるが、
画像サイズに比例した巨大な文字列となり、変換によって元サイズより33%データ量が増える。
var base64= this.canvas.toDataURL('image/png');
取得したBase64を<image>
のsrc
に指定すれば画像表示され、
<a>
のhref
に指定すればリンククリックでダウンロードできてこれはこれで便利。
Blobへの変換
canvas.toBlob()
を呼び出すだけで取得可能。
Blob形式で表現すれば、createObjectURL(blob)
によりURL参照が取得できるので、
画像サイズに依存せずメモリ使用量を抑えられるらしい。(未確認)
これは便利と思いきやcanvas.toBlob()
はFirefoxでのみサポートされており、
Firefox以外ではBase64経由でBlobを作成する方法とならざる得ない。
toBlob: function() {
var base64 = this.canvas.toDataURL('image/png');
// Base64からバイナリへ変換
var bin = atob(base64.replace(/^.*,/, ''));
var buffer = new Uint8Array(bin.length);
for (var i = 0; i < bin.length; i++) {
buffer[i] = bin.charCodeAt(i);
}
// Blobを作成
var blob = new Blob([buffer.buffer], {
type: type
});
return blob;
}
ちなみにサイズを確認すると、確かにBase64は33%増量していた。
type | size |
---|---|
base64.length | 132506 |
blob.size | 99361 |
Serverへ送信する
クライント側は Sencha Touch 2.3 を使用。
というのも2.3から XMLHTTPRequest Level 2(XHR2)を完全にサポートしたので、
バイナリデータも送信できるはずなのでその試験を兼ねて。
サーバは勉強も兼ねてSinatra
を利用。
- Base64のまま送信する
- Binaryに変換して送信する
- Blobに変換して送信する
1. Base64版
- Base64は先頭のminetype(
data:image/png;base64,
の部分)は不要なため削除 - サーバ側はデコードしてファイルに書き出してやれば画像として保存される
クライアント側
var base64 = this.canvas.toDataURL('image/png');
var request = {
url: 'http://localhost:4567/base64',
method: 'POST',
params: {
image: base64.replace(/^.*,/, '')
},
success: function (response) {
console.log(response.responseText);
}
};
Ext.Ajax.request(request);
サーバ側
require 'base64'
post '/base64' do
File.open('imageBase64.png', 'wb') do|f|
f.write(Base64.decode64(params['image']))
end
"OK"
end
2. Binary版
-
xhr2: true
を明示的に指定する -
rawData
として渡す(dataだと文字列と認識される) - サーバ側はbodyをそのまま書き出してやると画像として保存される
クライアント側
toBinary: function(canvas) {
var base64 = canvas.toDataURL('image/png'),
bin = atob(base64.replace(/^.*,/, '')),
buffer = new Uint8Array(bin.length);
for (var i = 0; i < bin.length; i++) {
buffer[i] = bin.charCodeAt(i);
}
return buffer;
}
// Binaryデータを作成
var buf = toBinary();
var request = {
url: 'http://localhost:4567/binary',
method: 'POST',
xhr2: true,
rawData: buf.buffer,
success: function (response) {
console.log(response.responseText);
}
};
Ext.Ajax.request(request);
サーバ側
post '/binary' do
File.open('imageBin.png', 'wb') do|f|
f.write(request.body.read)
end
"OK"
end
3. Blob版
- Blobの場合ファイルとして扱えるので、FormData形式で送信する
-
rawData
として渡す - サーバ側はアップロードされたファイルを書き出す
クライアント側
var buf = toBinary();
// Blobを作成
var blob = new Blob([buf.buffer], {
type: 'image/png'
});
// FormDataとして送信
var fd = new FormData();
fd.append("image", blob);
var request = {
url: 'http://localhost:4567/blob',
method: 'POST',
xhr2: true,
rawData: fd,
success: function (response) {
console.log(response.responseText);
}
};
Ext.Ajax.request(request);
サーバ側
post '/blob' do
img = params[:image]
File.open('imageBlob.png', 'wb') do|f|
f.write(img[:tempfile].read)
end
"OK"
end