アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

imageantialiasを使用せず画像の拡大・縮小でアンチエイリアス処理を行う

こんばんは。松田です。
最近はGDで画像処理を書いているので、今回はGDに関する小ネタです。
imageantialiasを使用せず、画像の拡大・縮小を利用してアンチエリアス処理を行ってみます。

GDで作成した画像にアンチエイリアス処理をかけて滑らかにする場合、通常はimageantialias()関数を使用します。
ですが、この関数には欠点があります。
GDで線を描画する際にimagesetthickness()で線の太さを変更しても、imageantialias()をかけると1ピクセルの線に書き換えられてしまう、という問題です。

これを回避するためにいろいろな処理を試した結果、数倍に拡大して描画した画像を元の大きさに縮小して表示する、という方法にたどり着きました。
スーパーサンプリング処理という名前が付いているらしいです。
この方法を使用すれば、線の太さを保ったまま線を滑らかにすることができます。

下が検証に使用したコードです。



<?php

/*
* 円と線を描画したimage resourceを返す関数。
* 通常は400*400の画像を作成する
* 引数を指定すると、その倍率分だけ描画する範囲を広げる
*
* draw(3)の場合、400*3=1200ピクセルの画像を描画した後、縮小処理を行う
*/
function draw($bai = 1) {
	
  // 通常は400px * 400px の画像を描画
  $width = 400 * $bai;
  $height = 400 * $bai;
  $im = ImageCreateTrueColor($width, $height);

  $white = ImageColorAllocate($im, 255, 255, 255);
  $black = ImageColorAllocate($im, 0, 0, 0);
  $blue  = ImageColorAllocate($im, 0, 0, 255);

  // 背景を真っ白に
  imagefilltoborder($im, 0, 0, $white, $white);

  // 線の太さを5に設定
  imagesetthickness($im, 5*$bai);

  // 楕円描画
  imagefilledellipse($im, $width/2, $height/2, 200*$bai, 250*$bai, $blue);

  // 線を描画
  imageline($im, 10*$bai, 10*$bai, 300*$bai, 400*$bai, $black);

  if ($bai > 1) {
    // 倍率が指定されていたら、400*400に縮小する
    $dst = imagecreatetruecolor(400, 400);
    imagecopyresampled($dst, $im, 0, 0, 0, 0, 400, 400, 400*$bai, 400*$bai);
    imagedestroy($im);
    return $dst;
  }

  return $im;
}


// 5倍まで作成してみる
$max = 5;

// このimageに作成したすべての画像をのっけて表示
$im = ImageCreateTrueColor(400, 400 * $max);
for ($i = 1; $i <= $max; $i++) {
  
  // image作成
  $src = draw($i);
  
  imagecopy($im, $src, 0, 400 * ($i - 1), 0, 0, 400, 400);
}

header("Content-type: image/png");
imagepng($im);
imagedestroy($im);
exit;

?>


draw()は、線と円を描画するだけの関数ですが、引数を渡すことによって拡大時の画像の大きさを決定しています。
何も渡さなければ400*400の画像を作成しリサイズも行ないません。
draw(3)と指定した場合、1200*1200のキャンバスに拡大した線と円を描画し、その後400*400まで縮小します。

これを試した結果が下の画像です。

上から順に、1倍(未処理)、2倍、…、5倍、の結果となっています。
画像の利サイズ用に、imagecopyresizedとimagecopyresampledという2つの関数が用意されていますが、imagecopyresizedでは画像がガックガクになってしまうため、imagecopyresampledを使います。

画像を見てわかるとおり、下に行くほど線が滑らかになっています。
線の太さもほぼ変わっていません。

ただ、元画像が数千ピクセルにもなってしまうと、画像の作成に体感できる程度の時間がかかってしまいます。
3倍以降からはほぼ見た目が変わっていないため、実際に使用する際は、作成コストを考えながらちょうどいい倍率を探していくのがいいかもしれません。

GDとImageMagickの画質比較

こんばんは、牧野です。
以前、GDでの画像処理を紹介しました。
今日はPHPでよく使われるもう1つの画像処理方法、ImageMagickを使うやり方で画質にどれくらい差があるのか比べてみました。

まずは早速、テスト用プログラムです。

gd_test.php


<?php
$image_file = 'sample.jpg';

$img = new MyImage($image_file);
$img->resizeImage(500, 500);
$img->createImageFile('.', 'gd_sample.jpg');

header('Content-type: image/jpeg');
readfile('gd_sample.jpg');

class MyImage {
    var $img;
    var $width;
    var $height;
    var $font_path;

    function MyImage($image_path, $font_file_path = null) {
        $this->img = imagecreatefromjpeg($image_path);
        $this->width = imagesx($this->img);
        $this->height = imagesy($this->img);
    }

    function resizeImage($max_w, $max_h) {
        if (floatval($max_w / $this->width - 1) <= floatval($max_h / $this->height - 1)) {
            $rate = floatval($max_w / $this->width);
            $new_w = $max_w;
            $new_h = (int)min(intval($this->height * $rate), $max_h);
        } else {
            $rate = floatval($max_h / $this->height);
            $new_w = (int)min(intval($this->width * $rate), $max_w);
            $new_h = $max_h;
        }
        $new_img = imagecreatetruecolor($new_w, $new_h);

        if (imagecopyresampled($new_img, $this->img, 0, 0, 0, 0, $new_w, $new_h, $this->width, $this->height)) {
            $this->img = $new_img;
            return true;

        } else {
            return false;
        }
    }

    function createImageFile($new_file_dir, $new_file_name) {
        $new_file_path = $new_file_dir .'/'. $new_file_name;
        $result = imagejpeg($this->img, $new_file_path, 100);
        chmod($new_file_path, 0666);
        return $result;
    }
}


imagick_test.php


<?php
$image_file = 'sample.jpg';

$img = new MyImage($image_file);

header('Content-type: image/jpeg');
echo $img->createResizedImage(500, 500);

class MyImage {
    var $img_path;
    var $width;
    var $height;
    var $font_file_path;

    function MyImage($image_path) {
        $this->img_path = $image_path;
        $image_info = getimagesize($this->img_path);
        $this->width = $image_info[0];
        $this->height = $image_info[1];
    }

    function createResizedImage($max_w, $max_h, $new_file_dir = null, $new_file_name = null) {
        if ($new_file_name) {
            $new_file_path = $new_file_dir .'/'. $new_file_name;
            $cmd = "convert ". $this->img_path ." -resize {$max_w}x{$max_h} {$new_file_path} ";
            system($cmd);
        } else {
            $cmd = "convert ". $this->img_path ." -resize {$max_w}x{$max_h} -";
            return shell_exec($cmd);
        }
    }

}


GDの場合、以前笹亀さんが書いていたように、サムネイル画像サイズを自力で計算する必要があります。
ImageMagickpeclエクステンションもありますが、サーバにインストールされているImageMagickPHPのバージョンの制限がわりと厳しいので、コマンドラインから使う方が手軽だと思います。

今回比べたかったのは画質なので、それ以外のことはとりあえず無視します。
(プログラムの書き方がいい加減というつっこみは今回はできればなしの方向で。。。)
画像をアップロードして、それを適当な大きさの表示用画像とサムネイル画像にサイズ変更して保存する、という機能は、ウェブアプリケーションでは比較的よくある機能だと思います。その時にどれくらい差が出るものなのかを調べるのが今回の目的です。
元画像のsample.jpgは、615×410で、今回のテストでは少しだけ小さくしています。

結果は、、

GDで変換した画像



ImageMagickで変換した画像


元画像はこちら

ブログの写真では変わらないように見えるかもしれませんが、ImageMagickを使ったほうがピントが合っているような感じで少し綺麗でした。
ということで、ImageMagickの方が画質的にはいいということがわかりました。

GD、ImageMagickともに様々な関数、オプションが用意されています。
GDでもこの関数をこんなふうにするともっと綺麗になる、等、何かご存知の方がいましたら、ぜひお知らせ下さい。

PHPで簡単に3D画像作成!

最近、特に何もしてないのにやたら日焼けしているらしい中川です。

PHPで3D画像を簡単に作成することができるライブラリ
PEAR::Image_3D」を紹介します。
3D画像をつくるとなるといろいろと面倒だったりするものですが、
このライブラリを使えば比較的簡単に3D画像を作成することができます。

現在、「PEAR::Image_3D」はver0.4.0のalpha版で提供されています。
マニュアルがなかったり、動作に不安がありますが、
サンプルファイルがたくさんあるので、よく動作確認してから利用してください。

インストールはpearコマンドで行えます。
PHPはGDを使えるようにしておいてください。)



# pear install Image_3D-alpha


それでは早速、サンプルをちょっと編集したもので動作を確認してみましょう。



<?php
set_time_limit(0);
require_once('Image/3D.php');

$world = new Image_3D();
$world->setColor(new Image_3D_Color(255, 255, 255));

$light = $world->createLight('Light', array(-400, -50, -100));
$light->setColor(new Image_3D_Color(255, 255, 255));

$text = $world->createObject('text', 'PHPpro-TIPS');
$text->setColor(new Image_3D_Color(0, 200, 255));
$text->transform($world->createMatrix('Rotation', array(0, 40, 0)));
$text->transform($world->createMatrix('Move', array(-30, 0, 0)));
$text->transform($world->createMatrix('Scale', array(3, 3, 3)));

$world->setOption(Image_3D::IMAGE_3D_OPTION_BF_CULLING, false);
$world->setOption(Image_3D::IMAGE_3D_OPTION_FILLED, true);

$world->createRenderer('perspectively');
$world->createDriver('GD');

$filename = "phppro.png";
$world->render(300, 50, $filename);

header("Content-Type: image/png");
readfile($filename);
exit;
?>




このように、簡単に3D画像を作ることができます。
他にも、サンプルには次のような画像を作成するスクリプトがあります。



まだマニュアルはそろっていないみたいようなので、
サンプルコードを見たり、実際のソースコードを確認しながら使ってみて下さい。
PHPで3D画像が作成できるということで、中々、便利なライブラリではないでしょうか。