ホーム 主筆 その他ソフト その他情報 Syuhitu.org English

Windows関連

スクリーンセーバー作成法

半透明ウインドウの性能

bootfont.bin

キャビネット形式

ウインドウスタイルをいじる

Java製ソフトをServiceに登録する

イベントログにメッセージを出力する

コントロールパネルにアイコンを追加する

スクリプトによる拡張1

スクリプトによる拡張2

ガジェットの作成

大容量メモリ

メモリ搭載量の下限に挑む

スパースファイルにする

表示されるアイコンの種類を調べてみた

メモリマップIOとエラー処理

ファイルを作る順番と速度の関係

Cryptography API: Next Generationを使う

Windows 10のアクセントカラー

iSCSIディスクにバックアップを取る

サーバプロセスを分離して実装する

サーバプロセスを分離して実装する - F#

レジストリに大量に書き込む

Solaris関連

OpenGL

Solaris設定

ディレクトリの読み込み

主筆プラグイン開発

マルチスレッドでの開発

door

音を出す

Blade100の正しい虐め方

パッケージの作成

画像入出力

BMPファイル

ICOファイル

ANIファイル

JPEGファイル

減色アルゴリズム

減色アルゴリズムの並列化

その他アルゴリズムなど

自由軸回転

Base64

文字列操作

CPU利用率の取得

正規表現ライブラリ

メタボールを作る

メタボールを作る2

正規表現とNFA・DFA

C言語の構文解析

液晶ディスプレイを解体してみた

iSCSIの理論と実装

単一フォルダにファイルを沢山作る

USB-HUBのカスケード接続

SafeIntの性能

VHDファイルのフォーマット

USBメモリに書き込み続けてみた

bootfont.binファイルの形式

2003年12月20日公開

WindowsNT/2000等ではブート時に表示する文字のためのフォントファイルとして「bootfont.bin」と言うものを用意しています。 

ここではそのbootfont.binというファイルの形式を説明し、プログラムから読み込んでみたいと思います。何の役に立つのかは解りませんが

はじめに

このファイルは起動ディスクのルートに格納されています。通常ならば「c:\」に存在します。 

しかし、このファイルは標準では表示されないようになっています。 表示するためにはフォルダオプションの「保護されたオペレーティング システム ファイルを表示しない(推奨)」という項目のチェックをはずす必要があります。 

そして、このチェックをはずすとなにやら警告が表示されますが、それにもめげずに「OK」を押すと、ようやく表示されます。

警告のメッセージ

当然ですが、警告が表示されると言うことは「危険な操作をしている」ということですから、 警告のメッセージを読むことができない人自分が何をしているか理解できない人は以下に書かれていることを実行しようとしないでください。 

また、当方では何が起きても一切責任は負えません。(こんなメッセージが表示されるようになったのは、きっと、窓を投げ捨ててしまう人が絶えなかったからなんだろうな。)

記録されている内容

このファイルは、主に以下のような構造のデータが記録されています。

  • ビットマップフォントです。 「文字の形状」は文字の部分は1・背景の部分は0で、上位ビットの方が左側となります。
  • 文字のサイズは、半角文字が縦16ドット×横8ドット、全角文字が縦16ドット×横16ドットです。
  • 文字の形状とそれに対応する文字コード番号が記録されています。
  • 文字コード番号はShiftJISです。
最近のアウトラインフォントに比較すればかなり貧相な内容ですが、 なにぶん使用されるのがブート時であり複雑な画像は表示できないのだからこれで事足りるのでしょう。

ヘッダ

このファイルには52バイトのヘッダが記録されています。しかし、ヘッダに何の内容が記録されているかは解りません。とりあえず読み飛ばしましょう。

半角文字

半角文字は以下の17バイトで記録されています。

例 「A(半角大文字のA・文字コード番号65」の場合。

データ(16進数) 内容
0x41 文字コード65(10進数)
0x00 □□□□□□□□
0x00 □□□□□□□□
0x18 □□□■■□□□
0x24 □□■□□■□□
0x42 □■□□□□■□
0x42 □■□□□□■□
0x42 □■□□□□■□
0x42 □■□□□□■□
0x7E □■■■■■■□
0x42 □■□□□□■□
0x42 □■□□□□■□
0x42 □■□□□□■□
0x42 □■□□□□■□
0x42 □■□□□□■□
0x00 □□□□□□□□
0x00 □□□□□□□□

上記のような文字が190文字記録されています。各文字のデータの間にはパディングなどは存在しないため、 そのまま連続して読み込むことができます。

全角文字

全角文字は以下の34バイトで記録されています。

例 全角「あ」(文字コード33440の場合)

データ(16進数) 内容
0x82 文字コードの上位バイト
0xA0 文字コードの下位バイト
0x01 □□□□□□□■(1行目左側)
0x00 □□□□□□□□(1行目右側)
0x01 □□□□□□□■(2行目左側)
0x00 □□□□□□□□(2行目右側)
0x1F □□□■■■■■(3行目左側)
0xFC ■■■■■■□□(3行目右側)
0x02 □□□□□□■□(4行目左側)
0x00 □□□□□□□□(4行目右側)
0x02 □□□□□□■□(5行目左側)
0x40 □■□□□□□□(5行目右側)
0x03 □□□□□□■■(6行目左側)
0xF0 ■■■■□□□□(6行目右側)
0x0E □□□□■■■□(7行目左側)
0x5C □■□■■■□□(7行目右側)
0x1A □□□■■□■□(8行目左側)
0x44 □■□□□■□□(8行目右側)
0x12 □□□■□□■□(9行目左側)
0xC6 ■■□□□■■□(9行目右側)
0x32 □□■■□□■□(10行目左側)
0x82 ■□□□□□■□(10行目右側)
0x22 □□■□□□■□(11行目左側)
0x82 ■□□□□□■□(11行目右側)
0x23 □□■□□□■■(12行目左側)
0x06 □□□□□■■□(12行目右側)
0x23 □□■□□□■■(13行目左側)
0x04 □□□□□■□□(13行目右側)
0x1C □□□■■■□□(14行目左側)
0x1C □□□■■■□□(14行目右側)
0x00 □□□□□□□□(15行目左側)
0x70 □■■■□□□□(15行目右側)
0x00 □□□□□□□□(16行目左側)
0x00 □□□□□□□□(16行目右側)

これではなんだかよく解らないので、横に2バイトずつ並べます。

□□□□□□□■ □□□□□□□□
□□□□□□□■ □□□□□□□□
□□□■■■■■ ■■■■■■□□
□□□□□□■□ □□□□□□□□
□□□□□□■□ □■□□□□□□
□□□□□□■■ ■■■■□□□□
□□□□■■■□ □■□■■■□□
□□□■■□■□ □■□□□■□□
□□□■□□■□ ■■□□□■■□
□□■■□□■□ ■□□□□□■□
□□■□□□■□ ■□□□□□■□
□□■□□□■■ □□□□□■■□
□□■□□□■■ □□□□□■□□
□□□■■■□□ □□□■■■□□
□□□□□□□□ □■■■□□□□
□□□□□□□□ □□□□□□□□

ここで気をつけなくてはいけないのは、上位バイトが先に記録されていると言うことです。 つまり、リトルエンディアンの環境で2バイトまとめて読み込むと、上位バイトと下位バイトが入れ替わってしまうと言うことです。 そのため、読み込むときは1バイトずつ読み込み、8ビットシフトするようにしてください。

プログラム

以上を踏まえて、bootfont.binを読み込むプログラムを作成してみたいと思います。

#include <stdio.h>
#include <stdlib.h>

// 半角文字の1文字分の情報を保持する
typedef struct tagChr8
{
	char n;	// 文字コード
	char c[16];	// 形状
} CHR8;

// 全角文字の1文字分の情報を保持する
typedef struct tagChr16
{
	short n;	// 文字コード
	short c[16];	// 形状
} CHR16;

// 半角文字を1文字分表示する
void p8( CHR8 *c )
{
	int i;
	int j;
	printf ( "CharNum = 0x%02X\n", c->n );
	for ( i = 0; i < 16; i++ ) {
		for( j = 0; j < 8; j++ )
			printf( "%s", ( c->c[i] << j ) & 0x80 ? "■" : " " );
		printf( " : 0x%02X\n", c->c[i] );
	}
}

// 全角文字を1文字分表示する
void p16( CHR16 *c )
{
	int i;
	int j;
	printf ( "CharNum = 0x%08X\n", c->n );
	for ( i = 0; i < 16; i++ ) {
		for( j = 0; j < 16; j++ )
			printf( "%s", ( c->c[i] << j ) & 0x8000 ? "■" : " " );
		printf( " : 0x%04X\n", c->c[i] );
	}
}

int main()
{
	int i;
	int j;
	unsigned int c;
	CHR8 v8[256];	// 半角文字の情報を保持する領域
	CHR16 *v16;
	FILE *infile;

	// ファイルを開く
	infile = fopen( "c:\\bootfont.bin", "rb" );
	// 全角文字の情報を保持する領域を確保する
	v16 = (CHR16*)calloc( sizeof( CHR16 ), 65536 );

	// 52バイトのヘッダを読み飛ばす
	for ( i = 0; i < 52 && !feof( infile ); i++ )
		getc( infile );

	// 190文字の半角文字を入力する
	for ( i = 0; i < 190 && !feof( infile ); i++ ) {
		// 文字コード(1バイト)を取得
		c = getc( infile );
		v8[c].n = c;
		// 文字の形状(8バイト)を取得
		for ( j = 0; j < 16 && !feof( infile ); j++ )
			v8[c].c[j] = getc( infile );
	}

	// ファイルの終端まで、全角文字の情報を取得する
	for ( i = 0; i < 65536 && !feof( infile ); i++ ) {
		// 文字コード(2バイト)を取得
		c = getc( infile );
		c =  ( c << 8 ) + getc( infile );	// リトルエンディアンのため
		if ( c < 65536 ) {
			v16[c].n = c;
			// 32バイトの文字の形状を取得
			for ( j = 0; j < 16 && !feof( infile ); j++ ) {
				v16[c].c[j] = getc( infile );
				v16[c].c[j] = ( v16[c].c[j] << 8 ) + getc( infile );
			}
		}
	}
	// ファイルを閉じる
	fclose ( infile );

	c = getchar();
	while ( EOF != c ) {
		if ( c >= 0x81 && c <= 0x9F || c >= 0xE0 && c <= 0xEF ) {
			// 全角文字
			c = ( c << 8 ) + getchar();
			p16( &(v16[ c ]) );
		}
		else {
			// 半角文字
			p8( &(v8[ c ]) );
		}
		c = getchar();
	}

	return 0;
}

このプログラムでは、bootfont.binを読み込み、配列の「文字コード」番目にデータを格納しています。 そして、標準入力から文字を読み、その文字の形状を標準出力に書き出します。

なお、VBで記述すると以下の通りです。

Option Explicit

' 半角文字の情報を保持する
Public Type CHR8
    n As Long
    c(16) As Long
End Type

' 全角文字の情報を保持する
Public Type CHR16
    n As Long
    c(16) As Long
End Type

' 半角文字の出力用の文字列を合成する
Public Function p8(ByRef r As CHR8) As String
    Dim i As Long
    Dim j As Long

    p8 = "CharNum = &H" + Hex(r.n) + vbCrLf
    For i = 0 To 15
        ' 上位ビットから順に1か0かを判定する
        For j = 0 To 7
            If (r.c(i) * (2 ^ j)) And &H80 Then
                p8 = p8 + "■"
            Else
                p8 = p8 + "□"
            End If
        Next
        p8 = p8 + " : &H" + Hex(r.c(i)) + vbCrLf
    Next
End Function

' 全角文字の出力用の文字列を合成する
Public Function p16(ByRef r As CHR16) As String
    Dim i As Long
    Dim j As Long

    p16 = "CharNum = &H" + Hex(r.n) + vbCrLf
    For i = 0 To 15
        ' 上位ビットから順に1か0かを判定する
        For j = 0 To 15
            If (r.c(i) * (2 ^ j)) And Abs(CLng(&H8000)) Then
                p16 = p16 + "■"
            Else
                p16 = p16 + "□"
            End If
        Next
        p16 = p16 + " : &H" + Hex(r.c(i)) + vbCrLf
    Next
End Function

Public Sub main()
    Dim v8(256) As CHR8
    Dim v16(65535) As CHR16
    Dim c As Long
    Dim i As Long
    Dim j As Long
    Dim s1 As String
    Dim s2 As String

    Open "c:\bootfont.bin" For Binary Access Read As #1
    c = AscB(InputB$(52, #1))   ' 52バイトのヘッダを読み飛ばす

    ' 半角文字(190文字)の情報を取得
    i = 0
    While Loc(1) < LOF(1) And i < 190
        c = AscB(InputB$(1, #1))    ' 文字コードを取得
        v8(c).n = c
        ' 形状のデータを取得
        For j = 0 To 15
            v8(c).c(j) = AscB(InputB$(1, #1))
        Next
        i = i + 1
    Wend

    ' 全角文字の情報を取得
    While Loc(1) < LOF(1)
        c = AscB(InputB$(1, #1))    ' 文字コードを取得
        c = c * 256 + AscB(InputB$(1, #1))
        v16(c).n = c
        ' 形状のデータを取得
        For j = 0 To 15
            v16(c).c(j) = AscB(InputB$(1, #1))
            v16(c).c(j) = v16(c).c(j) * 256 + AscB(InputB$(1, #1))
        Next
    Wend

    Close #1

    s1 = InputBox("文字列") ' 変換対象の文字列を取得
    s1 = StrConv(s1, vbFromUnicode) ' UnicodeをShiftJISに変換する
    i = 1
    While i <= LenB(s1)
        c = AscB(MidB$(s1, i, 1))
        ' 全角文字か半角文字かを判定する
        If c >= &H81 And c <= &H9F Or c >= &HE0 And c <= &HEF Then
            ' 全角文字
            i = i + 1
            c = c * 256 + AscB(MidB$(s1, i, 1))
            Debug.Print p16(v16(c))
        Else
            ' 半角文字
            Debug.Print p8(v8(c))
        End If
        i = i + 1
    Wend
End Sub

VBの場合では、「文字列」と表示されたダイアログに、変換したい文字を入力すると、イミディエイトウインドウに変換後の文字列が出力されます。それ以外の部分はCとほぼ同じです。

なお、全角文字と半角文字の判定ですが、これは、読み込んだデータが「0x81〜0x9Fか、0xE0〜0xEF」の間だった場合は、 全角文字の上位バイトであるということで判定できます。


連絡先 - サイトマップ - 更新履歴
Copyright (C)  2000 - 2016 nabiki_t All Rights Reserved.