You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Freetype、Xft与Xlib时字体大小无法修改的问题求助

解决Xft字体大小无法修改的问题

问题根源

  1. 直接修改font->height无效:XftFont结构体的成员是只读属性,字体加载完成后手动修改不会改变已加载的字体渲染数据。
  2. 使用了固定尺寸位图字体:fixed是X11自带的位图字体,仅支持有限的固定尺寸,无法自由缩放,必须改用可缩放的矢量字体(如TrueType/OpenType格式)。
  3. 打开字体时未指定大小:XftFontOpenName需要传入包含尺寸信息的字体名称字符串,才能加载对应大小的字体实例。

解决方案

  • 使用"字体名称-尺寸"的格式指定带大小的字体,或动态拼接字体名与目标尺寸。
  • 移除手动修改font->height的代码,改为在字体加载阶段指定大小。
  • 修复主循环逻辑:添加X事件处理避免窗口假死,每次绘制前清除窗口内容防止文本重叠。

修改后的完整代码

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/Xft/Xft.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

// 使用系统自带的可缩放矢量字体(可根据实际情况替换)
#define BASE_FONT_NAME "DejaVu Sans"

void drawText(Display *display, Window window, const char *text, int x, int y, int fontSize) {
    XftFont *font;
    XftDraw *xftDraw;
    XftColor color;

    // 动态拼接带尺寸的字体名称:"字体名-尺寸"
    char fontName[256];
    snprintf(fontName, sizeof(fontName), "%s-%d", BASE_FONT_NAME, fontSize);

    // 加载指定大小的字体
    font = XftFontOpenName(display, DefaultScreen(display), fontName);
    if (!font) {
        fprintf(stderr, "无法加载字体:%s\n", fontName);
        return;
    }

    // 创建Xft绘图上下文
    Visual *visual = DefaultVisual(display, DefaultScreen(display));
    Colormap colormap = DefaultColormap(display, DefaultScreen(display));
    xftDraw = XftDrawCreate(display, window, visual, colormap);

    // 设置白色文本颜色
    XRenderColor xrenderColor = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
    XftColorAllocValue(display, visual, colormap, &xrenderColor, &color);

    // 绘制文本:y坐标需加上字体ascent值,保证文本基线对齐到指定位置
    XftDrawStringUtf8(xftDraw, &color, font, x, y + font->ascent, (XftChar8 *)text, strlen(text));

    // 释放资源
    XftDrawDestroy(xftDraw);
    XftColorFree(display, visual, colormap, &color);
    XftFontClose(display, font);
}

int main() {
    Display *display = XOpenDisplay(NULL);
    if (!display) {
        fprintf(stderr, "无法打开显示\n");
        return 1;
    }

    int screen = DefaultScreen(display);
    int screenWidth = DisplayWidth(display, screen);
    int screenHeight = DisplayHeight(display, screen);
    int windowWidth = 400;
    int windowHeight = 300;
    int windowX = (screenWidth - windowWidth) / 2;
    int windowY = (screenHeight - windowHeight) / 2;

    // 创建窗口
    Window overlayWindow = XCreateSimpleWindow(display, DefaultRootWindow(display),
                                               windowX, windowY, windowWidth, windowHeight,
                                               0, 0, BlackPixel(display, screen));

    // 设置全屏属性(可选)
    Atom atom_net_wm_state = XInternAtom(display, "_NET_WM_STATE", False);
    Atom atom_fullscreen = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", False);
    XChangeProperty(display, overlayWindow, atom_net_wm_state,
                    XA_ATOM, 32, PropModeReplace, (unsigned char *)&atom_fullscreen, 1);

    // 设置窗口覆盖重定向
    XSetWindowAttributes attr;
    attr.override_redirect = True;
    XChangeWindowAttributes(display, overlayWindow, CWOverrideRedirect, &attr);

    XCompositeRedirectWindow(display, overlayWindow, CompositeRedirectAutomatic);

    XMapWindow(display, overlayWindow);
    XFlush(display);

    // 主循环:处理事件+绘制
    XEvent ev;
    while (1) {
        // 处理X事件,避免窗口假死
        while (XPending(display)) {
            XNextEvent(display, &ev);
            if (ev.type == DestroyNotify) {
                XDestroyWindow(display, overlayWindow);
                XCloseDisplay(display);
                return 0;
            }
        }

        // 清除窗口内容(黑色填充)
        XSetForeground(display, DefaultGC(display, screen), BlackPixel(display, screen));
        XFillRectangle(display, overlayWindow, DefaultGC(display, screen), 0, 0, windowWidth, windowHeight);

        // 绘制不同大小的文本测试
        drawText(display, overlayWindow, "字体大小24", 50, 50, 24);
        drawText(display, overlayWindow, "字体大小48", 50, 120, 48);
        drawText(display, overlayWindow, "字体大小64", 50, 200, 64);

        XFlush(display);
        // 短暂休眠降低CPU占用
        usleep(16000); // 约60fps
    }

    XDestroyWindow(display, overlayWindow);
    XCloseDisplay(display);
    return 0;
}

编译与测试

使用以下命令编译代码:

gcc -o xft-text xft-text.c -lX11 -lXft -lXcomposite

补充说明

  • 若系统没有DejaVu Sans字体,可替换为其他已安装的矢量字体,比如"Noto Sans"、"Roboto"等,可用fc-list命令查看系统可用字体列表。
  • 动态拼接字体名称是指定大小最简便的方式,也可使用XftFontOpenXlfd通过XLFD格式字符串指定更精细的字体属性(如字重、样式)。

内容的提问来源于stack exchange,提问作者Pedro A. Pinheiro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 01:15:11