c++ - 如何将(阿拉伯语)字形与 SDL-TTF v2.20 结合起来?

标签 c++ winapi sdl arabic sdl-ttf

SDL_TTF 2.20.0(启用 Harfbuzz)引入了 TTF_SetFontDirection()TTF_SetFontScriptName()“以使用 HarfBuzz 对字体进行额外控制”。

我正在尝试渲染一些阿拉伯语文本,并且我已将字体方向设置为 RTL 并将脚本名称设置为 "arSA\0",但字形没有正确连接。

TTF_SetFontDirection(ttf_font, TTF_DIRECTION_RTL)TTF_SetFontScriptName(ttf_font, "arSA\0") 都返回 0,表示成功。

这是我期望的文本显示方式:

joined

它是这样出现的:

enter image description here

谁能告诉我我做错了什么?

编辑:最小可重现示例: (改编自 https://github.com/aminosbh/sdl2-ttf-sample/blob/master/src/main.c )

#include <SDL.h>
#include <SDL_ttf.h>
#include <string>

int main(int argc, char* argv[])
{
    // Unused argc, argv
    (void)argc;
    (void)argv;

    // Initialize SDL2
    if (SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        printf("SDL2 could not be initialized!\n"
            "SDL2 Error: %s\n", SDL_GetError());
        return 0;
    }

    // Initialize SDL2_ttf
    TTF_Init();

    // Create window
    SDL_Window* window = SDL_CreateWindow("SDL2_ttf sample",
        SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED,
        SCREEN_WIDTH, SCREEN_HEIGHT,
        SDL_WINDOW_SHOWN);
    if (!window)
    {
        printf("Window could not be created!\n"
            "SDL_Error: %s\n", SDL_GetError());
    }
    else
    {
        // Create renderer
        SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
        if (!renderer)
        {
            printf("Renderer could not be created!\n"
                "SDL_Error: %s\n", SDL_GetError());
        }
        else
        {
            // Declare rect of square
            SDL_Rect squareRect;

            // Square dimensions: Half of the min(SCREEN_WIDTH, SCREEN_HEIGHT)
            squareRect.w = MIN(SCREEN_WIDTH, SCREEN_HEIGHT) / 2;
            squareRect.h = MIN(SCREEN_WIDTH, SCREEN_HEIGHT) / 2;

            // Square position: In the middle of the screen
            squareRect.x = SCREEN_WIDTH / 2 - squareRect.w / 2;
            squareRect.y = SCREEN_HEIGHT / 2 - squareRect.h / 2;

            TTF_Font* font = TTF_OpenFont(FONT_PATH, 40);
            if (!font) {
                printf("Unable to load font: '%s'!\n"
                    "SDL2_ttf Error: %s\n", FONT_PATH, TTF_GetError());
                return 0;
            }
            const auto fontDirectionSuccess = TTF_SetFontDirection(font, TTF_DIRECTION_RTL);
            const auto fontScriptNameSuccess = TTF_SetFontScriptName(font, "arSA\0");

            SDL_Color textColor = { 0x00, 0x00, 0x00, 0xFF };
            SDL_Color textBackgroundColor = { 0xFF, 0xFF, 0xFF, 0xFF };
            SDL_Texture* text = NULL;
            SDL_Rect textRect;




            // Arabic text to display
            const wchar_t * wstr = L"كسول الزنجبيل القط";

            // Convert unicode to multibyte
            int wstr_len = (int)wcslen(wstr);
            int num_chars = WideCharToMultiByte(CP_UTF8, 0, wstr, wstr_len, NULL, 0, NULL, NULL);
            CHAR* strTo = (CHAR*)malloc((num_chars + 1) * sizeof(CHAR));
            if (strTo)
            {
                WideCharToMultiByte(CP_UTF8, 0, wstr, wstr_len, strTo, num_chars, NULL, NULL);
                strTo[num_chars] = '\0';
            }


            // Render text to surface
            SDL_Surface* textSurface = TTF_RenderUTF8_Blended(font, strTo, textColor);
            if (!textSurface) {
                printf("Unable to render text surface!\n"
                    "SDL2_ttf Error: %s\n", TTF_GetError());
            }
            else {
                // Create texture from surface pixels
                text = SDL_CreateTextureFromSurface(renderer, textSurface);
                if (!text) {
                    printf("Unable to create texture from rendered text!\n"
                        "SDL2 Error: %s\n", SDL_GetError());
                    return 0;
                }

                // Get text dimensions
                textRect.w = textSurface->w;
                textRect.h = textSurface->h;

                SDL_FreeSurface(textSurface);
            }

            textRect.x = (SCREEN_WIDTH - textRect.w) / 2;
            textRect.y = squareRect.y - textRect.h - 10;


            // Event loop exit flag
            bool quit = false;

            // Event loop
            while (!quit)
            {
                SDL_Event e;

                // Wait indefinitely for the next available event
                SDL_WaitEvent(&e);

                // User requests quit
                if (e.type == SDL_QUIT)
                {
                    quit = true;
                }

                // Initialize renderer color white for the background
                SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);

                // Clear screen
                SDL_RenderClear(renderer);

                // Draw text
                SDL_RenderCopy(renderer, text, NULL, &textRect);

                // Update screen
                SDL_RenderPresent(renderer);
            }

            // Destroy renderer
            SDL_DestroyRenderer(renderer);
        }

        // Destroy window
        SDL_DestroyWindow(window);
    }

    // Quit SDL2_ttf
    TTF_Quit();

    // Quit SDL
    SDL_Quit();

    return 0;
}

编辑 2: 我换了

TTF_SetFontDirection(font, TTF_DIRECTION_RTL);
TTF_SetFontScriptName(font, "arSA\0");

与贬低:

TTF_SetDirection(HB_DIRECTION_RTL);
TTF_SetScript(HB_SCRIPT_ARABIC);

一切正常。我怀疑“arSA\0”可能是错误的,但我能找到的唯一文档说它应该是“恰好 4 个字符的空终止字符串”,没有指示或示例是哪 4 个字符。

最佳答案

您应该使用“Arab”而不是“arSA”。

参见 https://github.com/harfbuzz/harfbuzz/blob/7a219ca9f0f8140906cb7fd3b879b5bf5259badc/src/hb-common.h#L514

感谢评论者“1.8e9-where's-my-share m”和“skink”。

我在这里添加答案,这样您就可以接受答案。

关于c++ - 如何将(阿拉伯语)字形与 SDL-TTF v2.20 结合起来?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73275395/

相关文章:

c# - 获取无边框的进程窗口大小

java - Android NDK(带 SDL)构建基础架构说明

sdl - 什么是SDL中的Blit?

简单操作后 C++ 堆损坏

c++ - 阐明表达式的值类别

C 找出大数的质因数

c++ - C++ 中具有多重继承的奇怪多态行为?

c++ - 配对堆——递减键的实现

c++ - 重载赋值运算符不适用于链接 C++

c - 为什么“恢复”、“最小化”、“最大化”通知在不应该发送的情况下都被发送了?