EDGE2におけるEDGE形式の内部構造を解析する

この記事は、[ドット絵 Advent Calendar 2018 1日目](https://adventar.org/calendars/3094)の記事です。

アドベントカレンダーの1日目ってたいていは入門的な内容とか、比較的わかり易い内容から入ることも多いんじゃないかと思うのですが、本記事はそんなことはまったくなく、しょっぱなからとりあえず書きたいことを書かせていただきました。

さて、今回はEDGE2の画像フォーマットであるEDGE形式の内部構造について、概要を説明します。ただし、まだ未解明な部分が多くあります。ドット絵の描き方の話はしないので、たぶんこれらの情報を必要とする人はかなり限られるでしょう。

## はじめに

みなさんはドット絵を書くとき何のソフトを使われているでしょうか？いろいろあるのですが、私はいまのところEDGE2を使う事が多いです。EDGE2では、`.edg` という拡張子のついた独自画像フォーマット、通称EDGE形式でドット絵を保存します。他の多くのドット絵ソフトウェアでも、大抵の場合独自の画像フォーマットで保存することが多いですね。

さて、このEDGE2で使われるEDGE形式ですが、現在のところその内部の仕様は公開されていません。EDGE1のEDGE形式は、[EDGE形式に対応したC++用ライブラリのソース](http://takabosoft.com/edge/tool)が公開されているのですが、EDGE2には対応していません。公式サイトでも、[「EDGE2用のedgファイルのライブラリは存在しておりません。予定もありません。」](https://wikiwiki.jp/tkbsoft/edge2/%E8%B3%AA%E5%95%8F%E6%8E%B2%E7%A4%BA%E6%9D%BF/%E9%81%8E%E5%8E%BB%E3%83%AD%E3%82%B0000#d02a92a1) と名言されています。

EDGE形式をEDGE2以外のソフトウェアで扱うためには、このEDGE形式の内部構造がわからないと手の出しようがありません。逆に、もしそれがわかれば、ドット絵制作の幅は広がるのではないかと私は考えています。たとえば、下記のようなことができるようになるでしょう。

- EDGE2形式のファイルを別の画像フォーマット（png, gif, gal, psdなど）にEDGE2を使わずに変換できる
- 別の画像フォーマットをEDGE2を使わずにEDGE2形式に変換できる
- EDGE2ファイルを別のフォーマットに変換せずに直接ゲーム素材として読み込み利用できる
- EDGE2を使わずにEDGE2ファイルの各種加工ができる
    - 拡大・縮小・回転
    - ページアニメーションの抽出や結合、フレーム数の変更
    - レイヤーの抽出や結合
    - パレットの抽出や結合、変換
    - etc...

ちなみに、EDGE2からgifやpsdに変換するソフトはすでにありまして、[gizac](http://heriet.info/software/gizac/) という名前で公開しています。また、現在この gizac の次期開発版をつくっていたりするのですが、それはまた別の機会に紹介できればとおもいます。

## EDGEファイルの中身を見てみる

さて、EDGE形式の詳細を説明する前に、EDGEファイルの中身をぱっとみてみましょう。まず、EDGE2で保存したEDGE形式のファイルをテキストエディタで開いてみます。

```
EDGE2:x��SKKA���.�fg�
9IN{���M�[B  ��K   ɪI�����K@����d�ꮝ�dR�;��o���j��C��̥����sq��
W�̉���|wI���p��fl@l��x��r��3��Z�TӦ;�����hPE'��v_����!4&ɞ/�Zِ�v�YQ�e�3S��XK,�@amB�T2IF��p�!�	- 18��4��CF�5��k�`r�ާryȐLF�����q>u���FӺ/���<� ^�RO�E"3yd�H�(�9�<�aXG�S�Ϲ�f=դ��~[�
!H��=ۖfmW*��˨��{��9�����O�\��d}
��\�>?��{x�
�{���������h�9=�o.ͷwn7?v��jo����z���h���f���:���t�ۯ;'�ws�F�|㧦zS;�ZU�FWX�Ǫ>��̗�
```

当然ながら、EDGE形式は画像のバイナリデータとなっているので、テキストエディタで開いてもなにがなにやらわかりません。しかし、1つだけわかることがあります。そう、ファイルの1行目だけ「EDGE2」と読み取ることができますね。これは、EDGE2形式に必ず設定されているヘッダ情報です。
このヘッダ情報があるおかげで、このファイルを開いたとき、EDGE2の画像データであることがソフトウェアから簡単に判別できるようになります。ちなみに、EDGE形式にかぎらず、多くの画像フォーマットでは同様のヘッダが仕様として定められていることが多いです。たとえば、GIFファイルも最初にかならずテキストの「GIF」が設定されています。

テキストではヘッダ以外よくわからないことがわかったので、次にバイナリデータをみてみましょう。ドット絵描きの皆さんであればお手持ちの適当なバイナリエディタなどで開いてください。（注：このへんからよくわからない人にはよくわからない説明になっていくと思うので、適度に読み飛ばしてください）

```
$ xxd -g 1 sample.edg
00000000: 45 44 47 45 32 00 00 01 3a 04 00 00 78 9c ad 53  EDGE2...:...x..S
00000010: 4b 4b 1c 41 10 ee ea 9a d9 2e bb 66 67 fc 0d 39  KK.A.......fg..9
00000020: 49 4e 7b f4 98 8b b7 08 01 f1 ae 07 cd 4d c4 5b  IN{..........M.[
00000030: 10 42 20 7f 20 e0 c9 4b 20 7f 20 20 01 c9 aa 49  .B . ..K .  ...I
00000040: 04 c1 b3 c9 ee d1 4b 40 c4 f5 b1 8f 64 ef 9b ea  ......K@....d...
（略）
```

うーん。バイナリの中身を見てみましたが、やっぱりなんだかよくわかりませんね。この中に、画像のピクセルの情報や、パレットの情報が並んでいるはずなのですが…。たとえば、一般的に真っ白のパレットの情報をもつ画像であれば、どこかに `FF FF FF` （カラーコードでいうところの `#FFFFFF`）と並んだデータが存在するはずだと推測できます。が、それはEDGE形式のバイナリ上、見当たりません。

もし、バイナリを読むことになれている勘のいい方（ドット絵とはあまり関係の無いスキル）をお持ちのかたであれば、 1行目に `78 9c` が含まれていることに気がつくかもしれません。そう、EDGE形式のデータは Deflate で圧縮されているのです。 `78 9c` といえば、Deflate圧縮の際に必ず付与されるヘッダであることはあまりにも有名ですよね。たとえば、png形式もDeflate圧縮が使われているため、同様のバイナリ列を見つけることができます。

圧縮形式はわかったので、あとはこれを展開してあげると、やっとピクセルやパレットの情報が詰まったデータを得ることができます。この展開したデータは、後述するチャンクと呼ばれる構造をしています。チャンク構造であることさえわかれば、あとはEDGEファイルを少しずつ変更しながらバイト列を見比べることで、どのチャンクのどの部分にピクセルやパレットなどの情報が格納されているかがわかります。

データ差分を見比べていく作業は地味なので省略して、以下にEDGE形式の仕様として推測されるものを記述していきます。

## EDGE形式（EDGE2）

### 基本的な構成

EDGE形式は下記のデータ構成になっています。なお、各項目の区分けや項目名は著者が独自に解釈したものであり、公式の仕様とは異なる可能性があります。

|項目|サイズ|解説|
|---|---|---|
|ヘッダ部|8 byte|EDGE2ファイルであることを示すヘッダ|
|データ部の展開後のサイズ|4 byte|データ部を展開（Inflate）した後のサイズ|
|データ部|可変長|Deflate圧縮されたデータ|

さて、ここで気がつくのは、データ部の展開後のサイズが4byteであることです。つまり、この展開後のサイズの最大値はたかだか 2^32 - 1 = 4,294,967,295 バイト ≒ 約4.3GB ということです。EDGE2形式ではおそらく約4.3GB以上のデータを保存できないということが推測されます。ただ、これはドット絵が必要とするデータ量に対して非常に大きなもので、問題にはならないでしょう。

しかし、もしかすると約4.3GB以上のデータを保持する場合、このデータ部が分割されて保存される可能性はありえます。検証として、EDGE2で巨大なキャンバスサイズ×相当数のページ数のファイルを保存しようとしてみたのですが、巨大すぎてEDGE2がエラー落ちしてしまいました。そのため、実際のところ約4.3GB以上のデータ量になったときどうなるかは不明です。

ちなみに、EDGE形式内ではバイトオーダーは常にリトルエンディアンになっています。（バイトオーダーの概念を知っていてバイトオーダーが気になる人向け情報）

### ヘッダ

おそらく常に `45 44 47 45 32 00 00 01` の8 byteが設定されます。最初の5 byteはASCIIで「EDGE2」のテキストになります。

`00 00 01` の意味は未知ですが、著者の知る限りでは常に固定です。 `00 00 01` 以外になっている EDGE形式 ファイルをお持ちの方がもしいれば、教えてください。

### データ部

Deflate圧縮されています。展開後のデータ部は複数のチャンクで構成されています。（チャンクという名前は、pngが同様の構造をチャンクと呼んでいるため、ここでもチャンクと呼んでいます）

|項目|サイズ|解説|
|---|---|---|
|チャンク|可変長|チャンク構造のデータ|
|…|…|…|
|チャンク|可変長|チャンク構造のデータ|

すべてのチャンクは下記の構成になっています。

|項目|サイズ|解説|
|---|---|---|
|チャンクID|2 byte|チャンクの種類を示すID|
|チャンクサイズ|4 byte|チャンクデータ部のサイズ|
|チャンクデータ部|可変長|チャンクのデータ|

たとえば、チャンクID: 1008 はビット深度（1 byte）をデータとして保持するチャンクです。例として、ビット深度が8bit（256色）のとき、チャンクのバイナリは下記の7byteになります。

`E8 03 01 00 00 00 08`（※ `0x03e8 = 1000`）

また、特定のチャンクは、入れ子になっています。つまり、特定のチャンクのチャンクデータ部が、さらに別の複数のチャンクになっていることがあります。たとえば、チャンクID: 3008 は、そのチャンクデータ部の中にさらに チャンクIDが1000, 1001, 1002, 1003, 1004 のチャンクで構成されています。以後、入れ子なっているチャンクIDについて、たとえば 3008の中にある 1000 チャンクのIDを `3008->1000` と表記します

#### 2003チャンク（ページチャンク）

ページチャンクは、EDGE2におけるページのデータを格納しています。1つのページチャンクにつき、1ページ分のデータが格納されています。複数のページが存在する場合、ページチャンクも複数存在します。ページの順番に応じてページチャンクも並べられており、最初に出現するページチャンクは1ページ目に相当します。

ページチャンク内のデータは、さらに複数のチャンクが格納されています。特に大事なのは、ページチャンクの中には複数のレイヤーチャンクが含まれることでしょう。ページには必ず1つ以上のレイヤーチャンクが含まれます。

ページチャンク内のチャンクは下記のとおりです。

|チャンクID|サイズ|解説|
|---|---|---|
|2003->1000|可変長|ページ名|
|2003->1005|2 byte|ページのキャンバス横幅|
|2003->1006|2 byte|ページのキャンバス縦幅|
|2003->1008|4 byte|ページで使用しているパレットバンクインデックス|
|2003->2003|可変長|レイヤーチャンク|
|2003->3000|4 byte|ページアニメーション用 フレーム数|
|2003->3001|1 byte|ページアニメーション用 透過|
|2003->3002|1 byte|ページアニメーション用 表示後|
|2003->3003|5 byte|ページアニメーション用 x座標(4 byte) と x座標相対フラグ(1 byte)|
|2003->3004|5 byte|ページアニメーション用 y座標(4 byte) と y座標相対フラグ(1 byte)|
|2003->3005|1 byte|ページアニメーション用 アニメーションに使用するフラグ|

※ 他にも上記に記載していない未解明のチャンクが存在します

#### 2003->2003（レイヤーチャンク）

レイヤーチャンクは、EDGE2におけるページのデータを格納しています。1つのレイヤーチャンクにつき、1ページ分のデータが格納されています。複数のページが存在する場合、レイヤーチャンクも複数存在します。ページの順番に応じてレイヤーチャンクも並べられており、最初に出現するレイヤーチャンクは一番上のレイヤーに相当します。

レイヤーにおける画像データは、イメージチャンクに収められています。

レイヤーチャンク内のチャンクは下記のとおりです

|チャンクID|サイズ|解説|
|---|---|---|
|2003->2003->1000|可変長|レイヤー名|
|2003->2003->1002|1 byte|子フラグ|
|2003->2003->1005|1 byte|可視フラグ|
|2003->2003->1006|可変長|イメージチャンク|
|2003->2003->1007|1 byte|ロック|

他にも上記に記載していない未解明のチャンクが存在します。レイヤーアニメーションとか。

#### 2003->2003->1006（イメージチャンク）

イメージチャンクには、画素のデータが詰められています。画素のデータはパレット番号に対応した 1 byteのデータです。たとえば、イメージチャンクの最初の1byteは、画像の最も左上である [0,0]位置のパレット番号の値になります。イメージチャンクのデータサイズは 画像サイズ（高さ×幅）のbyte数と等しくなるはずです。

|項目|サイズ|解説|
|---|---|---|
|画素|1 byte|画素のパレット番号|
|…|…|…|
|画素|1 byte|画素のパレット番号|

えっ？ EDGE2はパレットカラーだけじゃなく、フルカラーも対応しているって？あー。うん。そう言われればそうですね…。えーと、その時は、どうなってるんでしょうね〜。（まだ未解明です）

#### 3003チャンク（パレットチャンク）

パレットチャンクは、パレットに関する情報が含まれています。EDGE2にはパレットの設定が多くあり、そのほとんどの対応は現在のところ未解明です。ただし、 `3003->1005` チャンクの中に実際のパレットの色情報が詰められていることがわかっています。

EDGE2のパレットバンク機能で複数のパレットを保持しているばあい、パレットチャンクも複数存在しています。その場合、パレットバンク番号順にパレットチャンクが格納されています。

#### 3003->1005チャンク（パレットカラーチャンク）

パレットカラーチャンクには、パレットの色情報がRGB形式で格納されています。EDGE2ではRDBの他にHSV, HSL, YMCでパレットカラーを操作することができますが、内部的保持している値はRGBのみのようです。なお、EDGE2内部ではおそらくuint24形式で保持されているのか、Blue, Green, Redの順でそれぞれ1 byteずつ保持されています（リトルエンディアンなので）。

EDGE2 の仕様上、パレットサイズは変更可能なため、このチャンクは2〜256 byteまで可変になると思われます。

|項目|サイズ|解説|
|---|---|---|
|パレットカラー|3 byte|RGBカラー（Blue, Green, Redの順）|
|…|…|…|
|パレットカラー|3 byte|RGBカラー（Blue, Green, Redの順）|


## まとめ

EDGE2のEDGE形式について、その構造を一部紹介しました。普段使われているEDGE2の情報が、どのようにPC上に保存されているのか、なんとなく伝えられたかとおもいます。もしくは、さっぱりよくわからなかった、という方も多いかもしれませんが、この構造自体はあまりドット絵を描くスキルにほとんど関係しないので、忘れていただいてもいいと思います。

EDGE2形式において、今回紹介できていないチャンクや、未解明のチャンクも多くあります。チャンク情報の解析は、時間をかければできるものも多いのですが、解析作業が地味過ぎてあまり進んでいないのが実情です…。

現在、gizacの次期開発版をつくりながら、未解明のチャンクについても解析をすすめているところです。より解明が進んだ頃に、何かしらの形でまた情報を公開できればと思います。