Add initial sources.
This commit is contained in:
commit
2c725d3cdd
145
dft.c
Normal file
145
dft.c
Normal file
@ -0,0 +1,145 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_STROKER_H
|
||||
|
||||
#define round_up_26_6(val) (((val) + 63) >> 6u)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int32_t line_height;
|
||||
int32_t baseline_offset;
|
||||
FT_Face ft_face;
|
||||
} dft_font_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t * bitmap;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
int32_t left;
|
||||
int32_t top;
|
||||
int32_t advance;
|
||||
FT_Glyph ft_glyph;
|
||||
} dft_glyph_t;
|
||||
|
||||
static FT_Library ft_library_handle;
|
||||
static bool ft_initialized;
|
||||
|
||||
static bool initialize_freetype()
|
||||
{
|
||||
if (ft_initialized)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (FT_Init_FreeType(&ft_library_handle) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ft_initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
dft_glyph_t * dft_glyph_new(dft_font_t * dft_font, uint32_t char_code, int32_t outline_size)
|
||||
{
|
||||
FT_Glyph glyph;
|
||||
FT_BitmapGlyph bitmap_glyph;
|
||||
|
||||
FT_UInt glyph_index = FT_Get_Char_Index(dft_font->ft_face, char_code);
|
||||
|
||||
/* Load the glyph to the face object. */
|
||||
FT_Load_Glyph(dft_font->ft_face, glyph_index, FT_LOAD_NO_BITMAP);
|
||||
FT_Get_Glyph(dft_font->ft_face->glyph, &glyph);
|
||||
|
||||
if (outline_size > 0)
|
||||
{
|
||||
FT_Stroker stroker;
|
||||
FT_Stroker_New(ft_library_handle, &stroker);
|
||||
FT_Stroker_Set(stroker, outline_size, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
|
||||
FT_Glyph_StrokeBorder(&glyph, stroker, false, true);
|
||||
}
|
||||
FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, NULL, true);
|
||||
bitmap_glyph = (FT_BitmapGlyph)glyph;
|
||||
|
||||
int32_t width = bitmap_glyph->bitmap.width;
|
||||
int32_t height = bitmap_glyph->bitmap.rows;
|
||||
dft_glyph_t * dft_glyph = (dft_glyph_t *)malloc(sizeof(dft_glyph_t));
|
||||
dft_glyph->ft_glyph = glyph;
|
||||
dft_glyph->width = width;
|
||||
dft_glyph->height = height;
|
||||
dft_glyph->left = bitmap_glyph->left;
|
||||
dft_glyph->top = bitmap_glyph->top;
|
||||
dft_glyph->advance = round_up_26_6(dft_font->ft_face->glyph->advance.x);
|
||||
size_t n_bytes = (size_t)(width * height);
|
||||
dft_glyph->bitmap = (uint8_t *)malloc(n_bytes);
|
||||
memcpy(dft_glyph->bitmap, bitmap_glyph->bitmap.buffer, n_bytes);
|
||||
|
||||
return dft_glyph;
|
||||
}
|
||||
|
||||
void dft_glyph_free(dft_glyph_t * dft_glyph)
|
||||
{
|
||||
FT_Done_Glyph(dft_glyph->ft_glyph);
|
||||
free(dft_glyph->bitmap);
|
||||
free(dft_glyph);
|
||||
}
|
||||
|
||||
static inline void build_font_metrics(dft_font_t * dft_font)
|
||||
{
|
||||
static const char load_chars[] = "Mg_^";
|
||||
|
||||
int max_top = INT_MIN;
|
||||
int min_bottom = INT_MAX;
|
||||
|
||||
for (size_t i = 0u; i < (sizeof(load_chars) - 1u); i++)
|
||||
{
|
||||
dft_glyph_t * dft_glyph = dft_glyph_new(dft_font, load_chars[i], 0);
|
||||
if (dft_glyph->top > max_top)
|
||||
{
|
||||
max_top = dft_glyph->top;
|
||||
}
|
||||
int bottom = dft_glyph->top - dft_glyph->height;
|
||||
if (bottom < min_bottom)
|
||||
{
|
||||
min_bottom = bottom;
|
||||
}
|
||||
}
|
||||
|
||||
dft_font->line_height = round_up_26_6(dft_font->ft_face->size->metrics.height);
|
||||
dft_font->baseline_offset = (dft_font->line_height - (max_top - min_bottom)) / 2 - min_bottom;
|
||||
}
|
||||
|
||||
dft_font_t * dft_font_new(const uint8_t * file_data, uint32_t file_size, int font_size)
|
||||
{
|
||||
if (!initialize_freetype())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FT_Face ft_face;
|
||||
|
||||
if (FT_New_Memory_Face(ft_library_handle, file_data, file_size, 0, &ft_face) != 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dft_font_t * dft_font = (dft_font_t *)malloc(sizeof(dft_font_t));
|
||||
dft_font->ft_face = ft_face;
|
||||
|
||||
FT_Set_Pixel_Sizes(ft_face, 0, font_size);
|
||||
|
||||
build_font_metrics(dft_font);
|
||||
|
||||
return dft_font;
|
||||
}
|
||||
|
||||
void dft_font_free(dft_font_t * dft_font)
|
||||
{
|
||||
FT_Done_Face(dft_font->ft_face);
|
||||
free(dft_font);
|
||||
}
|
96
package.d
Normal file
96
package.d
Normal file
@ -0,0 +1,96 @@
|
||||
module dft;
|
||||
|
||||
import std.file;
|
||||
|
||||
private struct dft_font_t
|
||||
{
|
||||
int line_height;
|
||||
int baseline_offset;
|
||||
};
|
||||
|
||||
private struct dft_glyph_t
|
||||
{
|
||||
ubyte * bitmap;
|
||||
int width;
|
||||
int height;
|
||||
int left;
|
||||
int top;
|
||||
int advance;
|
||||
};
|
||||
|
||||
private extern(C) dft_glyph_t * dft_glyph_new(dft_font_t * dft_font, uint char_code, int outline_size);
|
||||
private extern(C) void dft_glyph_free(dft_glyph_t * dft_glyph);
|
||||
private extern(C) dft_font_t * dft_font_new(const ubyte * file_data, uint file_size, int font_size);
|
||||
private extern(C) void dft_font_free(dft_font_t * dft_font);
|
||||
|
||||
class Font
|
||||
{
|
||||
class Glyph
|
||||
{
|
||||
dft_glyph_t * m_dft_glyph;
|
||||
|
||||
private this(Font font, uint char_code, int outline_size)
|
||||
{
|
||||
m_dft_glyph = dft_glyph_new(font.m_dft_font, char_code, outline_size);
|
||||
}
|
||||
|
||||
~this()
|
||||
{
|
||||
dft_glyph_free(m_dft_glyph);
|
||||
}
|
||||
|
||||
@property int width()
|
||||
{
|
||||
return m_dft_glyph.width;
|
||||
}
|
||||
|
||||
@property int height()
|
||||
{
|
||||
return m_dft_glyph.height;
|
||||
}
|
||||
|
||||
@property int left()
|
||||
{
|
||||
return m_dft_glyph.left;
|
||||
}
|
||||
|
||||
@property int top()
|
||||
{
|
||||
return m_dft_glyph.top;
|
||||
}
|
||||
|
||||
@property const(ubyte)[] bitmap()
|
||||
{
|
||||
int n_bytes = width * height;
|
||||
return m_dft_glyph.bitmap[0..n_bytes];
|
||||
}
|
||||
}
|
||||
|
||||
dft_font_t * m_dft_font;
|
||||
|
||||
this(const(ubyte)[] file_data, int font_size)
|
||||
{
|
||||
m_dft_font = dft_font_new(file_data.ptr, cast(uint)file_data.length, font_size);
|
||||
}
|
||||
|
||||
this(string file_name, int font_size)
|
||||
{
|
||||
const(ubyte)[] file_data = cast(const(ubyte)[])std.file.read(file_name);
|
||||
this(file_data, font_size);
|
||||
}
|
||||
|
||||
~this()
|
||||
{
|
||||
dft_font_free(m_dft_font);
|
||||
}
|
||||
|
||||
@property int line_height()
|
||||
{
|
||||
return m_dft_font.line_height;
|
||||
}
|
||||
|
||||
@property int baseline_offset()
|
||||
{
|
||||
return m_dft_font.baseline_offset;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user