MiniMagickを使って自動トリミングする方法


##環境
* ruby歴 初心者
* rails5
* ruby 2.4.1p111
* imagemagick 6.9.8-8 Q16 x86_64
* minimagick 4.5.1

##これはなに？
[ImageMagick](https://www.imagemagick.org/script/index.php) での自動トリミングを ruby で実現するために
ruby のインタフェースで作られた [MiniMagick](https://github.com/minimagick/minimagick) を利用してトリミングを実現しました。
その際に学んだことや発生した問題も踏まえて書き留めて置きたいと思います。

ちなみに筆者は画像処理についての知識は薄いのであしからず
また、コメントは細かいところでも大歓迎です。
 
##発端
まず、やりたかったことは **透過部分のトリミング** になります。
※背景は透過で、見やすいように枠線だけ加工して入れてます。

■オリジナル画像
![mask.png](https://qiita-image-store.s3.amazonaws.com/0/9514/900b0ed6-e30d-7e55-7460-bc727e775604.png "mask.png")


■ほしい画像
![trimmed_mask.png](https://qiita-image-store.s3.amazonaws.com/0/9514/6f1f0d3c-34e5-15cb-daf1-fa27438be6e3.png "trimmed_mask.png")

ということで、オリジナル画像にトリミングをかけていきます。
ImageMagick でトリミングしたい場合は [-trim オプション](http://www.imagemagick.org/script/command-line-options.php#trim)をつけるだけでOKでした。（すばらしい！）

```bash
convert <path/to/オリジナル画像> -trim <path/to/ほしい画像>
```

さて、次に ruby の場合です。
調査したところ実現する方法としては、下記の２通りありました。

 1. MiniMagick::Image#trim を用いて処理
 2. MiniMagick::Tool::Convert を用いて CLI のように処理

もちろん 1. が前述した convert 処理してるんだろうなと思い
そちらの手法で処理をしました。

##導入
基本的には下記の流れです。

1. imagemagick のインストール
2. minimagick の gem インストール

細かい部分は[公式](https://github.com/minimagick/minimagick)を見てください。
実装部分はこんな感じ

```!ruby:image_editor.rb
def trimming(input_path, output_path)
  image = MiniMagick::Image.open(input_path)
  image.trim
  image.write(save_path)
end
```

おお、簡単じゃないか..........っと！！！
ところがどっこい、世の中そんな甘くなかった

##問題
鼻歌まじりに、次のサンプルをトリミングにかけた時
衝撃の結果になりました。

■問題のサンプル
![mask.png](https://qiita-image-store.s3.amazonaws.com/0/9514/d41b284b-b6a5-dd8d-3e94-4e6496dee2cb.png "mask.png")

■衝撃の結果
![名称未設定.png](https://qiita-image-store.s3.amazonaws.com/0/9514/b2d69a10-ae20-7314-26b3-3a3c11e09b43.png "名称未設定.png")

なぜか上部の黒い部分まで切り取られてでてきやがったぜ....どういうことだってばよ
※「ちゃんと仕様みとけクソ」というツッコミありがとうございますm(_ _)m

なんでこんなことになったしまったのか、この時点でようやく trim の仕様を確認しに行く次第でした。

##原因
まずは、[ここ](http://www.imagemagick.org/script/command-line-options.php#trim)をよく読んで下さい。

> This option removes any edges that are exactly the same color as the corner
> pixels. 
**「コーナー」のピクセルと同じ色のエッジにそってトリミングします」** 

OMG、書いてあります。
ちゃんと書いてあるんです。

んんっ？？
コーナー......（いろいろ調べてみたら、左上隅の1ピクセルが対象となるらしい）

なるほどねー、左上隅のピクセル確かに黒いわー
今まで黒い部分が設置してなかったから気づかなかった....
期待してるトリミング画像ほしけりゃ左上隅のピクセル透過色にしないと無理ってことね。
いやいやいやいや、どうやるんですか
指定するピクセルで自動トリミングとかできないの？？
（できる方法あったら教えてくださいm(_ _)m）

##解決
ここでさらに[公式をチェック](http://www.imagemagick.org/Usage/crop/#trim_color)したところ.....ありました。
どうやら、トリミングしたい色のボーダーラインを追加してから -trim するようです。
なるほど、たしかにそれでできるね。
（ボダーラインみたいなゴリゴリじゃなくカラーを指定させてほしい......）

もはや、MiniMagickの範疇を超えているので、結局CLI風味で実装することになった。

```!ruby:image_editor.rb
def trimming(input_path, output_path)
  # trim image
  MiniMagick::Tool::Convert.new do |convert|
    convert << "#{input_path}"
    convert.merge! ["-bordercolor", "none"]
    convert.merge! ["-border", "1x1"]
    convert.merge! ["-trim"]
    convert << "#{output_path}"
  end
end
```

MiniMagickを使ってはいるが、結局のところCLIで下記のコマンドを実行しているだけのよう

```bash
convert <input_path> -bordercolor none -border 1x1 -trim <output_path>
```

※ `-bordercolor` については透過でほしかったので `none` にしております

結果、うまくトリミングできました。

■問題のサンプル
![mask.png](https://qiita-image-store.s3.amazonaws.com/0/9514/d41b284b-b6a5-dd8d-3e94-4e6496dee2cb.png "mask.png")

■結果
![correct.png](https://qiita-image-store.s3.amazonaws.com/0/9514/bb24dbb7-92fa-9e38-3fa5-6ca2395e0100.png "correct.png")


##おまけ
画像以外に元画像におけるトリミング領域の座標も欲しかったので取ってみました。
※[公式](http://www.imagemagick.org/Usage/crop/#trim_color)にも実装方法は書かれております。

```!ruby:image_editor.rb
def trimming(input_path, output_path)
  # trim image
  MiniMagick::Tool::Convert.new do |convert|
    convert << "#{input_path}"
    convert.merge! ["-bordercolor", "none"]
    convert.merge! ["-border", "1x1"]
    convert.merge! ["-trim"]
    convert << "#{output_path}"
  end
  
  # get trimmed image bounding box
  info = MiniMagick::Tool::Convert.new do |convert|
    convert << "#{save_path}"
    convert.merge! ["-set", "page", "%[fx:page.width-2]x%[fx:page.height-2]+%[fx:page.x-1]+%[fx:page.y-1]"]
    convert.merge! ["-format", "{ \"x\": \"%X\", \"y\": \"%Y\", \"width\": \"%w\", \"height\": \"%h\" }"]
    convert << "info:"
  end
  
  # parse to json
  trimmed_bounding_box = JSON.parse(info.delete('+'))
end
```

```!ruby:image_editor.rb
convert.merge! ["-set", "page", "%[fx:page.width-2]x%[fx:page.height-2]+%[fx:page.x-1]+%[fx:page.y-1]"]
```

ここの指定がミソっぽいですね。
追加したボーダーライン分の座標を調整しています。

##学んだこと
・自動トリミングの仕組み（左上隅ピクセル情報を用いてトリミングされる）
・指定の色でトリミングする場合はボーダーラインを追加してからトリミングする