コミックマーケット DVD-ROMカタログのデータを自作プログラムから使おう
コミックマーケット87DVD-ROMカタログが発売されます。
http://www.comiket.co.jp/info-a/CatalogShop.html
コミックマーケットカタログのROMデータは基本的にクローズドなデータになっておりプログラムから利用するには一定の解析が必要なのですが
コミックマーケットROMソフトから出力するチェックリスト.csvからタスク管理ツール「trello」に登録するComike2Trelloなるソフトとcomike_catalog_parserというRubyモジュールを前回の夏コミの時に作成したので、その時に得た情報を共有します。
想定されるユースケース
前述したように、コミックマーケットカタログのROMデータは仕様が公開されていないブラックボックスデータであり、毎回データ仕様変更がある可能性を考えると、バイナリデータを解析してパースするよりはカタログの公式ソフトから出力したCSVチェックリストを解析して利用するというのが手っ取り早いコミケカタログROMデータのプログラム活用アプローチだと思われます。
ROMデータのサークルカットのデータをパースする。
今回はROMデータのサークルカットのデータをパースしてみます。
カタログDVD-ROMにはPDATAというフォルダにサークルカットの画像が格納されています。
このデータはWindowsに普通にカタログをインストールするとローカルドライブにはインストールされません。
出力したカタログチェックリストからXXXX.PNGとサークルカットのポジジョンを割り出す。
これがカタログブラウザから出力したCSVをExcelでみた状態の画像です。
1~10行目までがラベル情報で、11行目から本来のチェックデータです。相当やばいCSVデータの格納方法だと思います。
D列 | E列 | |
---|---|---|
11行目以降 | XXXX.PNGの番号 | ページ内ポジジョン(1~36) |
このデータをパースすれば、チェックリストにあるサークルのカットだけをカッティングできます。
サークルカットページの仕様
ページ内ポジジョンの割り当ては上記のように左上が1で右にインクリメントされ一番右下が36になります。
1サークルカットのサイズと、ポジジョンの位置のサイズはだいたいこんな感じなります。
ImageMagickなどプログラムの画像APIで1つの画像からある箇所を切り出すときは上記のような情報が必要になります。
たとえばポジジョン9の画像を切り出したい場合
Image(XXXX.png).cut(切り出す画像の横サイズ,切り出す画像の高さのサイズ,切り出し開始位置[横],切り出し開始位置[縦])
Image(XXXX.png).cut(165,241,575,192)
のようなプログラムを書くことになります。
Rubyでサークルカットを抽出するプログラムを書く
今回はRubyのサンプルプログラムを書きます。
Rubyで画像を取り扱う場合はRMagickモジュールを利用します。
Gemfileに書いてbundle install
サークルカットページ画像(XXXX.PNG)から1サークルカットを切り出すプログラムは以下になります。
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
プログラムのコアは
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で画像の一部を切り出しています。
上記で作成したモジュールを利用し画像を切り出す例がこちら
require 'circle_cut.rb'
include ComikeCatalogParser
CircleCut.new("/Users/cocoa/PDATA/1093.PNG").individual_cut("32")'
カットすると以下のように36個かたまっていた画像が1つずつ取り出せます。
作成したプログラムのユースケース
コミックマーケットカタログROMのカタログブラウザには1サークルカットの画像を保存する機能がないのでこのようなソフトを作ってチェックしたサークルの画像を保存してSNSで共有したり、Trelloのようなタスクツールを使い購買計画をたてるのがいいでしょう。