22 changed files with 8993 additions and 159 deletions
@ -0,0 +1,87 @@ |
|||||||
|
#include <stddef.h> |
||||||
|
#include <stdint.h> |
||||||
|
#include <string.h> |
||||||
|
#include <stdlib.h> |
||||||
|
|
||||||
|
#include "base64.h" |
||||||
|
|
||||||
|
static const unsigned char decoding_table[256] = { |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3f, |
||||||
|
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, |
||||||
|
0x3c, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, |
||||||
|
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, |
||||||
|
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, |
||||||
|
0x17, 0x18, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, |
||||||
|
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, |
||||||
|
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, |
||||||
|
0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||||
|
}; |
||||||
|
|
||||||
|
char* base64_decode(const char *data) { |
||||||
|
size_t input_length = strlen(data); |
||||||
|
if (input_length % 4 != 0) { |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
size_t output_length = input_length / 4 * 3; |
||||||
|
|
||||||
|
if (data[input_length - 1] == '=') { |
||||||
|
(output_length)--; |
||||||
|
} |
||||||
|
if (data[input_length - 2] == '=') { |
||||||
|
(output_length)--; |
||||||
|
} |
||||||
|
|
||||||
|
unsigned char* output = (unsigned char *)malloc(output_length + 1); |
||||||
|
if (output == NULL) { |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
for (int i = 0, j = 0; i < (int)input_length;) { |
||||||
|
uint32_t sextet_a = (data[i] == '=') ? (0 & i++) : decoding_table[(unsigned char)(data[i++])]; |
||||||
|
uint32_t sextet_b = (data[i] == '=') ? (0 & i++) : decoding_table[(unsigned char)(data[i++])]; |
||||||
|
uint32_t sextet_c = (data[i] == '=') ? (0 & i++) : decoding_table[(unsigned char)(data[i++])]; |
||||||
|
uint32_t sextet_d = (data[i] == '=') ? (0 & i++) : decoding_table[(unsigned char)(data[i++])]; |
||||||
|
|
||||||
|
uint32_t triple = (sextet_a << 3 * 6) |
||||||
|
+ (sextet_b << 2 * 6) |
||||||
|
+ (sextet_c << 1 * 6) |
||||||
|
+ (sextet_d << 0 * 6); |
||||||
|
|
||||||
|
if (j < (int)output_length) { |
||||||
|
output[j++] = (triple >> 2 * 8) & 0xFF; |
||||||
|
} |
||||||
|
if (j < (int)output_length) { |
||||||
|
output[j++] = (triple >> 1 * 8) & 0xFF; |
||||||
|
} |
||||||
|
if (j < (int)output_length) { |
||||||
|
output[j++] = (triple >> 0 * 8) & 0xFF; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
output[output_length] = 0x00; |
||||||
|
return (char *)output; |
||||||
|
}; |
||||||
@ -0,0 +1,6 @@ |
|||||||
|
#ifndef __BASE64_H__ |
||||||
|
#define __BASE64_H__ |
||||||
|
|
||||||
|
char* base64_decode(const char *data); |
||||||
|
|
||||||
|
#endif |
||||||
@ -0,0 +1,171 @@ |
|||||||
|
#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, |
||||||
|
IBMPlexMono_Medium, |
||||||
|
sizeof(IBMPlexMono_Medium), |
||||||
|
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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,15 @@ |
|||||||
|
#ifndef __TEXT_H__ |
||||||
|
#define __TEXT_H__ |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
#include <stdbool.h> |
||||||
|
|
||||||
|
#include "parameters.h" |
||||||
|
|
||||||
|
typedef void text_t; |
||||||
|
|
||||||
|
const char *text_get_error(); |
||||||
|
bool text_create(const parameters_t *params, text_t **text); |
||||||
|
void text_draw(text_t *text, uint8_t *buf, int stride, int height); |
||||||
|
|
||||||
|
#endif |
||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue