172 lines
4.7 KiB
C
172 lines
4.7 KiB
C
#include <time.h>
|
|
|
|
#include <ft2build.h>
|
|
#include FT_FREETYPE_H
|
|
|
|
#include "text_font.h"
|
|
#include "text.h"
|
|
|
|
static char errbuf[256];
|
|
|
|
static void set_error(const char *format, ...) {
|
|
va_list args;
|
|
va_start(args, format);
|
|
vsnprintf(errbuf, 256, format, args);
|
|
}
|
|
|
|
const char *text_get_error() {
|
|
return errbuf;
|
|
}
|
|
|
|
typedef struct {
|
|
bool enabled;
|
|
char *text_overlay;
|
|
FT_Library library;
|
|
FT_Face face;
|
|
} text_priv_t;
|
|
|
|
bool text_create(const parameters_t *params, text_t **text) {
|
|
*text = malloc(sizeof(text_priv_t));
|
|
text_priv_t *textp = (text_priv_t *)(*text);
|
|
memset(textp, 0, sizeof(text_priv_t));
|
|
|
|
textp->enabled = params->text_overlay_enable;
|
|
textp->text_overlay = strdup(params->text_overlay);
|
|
|
|
if (textp->enabled) {
|
|
int error = FT_Init_FreeType(&textp->library);
|
|
if (error) {
|
|
set_error("FT_Init_FreeType() failed");
|
|
goto failed;
|
|
}
|
|
|
|
error = FT_New_Memory_Face(
|
|
textp->library,
|
|
text_font_ttf,
|
|
sizeof(text_font_ttf),
|
|
0,
|
|
&textp->face);
|
|
if (error) {
|
|
set_error("FT_New_Memory_Face() failed");
|
|
goto failed;
|
|
}
|
|
|
|
error = FT_Set_Pixel_Sizes(
|
|
textp->face,
|
|
25,
|
|
25);
|
|
if (error) {
|
|
set_error("FT_Set_Pixel_Sizes() failed");
|
|
goto failed;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
|
|
failed:
|
|
free(textp);
|
|
|
|
return false;
|
|
}
|
|
|
|
static void draw_rect(uint8_t *buf, int stride, int height, int x, int y, unsigned int rect_width, unsigned int rect_height) {
|
|
uint8_t *Y = buf;
|
|
uint8_t *U = Y + stride * height;
|
|
uint8_t *V = U + (stride / 2) * (height / 2);
|
|
const uint8_t color[3] = {0, 128, 128};
|
|
uint32_t opacity = 45;
|
|
|
|
for (unsigned int src_y = 0; src_y < rect_height; src_y++) {
|
|
for (unsigned int src_x = 0; src_x < rect_width; src_x++) {
|
|
unsigned int dest_x = x + src_x;
|
|
unsigned int dest_y = y + src_y;
|
|
int i1 = dest_y*stride + dest_x;
|
|
int i2 = dest_y/2*stride/2 + dest_x/2;
|
|
|
|
Y[i1] = ((color[0] * opacity) + (uint32_t)Y[i1] * (255 - opacity)) / 255;
|
|
U[i2] = ((color[1] * opacity) + (uint32_t)U[i2] * (255 - opacity)) / 255;
|
|
V[i2] = ((color[2] * opacity) + (uint32_t)V[i2] * (255 - opacity)) / 255;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void draw_bitmap(uint8_t *buf, int stride, int height, const FT_Bitmap *bitmap, int x, int y) {
|
|
uint8_t *Y = buf;
|
|
uint8_t *U = Y + stride * height;
|
|
uint8_t *V = U + (stride / 2) * (height / 2);
|
|
|
|
for (unsigned int src_y = 0; src_y < bitmap->rows; src_y++) {
|
|
for (unsigned int src_x = 0; src_x < bitmap->width; src_x++) {
|
|
uint8_t v = bitmap->buffer[src_y*bitmap->pitch + src_x];
|
|
|
|
if (v != 0) {
|
|
unsigned int dest_x = x + src_x;
|
|
unsigned int dest_y = y + src_y;
|
|
int i1 = dest_y*stride + dest_x;
|
|
int i2 = dest_y/2*stride/2 + dest_x/2;
|
|
uint32_t opacity = (uint32_t)v;
|
|
|
|
Y[i1] = (uint8_t)(((uint32_t)v * opacity + (uint32_t)Y[i1] * (255 - opacity)) / 255);
|
|
U[i2] = (uint8_t)((128 * opacity + (uint32_t)U[i2] * (255 - opacity)) / 255);
|
|
V[i2] = (uint8_t)((128 * opacity + (uint32_t)V[i2] * (255 - opacity)) / 255);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int get_text_width(FT_Face face, const char *text) {
|
|
int ret = 0;
|
|
|
|
for (const char *ptr = text; *ptr != 0x00; ptr++) {
|
|
int error = FT_Load_Char(face, *ptr, FT_LOAD_RENDER);
|
|
if (error) {
|
|
continue;
|
|
}
|
|
|
|
ret += face->glyph->advance.x >> 6;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void text_draw(text_t *text, uint8_t *buf, int stride, int height) {
|
|
text_priv_t *textp = (text_priv_t *)text;
|
|
|
|
if (textp->enabled) {
|
|
time_t timer = time(NULL);
|
|
struct tm *tm_info = localtime(&timer);
|
|
char buffer[255];
|
|
memset(buffer, 0, sizeof(buffer));
|
|
strftime(buffer, 255, textp->text_overlay, tm_info);
|
|
|
|
draw_rect(
|
|
buf,
|
|
stride,
|
|
height,
|
|
7,
|
|
7,
|
|
get_text_width(textp->face, buffer) + 10,
|
|
34);
|
|
|
|
int x = 12;
|
|
int y = 33;
|
|
|
|
for (const char *ptr = buffer; *ptr != 0x00; ptr++) {
|
|
int error = FT_Load_Char(textp->face, *ptr, FT_LOAD_RENDER);
|
|
if (error) {
|
|
continue;
|
|
}
|
|
|
|
draw_bitmap(
|
|
buf,
|
|
stride,
|
|
height,
|
|
&textp->face->glyph->bitmap,
|
|
x + textp->face->glyph->bitmap_left,
|
|
y - textp->face->glyph->bitmap_top);
|
|
|
|
x += textp->face->glyph->advance.x >> 6;
|
|
}
|
|
}
|
|
}
|