でお絵かき->DBに保存->PHPで表示->(゚Д゚)ウマー
きっかけ
canvasタグ上に描いた絵を保存しようとしたら、
意外に情報が見つからず苦労したんで、載せときます。
canvas?
まず、canvasやHTML5についての仕様は、以下のサイトを見てください
http://www.html5.jp/
流れ
今回は、フリーハンドで描いた絵を保存します。
- canvasタグを用意
- お絵かき
- 画像情報をサーバに送り、DBに保存
- DBから画像情報を取り出し表示
- (゚Д゚)ウマー
なお、DB関係の記述は省略します。
canvasタグを用意
<html> <head> <script src="js/prototype.js" type="text/javascript"></script> <script src="js/canvas.js" type="text/javascript"></script> <style type="text/css"> canvas { border: 1px solid #000; } </style> <title>CANVASでお絵かき</title> </head> <body> <canvas>canvasをサポートしていないブラウザです。</canvas><br> <canvas>canvasをサポートしていないブラウザです。</canvas><br> <canvas>canvasをサポートしていないブラウザです。</canvas><br> <canvas>canvasをサポートしていないブラウザです。</canvas><br> </body> </html>
タグなんで、って書くだけですね。
タグの中身は、非対応ブラウザへのメッセージです。
代替画像を表示する方が親切かと
お絵かき
やってることは、javascriptでマウスイベントを受け取り、canvasに反映です。
canvas.js
/** * Canvasクラス * canvas要素に対して、マウスの動きに合わせて描画するメソッドを持たせる */ Canvas = Class.create( { initialize: function(elem, num) { this.elem = elem; this.context = this.elem.getContext('2d'); this.x = this.elem.offsetLeft; this.y = this.elem.offsetTop; this.num = num; // 何番目のcanvasか区別するための番号 this.f_draw = false; // 描画フラグ this.cache = this.moveEvent.bindAsEventListener(this); Event.observe(this.elem, 'mousedown', this.begin.bindAsEventListener(this)); Event.observe(this.elem, 'mouseup', this.end.bind(this)); Event.observe(this.elem, 'mouseout', this.end.bind(this)); }, // canvas上でマウスダウンしたら、描写開始 begin: function(e) { this.f_draw = true; Event.observe(this.elem, 'mousemove', this.cache); // canvasの左上が(0, 0)になるように調整 var x = Event.pointerX(e) - this.x; var y = Event.pointerY(e) - this.y; // contextに書き始めるよ、と通知 this.context.beginPath(); // マウスダウンした位置まで開始点を移動 this.context.moveTo(x, y); }, // マウスが動くたびに、描画を繰り返す moveEvent: function(e) { if(this.f_draw) { var x = Event.pointerX(e) - this.x; var y = Event.pointerY(e) - this.y; this.context.lineTo(x, y); this.context.stroke(); } }, // マウスアップまたは、canvasの外へマウスが出たら // 描画を終了し、画像データをサーバに送る end: function() { if(this.f_draw) { Event.stopObserving(this.elem, 'mousemove', this.cache); // toDataURLメソッドは、画像の表現を含んだ data: URI をbase64形式のPNGファイルとして返す // 引数をimage/jpegにすれば、JPGファイルを返すことも可能 var PNG = this.elem.toDataURL('image/png').replace(/^.*,/, ''); // 画像情報をサーバに送る new Ajax.Request('save.php', { parameters: { num: this.num, src: PNG } }); this.f_draw = false; } } }); // domツリーが形成されたら、Canvasクラスを生成 Event.observe(document, 'dom:loaded', function() { $$('canvas').each(function(elem, num) { new Canvas(elem, num); }); });
DBに保存
save.php
先ほど送られてきた情報をDBに保存するだけ。
画像情報は、バイナリではないので文字列として扱えます。
DBから画像情報を取り出し表示
PNG.php
<?php /** * base64でエンコードされたPNGをPNG画像として出力する * このphpファイル自体がPNG形式の画像として認識される。 */ $num = $_GET['num']; // getで取り出す番号を指定 // このファイルは、PNGですよと宣言 header("Content-Type: image/png"); // DBから画像データを取り出しデコードして表示すれば、見られます。 // 仮に、データを $PNG に入れたとすると echo base64_decode($PNG);
(゚Д゚)ウマー1
イメージタグのsrcに、toDataURL('image/png')の戻り値を直接渡してもPNGファイルとして認識します。
var PNG = this.elem.toDataURL('image/png'); var img = new Image(); img.src = PNG; document.body.appendChild(img);
(゚Д゚)ウマー2
canvasには、画像を読み込むdrawImageメソッドがあるのですが、
上記(゚Д゚)ウマー1で紹介した方法の画像を読み込んで、toDataURL('image/png')メソッドを呼び出すと
セキュリティエラーが起きます。
(゚Д゚)ウマー1画像のある場所とtoDataURL('image/png')メソッドを呼び出した場所が違うと判断されるみたいです。
解決法としては、一度画像として保存して同じ場所から読み込めばいいみたいです。
要は、srcに今回の例だとPNG.phpを指定すれば怒られないで済みました。
// 以前書いた絵を取得しcanvasに読み込む var img = new Image(); img.src = 'PNG.php?num=' + this.num; Event.observe(img, 'load', function() { this.context.drawImage(img, 0, 0); }.bind(this));