コミックマーケット DVD-ROMカタログのデータをプログラムから利用する（サークルカット編）

#コミックマーケット ＤＶＤ－ＲＯＭカタログのデータを自作プログラムから使おう

コミックマーケット８７ＤＶＤ－ＲＯＭカタログが発売されます。
http://www.comiket.co.jp/info-a/CatalogShop.html

コミックマーケットカタログのROMデータは基本的にクローズドなデータになっておりプログラムから利用するには一定の解析が必要なのですが
コミックマーケットROMソフトから出力するチェックリスト.csvからタスク管理ツール「trello」に登録する**Comike2Trello**なるソフトと**comike_catalog_parser**というRubyモジュールを前回の夏コミの時に作成したので、その時に得た情報を共有します。

* https://github.com/AKB428/Comike2Trello 
* http://rubygems.org/gems/comike_catalog_parser

## 想定されるユースケース
前述したように、コミックマーケットカタログのROMデータは仕様が公開されていないブラックボックスデータであり、毎回データ仕様変更がある可能性を考えると、バイナリデータを解析してパースするよりはカタログの公式ソフトから出力したCSVチェックリストを解析して利用するというのが手っ取り早いコミケカタログROMデータのプログラム活用アプローチだと思われます。

## ROMデータのサークルカットのデータをパースする。
今回はROMデータのサークルカットのデータをパースしてみます。

![1.png](https://qiita-image-store.s3.amazonaws.com/0/36931/c1d7dd45-049d-a1a6-3fc9-d168f37d8734.png)

カタログDVD-ROMにはPDATAというフォルダにサークルカットの画像が格納されています。
このデータはWindowsに普通にカタログをインストールするとローカルドライブにはインストールされません。


###　出力したカタログチェックリストからXXXX.PNGとサークルカットのポジジョンを割り出す。


![CBIMGadsd001.png](https://qiita-image-store.s3.amazonaws.com/0/36931/02ed5570-a691-8806-3ed0-6c2c4e552aa7.png)
これがカタログブラウザから出力したCSVをExcelでみた状態の画像です。
1～10行目までがラベル情報で、11行目から本来のチェックデータです。相当やばいCSVデータの格納方法だと思います。

|  | D列        | E列 |
|:-----------|------------:|:------------:|
| 11行目以降      |        XXXX.PNGの番号 |     ページ内ポジジョン（1～36）     |


このデータをパースすれば、チェックリストにあるサークルのカットだけをカッティングできます。


### サークルカットページの仕様

![CBIMGadsd002.png](https://qiita-image-store.s3.amazonaws.com/0/36931/39c55cfe-04c3-418e-8a5a-53c289b66569.png)

ページ内ポジジョンの割り当ては上記のように左上が1で右にインクリメントされ一番右下が36になります。

![CBIMGadsd003.png](https://qiita-image-store.s3.amazonaws.com/0/36931/59582db5-1606-5fe7-5cbe-0cb77f2e07d3.png)

1サークルカットのサイズと、ポジジョンの位置のサイズはだいたいこんな感じなります。
ImageMagickなどプログラムの画像APIで1つの画像からある箇所を切り出すときは上記のような情報が必要になります。
たとえばポジジョン9の画像を切り出したい場合

` Image(XXXX.png).cut(切り出す画像の横サイズ,切り出す画像の高さのサイズ,切り出し開始位置[横],切り出し開始位置[縦])`

` Image(XXXX.png).cut(165,241,575,192)`

のようなプログラムを書くことになります。

### Rubyでサークルカットを抽出するプログラムを書く

今回はRubyのサンプルプログラムを書きます。
Rubyで画像を取り扱う場合はRMagickモジュールを利用します。

https://github.com/rmagick/rmagick

Gemfileに書いてbundle install

サークルカットページ画像(XXXX.PNG)から1サークルカットを切り出すプログラムは以下になります。

```ruby:circle_cut.rb
require 'pathname'
require 'fileutils'
require 'RMagick'
module ComikeCatalogParser
  class CircleCut

    WORK_FOLDER_NAME = "./circle_cut"

    CIRCLE_CUT_SIZE_WIDTH = 165
    CIRCLE_CUT_SIZE_HEIGHT = 241

    #とりあえず計算せずMAPで持つ 1ページ 6x6=36カット
    H1 = 70
    H2 = 323
    H3 = 575
    H4 = 828
    H5 = 1081
    H6 = 1333

    W1 = 15
    W2 = 192
    W3 = 369
    W4 = 547
    W5 = 724
    W6 = 903


    CIRCLE_CUT_MAP =
        [
            [W1,H1],[W2,H1],[W3,H1], [W4,H1],[W5,H1],[W6,H1],
            [W1,H2],[W2,H2],[W3,H2], [W4,H2],[W5,H2],[W6,H2],
            [W1,H3],[W2,H3],[W3,H3], [W4,H3],[W5,H3],[W6,H3],
            [W1,H4],[W2,H4],[W3,H4], [W4,H4],[W5,H4],[W6,H4],
            [W1,H5],[W2,H5],[W3,H5], [W4,H5],[W5,H5],[W6,H5],
            [W1,H6],[W2,H6],[W3,H6], [W4,H6],[W5,H6],[W6,H6],
        ]


    def initialize(circle_cut_page_file_path)
      @circle_cut_page_file_path = circle_cut_page_file_path
    end

    #対象のサークルカットPNGから1サークルのカットを切り取りファイルパスを返却する
    #すでに切り取っていたらそれを使う
    def individual_cut(position_id)

      circle_cut_page_file_name = Pathname(@circle_cut_page_file_path).basename.to_s
      circle_cut_page_file_name.gsub!("\.PNG", "")
      page_folder_name = Pathname.new(WORK_FOLDER_NAME).join(circle_cut_page_file_name).to_s
      FileUtils.mkdir_p(page_folder_name) unless File.exist?(page_folder_name)

      write_file_path_name = Pathname.new(page_folder_name).join(position_id + ".png").to_s

      #ファイルをすでにカットしていたら処理せず終了
      return write_file_path_name if File.exist?(write_file_path_name)

      image = Magick::Image.read(@circle_cut_page_file_path).first
      image.crop(CIRCLE_CUT_MAP[position_id.to_i - 1][0], CIRCLE_CUT_MAP[position_id.to_i - 1][1], CIRCLE_CUT_SIZE_WIDTH, CIRCLE_CUT_SIZE_HEIGHT).write(write_file_path_name)


      puts "create " + write_file_path_name
      write_file_path_name
    end

  end
end
```

プログラムのコアは

```rb
      image = Magick::Image.read(@circle_cut_page_file_path).first
      image.crop(CIRCLE_CUT_MAP[position_id.to_i - 1][0], CIRCLE_CUT_MAP[position_id.to_i - 1][1], CIRCLE_CUT_SIZE_WIDTH, CIRCLE_CUT_SIZE_HEIGHT).write(write_file_path_name)
```

の部分で**Magick::Image.read**で画像ファイルを読み込み**image.crop**で画像の一部を切り出しています。

上記で作成したモジュールを利用し画像を切り出す例がこちら

```rbuby:sample.rb
require 'circle_cut.rb'
include ComikeCatalogParser
CircleCut.new("/Users/cocoa/PDATA/1093.PNG").individual_cut("32")'
```

カットすると以下のように36個かたまっていた画像が1つずつ取り出せます。

![CBIMG454001.png](https://qiita-image-store.s3.amazonaws.com/0/36931/a52d5729-c130-e05d-4d98-5ff801450382.png)


### 作成したプログラムのユースケース

コミックマーケットカタログROMのカタログブラウザには1サークルカットの画像を保存する機能がないのでこのようなソフトを作ってチェックしたサークルの画像を保存してSNSで共有したり、Trelloのようなタスクツールを使い購買計画をたてるのがいいでしょう。