Help us understand the problem. What is going on with this article?

ImageMagick Gravity 指定

はじめに

ImageMagick の Gravity は画像を合成、連結、分割などする際にどの方向に寄せるかの機能です。例えばベース画像の上に文字や画像を載せる際のレイアウトを調整できます。-gravity オプションで指示します。

% convert granite: -gravity Center -pointsize 20 -annotate 0 Center  Center.png
% convert granite: rose: -gravity South -composite  South.png
Center.png South.png
Center.png South.png

gravity type (direction)

-list gravity で一覧が出せます。

% convert -list gravity
None
Center
East
Forget
NorthEast
North
NorthWest
SouthEast
South
SouthWest
West

地図で使われる方角の表現ですね。

Gravity type (direction)
image.png

尚、None は未指定、Forget は取り消しの意味合いですが、どちらも内部的な数値は 0 でデフォルト扱いの動作になります。

なお、+gravity で None 相当です。Forget じゃないのか。。

  • MagickWand/mogrify.c
if (LocaleCompare("gravity",option+1) == 0)
  {
    if (*option == '+')
      {
        draw_info->gravity=UndefinedGravity;
        break;
      }
    draw_info->gravity=(GravityType) ParseCommandOption(
      MagickGravityOptions,MagickFalse,argv[i+1]);
    break;
  }

コマンド例

annotate (文字入れ)

% for g in NorthWest North NorthEast West Center East SouthWest South SouthEast ; 
    do convert granite: -gravity $g -pointsize 20 -annotate 0 $g  $g.png ;
  done
West Center East
North NorthWest.png North.png NorthEast.png
Center West.png Center.png East.png
South SouthWest.png South.png SouthEast.png

composite (画像合成)

% for g in NorthWest North NorthEast West Center East SouthWest South SouthEast ;
      do convert granite: rose: -gravity $g -composite  $g.png ;
  done
West Center East
North NorthWest.png North.png NorthEast.png
Center West.png Center.png East.png
South SouthWest.png South.png SouthEast.png

append

% for g in West Center East ;
      do convert -gravity $g -append rose: granite:  $g.png ;
  done
West Center East
West.png Center.png East.png

-append は横に繋げるので、NorthWest, West, SouthWest のような縦方向の違いは影響せずに同じ結果になります。

% for g in North Center South ;
      do convert -gravity $g +append rose: granite:  $g.png ;
  done
North Center South
North.png Center.png South.png

+append は横に繋げるので、NorthWest, North, NorthEast のような横方向の違いは影響せずに同じ結果になります。

crop

別記事にあります。

オフセット

Gravity で寄せた場所から更にオフセット指定でずらす事が出来ます。

% for g in NorthWest North NorthEast West Center East SouthWest South SouthEast ;
      do convert granite: -gravity $g -pointsize 20 -annotate +20+20 $g  $g.png ;
  done
NorthWest.png North.png NorthEast.png
West.png Center.png East.png
SouthWest.png South.png SouthEast.png

いまいち分かりにくいので、オフセット無しの文字を薄字で入れて、更にズレた方向を赤い矢印で示してみます。

% for g in NorthWest North NorthEast West Center East SouthWest South SouthEast ;
      do convert granite: -gravity $g -pointsize 20 -annotate +20+20 $g \
                                         -fill gray -annotate 0 $g  $g.png ;
  done
NorthWest.png North.png NorthEast.png
West.png Center.png East.png
SouthWest.png South.png SouthEast.png

つまり、Gravity が左、上、中央によっている時はオフセットが + に働き、右、下の場合は - に働きます。端っこからどのくらい開けるかを何となく指定できるので慣れると便利です。

該当コード

まずは横方向を合わせて、次の縦方向を合わせる。それだけです。
〜EastGravity では width - x 、 〜SouthGravity は height - y してるように、この2つは逆転します。つまり端っこからどの程度空けるかの計算をしています。

MagickExport void GravityAdjustGeometry(const size_t width,
  const size_t height,const GravityType gravity,RectangleInfo *region)
{
  if (region->height == 0)
    region->height=height;
  if (region->width == 0)
    region->width=width;
  switch (gravity)
  {
    case NorthEastGravity:
    case EastGravity:
    case SouthEastGravity:
    {
      region->x=(ssize_t) (width-region->width-region->x);
      break;
    }
    case NorthGravity:
    case SouthGravity:
    case CenterGravity:
    {
      region->x+=(ssize_t) (width/2-region->width/2);
      break;
    }
    case ForgetGravity:
    case NorthWestGravity:
    case WestGravity:
    case SouthWestGravity:
    default:
      break;
  }
  switch (gravity)
  {
    case SouthWestGravity:
    case SouthGravity:
    case SouthEastGravity:
    {
      region->y=(ssize_t) (height-region->height-region->y);
      break;
    }
<略>

Forget のうんちく

None があるのに Forget があるのが不自然に見えるので、そのうんちく話です。
実は、大昔 X11 Window System にべったりだった頃の名残りです。

今現在 Gravity タイプは ImageMagick の geometry.h で以下のように定義されます。

typedef enum
{
  UndefinedGravity,
  ForgetGravity = 0,
  NorthWestGravity = 1,
  NorthGravity = 2,
  NorthEastGravity = 3,
  WestGravity = 4,
  CenterGravity = 5,
  EastGravity = 6,
  SouthWestGravity = 7,
  SouthGravity = 8,
  SouthEastGravity = 9
} GravityType;

ImageMagick-3 系までは、この enum は存在せず、Xlib の定義を参照していました。
当時は X11R4 が主流で、以下のヘッダが該当します。

| /* Bit Gravity */ |
|:--|
|  |
| #define ForgetGravity |  | 0 |
| #define NorthWestGravity | 1 |
| #define NorthGravity |  | 2 |
| #define NorthEastGravity | 3 |
| #define WestGravity |  | 4 |
| #define CenterGravity |  | 5 |
| #define EastGravity |  | 6 |
| #define SouthWestGravity | 7 |
| #define SouthGravity |  | 8 |
| #define SouthEastGravity | 9 |
| #define StaticGravity |  | 10 |

ImageMagick-4 系で Windows 対応した時に、自前のヘッダ(当時は classify.h)で定義するようになりました。
尚、同じ名前を使っているので X11 のヘッダを include すると衝突しそうですが、ForgetGravity が define されてたら 〜Gravity を #undef するという力技で対処してます。

#if defined(ForgetGravity)
#undef ForgetGravity
#undef NorthWestGravity
#undef NorthGravity
#undef NorthEastGravity
#undef WestGravity
#undef CenterGravity
#undef EastGravity
#undef SouthWestGravity
#undef SouthGravity
#undef SouthEastGravity
#endif

この 〜Gravity は X Window System で Window をどう配置するかの属性に使われるもので、このシステムが当時のオブジェクト指向のはしりだった事を考えると、ForgetGravity は命令としてのメッセージ性を高める為の命名だと思います。

参考

yoya
画像処理の事ばかり考えてます。ImageMagick ウォッチングが趣味です。
http://pwiki.awm.jp/~yoya/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away