Twitterでコラ画像が流行すると、大体数日で○○の画像ジェネレータみたいなものがリリースされます。
この画像ジェネレータ系のサービスはGDかImageMagickを使っているのかと思っていましたが、最近はcanvasでつくられているようです。
私もこういうものを作ってみたいと思っていたので、ちょっと調べて簡単な画像ジェネレータを作ってみました。
canvasを扱う場合はCreateJSを使うのが便利なようです。
今回はアニメーションの処理はないため、CreateJSの中のEaselJSのみを使用しました。
ADs
初出は以下の方のツイートではないかと思います。
大流行したわけではないですが、個人的には面白かったと同時にソウルジェムが濁っていくのを感じました…(;´Д`)
営業さん100人に聞きました pic.twitter.com/ZTDhsRBi3x
— スズコスケ (@suzukosuke) November 1, 2013
EaselJSとjQuery(必須ではないがあったほうが楽)をロードし、入力用のテキストエリアと出力用のcanvas要素を用意します。
フォームとして機能させる必要はないのでformタグは入りません。
canvasタグは生成される画像のwidth/heightが必要です。
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 |
<script src="https://code.createjs.com/easeljs-0.7.1.min.js"></script> <script src="https://code.jquery.com/jquery-1.11.0.min.js"></script> ~ 中略 ~ <!-- 入力エリア部分 --> <dl class="table"> <dt>タイトル</dt> <dd><input type="text" name="txt01" id="txt01" placeholder="営業さん" />100人に聞きました</dd> <dt>質問</dt> <dd><input type="text" name="txt02" id="txt02" placeholder="できますか?" /></dd> <dt>凡例:100%</dt> <dd><input type="text" name="txt03" id="txt03" placeholder="できる" /></dd> <dt>凡例:0%</dt> <dd><input type="text" name="txt04" id="txt04" placeholder="できない" /></dd> </dl> <div class="btn"> <button id="update">画像生成</button> </div> <!-- 出力部分 --> <div class="module"> <h2>結果</h2> <!-- width,heightは必須 --> <canvas id="result" width="600" height="400"></canvas> <div class="btn"> <form action="img.php" method="post" id="saveform"> <button id="save">画像として保存</button> </form> </div> </div> |
おおまかな手順としては
1.ステージをつくる
2.そのステージに画像と文字を入れる
3.再描画する
という流れになります。
FlashのActionScriptを書いていた人には分かりやすいそうですが、私はほとんど使ったことがないのであまりピンと来ませんでした…。
jQueryのappend()を繰り返している、と言うほうが個人的には分かりやすいです。
なお、今回つくったものはcanvasによる処理のみでなく、画像としてダウンロードさせる処理を入れています。
Javascript側で行っていることは、toDataURLでbase64に変換したデータをPHPにPOSTするだけです。
そのPOSTを受けてデコードし、headerをapplication/octet-streamに変更してダウンロードさせています。
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 |
(function($){ //初期化 var init = function(){ //ベースとなる画像のプリロード baseImg = new Image(); baseImg.src = 'image.jpg'; stage = new createjs.Stage('result'); } //画像と文字を合成する処理 var genImage = function(){ var img = new createjs.Bitmap(baseImg); stage.addChild(img); //合成する文字の位置情報などを定義 //input[type="text"]のnameをキーとし、X座標、Y座標、フォントサイズ、行揃えを持たせている。 //色などそれ以上の設定が必要な場合は配列で持たせておくと管理しやすい、と思う。 var txt = { 'txt01' : { 'x' : 300, 'y': 5, 'size': '20px', 'align': 'center' }, 'txt02' : { 'x' : 300, 'y': 35, 'size': '36px', 'align': 'center' }, 'txt03' : { 'x' : 363, 'y': 166, 'size': '20px', 'align': 'left' }, 'txt04' : { 'x' : 363, 'y': 245, 'size': '20px', 'align': 'left' } } //上記の配列より文字オブジェクトを生成し、stageにaddChildする $.each(txt,function(key,value){ //本文は入力された内容をそのまま取る var content = $('#' + key).val(); //固定文言がある場合はkeyで判別して追加したりするといいと思う if(key == 'txt01' && content){ var content = content + '100人に聞きました。'; } //必要があれば指定文字数ごとに"\n"をいれると改行されます。 //10文字で改行をいれるなら以下のように。 if(key == 'txt03' || key == 'txt04'){ var content = content.replace(/[\r|\r\n|\n]/g, "").replace(/(.{10})/g, "$1" + "\n"); } //文字オブジェクト生成 var obj = new createjs.Text(content); //文字の属性を設定する obj.textAlign = value.align; obj.font = 'bold ' + value.size + '/1.5 Meiryo,sans-serif'; //CSSのfontのショートハンドと同じ obj.x = value.x; //X座標 obj.y = value.y; //Y座標 stage.addChild(obj); }); } //保存させる処理 //ここだけはブラウザ上で完結できなかった…。 //base64をデコードしてheaderを付加してechoするだけのPHPへPOSTしています var save = function(){ var png = stage.toDataURL('image/png'); //base64エンコードした画像データ生成 if(png){ $('input[name="img"]').remove(); $('#saveform').append('<input type="hidden" name="img" value="'+png+'" />'); return true; } else { return false; } } $(function(){ //canvasオブジェクトを事前に定義しておく $(window).on('load',function(){ init(); }); //画像生成ボタンが押されたときにcanvas生成 $('#update').on('click',function(e){ //改めてnewすることでキャッシュが残って変な感じにならない…多分。 stage = new createjs.Stage('result'); genImage(); stage.update(); }); //「画像として保存」ボタンが押された時の処理 $('#saveform').on('submit',function(){ save(); }); }); })(jQuery); |
本題のcanvasの処理とは関係ないですが、base64のデータをデコードしています。
表示させるだけでいいのでしたら、得られたbase64のデータをimgのsrc属性に入れてやればdataURIを扱えるブラウザであれば表示されます。
この部分File APIというのを使えばブラウザだけで完結するのかなぁ…。
1 2 3 4 5 6 7 8 |
<?php if(isset($_POST['img'])){ //画像のダウンロード header('Content-Type: application/octet-stream'); header('Content-disposition: attachment; filename="generator.png"'); echo base64_decode(str_replace('data:image/png;base64,','',$_POST['img'])); } ?> |
GDを使ってこういう感じの画像合成処理を書いたことがありますが、処理が重いためにリアルタイムに結果を反映させるようなことができませんでした。
canvasでの画像処理は非常に高速で軽く、またサーバへの負荷を考えなくていいので大勢が使うようなサービスでも安定して使えそうです。
特定の画像の決められた位置に文字を合成するだけの処理なら、上記のように短いコードで簡単にできました。
次回何かのコラ画像がブームになる時は、爆速でコラ画像ジェネレータをリリースしたいと思いますww
当記事の内容に一部手を加え、【実写版】ハンドサインジェネレータを作成しました。ブームはもう終わりかけてますが、よろしければご利用ください_(._.)_
ADs
はじめまして、ジェネレータ系のスクリプトを探していて辿り着いたのですが、
【実写版】ハンドサインジェネレータのようにツイートをする方法を教えていただけないでしょうか…?
どうぞよろしくお願いします。
maro 様
コメントありがとうございます。
画像ジェネレータ本体はJavascriptによるものですが、Twitter認証と投稿はPHPの処理を使っています。JSだけでなくPHPの知識が必要な点にご注意ください。
ツイートする処理についてですが、以下のコードが分かりやすいかと思います。
(TwitterAPI 1時代のコードなので、1.1へ対応させるために書き換えが必要な部分があるかもしれません)
https://github.com/yusuke/twtr-api-pocket-reference/blob/master/php/oauth_authorize.php
上記のPHPをAPIキーなどを書き換えてサーバに置くと(tmhOAuth.phpのダウンロードは必要です)、Twitter認証を行った後、テキストをツイートするフォームが表示されます。
画像をツイートしたい場合はテキストだけでなく画像をツイートできるように改造すればよいです。
具体的には
$twitter->request(“POST”, $twitter->url(“1/statuses/update”), array(“status” => $_POST[“tweet”]));
となっている部分を
$twitter->request(
“POST”,
$twitter->url(“1.1/statuses/update_with_media”),
array(
“status” => $_POST[“tweet”]
“media[]” => base64_decode(str_replace(‘data:image/png;base64,’,”,$_POST[‘img’])) . “;type=image/png;filename=handsing.png”
)
);
と変更することで画像添付ツイートが実装できます。
※ $_POST[‘img’] はbase64_encodeされた画像データです。バイナリに戻して送信します。
Twitter認証を要求するサービスはスパム扱いされたり結構嫌われがちな風潮ですので、実装が難しいようでしたら見送ってもいいかもしれませんね。
こんにちは、早速のお返事有り難うございます。
スクリプトなどの情報有り難うございます。一旦頂いたものでテストしてみたいと思います。
確かにジェネレーター系でTwitter認証だとスパム扱いはありそうですね…このようなジェネレータで作成した画像をTwitter認証をせずに投稿する方法などはご存知でしょうか…?
質問を重ねて申し訳ないですが、どうぞよろしくお願いします。
maro 様
認証なしでツイートするのでしたら、生成した画像を自分のサーバに保存し、画像URLをツイートするという方法が考えられます。
1.画像を生成する
2.自分のサーバに保存する
3.上記保存した画像のURLを取得
4.URLを本文としてツイートダイアログを開く
※ https://twitter.com/intent/tweet?text=本文 というURLを別窓で開くと、ツイートするフォームが表示されます。
という流れでしょうか。画像掲示板のようなイメージで、ダイレクトにツイートするよりも一般的な方法ではないかと思います。
ただ、生成される画像を自分の管理下に置くのは、脅迫や殺人予告などが投稿された際にちょっと面倒なことになるかもしれません。利用者も画像が保存されると聞くとあまりいい気分はしないでしょう。
自分のサーバに保存するのを避けるのであれば
1.Twitterの捨てアカウントをつくる
2.画像生成時に捨てアカウントにハンドサインジェネレータのような画像付きツイートを行う
3.画像がTwitter上に保存されるので、そのURLを取得
4.URLを本文としてツイートダイアログを開く
という方法も考えられます。この方法は自分の知らないアカウントにツイートされるということになりますので、それはそれでちょっと気持ち悪いですね。
※以下WordPress上での事例ということですが、やりたいことは同じですので参考にしてみてください。
http://keisuke.tsukayoshi.com/blog/1642
どの方法を取っても一長一短なので、それならば(スパムが流行しなければ)正攻法である「認証させる→ツイートする」という方法が一番いいのではないかと思います。
お返事有り難うございます。大変参考になりました!
頂いた情報を元にして、色々とトライしてみようと思います。
本当にありがとうございます!
はじめまして。
画像ジェネレーターを作成したく、探しておりましたら辿り着きました。
「これだ!」と思い、さっそくソースコードを参考にさせて頂きましたが、現在は使用できないのでしょうか?
当方、お名前.comのレンタルサーバーを使用しており、index.htmlとimg.phpファイルを作成し、それぞれにソースコードをコピーさせて頂きましたが、「画像生成」が反応していただけません…。
また、「画像として保存」は動作してくれるものの保存されたデータ大きすぎるまたは破損しており開けませんでした。
ご迷惑でなければ、ご指摘等頂けましたら幸いです。
よろしくお願い致します。
koko様
コメントありがとうございます。
画像生成まではJavascriptでの動作ですので、サーバによって動く・動かないということはありません。
コピペミスでエラーが出ているとか、設置したサイトがhttpsとか(上述のサンプルコードではEaselJSとjQueryをhttpで呼んでいるので)とか…。
私の環境では動いている「100人に聞きましたジェネレータ」の必要データ一式を以下に用意しました。こちらを解凍してそのまま設置したらどうでしょうか?
https://wood-roots.com/sample/generator/gen.zip
管理人様
早速ご返信頂きました事、感謝申し上げます。
普段、phpを触る機会が少なくどうやら保存の際の文字コード?も間違っていたようです…(お恥ずかしい限りです)
頂戴したzipファイルをそのままアップロードさせて頂いたところ快適に動作してくれました。
このような初心者にもご丁寧に対応頂き、重ね重ねお礼申し上げます。
管理人様の記事を読んで勉強に励もうと思います!
ありがとうございました!今後ともよろしくお願い致します。
今このコードを元にジェネレーターを作ろうとしているのですが、文字色に変更と背景色の変更はどのように行うのでしょうか?
cssと同じだと思って以下のように書いてしまいましたが全く動きません。調べても分からないので教えてください。お願いします
‘txt02’ : {
‘x’ : 700,
‘y’: 140,
‘size’: ’60px’,
‘align’: ‘center’
‘color’: ‘#fff’,
‘background-color’: ‘black’,
},