arduinoで日本語表示の準備
マイコンで表示可能な320×240ドットとかの
グラフィックディスプレーに日本語を表示しようとすると、
メモリ容量などの問題から別のメモリ(ROM)等に
漢字のデータを用意する必要があります。
それの為に準備されたと思われる商品がGT20L16J1Yなんですけど、
もうすでに品切れで、作っていない様子です。
もっと早く試していればよかったんですけど、
遅きに失した状況です。
■GT20L16J1Yの説明を先にすると、
縦16ドット、横16ドット(半角は横8ドット)で文字が表現されており、
記号、英数字、カタカナ、第一水準、第二水準の漢字が格納されている。
点の濃淡はなく、黒を1、白を0としてデジタルデータで格納されており、
ROMのアドレスにSPI通信でアクセスする事で1バイト毎のデジタルデータとして
取得することが可能です。取得した1バイトのデータをさらに分解して
1ドット=1ビットのデータとして扱うことがが可能です。
縦16ドット、横16ドットの1文字は256ビット=32バイトで表現されています。
手に入らないものはしょうがないので、
他に使えそうなものがないかなと考え、思いついたのが、
昔DOS/Vで使われていたフォント形式。拡張子FNTとかだったと思う。
その筋で辿って行った所、いろいろと有用な情報が見つかりました。
以下調べた色々メモ。
■現在の主流は「つるータイプふぉんと」=TrueTypeFontである。
これはWindowsとかで使われていて拡大してもギザギザにならない方式です。
拡張子はTTFで、座標でデータを持っている。座標間を曲線で結ぶとか、
直線で結ぶとかの情報を持っていて、大きくした場合でも
座標に掛け算するだけなので簡単にギザギザのない文字表現が可能です。
ただし、ロジックが難しそうなので、マイコンに向いているかと言われると、
現時点では難しそう。
■FONTX2形式
DOS/Vなどで使われていたフォント=FONTX2
http://elm-chan.org/docs/dosv/fontx.html
「FONTXファイルの使いかた」さんのサイトです。
これによるとファイルの先頭から
char sig[6]; //FONTX2と入る
char name[8]; //フォント名
unsigned char width; //フォント幅 ドット
unsigned char height; //フォント高 ドット
unsigned char code; //文字コード 1=SJIS
unsigned char block_num; //コードブロック数
{ // コードブロック数分続く
unsigned short block_start; //ブロックごとのコードの開始 リトルエンディアン
unsigned short block_end; //ブロックごとのコードの終了 リトルエンディアン
}
unsigned char font_image[xx]; //フォントイメージ (※2:フォントサイズ×各ブロックのコード数の総和)
半角の場合
char sig[6]; //FONTX2と入る
char name[8]; //フォント名
unsigned char width; //フォント幅 ドット
unsigned char height; //フォント高 ドット
unsigned char code; //文字コード 0=ANK
unsigned char font_image[xx]; //フォントイメージ (フォントサイズ×256)
※フォントイメージは1バイト単位で格納されるため、幅が8の倍数でない場合は後ろに0が格納される
■IPAフォント
https://moji.or.jp/ipafont/ipaex00401/
IPAフォントライセンスなるものがあり、
上記参照ですが、3条の制限をよく読んでもらうとわかりますが、
若干の条件はありつつも、自由に使用可能です。
■IPAフォントをビットマップフォントに変換
http://ayati.cocolog-nifty.com/blog/2012/08/ipalx322416-64a.html
「こばこのひみつ」さんのサイトです。
ビットマップ変換済みのファイルをダウンロード可能です。
上記IPAのフォントをWFONTXにより変換し、FUTOME.EXEでボールド加工したもの
と解説されています。
ILFONT03.zip
上記のIPAライセンスに従って配布されているものですね。
■WFONTX
https://www.vector.co.jp/soft/dos/writing/se002881.html
Windows3.1用のソフトとの事で、Windows11で動かそうとしても動きませんね。
ソースが付いてくるので、そのうち挑戦かな?と思いますけど。
■FUTOME.EXE
捜索中
■今回の実行例
薔薇の ら ですね。32×32のビットマップイメージです。
■プログラム
全体はこちら。
→https://drive.google.com/file/d/1J5ESzDM_8dY5jtJ8GjAUxGUL_rQacaFQ/view?usp=sharing
抜粋と解説です。
■フォントは上記で紹介した こばこのひみつさんのものです。
#define FONT_FILE _T("ILGZ32XF.FNT")
■structで下記のように定義しました。
#pragma pack (1)
struct S_FONT {
char sig[6]; //FONTX2と入る
char name[8]; //フォント名
unsigned char width; //フォント幅 ドット
unsigned char height; //フォント高 ドット
unsigned char code; //文字コード 1=SJIS
} s_font;
struct S_BLOCK {
unsigned short block_start; //ブロックごとのコードの開始 リトルエンディアン
unsigned short block_end; //ブロックごとのコードの終了 リトルエンディアン
};
struct S_FONT2 {
unsigned char block_num; //コードブロック数
struct S_BLOCK* block; //コードブロック
} s_font2;
#pragma pack (8)
■次の関数でコードブロックまでの情報をメモリ上に展開しておきます。
void CFileReadDlg::OnBnClickedButton1()
{
CFile f;
BOOL bRet;
CFileException ex;
bRet = f.Open(FONT_FILE, CFile::modeRead, &ex);
if (bRet) {
TRACE("open success¥n");
char buf[256];
UINT n = f.Read(&s_font, sizeof(struct S_FONT));
if (n == sizeof(struct S_FONT)) {
memset(buf, '¥0', sizeof(buf));
memcpy(buf, s_font.sig, 6);
TRACE("%s¥n", buf);
memset(buf, '¥0', sizeof(buf));
memcpy(buf, s_font.name, 8);
TRACE("%s¥n", buf);
TRACE("width=%d¥n", s_font.width);
TRACE("height=%d¥n", s_font.height);
TRACE("code=%d¥n", s_font.code);
}
if (s_font.code == 0) { //ANSI
s_font2.block_num = 0;
}
if (s_font.code == 1){ //SJIS
n = f.Read(&s_font2.block_num, sizeof(s_font2.block_num));
if (n == sizeof(s_font2.block_num)) {
TRACE("block_num=%d¥n", s_font2.block_num);
}
if (s_font2.block) {
free(s_font2.block);
}
s_font2.block = (struct S_BLOCK *)malloc(sizeof(struct S_BLOCK) * s_font2.block_num);
n = f.Read(s_font2.block, sizeof(struct S_BLOCK) * s_font2.block_num);
if (n == sizeof(struct S_BLOCK) * s_font2.block_num) {
for (int i = 0; i < s_font2.block_num; i++) {
TRACE("block_read %x-%x¥n", s_font2.block[i].block_start, s_font2.block[i].block_end);
}
}
}
}
else {
TRACE("open error¥n");
return;
}
f.Close();
}
■次の関数にsjisコードを渡すと、デバッグとしてビットマップイメージを「■」と「・」で表示します。
「■」の所がビット1の所で、「・」の所がビット0の所です。
1文字のみ対応です。
この関数を呼び出す前に上の関数を呼び出しておく必要があります。
void ConvertDisplay(unsigned int code)
{
int char_count = 0;
int exist_flag = 0;
for (int i = 0; i < s_font2.block_num; i++) {
if (s_font2.block[i].block_start <= code && code <= s_font2.block[i].block_end) {
char_count = char_count + (code - s_font2.block[i].block_start);
exist_flag = 1;
break;
}
else {
char_count = char_count + (s_font2.block[i].block_end - s_font2.block[i].block_start) + 1;
}
}
if (s_font.code == 1 && exist_flag == 0) {
TRACE("見つかりません");
return;
}
if (s_font.code == 0 && code>=256) {
TRACE("見つかりません");
return;
}
unsigned int font_size;
font_size = (s_font.width + 7) / 8 * s_font.height;
unsigned int seek_point;
if (s_font.code == 1) {
seek_point = 18 + 4 * s_font2.block_num + char_count * font_size;
}
else { //ANSI
seek_point = 17 + code * font_size;
}
CFile f;
BOOL bRet;
CFileException ex;
bRet = f.Open(FONT_FILE, CFile::modeRead, &ex);
if (bRet) {
TRACE("open success¥n");
unsigned char* font_buf;
font_buf = (unsigned char*)malloc(font_size);
f.Seek(seek_point, CFile::begin);
unsigned int n = f.Read(font_buf, font_size);
if (n == font_size) {
char str[256];
memset(str, NULL, sizeof(str));
for (unsigned int i = 0; i < font_size; i++) {
//TRACE("%x", font_buf[i]);
unsigned int bit = font_buf[i];
for (int b = 0; b < 8; b++) {
if (bit & 128) {
strcat_s(str, sizeof(str), "■");
}
else {
strcat_s(str, sizeof(str), "・");
}
bit = bit << 1;
}
if ((i+1) % ((s_font.width + 7) / 8) == 0) {
TRACE("%s¥n", str);
memset(str, NULL, sizeof(str));
}
}
}
free(font_buf);
}
else {
TRACE("open error¥n");
return;
}
f.Close();
}