ImageMagick の歴史メモ

# はじめに

ドキュメントやソースコードから推測した ImageMagick の歴史メモです。
ImageMagick (無印)からImageMagick 7 までとなります。
識者の目に届いてより良質な情報が共有される呼び水になれれば幸いです。

# ImageMagick 公開前

- https://imagemagick.org/script/history.php

1987年に ImageMagick の開発が始まりました。
米DuPont 社の社員だった Cristy 氏が上司の依頼で 256 色モニタに、元の見た目をなるべく維持して表示するツールとして開発を始めたそうです。
24ビットカラー画像をそのまま表示できる環境が非常に高価で希少だった時代です。

# ImageMagick (無印)

1990年8月。DuPont 社の許可の元、Usenet's comp.archives にて一般公開されました。
DuPont 社は化学の営利企業なので画像処理に関して競合せずと制限しなかったとの事。
しかも最終的に ImageMagick Studio 社に権利を譲渡します。懐が深い。

この頃はまだ convert コマンドがありません。
主なコマンドは以下の通りです。

```text:x.org/X11R5/contrib/clients/ImageMagick/Announce
Display
Import
XtoPS
Animate
Montage
```

画像ファイルで入出力できるのは ImageMagick 独自形式の MIFF のみ。
別途、他の画像形式との変換フィルタが用意されています。

```shell:x.org/X11R5/contrib/clients/ImageMagick/filters
% ls
AVStoMIFF.c	MIFFtoGRAY.c	MIFFtoTIFF.c	RGBtoMIFF.c	ls-lR.Z
GIFtoMIFF.c	MIFFtoMTV.c	MIFFtoXBM.c	SUNtoMIFF.c	ls-ltR.Z
GRAYtoMIFF.c	MIFFtoPPM.c	MIFFtoXWD.c	TIFFtoMIFF.c
Imakefile	MIFFtoRGB.c	MTVtoMIFF.c	XBMtoMIFF.c
MIFFtoAVS.c	MIFFtoSTEREO.c	PPMtoMIFF.c	XWDtoMIFF.c
MIFFtoGIF.c	MIFFtoSUN.c	README		displayGIF
```

display コマンドで画像変換を指定して X Window System のモニタに表示した画像を MIFF 出力する事で、画像処理も出来ました。

画像処理のオプションは当時から結構あります。

```
-clip -colors -dither -enhance -gamma -geometry
-gray -inverse -magnify -map -monochrome -noise
-normalize -reflect -rotate -scale -visual
```

display の GUI メニューで指定できる画像処理は90度単位の回転や2倍の拡大/縮小といった簡単なものです。
X11 の XDrawImageString を使った文字を載せる処理もあります。

```c:x.org/X11R5/contrib/clients/ImageMagick/display.c
*MenuSelections[]=
{
  "Image Info",
  "Write Image",
  "Print Image",
  "Annotate Image",
  "Reflect Image",
  "Rotate Right",
  "Rotate Left",
  "Half Size",
  "Double Size",
  "Restore Image",
  "Next Image",
  "Quit"
};
```

メイン機能である減色のアルゴリズムは当初から Octree で、ディザは Floyd-Steinberg です。
ちなみにレトロPC絵で知られる組織的ディザは ImageMagick 6 で追加されます。

## X11R5/contrib/clients/ImageMagick/

- https://github.com/yoya/x.org/tree/master/X11R5/contrib/clients/ImageMagick

x.org の X11R5/contrib に含まれる ImageMagick には 1991年の Copyright があり、ImageMagick-2.0 が 1992年で、2 との差分も大きいので、これが ImageMagick-1.x 相当だと判断してこのエントリを書いています。

```c:x.org/X11R5/contrib/clients/ImageMagick/display.h
Version[]="@(#)ImageMagick 91/01/01 cristy@dupont.com";
```

# ImageMagick 2

1992年1月リリースだと思われます。

```c:ImageMagick2.0/display.h
Version[]="@(#)ImageMagick 92/01/01 cristy@dupont.com";
```
- https://unf.edu/public/cap6400/ychua/ (もう消えてます)

ソースコード上でのバージョン明記は 2.1 からです。

```c:ImageMagick2.1/display.h
Version[]="@(#)ImageMagick 2.1 92/10/10 cristy@dupont.com";
```
- https://pd.spuddy.org/fs/x11r5/contrib/ (もう消えてます)

2系 から様々な形式の画像ファイルを直接読めるようになりました。
MIFF 以外の画像形式を Alien Format と呼称します。当時から命名が独特のセンスですね。
先頭バイナリから推測した画像形式で読む処理はこの頃からです。
(例えるならイントロドン、みたいなテクニックです)

## convert コマンド

1992年リリースの ImageMagick-2系 から convert コマンドが含まれます。 > utilities/convert.c

たまに、Windows に convert コマンドがあるのに何故名前をぶつけてくるんだといった言説を耳にしますが、Windows のそれは NTFS の変換ツールで、Windows NT は 1993年リリースなので ImageMagick の方が先だと思われます。

そうだとしても他とぶつかりそうな名前は駄目でしょ、といった点では当時のターゲットである UNIX は cp や ls のように短縮系を使う慣習があり convert はむしろ特別なのと、X11 と密接なツールは /usr/X11R5/bin/ に置くので、他と衝突するなら PATH 設定で頑張って。位の感覚かもしれません。

## X11R5/contrib/ImageMagick2.1.tar.Z

https://pd.spuddy.org/fs/x11r5/contrib/

2 系ソースコードの入手経緯はこちら。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://pd.spuddy.org/fs/x11r5/contrib/">https://pd.spuddy.org/fs/x11r5/contr...</a> に ImageMagick2.1.tar.Z というものがありますね</p>&mdash; Watson (@watson1978) <a href="https://twitter.com/watson1978/status/1348328674274148353?ref_src=twsrc%5Etfw">January 10, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

その節はありがとうございました > @watson1978 

# ImageMagick 3

1994年6月リリースと思われます。

3 でもまだ X Window System に依存していますが UNIX のみでなく、Macintosh(MacX) や Windows NT のバイナリが出ていた事から、マルチプラットフォームも意識していたようです。
VMS も真面目に対応し始めました。1 や 2 でも一応 VMS でビルドできたのですが、#define で空白に置換したりと処理を省略してます。

magick.h で API 公開をはじめたバージョンです。

```c:
    #include <magick.h>

    int main(int argc,char **argv)
    {
      Image
        *image,
        *scaled_image;

      ImageInfo
        image_info;

      /*
        Initialize the image info structure and read an image.
      */
      GetImageInfo(&image_info);
      (void) strcpy(image_info.filename,"image.jpg");
      image=ReadImage(&image_info);
```

この API に応じて PerlMagick が誕生しました。言語バインディングの始まりです。(Shellもコンピュータ言語ですが別として)

- https://flex.phys.tohoku.ac.jp/texi/ImageMagick/www/perl.html

> PerlMagick, version 1.12, (略)
> You must have ImageMagick 3.8.7 or above and Perl version 5.002 or greater installed on your system.

まだ MagickWand みたいな高位レイヤーはなく、ReadImage などの低位レイヤーの関数を直接呼ぶ方式でした。

C++ API 提供も 3 系からはじまっています。

## フォルダ構成

この頃から magick フォルダにコアな処理をまとめるようになりました
alien.c は decode と encode に分かれ、magick/{decode.c|encode.c} に移されました。

```shell:x.org/X11R6/contrib/programs/ImageMagick/magick
% ls
Imakefile	X.h		decode.c	magick.h	utility.h
Make.com	XWDFile.h	encode.c	quantize.c	widget.c
PreRvIcccm.c	colors.c	error.c		shear.c		widget.h
PreRvIcccm.h	compress.c	image.c		signature.c
X.c		compress.h	image.h		utility.c
```

## 特記事項

特筆すべきは、-matte で透明度のon/offができるようになった事です。
あとは -blur, -shapen, -equalize といった少し高度な画像処理に対応。
枠をつける -border も 3系 で追加されています。

logo: といった組み込み画像も 3系 からです。

## X11R6/contrib/programs/ImageMagick

- https://www.x.org/releases/X11R6/
- https://github.com/yoya/x.org/tree/master/X11R6/contrib/programs/ImageMagick

X11R6/contrib に含まれる ImageMagick のソースコードには以下の copyright があるので、3.0 相当と思われます

```c:x.org/X11R6/contrib/programs/ImageMagick/magick/magick.h
Version[]="@(#)ImageMagick 3.0 94/06/01 cristy@dupont.com";
```

## ImageMagick 3.8.1

昔は、ImageMagick でなく ImageMagic だったという噂があります。

- https://grumbeer.dyndns.org/ftp/cdroms/suse/suse-linux-5.3-5/usr/lib/ImageMagick/www/Changelog.html

こちらを見ると、以前は ImageMagic で 1997年リリースの 3.8.1 から ImageMagick を呼称するようになったy想像できますが、本家は当初から ImageMagick で、comp.sources.x のアーカイブ名が imagemagic なので、パッケージ名の話かもしれません。

```text:x.org/X11R5/contrib/clients/ImageMagick/Announce
ImageMagick, an X11 image processing and display utility, is now available
on export.lcs.mit.edu as contrib/ImageMagick.tar.Z.  It is also available in
any comp.sources.x archive as imagemagic, volume 13, issue 17.
```

## ImageMagick 3.8.9

3 は開発の活発なバージョンです。
たまたま入手できた最後の(方の？)バージョン ImageMagick-3.8.9 では 3.0 に比べてコマンドオプションがほぼ倍に増えています。

画像処理だと -average -charcoal -colorize -contrast -emboss -implode -modulate -opaque -paint -wave といった、今では馴染みのもの、もしくは名前が変わりつつ残っている機能が沢山追加されています。
透明度の処理も -matte に加えて -transparent も入りました。

# ImageMagick 4

公式には 4.2.9 の 1998年9月リリースが初です。
4 系からWindows 95/NT にも対応しました。Visual C++ 7 でビルドできます。

それまで UNIX/VMS がターゲットで X Window System に依存していましたが、クロスプラットフォームを意識して、X Windows への依存がほぼ解消されました。

Macintosh サポートもあります。Metrowerks CodeWarrior でビルドできます。
ただし、display や animate, import といった GUI 連携は動きません。

あと、UNIX 用に autoconf 対応が入りました。(開発者的には超重要)

DICOM(医療)や VICAR(天体) など特殊用途の画像形式が増えている事から、いろんな分野で利用されている事が想像できます。


次の 5 系がでるまで短かったのですが、4.x はアプリケーションとしての完成度が高く広く普及しました。

ImageMagick-4 までの Copyright は Dupont 社です。

## 幻の 4.2.7

確か、同年7月リリースの 4.2.7 でも rc が取れていたはずですが、公式に 4.2.9 が初リリース扱いなのは、何か事情があるのでしょうか。

# ImageMagick 5

1999年リリースです。
Bob Friesenhahn 氏が API の改善を提案したのがキッカケで始まりました。
5系から Copyright が  DuPont 社から ImageMagick Studio に変わっているので、この時に権利の譲渡が行われたと思われます。ふとっぱら。

5系で PerlMagick が ImageMagick ソースに追加されました。

MagickWand は 5系初期には存在せず、PerlMagick は低レベルの API を触っています。これは今でも続いています。

## GraphicsMagick

- http://www.graphicsmagick.org/

API やコマンドラインオプションが安定しないのに業を煮やした Bob 氏が ImageMagick-5.5.2 からフォークして新たに GraphicsMagick を立ち上げました。
API の安定が GraphicsMagick の主な存在理由です。

巷では ImageMagick より GraphicsMagick が速いと評判ですが、

- 5.x の頃の方のアルゴリズムが単純な事もあって、ImageMagick-6 と比べると処理が速い事もある。画質劣化やファイルサイズの増加と引き換え
- ImageMagick は 16bit デフォルトビルド、GraphicsMagick は 8bit ビルドなので利用メモリが半分で速い。その代わり画質は微妙

といった要因があって特に高速化チューニングがされている訳ではないです。
GraphicsMagick はソースコードが綺麗だとか ChangeLog が分かりやすい(ImageMagickもここ数年は改善傾向)といった、優れた点があります。

(以前調べた時は ImageMagick-5.5.2 でなく 5.5.4 からのフォークに見えたので、要検証)

## ImageMagick 5.5.7 MagickWand

上位 API レイヤーの MagickWand API ができました。
これ以降、いろんな言語からのバインディングが加速します。

# ImageMagick 6

2004年リリースです。
複数の画像を扱う時にコマンドラインが分かりにくいとの指摘があり見直しました。
我々が convert コマンドとして親しみのある機能と使い方は、このバージョンからです。

- ライセンスをApache スタイルに変更しました。(以前は BSD ？）
  - 参考) https://masao.jpn.org/d/2004-04-16.html

- コマンドラインの引数の指定の仕方が変わりました
```
5 まで UNIX の流儀に合わせて、はじめにオプションをまとめる
command [options] input_image output_image
6 から画像ファイルの後ろにオプションを並べる
command [options] image1 [options] image2 [options] output_image
```

- 画像ファイル形式処理が以前 magick にあったのが、coders にまとめられました
- EXIF が読めるようになりました
- -strip が入りました
- -random-threshold と -ordered-dither が追加されました。レトロPC画像で馴染みのある組織的ディザです

## ImageMagick 6.7.x 6.8.x

6.7.x / 6.8.x は色空間処理の根本的な見直しがあり、思考錯誤で色の不具合の多かったバージョンです。

特に 6.7 で RGB の別名で sRGB を新設したはユーザだけでなく開発者も混乱しているように感じました。また、sRGB 互換かどうかの処理がバラバラで統一されてなくパターンによって罠を踏む事もありました。

- https://www.imagemagick.org/discourse-server/viewtopic.php?t=23707

6.8.9 あたりで不具合はだいたい解消されていきます。

- https://yoya.hatenadiary.jp/entry/20140412/im

## ImageMagick 6.9.1 API breaking change

ImageMagick API を 6.8.9 以前と同じ使い方をするとコンパイルでエラーが出ます。
ただ、5 系と違って目立った breaking change はこの一度のみです。GraphicsMagick の件が堪えたのか、もしくは理想に近づいて変更する理由がなくなってきたのか。

## ImageMagick 6 EoL

元々、ImageMagick 7 を出した時に、6 の EoL を 2020年と定めましたが、7 への移行が進まず 2027年に延長されました。

- https://imagemagick.org/discourse-server/viewtopic.php?t=34128

# ImageMagick 7

2016年リリース。現時点(2024年)で最新のメジャーバージョンです。
フォルダ構成が magick => MagickCore, wand => MagickWand に変わっていますが他はだいたい同じ。

元々、RGB を前提としてそれ以外の CMYK や Alpha は後付けの設計なので、7系ではそれらを特別扱いせず処理できるよう見直されています。

## magick コマンド

コマンド名が magick に変わりました。
convert コマンドは互換性の為に残しています

この互換性はコマンドの名前だけでなく、
convert コマンド(もしくは magick convert) の方は ImageMagick6 と同じコマンド引数処理を行います。for と switch のベタな制御構造です。
magick コマンドは引数処理を一から実装し直していて、引数テーブルを検索して該当する関数を呼ぶようになっています。
移植のミスか意図的なのか分かりませんが、convert と微妙に動きが異なる時があるのに注意が必要です。

## 7.1.1-33 convert deprecated

このバージョンから convert コマンドを使うと警告が出るようになりました。

- https://github.com/ImageMagick/Website/blob/main/ChangeLog.md#711-33---2024-05-25
- https://github.com/ImageMagick/ImageMagick/commit/75a5c6d168379dd6e74f207468444cb2cff11720

# 脆弱性

ImageMagick は多くの画像形式に対応している為、入力形式を制限していない場合、その数だけ脆弱性が入り込みやすくなります。
また、ImageMagick 本体に脆弱性がなくても、画像ライブラリは多くは外部のライブラリやアプリケーションに依存しているので、そちらに脆弱性があれば、ImageMagick に影響する事があります。
昔は libtiff や libpng に脆弱性が多く、ImageMagick の更新を頻繁にする時期もありました。
最近でも ghostscript の脆弱性が耳に新しいです。

特に大きく話題になった２つの脆弱性。ImageTragick (CVE-2016–3714) と Yahoobleed (CVE-2017-9098) は歴史として語る必要があろうかと思います。
どちらもファイル形式を絞らず、可能な限り受け入れていた環境での話です。

## ImageTragick (CVE-2016–3714)

MVG(MagickVectorGraphics) や SVG といったベクター画像ファイルに埋める描画コマンドのフィルタ漏れで、リモートコード実行が可能な脆弱性です。
以下のは例です。

```shell:
https://example.com/foo.jpg"|ls "-la
```

また、@〜 でファイル読み込みできる仕様があり、label:@/etc/passwd を指定すると、パスワードファイルの中身が画像ファイルとして変換できるのですが、描画コマンドでも指定できてしまいました。

これは描画コマンドのモジュールを無効にするのが回避策で、その後、フィルタのチェックやエスケープが強化されました。

## Yahoobleed (CVE-2017-9098)

こちらは、Yahoo が ImageMagick 利用をやめた事で大きく話題になった不具合です。

- 米Yahoo!、メール添付画像流出の脆弱性に対処　「ImageMagick」は引退
  - http://www.itmedia.co.jp/enterprise/articles/1705/23/news070.html 
- 
RLE 読み込みの不具合で ImageMagick のメモリにある他の画像が漏れる可能性のある脆弱性です。

- URT - Utah Raster Toolkit
  - http://paulbourke.net/dataformats/urt/

実際に、罠をしこんだ RLE ファイルを Yahoo! メールに添付して得たとされる画像がこれらです。

|yahoo_letter_a_anon.jpg| yahoo_leak_512_1_anonymized.jpg | yahoo_leak_cmy_bands.jpg|
|---|---|---|
| ![yahoo_letter_a_anon.jpg](https://qiita-image-store.s3.amazonaws.com/0/1798/911db977-6afe-0d23-6361-98d44b32b51b.jpeg) | ![yahoo_leak_512_1_anonymized.jpg](https://qiita-image-store.s3.amazonaws.com/0/1798/9c7baf14-f723-b216-0d4d-811ce00bdc87.jpeg) | ![yahoo_leak_cmy_bands.jpg](https://qiita-image-store.s3.amazonaws.com/0/1798/831839ce-2724-f037-ae67-c6d1c682bd47.jpeg) |

yahoo_letter_a_anon.jpg の width と stride(1 scanline 辺りの内部データ長) をずらすと以下のようになります。

| a_planes2.png (width:256 stride:172) |
|---|
| ![a_planes.png](https://qiita-image-store.s3.amazonaws.com/0/1798/1ebe2d57-57e6-35f2-4ace-594384703d00.png) |

## 脆弱性対策

これらを反省したのか 2017年は脆弱性を洗うセキュリティ月間的な動きがありました。特に C言語の暗黙的な型変換を危険視して、キャストを入れるコミットが多かった印象です。

また、Google 社が 2016年ベータ公開した OSS-Fuzz というファジングチェックツールも助けになり、2017年は多くの脆弱性が対策されました。

ただ、この年の突出した脆弱性報告数は、日本の一部界隈で不安を招く結果となりました。

- さようなら ImageMagick
  - https://blog.cybozu.io/entry/2018/08/21/080000

![cybozu-blog-2018.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1798/bb330d50-5321-395e-f784-295503657226.png)

難しいものですね。

2018年から OSS-Fuzz を CI で回すようになり、以前よりだいぶ堅牢になっていると思われます。

# 参考資料

- https://imagemagick.org/script/history.php
- https://masao.jpn.org/d/2004-04-16.html
- https://grumbeer.dyndns.org/ftp/cdroms/suse/suse-linux-5.3-5/usr/lib/ImageMagick/www/Changelog.html
- https://qiita.com/yoya/items/2076c1f5137d4041e3aa
- https://www.x.org/releases/X11R5/
- https://www.x.org/releases/X11R56/