扱うデータに画像を含むようなアプリを作る場合、クライアント側にある画像ファイルあるいはスマホなどであればその場で撮影した画像をサーバーにアップロードして保存することになります。最近のスマホのカメラは大変解像度が高くなり、そのままだとサイズが大きすぎるので、縮小処理したい場合も多いと思います。
Buddyではサーバーに保存された画像ファイルを縮小処理する方法も用意されていますが、クライアント側で縮小してからサーバーにアップロードすることができれば、通信量が減るのでよりよい方法となります。
これを実現するには、
1)選択した画像の内容を読み取る。
2)画像を縮小する。
3)縮小した画像をアップロードする。
という処理をJavascriptでおこなう方法を知る必要があります。
具体絵的には、1)はFileReaderクラスの使い方、2)はcanvasの機能、3)は画像データをアップロードに必要なFileオブジェクトにする方法、そして共通するテクニックとしてデータURLの扱い、ということになります。これらをすべて学んで適切に組み立てるのは結構面倒です。そこで、必要な機能をまとめたライブラリファイルとしてimagefiletool.jsを作成しました。
imagefiletool.js です。← このファイル名部分をクリックしてダウンロードしてください。
imagefiletool.jsを、アプリのfiles/javascriptsフォルダに入れることによって、スクリーンのスクリプトでImageFileToolというクラスと、ImageUtilというオブジェクトが使えるようになります。これらには次の機能があります。
new ImageFileTool() で得たオブジェクトで次のメソッドを使う readFile() 画像ファイルのFileオブジェクトから読み取り、縮小して内部のキャンバスに描画 getSrc() その画像を表示するsrc,width,heightを得る fileForUpload() その画像をアップロードするFileオブジェクトを得る 次のユーティリティもある。これはImageFileToolとは独立して使える。 ImageUtil.getSize() 画像の幅と高さを得てコールバックで返す ImageUtil.calcShrinkSize() 幅と高さを指定の最大長辺値内になるように計算する
スクリーンで、ファイル選択モジュールFILE1、画像モジュールIMAGE1、ボタンBUTTON1、が配置されているとして、FILE1で画像を選択したら縮小処理するとともに画像をIMAGE1に表示し、BUTTON1をクリックしたらアップロードする、というスクリプトは次のようになります。
// 画像ファイル選択時 FILE1_onChange: function(evt){ var files = this.items.FILE1.getFiles(); if(files.length != 1) return; this.ift.readFile(files[0], (function(err){ if(err) return console.log(err); var src = this.ift.getSrc(); this.items.IMAGE1.setSrc(src.src); this.items.IMAGE1.setStyle({width: src.width, height: src.height}); }).bind(this)); }, // ボタンクリック時 BUTTON1_onClick: function(evt){ var file = this.ift.fileForUpload(); var dir = 'files/…'; // アップロード先のフォルダ api.request.upload(api.constants.appName, dir, [file], (function(error, result){ // アップロード結果にもとづく処理 … }).bind(this)); }, // スクリーンロード時 onLoad: function(){ // maxはアップロードする縮小画像の長辺サイズ、showmaxは表示する縮小画像の長辺サイズ this.ift = new ImageFileTool({max: 800, showmax: 150}); },
このように、縮小処理とアップロードを簡単に行うことができます。
なお、カメラで撮影した画像を読み取った場合、右や左に回転した状態の画像となる場合があります。imagefiletool.jsではこれを補正する処理も行っています。興味のある方はソースコードをご覧ください。
(2022/9/13 中島)