[PHP解説編] Jawbone UP のログから画像を生成して Facebook に投稿するよ
はじめに
今回は、前回の続きです。IFTTT って何? 何をしようとしてるの? という方は前回の記事を読んでから先に進んでください m(_ _)m
さて、前回の解説では IFTTT だけでは Facebook へのポスト方法に限界があるので、自前でスクリプトを用意して画像を動的に生成して Facebook にポストするという方法を提案しました。
今回は、前回触れなかった PHP スクリプト部分について書こうと思います。
IFTTT側の準備
まずは IFTTT の web からトリガーとアクションを設定しておく必要があります。
UP (トリガー)側
IFTTT を使って2つのサービスを連携させるために、まずは トリガー側である Jawbone UP の発火条件として「New daily movement」を選びます。これは Jawbone UP とスマホを同期してその日のアクティビティが登録されたときにトリガーがかかります。ですので、毎日同期すると1日1回トリガーがかかります。特に設定などはないのでトリガー側はこれでおしまいです。
Facebook (アクション側)
次に、アクション側である Facebook ですが、アクションとして「Upload a photo from URL」を選びます。これは、画像 URL と文章を指定してポストすると、画像 URL の写真が文章とともに Facebook のアルバムに登録されます。画像は Facebook 側にコピーされるので、PHP で画像を作ったものを自分のサーバに保存しておく必要はありません。
このアクションを選ぶと下図のような入力フィールドが現れます。
Photo URL
ここが今回のミソです。固定の画像 URL を渡すのではなく、下のような PHP にパラメータを渡す形で自前のサーバに画像を要求しています。この URL の中で {{…}} で囲われている部分は実際には Jawbone UP のトリガーから渡されてくる値に置換されます。
http://miyadi.net/test/jawbone_up/activity_graph.php?target=10000&steps={{TotalSteps}}&calories={{TotalCaloriesBurned}}&distance={{DistanceCoveredKM}}&unit=Km&date={{DateOfActivity}}
ここから先は PHP 側の処理になるのでちょっと先に他のパラメータの解説をしておきます。
Message
画像に付ける文章です。ここにも Jawbone UP トリガー側から送られてくるパラメータを入れることができます。
Album name
Facebook に保存するときのアルバム名を指定します。ここでは 「Jawbone UP logs」というアルバム名にして普通の写真と混ざらないように別の名前で分かりやすくしています。
スクリプトで画像を生成する
Facebook の投稿設定で指定した画像 URL の先にある PHP スクリプトを用意します。このファイルはレンタルサーバや自前のサーバなどに置いて動かします。僕の場合はナウでヤングなロリポップサーバを使っています。家計にも優しいので。ロリポップのステマではありませぬ。
全体の流れ
処理全体のおおまかな流れは下図の通りです。オレンジ色の部分が実際に画像を生成しています。といっても大したことはしておらず、ベースとなる画像に達成度に応じた顔マークとグラフを置いて、文字を描画しているだけです。フォントは Fonts2U から Decker というフリーの書体を選びました。イメージファイルや フォントファイルは PHP を置いたフォルダの下にサブフォルダを作って置きました。
パラメータの取得
まず、渡された URL から各種パラメータを取得して、変数に格納しておきます。各パラメータが存在するかのチェックはここでは省いてあります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// パラメータの取得 // 日付 $date = $_GET['date']; // 目標歩数 $target = $_GET['target']; // 歩数 $steps = $_GET['steps']; // カロリー $calories = $_GET['calories']; // 距離 $distance = round( $_GET['distance'], 2); // 距離単位 $dis_unit = $_GET['unit']; // 達成率計算 $percent = round( ($steps / $target) * 100 ); |
ターゲット歩数 $target と 実績歩数 $steps から達成率 $percent も計算しておきます。
画像の生成
ざっくり図にすると次のようになります。
コードを載せます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
// ベース画像の読み込み $imgMain = imagecreatefromjpeg( "images/base.jpg" ); // 人型グラフ用 0% 画像の読み込み $img0 = imagecreatefromjpeg( "images/walk_0.jpg" ); // イメージの描画 // 達成率に合わせて人型グラフを描画 $sizeY = ( (100 - $percent) / 100) * MAN_SIZE_Y ; if( $sizeY > MAN_SIZE_Y ){ $sizeY = MAN_SIZE_Y; } imagecopy( $imgMain, $img0, 0, GRAPH_OFFSET_Y, 0 , 0, MAN_SIZE_X, $sizeY ); // 達成率に合わせたムード表示 if( $percent < 30 ){ $imgMood = imagecreatefromjpeg( "images/worst.jpg" ); } else if( $percent < 60 ){ $imgMood = imagecreatefromjpeg( "images/bad.jpg" ); } else if( $percent < 80 ){ $imgMood = imagecreatefromjpeg( "images/soso.jpg" ); } else if( $percent < 100 ){ $imgMood = imagecreatefromjpeg( "images/nice.jpg" ); } else { $imgMood = imagecreatefromjpeg( "images/best.jpg" ); } imagecopy( $imgMain, $imgMood, MOOD_OFFSET_X, MOOD_OFFSET_Y, 0 , 0, MOOD_SIZE_X, MOOD_SIZE_Y ); |
7〜10行目で人型グラフを生成してベース画像に部分的に重ねます。それ以降は、達成率に合わせて達成マーク画像を読み込んでベース画像に合成しています。
文字列の描画
あとはレイアウトに従って文字列を1つずつ描画しています。フォント設定と達成率の描画部分を下に示します。
1 2 3 4 5 6 7 8 |
// フォント設定 $fontColor = imagecolorallocate( $img0, 0, 0, 0 ); $fontPath = "fonts/DeckerB.ttf"; // 達成率の描画 $text = mb_convert_encoding( $percent."%", "UTF-8", "EUC-JP" ); imagettftext( $imgMain, TEXT_SIZE_PERCENT, 0, TEXT_OFFSET_HEAD_P, MOOD_SIZE_Y, $fontColor, $fontPath, $text ); |
すべての文字列を描画すると下図のような画像ができて完成です。
フォントはフリーの DeckerB.ttf を利用しました。また、文字列に将来日本語を使うことも考えてテキストの文字コード変換をかませてから表示しています。
PHP 全体
たいした行数ではないので、全コードを載せておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
<?php /*--------------------------------------------------------- 定数の定義 ----------------------------------------------------------*/ define("MAN_SIZE_X", 175); define("MAN_SIZE_Y", 168); define("GRAPH_OFFSET_Y", 60); define("MOOD_SIZE_X", 46); define("MOOD_SIZE_Y", 46); define("MOOD_OFFSET_X", 10); define("MOOD_OFFSET_Y", 10); define("TEXT_OFFSET_HEAD_P", MOOD_SIZE_X + 20); define("TEXT_OFFSET_HEAD_D", MOOD_SIZE_X + 160); define("TEXT_OFFSET_X1", 70); define("TEXT_OFFSET_X2", 230); define("TEXT_OFFSET_X3", 400); define("TEXT_OFFSET_Y", 170); define("TEXT_UNIT_OFFSET_X", 40); define("TEXT_UNIT_OFFSET_Y", 190); define("TEXT_SIZE_PERCENT", 32); define("TEXT_SIZE_MAIN", 26); define("TEXT_SIZE_UNIT", 18); /*--------------------------------------------------------- URL からパラメータの取得 ----------------------------------------------------------*/ // パラメータの取得 // 日付 if(isset($_GET['date'])) { $date = $_GET['date']; } // 目標歩数 if(isset($_GET['target'])) { $target = $_GET['target']; } // 歩数 if(isset($_GET['steps'])) { $steps = $_GET['steps']; } // カロリー if(isset($_GET['calories'])) { $calories = $_GET['calories']; } // 距離 if(isset($_GET['distance'])) { $distance = round( $_GET['distance'], 2); } // 距離単位 if(isset($_GET['unit'])) { $dis_unit = $_GET['unit']; } // 達成率計算 $percent = round( ($steps / $target) * 100 ); /*--------------------------------------------------------- 画像の生成 ----------------------------------------------------------*/ // ベース画像の読み込み $imgMain = imagecreatefromjpeg( "images/base.jpg" ); // 人型グラフ用 0% 画像の読み込み $img0 = imagecreatefromjpeg( "images/walk_0.jpg" ); // イメージの描画 // 達成率に合わせて人型グラフを描画 $sizeY = ( (100 - $percent) / 100) * MAN_SIZE_Y ; if( $sizeY > MAN_SIZE_Y ){ $sizeY = MAN_SIZE_Y; } imagecopy( $imgMain, $img0, 0, GRAPH_OFFSET_Y, 0 , 0, MAN_SIZE_X, $sizeY ); // 達成率に合わせたムード表示 if( $percent < 30 ){ $imgMood = imagecreatefromjpeg( "images/worst.jpg" ); } else if( $percent < 60 ){ $imgMood = imagecreatefromjpeg( "images/bad.jpg" ); } else if( $percent < 80 ){ $imgMood = imagecreatefromjpeg( "images/soso.jpg" ); } else if( $percent < 100 ){ $imgMood = imagecreatefromjpeg( "images/nice.jpg" ); } else { $imgMood = imagecreatefromjpeg( "images/best.jpg" ); } imagecopy( $imgMain, $imgMood, MOOD_OFFSET_X, MOOD_OFFSET_Y, 0 , 0, MOOD_SIZE_X, MOOD_SIZE_Y ); /*--------------------------------------------------------- 文字列の描画 ----------------------------------------------------------*/ // フォント設定 $fontColor = imagecolorallocate( $img0, 0, 0, 0 ); $fontPath = "fonts/DeckerB.ttf"; // 達成率の描画 $text = mb_convert_encoding( $percent."%", "UTF-8", "EUC-JP" ); imagettftext( $imgMain, TEXT_SIZE_PERCENT, 0, TEXT_OFFSET_HEAD_P, MOOD_SIZE_Y, $fontColor, $fontPath, $text ); // 日付の描画 $text = mb_convert_encoding( "[".$date."]", "UTF-8", "EUC-JP" ); imagettftext( $imgMain, TEXT_SIZE_MAIN, 0, TEXT_OFFSET_HEAD_D, MOOD_SIZE_Y - 5, $fontColor, $fontPath, $text ); // 歩数の描画 $text = mb_convert_encoding( $steps, "UTF-8", "EUC-JP" ); imagettftext( $imgMain, TEXT_SIZE_MAIN, 0, TEXT_OFFSET_X1, TEXT_OFFSET_Y, $fontColor, $fontPath, $text ); $unit = mb_convert_encoding( "steps", "UTF-8", "EUC-JP" ); imagettftext( $imgMain, TEXT_SIZE_UNIT, 0, TEXT_OFFSET_X1 + TEXT_UNIT_OFFSET_X, TEXT_UNIT_OFFSET_Y, $fontColor, $fontPath, $unit ); // カロリーの描画 $text = mb_convert_encoding( $calories, "UTF-8", "EUC-JP" ); imagettftext( $imgMain, TEXT_SIZE_MAIN, 0, TEXT_OFFSET_X2, TEXT_OFFSET_Y, $fontColor, $fontPath, $text ); $unit = mb_convert_encoding( "kcal", "UTF-8", "EUC-JP" ); imagettftext( $imgMain, TEXT_SIZE_UNIT, 0, TEXT_OFFSET_X2 + TEXT_UNIT_OFFSET_X, TEXT_UNIT_OFFSET_Y, $fontColor, $fontPath, $unit ); // 距離の描画 $text = mb_convert_encoding( $distance, "UTF-8", "EUC-JP" ); imagettftext( $imgMain, TEXT_SIZE_MAIN, 0, TEXT_OFFSET_X3, TEXT_OFFSET_Y, $fontColor, $fontPath, $text ); $unit = mb_convert_encoding( $dis_unit, "UTF-8", "EUC-JP" ); imagettftext( $imgMain, TEXT_SIZE_UNIT, 0, TEXT_OFFSET_X3 + TEXT_UNIT_OFFSET_X, TEXT_UNIT_OFFSET_Y, $fontColor, $fontPath, $unit ); /*--------------------------------------------------------- 最終画像の表示 ----------------------------------------------------------*/ header('Content-Type: image/png'); ImagePNG($imgMain); /*--------------------------------------------------------- 後始末 ----------------------------------------------------------*/ imagedestroy( $imgMood ); imagedestroy( $img0 ); imagedestroy( $imgMain ); ?> |