Browse Source

textium: Add, wire up, and add example of rasterizing characters

master
Erin 8 years ago
parent
commit
cd93bc73da
4 changed files with 112 additions and 3 deletions
  1. BIN
      textium/examples/Gudea-Regular.ttf
  2. +26
    -0
      textium/examples/render_char.rs
  3. +3
    -3
      textium/src/lib.rs
  4. +83
    -0
      textium/src/rasterizer.rs

BIN
textium/examples/Gudea-Regular.ttf View File


+ 26
- 0
textium/examples/render_char.rs View File

@ -0,0 +1,26 @@
extern crate textium;
extern crate rusttype;
use rusttype::{FontCollection};
fn main() {
let font_data = include_bytes!("Gudea-Regular.ttf");
let font = FontCollection::from_bytes(font_data as &[u8])
.into_font().unwrap();
let font = textium::Font::new(font);
let (metadata, bitmap) = font.rasterize_char('A', 40.0).unwrap();
println!("{:?}", metadata);
for line in bitmap.lines() {
for &pixel in line {
if pixel == 0 {
print!(" ");
} else {
print!("#");
}
}
println!();
}
}

+ 3
- 3
textium/src/lib.rs View File

@ -4,19 +4,19 @@ extern crate rusttype;
#[macro_use]
extern crate glium;
mod error;
mod texture;
mod geometry;
mod error;
mod rasterizer;
use std::iter::Iterator;
use std::collections::HashMap;
use glium::backend::Facade;
use glium::texture::Texture2d;
use rusttype::Font;
use texture::{Texture2dData, get_nearest_pow2};
pub use error::Error;
pub use geometry::Rect;
pub use rasterizer::Font;
/// Information used to render a glyph in a font.
#[derive(Debug)]


+ 83
- 0
textium/src/rasterizer.rs View File

@ -0,0 +1,83 @@
use rusttype;
use std::collections::HashMap;
use ::{FontAtlas, GlyphMetadata};
use ::geometry::Rect;
use ::texture::{Buffer2d, Bitmap};
use ::packer::SkylinePacker;
pub struct Font<'a> {
font: rusttype::Font<'a>
}
#[allow(dead_code)]
impl<'a> Font<'a> {
/// Construct a Textium font from a RustType one.
pub fn new(rt_font: rusttype::Font<'a>) -> Font {
Font {
font: rt_font
}
}
/// Build a font atlas for a set of characters in a font, rasterized at a given scale.
///
/// `margin` is the distance between glyphs in the atlas, in pixels.
/// `width` and `height` are the starting size of the bitmap.
///
/// The packer may enlarge the bitmap beyond its initial dimensions in order to fit all glyphs.
pub fn make_atlas<I>(&self, chrs: I, scale: f32, margin: u32, width: usize, height: usize)
-> (FontAtlas, Bitmap<u8>)
where I: Iterator<Item=char>
{
let mut atlas = FontAtlas {glyph_data: HashMap::new()};
let mut packer = SkylinePacker::new(Bitmap::new(width, height));
packer.set_margin(margin);
for chr in chrs {
if let Some((mut info, rendered)) = self.rasterize_char(chr, scale) {
let r = packer.pack_resize(&rendered);
}
}
(atlas, packer.into_buf())
}
pub fn rasterize_char(&self, chr: char, scale: f32)
-> Option<(GlyphMetadata, Bitmap<u8>)>
{
let glyph = match self.font.glyph(chr) {
Some(g) => g,
None => return None, // propogate missing glyphs out of the function
}.scaled(rusttype::Scale::uniform(scale));
let h_metrics = glyph.h_metrics();
let glyph = glyph.positioned(rusttype::Point {x: 0., y: 0.});
let bbox = match glyph.pixel_bounding_box() {
Some(b) => b,
None => return None, // if the bounding box is missing, we can't rasterize
};
let mut out: Bitmap<u8> = Bitmap::new(bbox.width() as usize, bbox.height() as usize);
glyph.draw(|x, y, v| {
out.set(x as usize, y as usize, (v * 255.0) as u8);
});
println!("{:?}", bbox);
let data = GlyphMetadata {
scale: scale,
bounding_box: Rect {
x: bbox.min.x as usize,
y: bbox.min.y as usize,
w: bbox.width() as usize,
h: bbox.height() as usize,
},
advance_width: h_metrics.advance_width,
left_bearing: h_metrics.left_side_bearing,
};
Some((data, out))
}
}

Loading…
Cancel
Save