QiitaやGithub のようにWebアプリ上でクリップボードにコピーした画像をペーストコマンドでサーバに直接アップロードする方法。
実装例
DevHubというチャットツールのチャット欄・メモ欄に実装した。
Web上の画像をコピー、または画面キャプチャから直接ペースト機能を使ってファイルアップロードからの表示ができるようになったのでとても便利になった。
以下、動作イメージ。
実装手順
- 貼り付け対象のDOMに 'paste' イベントをバインド
- pasteイベント処理内でeventから画像を取り出す
- Ajaxで画像情報をサーバに送信
- サーバ側でファイルを保存し保存後のパスをクライアントに送信
- クライアントで保存後のファイルパスを元に画像を表示する
クライアントサイド(js)
pasteイベント発生時にクリップボードの画像をサーバへ送信する。
Ajaxでのアップロード処理は通常のフォームからのファイルアップロードと同様。
(以下のソースは DevHubのソースから抜粋して多少単純化している)
$target.on('paste', function(event){
// event からクリップボードのアイテムを取り出す
var items = event.originalEvent.clipboardData.items; // ここがミソ
for (var i = 0 ; i < items.length ; i++) {
var item = items[i];
if (item.type.indexOf("image") != -1) {
// 画像のみサーバへ送信する
var file = item.getAsFile();
upload_file_with_ajax(file);
}
}
});
// ファイルアップロード
function upload_file_with_ajax(file){
var formData = new FormData();
formData.append('file', file);
$.ajax('/upload' , {
type: 'POST',
contentType: false,
processData: false,
data: formData,
error: function() {
// アップロードエラー処理
},
success: function(res) {
// アップロード成功処理 res.fileName
}
});
}
サーバサイド(Node)
サーバサイドではクライアントからPOSTに対し画像の保存と保存後ファイルパスの返却を行う。
var fs = require('fs');
var util = require('../lib/util');
exports.post = function(req, res) {
var tmp_path = req.files.file.path;
var base_name = req.files.file.name;
// 画像貼り付けの場合は拡張子を付加する paste_image.xxx
if (base_name == "blob" && req.files.file.type.indexOf('image') != -1){
base_name = "paste_image." + req.files.file.type.split('/')[1];
}
// 20141114000310_paste_image.png のようなファイル名を生成
var file_name = util.getFullDateNoSepa(new Date()) + '_' + base_name;
var target_path = './static/uploads/' + file_name; // 保存先パス
var access_path = '/uploads/' + file_name; // クライアントへ返すパス
// ファイルの保存が成功したらレスポンスを返す
fs.rename(tmp_path, target_path, function(err) {
if (err) {
throw err;
}
fs.unlink(tmp_path, function() {
if (err) {
throw err;
}
res.send({fileName: access_path});
// クライアントでは fileName でファイルパスの取得可能
});
});
};