linux下OSD使用SDL_ttf生成点阵数据,移植+开发代码详解

前言

        在做音视频开发的时候,一般会在视频上增加osd水印,时间或者logo之类的,这种水印其实就是由点阵数据构成,本文使用freetype+SDL+SDL_ttf生成文字点阵数据,并保存为bmp格式图片。使用这种方式的优点:

方便快捷,直接调用SDL_ttf的库函数生成数据,并且可以自定义文字水印的字体大小。

移植开发环境

虚拟机:ubuntu18.04

交叉编译器:arm-gcc7.3-linux-musleabi-gcc(替换为你自己的编译器)

源码:

        freetype-2.4.10

        SDL-1.2.15

        SDL_ttf-2.0.11

源码和demo已经上传到我的gitee。

sdl_ttf: linux下OSD使用SDL_ttf生成点阵数据

源码编译

1、freetype编译

解压源码,进入源码目录,裁剪编译

./configure CC=arm-gcc7.3-linux-musleabi-gcc --host=arm-gcc7.3-linux --prefix=/share/test/sdl/freetype-lib

2、SDL编译

解压源码,进入源码目录,裁剪编译

./configure CC=arm-gcc7.3-linux-musleabi-gcc --host=arm-gcc7.3-linux --prefix=/share/test/sdl/sdl-lib --disable-alsa --disable-pulseaudio --enable-esd=no

3、SDL_ttf编译

解压源码,进入源码目录,裁剪编译

./configure CC=arm-gcc7.3-linux-musleabi-gcc --host=arm-gcc7.3-linux --prefix=/share/test/sdl/sdl_ttf-lib --with-freetype-prefix=/share/test/sdl/freetype-lib --with-sdl-prefix=/share/test/sdl/sdl-lib

注意编译sdl_ttf的时候,需要链接上freetype和sdl的库

完成后将sdl和sdl_ttf编译生成的库文件和头文件复制出来,后续编译demo的时候需要参与编译。freetype的不需要。

开发demo

C语言例程

#include <stdio.h>
#include "SDL.h"
#include "SDL_ttf.h"
 
 
int main(int argc, const char *argv[])
{
    char * pstr = "hello你好";
    SDL_PixelFormat *fmt;
    TTF_Font *font; 
    SDL_Surface *text, *temp; 
 
    if (TTF_Init() < 0 )
    { 
        fprintf(stderr, "Couldn't initialize TTF: %s\n",SDL_GetError()); 
        SDL_Quit();
    } 
 
    font = TTF_OpenFont("./simsun.ttf", 48);
    if ( font == NULL )
    { 
        fprintf(stderr, "Couldn't load %d pt font from %s: %s\n",18,"ptsize", SDL_GetError()); 
    } 
 
    SDL_Color forecol = { 0xff, 0xff, 0xff, 0xff }; 
    text = TTF_RenderUTF8_Solid(font, pstr, forecol);
 
    fmt = (SDL_PixelFormat*)malloc(sizeof(SDL_PixelFormat));
    memset(fmt,0,sizeof(SDL_PixelFormat));
    fmt->BitsPerPixel = 24;
    fmt->BytesPerPixel = 3;
    fmt->colorkey = 0xffffffff;
    fmt->alpha = 0xff;

    temp = SDL_ConvertSurface(text,fmt,0);
    SDL_SaveBMP(temp, "/tmp/save.bmp");
 
    SDL_FreeSurface(text); 
    SDL_FreeSurface(temp);
    TTF_CloseFont(font); 
    TTF_Quit(); 
 
    return 0;
}

编译

arm-gcc7.3-linux-musleabi-gcc -o demo test.c -I./include libSDL_ttf.a libfreetype.a libSDL.a -lpthread -lm

编译完成后,执行程序,会生成一张bmp图片,内容为要生成的文字。

bmp格式解析

代码里面的字体文件库simsun.ttf,可在我的gitee一起下载,也可以用你自己的。

值得注意的是代码里 fmt->BitsPerPixel、fmt->BytesPerPixel这两个参数,

fmt->BitsPerPixel表示像素格式的类型,SDL 定义了许多预设的像素格式,例如:

  • SDL_PIXELFORMAT_RGB24:24位像素格式,每个像素占用3字节,顺序为 R-G-B。

  • SDL_PIXELFORMAT_RGBA32:32位像素格式,每个像素占用4字节,顺序为 R-G-B-A。

  • SDL_PIXELFORMAT_RGB565:16位像素格式,5位红色,6位绿色,5位蓝色。

  • SDL_PIXELFORMAT_ARGB8888:32位像素格式,每个像素占用4字节,顺序为 A-R-G-B

fmt->BytesPerPixel表示每个像素占用的字节数。例如:

  • 对于 SDL_PIXELFORMAT_RGB24BytesPerPixel 为 3。

  • 对于 SDL_PIXELFORMAT_RGBA32BytesPerPixel 为 4。

  • 对于 SDL_PIXELFORMAT_RGB565BytesPerPixel 为 2。

参考文档:

BMP文件格式解析_bmp格式-优快云博客

### 如何使用 SDL_TTF 库实现 OSD 文本渲染 SDL2_ttfSDL 的一个扩展库,它允许开发者利用 TrueType 字体进行高质量的文本渲染[^1]。为了生成屏幕上的文字叠加 (OSD),可以按照以下方式编写代码。 以下是完整的示例代码,展示如何加载字体文件并渲染一段简单的文本到屏幕上: ```c #include <SDL.h> #include <SDL_ttf.h> int main(int argc, char* argv[]) { // 初始化 SDLTTF 子系统 if (SDL_Init(SDL_INIT_VIDEO) != 0 || TTF_Init() != 0) { SDL_Log("无法初始化 SDLTTF: %s", SDL_GetError()); return -1; } // 创建窗口 SDL_Window* window = SDL_CreateWindow( "OSD Text Example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN); if (!window) { SDL_Log("无法创建窗口: %s", SDL_GetError()); goto cleanup_sdl; } // 创建渲染器 SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); if (!renderer) { SDL_Log("无法创建渲染器: %s", SDL_GetError()); goto cleanup_window; } // 加载字体文件 const int fontSize = 24; TTF_Font* font = TTF_OpenFont("arial.ttf", fontSize); // 替换为实际路径中的字体文件名 if (!font) { SDL_Log("无法加载字体: %s", TTF_GetError()); goto cleanup_renderer; } // 定义颜色(RGBA) SDL_Color textColor = {255, 255, 255, 255}; // 白色 // 渲染文本表面 const char* textContent = "这是一个OSD文本示例"; SDL_Surface* surfaceMessage = TTF_RenderUTF8_Blended(font, textContent, textColor); if (!surfaceMessage) { SDL_Log("无法渲染文本表面: %s", TTF_GetError()); goto cleanup_font; } // 将表面转换为纹理 SDL_Texture* messageTexture = SDL_CreateTextureFromSurface(renderer, surfaceMessage); if (!messageTexture) { SDL_Log("无法创建纹理: %s", SDL_GetError()); goto cleanup_surface; } // 获取文本尺寸用于定位 int w, h; SDL_QueryTexture(messageTexture, NULL, NULL, &w, &h); // 设置矩形区域来绘制文本 SDL_Rect dstRect = {400 - w / 2, 300 - h / 2, w, h}; // 主循环 bool quit = false; while (!quit) { SDL_Event e; while (SDL_PollEvent(&e)) { if (e.type == SDL_QUIT) { quit = true; } } // 绘制背景 SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderClear(renderer); // 绘制文本 SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); SDL_RenderCopy(renderer, messageTexture, NULL, &dstRect); // 更新屏幕 SDL_RenderPresent(renderer); } cleanup_texture: SDL_DestroyTexture(messageTexture); cleanup_surface: SDL_FreeSurface(surfaceMessage); cleanup_font: TTF_CloseFont(font); cleanup_renderer: SDL_DestroyRenderer(renderer); cleanup_window: SDL_DestroyWindow(window); cleanup_sdl: TTF_Quit(); SDL_Quit(); return 0; } ``` 上述代码展示了如何使用 `TTF_RenderUTF8_Blended` 函数将字符串渲染成带有透明度支持的图像[^2]。此方法适合于动态变化的文字内容以及复杂的视觉效果需求。 #### 关键点说明 - **字体加载**: 使用 `TTF_OpenFont` 打开指定大小的字体文件。 - **文本渲染**: 调用 `TTF_RenderUTF8_Blended` 方法可生成带抗锯齿效果的高质量文本。 - **内存管理**: 确保释放所有分配的对象资源以防止泄漏。 如果遇到类似 `SDL_UpdateRect` 导致程序崩溃的情况,则可能是由于对某些 API 参数的理解不足引起的[^3]。建议仔细阅读官方文档或调试具体调用栈。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值