透過を指定するアドレスを発見&サムネイル抽出

ページ透過

ページの透過情報を探してみた。透過のみ違わせたメモを4つ用意して確認してみた。
Stirlingで比較したところ、タイムスタンプを格納してある「0x009A」、チェックサムが格納されている「0x0964」以下以外に、もう一箇所だけ違う部分があった。
それは0x06A6。1byteだけ違う。

上から、両方見える、上だけ、下だけ、両方見えない。
疑う余地なくここだ!確実にここだ!!

Wikiのほうにはココのアドレスは、アニメーションセクションのUnKnowとなっていた。バージョン2から使うようになったのだろう。

上紙を隠す場合下のビットを、下紙を隠す場合、上のビットをオンにするようですね。

サムネイルを取得

とりあえず、サムネイル解析に入る。

Wikiからの情報に従って、変換する。

static Color[] PalletEntries = {Color.White,Color.DimGray,Color.White,Color.DarkGray,Color.Red, Color.DarkRed , Color.Pink,
                                Color.Green,Color.Blue,Color.DarkBlue,Color.LightBlue,Color.Green,Color.Purple,Color.Green,Color.Green,Color.Green};
Bitmap GetPreviewImage(byte[] bin)
{
 GCHandle gh = GCHandle.Alloc(bin, GCHandleType.Pinned);
 IntPtr pointer = gh.AddrOfPinnedObject();
 Bitmap bmp = new Bitmap(64, 48);
 Graphics g = Graphics.FromImage(bmp);
 pointer = new IntPtr(pointer.ToInt32() );
 for (int i = 0; i < (6 * 8); i++)
 {
  Bitmap tmp = new Bitmap(8, 8, 4, PixelFormat.Format4bppIndexed, pointer);
  
  /*Bitmap tmp = new Bitmap(8,8,PixelFormat.Format4bppIndexed);

    BitmapData bd = tmp.LockBits(new Rectangle(0, 0, 8, 8), ImageLockMode.WriteOnly, PixelFormat.Format4bppIndexed);
    Marshal.Copy( bin, i * 32, bd.Scan0 , 32);
    tmp.UnlockBits(bd);
    */
    ColorPalette cp = tmp.Palette;
    for (int j = 0; j < PalletEntries.Length; j++)
    {
     cp.Entries[j] = PalletEntries[j];
    }
    tmp.Palette = cp;
    g.DrawImage(tmp, (i % 8) * 8, (i / 8) * 8);
    pointer = new IntPtr(pointer.ToInt32() + 32);
    }
   gh.Free();
   return bmp;
 }

それで、取得したものがこちら。

う〜む、若干違和感を覚える。
完全ではないらしい。

コメントアウトしてある部分のやり方も試したが、同じでした。

いったいなぜ・・・
よく見ると、1つづつ入れ替わっているのがわかります。
・・・ということは!上位ビットと下位ビットを反転!

ーーーーーーーキターーーーーーーーーー(゚∀゚)ーーーーーーーーーーーー
やっとできた!これに数時間かかったぞ!バカヤロウ!
で、完全なソースこれにサムネイルの1536byteの大きさの配列を渡せば画像が帰ってきます☆
カラーパレットもWikiにあわせて変更してみました

 static Color[] PalletEntries = {Color.White,Color.FromArgb(0x52,0x52,0x52),Color.White,Color.FromArgb(0xA4,0xA4,0xA4),Color.Red, Color.FromArgb(0x7B,0,0) , Color.FromArgb(0xFF,0x7B,0x7B),

Bitmap GetPreviewImage(byte[] bin)
{
 GCHandle gh = GCHandle.Alloc(bin, GCHandleType.Pinned);
 IntPtr pointer = gh.AddrOfPinnedObject();
 Bitmap bmp = new Bitmap(64, 48);
 Graphics g = Graphics.FromImage(bmp);
 pointer = new IntPtr(pointer.ToInt32());
 for (int i = 0; i < 6 * 8 * 32; i++)
  {
   int tmp = bin[i] & 0x0F;
   bin[i] = (byte)(bin[i] >> 4);
   bin[i] |= (byte)(tmp << 4);
  }

  for (int i = 0; i < (6 * 8); i++)
   {
    Bitmap tmp = new Bitmap(8, 8, 4, PixelFormat.Format4bppIndexed, pointer); 
    ColorPalette cp = tmp.Palette;
    for (int j = 0; j < PalletEntries.Length; j++)
    {
     cp.Entries[j] = PalletEntries[j];
    }
  tmp.Palette = cp;
  g.DrawImage(tmp, (i % 8) * 8, (i / 8) * 8);
  pointer = new IntPtr(pointer.ToInt32() + 32);
  }
  gh.Free();
  return bmp;
  }

いや〜、カラーパレットの設定とビット交換に気づくのに一日かかったわ。
プログラムって難しい。

アニメーションセクションのほうにも挑戦しようとしたけど、あえなく撃沈。
英語が読めないんだもん!
気が向いたら続きをやろう。