@blog.justoneplanet.info

日々勉強

GDとImageMagickの速度を比較してみた

■GD

以下のようなコードを用いてGDで合成画像を1000枚生成した時の時間を調べた。

$layers = array(
    0 => 'dress_back.png',
    1 => 'dress_back.png',
    2 => 'body.png',
    3 => 'dress.png',
    4 => 'bag.png',
    5 => 'bag.png',
    6 => 'face.png',
    7 => 'hear.png',
    8 => 'teara.png',
);
$start = microtime(true);
for($i = 0; $i < 10; $i++){
    $image = imagecreatefrompng("background.png");
    foreach($layers as $key => $value){
        $layer = imagecreatefrompng($value);
        imagecopy($image, $layer, 0, 0, 0, 0, 410, 454);
    }
    imagegif($image, "image{$i}.gif");
}
$end = microtime(true);
print($end - $start);

/*
 * windows
 * 10 => 0.27269101142883
 * 100 => 2.1620790958405
 * 1000 => 24.812913894653
 * 
 * linux
 * 10 => 0.21701502799988
 * 100 => 2.1362149715424
 * 1000 => 21.695859193802
 */

■ImageMagic

以下のようなコードを用いてImageMagickで合成画像を1000枚生成した時の時間を調べた。

$layers = array(
    0 => 'dress_back.png',
    1 => 'dress_back.png',
    2 => 'body.png',
    3 => 'dress.png',
    4 => 'bag.png',
    5 => 'bag.png',
    6 => 'face.png',
    7 => 'hear.png',
    8 => 'teara.png',
);
set_time_limit(0);
//$path = 'C:\xampp\htdocs\local.sample.org\public_html\\';
$path = '/home/local.sample.org/trunk/public_html/imagick/';
$start = microtime(true);
for($i = 0; $i < 1000; $i++){
    $image = new Imagick("{$path}background.png");
    foreach($layers as $key => $value){
        $layer = new Imagick($path . $value);
        $image->compositeImage($layer, $layer->getImageCompose(), 0, 0);
    }
    $image->writeImage("{$path}image{$i}.gif");
}
$end = microtime(true);
print($end - $start);

/*
 * windows
 * 10 => 2.2297260761261
 * 100 => 24.065160989761
 * 1000 => 247.36853098869
 * 
 * linux
 * 10 => 0.33637809753418
 * 100 => 3.3278291225433
 * 1000 => 33.274304866791
 */

■結果

Linuxの場合は1.5倍ImageMagickが遅かった。Windowsの場合は10倍ImageMagickが遅かった。

CentOSにImageMagickをインストールしてPHPから使う

以下のコマンドでインストールする。

yum install ImageMagick
yum install ImageMagick-devel
pecl install imagick
cp /etc/php.d/curl.ini /etc/php.d/imagick.ini
vi /etc/php.d/imagick.ini

コピーしたファイルを以下のように記述する。

; Enable imagick extension module
extension=imagick.so

apacheをreloadする。

/etc/init.d/httpd reload

PHP5.3の名前空間を使ってみる

そういえば今まであんまり使わなかったけど、PHP5.3の名前空間を使ってみる。

namespace Lib\Mobile;

class Emoji{
    public function getEmoji(){
        return '絵文字一覧です';
    }
}

上述のように定義した場合は、以下のように使用することができる。

require_once 'Emoji.php';

$emoji = new Lib\Mobile\Emoji();
var_dump($emoji->getEmoji());// 絵文字一覧です

また、以下のようにuseを使用してインポートを先頭で明示することもできる。

require_once 'Emoji.php';
use Lib\Mobile as MobileLib;

$emoji = new MobileLib\Emoji();
var_dump($emoji->getEmoji());// 絵文字一覧です

asを使用しなかった場合は以下のように最後の単語がasの後にあるようなイメージだ。

require_once 'Emoji.php';
use Lib\Mobile;

$emoji = new Mobile\Emoji();
var_dump($emoji->getEmoji());// 絵文字一覧です

なんとなーく現時点では使いそうもないなーφ(-ω-。`)。

PHP5.3の遅延静的束縛を使ってみる

そういえば今まであんまり使わなかったけど、遅延静的束縛というものを使ってみる。

class Animal{
    public function cry(){
        print(self::_getVoice());
    }
    protected static function _getVoice(){
        return '(「・ω・)「がおー';
    }
}
class Dog extends Animal{
    protected static function _getVoice(){
        return 'bow!';
    }
}
$pochi = new Dog();
$pochi->cry();// (「・ω・)「がおー

マニュアルを参照すると以下のような記述がされている。

静的遅延束縛は直近の “非転送コール”(self:: や parent::、static:: による静的なコール、 あるいはクラス階層の中での forward_static_call() によるコール) のクラス名を保存します。 静的メソッドの場合、これは明示的に指定されたクラス (通常は :: 演算子の左側に書かれたもの) となります。静的メソッド以外の場合は、そのオブジェクトのクラスとなります。 get_called_class() 関数を使うとコール元のクラス名を文字列で取得できます。 static:: はこのクラスのスコープとなります。

selfでは直近のクラスが参照されるので、上述の例の場合はselfはAnimalクラスということになる。pochiにもっと犬らしくして欲しい時は以下のようにstaticを用いて記述する。

<?php
class Animal{
    public function cry(){
        print(static::_getVoice());
    }
    protected static function _getVoice(){
        return '(「・ω・)「がおー';
    }
}
class Dog extends Animal{
    protected static function _getVoice(){
        return 'bow!';
    }
}
$pochi = new Dog();
$pochi->cry();// bow!

親クラスから子クラスのメソッドが呼び出される感じなのでアクセス権はprotected以上でないと「Fatal error: Call to private method」となる。

Pythonでは以下のように問題なく、selfを使用することができる。

class Animal:
    def cry(self):
        print(self._getVoice())
    def _getVoice(self):
        return 'gao!'

class Dog(Animal):
    def _getVoice(self):
        return 'bow!'

pochi = Dog()
pochi.cry()# bow!

Javaの場合はそもそもselfがない。クラス名を直接指定する必要があり、明示しない時はカレントクラスのメソッドがコールされる。

static class Animal{
    public static String cry(){
        return getVoice();// 明示しない場合はAnimal.となる
    }
    protected static String getVoice(){
        return "(「・ω・)「がおー";
    }
}
static class Dog extends Animal{
    protected static String getVoice(){
        return "bow!";
    }
}
Dog pochi = new Dog();
Log.e("cry", pochi.cry());// (「・ω・)「がおー

CentOSにJDKをインストールする

■jdk

以下のコマンドでJDKをインストールする。

ダウンロードしたらアップロード

chmod 0777 jdk-6u12-linux-i586-rpm.bin
./jdk-6u12-linux-i586-rpm.bin

■JAVA_HOME

以下のようにしてJAVA_HOMEを設定する。

vi /etc/profile

以下の行を最終行に付加する。

export JAVA_HOME=/usr/java/default
export PATH=$PATH:$JAVA_HOME/bin
export CLASSPATH=.:$JAVA_HOME/jre/lib:$JAVA_HOME/lib:$JAVA_HOME/lib/tools.jar

編集が終わったら以下のコマンドを実行する。

source /etc/profile

【参考】

http://centossrv.com/tomcat6.shtml

Tokyo Tyrantを使ってみる

仕事で使うかもしれないので一応やってみる。

■インストール

wget http://fallabs.com/tokyocabinet/tokyocabinet-1.4.46.tar.gz
wget http://fallabs.com/tokyotyrant/tokyotyrant-1.1.41.tar.gz
tar xvzf tokyocabinet-1.4.46.tar.gz
tar xvzf tokyotyrant-1.1.41.tar.gz
cd tokyocabinet-1.4.46
./configure
make
make install
cd ../tokyotyrant-1.1.41
./configure

エラー1

tokyo cabinetが先にインストールされていないと以下のエラーがでる。

checking for tcutil.h... no
configure: error: tcutil.h is required
make
make install

ちょっと動かしてみる。

ttserver

■PHPから使う

pecl install tokyo_tyrant-beta
cp /etc/php.d/curl.ini /etc/php.d/tt.ini

元の記述を削除して、以下の記述に書き換える。

extension=tokyo_tyrant.so

■ベンチマーク

以下のコードを使用して簡単にベンチマークしてみた。

$start = microtime(true);
$tt    = new TokyoTyrant("localhost");
for($i = 0; $i < 10000; $i++){
    $tt->put("k{$i}", "abcdefghijglmnopqrstuvwxyz");
}
$end = microtime(true);
print($end - $start);//0.65114498138428

ベンチマークをしておいて言うのもオカシイが、データストアにおいて全く同じ条件というものは再現できないので単純に比較してはならない。用途に応じた選択が必要である。

androidの戻るボタンの動作を変える

備忘録。

    /**
     * キーイベントが発火した時
     */
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {// 戻るボタン
            if (event.getAction() == KeyEvent.ACTION_DOWN) {// 押された時
                webView.goBack();// WebViewを戻す
            }
            return true;
        }
        return super.dispatchKeyEvent(event);
    }

特にWebViewを使ってる時などは必要になると思う。

Gitでバージョン管理をする

■サーバ側

グループの作成とユーザの追加

/usr/sbin/groupadd sample.project.justoneplanet.info
gpasswd -a ishimoto sample.project.justoneplanet.info

プロジェクトディレクトリの作成

mkdir sample.project.justoneplanet.info
cd sample.project.justoneplanet.info

リポジトリの作成

git --bare init
vi description

リポジトリの概要でも書いておく。書かなかった場合は以下のエラーが出る。

*** Project description file hasn't been set
error: hooks/update exited with error code 1
error: hook declined to update refs/heads/master

権限設定

SSHでpushしたりするために以下の操作を行う。

chmod -R 0775 /usr/local/development/repos/sample.project.justoneplanet.info
chmod -R g+s /usr/local/development/repos/sample.project.justoneplanet.info
chgrp -R sample.project.justoneplanet.info /usr/local/development/repos/sample.project.justoneplanet.info

正しく設定できていない場合、push時に以下のエラーが出る。

error: failed to push some refs to 'ssh://ishimoto@123.123.123.123:1234/usr/local/development/repos/sample.project.justoneplanet.info'

■クライアント側

リポジトリの準備

mkdir sample.project.justoneplanet.info
cd sample.project.justoneplanet.info
git init

ファイルの追加とコミット

git add .
git commit -a -m "first commit"

リモートリポジトリの追加とpush

git remote add origin ssh://ishimoto@123.123.123.123:1234/usr/local/development/repos/sample.project.justoneplanet.info
git push origin master
リモートリポジトリの設定を間違えた場合
git remote set-url origin ssh://ishimoto@123.123.123.123:1234/usr/local/development/repos/sample.project.justoneplanet.info

複素数を表現する

不変性を保証するためにはサブクラスを作らせない必要があり以下のようにfinalクラスとした。

public final class Complex {
    private final double re;
    private final double im;
    public Complex(double re, double im) {
        this.re = re;
        this.im = im;
    }
    public double realPart() {
        return this.re;
    }
    public double imaginaryPart() {
        return this.im;
    }
    public Complex add(Complex c) {
        return new Complex(this.re + c.re, this.im + c.im);
    }
    public Complex subsract(Complex c) {
        return new Complex(this.re - c.re, this.im - c.im);
    }
    public Complex multiply(Complex c) {
        return new Complex(this.re * c.re - this.im * c.im, this.re * c.im + this.im * c.re);
    }
    public Complex divide(Complex c) {
        return new Complex(
            (this.re * c.re + this.im * c.im) / (c.re * c.re + c.im * c.im),
            (this.im * c.re - this.re * c.im) / (c.re * c.re + c.im * c.im)
        );
    }
    @Override
    public boolean equals(Object o) {
        if(o == this) {
            return true;
        }
        if(!(o instanceof Complex)) {
            return false;
        }
        Complex c = (Complex) o;
        return Double.compare(this.re, c.re) == 0 && Double.compare(this.im, c.im) == 0;
    }
    @Override
    public int hashCode() {
        int result = 17 + hashDouble(this.re);
        result = 31 * result + hashDouble(this.im);
        return result;
    }
    private static int hashDouble(double value) {
        long longBits = Double.doubleToLongBits(value);
        return (int) (longBits ^ (longBits >>> 32));
    }
    @Override
    public String toString() {
        return "(" + this.re + " + " + this.im + "i" + ")";
    }
}

また以下のようにstaticファクトリーメソッドを用いる事でも可能である。

public class Complex {
    private final double re;
    private final double im;
    private Complex(double re, double im) {
        this.re = re;
        this.im = im;
    }
    public static Complex valueOf(double re, double im) {
        return Complex(re, im);
    }
}

publicやprotectedのコンストラクタを持たないクラスを他のパッケージから拡張することはできない。