9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ImageMagickAdvent Calendar 2017

Day 17

ImageMagick Gravity 指定

Last updated at Posted at 2019-01-04

はじめに

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 、 South〜Gravity は 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 があるのが不自然に見えるので、そのうんちく話です。
実は、大昔の ImageMagick が 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 は命令としてのメッセージ性を高める為の命名だと思います。

参考

9
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?