canvasにローカルの画像ファイルを描画するには
適当なお絵描きサイトをHTML5, canvas, javascriptで作ってました。
その時にやりたかったのが、canvas内にローカルの画像ファイルを描画し、
その画像を背景にお絵描きすることだったんですが、意外につまづいたので、メモしておきます。
仕様の概要はこんな感じです
- input type="file"を使ってローカルファイルを参照すること
- 参照した画像ファイルをcanvasに描画すること
- 画像ファイルをサーバにアップロードしないこと(ローカルで完結)
ソースは以下の通り
HTML
<div id="drawArea"> <canvas id="myCanvas" width="300" height="300"></canvas> </div> <div id="uploadArea"> <input id="uploadFile" name="image" type="file" /> </div>
javascript
$("#uploadFile").change(function() { var canvas = $("#myCanvas"); var ctx = canvas[0].getContext("2d"); // 選択されたファイルを取得 var file = this.files[0]; // 画像ファイル以外は処理中止 if (!file.type.match(/^image\/(png|jpeg|gif)$/)) return; var image = new Image(); var reader = new FileReader(); // File APIを使用し、ローカルファイルを読み込む reader.onload = function(evt) { // 画像がloadされた後に、canvasに描画する image.onload = function() { ctx.drawImage(image, 0, 0); } // 画像のURLをソースに設定 image.src = evt.target.result; } // ファイルを読み込み、データをBase64でエンコードされたデータURLにして返す reader.readAsDataURL(file); });
つまづいたところは以下の部分ですね。
// 画像がloadされた後に、canvasに描画する // ** 失敗 ** // 最初はこう書いてた // このタイミングだと、imageのloadが終了していないため、canvasに何も描画されなかった(´・ω・`) ctx.drawImage(image, 0, 0); // ** 成功 ** // imageのloadが完了してから、drawImageすれはOK image.onload = function() { ctx.drawImage(image, 0, 0); }
div要素の中に画像を追加するといった場合は問題ありませんが、
$("div").append(image); // これでOK
canvasに画像を描画する時は、ロードが完了してからという処理を加えないとダメです。
ちなみに、本来javascriptはローカルファイルを参照できませんが、
HTML5のFile API(FileReader)のおかげでこれができるようになりました。