swfmillでケータイFlashを動的生成してみよう(画像置換編)

By ookura - 08/12/19 - このエントリをはてなブックマークに追加このエントリをYahoo!ブックマークに追加このエントリをdel.icio.usに追加このエントリをFC2ブックマークに追加

前回はswf内の文字列置換について説明しました。
今回はswfmillを使ったswf内の画像の置換方法について説明します。
参照:swfmillでケータイFlashを動的生成してみよう(文字列置換編)
 
今回ご紹介するのはJPEG画像の置換処理になります。
※JPEG以外の画像形式の置換方法についてはここでは説明しません。

swfファイルを用意する

あらかじめFlashLite1.1のswfファイルを用意します。
以前作成した縦スクロールするFlashを少し変更して使います。
参照:「ケータイFlashで縦スクロールするページを作ってみよう
 
変更点は以下の通りです。
 
 
mainムービークリップを編集します。
背景画像ファイルをヘッダに画像の入ったデザインに変更しておき、
ライブラリに読み込んで背景画像ファイル入れ替えます。
[図51]
 
置換用のダミー画像(ここでは220px×140px)をライブラリに読み込んだものを、新規にレイヤー(top)を追加して配置し、グラフィックシンボルに変更します。
画像には判別ミスを防ぐためにFlashに組み込む前からテキストで「{$topImage}」と入れておきます。
[図52]
 
デザイン上の見ばえを意識してトップ画像の上にさらにレイヤー(frame)を追加し、シェイプで枠をつけます。
[図53]
 
ヘッダ・フッタのテキストは中央揃えにして横いっぱいに伸ばします。
[図54]
 
各リンクの文字列は背景の変更に合わせて位置を修正します。
[図55]
 
各静止テキストに置換用の変数名を入れていきます。
タイトルとフッタの文字列を以下のように設定します。
「{$titleText}」「{$footerText}」
 
リンクの文字列を以下のように設定します。
「{$linkText1}」「{$linkText2}」「{$linkText3}」「{$linkText4}」「{$linkText5}」
[図56]
 
静止テキストのフォントはデバイスフォントの「_等幅」にしておきます。
静止テキストのフォントサイズは大きいものは20px,小さいものは12pxで設定しました。
 
 
リンクのURL文字列を変更します。
シーン1に戻り、一時的にmainムービークリップのあるpageレイヤーを非表示にして設定します。
リンク先のURLは以下のように指定します。
「{$linkUrl1}」「{$linkUrl2}」「{$linkUrl3}」「{$linkUrl4}」「{$linkUrl5}」
[図57]

on (press) {
    getURL("{$linkUrl1}");
}

 
カーソルの座標を各リンク文字の位置に合わせて調整します。
[図58]

if (selectNo == 1) {
    pageY = 0;
    main/cursor:_x = 4;
    main/cursor:_y = 220;
}
if (selectNo == 2) {
    pageY = -50;
    main/cursor:_x = 25;
    main/cursor:_y = 270;
}
if (selectNo == 3) {
    pageY = -100;
    main/cursor:_x = 45;
    main/cursor:_y = 321;
}
if (selectNo == 4) {
    pageY = -150;
    main/cursor:_x = 66;
    main/cursor:_y = 372;
}
if (selectNo == 5) {
    pageY = -200;
    main/cursor:_x = 86;
    main/cursor:_y = 423;
}

 
できたらパブリッシュしてサーバーにアップロードします。
[図59]
 
 


PHPとswfmillの連携

では実際に変換する処理をPHPで作成します。
 
処理の流れとしては、以下のようになります。
・swfファイルを用意する
・swfファイルを読み込む
・swfmillに対してパイプ処理でswfファイルの内容を渡してxmlデータを取得する
・xmlデータの文字列を書き換える
・元画像と置換画像のデータをそれぞれ取得する
・xmlデータの画像データを書き換える
・swfmillに対してパイプ処理でxmlデータを渡してswfファイルの内容を取得する
・flashのヘッダを出力してswfファイルの内容を出力する
 
 


画像を置換するしくみ

画像の入ったswfファイルをswfmillでXMLで分解すると、画像のバイナリデータがBase64エンコードされた文字列としてXMLデータ内に入ります。

SWFファイルから変換したXMLデータ
(前略)
……
<DefineBitsJPEG2 objectID="**">
  <data>
    <data>[Base64エンコードされた元画像バイナリ]</data>
  </data>
</DefineBitsJPEG2>
……
(後略)

 
あらかじめswfに組み込んだ画像ファイルを別に用意しておき、Base64エンコードした文字列に変換します。
表示させたい画像ファイルも同様にbase64エンコードして元画像の文字列と置換すれば画像の差し替えができます。

元画像を取得してBase64エンコード
↓
置換したい画像を取得してBase64エンコード
↓
XMLデータ上で置換

(前略)
……
<DefineBitsJPEG2 objectID="**">
  <data>
    <data>[Base64エンコードされた置換画像バイナリ]</data>
  </data>
</DefineBitsJPEG2>
……
(後略)

 
 


元画像と置換画像のデータをそれぞれ取得する

それぞれの画像ファイルパスをあらかじめ配列に格納しておきます。
複数の画像を置換する場合はこの連想配列を増やせば対応できます。

// 画像置換

// 元のファイル名を連想配列で設定
$defaultImage = array(
    'topImage'   => "default_top_image.jpg",
);

// 置換するファイル名を連想配列で設定
$replaceImage[0] = array(
    'topImage'   => "top_image1.jpg",
);
$replaceImage[1] = array(
    'topImage'   => "top_image2.jpg",
);

 
file_get_contents()関数で画像データを取得し、
頭にバイナリをつけてbase64_encode()関数でエンコードします。
そして、XMLデータの画像部分を置換します。

foreach($replaceImage[$pattern] as $key => $value){
    
    // 元の画像データを取得してエンコード
    $defaultImageData = file_get_contents($defaultImage[$key]);
    $defaultImageEncoded = base64_encode("\xFF\xD9\xFF\xD8" . $defaultImageData);
    
    // 置換する画像データを取得してエンコード
    $replaceImageData = file_get_contents($replaceImage[$pattern][$key]);
    $replaceImageEncoded = base64_encode("\xFF\xD9\xFF\xD8" . $replaceImageData);
    
    // エンコードした画像データを置換
    $xmlString = str_replace($defaultImageEncoded, $replaceImageEncoded, $xmlString);
}

 
JPEGバイナリデータをbase64エンコードする際は、swfファイル内でのJPEGバイナリの格納形式に沿って以下のように各画像の先頭にバイナリをつけてからbase64エンコードする必要があります。

$defaultImageEncoded = base64_encode(
    "\xFF\xD9\xFF\xD8" . $defaultImageData);

上記のバイナリ「\xFF\xD9\xFF\xD8」は画像セグメントを分割するマーカーになります。
 
SWFファイル内では画像バイナリに上記のマーカーがついた形で保存されていますので、置換する画像をエンコードする際にもバイナリを付けておく必要があります。
 
※上記の方法はFlashLite1.1の場合で、FlashLite2.0以上の場合は上記バイナリはつけずにそのままbase64エンコードします。
 
 


備考

・JPEG画像の形式によってはうまく置換できない可能性があります。
 
・画像の読み込み・置換処理はサーバー負荷が高くなりますので、アクセスが多い場合にはキャッシュを保存するなどの対応が必要になってくることでしょう。
 
・置換方法に関してはいろいろな方法があり、上記で紹介したものよりもっと効率的な方法があるかと思います。
 
 


PHPソース例

実際のソースは以下の通りです。
 
sample1775.php

<?php
/* 
 * swfの画像を置換して出力するサンプル
 */

// 置換パターンを指定
$pattern = intval($_GET['pattern']);
if (!in_array($pattern, array(0,1))) {
    $pattern = 0;
}

// SWFファイルの内容を取得
$swfData = file_get_contents('sample1775.swf');


// SWFからXMLに変換

// コマンド実行時の入出力とエラー出力先を指定
$descriptorspec = array(
   0 => array("pipe", "r"),
   1 => array("pipe", "w"),
   2 => array("file", "error-output.txt", "a")
);

// swfmillコマンドを実行してリソースとファイルポインタを取得
$process = proc_open('/usr/local/bin/swfmill -e cp932 swf2xml stdin stdout', $descriptorspec, $pipes);

if (is_resource($process)) {
    // 標準入力にSWFファイルのバイナリデータを書き込み
    fwrite($pipes[0], $swfData);
    fclose($pipes[0]);
    
    // 標準出力からXMLデータを読み込み
    $xmlString = stream_get_contents($pipes[1]);
    fclose($pipes[1]);
    
    // パイプを全て閉じてからプロセスを閉じる
    proc_close($process);
}

// 文字列置換

// 置換する値を連想配列で設定
$replaceStrings[0] = array(
    'titleText'   => "ページタイトル",
    'footerText'  => "フッタテキスト",
    'linkText1'   => "リンク1",
    'linkText2'   => "リンク2",
    'linkText3'   => "リンク3",
    'linkText4'   => "リンク4",
    'linkText5'   => "リンク5",
    'linkUrl1'    => "link1.html",
    'linkUrl2'    => "link2.html",
    'linkUrl3'    => "link3.html",
    'linkUrl4'    => "link4.html",
    'linkUrl5'    => "link5.html",
);
$replaceStrings[1] = array(
    'titleText'   => "携帯サイトをつくろう。",
    'footerText'  => "(c)www.plusmb.jp",
    'linkText1'   => "新着情報",
    'linkText2'   => "携帯サイトとは?",
    'linkText3'   => "カテゴリ一覧",
    'linkText4'   => "人気の記事",
    'linkText5'   => "最近の投稿",
    'linkUrl1'    => "link6.html",
    'linkUrl2'    => "link7.html",
    'linkUrl3'    => "link8.html",
    'linkUrl4'    => "link9.html",
    'linkUrl5'    => "link10.html",
);

foreach($replaceStrings[$pattern] as $key => $value){
    
    // 文字列を連想配列の値に置換
    $xmlString = str_replace('{$' . $key . '}', $value, $xmlString);
    
}

// 画像置換

// 元のファイル名を連想配列で設定
$defaultImage = array(
    'topImage'   => "default_top_image.jpg",
);

// 置換するファイル名を連想配列で設定
$replaceImage[0] = array(
    'topImage'   => "top_image1.jpg",
);
$replaceImage[1] = array(
    'topImage'   => "top_image2.jpg",
);

foreach($replaceImage[$pattern] as $key => $value){
    
    // 元の画像データを取得してエンコード
    $defaultImageData = file_get_contents($defaultImage[$key]);
    $defaultImageEncoded = base64_encode("\xFF\xD9\xFF\xD8" . $defaultImageData);
    
    // 置換する画像データを取得してエンコード
    $replaceImageData = file_get_contents($replaceImage[$pattern][$key]);
    $replaceImageEncoded = base64_encode("\xFF\xD9\xFF\xD8" . $replaceImageData);
    
    // エンコードした画像データを置換
    $xmlString = str_replace($defaultImageEncoded, $replaceImageEncoded, $xmlString);
}

// XMLからSWFに変換

// コマンド実行時の入出力とエラー出力先を指定
$descriptorspec = array(
   0 => array("pipe", "r"),
   1 => array("pipe", "w"),
   2 => array("file", "error-output.txt", "a")
);

// swfmillコマンドを実行してリソースとファイルポインタを取得
$process = proc_open('/usr/local/bin/swfmill -e cp932 xml2swf stdin stdout', $descriptorspec, $pipes);

if (is_resource($process)) {
    
    // 標準入力にXMLデータを書き込み
    fwrite($pipes[0], $xmlString);
    fclose($pipes[0]);
    
    // 標準出力からSWFファイルのバイナリデータを読み込み
    $swfOutput = stream_get_contents($pipes[1]);
    fclose($pipes[1]);
    
    // パイプを全て閉じてからプロセスを閉じる
    proc_close($process);
}

// SWFのヘッダを出力
header('Content-type: application/x-shockwave-flash');

// SWFのデータを出力
echo $swfOutput;
?>

 
 


参照URL

swfmillの構造を理解する – 続・ken39arg
 
 


実行例

実行例はこちらからご確認下さい。

URLをメールで送る
http://ookura.tanikaze.com/Sample/post1775/
 
 


Flashサイト動的生成関連の記事一覧

1.ケータイFlashの概要
 1-1 ケータイFlashの概要について
 
2.ケータイFlashのページ作成
 2-1 ケータイFlashのページを作ってみよう
 2-2 ケータイFlashで縦スクロールするページを作ってみよう
 
3.swfmillでケータイFlashを動的生成
 3-1 swfmillでケータイFlashを動的生成してみよう(インストール編)
 3-2 swfmillでケータイFlashを動的生成してみよう(文字列置換編)
 3-3 swfmillでケータイFlashを動的生成してみよう(画像置換編)
 3-4 ケータイFlashのレイアウトを文章量に同期させよう
 
4.ActionScriptとPHPの連携
 4-1 ActionScriptで文字列をPHPから動的に取得しよう
 4-2 ケータイFlashでテキスト入力フォームを作ろう