Skip to content

Commit 1dddfdf

Browse files
committed
vcap/tescard2: draw scale the non-TTF drawn font
1 parent 9420b20 commit 1dddfdf

File tree

3 files changed

+91
-28
lines changed

3 files changed

+91
-28
lines changed

src/utils/text.c

Lines changed: 79 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,10 @@ wrap_paragraph(char *text)
238238
return text;
239239
}
240240

241+
242+
static unsigned char font_data[(FONT_W * FONT_COUNT + 7) / 8 * FONT_H];
243+
static bool font_data_initialized = false;
244+
241245
// since the data are already in memory, it would be also possible to use
242246
// pointer directly to font array (skipping or deleting PBM header)
243247
static bool draw_line_init(unsigned char *out) {
@@ -263,41 +267,51 @@ static bool draw_line_init(unsigned char *out) {
263267

264268
memcpy(out, font_data, (info.width + 7) / 8 * info.height);
265269
free(font_data);
270+
font_data_initialized = true;
266271
return true;
267272
}
268273

274+
/// draw the letter as RGBA pixmap
269275
static void
270-
draw_letter(char c, uint32_t color, char *buf, const unsigned char *font_data,
271-
int pitch, bool solid)
276+
draw_letter(char c, uint32_t fg, uint32_t bg, unsigned char *buf,
277+
const unsigned char *font_data, int pitch)
272278
{
273279
if (c < ' ' || c > '~') {
274280
c = '?';
275281
}
276282
c -= ' ';
283+
const unsigned char fg0 = fg & 0xFFU;
284+
const unsigned char fg1 = (fg >> 8U) & 0xFFU;
285+
const unsigned char fg2 = (fg >> 16U) & 0xFFU;
286+
const unsigned char fg3 = (fg >> 24U) & 0xFFU;
287+
const unsigned char bg0 = bg & 0xFFU;
288+
const unsigned char bg1 = (bg >> 8U) & 0xFFU;
289+
const unsigned char bg2 = (bg >> 16U) & 0xFFU;
290+
const unsigned char bg3 = (bg >> 24U) & 0xFFU;
277291
for (int j = 0; j < FONT_H; ++j) {
278292
for (int i = 0; i < FONT_W; ++i) {
279293
int pos_x = (FONT_W * c + i) / 8;
280294
int mask = 1 << (FONT_W - ((FONT_W * c + i) % 8));
281295
int offset = (FONT_W * FONT_COUNT + 7) / 8 * j;
282296
if (font_data[offset + pos_x] & mask) {
283297
// clang-format off
284-
buf[(j * pitch) + (4 * i)] = color & 0xFFU;
285-
buf[(j * pitch) + (4 * i) + 1] = (color >> 8U) & 0xFFU;
286-
buf[(j * pitch) + (4 * i) + 2] = (color >> 16U) & 0xFFU;
287-
buf[(j * pitch) + (4 * i) + 3] = (color >> 24U) & 0xFFU;
298+
buf[(j * pitch) + (4 * i)] = fg0;
299+
buf[(j * pitch) + (4 * i) + 1] = fg1;
300+
buf[(j * pitch) + (4 * i) + 2] = fg2;
301+
buf[(j * pitch) + (4 * i) + 3] = fg3;
288302
// clang-format on
289-
} else if (solid) {
290-
buf[(j * pitch) + (4 * i)] = 0;
291-
buf[(j * pitch) + (4 * i) + 1] = 0;
292-
buf[(j * pitch) + (4 * i) + 2] = 0;
293-
buf[(j * pitch) + (4 * i) + 3] = 0xFFU; // alpha
303+
} else if (bg != 0) {
304+
buf[(j * pitch) + (4 * i)] = bg0;
305+
buf[(j * pitch) + (4 * i) + 1] = bg1;
306+
buf[(j * pitch) + (4 * i) + 2] = bg2;
307+
buf[(j * pitch) + (4 * i) + 3] = bg3;
294308
}
295309
}
296-
if (solid) { // fill space between characters
297-
buf[(j * pitch) + (4 * (FONT_W_SPACE - 1))] = 0;
298-
buf[(j * pitch) + (4 * (FONT_W_SPACE - 1)) + 1] = 0;
299-
buf[(j * pitch) + (4 * (FONT_W_SPACE - 1)) + 2] = 0;
300-
buf[(j * pitch) + (4 * (FONT_W_SPACE - 1)) + 3] = 0xFFU;
310+
if (bg) { // fill space between characters
311+
buf[(j * pitch) + (4 * (FONT_W_SPACE - 1))] = bg0;
312+
buf[(j * pitch) + (4 * (FONT_W_SPACE - 1)) + 1] = bg1;
313+
buf[(j * pitch) + (4 * (FONT_W_SPACE - 1)) + 2] = bg2;
314+
buf[(j * pitch) + (4 * (FONT_W_SPACE - 1)) + 3] = bg3;
301315
}
302316
}
303317
}
@@ -306,19 +320,17 @@ draw_letter(char c, uint32_t color, char *buf, const unsigned char *font_data,
306320
* draws a line with built-in bitmap 12x7 bitmap font separated by 1 px space, RGBA
307321
*/
308322
bool draw_line(char *buf, int pitch, const char *text, uint32_t color, bool solid) {
309-
static unsigned char font_data[(FONT_W * FONT_COUNT + 7) / 8 * FONT_H];
310-
static bool font_data_initialized = false;
311-
if (!font_data_initialized) {
312-
if (!draw_line_init(font_data)) {
313-
return false;
314-
}
315-
font_data_initialized = true;
323+
if (!font_data_initialized && !draw_line_init(font_data)) {
324+
return false;
316325
}
317326
int idx = 0;
327+
const uint32_t bg = solid ? 0xFF000000U : 0;
318328
while (*text) {
319329
char c = *text++;
320-
draw_letter(c, color, buf + (size_t) (4 * idx * FONT_W_SPACE),
321-
font_data, pitch, solid);
330+
draw_letter(c, color, bg,
331+
(unsigned char *) buf +
332+
(size_t) (4 * idx * FONT_W_SPACE),
333+
font_data, pitch);
322334
if ((++idx + 1) * FONT_W_SPACE * 4 > pitch) {
323335
return true;
324336
}
@@ -327,6 +339,48 @@ bool draw_line(char *buf, int pitch, const char *text, uint32_t color, bool soli
327339
return true;
328340
}
329341

342+
/**
343+
* similar to draw_line() but integer upscaling can be applied
344+
*
345+
* transparency not supported/implemented
346+
*
347+
* @param bg must not be 0, use 0xFF<<24 (alpha set to 0xFF)
348+
*/
349+
bool
350+
draw_line_scaled(char *buf, int pitch, const char *text, uint32_t fg,
351+
uint32_t bg, unsigned scale)
352+
{
353+
(void) buf;
354+
assert(scale > 0);
355+
assert(bg != 0); // draw letter would than assume transparency which
356+
// doesn't work with the _scaled version
357+
if (!font_data_initialized && !draw_line_init(font_data)) {
358+
return false;
359+
}
360+
int idx = 0;
361+
while (*text) {
362+
char c = *text++;
363+
unsigned char letter[4 * FONT_W_SPACE * FONT_H];
364+
draw_letter(c, fg, bg, letter, font_data, 4 * FONT_W_SPACE);
365+
// resize
366+
for (unsigned y = 0; y < FONT_H; ++y) {
367+
for (unsigned x = 0; x < FONT_W_SPACE; ++x) {
368+
for (unsigned sv = 0; sv < scale; ++sv) {
369+
for (unsigned sh = 0; sh < scale; ++sh) {
370+
memcpy(buf + ((scale * y + sv) * pitch + (((idx * scale * FONT_W_SPACE)
371+
+ (x * scale + sh)) * 4)), letter + (4 * (y * FONT_W_SPACE + x)), 4);
372+
}
373+
}
374+
}
375+
}
376+
if ((++idx + 1) * FONT_W_SPACE * 4 * scale > (unsigned) pitch) {
377+
return true;
378+
}
379+
}
380+
381+
return true;
382+
}
383+
330384
/// @returns null-terminated list of TTF font candidates
331385
const char *const *
332386
get_font_candidates()

src/utils/text.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @author Martin Pulec <[email protected]>
44
*/
55
/*
6-
* Copyright (c) 2014-2023 CESNET z.s.p.o.
6+
* Copyright (c) 2014-2025 CESNET, zájmové sdružení právnických osob
77
* All rights reserved.
88
*
99
* Redistribution and use in source and binary forms, with or without
@@ -59,6 +59,8 @@ size_t urlencode(char *out, size_t max_len, const char *in, int (*eval_pass)(int
5959
size_t urldecode(char *out, size_t max_len, const char *in);
6060

6161
bool draw_line(char *buf, int pitch, const char *text, uint32_t color, bool solid);
62+
bool draw_line_scaled(char *buf, int pitch, const char *text, uint32_t fg,
63+
uint32_t bg, unsigned scale);
6264

6365
const char *const *get_font_candidates(void);
6466

src/video_capture/testcard2.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
# define SDL_ERR (-1)
6868
# endif // defined HAVE_SDL3
6969
#else
70+
# include "utils/bitmap_font.h"
7071
# define SDL_DestroySurface(...)
7172
#endif
7273

@@ -531,8 +532,14 @@ void * vidcap_testcard2_thread(void *arg)
531532
}
532533
}
533534
#else
534-
draw_line((char *) banner, vc_get_linesize(s->desc.width, RGBA),
535-
frames, 0x0, false);
535+
int scale = FONT_HEIGHT / FONT_H;
536+
int w = strlen(frames) * FONT_W_SPACE * scale;
537+
int h = FONT_H * scale;
538+
long xoff = ((long) s->desc.width - w) / 2;
539+
long yoff = (BANNER_HEIGHT - h) / 2;
540+
int linesz = vc_get_linesize(s->desc.width, RGBA);
541+
draw_line_scaled((char *) banner + yoff * linesz + xoff * 4,
542+
linesz, frames, 0xFF000000U, 0xFFFFFFFFU, scale);
536543
#endif // defined HAVE_LIBSDL_TTF
537544

538545
testcard_convert_buffer(

0 commit comments

Comments
 (0)