抽出作業、進行中。
今回も少し変でも気にしない
他のメモでもテストを行った。
その結果、違うデータとおもわれるものが入る場合と、入らない場合があるっぽい。
さらに、
---------------- <= 横直線(高さ1px)
<= たての縞々(高さ1px) |
---------------- <= 横直線(高さ1px)
という画像を検証してみた。
結果、Coded、RawLineDataCodedとなった。RawLinDataCodedは、生データのよう。
Codedは、行全体が塗りつぶされた場合かもしれない。
のようなものも、RawLineData、RawLineDataになった。
その後の0x070Dからは0xAAが続く。
0xAAは、10101010なので、これがやはり実データのようだ。
また、最初の例の場合、続く長さは32byte。1byteに8ピクセルを格納できるため、32*8=256。画面の横幅と同じ。長さ的にもちょうどよい。
ここでは、Wikiにあるようにビットを入れ替える必要がある。
とりあえず、かなりシンプルな絵の場合に読み込みが成功することを確認。
InvertedCodedLineの考察1
厄介なのが、これ。InvertedCodedLine。
意味もよくわからない。
かなりの数のメモでこれが出没する。
たよりのwikiによると、ヘッダ情報が4byteあるとか。
とりあえず、4byte読む。
[0]: 192
[1]: 255
[2]: 1
[3]: 0
16進にすると、
[0]: 0xc0
[1]: 0xff
[2]: 0x01
[3]: 0x00
2進にすると、
[0]: 11000000
[1]: 11111111
[2]: 00000001
[3]: 00000000
よくわからんの。
wikiをみると、0x80000000がフラグか何かに使われているのでは?と思う。
でも、結局わからん。
PPM.pyの解析
この解析には先駆者がいる。
pbsds's blog
pythonで書かれている。
pythonはインタプリタこそどこかに入れたと思うが、まったくわからない。
でも、これ以上の解析するには、もっと頭のいい人が解析したものをパクって参考にさせていただかなければなるまい。
ということで、時間をかけつつPPM.pyにコメントを振っていく。
その結果、なんとなくつかむことができた。
解析の途中で気がついたのはこの部分。
MovePrevFrame = (ord(self.File[Offset]) >> 5) & 0x03 #上と同じく。上位3,4bit目かもしれぬ。 FrameMove = [0,0] #0,0の入った長さ2の配列(リスト) if MovePrevFrame & 2: #次のフレーム情報の0b10をの場所を取得。 FrameMove[0] = (ord(self.File[Offset+2])>>8)|ord(self.File[Offset+1])-256 #エンディアンをひっくり返してあわせたものから256を引く。 Offset += 2 if MovePrevFrame & 1: FrameMove[1] = (ord(self.File[Offset+2])>>8)|ord(self.File[Offset+1])-256 Offset += 2
ここは、1byteの長さのフレーム情報を読み込んでいるところ。
しかし、ここでなぞが。前に書いたがんばってPPMファイルのフォーマットを翻訳してみた - NoMeaningをみると、
開始ビット | 長さ | 説明 |
---|---|---|
00 | 1 | 新しいフレーム |
01 | 2 | 不明 |
03 | 2 | レイヤー2 |
05 | 2 | レイヤー1 |
07 | 1 | 紙 |
となっている。このMovePrevFrameのところは、UnKnowになっていたのだ。
しかし、実際は入っている。wikiよりソースが正確なはずなので、考える。名前からして、前のフレームを動かした、だろう。
そういえば、id:bricklifeさんの、2009-01-23 - bricklifeの日記 - うごメモはてな部の日記を思い出しました。
「元画像をXY方向に動かすオプションがある」とのことです。これではないでしょうか・・・
んで、作業を進める。ほとんど、PPM.pyの翻訳作業に近い。pythonってインデントを重視する言語だっけなぁとか、リストリスト内包表記はLINQっぽいものかとか、rangeでforをやるんだとかやっているうちに、なんとなくいい感じに。
現状の画像。
最初のは、いつもどおりフリップノートマリオ、2つ目は自作の①と書いてあるだけの画像。
いい感じじゃね!?
まだ上下が変だけど、かなり可読性があがっている。
まだ前のページとのXOR差分のところを書いていないので、そこを書けばもう少し精度が上がるはず。あとは、なぜかメモによって本アニメデータの開始アドレスが違うような気がする。
おまけ
ちなみに、現在、これが私が作成したメモのフレームの情報を取得するクラスです。
まだ画像の取得はできません。InfoByteに、1byteのページ情報を入れてください。
class MemoPage { public byte InfoByte { get; set; } public byte[] Layer1 { get; set; } public byte[] Layer2 { get; set; } /// <summary> /// 前のフレームを継承しているか /// </summary> public bool NewFrame { get { return ((InfoByte >> 7) & 0x01) != 0; } } /// <summary> /// 詳細不明 /// </summary> public bool MovePrevFrame { get { return ((InfoByte >> 5) & 0x01) != 0; } } /// <summary> /// 上紙の色 /// </summary> public LayerColor Brush1 { get { return (LayerColor)((InfoByte >> 3) & 0x03); } } /// <summary> /// 下紙の色 /// </summary> public LayerColor Brush2 { get { return (LayerColor)((InfoByte >> 1) & 0x03); } } /// <summary> /// trueだと白。falseだと黒。 /// </summary> public bool Paper { get { return (InfoByte & 0x01) != 0; } } /// <summary> /// ラインコードを取得します /// </summary> /// <param name="UnderLayer">下紙(Layer1)の場合にtrue</param> /// <param name="num">ラインコードを取得する行を指定します。これは0から始まります。</param> /// <returns>行のラインコード</returns> public LineCode GetLineCode(bool UnderLayer, int num) { if (UnderLayer) return (LineCode)(((Layer1[num / 4] << ((num % 4) * 2)) & 0xC0) >> 6); else return (LineCode)(((Layer2[num / 4] << ((num % 4) * 2)) & 0xC0) >> 6); } }
他のソースは完成後に公開予定。今ほしい人は言ってくれれば出します。
やった!解析の精度が格段にアップ!!!!
これが前回。
そして、前のページとのXOR差分を実装しました。
それでもうまくいかなかったんですが、フレームのアドレスを取得する際、オフセットテーブルのサイズを足し算するのを忘れていました。
それを足したところ・・・
キター!ー!−!−!−(゚∀゚)ー!−!−!−!−!−
それでも、まだぶれます。
先頭のページはまだこう。
かなりぐちゃぐちゃですが、単に位置がずれているだけです。
もう少し修正を加えれば、できると思います。さて、どこを修正すればいいのやら。
VisualStudioでステップインして細かく見ていくしかないか・・・?
あと、時間がかかりすぎるのも問題。別スレッドでしばらく待たせないといけないレベル。
結構無駄の多い設計なので、ラグを見つけて修正しなければ。やはり、画像をDrawImageで2回書いているのが遅いのか。
とすると、byte配列を引き伸ばさなければ・・・