x.ttf #
TTF font utility
introduction
This module is designed to perform two main task
- Load the font file
- Render text using a TTF font
The render system can be single or multiple, for example it is possible to have a bitmap render and a HW accelerated render.
TTF loader
This part of the module do a simple task, load a TTF file and preprocess all the loaded data in order to simplify the rendering phase.
Let's start with a simple snippet of code that load a font from the disk:
mut ttf_font := ttf.TTF_File{}
ttf_font.buf = os.read_bytes('arial.ttf') or { panic(err) }
ttf_font.init()
Note > The font must be passed to the
TTF_file
as RAM buffer.
At this point the font "arial" is loaded and parsed and if it is a valid TTF font it is ready for the rendering. We can get some quick info on the font as string using the get_info_string
function:
println(ttf_font.get_info_string())
produces an output like this:
----- Font Info -----
font_family : Arial
font_sub_family : Normal
full_name : Arial
postscript_name : ArialMT
version : 1
font_revision : 5.06
magic_number : 5f0f3cf5
flags : 81b
created unixTS : 649950890
modified unixTS : 1282151447
units_per_em : 2048
box : [x_min:-1361, y_min:-665, x_Max:4096, y_Max:2060]
mac_style : 0
-----------------------
Once loaded a font the TTF_File
struct is filled with the font data and texts can be rendered. At high level no more action are required to use the loaded font. Multiple fonts can be loaded without problems at the same time.
TTF Bitmap render
In this module it is possible to have different renders running at the same time. At the present time all the rendering are made on the CPU, sokol is used only to draw the rendered text to the screen. Let's start with a simple snippet of code:
import os
import x.ttf
fn main() {
mut ttf_font := ttf.TTF_File{}
ttf_font.buf = os.read_bytes('arial.ttf') or { panic(err) }
ttf_font.init()
// print font info
println(ttf_font.get_info_string())
}
This simple code load a TTF font and display its basic information.
draw_text
The draw text function draw simple strings without indentation or other imagination tasks. At this point we can render a simple text:
import os
import x.ttf
fn main() {
mut ttf_font := ttf.TTF_File{}
ttf_font.buf = os.read_bytes('arial.ttf') or { panic(err) }
ttf_font.init()
// print font info
println(ttf_font.get_info_string())
bmp_width := 200
bmp_height := 64
bmp_layers := 4 // number of planes for an RGBA buffer
// memory size of the buffer
bmp_size := bmp_width * bmp_height * bmp_layers
font_size := 32 // font size in points
device_dpi := 72 // default screen DPI
// Formula for scale calculation
// scaler := (font_size * device dpi) / (72dpi * em_unit)
scale := f32(font_size * device_dpi) / f32(72 * ttf_font.units_per_em)
// height of the font to use in the buffer to separate the lines
y_base := int((ttf_font.y_max - ttf_font.y_min) * scale)
// declare the bitmap struct
mut bmp := ttf.BitMap{
tf: &ttf_font
buf: malloc(bmp_size)
buf_size: bmp_size
width: bmp_width
height: bmp_height
bp: bmp_layers
color: 00x000000FF // RGBA black
scale: scale
}
bmp.init_filler()
bmp.clear()
bmp.set_pos(10, y_base)
bmp.draw_text('Test Text!')
bmp.save_as_ppm('test.ppm')
}
This is the low level render that draw the text on a bitmap and save the bitmap on a disk as .ppm
file.
Note > The render in this case is a raw rendering without any postfiltering or other processing.
Using the low level rendering you need to manage all the amenities like allocate and release memory and other tasks like calc the character dimensions.
You can specify the style for the text rendering in the BitMap
struct::
enum Style {
outline
outline_aliased
filled // default style
raw
}
Use this level only if you want achieve particular result on text rendering.
draw_text_block
Draw text block draw a justified and indented block of multiline text in the bitmap.
import os
import x.ttf
fn main() {
mut ttf_font := ttf.TTF_File{}
ttf_font.buf = os.read_bytes('arial.ttf') or { panic(err) }
ttf_font.init()
// print font info
println(ttf_font.get_info_string())
bmp_width := 200
bmp_height := 200
bmp_layers := 4 // number of planes for an RGBA buffer
// memory size of the buffer
bmp_size := bmp_width * bmp_height * bmp_layers
font_size := 32 // font size in points
device_dpi := 72 // default screen DPI
// Formula for scale calculation
// scaler := (font_size * device dpi) / (72dpi * em_unit)
scale := f32(font_size * device_dpi) / f32(72 * ttf_font.units_per_em)
// height of the font to use in the buffer to separate the lines
y_base := int((ttf_font.y_max - ttf_font.y_min) * scale)
text := 'Today it is a good day!
Tomorrow I'm not so sure :(
But Vwill prevail for sure, V is the way!!
òàèì@ò!£$%&
'
// declare the bitmap struct
mut bmp := ttf.BitMap{
tf: &ttf_font
buf: malloc(bmp_size)
buf_size: bmp_size
width: bmp_width
height: bmp_height
bp: bmp_layers
color: 00x000000FF // RGBA black
scale: scale
}
bmp.init_filler()
bmp.clear()
bmp.justify = true
bmp.align = .left
bmp.draw_text_block(text, x: 0, y: 0, w: bmp_width - 20, h: bmp_height)
bmp.save_as_ppm('test.ppm')
}
This is the low level render that draw text block on the bitmap. A text block is defined from a Text_block
struct:
struct Text_block {
x int // x position of the left high corner
y int // y position of the left high corner
w int // width of the text block
h int // height of the text block
cut_lines bool = true // force to cut the line if the length is over the text block width
}
and use the following bitmap fields:
style Style = .filled // default style
align Text_align = .left // default text align
justify bool // justify text flag, default deactivated
justify_fill_ratio f32 = 0.5 // justify fill ratio, if the ratio of the filled
// row is >= of this then justify the text
It is possible to modify these parameters to obtain the desired effect on the text rendering.
TTF Sokol render
The sokol render use the bitmap render to create the text and the gg
functions to render the text to the screen. It is simpler to use in a gg app
than the raw bitmap render. Each single text rendered need its own reder to be declared, after you can modify it. Here a simple example of the usage:
import gg
import gx
import sokol.sapp
import sokol.sgl
import sokol.gfx
import x.ttf
import os
const win_width = 600
const win_height = 700
const bg_color = gx.white
const font_paths = [
'arial.ttf',
]
struct App_data {
pub mut:
gg &gg.Context = unsafe { nil }
sg_img gfx.Image
init_flag bool
frame_c int
tf []ttf.TTF_File
ttf_render []ttf.TTF_render_Sokol
}
fn my_init(mut app App_data) {
app.init_flag = true
}
fn draw_frame(mut app App_data) {
cframe_txt :='Current Frame: ${app.frame_c}'
app.gg.begin()
sgl.defaults()
sgl.matrix_mode_projection()
sgl.ortho(0.0, f32(sapp.width()), f32(sapp.height()), 0.0, -1.0, 1.0)
// draw text only if the app is already initialized
if app.init_flag == true {
// update the text
mut txt1 := &app.ttf_render[0]
txt1.destroy_texture()
txt1.create_text(cframe_txt, 43)
txt1.create_texture()
txt1.draw_text_bmp(app.gg, 30, 60)
}
app.frame_c++
app.gg.end()
}
fn main() {
mut app := &App_data{}
app.gg = gg.new_context(
width: win_width
height: win_height
create_window: true
window_title: 'Test TTF module'
user_data: app
bg_color: bg_color
frame_fn: draw_frame
init_fn: my_init
)
// load TTF fonts
for font_path in font_paths {
mut tf := ttf.TTF_File{}
tf.buf = os.read_bytes(font_path) or { panic(err) }
println('TrueTypeFont file [${font_path}] len: ${tf.buf.len}')
tf.init()
println(tf.get_info_string())
app.tf << tf
}
// TTF render 0 Frame counter
app.ttf_render << &ttf.TTF_render_Sokol{
bmp: &ttf.BitMap{
tf: &app.tf[0]
buf: unsafe { malloc(32000000) }
buf_size: (32000000)
color: 0xFF0000FF
// style: .raw
}
}
app.gg.run()
}
fn color_multiply #
fn color_multiply(c u32, level f32) u32
color_multiply multiplies R,G,B channels of color c
with the level
value.
fn color_multiply_alpha #
fn color_multiply_alpha(c u32, level f32) u32
color_multiply_alpha multiplies color c
's alpha channel with the level
value.
enum Style #
enum Style {
outline
outline_aliased
filled
raw
}
draw style
enum Text_align #
enum Text_align {
left
center
right
justify
}
text align
struct BitMap #
struct BitMap {
pub mut:
tf &TTF_File = unsafe { nil }
buf &u8 = unsafe { nil } // pointer to the memory buffer
buf_size int // allocated buf size in bytes
width int = 1 // width of the buffer
height int = 1 // height of the buffer
bp int = 4 // byte per pixel of the buffer
bg_color u32 = 00xFFFFFF00 // background RGBA format
color u32 = 00x000000FF // RGBA format
scale f32 = 1.0 // internal usage!!
scale_x f32 = 1.0 // X scale of the single glyph
scale_y f32 = 1.0 // Y scale of the single glyph
angle f32 = 0.0 // angle of rotation of the bitmap
// spaces
space_cw f32 = 1.0 // width of the space glyph internal usage!!
space_mult f32 = f32(0.0) // 1.0/16.0 // space between letter, is a multiplier for a standard space ax
// used only by internal text rendering!!
tr_matrix []f32 = [f32(1), 0, 0, 0, 1, 0, 0, 0, 0] // transformation matrix
ch_matrix []f32 = [f32(1), 0, 0, 0, 1, 0, 0, 0, 0] // character matrix
style Style = .filled // default style
align Text_align = .left // default text align
justify bool // justify text flag, default deactivated
justify_fill_ratio f32 = 0.5 // justify fill ratio, if the ratio of the filled row is >= of this then justify the text
filler [][]int // filler buffer for the renderer
// flag to force font embedded metrics
use_font_metrics bool
}
BitMap represents a bitmap image of text rendered with the font supplied via the tf
field.
fn (BitMap) aline #
fn (mut bmp BitMap) aline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32)
aline draws an aliased line on the bitmap
fn (BitMap) box #
fn (mut bmp BitMap) box(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32)
box plots a (hollow) box to the internal buffer from top-left in_x0
, in_y0
to bottom right in_x1
, in_y1
in color c
.
fn (BitMap) clear #
fn (mut bmp BitMap) clear()
clear clears the bitmap with 0 bytes.
fn (BitMap) clear_filler #
fn (mut bmp BitMap) clear_filler()
clear_filler clears the internal filler
buffer
fn (BitMap) draw_glyph #
fn (mut bmp BitMap) draw_glyph(index u16) (int, int)
draw_glyph plots the pixels of the glyph at index
to the internal buffer and returns the x_max
and x_min
values.
fn (BitMap) draw_text #
fn (mut bmp BitMap) draw_text(in_string string) (int, int)
draw_text plots the pixels of the text in_string
to the internal buffer and returns the text bounding box.
fn (BitMap) draw_text_block #
fn (mut bmp BitMap) draw_text_block(text string, block Text_block)
draw_text_block renders out text
in the Text_block
block
.
fn (BitMap) exec_filler #
fn (mut bmp BitMap) exec_filler()
exec_filler plots the pixels of the BitMap
to the internal buffer.
fn (BitMap) fline #
fn (mut bmp BitMap) fline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32)
fline populates the internal filler
buffer with a line segment from in_x0
,in_y0
to in_x1
,in_y1
.
fn (BitMap) get_bbox #
fn (mut bmp BitMap) get_bbox(in_string string) (int, int)
get_bbox returns the bounding box (width and height) of text in_string
.
fn (BitMap) get_chars_bbox #
fn (mut bmp BitMap) get_chars_bbox(in_string string) []int
get_chars_bbox returns all characters found in bounding box of string in_string
.
fn (BitMap) get_justify_space_cw #
fn (mut dev BitMap) get_justify_space_cw(txt string, w int, block_w int, space_cw int) f32
get_justify_space_cw returns the space needed to justify txt
.
fn (BitMap) get_raw_bytes #
fn (mut bmp BitMap) get_raw_bytes() []u8
get_raw_bytes returns the raw bytes of the bitmap.
fn (BitMap) init_filler #
fn (mut bmp BitMap) init_filler()
init_filler initializes the internal filler
buffer.
fn (BitMap) line #
fn (mut bmp BitMap) line(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32)
line plots a line segment to the internal buffer from in_x0
,in_y0
to in_x1
,in_y1
in the color c
.
fn (BitMap) plot #
fn (mut bmp BitMap) plot(x int, y int, c u32) bool
plot plots a pixel at x
,y
in color c
in the internal bitmap buffer.
fn (BitMap) quadratic #
fn (mut bmp BitMap) quadratic(in_x0 int, in_y0 int, in_x1 int, in_y1 int, in_cx int, in_cy int, c u32)
quadratic plots a quadratic Bezier curve in color c
.
fn (BitMap) save_as_ppm #
fn (mut bmp BitMap) save_as_ppm(file_name string)
save_as_ppm saves the BitMap
data in .ppm file format to file_name
.
fn (BitMap) save_raw_data #
fn (mut bmp BitMap) save_raw_data(file_name string)
save_raw_data saves the raw data to file_name
.
fn (BitMap) set_pos #
fn (mut bmp BitMap) set_pos(x f32, y f32)
set_pos sets the draw position in the buffer
fn (BitMap) set_rotation #
fn (mut bmp BitMap) set_rotation(a f32)
set_rotation sets the rotation angle in radians a
fn (BitMap) trf_ch #
fn (bmp &BitMap) trf_ch(p &Point) (int, int)
trf_ch returns the transform matrix applied to the char.
fn (BitMap) trf_txt #
fn (bmp &BitMap) trf_txt(p &Point) (int, int)
trf_txt returns the transform matrix applied to the text.
struct Glyph #
struct Glyph {
pub mut:
g_type u16 = g_type_simple
contour_ends []u16
number_of_contours i16
points []Point
x_min i16
x_max i16
y_min i16
y_max i16
valid_glyph bool
components []Component
}
Glyph represents a single renderable unit ("a character") of the TTF.
struct Point #
struct Point {
pub mut:
x int
y int
on_curve bool
}
Point represents a 2D point
struct TTF_File #
struct TTF_File {
pub mut:
buf []u8
pos u32
length u16
scalar_type u32
search_range u16
entry_selector u16
range_shift u16
tables map[string]Offset_Table
version f32
font_revision f32
checksum_adjustment u32
magic_number u32
flags u16
units_per_em u16
created u64
modified u64
x_min f32
y_min f32
x_max f32
y_max f32
mac_style u16
lowest_rec_ppem u16
font_direction_hint i16
index_to_loc_format i16
glyph_data_format i16
font_family string
font_sub_family string
full_name string
postscript_name string
cmaps []TrueTypeCmap
ascent i16
descent i16
line_gap i16
advance_width_max u16
min_left_side_bearing i16
min_right_side_bearing i16
x_max_extent i16
caret_slope_rise i16
caret_slope_run i16
caret_offset i16
metric_data_format i16
num_of_long_hor_metrics u16
kern []Kern0Table
// panose
panose_array []u8 = []u8{len: 12, init: 0}
// cache
glyph_cache map[int]Glyph
// font widths array scale for PDF export
width_scale f32 = 1.0
}
TTF_File represents the data contents of a complete *.ttf
file. The struct is usually initialized by reading raw TTF data into the buf
member field for example by doing: ttf_font.buf = os.read_bytes("arial.ttf") or { panic(err) }
, and then run the init/0
method, for example: ttf_font.init()
fn (TTF_File) init #
fn (mut tf TTF_File) init()
init initializes essential TTF_File
fields from the contents of buf
.
fn (TTF_File) get_horizontal_metrics #
fn (mut tf TTF_File) get_horizontal_metrics(glyph_index u16) (int, int)
get_horizontal_metrics returns the horizontal metrics advance_width
and left_side_bearing
for the glyph at index glyph_index
.
fn (TTF_File) glyph_count #
fn (mut tf TTF_File) glyph_count() u16
glyph_count returns the number of glyphs available in the TTF.
fn (TTF_File) read_glyph_dim #
fn (mut tf TTF_File) read_glyph_dim(index u16) (int, int, int, int)
read_glyph_dim returns glyph dimension data in the form x_min
, x_max
, y_min
and y_max
.
fn (TTF_File) get_ttf_widths #
fn (mut tf TTF_File) get_ttf_widths() ([]int, int, int)
get_ttf_widths returns all possible widths of the TTF.
fn (TTF_File) read_glyph #
fn (mut tf TTF_File) read_glyph(index u16) Glyph
read_glyph returns Glyph
data for the glyph at index
.
fn (TTF_File) map_code #
fn (mut tf TTF_File) map_code(char_code int) u16
map_code returns the glyph index for the char_code
character code. map_code returns 0
if the character code could not be found.
fn (TTF_File) reset_kern #
fn (mut tf TTF_File) reset_kern()
reset_kern resets the internal kerning table data.
fn (TTF_File) next_kern #
fn (mut tf TTF_File) next_kern(glyph_index int) (int, int)
next_kern returns the next x
, y
kerning for the glyph at index glyph_index
.
fn (TTF_File) get_info_string #
fn (tf TTF_File) get_info_string() string
get_info_string returns a string with various information about the TTF.
struct TTF_render_Sokol #
struct TTF_render_Sokol {
pub mut:
bmp &BitMap = unsafe { nil } // Base bitmap render
// rendering fields
sg_img gfx.Image // sokol image
sg_smp gfx.Sampler // sokol sampler
scale_reduct f32 = 2.0 // scale of the cpu texture for filtering
device_dpi int = 72 // device DPI
}
TTF_render_Sokol is a structure containing data for rendering a TTF font as a sokol texture
fn (TTF_render_Sokol) format_texture #
fn (mut tf_skl TTF_render_Sokol) format_texture()
format_texture formats the BMP (bitmap).
fn (TTF_render_Sokol) create_text #
fn (mut tf_skl TTF_render_Sokol) create_text(in_txt string, in_font_size f32)
create_text prepares the text in_txt
in size in_font_size
as a sokol texture.
fn (TTF_render_Sokol) create_text_block #
fn (mut tf_skl TTF_render_Sokol) create_text_block(in_txt string, in_w int, in_h int, in_font_size f32)
create_text_block prepares a block of text as a sokol texture.
fn (TTF_render_Sokol) create_texture #
fn (mut tf_skl TTF_render_Sokol) create_texture()
create_texture creates the sokol texture from the internal buffer state.
fn (TTF_render_Sokol) destroy_texture #
fn (tf_skl TTF_render_Sokol) destroy_texture()
destroy_texture detroys the internal sokol texture.
fn (TTF_render_Sokol) update_text_texture #
fn (mut tf_skl TTF_render_Sokol) update_text_texture()
update_text_texture updates the sokol texture with current internal state.
Note: Only use if .dynamic
is set.
fn (TTF_render_Sokol) draw_text_bmp #
fn (tf_skl TTF_render_Sokol) draw_text_bmp(ctx &gg.Context, x f32, y f32)
draw_text_bmp renders the internal state to the current sokol pipeline.
struct Text_block #
struct Text_block {
x int // x position of the left high corner
y int // y position of the left high corner
w int // width of the text block
h int // height of the text block
cut_lines bool = true // force to cut the line if the length is over the text block width
}
Text_block represents a visual block of TTF text.
- README
- fn color_multiply
- fn color_multiply_alpha
- enum Style
- enum Text_align
- struct BitMap
- fn aline
- fn box
- fn clear
- fn clear_filler
- fn draw_glyph
- fn draw_text
- fn draw_text_block
- fn exec_filler
- fn fline
- fn get_bbox
- fn get_chars_bbox
- fn get_justify_space_cw
- fn get_raw_bytes
- fn init_filler
- fn line
- fn plot
- fn quadratic
- fn save_as_ppm
- fn save_raw_data
- fn set_pos
- fn set_rotation
- fn trf_ch
- fn trf_txt
- struct Glyph
- struct Point
- struct TTF_File
- struct TTF_render_Sokol
- struct Text_block