BakuretuKen99 フォーマット解析
- 独自解析結果。おそらくバージョン依存?
- 無保証。
- このドキュメント自体がそもそも要解析かも…。
データ個数.サイズ |
値 |
備考 |
ヘッダ部 (ファイル先頭から、この順にデータが並ぶ) |
1.w |
N1 (== 13) |
次のブロックサイズ |
N1.s |
"BakuretuKen99" |
識別文字列? |
1.w |
N2 (== 17) |
次のブロックサイズ |
N2.s |
"BakuretuConv99v10" |
作成ユーティリティ識別文字列? |
1.l |
P1 |
パレット数 |
1.b |
0x00 |
透過フラグ。透過色がない場合は 0 、透過の時は 1 (詳細不明) |
1.l |
0x00000000 |
透過するパレットの番号 (1〜 透過しない場合は0) (詳細不明) |
4.b |
Flag R G B |
パレット1の色 (Flag はFFの時通常色、00の時透過色) |
4.b |
Flag R G B |
パレット2の色 (同上) |
… |
… |
… |
4.b |
Flag R G B |
パレットP1の色 |
1.l |
X |
Xピクセルサイズ |
1.l |
Y |
Yピクセルサイズ |
1.l |
N3 |
以降のデータ部のブロックサイズ(バイト) |
データ部 (ファイル末尾まで以下いずれかのブロックの繰り返し) |
1.b |
N4 |
パレット番号を「(ひとつ前のパレット番号 + N4) mod 256」に変更後、1ドット描画 |
2.b |
0x80 N5 |
相対パレット番号が 0 (0x80) の時、ひとつ前のパレット番号のドットを N5 個描画 |
- データサイズは
- .b … バイト (1バイト == 8ビット)
- .w … ワード (2バイト)
- .l … ロングワード (4バイト)
- .s … 文字列 (1バイト×文字列長)
- リトルエンディアン (たぶん)
- データ分は実際には各バイトそれぞれ、 0x80 で xor を取った値。(符号なし数)
- データブロックの一番先頭は必ず 0x80 (パレット番号1の色で1ドット描画)
BakuretuKen99 から BMP への変換スクリプト (Perl)
# K99 から BMP へ (テスト版)
use strict;
my ($src, $dst) = @ARGV;
if (! $src) {
usage();
}
if (! $dst) {
($dst = $src) =~ s/\.k99$/\.bmp/i;
}
open my $in, '<', $src or die "$!: $src file open err.";
#↓WindowsのActive Perlの時は必要
#binmode($in);
open my $out, '>', $dst or die "$!: $dst file open err.";
#↓WindowsのActive Perlの時は必要
#binmode($out);
my ($bf, $s);
read $in, $bf, 2;
$bf = unpack "n", $bf;
read $in, $s, $bf;
die "format err 1" if $s ne "BakuretuKen99";
read $in, $bf, 2;
$bf = unpack "n", $bf;
read $in, $s, $bf;
die "format err 2" if $s ne "BakuretuConv99v10";
read $in, $bf, 4;
my $palet_max = unpack "N", $bf;
read $in, $bf, 1;
my $trans_f = unpack "C", $bf; #透過フラグ 使わず
read $in, $bf, 4;
my $trans_no = unpack "N", $bf; #透過パレット番号 使わず
my @palet;
for my $i (0 .. ($palet_max - 1)) {
read $in, $bf, 4;
my ($f, $r, $g, $b) = unpack "CCCC", $bf;
$palet[$i] = ($b << 16) + ($g << 8) + $r; # BMP は BGR の順
}
read $in, $bf, 4;
my $px = unpack "N", $bf;
read $in, $bf, 4;
my $py = unpack "N", $bf;
read $in, $bf, 4;
my $data_size = unpack "N", $bf;
my $pal_idx = 0;
read $in, $bf, 1;
--$data_size;
$bf = unpack "C", $bf;
warn "first data err?" if $bf != 0x80;
my @data = ($palet[$pal_idx]);
while ($data_size > 0) {
last if read($in, $bf, 1) != 1;
last if --$data_size < 0;
my $pal = unpack "C", $bf;
$pal ^= 0x80;
if ($pal == 0) {
last if read($in, $bf, 1) != 1;
last if --$data_size < 0;
my $len = unpack "C", $bf;
$len ^= 0x80;
for (1 .. $len) {
push @data, $palet[$pal_idx];
}
} else {
$pal_idx = ($pal_idx + $pal) & 255;
if ($pal_idx >= $palet_max) {
warn "palet err?";
}
push @data, $palet[$pal_idx];
}
}
close $in;
my @linebf;
my $lx = $px * 6;
for my $y (reverse 0 .. ($py - 1)) {
my $bf;
for my $x (0 .. ($px - 1)) {
$bf .= sprintf "%06x", shift @data;
}
$linebf[$y] = pack "H$lx", $bf;
}
select $out;
# header
# marker
print "BM";
# ファイルサイズ
print pack "V", 3 * $px * $py + 0x36;
# 予約
print pack "v", 0;
# 予約
print pack "v", 0;
# ファイル内データのオフセット (パレットがなければ 0x36)
print pack "V", 0x36;
# 以下ヘッダ
# ヘッダサイズ (0x28)
print pack "V", 0x28;
# ビットマップ幅
print pack "V", $px;
# ビットマップ高さ
print pack "V", $py;
# デバイス面数 (1)
print pack "v", 1;
# ピクセルあたりビット数 (色深度)
print pack "v", 24;
# 圧縮形式:0=なし
print pack "V", 0;
# データ容量
print pack "V", 3 * $px * $py;
# 水平解像度 (72dpi =~ 2834dpm)
print pack "V", 2834;
# 垂直解像度 (72dpi =~ 2834dpm)
print pack "V", 2834;
# カラーインデックス数
print pack "V", 0;
# ?
print pack "V", 0;
for (my $y = 0; $y < $py; $y++) {
print $linebf[$y];
}
close $out;
sub usage {
print <<EOT;
BakuretuKen99(.k99) を BMP に変換
source [destination]
destination 省略時は source の拡張子を .bmp に置き換えたファイル名 (ex. foo.k99 -> foo.bmp)
EOT
}
戻る