如何使用后备字体通过xlib/libxft绘制文本?

问题描述 投票:0回答:1

如何使用后备字体通过 xlib/libxft 绘制文本? 例如,绘制字符串时,当前字体不包含某些字符,但另一种字体包含。那么,如何使用后备字体来绘制字符呢?

fonts xlib freetype fallback
1个回答
0
投票

这样可以,但是效率低:

#include <stdio.h>
#include <stdint.h>
#include <locale.h>
#include <X11/Xlib.h>
#include <X11/Xft/Xft.h>

#define ARRAY_NUM(a) (sizeof(a)/sizeof(a[0]))
#define FONT_NAMES (const char *[]){"DejaVu Sans", "Noto Sans Devanagari", "Noto Color Emoji"}
#define FONT_N ARRAY_NUM(FONT_NAMES)

Display *display=NULL;
Window root;
int screen;
Visual *visual=NULL;
Colormap colormap;
XftFont *fonts[FONT_N];
XftColor color;

int get_utf8_codepoint(const char *str, uint32_t *codepoint)
{
    const uint8_t *p=(const uint8_t*)str;
    int len=0;
    
    if(*p < 0x80) // 單字節字符
        len=1, *codepoint=*p;
    else if((*p>>5) == 0x06) // 雙字節字符
        len=2, *codepoint=(*p & 0x1F)<<6 | (*(p+1) & 0x3F);
    else if((*p>>4) == 0x0E) // 三字節字符
        len=3, *codepoint=(*p & 0x0F)<<12 | (*(p+1) & 0x3F)<<6 | (*(p+2) & 0x3F);
    else if((*p>>3) == 0x1E) // 四字節字符
        len=4, *codepoint=(*p & 0x07)<<18 | (*(p+1) & 0x3F)<<12 | (*(p+2) & 0x3F)<<6 | (*(p+3) & 0x3F);
    else // 非utf8編碼字符
        len=0;

    return len;
}

void load_fonts(void)
{
    for(int i=0; i<FONT_N; i++)
        fonts[i]=XftFontOpenName(display, screen, FONT_NAMES[i]);
}

void close_fonts(void)
{
    for(int i=0; i<FONT_N; i++)
        XftFontClose(display, fonts[i]);
}

void draw_utf8_string(Drawable drawable, const char *s, int x, int y)
{
    XGlyphInfo glyphInfo;
    int len=0;
    int32_t codepoint;

    XftDraw *xftDraw=XftDrawCreate(display, drawable, visual, colormap);
    while(*s)
    {
        len=get_utf8_codepoint(s, &codepoint);
        for(int i=0; i<FONT_N; i++)
            if (XftCharExists(display, fonts[i], codepoint)) {
                XftDrawStringUtf8(xftDraw, &color, fonts[i], x, y, (XftChar8*)s, len);
                XftTextExtentsUtf8(display, fonts[i], (XftChar8*)s, len, &glyphInfo);
                x += glyphInfo.xOff;
                break;
            }
        s+=len;
    }
    XftDrawDestroy(xftDraw);
}

int main(void)
{
    const char *s="Hello🔋,你好🥲,नमस्ते🤡.";
    display=XOpenDisplay(NULL);
    root=DefaultRootWindow(display);
    screen=DefaultScreen(display);
    visual=DefaultVisual(display, screen);
    colormap=DefaultColormap(display, screen);

    if(!setlocale(LC_ALL, "") || !XSupportsLocale())
        fprintf(stderr, "warning: no locale support\n");
    XftColorAllocName(display, visual, colormap, "yellow", &color);
    load_fonts();
    draw_utf8_string(root, s, 100, 100);
    close_fonts();
    XCloseDisplay(display);

    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.