画像サムネイル表示ライブラリの詳細
これから画像サムネイル表示ライブラリの詳細を説明します。
1 var Image = Image || {};
2 Image.Thumbnail = Class.create();
3 Image.Thumbnail.prototype = {
....
87 }
1行目でImageオブジェクトを定義しています。Imageオブジェクトはただのオブジェクトですが、事実上、名前空間のように使用しています。画像サムネイル表示ライブラリは画像用のライブラリなので、Imageという名前空間に閉じ込めたかったため、このようにしています。prototype.jsではオブジェクトを名前空間のように使用していますので、覚えておくとよいテクニックの一つです。
Image || {}と書いてあるのは、既にImageオブジェクトが定義されていることを考慮しています。よくあるプログラミング言語だとA || BはTRUEまたはFALSEと評価されますが、JavaScriptの場合は、左辺が定義されたオブジェクトであれば左辺のオブジェクトを評価し、そうでなければ右辺を評価するようになっています。つまりImage || {}はImageが定義されていればImageを返して、そうでなければ{}(空オブジェクト)を返しますので、既にImageが定義されていれば、それを上書きしないようにします。
2行目はprototype.jsの機能を使ってクラスの宣言を行っています。Image.ThumbnailはImageオブジェクトのメンバとなっていて、Imageの中に閉じ込められています。ここはImage.Thumbnailというクラスが宣言されていると考えればよいでしょう。
3~87行目で実際にクラスの定義を行っています。prototypeというメンバにオブジェクトを代入していますが、これはおまじないのようなものなので、そういうものなんだと理解しておいてください。
4 initialize: function(img, input, options) { 5 this.setOptions(options); 6 7 var img = $(img); 8 this.img = img; 9 this._saveImageInfo(); 10 11 var input = $(input); 12 this.input = input; 13 Event.observe(input, 'change', this.show.bind(this)) 14 },
initializeメソッドはprototype.jsでクラスを定義した場合、newするときに必ず呼ばれるメソッドです。つまりコンストラクタになります。
常に必要な引数はimg、inputです。optionsはその名の通りオプションの指定なのでなくても問題ありません。オプションの処理は5行目のsetOptionsで行います。
7~9行目でimgの処理を行います。7行目はimgで指定されたエレメントのオブジェクトを取得し、8行目でそれを保存しています。9行目のthis._saveImageInfoでimgオブジェクトの情報を保存しています。
$という関数はprototype.jsで定義されているエレメントを取得する関数でdocument.getElementByIdとほぼ同じようなことをしてくれます。関数名が短くて済み、prototype.jsでは非常に多用される関数なので、ぜひ覚えてください。
11~13行目でinputの処理を行います。imgと同じようにオブジェクトの取得、保存を行います。13行目でinputのchangeイベントにthis.showを登録しています。これにより、inputタグでファイルが参照されたとき(changeイベントが発生したとき)に、this.showが実行されるようになります。
Event.observeはprototype.jsが提供しているイベント登録の機能です。prototype.jsのEvent.observeを使うことでブラウザに依存しない(クロスブラウザ)イベントの登録を行うことができます。
this.show.bind(this)はクラスメソッドをイベント登録する時のおまじないです。詳細な説明は省きますが、bind(this)を使用することでthisオブジェクトを束縛することができます。
16 setOptions: function(options) { 17 this.options = { 18 suffixes: { 19 gif: true, 20 jpeg: true, 21 jpg: true, 22 png: true 23 } 24 } 25 Object.extend(this.options, options || {}); 26 },
setOptionsでは、コンストラクタで渡されたオプションの設定を行います。
17~24行目にオプションのデフォルト値が定義されています。画像サムネイル表示ライブラリで使用されているオプションはsuffixesのみです。suffixesは画像として有効なファイルの拡張子を定義しています。
25行目でオプションの上書きを行います。Object.extendもprototype.jsの機能で、これを使うことでオブジェクトの上書きが行えます。もし、コンストラクタで違うsuffixesが設定されていれば、その値でオプション値が上書きされます。
28 _saveImageInfo: function() { 29 var img = this.img; 30 if (!img.width) { 31 setTimeout((function(){this._saveImageInfo()}).bind(this), 1000); 32 return; 33 } 34 var img_org = document.createElement('img'); 35 this.img_org = img_org; 36 img_org.src = img.src; 37 img_org.width = img.width; 38 img_org.height = img.height; 39 },
_saveImageInfoはコンストラクタで指定されたimgエレメントの情報を保存します。
30~33行目のif文で少し複雑なことをしています。ここの処理で行っていることは、ブラウザによるタイミングの調整です。回線やクライアントの状態によってHTMLや画像ファイルの読み込みに時間差があるので、30行目のif文でwidth属性の値を調べています。もし、この値がちゃんと設定されていなければ、まだ画像ファイルが読み込まれていないので、1秒後にもう一度自分自身を呼び出します。このようにすることで確実にimgエレメントの情報を取得できるようになるわけです。無事にimgエレメントの情報を取得できると34行目に進みます。
34~38行目でimgエレメントの情報を保存しています。新しくimgエレメントを生成し、this.img_orgに保存しています。保存される情報はsrc、width、height属性です。ここで保存された情報は、元のサムネイルの画像を復元するのに使用されます。
41 show: function() { 42 var filename = this.input.value; 43 if (!this.isValidSuffix(filename)) { 44 this.showOriginal(); 45 return false; 46 } 47 48 var img_tmp = document.createElement('img'); 49 filename = filename.replace(/\\/g, '/'); 50 img_tmp.src = 'file:///'+filename; 51 this.img_tmp = img_tmp; 52 Event.observe(img_tmp, 'load', this._show.bind(this)) 53 },
showメソッドでサムネイルの表示を行います。42行目でファイル名を取得し、43行目でファイル名の拡張子が画像ファイルかどうかをチェックしています。ここで呼んでいるisValidSuffixの処理は後述します。もし画像ファイルでなかった場合は、this.showOriginalで元のサムネイル画像を復元します。元のサムネイル画像の情報はthis.img_orgに保存されています。拡張子が画像ファイルであった場合は、48行目に進みます。
48~52行目で、指定された画像ファイルの情報取得を行っています。ここでのポイントは、指定された画像ファイルを直接サムネイル用画像に適用させてないところです。なぜかと言うと、指定されたファイルをそのままサムネイル画像に適用してしまうと、大きな画像が表示されてしまうからです。そのため、一度テンポラリなimgエレメントに指定された画像ファイルを読み込んで情報の取得を行います。
48行目でimg_tmp(テンポラリimgエレメント)を生成し、49行目でファイル名の "\" を "/" に置き換えます。50行目でimg_tmpに画像ファイルを読み込み、51行目でthis.img_tmpにimg_tmpを保存しています。52行目でimg_tmpのloadイベント(読み込みが完了したときに呼ばれる)にthis._showメソッドを登録しています。src属性に値を代入すると読み込みが開始されますが、読み込みには時間がかかるため、すぐには値が取り出せません。そこで、loadイベントに登録することで読み込みが完了した後に情報を取り出すようにします。
55 _show: function() { 56 var img = this.img; 57 var img_tmp = this.img_tmp; 58 var max_length = this.img_org.width; 59 var ox = img_tmp.width; 60 var oy = img_tmp.height; 61 62 if ((img_tmp.width >= img_tmp.height) && (ox > max_length)) { 63 ox = max_length; 64 oy = img_tmp.height * max_length / img_tmp.width; 65 } else if (img_tmp.height > max_length) { 66 ox = img_tmp.width * max_length / img_tmp.height; 67 oy = max_length; 68 } 69 70 img.src = img_tmp.src; 71 img.width = ox; 72 img.height = oy; 73 },
_showメソッドはthis.img_tmpの画像読み込みが完了した時点で呼び出されます。_showメソッドは、読み込まれた情報を元に、実際にサムネイル画像を表示する処理を行います。
ここで行っている処理はそれほど難しくはありません。this.img_tmpから画像の情報を読み出してwidth、heightの値を取得します。this.img_orgからサムネイル画像の横幅を取り出し、これを画像の最大サイズとして使用します。width、heightが最大サイズより長い場合はそれを適切に変換して、サムネイル画像のsrc、width、heightの値を更新します。これでサムネイル画像の表示は完了です。
75 isValidSuffix: function(filename) { 76 filename.match(/\.([^.]*)$/); 77 return this.options.suffixes[RegExp.$1]; 78 },
isValidSuffixは前述したファイル名の拡張子をチェックするメソッドです。76行目でファイル名の拡張子を取り出して、77行目で拡張子が正しいかどうか判定しています。this.options.suffixesに拡張子を登録していて、この値はコンストラクタの第3引数で変更可能です。デフォルトでgif、jpeg、jpg、pngが登録されていますが、構築するWebサイトでサポートされる拡張子を減らしたり増やしたりしたい場合は、好きな値で上書きしてください。
80 showOriginal: function() { 81 var img = this.img; 82 var img_org = this.img_org; 83 img.src = img_org.src; 84 img.width = img_org.width; 85 img.height = img_org.height; 86 } 87 }
showOriginalはオリジナルの画像を表示するメソッドです。このメソッドはサポートされてない拡張子の場合に呼ばれます。サポートされてない拡張子のファイルが指定されたときに何も起こらないと、前回表示されたサムネイルがそのまま表示されてしまいますので、対応してない画像ファイルの場合は、最初に表示していたサムネイルの画像に戻す処理をしています。
実際の処理はすごく簡単で、this.img_orgに保存していたオリジナルの画像の情報を書き込んでいるだけです。
まとめ
画像サムネイル表示ライブラリ、いかがだったでしょうか。prototype.jsを使っているので、通常のJavaScriptと少し書き方が異なる部分があり、戸惑いがあったのではないかと思います。ですが、prototype.jsはWeb 2.0時代において非常に重要なライブラリなので、使い方を覚えておくと便利です。
画像をアップロードする時に、どのファイルがどの画像なのかをいちいち確認するのは大変です。 画像サムネイル表示ライブラリを使えば、ファイルを選択した時にブラウザ上にサムネイルが表示されるので親切です。 画像サムネイル表示ライブラリは組み込みも簡単です。ライブラリのjsファイルを読み込んでおけば、newするだけで使えるようになります。
みなさんの構築しているWebサイトに、ぜひ画像サムネイル表示ライブラリを組み込んでみてはいかがでしょうか。
