8 releases (stable)
new 2.2.6 | Dec 11, 2024 |
---|---|
2.2.4 | Dec 2, 2024 |
2.2.3 | Nov 27, 2024 |
#466 in Text processing
1,095 downloads per month
Used in cn-font-split
2MB
46K
SLoC
harfbuzz_rs_now
harfbuzz_rs_now
is a high-level interface to HarfBuzz, exposing its most important functionality in a safe manner using Rust. And we provide more powerful methods to you.
- normal usage
- subset font
- svg string output
- wasi32 support build!
What is HarfBuzz?
HarfBuzz is a library for performing complex text layout. It does not perform any drawing. This is quite a low-level operation. If you want to simply draw some text on the screen you should maybe choose another more high-level library. However if you want to build a library for drawing text on some canvas or need a lot of control on advanced text layout then this is the right library to use.
Getting Started
To shape a simple string of text you just create a Font
from a font file, fill
a Buffer
with some text and call the shape
function.
use harfbuzz_rs_now::*;
fn main() {
let path = "./src/SourceSansVariable-Roman.ttf";
let index = 0; //< face index in the font file
let mut face = Face::from_file(path, index).unwrap();
// create a font subset
let font_subset = subset::Subset::new();
let chars: [u32; 3] = [32, 33, 34];
font_subset.add_chars(&chars);
// Preserve all OpenType tables (like glyf, cmap, etc.) for full font functionality
font_subset.clear_drop_table();
// Maintain all OpenType layout features (like ligatures, kerning) and script support
font_subset.adjust_layout();
let new_font_face = font_subset.run_subset(&face);
let shared_data = new_font_face.face_data();
let binary_data_of_subset = shared_data.get_data();
std::fs::write("subset.ttf", binary_data_of_subset).expect("Failed to write font subset");
let mut font = Font::new(face);
let buffer = UnicodeBuffer::new().add_str("Hello World!");
let output = shape(&font, buffer, &[]);
// The results of the shaping operation are stored in the `output` buffer.
let positions = output.get_glyph_positions();
let infos = output.get_glyph_infos();
// iterate over the shaped glyphs
for (position, info) in positions.iter().zip(infos) {
let gid = info.codepoint;
let cluster = info.cluster;
let x_advance = position.x_advance;
let x_offset = position.x_offset;
let y_offset = position.y_offset;
// Here you would usually draw the glyphs.
println!(
"gid{:?}={:?}@{:?},{:?}+{:?}",
gid, cluster, x_advance, x_offset, y_offset
);
}
// render a simple string to svg!
let svg_string = font.render_svg_text("Hello World\nI can see you", &[]);
println!("{}", svg_string);
}
This should print out something similar to the following:
gid41=0@741,0+0
gid70=1@421,0+0
gid77=2@258,0+0
gid77=3@253,0+0
gid80=4@510,0+0
gid1=5@227,0+0
gid56=6@874,0+0
gid80=7@498,0+0
gid83=8@367,0+0
gid77=9@253,0+0
gid69=10@528,0+0
gid2=11@276,0+0
The values of x_advance
, x_offset
, y_advance
and y_offset
are all given in so-called font units by default.
By calling face.upem()
you get the number of font units per EM for
a specific face
. This upem
value can be used to scale the advances and offsets to a given font-size.
For example, if you want to display a font at 16 point (pt) size, that means that 1 EM = 16 pt.
In this example, to convert a value, say x_advance
, from font-units to points, we compute ((x_advance * font_size) as f64) / (upem as f64)
, where font_size = 16
is a variable specifying the font size in points.
Note that harfbuzz internally supports scaling fonts itself as well (using font.set_scale(...)
, etc.) but in my opinion it is easier to scale the results oneself as described in the paragraph above.
Supported HarfBuzz versions
This crate is tested to work with harfbuzz versions 2.0 and higher. Older versions may work as well. I recommend statically linking the harfbuzz library provided by the harfbuzz-sys
crate which is always up-to-date.
Wasm32-wasi Support
First, install the wasi-sdk, then set the WASI_SYSROOT environment variable to the share/wasi-sysroot path of your wasi-sdk. Finally, run cargo build --target wasm32-wasi.
apt install wget
WASI_OS=linux
WASI_ARCH=x86_64
WASI_VERSION=24
WASI_VERSION_FULL=${WASI_VERSION}.0
wget https://github.moeyy.xyz/https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_VERSION}/wasi-sdk-${WASI_VERSION_FULL}-${WASI_ARCH}-${WASI_OS}.tar.gz
if [ ! -d "/opt/wasi-sdk" ]; then
mkdir /opt/wasi-sdk
fi
tar xvf wasi-sdk-${WASI_VERSION_FULL}-${WASI_ARCH}-${WASI_OS}.tar.gz -C /opt/wasi-sdk
rm -rf wasi-sdk-${WASI_VERSION_FULL}-${WASI_ARCH}-${WASI_OS}.tar.gz
export WASI_SYSROOT="/opt/wasi-sdk/wasi-sdk-${WASI_VERSION_FULL}-${WASI_ARCH}-${WASI_OS}/share/wasi-sysroot"
echo -e "\nexport WASI_SYSROOT=\"${WASI_SYSROOT}\"\n" >> ~/.bashrc
Optional Features
If you want to use rusttype as font functions enable the rusttype
feature.