Please feel free to link to this page.
TOP PDF ver.
Powered by SmartDoc

Imagemagickの使い方

初版 2002/09/24 最終更新 2003/06/30
Shohei NOBUHARA
Imagemagickが便利そうなことは想像がつくものの,実際の使い方,それもマニュアル以上のことを解説した文章に巡り会うことは少ない・・・ので,自分の知っていること(つまり使ったことのある機能)をメモしておく.

目次

1 はじめに

1.1 ImageMagickの入手

www.imagemagick.orgからソースを入手できる.

debianなら

図 1 ImageMagickのインストール
# apt-get -f install imagemagick

とすれば勝手にダウンロードしてインストールしてくれる.

なお現時点のバージョンは5.4.8.2であった.

ちなみにwindowsバイナリも上記サイトからダウンロードできる.詳しくは後述.

1.2 標準画像の入手

標準画像として有名なLena(lena_std.tif)をwww.lena.orgからダウンロードして使うことにする.

べつに他の画像でも全然問題ない.

2 convert

2.1 epsの圧縮

拡張子をeps2, eps3にすると,それぞれlevel2, level3のpostscriptになる.level2, level3だと画像の圧縮ができるので,ラスタ画像をepsに変換したときなどに結構意味を持つ.

図 2 epsの圧縮
$ convert lena_std.tif lena_std.eps
$ convert lena_std.tif lena_std.eps2
$ convert lena_std.tif lena_std.eps3
$ convert -compress ZIP lena_std.tif lena_std.zip.eps2
$ convert -compress ZIP lena_std.tif lena_std.zip.eps3

大きさを比較すると,表2.1.1[圧縮されたepsの大きさ]のようになる.

表 1 圧縮されたepsの大きさ
オリジナルTIFF 776KB
eps2(オプション無し) 984KB
eps3(オプション無し) 1304KB
eps2(オプション-compress ZIP) 784KB
eps3(オプション-compress ZIP) 784KB

となった.(1)

  1. ImageMagickでは出力ファイル名の拡張子から出力形式を判断している.そのためこの例では.eps2としたが,eps2:lena_std.epsのように,先頭に「ファイル形式:」をつけるとその形式で変換してくれる.

2.1.1 注意?

2.2 Jpeg2000による自然画のロスレス圧縮

Jpeg2000を使うとロスレス圧縮が可能になる(ホントはJpegにもその規格はある).

これを使うには,まずjasperライブラリをインストールし,その後ImageMagickを再コンパイルする必要がある.

2.2.1 jasperのインストールとImageMagickの再コンパイル

  1. ソースの取得
    $ wget \
        http://www.ece.uvic.ca/~mdadams/jasper/software/jasper-1.600.0.zip \
    $ unzip jasper-1.600.0.zip
    
  2. ソースを修正

    困ったことに,オリジナルのソースでは一時ファイルの作成にtmpnam関数を使用している.これははっきり言ってマズイので,修正してしまう.なおこれは次のパッケージ作成パッチに含まれているので,パッケージを作るときには飛ばして構わない.

    リスト 1 tmpnam -> mkstempパッチ
    --- jasper-1.600.0.orig/src/libjasper/base/jas_stream.c
    +++ jasper-1.600.0/src/libjasper/base/jas_stream.c
    @@ -386,7 +386,7 @@
     {
            jas_stream_t *stream;
            int *obj;
    -       char filename[L_tmpnam + 1];
    +       char filename[14];
     
            if (!(stream = jas_stream_create())) {
                    return 0;
    @@ -404,11 +404,11 @@
            stream->obj_ = obj;
     
            /* Choose a file name. */
    -       tmpnam(filename);
    +       snprintf( filename, sizeof(filename), "jasper_XXXXXX" );
     
            /* Open the underlying file. */
    - if ((*obj = open(filename, O_CREAT | O_EXCL | O_RDWR | O_TRUNC | \
        O_BINARY,
    -         JAS_STREAM_PERMS)) < 0) {
    +       if((*obj = mkstemp(filename)))
    +       {
                    jas_stream_destroy(stream);
                    return 0;
            }
    
  3. debパッケージ化

    make & make installは気持ち悪いので,パッケージにする.ソースディレクトリで以下のパッチをあてる.

    リスト 2 deb化パッチ
    --- jasper-1.600.0.orig/src/libjasper/base/jas_stream.c
    +++ jasper-1.600.0/src/libjasper/base/jas_stream.c
    @@ -386,7 +386,7 @@
     {
            jas_stream_t *stream;
            int *obj;
    -       char filename[L_tmpnam + 1];
    +       char filename[14];
     
            if (!(stream = jas_stream_create())) {
                    return 0;
    @@ -404,11 +404,11 @@
            stream->obj_ = obj;
     
            /* Choose a file name. */
    -       tmpnam(filename);
    +       snprintf( filename, sizeof(filename), "jasper_XXXXXX" );
     
            /* Open the underlying file. */
    - if ((*obj = open(filename, O_CREAT | O_EXCL | O_RDWR | O_TRUNC | \
        O_BINARY,
    -         JAS_STREAM_PERMS)) < 0) {
    +       if((*obj = mkstemp(filename)))
    +       {
                    jas_stream_destroy(stream);
                    return 0;
            }
    --- jasper-1.600.0.orig/debian/README.debian
    +++ jasper-1.600.0/debian/README.debian
    @@ -0,0 +1,6 @@
    +jasper for Debian
    +----------------------
    +
    +Comments regarding the Package
    +
    +Shohei Nobuhara <>, Sat, 27 Apr 2002 17:06:55 +0900
    --- jasper-1.600.0.orig/debian/changelog
    +++ jasper-1.600.0/debian/changelog
    @@ -0,0 +1,15 @@
    +jasper (1.600.0-1) unstable; urgency=low
    +
    +  * new upstream
    +
    + -- Shohei Nobuhara <>  Wed,  6 Jan 2003 17:06:55 +0900
    +
    +jasper (1.500.4-1) unstable; urgency=low
    +
    +  * Initial release.
    +
    + -- Shohei Nobuhara <>  Sat, 27 Apr 2002 17:06:55 +0900
    +
    +Local variables:
    +mode: debian-changelog
    +End:
    --- jasper-1.600.0.orig/debian/copyright
    +++ jasper-1.600.0/debian/copyright
    @@ -0,0 +1,8 @@
    +This package was debianized by Shohei Nobuhara on
    +Sat, 27 Apr 2002 17:06:55 +0900.
    +
    +It was downloaded from \
        http://www.ece.uvic.ca/~mdadams/jasper/software/jasper-1.600.0.zip
    +
    +Copyright:
    +
    +Copyright 1999-2003 Michael D. Adams
    +
    --- jasper-1.600.0.orig/debian/dirs
    +++ jasper-1.600.0/debian/dirs
    @@ -0,0 +1,2 @@
    +usr/bin
    +usr/sbin
    --- jasper-1.600.0.orig/debian/control
    +++ jasper-1.600.0/debian/control
    @@ -0,0 +1,15 @@
    +Source: jasper
    +Section: unknown
    +Priority: optional
    +Maintainer: Shohei Nobuhara <>
    +Standards-Version: 3.2.1
    +
    +Package: jasper
    +Architecture: any
    +Depends: ${shlibs:Depends}
    +Description: JPEG-2000 Part-1 standard (i.e., ISO/IEC 15444-1) codec \
        library
    + JasPer is a software-based implementation of the codec specified in the
    + emerging JPEG-2000 Part-1 standard (i.e., ISO/IEC 15444-1). 
    + The JasPer software is written in the C programming language.
    + .
    + see also http://www.ece.ubc.ca/~mdadams/jasper/
    --- jasper-1.600.0.orig/debian/rules
    +++ jasper-1.600.0/debian/rules
    @@ -0,0 +1,50 @@
    +#!/usr/bin/make -f
    +# Made with the aid of debmake, by Christoph Lameter,
    +# based on the sample debian/rules file for GNU hello by Ian Jackson.
    +
    +package=jasper
    +
    +build:
    +       $(checkdir)
    +       ./configure --prefix=/usr
    +       $(MAKE) CFLAGS="-O2 -g -Wall"
    +       touch build
    +
    +clean:
    +       $(checkdir)
    +       -rm -f build
    +       -$(MAKE) distclean
    +       -rm -f `find . -name "*~"`
    +       -rm -rf debian/tmp debian/files* core debian/substvars
    +
    +binary-indep: checkroot build
    +       $(checkdir)
    +# There are no architecture-independent files to be uploaded
    +# generated by this package.  If there were any they would be
    +# made here.
    +
    +binary-arch: checkroot build
    +       $(checkdir)
    +       -rm -rf debian/tmp
    +       install -d debian/tmp
    +       cd debian/tmp && install -d `cat ../dirs`
    +       $(MAKE) install prefix=`pwd`/debian/tmp/usr
    +# Must have debmake installed for this to work. Otherwise please copy
    +# /usr/bin/debstd into the debian directory and change debstd to \
        debian/debstd
    +       debstd ChangeLog NEWS README 
    +       dpkg-gencontrol -isp
    +       chown -R root.root debian/tmp
    +       chmod -R go=rX debian/tmp
    +       dpkg --build debian/tmp ..
    +
    +define checkdir
    +       test -f debian/rules
    +endef
    +
    +binary: binary-indep binary-arch
    +
    +checkroot:
    +       $(checkdir)
    +       test root = "`whoami`"
    +
    +.PHONY: binary binary-arch binary-indep clean checkroot
    --- jasper-1.600.0.orig/debian/docs
    +++ jasper-1.600.0/debian/docs
    @@ -0,0 +1,2 @@
    +doc/
    +images/
    

    パッチ後,

    $ dpkg-buildpackage -us -uc -rfakeroot
    

    として,できあがったパッケージをインストール.

そして次にImageMagickの再コンパイルを行う.

$ apt-get source imagemagick
$ cd imagemagick-5.4.9.1
$ dpkg-buildpackage -us -uc -rfakeroot

できあがったパッケージをインストールして準備完了.

なおconfigure時にjasperを認識しない場合,

$ export CFLAGS=-I/usr/local/include
$ export CXXFLAGS=-I/usr/local/include
$ export LDFLAGS=-L/usr/local/lib
$ ./configure

のように

どこにjasperがあるのか

をconfigure前に設定しておく必要があるかもしれない(これは/usr/local/以下の例).configureスクリプトを読めばわかることだが,要するに

#include <jasper/jasper.h>

というソース(test.c)をコンパイルできて,かつ

$ gcc test.c -ljasper

のように,libjasper.soがリンクできればどこにインストールしてあっても構わない.

こうしてできあがったimagemagickを使ってJpeg2000にするには

$ convert lena_std.tif lena.jp2

とし,特にロスレス圧縮であることを指定するには

$ convert -compress Lossless lena_std.tif lena.jp2

とする.

できあがったサイズを比較すると,表2.2.1[Jpeg2000のサイズ比較]のようになった.

表 2 Jpeg2000のサイズ比較
オリジナルTIFF 776KB
Jpeg(オプション無し) 40KB
Jpeg(-compress Lossless) 212KB 全然ロスレスではない!
Jpeg2000(オプション無し) 440KB デフォルトでLosslessっぽい.しかし画素値1のずれが数カ所起きる?
Jpeg2000(-compress Lossless) 440KB 画素値1のずれが数カ所起きる?

画像の比較は,jasperに含まれるimgcmpを用いて

$ convert lena_std.tif lena_std.ppm
$ imgcmp -f lena_std.ppm -F lena.jp2 -m pae

などとして行うことができる.また別の方法として,

$ convert +compress lena_std.tif lena_std.ppm
$ convert +compress lena.jp2 lena_jp2.ppm
$ diff lena_std.ppm lena_jp2.ppm

のように,P3形式(テキスト形式)に変換し,diffをとるというのもある.

2.3 Jpeg2000画像の表示

当たり前のことだが,jasperを使って再コンパイルしたimagemagickのdisplayコマンドを使えば問題なく表示できる.

またwindowsではIrfanView (日本語版)に公式ページにあるプラグインを追加すれば表示できる.

3 import

importを使うとXの画面をキャプチャできる.

シンプルに

$ import

とするとマウスのカーソルが変化するので,取り込みたいウィンドウをクリックする.取り込み完了を示すbeepが鳴り,magick.miffができているはず.あとはこれをconvertで変換すればよい.

最初から出力ファイル名を指定することもできる.

$ import a.ppm

また画面全体をキャプチャするには,

$ import -window root

とする.

3.1 注意

4 libmagick

libmagickを使うと,自分のプログラムの中でImageMagickの機能を使うことができる.特に様々なフォーマットのファイル入出力は便利.

4.1 読み込み

ファイル名を指定して画像をunsigned charの1次元配列として読み込むにはリスト4.1.1[読み込み関数]のようにする.

リスト 3 読み込み関数
#include <magick/api.h>

/**
 * たいていの画像を読み込んでしまう関数
 *
 * - 結果は unsigned char の1次元配列
 * - 結果配列は使用者側で解放すること
 * - 画素のフォーマットを colormap で指定する必要がある
 *   - colormap は R,G,B,A,C,Y,M,K,I の任意の組み合わせ
 *   - ふつう,PPM ファイルなら colormap = "RGB"
 *   - R だけほしければ colormap = "R" とすればよい
 *
 * @param filename [in] ファイル名
 * @param width [out] 読み込んだ画像の横サイズ
 * @param height [out] 読み込んだ画像の縦サイズ
 * @param colormap [in] 取得する画素形式
 * @return 成功したときは得られた1次元配列の先頭へのポインタを,失敗したときはNULLを返す
 */
unsigned char * magick_read(const char * filename, int * width, int * \
    height, const char * colormap)
{
  ExceptionInfo exception;
  Image * image;
  ImageInfo * image_info;
  unsigned char * data;
  int n_pixels;
  int colors;
  
  GetExceptionInfo(&exception);
  image_info=CloneImageInfo((ImageInfo *)NULL);
  strncpy(image_info->filename, filename, MaxTextExtent-1);
  image=ReadImage(image_info, &exception);
  
  if (image == (Image *)NULL)
    {
MagickWarning(exception.severity,exception.reason,exception.description);
      return NULL;
    }

  *width  = image->columns;
  *height = image->rows;
  colors  = strlen(colormap);

  n_pixels = image->columns * image->rows;
data = (unsigned char *)malloc( n_pixels * (colors) * sizeof(unsigned \
    char));
  
if( ! DispatchImage(image, 0, 0, *width, *height, colormap, CharPixel, \
    (void *)(data), &exception) )
    {
MagickWarning(exception.severity,exception.reason,exception.description);
      return NULL;
    }
  
  DestroyImage(image);
  DestroyImageInfo(image_info);

  return data;
}

4.2 書き込み

unsigned charの1次元配列として表された画像をファイルに保存するにはリスト4.2.1[書き込み関数]のようにする.

リスト 4 書き込み関数
/**
 * たいていの画像形式で書き込んでしまう関数
 *
 * - 渡すデータは unsigned char の1次元配列
 * - 渡すデータのフォーマットを colormap で指定する必要がある
 *   - colormap は R,G,B,A,C,Y,M,K,I の任意の組み合わせ
 *   - R,G,B 8bit ずつのデータなら colormap = "RGB"
 *
 * @param filename [in] ファイル名
 * @param data [in] 画像データ
 * @param width [in] 画像の横サイズ
 * @param height [in] 画像の縦サイズ
 * @param colormap [in] 渡したデータの画素形式
 * @return 成功したときは0を返す
 */
int magick_write(const char * filename, const unsigned char * data, int \
    width, int height, const char * colormap)
{
  Image * image;
  ExceptionInfo exception;
  ImageInfo * image_info;
  CompressionType comp;
  int quality;
  
  comp = UndefinedCompression; /* ほかには LZWCompression など */
  quality = 0;
  
  GetExceptionInfo(&exception);
  image_info=CloneImageInfo((ImageInfo *)NULL);
image = ConstituteImage( width, height, colormap, CharPixel, (const void \
    *)data, &exception );
  if (image == (Image *)NULL)
    {
MagickWarning(exception.severity,exception.reason,exception.description);
      return 1;
    }
  
  strncpy(image->filename, filename, MaxTextExtent-1);
  
  if( quality > 0 && quality <= 100 )
    {
      image_info->quality = quality;
    }

  image->compression = comp;
  image_info->compression = comp;

  /*
   * char で渡すので, 8 bits per color とする (デフォルトは16っぽい).
   * 
* if( ( (image_info->compression == NoCompression) || (image->depth > 8) ) \
    ) が,
   * PNM で ASCII フォーマットになる条件らしい.
   *
   * see imagemagick/coders/pnm.c
   */
  image->depth = 8;
  
  if( 0 == WriteImage(image_info, image) )
    {
MagickWarning(image->exception.severity,image->exception.reason,exception.description);
      return 1;
    }

  DestroyImage(image);
  DestroyImageInfo(image_info);
  
  return 0;
}

4.3 コンパイル&リンク

CFLAGS          += `Magick-config --cppflags`
CXXFLAGS        += `Magick-config --cppflags`
LFLAGS          += `Magick-config --ldflags --libs`

とする.

4.4 注意

5 Windows版のインストール

Windows版のimagemagickも,開発元からダウンロードできる.なおそのページに書いてあるように,Postscript関係のファイル(ps, eps, pdf)を扱うにはghostscriptが必要となる.ghostscriptのwindows版のインストールに関しては,TeX関係のページに詳しく記載されていることが多いので,そちらを参考のこと.

適当なミラーサイトを選択すると,binaries/ディレクトリの下に

のようにQ8とQ16,dllとstaticの計4つのバージョンが存在するので,自分に必要なものを選んでインストールする.

ここでQ8とQ16は,1チャネルのビット数を表し,たとえばQ8ではRGBそれぞれ8bitで扱う.通常の画像であればこれで全く問題ないが,PPMなどで48bit画像を使う場合などはQ16を使用する.またdllとstaticの違いは単にリンク方法が違うだけなので,特に理由がなければdllでかまわない.

なお開発元のページにはVC.netからlibmagickを使う方法が紹介されている.