Magick++ で画像の種類を調べてみる

アップロードされた画像ファイルの種類を調べたいとき、PHP だと $_FILES の type を見て MIME が取れたりしますが、その値も信頼できないということで、exif_imagetype とかを使って本当の画像の種類を調べる必要がありそうです。

というわけで、さらに PHP でもない環境でなんかわかんないけどポツンと画像ファイルらしきものがあるとして、ImageMagick の C++ な I/F である Magick++ を使ってその種類を調べてみます。

Magick++ 自体は ImageMagick のパッケージに引っ付いてくるみたいなので、MacPorts だとこんな感じでまずインストール。+jpeg2 で jasper が入ります。

CODE:
  1. [ihara@barcelona.local:~] $ port list | grep -i imagemagick
  2. ImageMagick                    @6.3.5-6        graphics/ImageMagick
  3. [ihara@barcelona.local:~] $ port variants ImageMagick
  4. ImageMagick has the variants:
  5.         universal
  6.         perl
  7.         gs
  8.         lcms
  9.         wmf
  10.         mpeg
  11.         jbig
  12.         jpeg2
  13.         graphviz
  14.         no_x11
  15.         no_plus_plus
  16.         darwin_6
  17.         darwin_8
  18. [ihara@barcelona.local:~] $ sudo port install -dv ImageMagick +jpeg2

で、Magick++ を使って書いてみた magickpp.cc。

C++:
  1. #include <iostream>
  2. #include <vector>
  3. #include <Magick++.h>
  4.  
  5. using namespace std;                                                                                                                                               
  6.  
  7. int main(int argc, char* argv[]) {
  8.     char* files[] = {"/Users/ihara/work/jpeg.jpg", // JPEG
  9.                      "/Users/ihara/work/jpeg2000.jp2", // JPEG 2000
  10.                      "/Users/ihara/work/gif.gif", // GIF
  11.                      "/Users/ihara/work/animgif.gif", // Animation GIF
  12.                      "/Users/ihara/work/png.png", // PNG
  13.                      "/Users/ihara/work/magickpp", // 存在しないファイル
  14.                      "/Users/ihara/work/magickpp.cc"}; // このソースファイル
  15.     for (unsigned int i = 0; i <sizeof(files) / sizeof(files[0]); i++) {
  16.         try {
  17.             vector<Magick::Image> imageList;
  18.             Magick::readImages(&imageList, files[i]);
  19.             const string& magick = imageList[0].magick();
  20.             if (magick != "GIF") {
  21.                 cerr <<files[i]
  22.                      <<": "
  23.                      <<magick
  24.                      <<endl;
  25.             } else {
  26.                 if (imageList.size() == 1) {
  27.                     cerr <<files[i]
  28.                          <<": "
  29.                          <<magick
  30.                          <<endl;
  31.                 } else {
  32.                     // アニメーション GIF はエラーとする
  33.                     cerr <<"ERROR: "
  34.                          <<files[i]
  35.                          <<": animation gif, frame size: "
  36.                          <<imageList.size()
  37.                          <<endl;
  38.                 }
  39.             }
  40.         } catch (const Magick::Exception& e) {
  41.             cerr <<"ERROR: "
  42.                  <<files[i]
  43.                  <<": "
  44.                  <<e.what()
  45.                  <<endl;
  46.         }
  47.     }
  48.     return 0;
  49. }

Magick::readImages() で画像を読み込んで、フレームが 2 つ以上ある GIF はエラーにしています。

で、ビルド。C なら Magick-config、C++ なら Magick++-config ってツールで必要なコンパイルオプションを出力してくれます。g++ ならこんな感じ。

CODE:
  1. [ihara@barcelona.local:~/work] $ g++ `Magick++-config --cppflags` `Magick++-config --ldflags --libs` magickpp.cc

できた a.out を実行してみます。

CODE:
  1. [ihara@barcelona.local:~/work] $ ./a.out
  2. /Users/ihara/work/jpeg.jpg: JPEG
  3. /Users/ihara/work/jpeg2000.jp2: JP2
  4. /Users/ihara/work/gif.gif: GIF
  5. ERROR: /Users/ihara/work/animgif.gif: animation gif, frame size: 6
  6. /Users/ihara/work/png.png: PNG
  7. ERROR: /Users/ihara/work/magickpp: ImageMagick: unable to open image `/Users/ihara/work/magickpp': No such file or directory
  8. ERROR: /Users/ihara/work/magickpp.cc: ImageMagick: no decode delegate for this image format `/Users/ihara/work/magickpp.cc'

フレームのサイズが 6 な animgif.gif(5 行目)や、存在しないファイル(7 行目)、テキストファイル(8 行目)はエラーになっています。

identify 叩けばさくっと終わる話なんですけどね。


About this entry