最近のGUIでは、サウンドやムービーは欠かせない要素になってきています。特にYouTubeが登場してからは、ムービーが当たり前に扱われるようになっています。しかし、Javaではサウンドやムービーなどのメディアは苦手としてきた領域です。
JavaFXではこの状況を打開すべく、JavaOne 2008にてOn2 Technology との提携が発表されました。On2 Technologyといえば、Adobe Flash Videoが採用しているVP6コーデックを開発してる企業です。この提携によりJavaFXでもAdobe Flash VideoのFLVフォーマットを再生できるようになりました。
また、同じくJavaが苦手としている領域として、デザイナーとの分業があります。デザイナーでも扱えるツールでGUIを構築することがなかなかできないというのが、Javaの現状です。これはJavaFXでも同じです。
この問題に対し、JavaFXでは既存のツールを活かすという方法を採用しました。それがJavaFX Production Suite です。
Production Suiteにはいくつかのツールが含まれていますが、キーとなるのがAdobe IllustratorとAdobe Photoshopのプラグインです。IllustratorとPhotoshopはデザイナーにとってデファクトスタンダードとなりつつあるツールです。Production Suiteのプラグインを使用することで、IllustratorやPhotoshopで作成したアートワークをそのままJavaFXの世界に持ち込むことができるのです。
今回は、この2つの領域、メディアとProduction Suiteについて解説していきます。なお、今回使用したサンプルのソースを含めたNetBeansのプロジェクトは、下記のリンクよりダウンロードすることができます。
JavaFXがサポートしているメディア
サウンドやムービーのAPIを紹介する前に、現在JavaFXでサポートしているメディアについてまとめておきましょう。現状では、JavaFXを動作させるプラットフォームによってサポートしているメディアが異なります。表1 にサポートしているメディアをまとめました。
表1 JavaFXがサポートしているメディア(JavaFX FAQ より引用)
プラットフォーム
コーデック
ファイルフォーマット
Mac OS X 10.4以降
ビデオ: H.261、H.263、H.264、MPEG-1、MPEG-2、MPEG-4、Sorenson Video 2、Sorenson Video 3
オーディオ: AIFF、MP3、WAV、MPEG-4 AAC Audio、MIDI
.3gp、.3gpp、3g2、3gp2、 .avi、.mov、.mp4、.mp3、 .m4a、.m4b、.m4p
Windows XP、Vista
ビデオ: Windows Media Video、H.264
オーディオ: MPEG-1、MP3、Windows Media Audio、 MIDI
.mp3、.wav、 .wmv、.avi、.asf
Windows XP、Vista、Mac OS X 10.4以降、Linux、Solaris
ビデオ: On2 VP6
オーディオ: MP3
.flv、.fxm、.mp3
WindowsではDirectXに含まれるDirectShowがサポートしているメディアを使用することができ、Mac OS XではQuickTimeがサポートしているメディアを使用することができます。
プラットフォームによらずサポートしているサウンドはMP3です。ムービーはコーディックとしてOn2 VP6を使用したAdobe Flash VideoのFLVフォーマット、またSun Microsystems社が策定したFLVのサブセットであるFXMフォーマットを使用することができます。
FLVフォーマットと、FXMフォーマットの両方フォーマットを作成できるツールは、現状On2 Flixしかありません。On2 Flixは試用版が60日間使用できるので、試しに使ってみるのはいいかもしれません。ただし、試用版は左下にOn2のクレジットが入ってしまいます。
FLVフォーマットだけであれば、Adobe Creative Suite 4に含まれるAdobe Media Encoderで作成することができます。本解説でもAdobe Media Encoderを使用してムービーをエンコードしました[1] 。
サウンドを扱う
では、実際にメディアに関するAPIを使用していきましょう。まずはサウンドです。
とはいうものの、サウンドもムービーも同じクラスを使用して再生します。サウンドとムービーの違いは描画の有無でしかありません。
メディアを扱うのがjavafx.scene.media.Mediaクラスです。Mediaクラスは再生するメディアをsourceアトリビュートで表します。sourceアトリビュートはURIでメディアの位置を指定します。サウンドの場合、プロトコルとしてhttp:とfile:が使用できます。また、サウンドファイルをJARファイルに含めることも可能です。
メディアを再生するのがjavafx.scene.media.MediaPlayerクラスです。MediaPlayerオブジェクトのmediaアトリビュートにMediaオブジェクトを指定し、play関数をコールすることでメディアを再生します。再生の停止はstop関数、ポーズはpause関数です。たとえば、クラスファイルと同ディレクトリにあるsound.mp3ファイルを再生するには次のようなスクリプトを使用します。
リスト1
var player = MediaPlayer {
// 再生するサウンドファイル
media: Media {
source: "{__DIR__}sound.mp3"
}
};
// サウンドの再生
player.play();
これだけです。簡単ですね。
MediaPlayerクラスにはmediaアトリビュート以外に、ボリュームを表すvolumeアトリビュートや、繰り返して再生する回数を表すrepeatCountアトリビュートなどがあります。これらのアトリビュートも使ってサンプルを作成してみましょう。
音符の形のノードをクリックしている間サウンドを再生し、マウスボタンを放すとサウンドの再生を停止するというサンプルです。それだけでなく、音符をドラッグすることにより、ボリュームや左右のバランスを変更することも行ってみましょう。垂直方向のドラッグがボリューム、水平方向のドラッグがバランスを変更するようしてみました。
音符の形は楕円と直線を用いて作成しました。音符の位置はlocationX変数とlocationY変数にバインドさせます。locationXがバランスに連動し、locationYがボリュームに連動します。
以下にMediaPlayerオブジェクトを生成する部分を示します。
リスト2
// 音符の形の x 座標
// サウンドの左右のバランスに連動
var locationX = 100.0;
// 音符の形の y 座標
// サウンドのボリュームに連動
var locationY = 100.0;
var player = MediaPlayer {
// 左右のバランスは -1.0 から 1.0 の範囲
balance: bind locationX / 100.0 - 1.0
// ボリュームは 0.0 から 1.0 の範囲
volume: bind (200.0 - locationY) / 200.0
// 無限に繰り返す
repeatCount: MediaPlayer.REPEAT_FOREVER
// 再生するサウンドファイル
media: Media {
source: "{__DIR__}sound.mp3"
}
}
locationXとlocationYは0から200までの値をとるようにしています。左右のバランスを表すbalanceアトリビュートは-1.0から1.0の値を取るので、locationXと連動できるように100で割り、1を引いています。同様にvolumeは0.0から1.0の値を取り、上にいくほどボリュームを大きくさせるため、200からlocationYを引き、200で割っています。
また、クリックしている間ずっとサウンドを再生させるため、repeatCountアトリビュートを無限に繰り返すMediaPlayer.REPEAT_FOREVERに設定しています。
次に音符の形のノードをドラッグして位置を変化させる部分を示します。
リスト3
Stage {
title: "Sound Controller"
resizable: false
scene: Scene {
width:200
height: 200
content: [
// 四分音符の形
Group {
translateX: bind locationX
translateY: bind locationY
content: [ <<省略>> ]
// ドラッグの開始位置
var dragStartX: Number = 0.0;
var dragStartY: Number = 0.0;
// マウスボタンが押されたら、サウンドを再生し、
// 位置を保存する
onMousePressed: function(event: MouseEvent) {
player.play();
dragStartX = locationX;
dragStartY = locationY;
}
// マウスボタンから離れたら、サウンドの再生を停止
onMouseReleased: function(event: MouseEvent) {
player.stop();
}
// ドラッグされたら、位置を変化させる
// 位置の変更に応じて、サウンドのバランス、ボリュームが変化
onMouseDragged: function(event: MouseEvent) {
// x 座標の変更
// ウィンドウからはみ出た場合も考慮する
locationX = event.dragX + dragStartX;
if (locationX >= 200) {
locationX = 200;
} else if (locationX <= 0) {
locationX = 0;
}
// y 座標の変更
// ウィンドウからはみ出た場合も考慮する
locationY = event.dragY + dragStartY;
if (locationY >= 200) {
locationY = 200;
} else if (locationY <= 0) {
locationY = 0;
}
}
}
]
}
}
javafx.scene.Groupクラスは座標を表すxアトリビュートやyアトリビュートがないため、青字で示したように、translateXアトリビュートとtranslateYアトリビュートにlocationX変数、locationY変数をバインドさせています。translateXアトリビュートとtranslateYアトリビュートを0とした場合、音符の楕円の中心が座標(0, 0)となるようにしてあります。
マウスボタンが押された時にコールされるonMousePressed関数でMediaPlayerオブジェクトのplay関数をコールし、再生を開始します。またこの時、ドラッグの開始位置をdragStartX変数とdragStartY変数に保持させておきます。
そして、マウスボタンから離れた時にコールされるonMouseReleased関数でMediaPlayerオブジェクトのstop関数をコールし、再生を停止します。
ドラッグによって描画位置を変更するのがonMouseDragged関数です。
オレンジで示しているように、ドラッグの開始位置とドラッグ量を足し合わせて、ノードの描画位置を決めています。オレンジの下のif文はSceneオブジェクトの領域からはみ出てしまった場合に、領域内に描画させるようにするために使用しています。
図1 にサンプルの実行結果を示しました。今回も実行結果の図からアプレットページに飛びますので、ぜひ実際に試してみてください。また、省略した部分を含むスクリプトのソースも示しましたので、参考になさってください。
図1 ドラッグによりサウンドをコントロールする
ムービーを扱う
次にムービーを再生してみましょう。ムービーを再生するには、javafx.scene.media.MediaViewクラスを使用します。
MediaViewクラスはmediaPlayerアトリビュートを持つので、ここにサウンドの場合と同様にMediaPlayerオブジェクトを生成して代入します。ムービーであってもMediaクラスが扱えるプロトコルはhttp:とfile:です。ただし、ムービーの場合、JARファイルにムービーファイルを含めることはできません。
C:\temp\movie.flvファイルを再生する場合、次のように記述します。
リスト4
// ムービーのメディア
var media = Media {
source: "file:/C:/temp/movie.flv"
};
// ムービーのメディアを含んだメディアプレイヤ
var mediaPlayer = MediaPlayer {
media: media
};
Stage {
title: "Video Player"
scene: Scene {
width: media.width
height: media.height
// メディアプレイヤを表示するノード
content: MediaView {
mediaPlayer: mediaPlayer
}
}
}
// ムービーの再生
mediaPlayer.play();
ムービーのURIのプロトコルにfile:を使用する場合、file:///C:/temp/movie.flvとfile:の後に3つのスラッシュを表記すると、MediaUnsupportedException例外が発生するというバグがあります。URIとしてはfile:///が本来の仕様ですが、このバグを回避するため上記のようにfile:/C:/temp/movie.fllvという表記にしてあります。
ムービーの幅と高さはMediaオブジェクトから取得できるので、赤字で示しているようにSceneオブジェクトのサイズをムービーと同じにしています。
赤字で示した部分がMediaViewオブジェクトの生成部分です。ムービーの再生はサウンドの場合と同じく、MediaPlayerオブジェクトのplay関数をコールします。
MediaViewオブジェクトは変形させることも可能です。ただし、回転をさせる場合はrotatableアトリビュートをtrueに設定し、傾ける場合はtransformableアトリビュートをtrueにしておく必要があります。移動は特に指定する必要はありません。
ここでは、移動しながらムービーを再生するサンプルを作成しました。以下に垂直方向のアニメーションを行う部分を示します。
リスト5
// メディアプレイヤを表示するノード
var mediaView = MediaView {
mediaPlayer: mediaPlayer
}
Stage {
title: "Animated Movie Player"
scene: Scene {
width: 400
height: 200
fill: Color.BLACK
content: mediaView
}
}
// ムービーの再生
mediaPlayer.play();
// 垂直方向のアニメーション
Timeline {
autoReverse: true
repeatCount: Timeline.INDEFINITE
keyFrames: [
KeyFrame {
time: 0s
values: mediaView.y => 0
},
KeyFrame {
time: 10s
// ムービーの高さから移動範囲を決める
values: mediaView.y => 200 - media.height
}
]
}.play();
ムービーということを意識せずに、通常のノードと同様にアニメーションを行っています。
図2 に実行結果を示します。また、アプレットページには省略した水平方向のアニメーションのスクリプトを含めたソースを示しました。
図2 移動しながらムービーの再生を行う
MediaViewクラスはムービー再生の最低限の機能しかありません。もし、再生ボタンやボリューム調整などが必要な場合には、JavaFXのサンプルSimpleVideoPlayer が提供しているMediaComponentクラスが使用できます。ぜひ参考にしてください。
JavaFX Production Suite
JavaFX Production Suiteは複数のツールから構成されています。表2 にProduction Suiteに含まれるツールをまとめました。
表2 JavaFX Production Suiteに含まれるツール
ツール
説明
Adobe Illustrator用JavaFXプラグイン
Illustratorで作成したアートワークをJavaFXフォーマットで保存するプラグイン
Adobe Photoshop用JavaFXプラグイン
Photoshopで作成したアートワークをJavaFXフォーマットで保存するプラグイン
SVGコンバータ
SVGファイルをJavaFXフォーマットに変換するツール
fx viewer
JavaFXフォーマットのグラフィックファイルのビューア
JavaFXフォーマットについては後述します。
Production Suiteのインストール
では、Production Suiteをインストールしてみましょう。Production SuiteはJavaFX SDKと同じくhttp://javafx.com/ もしくは、http://java.sun.com/javafx/downloads/ からダウンロードできます。Windowsの場合、ダウンロードするファイルはjavafx_production_suite-1_0-windows-i586.exeです。
このファイルを実行すると、図3 に示したようなウィザードが表示されます。
図3 JavaFX Production Suiteセットアップウィザード
[Next >]をクリックして先に進むと、図4 に示したライセンス条項が提示されます。ライセンスを確認後、[I accept the terms in the Licence Agreement]にチェックをし、[Next >]をクリックします。
図4 JavaFX Production Suiteのライセンス
次にProduction Suiteをインストールする場所を設定します(図5 ) 。[Next >]をクリックすると、インストールを開始します。
図5 インストール場所の設定
Adobe IllustratorおよびPhotoshop用JavaFXプラグインのインストール
IllustratorのプラグインはProduction Suiteをインストールしたディレクトリの直下にあるJavaFX Plugin for Adobe Illustratorディレクトリにあります。同様にPhotoshopのプラグインはJavaFX Plugin for Adobe Photoshopディレクトリです。
ここでは、Illustratorプラグインの場合を説明しますが、Photoshopでも同様に行うことができます。
JavaFX Plugin for Adobe Illustratorディレクトリの下にPlug-insディレクトリがあります。このディレクトリごとIllustratorをインストールしたディレクトリにコピーします。
筆者はAdobe CS4を使用しており、Illustrator CS4はC:\Program Files\Adobe\Adobe Illustrator CS4ディレクトリにインストールされています。ここにPlug-insディレクトリをコピーしました。コピーすると、「 フラグイン」フォルダと「Plug-ins」フォルダを統合するかを確認するダイアログが表示されます。もちろん、統合してしまってかまわないので、「 はい」をクリックします。また、同様に「Illustrator 形式 - 標準」フォルダと「Illustrator Formats」フォルダを統合するか確認するダイアログも表示されるので、「 はい」をクリックします[2] 。
コピーした後、Illustratorを起動すると、図6 のようにメニューバーの[File]の中に[Save for JavaFX...]が追加されているはずです。Photoshopの場合は、[ファイル]-[自動処理]-[Save for JavaFX...]になります。
図6 インストール場所の設定
[2] Illustrator CS3の場合、Plug-ins\Illustrator FormatsにあるAI2JavaFX.aipファイルとAI2JavaFX.jarファイルを、Illustrator CS3をインストールしたディレクトリ下の「プラグイン\Illustrator 形式 - 標準」ディレクトリにコピーしてください。
JavaFXプラグインを使ってみる
では、実際にJavaFXプラグインを使用してみましょう。まずIllustratorで次のような絵を描いてみました。
図7 元となる図
JavaFXで扱えるようにするには、図6に示したようにメニューバーの[ファイル]から[Save for JavaFX...]を選択します。すると図8 のようなダイアログが表示されます。
図8 JavaFXエクスポートダイアログ
左側のペインに表示されているように、[Show Preview]をチェックするとプレビューが表示されます(図9 ) 。
図9 アートワークのプレビュー
では、ここで[Save]をクリックして、保存してみましょう。保存するとファイルの拡張子はfxzになります。
fxzファイルはどのような記述がなされているのでしょう。実をいうと、fxzファイルはZIP形式で圧縮されたファイルです。つまり、そのまま展開することができます。ここではartwork.fxzというファイルにしたので、それを展開してみました。
展開するとcontent.fxdファイルが含まれていることがわかります。次にcontent.fxdファイルを示します(見やすさのため整形してあります) 。
リスト6
/*
* Generated by JavaFX plugin for Adobe Illustrator.
* Created on Tue Jan 17 14:56:50 JST 2009
* Build date: 2008-11-26_00-26-18
* Build id: 1.22768768E9
* Revision: 2210.0
*/
//@version 1.0
Group {
content: [
Group {
content: [
Rectangle {
fill: Color.rgb(0xff,0x33,0x33,1.0)
stroke: Color.BLACK
strokeWidth: 1.0
x: 0.5
y: 0.5
width: 120.0
height: 80.0
},
SVGPath {
fill: Color.rgb(0x66,0x99,0xff,1.0)
stroke: Color.BLACK
strokeWidth: 1.0
content: "M70.05,84.32 C70.05,56.71 92.43,
34.32 120.05,34.32 C147.66,34.32 170.05,
56.71 170.05,84.32 C170.05,111.94 147.66,
134.32 120.05,134.32 C92.43,134.32 70.05,
111.94 70.05,84.32 Z "
},
]
},
]
}
なんのことはない、ごくごく普通のJavaFX Scriptのスクリプトでした。このFXDファイルの記述がJavaFXフォーマットと呼ばれているものです。
では、このJavaFXフォーマットのファイルをスクリプトの中から扱ってみましょう。ここではpluginsample1というNetBeansのプロジェクトを作成しました。そして、JavaFXフォーマットファイルをロードするためのライブラリをインポートします。Production Suiteをインストールしたディレクトリの直下のLibrariesディレクトリにあるjavafx-fxd-1.0.jarが、そのライブラリです。
ここでは、pluginsample1ディレクトリの下にlibディレクトリを作成し、そこにjavafx-fxd-1.0.jarファイルをコピーしました。次にNetBeansで、pluginsample1プロジェクトのLibrariesを右クリックします。すると、図10 のようにポップアップメニューが表示されるので、[Add Jar/Folder]を選択します。ファイルチューザが表示されるので、先ほどコピーしたjavafx-fxd-1.0.jarファイルを指定します。
図10 JARファイルの追加
JARファイルが追加されると、図11 のようにLibrariesの下にjavafx-fxd-1.0.jarが表示されます。
図11 javafx-fxd-1.0.jarファイルの追加結果
次に、先ほど作成したartsample.fxzをパッケージに含めておきましょう。ここでは、pluginsample1プロジェクトのsrcディレクトリにコピーしました。
スクリプトからJavaFXフォーマットファイルをロードするには、javafx-fxd-1.0.jarに含まれているjavafx.fxd.FXDLoaderクラスを使用します。以下にFXZファイルの内容を描画するスクリプトを示します。
リスト7
Stage {
title: "Plugin Sample"
scene: Scene {
width: 200
height: 200
content: {
// FXZファイルのロード
FXDLoader.load("{__DIR__}artwork.fxz"); }
}
}
JavaFXフォーマットファイルのロードはFXDLoaderクラスのload関数で行います。引数はURIで、戻り値がJavaFXフォーマットで表された描画ノードになります。
このスクリプトを実行した結果を図12 に示します。
図12 JavaFXフォーマットファイルの描画
IllustratorやPhotoshopで作成したアートワークを1つのものとして扱うのであれば、この方法でかまいません。しかし、たとえば図12の四角と丸を別々に扱いたい場合もあるはずです。
このような場合、IllustratorやPhotoshopで別々に扱う描画オブジェクトに名前をつけておきます。名前をつける場合、レイヤーとオブジェクトのどちらでもかまいませんが、名前にjfx:という接頭語をつけておきます。こうすることで、JavaFXがjfx:の接頭語のついたレイヤーもしくはオブジェクトを個別に扱うことができます。
図13 にIllustratorの例を示しました。図13では四角をjfx:rectangleレイヤー、丸をcircleレイヤーにあるjfx:circleオブジェクトと名前をつけました。
図13 Illustratorでのレイヤー分割
そして、再びJavaFXプラグインを使用して、FXZファイルを生成します。名前付けしたオブジェクトを個々に取得するにはFXDLoaderクラスのloadContent関数を使用します。loadContent関数の戻り値はjavafx.fxd.FXDContentクラスです。
FXDContentクラスはgetShape関数とgetNode関数を持ちます。前者がIllustratorでオブジェクトに名前付けしたもの、後者がレイヤーに名前付けしたものを取得できます。2つの関数とも、引数にはjfx:を除いた名前を用います。
リスト8
// FXZファイルのロード
var content: FXDContent = FXDLoader.loadContent("{__DIR__}artwork2.fxz");
// FXDContentオブジェクトから描画オブジェクトを取得
// レイヤーに名前付けしたものはNodeクラス、
// オブジェクトに名前付けしたものはShapeクラスで表される
var circle: Shape = content.getShape("circle");
var square: Node = content.getNode("rectangle");
Stage {
title: "Plugin Sample"
scene: Scene {
width: 200
height: 150
content: [circle, square]
}
}
ここでは、丸がShapeオブジェクト、四角がNodeオブジェクトとして扱われます。別々に取得できたので、描画順序を変えてみたの結果が図14 です。
図14 描画オブジェクトを個別に扱う
今までのサンプルは、FXDLoaderクラスとFXDContentクラスを直接使用しましたが、この2つのクラスの機能をまとめたjavafx.fxd.UiStubクラスも使用することができます。興味がある方はProduction Suiteをインストールしたディレクトリ下のLibrariesディレクトリにAPIドキュメントがあるので、そちらをご参照ください。
最後にもう1つサンプルを紹介しましょう。桜の花びらが1枚落ちていくというアニメーションを行うスクリプトです。
Illustratorで作成したアートワークを図15 に示します。黒い線は桜の花びらが落ちる軌跡を示しています。つまり、前回使用したjavafx.animation.transition.PathTransitionクラスで使用するパスをIllustratorで作成してしまったわけです。
このような複雑な曲線をプログラムだけで作成するのは大変ですが、Illustratorであれば簡単に作成できます。このような曲線はリスト6 にも示したようにjavafx.scene.shape.SVGPathクラスで表されます。PathTransitionクラスで使用するガイドパスを作成するjavafx.animation.transition.AnimationPathクラスには、SVGPathオブジェクトを引数にとるcreateFromPath関数が定義されています。この関数を使うことで、Illustratorで作成した曲線に沿ってアニメーションすることが可能になります。
図15 桜と花びらの落ちる軌跡
ここではスクリプトの解説は行いませんが、興味がある方は図16 からリンクしているアプレットのページにスクリプトを示しておきましたので、参考にしてください。
図16 桜の花びらが落ちるアニメーション