VFDパネルを制御できる環境ができたところで、今度は日本語フォントを扱うことについて説明したいと思います。
フォント形式にはbdfやFONTX2などがあります。WindowsではTrueTypeやOpenTypeが主流ですね。
ここでは、FONTX2のビットマップフォントを扱うことについて説明します。
今回は、東雲フォントの東雲16フォントのFONTX形式をそのまま組み込みで利用させていただくことにします。
また、予めお断りしておきますが、パフォーマンスを重視した場合、データは事前にパソコンで処理しておいて組み込みマイコンで参照する方がいいデータもありますが、ここでは敢えてマイコンでフォントデータをリロードして展開できるように、全てマイコン内でハンドリングする事にします。
(実際にはそれほど処理時間を必要とするわけではありません)
まず、このページでは、「指定した文字コード」から、「文字のビットマップデータのアドレス取得」を行うフォントドライバを作成します。
別なページで、RubyのスクリプトでバイナリファイルをC言語の配列の形式に変換する方法を紹介していますので、よろしければご参考にして下さい。
変換後のフォントファイルを*.INCというファイルに書き出し、以下のようなコードでconst配列データにしました。
const char font_table_kanji[] = {
#ifdef FONT_MINCHO
#include "./SHMZN16X.INC"
#else
#include "./SHGZN16X.INC"
#endif
};
const char font_table_ascii[] = {
#include "./SHNHN16X.INC"
};
FONT_MINCHOが定義されている場合、明朝体の東雲フォントが導入されるようにしました。
なお、FONTX2では全角フォントと半角フォントが別々に定義されていますので、配列も分かれています。
FONTX2形式での漢字コードは、一般にShift-JISとなっており、その文字コードから実際のフォントデータのインデックスを導き出すテーブルデータがフォントファイルの先頭部分に含まれています。
なお、ここでご紹介させていただくサンプルプログラムでは、フォントサイズは可変ですが、横方向が8の倍数のドットになるものだけに対応しています。
後ほどFONTX2形式のフォーマット解説込みで説明します。^^;;
/*
FONTX2 フォントドライバの初期化処理
内容:
フォント実データへのポインタ生成
フォントテーブルデータを参照し、フォントサーチ用のテーブルを生成
*/
void init_fontdrv(void){
int i;
ucpFontDataStart_Kanji = (unsigned char*)(font_table_kanji + FONT_CODE_TNUM_KANJI * 4 + 18);
usFontSearchTable_Kanji[0] = 0;
for (i=1;i<FONT_CODE_TNUM_KANJI;i++){
usFontSearchTable_Kanji[i] = (FONT_BLOCK_E_KANJI(i-1) - FONT_BLOCK_S_KANJI(i-1) + 1) +
usFontSearchTable_Kanji[i-1];
}
}
後ほどFONTX2形式のフォーマット解説込みで説明します。^^;;
アスキーコード(半角)データは、フォントビットマップデータの先頭からそのままアスキーコード並びでデータが並んでいます。
しかし、漢字コードに関しては、元々Shift JISコードには空きのエリアがところどころにある為にコード並びにフォントのビットマップデータを配置するとダミーデータ領域が沢山出来てしまうことから、フォント参照用の中間テーブル情報があります。
以下は、アスキーに関してはビットマップデータの始点アドレスをフォントビットマップデータの始点×アスキーコード×1フォントのバイトサイズで算出できますが、漢字に関しては一旦中間テーブルでフォントインデックス番号を引いてから算出しています。
/*
指定したSHIFT-JIS文字コードから、FONTX2文字コードのテーブル
より文字データの存在するエリアの番号を得る
*/
static int SearchFontAreaNo_Kanji(unsigned short code){
int i;
int ret;
for (i=0;i<FONT_CODE_TNUM_KANJI;i++){
if((FONT_BLOCK_S_KANJI(i) <= code) && (FONT_BLOCK_E_KANJI(i) >= code)){
return(i);
}
}
return (-1);
}
/*
指定したAsciiコードから、該当するフォントデータのビットマップエリア
へのポインタを得る
*/
unsigned char* GetFontPtr_Ascii(unsigned char code){
if (code > 0x7f){
code = UNKNOWN_CHAR_REPLACE_ASCII;
}
return (FONT_DATA_START_ADDR + code * FONT_SIZE_ASCII);
}
/*
指定したSHIFT-JIS文字コードから、該当するフォントデータのビットマップ
エリアへのポインタを得る
*/
unsigned char* GetFontPtr_Kanji(unsigned short code){
int FontArea;
unsigned short CodeOffset;
unsigned long FontStartAddr;
// 指定文字コードの属するフォントのエリアを算出
FontArea = SearchFontAreaNo_Kanji(code);
// 文字コードに該当するフォントが見つからない場合
if (FontArea == -1){
// 不明なので置き換え用のコードに挿げ替え
code = UNKNOWN_CHAR_REPLACE_KANJI;
FontArea = SearchFontAreaNo_Kanji(code);
}
// フォントのブロック先頭からのオフセット量算出
CodeOffset = code - FONT_BLOCK_S_KANJI(FontArea);
// フォントエリア先頭からの指定フォントの開始オフセット量算出
FontStartAddr = (usFontSearchTable_Kanji[FontArea] + CodeOffset) * FONT_SIZE_KANJI;
// フォントスタート実アドレス + オフセット量の和を返す
return((unsigned char*)(ucpFontDataStart_Kanji + FontStartAddr));
}