グラフィックLCDにUTF-8エンコードされた漢字を表示する

2016年9月23日

 

今の時代どんなファイルの文字コードもUTF-8です。

この話はCのソースコードがUTF-8の場合です。CJKOSフォントの使い方もかな。

ソースコードの文字配列やテキストファイルは漢字混在文字列は何バイトか不明です。

uint8_t strings[] = “こんにちは";      // UTF-8文字での日本語は基本的に3byteなんですが。

は、15byteです。このUTF-8の文字コードで漢字を表示させる方法です。(半角8bit文字には対応していません。)

とりあえずビットマップフォントを入手しましょう。TTFとか高度なフォントを使う気力はありません

CJKOS Japanese Fonts

ここに色々なフォントとサイズのファイルが置いてあります;。組み込みには最適。最高です。

これを使ったのですが、くじけそうになるほどファイル形式が全然分かりません(笑

一番不明なのは文字コードの配列です。ShiftJISなのかJISなのかUTF-8なのかUTF-16なのかその他なのか全く分かりません。当初はShiftJISだろうと思ってプログラムを作っていたのですが。(根拠はここ:CJKOS用ハイレゾ日本語フォント 2003.03.31)

設定が「CharSet : ShiftJIS」となっています。ですがどうしてもうまくいきません。違う文字が表示されます。

独自解析したとあるページには、ヘッダと「あとは,グリフデータがコード順に 0x2121 から 0x747e まで, ベタに書きこまれているだけです。たとえば,12dot のBDFフォントで “津"云々」と書いてあります。ここで意味を取り違いました。

ShiftJISの「津」の文字コードではなく、0x2121はJISコード文字の先頭コードでした。全然違います。どこにもフォントのエンコードが書かれていないのです。ヘッダには「JapaneseJIS」と書いてありますが。

結局JISコードで並んでいることが分かるまで大変な時間を消費しました。(次に書いた通り変換表が間違えていたのもあります。

さて、気を取り直して色々なフォントとサイズがあるのですが、流石にPICのFlashメモリには入りきれません。なのでSDカードに入れました。

次にJISコードで並んでいるフォントをUTF-8コードで表示するために変換コードを書く必要があります。

最初はどこかのHPで見つけたUTF-8、ShiftJIS、JISコードなど漢字の対応表を使いました。全然うまく表示されません。違う文字が表示されます。

よくよく調べてみるとJISコードの16進文字が10進文字に間違えて書いてありました。ABCが入っているのはHEXで、数字だけは10進です。非常に残念な事態です。

エクセルでcsvファイルを読み込ませると発生するので、これのせいでしょう。

対応表をグーグル先生で検索しまくったのですが見つかりません。これは困りました。

ぼわ~っと脱力しているときに考え付きました。JIS文字コード表のHPでそのページのエンコードがUTF-8なら文字自体はUTF-8です。使ったのはこちら。UTF-8ではなくてもメモ帳にコピペするとUTF-8で保存できます。

JIS 漢字コード表 (JIS X 0208)

のhtml文法で書かれているコードを見るとテーブルで表示しているので、<td>を “, ” に置換他は削除。あとは少し手を加えるだけ。

MPLAB X IDEでこのファイルを追加すると、UTF-8でプログラムを作成しても何故か文字が化けますので、メモ帳で開いてコピペでおkです。

UTF-8以外のCソーコードを使っているなら、バイナリプログラムで開いてコピペして、1byte単位に並べます。あとは不要な文字を置換してバイト配列にすればよいかと思います。

const unsigned char TableUTF8toJIS[][4] = {
" ", "、", "。", ",", ".", "・", ":", ";", "?", "!", "゛", "゜", "´", "`", "¨", "

天才。超手抜きでJISコード並びのUTF-8コードの対応配列が作れました。(そのうちPerlかPHPでHEXで書こうとは思っていますが)

次に文字列のバイト数です。UTF-8は可変長バイトなので、1文字に何バイト使っているか不明です。ですのでこんなプログラムを書きました。

// ----------------------------------------------------------------------------
//
// UTF-8の文字数
//
// http://ja.stackoverflow.com/questions/2988/c%E8%A8%80%E8%AA%9E%E3%81%A7%E3%81%AEutf-8%E6%96%87%E5%AD%97%E5%88%97%E3%81%AE%E6%AD%A3%E7%A2%BA%E3%81%AA%E9%95%B7%E3%81%95%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B
// 
// ----------------------------------------------------------------------------
static const char utf8len_codepage[256] =
{
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
  3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,1,1,1,1,1,1,1,1,1,1,1,
};

int utf8len(const char* p)
{
    int len;
    int i;

    if (*p == 0) return 1;
    len = utf8len_codepage[(const unsigned char)*p];
    for (i = 1; i < len; ++i) {
        if ((p[i] & 0xc0) != 0x80) return 1;
    }
    return len;
}

int utf8strlen(const char* p)
{
    int len;
    for (len = 0; *p; ++len) {
        p += utf8len(p);
    }
    return len;
}

uint16_t GetJisPoint(uint8_t *pCode)
{
    int i , j;
    int bytes;
    uint32_t code, table, max;
    
    bytes = utf8len(pCode);                 // UTF8の文字は何バイトか
    
    for(i = 0, code = 0; i < bytes; i++) {  // 検索するUTF-8文字コード
        code <<= 8;
        code += *(pCode + i);
    }
    
    max = sizeof(TableUTF8toJIS) / sizeof(TableUTF8toJIS[0]);      // 配列の数
    
    for(i = 0; i < max; i++) {
        for(j = 0, table = 0; j < bytes; j++) {
            table <<= 8;
            table += TableUTF8toJIS[i][j];
        }
        
        if(code == table) {
            return i;
        }
    }
    return 0;
}

文字列の文字数と、1文字のバイト数を調べる関数を作ります。その文字コードをJIS並びのUTF-8コードで検索します。

その文字がJISで何番目か解ればもうできたも同然です。CIMG1097

Hello World!! はC言語が生まれてテストプログラムを書く時の非常に伝統的な文字列です。よく意味が分かっていませんでしたが、直訳するとこんなことになっていました。