2014年5月22日木曜日

PHPのバックトレースを程よい文字列で取得

バックトレースを文字列で欲しい場合。
・debug_print_backtrace()では出力してしまうのでoutput bufferなどでの補足が必要で微妙。
・debug_backtrace(); は配列なので冗長。。もっとコンパクトにまとまってて欲しい。

と思ってたんだけど、PHPマニュアルのコメント欄でいいものを見つけた。
$e = new Exception();
print_r(str_replace('/path/to/code/', '', $e->getTraceAsString()));
from http://www.php.net/manual/ja/function.debug-print-backtrace.php#92542

これくらいの出力がちょうどいい。

2014年5月1日木曜日

PHP, ImagickでNeon系装飾で文字を入れる

Neonというか覆い焼き
例:

$TEXT      = "example example!";
$FONT_SIZE = 32;
$FWCOLOR   = "#FFFFFF";
$BGCOLOR   = "#FF0000";

// 貼り付け先の画像
$im = new Imagick();
$im->readImageBlob(file_get_contents('/path/to/baseimagefile'));

// 文字入れ作業用の画像
$tmp = new Imagick();
$tmp->newImage($im->getImageWidth(), $im->getImageHeight(), "transparent", "png");
$tmp2 = clone $tmp;

// 文字入れ用の設定
$draw = new ImagickDraw();
//$draw->setFont('/path/to/font/file');
$draw->setFontSize($FONT_SIZE);
$draw->setGravity(Imagick::GRAVITY_CENTER);

// 文字:ぼかし下地
$draw->setFillColor($BGCOLOR);
$tmp->annotateImage($draw, 0, 0, 0, $TEXT);
$tmp->blurImage($FONT_SIZE / 8, $FONT_SIZE / 10, Imagick::CHANNEL_ALL);
// 文字:全面に来る文字部分
$draw->setFillColor($FWCOLOR);
$tmp->annotateImage($draw, 0, 0, 0, $TEXT);
// 文字:ぼかし調整
$draw->setFillColor($BGCOLOR);
$tmp2->annotateImage($draw, 0, 0, 0, $TEXT);
$tmp2->blurImage(5, 3, Imagick::CHANNEL_ALL);
$tmp->compositeImage($tmp2, Imagick::COMPOSITE_COLORDODGE, 0, 0);

// 最終画像結合
$im->compositeImage($tmp, Imagick::COMPOSITE_COLORDODGE, 0, 0);

// 出力
//$output = $im->getImagesBlob();
//header('Content-Type: ' . $im->getimagemimetype());
//echo $output;


ポイントは
・Imagick::blurImage()で適度にぼかす
・Imagick::compositeImage()でImagick::COMPOSITE_COLORDODGE(覆い焼き)をする

単に一度だけの合成だとネオン効果が弱い気がするのでぼかし下地で強化。

2014年4月30日水曜日

UIWebViewへアプリ作成画像(UIImage)を入れ込む

AssetLibraryを使わず、画像などをData URI Schemeでhtmlに直接埋め込む。


- (void)changeImage:(UIImage*)image webview:(UIWebView*)webview imageDomId:(NSString*)domId {
  NSData *imageData = UIImageJPEGRepresentation(image, 0.8f);

  // iOS7以上、6以下は何かライブラリ使う
  NSString *imageBase64 = [imageData base64EncodedStringWithOptions:0];

  // encodedに改行が含まれてるとuiwebviewでエラーになるため、取り除く
  // 上記encodeメソッドで改行が含まれないのであれば不要
  imageBase64 = [imageBase64 stringByReplacingOccurrencesOfString:@"\r" withString:@""];
  imageBase64 = [imageBase64 stringByReplacingOccurrencesOfString:@"\n" withString:@""];

  [webview stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"$('%@').attr('src', 'data:image/jpeg;base64,%@');", domId, imageBase64];
}


jsの変数に入れて使ったりも出来る。その場合は"data:image/[format];base64,[content]"をさらにJSONエンコードしとかないと動かないかも。

2014年3月25日火曜日

2014年、PHPフレームワーク雑感(CakePHP, FuelPHP, Yii, ZendFramework)

まとめると、中規模開発以上はYii、ミニサービスやスモールスタートならCakePHPが良いかなと思う。

CakePHPが良いのはやはり学習コストが低い点。お膳立てが多いので欲しいなと思ったものはだいたいある。まだ安定版出てないけどこれからは3.xでいいと思う。

CakePHP(2.x)

公式ドキュメントを参照するだけでほとんど迷うこと無く開発を進めることが出来る。導入のしやすさはピカイチ。ただし細かいことしようとするとブラックボックスな配列の取り回しに苦労する。とにかく配列が深い、引数が多い、謎、ストレス。
個人的に気になったところは、
・autoload:ディレクトリパス指定とかで自動で読み込んで欲しい。
・ORM:2.xでは推奨されておらず謎のストレスフルな配列結果セットを使うことになる。3.xでは改善されそう。
・マジックメソッド多用:コード補完が効かなくてつらい。

FuelPHP(1.x)

CakePHPに比べてお膳立てが少ないので自分であれこれ付け加える必要がある。ディレクトリ構成がモヤッとする。fuel/app/classesとか。導入はCakePHPについで楽だしFuelとかoilとかforgeとかなんかかっこいいけど、CakePHPを超えるメリットはあらかじめ環境切り分け(Production, Develop / DB master, slave)が考慮されているところくらいしか思いつかなかった。ORMのテーブル情報をキャッシュしてくれないところも微妙な点。

Yii(1.1.x)

日本では人気無いけど英語圏では人気のFWなので情報が豊富。ディレクトリ構成がわかりやすくて、Viewのコンポーネントも充実してる。CakeやFuelよりは導入コストがかかるが、Zendよりは導入しやすい。

Zend(2.x)

1.xから大きく変わり、色々煩雑になってしまった印象。全体的にお固くて設定の配列が冗長、ディレクトリ構造もわかりづらい。FW自体開発者の利便性よりもオブジェクト指向優先でクラスは細かく細分化されている。学習コストは高いが、その分一度慣れると収まるものが収まるところに収まってるので使いやすく感じる。Zend_Formはとても良い。

まとめ2

ORMは信用しない方が良い。単純な取得や単体での保存では使うが、複雑な条件での取得・トランザクションはモデル内のメソッドとして自前で実装したほうが良い。特にリレーション設定(hasOne, hasMany等)は使わない。
SELECTもController側でmodel->select()->where()みたいなことせずに、それぞれ該当モデルにてメソッド化する方が後から見た時にわかりやすい。

各FWともPSRとか出てきてここ2年くらいで刷新したバージョンを出してる(出そうとしてる)けど、その中だとやはりCakePHP-3.xとYii-2.x系が良さそうだなと思う。
他のフレームワークで注視しとくのはLaravelくらいか。

2013年10月16日水曜日

iosでのappstoreの国設定切り替え

ios7対応、2013.10.15現在

・設定アプリ>一般>言語環境から、言語と書式(国)を切り替える
・設定アプリ>iTunes Store/App Storeからその国に設定しているAppleIDでSign in
※初回はレビューしてクレカ情報とか入力してください言われるけど、alertのレビューをおした後に表示される画面でAppStore国を設定して「次へ」で次画面へ行ったあとに
キャンセルすればOK

2013年9月12日木曜日

cocos2d-xでCocosDenshion::SimpleAudioEngineのplayEffect()がresume時(background to foreground)に鳴らない問題対応

BGMは問題ないのだが、効果音(playEffect)が一度backgroundに移行後、再度foregroundに移行した時に鳴らない場合がある。
target os: iOS6.1
audio format: .caf
cocos2dx ver.: 2.1rc0-x-2.1.4

SimpleAudioEngine::playEffectを追ってみたら[CocosDenshion playSound:sourceGroupId:pitch:pan:gain:loop:]でも特にエラーが起きておらず、正常にOpenALのalSourcePlay()が呼び出されているようだ。loadも問題ないし原因不明。

ググったら公式フォーラムでちらほら報告があるだけ。
Sound FX not playing after a while.
http://www.cocos2d-x.org/boards/6/topics/3153
http://www.cocos2d-x.org/issues/2512

とりあえずの対処としてBackgroundに移行する時にend()して、Foregroundにresumeする時にアプリ起動時にpreloadすることで音を鳴らす事ができる(ただしpause~resumeではないので、途中から鳴らす事はできない。)
bool AppDelegate::applicationDidFinishLaunching()
{
    // some code ...

    CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadEffect("press_button.caf");
}
void AppDelegate::applicationDidEnterBackground()
{
    CCDirector::sharedDirector()->pause();
    CCDirector::sharedDirector()->stopAnimation();

    // end
    SimpleAudioEngine::sharedEngine()->end();
}

// this function will be called when the app is active again
void AppDelegate::applicationWillEnterForeground()
{
    CCDirector::sharedDirector()->resume();
    CCDirector::sharedDirector()->startAnimation();

    // preloadEffect
    CocosDenshion::SimpleAudioEngine::sharedEngine()->preloadEffect("press_button.caf");
}

ゲーム系で音が鳴らなくなるって結構致命的な気がするんだけど、v2.1.4stableとか、v3.xでは直ってるのかな。不明。

2013年9月2日月曜日

Google Analytics iOS SDK v2.0beta から v3.0への移行、変更点

Automatic Screen Measurement - 自動的な画面計測

// v2 -------
// SomeViewController.h
#import "GAITrackedViewController.h"
@interface SomeViewController : GAITrackedViewController
@end

// SomeViewController.m
- (void)viewDidAppear:(BOOL)animated {
  [super viewDidAppear:animated];
  self.trackedViewName = @"Some Screen";
}

// v3 -------
// change "self.trackedViewName" to "self.screenName"


Manual Screen Measurement - 手動での画面計測

// v2 -------
[[[GAI sharedInstance] defaultTracker] sendView:view]; // or trackView:view

// v3 -------
#import "GAIFields.h"
#import "GAIDictionaryBuilder.h"
[[[GAI sharedInstance] defaultTracker] set:kGAIScreenName value:view];
[[[GAI sharedInstance] defaultTracker] send:[[GAIDictionaryBuilder createAppView] build]];


Event Tracking - イベントのトラッキング

// v2 -------
[[[GAI sharedInstance] defaultTracker] sendEventWithCategory:category withAction:action withLabel:label withValue:value];

// v3 -------
#import "GAIDictionaryBuilder.h"
[[[GAI sharedInstance] defaultTracker] send:[[GAIDictionaryBuilder createEventWithCategory:category action:action label:label value:value] build]];

初期化時は[GAI sharedInstance].debugがなくなったくらい。