Draft by Grok

This commit is contained in:
Stanislav N Mikhailov
2025-07-26 23:04:01 +03:00
parent e1a0bc8f66
commit 26163c37be
3 changed files with 172 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
build/*
+27
View File
@@ -0,0 +1,27 @@
cmake_minimum_required(VERSION 3.15)
project(ttf2bmp)
# 1. Скачиваем STB в libs/stb
include(FetchContent)
FetchContent_Declare(
stb
GIT_REPOSITORY https://github.com/nothings/stb.git
GIT_TAG master
SOURCE_DIR "${CMAKE_SOURCE_DIR}/libs/stb"
)
FetchContent_MakeAvailable(stb)
# 2. Добавляем libs/stb в include-пути
include_directories(libs/stb)
# 3. Компилируем основную программу (STB реализован прямо в ttf2bmp.c)
add_executable(ttf2bmp src/ttf2bmp.c)
# Подключаем математическую библиотеку (libm)
target_link_libraries(ttf2bmp PRIVATE m)
# Устанавливаем стандарт C для всего проекта (опционально)
set_property(TARGET ttf2bmp PROPERTY C_STANDARD 11)
set_property(TARGET ttf2bmp PROPERTY CXX_STANDARD 11) # Если вдруг есть C++ код
+144
View File
@@ -0,0 +1,144 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STB_TRUETYPE_IMPLEMENTATION
#include "stb_truetype.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
// Функция для декодирования UTF-8 в кодовую точку Unicode
int utf8_to_unicode(const char *str, int *bytes_read) {
unsigned char c = str[0];
if (c < 0x80) {
*bytes_read = 1;
return c;
} else if ((c & 0xE0) == 0xC0) {
*bytes_read = 2;
return ((str[0] & 0x1F) << 6) | (str[1] & 0x3F);
} else if ((c & 0xF0) == 0xE0) {
*bytes_read = 3;
return ((str[0] & 0x0F) << 12) | ((str[1] & 0x3F) << 6) | (str[2] & 0x3F);
}
*bytes_read = 1;
return 0; // Некорректный символ
}
int main(int argc, char *argv[]) {
if (argc != 3) {
fprintf(stderr, "Usage: %s <font_path> <font_height>\n", argv[0]);
return 1;
}
// Чтение файла шрифта
FILE *font_file = fopen(argv[1], "rb");
if (!font_file) {
fprintf(stderr, "Failed to open font file: %s\n", argv[1]);
return 1;
}
fseek(font_file, 0, SEEK_END);
long font_size = ftell(font_file);
fseek(font_file, 0, SEEK_SET);
unsigned char *font_data = malloc(font_size);
fread(font_data, 1, font_size, font_file);
fclose(font_file);
// Инициализация шрифта
stbtt_fontinfo font;
if (!stbtt_InitFont(&font, font_data, 0)) {
fprintf(stderr, "Failed to initialize font\n");
free(font_data);
return 1;
}
// Парсинг высоты шрифта
int font_height = atoi(argv[2]);
if (font_height <= 0) {
fprintf(stderr, "Invalid font height: %s\n", argv[2]);
free(font_data);
return 1;
}
// Набор символов (ASCII + кириллица)
const char *chars = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
"АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя";
// Подсчет кодовых точек
int char_count = 0;
for (int i = 0; chars[i]; ) {
int bytes_read;
utf8_to_unicode(&chars[i], &bytes_read);
i += bytes_read;
char_count++;
}
// Массив для хранения кодовых точек
int *codepoints = malloc(char_count * sizeof(int));
int idx = 0;
for (int i = 0; chars[i]; ) {
int bytes_read;
codepoints[idx++] = utf8_to_unicode(&chars[i], &bytes_read);
i += bytes_read;
}
// Расчет масштаба и метрик
float scale = stbtt_ScaleForPixelHeight(&font, font_height);
int ascent, descent, line_gap;
stbtt_GetFontVMetrics(&font, &ascent, &descent, &line_gap);
ascent = (int)(ascent * scale);
descent = (int)(descent * scale);
// Расчет общей ширины с дополнительным отступом (20% от ширины символа)
const float spacing_factor = 1.3f; // 20% дополнительного пространства
int total_width = 0;
for (int i = 0; i < char_count; i++) {
int advance, lsb;
stbtt_GetCodepointHMetrics(&font, codepoints[i], &advance, &lsb);
total_width += (int)(advance * scale * spacing_factor);
}
// Создание битмапа
unsigned char *bitmap = calloc(total_width * font_height, 1);
if (!bitmap) {
fprintf(stderr, "Failed to allocate bitmap\n");
free(codepoints);
free(font_data);
return 1;
}
// Рендеринг каждого символа
int x_offset = 0;
for (int i = 0; i < char_count; i++) {
int w, h, xoff, yoff;
unsigned char *glyph = stbtt_GetCodepointBitmap(&font, 0, scale, codepoints[i], &w, &h, &xoff, &yoff);
// Копирование глифа в битмап
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
int bitmap_x = x_offset + x + xoff;
int bitmap_y = ascent + y + yoff;
if (bitmap_x >= 0 && bitmap_x < total_width && bitmap_y >= 0 && bitmap_y < font_height) {
bitmap[bitmap_y * total_width + bitmap_x] = glyph[y * w + x];
}
}
}
// Обновление x_offset с учетом отступа
int advance, lsb;
stbtt_GetCodepointHMetrics(&font, codepoints[i], &advance, &lsb);
x_offset += (int)(advance * scale * spacing_factor);
stbtt_FreeBitmap(glyph, NULL);
}
// Запись BMP
if (!stbi_write_bmp("output.bmp", total_width, font_height, 1, bitmap)) {
fprintf(stderr, "Failed to write BMP file\n");
}
// Очистка
free(bitmap);
free(codepoints);
free(font_data);
return 0;
}