やること
- カメラロールで画像を選択する
- ブラウザ上に表示する
- canvasで画像に効果をつける
- おまけ
準備
html,js,cssを準備しておく。
今回は↓のような構成。
Camera−Roll
┃
┣━ index.html
┃
┣━ js
┃ ┃
┃ ┗━ script.js
┃
┗━ css
┃
┗━ style.css
カメラロールで画像を選択する
画像を選択させるためにinput
要素をおく。
type="file"
にしておくと、タップしたときに写真を撮るかカメラロールから選ぶかを選択するおなじみのアレが出てくる。
id
属性はあとでjs側でつかうのでつけておく
<input type="file" id="file" />
ブラウザ上に表示する
今のままではファイルを選択しても特に何も起きないので、選択したファイルをあれこれする処理をjsに書いていく。
jsでの主な処理は以下のとおり。
- ファイルが選択されたイベントをキャッチする
-
FileReader
を使い、選択されたファイルをURL形式で読み込む - 取得したURL形式のデータを、Imageオブジェクトのsrcに指定する
ではやっていきます。
ファイルが選択されたイベントをキャッチする
// 要素を取得
var input = document.getElementById('file');
// changeイベントでファイルの選択をキャッチ
input.addEventListener('change', function (e) {
// 処理
alert('ファイルが選択されました');
});
ここまででこんな感じ。
FileReaderを使い、選択されたファイルをURL形式で読み込む
FileReaderを使うことで、選択されたファイルをいろんな形式で扱えるようになる。
今回はURL形式で扱う。
var input = document.getElementById('file');
input.addEventListener('change', function (e) {
// コールバック引数のsrcElementに、filesという名前で配列形式でファイルオブジェクトが格納されている
// 今回は単一ファイルしか選択させないので、0番目に選択したファイルがある
var file = e.srcElement.files[0];
// FileReaderを初期化して、
var fr = new FileReader();
// ファイルが読み込み終わったあとの処理を書いておく
fr.addEventListener('load', function() {
// resultプロパティに読み込んだデータが入ってくる
var url = fr.result;
alert(url);
});
// 最後にreadAsDataURLメソッドに選択したファイルオブジェクトを渡すと
// 上記resultプロパティにURL形式でデータが入る
fr.readAsDataURL(file);
});
取得したURL形式のデータを、Imageオブジェクトのsrcに指定する
前のステップまでで選択したファイルをURL形式のデータで扱うことができるようになっているので、あとはそんなに難しくない。
var input = document.getElementById('file');
input.addEventListener('change', function (e) {
var file = e.srcElement.files[0];
var fr = new FileReader();
fr.addEventListener('load', function() {
var url = fr.result;
// Imageオブジェクトをつくり
var img = new Image();
// srcにurlを指定する
img.src = url;
// そのままだとでかすぎるのでサイズ調整して
img.height = 200;
// bodyに追加する
document.body.appendChild(img);
});
fr.readAsDataURL(file);
});
するとこんな感じ。
これまでずっとカメラロールからファイルを選択するという話をしてきたが、その場で写真を撮ってもいける。
Use Photo
を押すとカメラロールのときと同じように表示される。
canvasで画像に効果をつける
Imageオブジェクトで扱えるようになっているので、canvasに描き出すことも簡単。
まずは普通にcanvasに描きだしてみる。
var input = document.getElementById('file');
input.addEventListener('change', function (e) {
var file = e.srcElement.files[0];
var fr = new FileReader();
fr.addEventListener('load', function() {
var url = fr.result;
var img = new Image();
// onloadでcanvasに描き込む処理を書く
img.onload = function () {
// canvasをつくる
var canvas = document.createElement('canvas');
// canvasのwidthとheightは、imgと同じ値にする
canvas.width = img.width;
canvas.height = img.height;
// 見た目上のサイズは小さめにしておく
// heightはとりあえず200
canvas.style.height = '200px';
// widthはimgの比率を維持するように計算
canvas.style.width = (img.width / img.height) * 200 + 'px';
// canvasをbodyに追加する
document.body.appendChild(canvas);
// contextを取得
var context = canvas.getContext('2d');
// imgを描き込む
context.drawImage(img, 0, 0, canvas.width, canvas.height);
};
img.src = url;
});
fr.readAsDataURL(file);
});
次になにか効果をつける。
いいのが思いつかなかったので、canvasで輪郭を検出してアートっぽくするでやった補色を使う。
描き換えの詳細もそちらを参考に。
var input = document.getElementById('file');
input.addEventListener('change', function (e) {
var file = e.srcElement.files[0];
var fr = new FileReader();
fr.addEventListener('load', function() {
var url = fr.result;
var img = new Image();
img.onload = function () {
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
canvas.style.height = '200px';
canvas.style.width = (img.width / img.height) * 200 + 'px';
document.body.appendChild(canvas);
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0, canvas.width, canvas.height);
// 補色を計算する関数
var getComplementaryRGB = function (rgb) {
var max = Math.max(rgb.r, rgb.g, rgb.b),
min = Math.min(rgb.r, rgb.g, rgb.b),
sum = max + min;
return {
r: sum - rgb.r,
g: sum - rgb.g,
b: sum - rgb.b
};
};
// 描き込まれたデータを取得する
var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
var data = imageData.data;
// 全ピクセル描き変える
for (var i = 0, l = data.length; i < l; i += 4) {
// rgbの値を取り出して
var rgb = {
r: data[i],
g: data[i + 1],
b: data[i + 2]
};
// 補色のrgbを計算する
var complementaryRGB = getComplementaryRGB(rgb);
// 計算したrgbで描き変える
data[i] = complementaryRGB.r;
data[i + 1] = complementaryRGB.g;
data[i + 2] = complementaryRGB.b;
}
// 描き換えたdataをimageDataにもどし、描画する
imageData.data = data;
context.putImageData(imageData, 0, 0);
};
img.src = url;
});
fr.readAsDataURL(file);
});
するとこうなる。
ピッコロさんかな?
おまけ
ファイル選択のUIがダサいのでなんとかする。
カメラロールのアレを表示させるにはChoose File
がタップ(クリック)されればいいだけなので、別のボタンを用意してそれがクリックされたらinputのclick
メソッドを呼べばおk。
htmlに要素を追加する。
あとでどうとでもできるように、今回はとりあえずanchorタグを追加。
<input type="file" id="file" />
<a href="javascript:void(0);" id="button">Tap me!</a>
ダサいやつはcssで見えなくしておく。
#file {
display: none;
}
jsにclick時の処理を追加。
// 略
// 要素を取得
var button = document.getElementById('button');
// clickされたら
button.addEventListener('click', function () {
// inputのclickメソッドを呼ぶ
input.click();
});
するとあのダサいやつを見なくてもよくなる。