sinatra + html5_canvas + jquery 画像ドラッグドロップでファイル保存
こんにちは。麺処まつば副店長です。風が凄まじいですね(台風)
ここ暫く更新せずにいたら、ついに店長の大目玉をくらいました。
台風と店長の大目玉のダブルパンチ。恐ろしや……。
さて今日は、sinatra + HTML5 + jquery で canvas にドラッグドロップされた画像を
サーバに送信ファイル保存しつつ表示というのをやってみようと思います。
どれだけ需要があるか分かりませんが(笑)
手順はこんなカンジです。
1.views/index.haml
2.public/javascripts/dragdrop.js
3.app.rb
それでは作っていきましょう。
views/index.haml
副店長の悪いクセなんですが、まず見た目から入ります。
canvas をひとつだけおいたファイルを用意します。
1 !!! XML 2 !!! 3 4 %html{:lang => "ja"} 5 %head 6 %meta{ :content=>"text/html", :charset=>"utf-8" } 7 %title 画像 8 %link{ :rel => "stylesheet", :href =>"/style.css" } 9 %script{ :src => "javascript/jquery-1.6.2.min.js" } 10 %script{ :src => "javascript/dragdrop.js" } 11 %body 12 #main 13 %canvas{ :id=> "img_canvas", 14 :width => "500", :height => "500", 15 :ondragover => "onDragOver(event)", :ondrop => "onDrop(event)", 16 :style => "border: medium dotted #666;"}
9、10行目で、自作する js ファイルと、使用する jquery を指定しています。
13〜16行目で、canvas を設置しています。
ondragover / ondrop で、自作 js の関数を呼びます。
それから、canvas の width と height は、
スタイルシートで指定しないほうがいいみたいです。
こないだ参加したHTML5勉強会の講師の先生が
スタイルシートで書くと何故かうまくいかないって仰ってました。
(そして自分では試してないので、どううまくいかないのかは良く分かりません(笑))
public/javascript/dragdrop.js
上記で書いた canvas に画像がドラッグドロップされたときに動く
javascript をかいていきます。
1 function onDrop(event){ 2 // drop されたファイルの取得 3 var f = event.dataTransfer.files[0]; 4 5 // drop されたファイルが画像ファイルの場合の処理 6 if(/^image/.test(f.type)){ 7 // 画像ファイルを読み込むための準備 8 var img = document.createElement('img'); 9 var fr = new FileReader(); 10 11 fr.onload = function(){ 12 img.src = fr.result; 13 img.onload = function() { 14 // jquery ajax を使ってPOST 15 new $.ajax({ 16 url: "/post_img", 17 type: "POST", 18 data: {file: img.src}, 19 success: function(){ 20 // canvas に画像描画 21 canvas = document.getElementById("img_canvas"); 22 context = canvas.getContext("2d"); 23 canvas.width = img.width; 24 canvas.height = img.height; 25 context.drawImage(img, 0, 0); 26 }, 27 error: function(){ alert("ごめん失敗した。");}, 28 complete: function(){ alert("保存した!"); } 29 }); 30 } 31 } 32 fr.readAsDataURL(f); 33 } 34 35 // ブラウザがファイル自体を表示するのを防止 36 event.preventDefault(); 37 } // end funciton [openDrop] 38 39 function onDragOver(event){ 40 event.preventDefault(); 41 } // end function [onDragOver]
こんなカンジです。
15行目から、ajax を使って画像をPOSTしています。
成功すれば、canvas に読み込んだ画像を表示するようにしています。
app.rb
sinatra な ruby のファイルです。
画面表示と送信された画像を受けてファイル保存なぞします。
1 #coding:utf-8 2 3 require 'rubygems' 4 require 'sinatra' 5 require 'haml' 6 7 configure :production do 8 end 9 10 get '/' do 11 set :haml, :format => :html5 12 haml :index 13 end # end [get /] 14 15 post '/post_img' do 16 # 画像ファイルの取得 17 img_array = params[:file].split(/\s*,\s*/) 18 19 # 拡張子 20 ext = ".dat" 21 case img_array[0] 22 when "data:image/jpeg;base64" 23 ext = ".jpg" 24 when "data:image/gif;base64" 25 ext = ".gif" 26 when "data:image/png;base64" 27 ext = ".png" 28 end 29 30 # 画像ファイル保存 31 f = File.open("tmp/image#{ext}",'w') 32 f.puts img_array[1].unpack('m')[0] 33 f.close 34 return "" 35 end 36 37 get '/style.css' do 38 content_type 'text/css', :charset => 'utf-8' 39 sass :style 40 end
10〜13行目で、/ へのGETの定義
15〜35行目で、post された画像を保存する処理を書いています。
ajaxからどんなデータが渡ってくるかなって思ったら、
base64でエンコードされた文字列でした。
こんな感じの→「画像情報, エンコードされた文字列」
"data:image/jpeg;base64", "/9j/4AAQSkZJRgAB…
カンマ区切りだったんで配列化して、0番目の情報から画像情報を取得、
ファイル保存時の拡張子を指定しています(19〜28行目)
30〜33行目の間でファイルを保存しています。
終わりです。
※あ。「tmp」ディレクトリ作っといてくださいね。
では、さっそくできた画面内の canvas 領域に画像をドラッグドロップしてみましょう。
canvas に画像が表示されますか?→OK
サーバに画像は保存されますか?→OK
できました。
次回はコレをストレージに保存してみるところをやってみようと思います。