トップ 最新

かってきままな日々

2021-11-21 (Su) [長年日記]

_ 全角と半角の文字幅

固定幅フォントにおいては、2:1 になるのが正しいと思ってたんだけど…

なんでか、全角半角を混ぜてテキストで表を作ろうとすると、 必ず | の位置が微妙にずれてしまう。

ここ数日ちょっと調べてみた。

freetype を直接ごりごり扱ってみたり。

#include <ft2build.h>
#include FT_FREETYPE_H
#include <freetype/ftimage.h>

static unsigned int text[] = {
    0x00003042, 0x00003044, 0x00003046, 0x00003048,
    0x0000304a, 0x0000304b, 0x0000304d, 0x0000304f,
    0x00003051, 0x00003053, 0x00003055, 0x00003057,
    0x00003059, 0x0000305b, 0x0000305d, 0x0000305f,
    0x00003061, 0x00003064, 0x00003066, 0x00003068,
    0x00003042, 0x00003044, 0x00003046, 0x00003048,
    0x0000304a, 0x0000304b, 0x0000304d, 0x0000304f,
    0x00003051, 0x00003053, 0x00003055, 0x00003057,
    0x00003059, 0x0000305b, 0x0000305d, 0x0000305f,
    0x00003061, 0x00003064, 0x00003066, 0x00003068,
    0x0000000a,
    0x00000061, 0x00000062, 0x00000063, 0x00000064,
    0x00000065, 0x00000066, 0x00000067, 0x00000068,
    0x00000069, 0x0000006a, 0x0000006b, 0x0000006c,
    0x0000006d, 0x0000006e, 0x0000006f, 0x00000070,
    0x00000071, 0x00000072, 0x00000073, 0x00000074,
    0x00000075, 0x00000076, 0x00000077, 0x00000078,
    0x00000079, 0x0000007a,
    0x00000061, 0x00000062, 0x00000063, 0x00000064,
    0x00000065, 0x00000066, 0x00000067, 0x00000068,
    0x00000069, 0x0000006a, 0x0000006b, 0x0000006c,
    0x0000006d, 0x0000006e, 0x0000006f, 0x00000070,
    0x00000071, 0x00000072, 0x00000073, 0x00000074,
    0x00000075, 0x00000076, 0x00000077, 0x00000078,
    0x00000079, 0x0000007a,
    0x0000000a,
};
#define LEN (sizeof text / sizeof text[0])

#define WIDTH  1024
#define HEIGHT 256
#define LEFT 16
#define TOP 128
static unsigned char paper[HEIGHT][WIDTH];


static void draw(FT_Bitmap *bitmap, int x, int y)
{
    for (int j = 0; j < bitmap->rows; j++) {
        for (int i = 0; i < bitmap->width; i++) {
            unsigned char c = bitmap->buffer[j * bitmap->pitch + i];
            if (c) {
                if (y + j >= 0 && y + j < HEIGHT) {
                    if (x + i >= 0 && x + i < WIDTH)
                        paper[y + j][x + i] = 255;
                }
            }
        }
    }
}

int main(void)
{
    FT_Library library;
    int error;

    error = FT_Init_FreeType(&library);
    if (error) {
        fprintf(stderr, "ft init error\n");
        exit(1);
    }

    FT_Face face;
    error = FT_New_Face(
            library,
            "/usr/share/fonts/TTF/NasuM-Regular-20141215.ttf",
            0,
            &face);
    if (error) {
        fprintf(stderr, "new face error\n");
        exit(1);
    }

    error = FT_Set_Char_Size(
            face,
            0,
            8 * 64,
            300,
            300);
    if (error) {
        fprintf(stderr, "set size error\n");
        exit(1);
    }
    
    int x = LEFT, x6 = LEFT<<6, y = TOP;
    unsigned int idces[LEN];
    for (int i = 0; i < LEN; i++) {
        if (text[i] == '\n') {
            x = LEFT;
            x6 = LEFT<<6;
            y += 24;
            continue;
        }

        idces[i] = FT_Get_Char_Index(face, text[i]);

        error = FT_Load_Glyph(
                face,
                idces[i],
                0 |
//              FT_LOAD_DEFAULT |        // x
                FT_LOAD_NO_HINTING |     // o
//              FT_LOAD_PEDANTIC |       // x
//              FT_LOAD_NO_AUTOHINT |    // x
                0
);
        if (error) {
            fprintf(stderr, "no glyph error\n");
            exit(1);
        }

        error = FT_Render_Glyph(
                face->glyph,
                FT_RENDER_MODE_NORMAL);
        if (error) {
            fprintf(stderr, "glyph render error\n");
            exit(1);
        }
        
        draw(&face->glyph->bitmap,
                (x6 >> 6) + face->glyph->bitmap_left,
                y - face->glyph->bitmap_top);
        
        x += face->glyph->advance.x >> 6;
        x6 += face->glyph->advance.x;
    }
    
    printf("P3\n%d %d\n%d\n", WIDTH, HEIGHT, 255);
    for (int y = 0; y < HEIGHT; y++) {
        for (int x = 0; x < WIDTH; x++) {
            if (paper[y][x]) {
                printf("%d %d %d ", 255, 255, 255);
            } else {
                printf("%d %d %d ", 0, 0, 0);
            }
            printf("\n");
        }
    }
}

実行したら標準出力に ppm ファイルが出力されるので、適当にファイルにリダイレクトして 適当な画像ビューワで見る。

なんと、FT_LOAD_NO_HINTING を指定するとちゃんと 2:1 になるのね。 hinting が悪さしてる? でも fonts.conf で false にしても治らない。

うーーん…

emacs の FT_LOAD_xxx の箇所に全部 FT_LOAD_NO_HINTING を追加してみても、 やっぱりずれるし。

ゔ〜〜〜ん

freetype-infinality とかいうやつにしてみたけど変化なく。

もしや Ubuntu ならうまく設定してたりするのか? と思って Ubuntu live media で 起動してみたけど、やっぱりずれるし。

世の中、幅の比率はあまり気にしない方向なのか? テキストで表を作ろうってのがもう老害?

(3:2 のフォントもあるらしいけど、それは好みなので置いておく)

macOS 上の emacs だと問題ないんだけどな。その辺はさすが mac かな。