Skip to content

Commit

Permalink
rfct(pff2): Impl an iter for rendering a bitmap
Browse files Browse the repository at this point in the history
  • Loading branch information
max-ishere committed Feb 7, 2024
1 parent 5a319f7 commit e3caf61
Show file tree
Hide file tree
Showing 6 changed files with 322 additions and 256 deletions.
33 changes: 33 additions & 0 deletions .github/workflows/cargo-doc-pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Deploy `cargo doc` to GitHub Pages

on:
push:
branches:
- main

jobs:
deploy-doc:
runs-on: ubuntu-latest

environment:
name: github-pages
url: ${{steps.deployment.outputs.page_url}}

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Pages
uses: actions/configure-pages@v3

- name: Run `cargo doc`
run: cargo doc --lib --no-deps

- name: Upload Artifact
uses: actions/upload-pages-artifact@v2
with:
path: 'target/doc'

- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v2
176 changes: 17 additions & 159 deletions examples/pff2.rs
Original file line number Diff line number Diff line change
@@ -1,182 +1,40 @@
//! A minimal font.pf2 parser impl that prints the parsed Rust struct
#![feature(iter_array_chunks)]
//! A minimal font.pf2 parser impl that prints a glyph from a PFF2 font
use std::fs::read;
use std::{fs::read, path::PathBuf};

use args::Args;
use clap::Parser as _;
use theme_parser::parser::pff2::{Glyph, Parser};

mod args {
use std::path::PathBuf;
#[derive(clap::Parser)]
struct Args {
#[clap(long, short = 'f')]
pub font_file: PathBuf,

use clap::Parser;

#[derive(Parser)]
pub struct Args {
#[clap(long, short = 'f')]
pub font_file: PathBuf,
}
#[clap(long = "char", short)]
pub character: char,
}

const SQUARE_BLOCK: &str = "\u{2588}\u{2588}";

fn main() -> anyhow::Result<()> {
let args = Args::parse();

let data = read(args.font_file)?;
let font = Parser::parse(&data)?.validate()?;

println!("{}", font.name);
render_glyphs(&font.glyphs, font.ascent, font.descent);

Ok(())
}

fn render_glyphs(glyphs: &[Glyph], ascent: u16, descent: u16) {
for glyph in glyphs {
render_glyph(glyph);
print_glyph(glyph, ascent, descent);
}
}

fn render_glyph(glyph: &Glyph) {
if glyph.height == 0 || glyph.width == 0 {
println!(
r" 0 {:-8} {:-8}
0 |
0x0
",
glyph.code,
glyph.code.escape_unicode(),
);

return;
}

let w_range = 0..glyph.width;
let h_range = 0..glyph.height + 2; // to render the last row

let h_range = h_range.array_chunks();

const FILLED: Option<bool> = Some(Glyph::FILLED_PIXEL);
const TRANSPARENT: Option<bool> = Some(Glyph::TRANSPARENT_PIXEL);

println!(
" {} {:-8} | {:-8}",
(0..glyph.width).fold(String::new(), |acc, i| format!("{acc}{}", i % 8)),
glyph.code.escape_unicode(),
glyph.code,
);

let mut bytes = glyph.bitmap.iter().enumerate();

for [y0, y1] in h_range {
if y0 >= glyph.height {
break;
}
print!("{} ", y0 % 10);

for x in w_range.clone() {
let upper_pixel = glyph.pixel(x, y0);
let lower_pixel = glyph.pixel(x, y1);
let glyph = font.glyph(args.character).unwrap();

let rendered = match (upper_pixel, lower_pixel) {
(FILLED, FILLED) => '\u{2588}', // █
(FILLED, TRANSPARENT) | (FILLED, None) => '\u{2580}', // ▀
(TRANSPARENT, FILLED) => '\u{2584}', // ▄
(TRANSPARENT, TRANSPARENT) | (TRANSPARENT, None) => '—',
(None, _) => {
break;
}
};
render_glyph(glyph);

print!("{rendered}");
}

let should_be_at = ((glyph.width * (y1 + 1)) as f32 / 8.).ceil() as usize;

loop {
let Some((i, byte)) = bytes.next() else {
break;
};
print!(" | {:08b}", byte);
if i + 1 >= should_be_at && y1 + 1 < glyph.height {
break;
}
}

println!();
}

println!(
" {}x{} {}B {}dx {}dy\n\n",
glyph.width,
glyph.height,
glyph.bitmap.len(),
glyph.x_offset,
glyph.y_offset
);
Ok(())
}

fn print_glyph(glyph: &Glyph, ascent: u16, descent: u16) {
println!(
"{c:2} {u} | {w:2}w {h:2}h | {dx:3}dx {dy:3}dy | {W:2}W",
c = glyph.code,
u = glyph.code.escape_unicode(),
w = glyph.width,
h = glyph.height,
dx = glyph.x_offset,
dy = glyph.y_offset,
W = glyph.device_width,
);

let mut xmax = glyph.x_offset + glyph.width as isize;
if xmax < glyph.device_width as isize {
xmax = glyph.device_width as isize;
}
let xmax = xmax;

let mut xmin = glyph.x_offset;
if xmin > 0 {
xmin = 0
}
let xmin = xmin;

let mut ymax = glyph.y_offset + glyph.height as isize;
if ymax < ascent as isize {
ymax = ascent as isize;
}
let ymax = ymax;

let mut ymin = glyph.y_offset;
if ymin > -(descent as isize) {
ymin = -(descent as isize);
}

let mut bitmap = glyph.bitmap.iter();
let mut byte = bitmap.next().unwrap_or(&0);
let mut mask = 0x80;

// dbg!(xmin, xmax, ymin, ymax, glyph.x_offset, glyph.width, glyph.device_width);

for y in (ymin..ymax).rev() {
for x in xmin..xmax {
if x >= glyph.x_offset
&& x < glyph.x_offset + glyph.width as isize
&& y >= glyph.y_offset
&& y < glyph.y_offset + glyph.height as isize
{
print!("{}", if byte & mask != 0 { "%" } else { " " });
mask >>= 1;
if mask == 0 {
mask = 0x80;
byte = bitmap.next().unwrap_or(&0);
}
} else if x >= 0 && x < glyph.device_width as isize && y >= -(descent as isize) && y < ascent as isize {
print!("{}", if x == 0 || y == 0 { "+" } else { "." });
} else {
print!("*");
}
fn render_glyph(glyph: &Glyph) {
for row in &glyph.bitmap {
for col in row {
print!("{}", if col { SQUARE_BLOCK } else { " " });
}
println!();
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ pub mod render {
}

pub type OwnedSlice<T> = Rc<T>;

trait Sealed {}
Loading

0 comments on commit e3caf61

Please sign in to comment.