画像を端末に保存し、ギャラリーに登録する
次に、エフェクトを掛けた画像を端末にファイル保存していきます。
Tizen Device API
セキュリティ上、JavaScriptから直接ファイルの読み書きをする機能は、現在のHTML5の仕様には存在しません。このような、スマートフォンアプリには必須の機能なのに、まだHTML5での標準化が間に合っていないいくつかの機能について、Tizenでは「Tizen Device API」というTizen独自のJavaScriptのAPIを用意しています。
今回は、使用権限をユーザに確認した上でファイルシステムにアクセスできる「Filesystem API」と端末内のギャラリーにアクセスするための「Content API」を利用していきます。Device APIには他にも着信やメールのコールバックや、アドレス帳へのアクセス、各種のセンサーやBluetooth、NFCなどの操作、他のアプリケーションとの連携などのさまざまなAPIが用意されています。
使用権限(PRIVILEGES)の設定
Device APIに触れる前にまず、Device APIを利用するためのアプリケーション設定をする必要があります。config.xmlを開き、[Privileges]タブを選択しましょう。ここでアプリケーションに与える権限を指定することができます。
右上の[Add]ボタンを押し、下記の4つの権限を選択してください。それぞれ、コンテントデータの読み書き、ファイルシステムの読み書きの権限に対応しています。
http://tizen.org/privilege/content.read http://tizen.org/privilege/content.write http://tizen.org/privilege/filesystem.read http://tizen.org/privilege/filesystem.write
FILESYSTEM API
それでは実際にFilesystem APIを触っていきます。これまで作成してきたIMAGEエレメントのデータを保存するソースは、下記のとおりです。
//保存するファイル名 var fileName = "sample.png"; //保存するイメージデータ。dataURL形式のIMAGEエレメントのSRCデータのヘッダ部を取り除く var content = $("#inputImage").attr("src").replace(/^data:image\/(png|jpeg);base64,/, "") //エラーコールバック var errorCallback = function(e){ console.error(e) } //イメージディレクトリを読み書きモードで開く tizen.filesystem.resolve("images", function(dir) { //ファイルを新規作成する var file = dir.createFile(fileName); //ファイルストリームを書き込みモードで開く file.openStream("w", function(fs) { //ファイルストリームにbase64形式のデータを書き込む fs.writeBase64(content); //ファイルストリームを閉じる fs.close(); //※ギャラリーに登録する方法は下記参照 }, errorCallback); }, errorCallback, "rw");
まず、tizen.filesystem.resolveメソッドでディレクトリを開きます。引数に"images"と入っているのはパス名です。Tizenでは、メディアの種類ごとの保存先を仮想パスによってアクセスできるようになっています。ここで”images”と指定すると、アプリ共通の画像ディレクトリを自動的に指定してくれるようになります。仮想パスとして使用できる文字列は、以下のとおりです。
仮想パスの文字列 | 説明 |
---|---|
images | 画像の場所 |
videos | ビデオの場所 |
music | 音声ファイルの場所 |
documents | 書類の場所 |
downloads | ダウンロードアイテムの場所 |
ringtones | 着信メロディの場所(読み込み専用) |
wgt-package | アプリケーションパッケージのある場所(読み込み専用) |
wgt-private | アプリケーション専用のプライベート空間 |
wgt-private-tmp | アプリケーション専用の一時フォルダ |
ディレクトリの取得に成功するとコールバック関数が呼ばれます。コールバック関数の引数「dir」がディレクトリのインスタンスとなっており、ファイルの新規作成やファイルの一覧の取得などを行うことができます。ここでは「createFile」メソッドによってファイルを新規作成し、返り値にファイルインスタンスを取得します。
ファイルを新規作成したら、次にデータを書き込むためにファイルストリームを開きます。取得したファイルインスタンスから「openStream」メソッドでストリームを開きます。コールバック関数で取得したファイルストリームが引数「fs」で操作できます。
ファイルストリームを開いたら、通常は「write」メソッドでファイルを書き込むのですが、今回はファイルに直接base64エンコードのデータを書き込むためのメソッド「writeBase64」を用いて書き込みます。ここで、IMAGEエレメントから取得したdataURL形式のデータは通常base64エンコードがかかっているデータなのですが、そのままだとヘッダにスキーマデータ(「data:image/png;base64;」など)が残ったままなので、それを事前に「replace」メソッドで削除しておきましょう。最後にcloseメソッドでファイルストリームを閉じて終了です。
また、「images」パスに画像を保存すればそのままギャラリーアプリには登録されるのですが、残念ながらすぐに反映されるわけではありません。そこで、即時に反映させるためにギャラリーへの手動登録を行ってみます。ソースは以下のようになります。
//※上記ソースの米印の箇所に tizen.content.scanFile(file.toURI(), function(){ console.log("scan success") }, errorCallback);
このように「tizen.content.scanFile」メソッドにURI形式でパスを渡すことによって、ギャラリーにメディアデータとしてファイルが登録されます。
アプリへの組み込み
それでは実際にアプリに組み込んでみましょう。まずは、index.htmlの2ページ目にsaveボタンを設置します。ここではヘッダの部分にボタンを設置してみます。
<div data-role="page" id="two"> <div data-role="header" data-position="fixed"> <h1>Two</h1> <button id="saveButton">save</button> </div> <中略> </div>
次に、main.jsにボタンのハンドラ含めて実装していきましょう。
$("#saveButton").click(function(){ var imageSrc = $("#inputImage").attr("src"); if(!imageSrc) return; $.mobile.loading( 'show' ); //保存するファイル名 var fileName = "codezine" + new Date().getTime() + ".png"; //保存するイメージデータ。dataURL形式のIMAGEエレメントのSRCデータのヘッダ部を取り除く var content = imageSrc.replace(/^data:image\/(png|jpeg);base64,/, ""); //エラーコールバック var errorCallback = function(e){ console.error(e); $.mobile.loading( 'hide' ); } //イメージディレクトリを読み書きモードで開く tizen.filesystem.resolve("images", function(dir) { //ファイルを新規作成する var file = dir.createFile(fileName); //ファイルストリームを書き込みモードで開く file.openStream("w", function(fs) { //ファイルストリームにbase64形式のデータを書き込む fs.writeBase64(content); //ファイルストリームを閉じる fs.close(); //ギャラリーに登録する tizen.content.scanFile(file.toURI(), function(){ console.log("scan success") }, errorCallback); $.mobile.loading( 'hide' ); alert("Saving image Succeeded"); }, errorCallback); }, errorCallback, "rw"); });
以上が画像を端末に保存し、ギャラリーに登録する実装になります。Device APIを利用したファイルアクセスについてご理解いただけたでしょうか。