mirror of
https://github.com/stasenso/ttf2bmp.git
synced 2026-06-26 21:42:43 +03:00
Draft by Grok
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
build/*
|
||||||
@@ -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
@@ -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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user