猫星人 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 個描画

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
}

戻る