Coder Social home page Coder Social logo

fontdue's People

Contributors

avafloww avatar avl avatar bastidood avatar brooooooklyn avatar bschwind avatar cedric-h avatar cybersoulk avatar deeprobin avatar deprilula28 avatar grovesnl avatar jay3332 avatar koranir avatar lassade avatar lunabunn avatar marimegui avatar maroider avatar mooman219 avatar riey avatar robmcl4 avatar ryan-scott-dev avatar skalt avatar tesselode avatar tronical avatar twitchyliquid64 avatar weswigham avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fontdue's Issues

The letter "u" does not align correctly.

Title pretty much says it all. The code that I'm using for layout is basically this, except the ymax variable is floored as soon as it's read to fix the issue that I was having when I posted that code. I'm not sure how much you'll care about this bug, given that proper layout is coming soon (I eagerly await this), but I figured that I should make you aware either way.

image

Documentation for horizontal_line_metrics is confusing

I just noticed that the documentation for Font::horizontal_line_metrics states:

"The new line height for the font. Only populated for fonts with vertical text layout metrics."

Is the text correct? Does horizontal_line_metrics only work for fonts with 'vertical text layout metrics'? Shouldn't it be 'horizontal text layout metrics'?

Enumerate all characters in font

Hello, I'm looking into using fontdue for font atlas rendering, but as far as I can tell, there is no way to enumerate the characters in Font. I'm wondering what your thoughts on supporting something like that are? I'm happy to do the initial work for that, seems straightforward enough

BDF Font Support?

I'm thinking of using this for my Retro Rust game engine, but if possible I would like to support the BDF font format which seems to be often used for low-resolution bitmap fonts.

Is this out of scope for fontdue?

Expose more metrics from ttf_parser

Hey, thanks for this blazing fast rasterizer.

While implementing a text drawing backend I found out that I need some more metrics that are currently available in ttf_parser but not exposed in fontdue. Like for example underline/strikeout drawing hints from Face::underline_metrics() and Face::strikeout_metrics(). Current workaround is to reparse the same font twice just to get the metrics, which is a bit wasteful since this is done on fontdue already.

I can contribute PR, just wanted to run this by to make sure it's something you want to include in this lib?

API design questions

Hello again!

I'm running into a few issues which I'm not quite sure how to solve with fontdue's current API. I have an OpenGL glyph renderer and I pass it structs which are very similar to fontdue's TextStyle, but with a color attribute:

pub type Color = (f32, f32, f32, f32);

pub struct StyledText<'a> {
    pub text: &'a str,
    pub font: Font, // My own enum, you can ignore this
    pub color: (u8, u8, u8, u8),
}

After rasterizing, I have to correlate fontdue's output of GlyphPositions back to my original output to determine which color to use for the glyph. I see you added include_whitespace to support solving this problem, but I'm running into a whitespace issue that makes this a little difficult:

  • When rasterizing, '\n' will map to the font's fallback character but ' ' will map to a zero-width and zero-height bitmap

I need to double check tomorrow, but from my tests the rasterizer seemed to handle it as a missing glyph, here was my debug output when rasterizing and packing into a glyph texture:

# The font is IBM Plex Sans, 300 weight
'あ': Ok(GlyphMissing)
'0': Ok(Packed)
'1': Ok(Packed)
':': Ok(Packed)
'4': Ok(Packed)
'8': Ok(Packed)
'\n': Ok(GlyphMissing)
'F': Ok(Packed)
'P': Ok(Packed)
'S': Ok(Packed)
':': Ok(Packed)
' ': Ok(WhitespaceChar)
'5': Ok(Packed)
'8': Ok(Packed)

I currently keep track of all this with a data structure of type Vec<(Range<usize>, Color)>, and I use include_whitespace = true so the character indices line up with the input. Let me know if you're interested in seeing the full code, it's kind of messy and it's a lot of extra work just to correlate the output back to the original input colors.

It all feels a bit fragile though and I'm wondering if you'd be open to possible API changes to make it easier to correlate.

For example, GlyphPosition could potentially hold an index which points to the TextStyle it came from.

Or if struct size is an issue, maybe TextStyle and GlyphPosition could be generic over a user-provided struct so it could default to a zero-sized struct but also allow us to optionally attach extra data that gets included in the output. Here's a brief example of that.

I could make an attempt at adding this to fontdue if it sounds like something you'd be interested in including in its API, but I just wanted to start a discussion here first. Thanks for the consideration!

How to calculate the glyphs layout?

There is a Metrics struct, but have no baseline info.

    /// Inner bounds of the glyph at the offsets specified by the font.
    pub bounds: AABB,

How to use the bounds?

image

================================

font.new_line_width() is a fixed value, This has no scale with it?

Scale units

The px scale units appear to be pixels per Em. This could be clearer in the docs.

If you want inspiration for the docs, see: https://github.com/kas-gui/kas-text/blob/master/src/fonts/mod.rs#L38

Ironically my library exposes scale via "DPU" (pixels for font unit) which is what fontdue uses internally, thus I have to multiply by units-per-em so that fontdue can divide again (in Font::scale_factor, called by various functions). Not really an issue.

Possible word wrapping error when allowing wrap_hard_breaks

Hi.

Given the following string:
https://github.com/emilk/egui/blob/a35fe7da126f82dcdf3738a250e150a5ff5d30bb/egui/src/demos/mod.rs#L19

I get the following output (please ignore the miss aligned glyphs for now):
render

I used the following layout settings:

        let settings = LayoutSettings {
            max_width: max_width_in_points,
            wrap_hard_breaks: true,
            ..Default::default()
        };

Given these settings I would assume that line breaks are honoured and I get an empty line between the paragraphs. It also seems that after the line break, the wrapping isn't working anymore.

Is this the expected behaviour?

Font missing dots above lowercase 'i' and 'j'

When the following font is rasterized with fontdue it is missing the dots above the lowercase i and j.

https://nickmass.com/files/evesansneue-regular.otf

I modified the raster-print example code to render the same font with rusttype/freetype-rs for comparison:

image

Changing the rasterizing scale has no effect on the problem, and slightly interestingly the exclamation point renders with its dot just fine.

I checked the font against some previous versions of fontdue and noticed that prior to commit cb2e9b2 the problem is actually reversed and it only renders the dot while the stem of the characters is absent.

I added some debugging to the fontdue Geometry struct to see if the glyphs were being loaded correctly and as far as I could tell that was fine.

// fontdue loading the lowercase 'i'
move_to(x0: 75, y0: 540)
line_to(x0: 155, y0: 540)
line_to(x0: 155, y0: 0)
line_to(x0: 75, y0: 0)
close()
move_to(x0: 75, y0: 640)
line_to(x0: 155, y0: 640)
line_to(x0: 155, y0: 720)
line_to(x0: 75, y0: 720)
close()

// results in the following v_lines being created
v_line(start:(155, 540), end:(155, 0))
v_line(start:(75, 0), end:(75, 540))
v_line(start:(155, 640), end:(155, 720))
v_line(start:(75, 720), end:(75, 640))

Code Formatting

I hope this doesn't come off as snobbish or anything like that, but I find the code can be hard to read at times. For instance,

pub fn read_utf8(string: &str, byte_offset: &mut usize) -> char {
    let bytes = string.as_bytes();
    let x = bytes[*byte_offset];
    *byte_offset += 1;
    if x < 128 {
        return unsafe { core::char::from_u32_unchecked(x as u32) };
    }
    let init = (x & (0x7F >> 2)) as u32;
    let y = bytes[*byte_offset];
    *byte_offset += 1;
    let mut ch = utf8_acc_cont_byte(init, y);
    if x >= 0xE0 {
        let z = bytes[*byte_offset];
        *byte_offset += 1;
        let y_z = utf8_acc_cont_byte((y & CONT_MASK) as u32, z);
        ch = init << 12 | y_z;
        if x >= 0xF0 {
            let w = bytes[*byte_offset];
            *byte_offset += 1;
            ch = (init & 7) << 18 | utf8_acc_cont_byte(y_z, w);
        }
    }
    unsafe { core::char::from_u32_unchecked(ch) }
}

It's a bit hard to read at first glance because of a lack of newlines. I myself would've preferred,

pub fn read_utf8(string: &str, byte_offset: &mut usize) -> char {
	let bytes = string.as_bytes();
	let x = bytes[*byte_offset];
	*byte_offset += 1;
	
	if x < 128 {
		return unsafe { core::char::from_u32_unchecked(x as u32) };
	}
	
	let init = (x & (0x7F >> 2)) as u32;
	let y = bytes[*byte_offset];
	*byte_offset += 1;

	let mut ch = utf8_acc_cont_byte(init, y);
	
	if x >= 0xE0 {
		let z = bytes[*byte_offset];
		*byte_offset += 1;
		let y_z = utf8_acc_cont_byte((y & CONT_MASK) as u32, z);
	
		ch = init << 12 | y_z;
		
		if x >= 0xF0 {
			let w = bytes[*byte_offset];
			*byte_offset += 1;
			
			ch = (init & 7) << 18 | utf8_acc_cont_byte(y_z, w);
		}
	}
	unsafe { core::char::from_u32_unchecked(ch) }
}

Of course, this is an entirely subjective and pedantic issue and I apologise if I've offended you in some way, but I really think some degree of separation should be there. Thoughts?

Hashbrown outdated and usage of std-only f32 features ?

Hello to anyone reading this !

I am in the process of building a Console for a bare-metal PowerPC system (can you guess which one ?) with fontdue 0.0.4 !

When creating the console under native Windows/x64, everything worked just fine, I then copied my code over to my main PPC repo, adapted stuff and tried compiling it...

You might have guessed it didn't go far:

error[E0463]: can't find crate for `std`
  --> /home/guillaume/.cargo/registry/src/github.com-1ecc6299db9ec823/hashbrown-0.5.0/src/lib.rs:36:1
   |
36 | extern crate std as alloc;
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate
   |
   = note: the `powerpc-none-eabi-2552456384893224483` target may not be installed

Looking at the surrounding code in the repo for hashbrown version 0.5.0, it performs a check for the 'nightly' feature, but fails somehow ?

Anyways, it was apparently fixed in a later release, because trying to cross-compile hashbrown 0.5 on it's own (without fontdue) in a separate crate with minimal code fails just like above, but when raising the version to 0.6 for example the build works just fine.

Cloning fontdue locally and modifying the version to 0.6 fixes the issue with hashbrown, but raises another one: A lot of code in fontdue that uses f32 fns like .powi(), .ceil() or .abs() fails to compile.

I also tried on my native Windows/x64 machine, on a crate WITH std, cloning the repo locally and changing the version of hashbrown to 0.6 raises the same f32 fns issues !

As far as I understand, this bug in hashbrown made the std-only f32 fns available in fontdue's no-std environment, but when upgrading hashbrown, fixing this bug, these features aren't available anymore to fontdue and the build fails, just like one would expect...

So this raises a bit of an issue... Correct me if I am wrong, but the std-only features were used by mistake in developpement of this crate because of that bug ? This is quite the problem for supporting no-std platforms, one of the biggest features of this crate...

Is this really what I think ? I'd be willing to help to fix these issues to get my project back on track !

Thanks,
Marime Gui

Please use the Zlib license <3 <3 <3

It's better for the long term health of the Rust ecosystem.

You don't need to remove the MIT license though! You could simply add Zlib as an option

license = "MIT OR Zlib"

Font size and layout not quite right

It seems like that Fontdue's rasterized characters are just a little smaller than that of Firefox or Chrome. Also, using the Roboto font, the lowercase 'i' is very noticeably different.

I made a little test where I laid my program over Firefox, both using Roboto-Regular, 40px.

font woes

It looks like the character advance and line height aren't quite right. Does Fontdue support kerning? Also, will we be able to change the line height in the future? I couldn't find anything related to these in the docs.

First-line indentation

First-line indentation is very common in typesetting, and looks like this:

   The first line starts
further to the right than
the subsequent lines of
text.

It would be wonderful if fontdue could support it, e.g. with a simple first_line_indentation: f32 in LayoutSettings, especially if this is simple to implement. Of course the setting only makes sense for HorizontalAlign::Left.

I am writing an immediate mode GUI and this would enable me to seemlessly mix text with others widgets (in a row-based fashion). Basically I would use first_line_indentation to indicate that I've already used up the first few pixels of the first line (maybe there is a button there or some other text using a different font).

Does this library supports rendering outlined gylphs?

I'm currently looking for several font libraries available in Rust. One feature I want is to render outlined glyph, as in Glyph Stroker in FreeType (expected output: like this). I looked up the docs for this library but could not find plausible one. Does this library currently support the feature? (Additionally, do you know some other library for Rust that supports this? You don't have to answer this question in the parenthesis)

Error: f32::abs function not found

Hi!
I found something strange after updating dependencies for my project recently.
Rust compiler can't build fontdue library with a message:

  --> /Users/gerodrus/.cargo/registry/src/github.com-1ecc6299db9ec823/fontdue-0.5.1/src/platform/float/get_bitmap.rs:18:62
   |
18 |             *(output.get_unchecked_mut(i)) = f32::clamp(f32::abs(height) * 255.9, 0.0, 255.0) as u8;
   |                                                              ^^^ function or associated item not found in `f32`

rustc version is 1.52.1 with target -- stable-aarch64-apple-darwin (Apple Silicon)
My project is using macroquad library, that depends on fontdue.
If I can provide any further information, feel free to ask.

Consider separating the raster and parser

TrueType and OpenType need a lot of coverage. Consider upstreaming sanitation changes to ttf input that fontdue does right now into a library dedicated to being a parser.

Visual quality regressions

Hello again !

After upgrading my console from version 0.0.4 to 0.1.0 of fontdue, visual quality of the rendered characters significantly degraded.

Here is what it looked like before:
Old

This is what it looks like now:
New

(I am using font size 15.0 btw)

Certain characters look different, just slightly "denser" or "thinner" in certain areas. This is especially visible on 'o', 'a', 'g' and 'c' characters (mostly the ones that curve apparently).

It traced it back to this commit, fixing the std problem where std ops were used by implementing a custom atan2 fn.

I tried replacing it by copy-pasting the one found in libm, and it fixed this issue, restoring back the look before this commit.

I tried looking for what's wrong in the new code, but I'm not smart enough sadly.

Do you think a fix is possible ?

Thanks again,
Marime Gui

Compilation failed in `no_std` environment

Hi @mooman219,

I was try to use your crate in no_std environment, but without success.

First problem was that the crate has hashbrown = "0.5" as dependency without disabling default features. It seems if I change hashbrown version to 0.6 it fixes this issue.

Second problem looks like that in no_std environment there is no functions like ceil, floor, abs and sqrt defined for f32 type.

compilation error log

error[E0599]: no method named `ceil` found for type `f32` in the current scope
  --> src/font.rs:39:41
   |
39 |             width: (scale * self.width).ceil() as usize,
   |                                         ^^^^

error[E0599]: no method named `ceil` found for type `f32` in the current scope
  --> src/font.rs:40:43
   |
40 |             height: (scale * self.height).ceil() as usize,
   |                                           ^^^^

error[E0599]: no method named `ceil` found for type `f32` in the current scope
  --> src/raster.rs:70:39
   |
70 |         for y in y0..min(self.h, p1.y.ceil() as usize) {
   |                                       ^^^^

error[E0599]: no method named `floor` found for type `f32` in the current scope
  --> src/raster.rs:80:30
   |
80 |             let x0floor = x0.floor();
   |                              ^^^^^

error[E0599]: no method named `ceil` found for type `f32` in the current scope
  --> src/raster.rs:82:29
   |
82 |             let x1ceil = x1.ceil();
   |                             ^^^^

error[E0599]: no method named `sqrt` found for type `f32` in the current scope
   --> src/raster.rs:121:57
    |
121 |         let n = 1 + (tol * (devx * devx + devy * devy)).sqrt().sqrt().floor() as usize;
    |                                                         ^^^^

error[E0599]: no method named `abs` found for type `f32` in the current scope
   --> src/raster.rs:144:25
    |
144 |             let y = acc.abs();
    |                         ^^^

error[E0599]: no method named `abs` found for type `f32` in the current scope
   --> src/raster.rs:166:25
    |
166 |             let y = acc.abs();
    |                         ^^^

error: aborting due to 8 previous errors

For more information about this error, try `rustc --explain E0599`.
error: Could not compile `fontdue`.

Some fonts included on Macs rasterize totally blank.

I was trying various fonts included in the Fonts directory on my Mac with the raster-print.rs example. I tried HelveticaNeue.ttc and NewYork.ttf and both produced metrics with a width and height > 0 but the output is totally blank.

(Also happy holidays!🎄🎄🎄)

Characters not rendered at size == scale can be "off" by a pixel

I have in-engine text rendering working. For now I hardcode scale == 40.0. I noticed when I render font size at 40px it looks great, but this other text at 15px has the appearance of character spacing/alignment being off by a pixel.

image

  1. There's a good chance that this is expected behavior, but if you know for certain it is/isn't, would appreciate it! I have tried mipmapping the font texture but it did not improve it.
  2. I would consider rasterizing the font at two different scales to solve this, but some fonts have many characters and makes creating a new "copy" of the font at a different scale very expensive, even if I'm only going to rasterize a few of them. (mentioned in #59). Would you be interested in a pull request to add a way to filter what characters to load?

Thanks for the great library!

Crash on malformed font

Did some fuzzing of the function fontdue::Font::from_bytes and found this crash:

$ RUST_BACKTRACE=1 ./target/debug/fontdue-crash 
thread 'main' panicked at 'attempt to add with overflow', /home/capitol/.cargo/git/checkouts/fontdue-8bd74c91401c4cc7/dc8670e/src/font.rs:113:28
stack backtrace:
   0: rust_begin_unwind
             at /rustc/397b390cc76ba1d98f80b2a24a371f708dcc9169/library/std/src/panicking.rs:475
   1: core::panicking::panic_fmt
             at /rustc/397b390cc76ba1d98f80b2a24a371f708dcc9169/library/core/src/panicking.rs:85
   2: core::panicking::panic
             at /rustc/397b390cc76ba1d98f80b2a24a371f708dcc9169/library/core/src/panicking.rs:50
   3: fontdue::font::LineMetrics::new
             at /home/capitol/.cargo/git/checkouts/fontdue-8bd74c91401c4cc7/dc8670e/src/font.rs:113
   4: fontdue::font::Font::from_bytes
             at /home/capitol/.cargo/git/checkouts/fontdue-8bd74c91401c4cc7/dc8670e/src/font.rs:280
   5: fontdue_crash::main
             at ./src/main.rs:5
   6: core::ops::function::FnOnce::call_once
             at /home/capitol/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:227

Can be reproduced with this program:

fn main() {

    let font = vec![0, 1, 0, 0, 0, 250, 255, 255, 127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 101, 210, 210, 58, 117, 210, 32, 0, 109, 97, 112, 126, 33, 0, 0, 0, 0, 0, 99, 102, 1, 0, 30, 1, 91, 1, 0, 253, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 0, 86, 79, 82, 71, 0, 1, 82, 77, 103, 118, 97, 114, 220, 70, 70, 51, 0, 0, 0, 0, 35, 0, 0, 116, 116, 99, 102, 33, 1, 125, 0, 0, 103, 118, 97, 114, 120, 0, 0, 0, 0, 30, 1, 91, 1, 0, 253, 0, 86, 79, 82, 71, 0, 1, 82, 77, 103, 118, 97, 114, 220, 70, 70, 51, 0, 0, 0, 0, 0, 0, 0, 116, 116, 99, 102, 33, 1, 125, 0, 0, 103, 118, 97, 114, 120, 0, 0, 0, 1, 77, 103, 118, 97, 114, 220, 255, 255, 255, 255, 255, 255, 0, 236, 0, 0, 98, 77, 1, 91, 0, 0, 220, 70, 70, 50, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 97, 114, 120, 0, 0, 0, 0, 30, 1, 91, 1, 0, 253, 0, 86, 79, 82, 71, 0, 1, 82, 77, 103, 118, 97, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 82, 71, 0, 0, 0, 0, 0, 118, 97, 0, 1, 0, 0, 1, 0, 0, 0, 1, 82, 77, 0, 190, 250, 184, 102, 118, 97, 114, 115, 98, 105, 120, 0, 0, 0, 0, 0, 0, 0, 4, 61, 6, 82, 77, 220, 45, 103, 79, 41, 114, 117, 250, 184, 102, 118, 97, 114, 115, 98, 105, 120, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 64, 255, 0, 0, 116, 116, 99, 102, 33, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 8, 17, 0, 0, 0, 6, 0, 72, 0, 0, 0, 1, 0, 0, 210, 5, 0, 0, 0, 0, 0, 0, 0, 255, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, 0, 109, 97, 98, 105, 120, 0, 0, 0, 0, 0, 0, 0, 4, 61, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 117, 210, 0, 0, 33, 93, 112, 126, 33, 0, 0, 0, 0, 103, 118, 97, 114, 220, 70, 70, 55, 0, 0, 0, 0, 0, 0, 0, 116, 116, 99, 102, 33, 1, 125, 0, 0, 103, 118, 97, 114, 120, 0, 0, 0, 0, 0, 0, 109, 97, 112, 126, 33, 0, 0, 0, 0, 0, 99, 102, 1, 0, 30, 1, 91, 1, 0, 253, 0, 210, 58, 117, 210, 0, 0, 109, 97, 112, 126, 33, 0, 0, 255, 0, 0, 0, 99, 102, 1, 0, 30, 1, 91, 1, 0, 253, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 255, 101, 210, 210, 58, 117, 210, 32, 0, 255, 255, 255, 109, 255, 255, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 253, 0, 109, 97, 120, 112, 0, 1, 0, 253, 0, 0, 0, 0, 0, 0, 0, 64, 255, 70, 51, 0, 0, 0, 0, 0, 0, 0, 116, 116, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 97, 120, 112, 0, 1, 0, 58, 117, 0, 0, 205, 0, 0, 1, 0, 0, 253, 0, 0, 0, 0, 0, 0, 0, 64, 255, 255, 210, 1, 255, 255, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 17, 17, 17, 0, 67, 70, 70, 50, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 77, 0, 190, 27, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 3, 72, 0, 0, 0, 0, 0, 0, 116, 116, 99, 102, 33, 1, 125, 0, 0, 103, 118, 97, 114, 120, 0, 0, 0, 1, 77, 103, 118, 97, 114, 220, 255, 255, 255, 255, 255, 255, 0, 236, 0, 0, 98, 77, 103, 118, 97, 77, 65, 0, 0, 1, 0, 0, 0, 1, 174, 178, 35, 0, 45, 79, 104, 104, 101, 97, 169, 1, 0, 15, 0, 0, 0, 0, 0, 0, 0, 36, 120, 169, 0, 1, 0, 0, 0, 0, 0, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 101, 210, 210, 58, 117, 0, 1, 0, 0, 0, 27, 0, 1, 0, 0, 1, 0, 255, 255, 255, 255, 148, 0, 0, 0, 0, 0, 118, 97, 1, 1, 0, 0, 4, 61, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 101, 210, 210, 58, 117, 210, 32, 0, 109, 97, 112, 126, 33, 0, 0, 0, 0, 16, 99, 0, 1, 30, 1, 102, 91, 1, 0, 253, 0, 86, 79, 210, 71, 0, 1, 103, 77, 82, 118, 97, 114, 220, 70, 70, 56, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 27, 0, 2, 251, 0, 1, 0, 255, 255, 255, 4, 148, 0, 0, 0, 0, 0, 97, 118, 0, 0, 1, 16, 0, 1, 82, 77, 0, 190, 250, 184, 105, 118, 97, 114, 115, 98, 105, 136, 0, 255, 66, 66, 76, 0, 17, 0, 5, 64, 8, 38, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 67, 70, 0, 0, 27, 0, 2, 251, 0, 1, 0, 255, 255, 255, 4, 148, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 1, 0, 0, 0, 242, 72, 77, 65, 82, 77, 0, 190, 255, 255, 255, 4, 148, 0, 0, 0, 0, 0, 97, 118, 0, 0, 250, 184, 102, 118, 97, 114, 115, 184, 98, 255, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 67, 70, 70, 49, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 77, 0, 190, 58, 27, 0, 1, 6, 0, 67, 70, 70, 0, 0, 118, 97, 114, 0, 116, 116, 99, 102, 33, 1, 0, 1, 0, 0, 0, 27, 0, 0, 0, 0, 0, 3, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 0, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 115, 98, 105, 136, 0, 255, 66, 66, 76, 0, 17, 0, 5, 64, 8, 38, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 77, 0, 190, 58, 27, 0, 0, 0, 0, 67, 70, 70, 0, 0, 116, 116, 118, 97, 1, 148, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 1, 0, 0, 0, 242, 72, 77, 65, 82, 77, 0, 190, 250, 184, 102, 118, 97, 114, 115, 184, 98, 38, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 67, 70, 70, 49, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 77, 0, 190, 58, 27, 0, 1, 6, 0, 67, 70, 70, 0, 0, 118, 97, 114, 0, 116, 116, 99, 102, 33, 1, 0, 1, 0, 0, 0, 27, 0, 0, 0, 0, 0, 3, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 0, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 115, 98, 105, 136, 0, 255, 66, 66, 76, 0, 17, 0, 5, 64, 8, 38, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 77, 0, 190, 58, 27, 0, 0, 0, 0, 67, 70, 70, 0, 0, 116, 116, 118, 97, 1, 0, 0, 0, 1, 209, 77, 0, 190, 0, 1, 0, 0, 0, 1, 0, 0, 220, 104, 101, 97, 100, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 54, 110, 137, 0, 1, 12, 255, 255, 255, 255, 255, 255, 199, 107, 101, 114, 58, 27, 0, 1, 0, 0, 67, 70, 70, 0, 0, 255, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 255, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 97, 114, 115, 98, 105, 136, 0, 255, 66, 66, 76, 0, 193, 17, 0, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 70, 0, 0, 116, 116, 118, 97, 114, 220, 70, 70, 51, 0, 0, 0, 0, 0, 0, 1, 28, 28, 114, 220, 70, 70, 51, 0, 0, 0, 0, 35, 0, 0, 116, 116, 99, 102, 33, 1, 125, 0, 0, 103, 118, 97, 114, 120, 0, 0, 0, 0, 30, 1, 91, 1, 0, 253, 0, 86, 79, 82, 71, 0, 1, 82, 77, 103, 118, 97, 114, 220, 70, 70, 51, 0, 0, 0, 0, 0, 0, 0, 116, 116, 99, 102, 33, 1, 125, 0, 0, 103, 118, 97, 114, 120, 0, 0, 0, 1, 77, 103, 118, 97, 114, 220, 255, 255, 255, 255, 255, 255, 0, 236, 0, 0, 116, 116, 99, 102, 33, 1, 125, 0, 0, 103, 118, 97, 114, 120, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 27, 0, 1, 255, 71, 86, 255, 255, 255, 148, 0, 0, 1, 0, 0, 1, 0, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 103, 72, 77, 65, 0, 0, 1, 0, 0, 0, 1, 174, 178, 35, 0, 45, 79, 104, 104, 101, 97, 169, 1, 0, 15, 0, 0, 0, 0, 0, 0, 0, 36, 120, 169, 0, 1, 0, 0, 0, 0, 0, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 101, 210, 210, 58, 117, 0, 1, 0, 0, 0, 27, 0, 1, 0, 0, 1, 0, 255, 255, 255, 255, 148, 0, 0, 0, 0, 0, 118, 97, 1, 1, 0, 0, 4, 61, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 101, 210, 210, 58, 117, 210, 32, 0, 109, 97, 112, 126, 33, 0, 0, 0, 0, 16, 99, 0, 1, 30, 1, 102, 91, 1, 0, 253, 0, 86, 79, 210, 71, 0, 1, 103, 77, 82, 118, 97, 114, 220, 70, 70, 51, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 27, 0, 2, 251, 0, 1, 0, 255, 255, 255, 4, 148, 0, 0, 0, 0, 0, 97, 118, 0, 0, 1, 16, 0, 1, 82, 77, 0, 190, 250, 184, 105, 118, 97, 114, 115, 98, 105, 136, 0, 255, 66, 66, 76, 0, 17, 0, 5, 64, 8, 38, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 67, 70, 0, 0, 27, 0, 2, 251, 0, 1, 0, 255, 255, 255, 4, 148, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 1, 0, 0, 0, 242, 72, 77, 65, 82, 77, 0, 190, 250, 184, 102, 118, 97, 114, 115, 184, 98, 38, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 67, 70, 70, 50, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 77, 0, 190, 58, 27, 0, 1, 6, 0, 67, 70, 70, 0, 0, 118, 97, 114, 0, 116, 116, 99, 102, 33, 1, 0, 1, 0, 0, 0, 27, 0, 0, 0, 0, 0, 3, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 0, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 115, 98, 105, 136, 0, 255, 66, 66, 76, 0, 17, 0, 5, 64, 8, 38, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 77, 0, 190, 58, 27, 0, 0, 0, 0, 67, 70, 70, 0, 0, 116, 116, 118, 97, 1, 0, 0, 0, 1, 209, 77, 0, 190, 0, 1, 0, 0, 0, 1, 0, 0, 220, 104, 101, 97, 100, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 54, 110, 137, 0, 1, 12, 255, 255, 255, 255, 255, 255, 199, 107, 101, 114, 58, 27, 0, 1, 0, 0, 67, 70, 70, 0, 0, 255, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 255, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 97, 114, 115, 98, 105, 136, 0, 255, 66, 66, 76, 0, 193, 17, 0, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 70, 0, 0, 116, 116, 118, 97, 114, 220, 70, 70, 51, 0, 0, 0, 0, 0, 0, 1, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 5, 64, 24, 12, 12, 12, 12, 12, 12, 12, 99, 102, 1, 0, 30, 1, 91, 1, 0, 253, 0, 86, 79, 82, 71, 0, 1, 82, 0, 0, 30, 1, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 205, 0, 0, 1, 0, 0, 0, 0, 1, 209, 77, 0, 190, 0, 1, 0, 0, 0, 1, 0, 0, 220, 104, 101, 97, 100, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 54, 110, 137, 0, 1, 12, 255, 255, 255, 255, 255, 255, 199, 107, 101, 114, 58, 27, 0, 1, 0, 0, 67, 70, 70, 0, 0, 255, 15, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 0, 0, 1, 0, 0, 1, 0, 255, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 97, 114, 115, 98, 105, 136, 0, 255, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 70, 0, 0, 116, 116, 118, 97, 114, 220, 70, 70, 51, 0, 0, 0, 0, 0, 0, 1, 28, 28, 114, 220, 70, 70, 51, 0, 0, 0, 0, 35, 0, 0, 116, 116, 99, 102, 33, 1, 125, 0, 0, 103, 118, 97, 114, 120, 0, 0, 0, 0, 30, 1, 91, 1, 0, 253, 0, 86, 79, 82, 71, 0, 1, 82, 77, 103, 118, 97, 114, 220, 70, 70, 51, 0, 0, 0, 0, 0, 0, 0, 116, 116, 99, 102, 33, 1, 125, 0, 0, 103, 118, 97, 114, 120, 0, 0, 0, 1, 77, 103, 118, 97, 114, 220, 255, 255, 255, 255, 255, 255, 0, 236, 0, 0, 116, 116, 99, 102, 33, 1, 125, 0, 0, 103, 118, 97, 114, 120, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 27, 0, 1, 255, 71, 86, 255, 255, 255, 148, 255, 65, 0, 0, 0, 0, 0, 118, 97, 1, 1, 0, 0, 4, 61, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 103, 72, 77, 65, 0, 0, 1, 0, 0, 0, 1, 174, 178, 35, 0, 45, 79, 104, 104, 101, 97, 169, 1, 0, 15, 0, 0, 0, 0, 0, 0, 0, 36, 120, 169, 0, 1, 0, 0, 0, 0, 0, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 101, 210, 210, 58, 117, 0, 1, 0, 0, 0, 27, 0, 1, 0, 0, 1, 0, 255, 255, 255, 255, 148, 0, 0, 0, 0, 0, 118, 97, 1, 1, 0, 0, 4, 61, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 101, 210, 210, 58, 117, 210, 32, 0, 109, 97, 112, 126, 33, 0, 0, 0, 0, 16, 99, 0, 1, 30, 1, 102, 91, 1, 0, 253, 0, 86, 79, 210, 71, 0, 1, 103, 77, 82, 118, 97, 114, 220, 70, 70, 51, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 27, 0, 2, 251, 0, 1, 0, 255, 255, 255, 4, 148, 0, 0, 0, 0, 0, 97, 118, 0, 0, 1, 16, 0, 1, 82, 0, 17, 0, 5, 64, 8, 38, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 70, 0, 0, 27, 0, 2, 251, 0, 1, 0, 255, 255, 255, 4, 148, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 1, 0, 0, 0, 242, 72, 77, 65, 82, 77, 0, 190, 250, 184, 102, 118, 97, 114, 115, 184, 98, 38, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 67, 70, 70, 50, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 77, 0, 190, 58, 27, 0, 1, 6, 0, 67, 70, 70, 0, 0, 118, 97, 114, 0, 116, 116, 99, 102, 33, 1, 0, 1, 0, 0, 0, 27, 0, 0, 0, 0, 0, 3, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 0, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 115, 98, 105, 136, 0, 255, 66, 66, 76, 0, 17, 0, 5, 64, 8, 38, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 77, 0, 190, 58, 27, 0, 0, 0, 0, 67, 70, 70, 0, 0, 116, 116, 118, 97, 1, 0, 0, 0, 1, 209, 77, 0, 190, 0, 1, 0, 0, 0, 1, 2, 0, 36, 151, 154, 158, 155, 255, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 54, 110, 137, 0, 1, 12, 255, 255, 255, 255, 255, 255, 199, 107, 101, 114, 58, 27, 0, 1, 0, 0, 67, 70, 70, 0, 0, 255, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 255, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 97, 114, 115, 98, 105, 136, 0, 255, 66, 66, 76, 0, 193, 17, 0, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 70, 0, 0, 116, 116, 118, 97, 114, 220, 70, 70, 51, 0, 0, 0, 0, 0, 0, 1, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 5, 64, 24, 12, 12, 12, 12, 12, 12, 12, 99, 102, 1, 0, 30, 1, 91, 1, 0, 253, 0, 86, 79, 82, 71, 0, 1, 82, 0, 0, 30, 1, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 205, 0, 0, 1, 0, 0, 210, 1, 0, 0, 255, 255, 255, 199, 107, 101, 114, 110, 82, 1, 63, 169, 173];

    if let Ok(font) = fontdue::Font::from_bytes(font, fontdue::FontSettings::default()) {
        let (metrics, bitmap) = font.rasterize('g', 17.0);
    }
    println!("Hello, world!");
}

Wacky text alignment

image
Text seems to be top aligned, or not even aligned at all when iterating over the &GlyphPositions and rasterizing them with rasterize_config.

Sample code:

let mut img3 = ImageBuffer::<Pixel, _>::new(WIDTH, HEIGHT);
    // Fontdue
    {
        let canvas = &mut img3;

        let mut layout = Layout::new();
        let mut output = Vec::new();

        let helvetica = Font::from_bytes(HELVETICA_DATA, FontSettings::default()).unwrap();
        let fonts = &[helvetica];

        let (x, y) = (100, 200);
        let color = Pixel::from([Depth::MAX, Depth::MAX / 4, Depth::MAX / 2, Depth::MAX]);

        layout.layout_horizontal(
            fonts,
            &[
                &TextStyle::new("Hello ", 35.0, 0),
                &TextStyle::new("world!", 50.0, 0),
            ],
            &LayoutSettings {
                // max_width: Some(150.0),
                x: x as f32,
                y: y as f32,
                max_height: Some(10.0),
                ..LayoutSettings::default()
            },
            &mut output,
        );

        output.iter().for_each(|c| {
            let (metrics, pixels) = fonts[c.key.font_index].rasterize_config(c.key);

            dbg!(&c);
            draw_filled_rect_mut(
                canvas,
                Rect::at(c.x as _, c.y as i32 + c.height as i32)
                    .of_size(c.width as _, c.height as _),
                Rgba([0, !0, 0, !0]),
            );

            pixels.into_iter().enumerate().for_each(|(i, p)| {
                let p = (p as f32 / u8::MAX as f32);
                let image_x = (c.x as i32 + (i % c.width) as i32);
                let image_y = ((c.y as i32 + (c.height as i32)) + (i / c.width) as i32);

                let image_width = canvas.width() as i32;
                let image_height = canvas.height() as i32;

                if image_x >= 0 && image_x < image_width && image_y >= 0 && image_y < image_height {
                    let pixel = *canvas.get_pixel(image_x as u32, image_y as u32);

                    let weighted_color = weighted_sum(pixel, color, 1.0 - p, p);

                    canvas.draw_pixel(image_x as u32, image_y as u32, weighted_color);
                }
            });
        });
    }

produces:
image

Unable to write a font bitmap to a pixel buffer

I noticed that the format of the pixmap doesn't really seem to match what I usually expect. There seems to be no pixel since dimensions of the pixmap are not always multiples of 4.

I am probably missing something. Am I using fontdue correctly?

        let mut index = ((x + (y * width as u32)) * 4) as usize;
        let font = include_bytes!("/home/bryan/.local/share/fonts/TerminusTTF-Bold.ttf") as &[u8];
        // Parse it into the font type.
        let font = fontdue::Font::from_bytes(font, fontdue::FontSettings::default()).unwrap();
        for c in self.text.chars() {
            let (metrics, bitmap) = font.rasterize(c, self.font_size);
            for i in (0..metrics.width * metrics.height).into_iter().step_by(metrics.width) {
                if index >= canvas.len() {
                    break;
                } else {
                    let mut writer = &mut canvas[index..];
                    writer.write(&bitmap[i..i+metrics.width]).unwrap();
                    writer.flush().unwrap();
                    index += width as usize * 4;
                }
            }
        }

This is supposed to be the letter 'm'.
image

Line breaks when max_width is None

Hi,

I'm not sure what the intended behavior is here, but when max_width is set to None in LayoutSettings, hard line breaks have no effect. Relevant code:

let wrap = settings.max_width.is_some() && (wrap_soft_breaks || wrap_hard_breaks);

If this is intentional then that's totally fine, I'll specify a relevant maximum width.

Thanks for the great library!

Some pixel font rasterize incorrect

https://github.com/SolidZORO/zpix-pixel-font/tree/master/dist

Zpix is a pixel font. Standard size is 12px. Is rasterize ok on multiple of 12px.
But in some size the rasterize is incorrect.

For example:

size = 12px

a:
image
:
image

size = 32px

a:
image
:
image

size = 48px

a:
image
:
image

size = 64px

a:
image
:
image

There some lines in bottom.

=================================

https://purestudio.itch.io/ipix

IPix is another pixel font. Recommand size is 12px, but actually is 16px.

size = 12px

a:
image
:
image

size = 16px

a:
image
:
image

size = 48px

a:
image
:
image

size = 64px

a:
image
:
image

=============================
rusttype can rasterize correct, but lost hard edge.

Zpix.ttf

size = 12px

a:
image
:
image

size = 48px

a:
image
:
image

size = 64px

a:
image
:
image

Failing to build on WASM

cargo build --target wasm32-unknown-unknown --release

 Compiling fontdue v0.1.2
error[E0432]: unresolved import `crate::platform::float::trunc`
 --> /Users/bombfuse/.cargo/registry/src/github.com-1ecc6299db9ec823/fontdue-0.1.2/src/platform/simd_core.rs:3:5
  |
3 | use crate::platform::float::trunc;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `trunc` in `platform::float`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0432`.
error: could not compile `fontdue`.

Subpixel positioning

Just wondering what the state / milestones are around subpixel positioning? I see rasterize_subpixel() got added recently, but that appears to quantize to units of 1/3 of a pixel.

Iced would love to switch to using fontdue, but subpixel positioning is a need for our layouts.

Segfault when rasterizing a glyph with size=0

To reproduce: in the 'simple' example change the constants to SIZE = 0.0, CHARACTER = 'o', FONT = include_bytes!("path to UbuntuMono-Regular.ttf"). (You can download "UbuntuMono-Regular.ttf" from Google Fonts, GitHub doesn't allow attaching .ttf files to issues).

Program received signal SIGSEGV, Segmentation fault.
0x000055555558b570 in fontdue::raster::Raster::add (self=0x7fffffffcb00, index=18446744071562067968, height=0, mid_x=0) at src/raster.rs:45
45	            *self.a.get_unchecked_mut(index) += height - m;
(gdb) bt
#0  0x000055555558b570 in fontdue::raster::Raster::add (self=0x7fffffffcb00, index=18446744071562067968, height=0, mid_x=0) at src/raster.rs:45
#1  fontdue::raster::Raster::m_line (self=0x7fffffffcb00, line=0x5555558a7710, coords=..., params=...) at src/raster.rs:118
#2  fontdue::raster::Raster::draw (self=0x7fffffffcb00, glyph=0x55555567a430, scale_x=0, scale_y=0, offset_x=0, offset_y=0) at src/raster.rs:36
#3  0x000055555558e457 in fontdue::font::Font::rasterize_indexed (self=0x7fffffffcd08, index=82, px=0) at src/font.rs:525
#4  0x0000555555570fb1 in fontdue::font::Font::rasterize (self=0x7fffffffcd08, character=111 'o', px=0) at /home/leshainc/Projects/fontdue/src/font.rs:462
#5  0x000055555556be7b in simple::generate_fontdue () at examples/simple.rs:28
#6  0x000055555556bdc6 in simple::main () at examples/simple.rs:14

Spanish letters misaligned with font sizes smaller than ~22

Spanish uses some accented letters that don't exist in English. These include "í" "ó" and "á". Consider the sample string:

¿Cómo estás?

As can be seen when Github+Firefox render this string, the vertical alignment of the accented letters is fine. Yet, when I render this same string using fontdue, the letters are slightly lower than they should be, but only with smaller font sizes.

Font size 12:
image

Font size 17:
image

Font size 22:
image

This is the code that handles the rendering:

fn draw_string(string: &str, x: i32, y: i32, font_size: f32, buffer: &mut Bitmap){
    let font = include_bytes!("roboto/Roboto-Regular.ttf") as &[u8];
    let mut font = Font::from_bytes(font, FontSettings::default()).unwrap();

    let xf = x as f32;
    let yf = y as f32;

    let mut x_offset: f32 = 0.0;
    for c in string.chars(){
        let (metrics, bitmap) = font.rasterize(c, font_size);
        let xmin = metrics.bounds.xmin;
        let ymax = metrics.bounds.ymax;

        for cx in 0..metrics.width{
            for cy in 0..metrics.height{
                let intensity = bitmap[cy*metrics.width+cx];
                let x_pos = xf+x_offset+(cx as f32)+xmin;
                let y_pos = yf+(cy as f32)- ymax;
                if x_pos >= 0.0 && y_pos >= 0.0 {
                    buffer.set_pixel(x_pos as usize, y_pos as usize, Color::new(intensity, intensity, intensity));
                }
            }
        }
        x_offset += metrics.advance_width;
    }
}

Compilation fails with `method not found`

When doing cargo run --example layout, I get

error[E0599]: no method named `to_string` found for struct `ttf_parser::tables::name::Name<'_>` in the current scope
   --> src/font.rs:212:25
    |
212 |             return name.to_string();
    |                         ^^^^^^^^^ method not found in `ttf_parser::tables::name::Name<'_>`

I was able to get the samples running by replacing the call to to_string() with a call to format!() (for which I had to add #[macro_use] extern crate std; to lib.rs), but clearly that is just a kludge.

Doc: what does "scale" do?

As far as I can tell from reading the code, this is a simplification step (performed while loading a font) which omits details which would not be visible at smaller sizes. Is that correct?

Related: #60.

Also related: #49. If I wished to render a glyph for multiple sub-pixel positions (e.g. (0, 0) and (0.5, 0)not RGB sub-pixel rendering)... this isn't supported. Does the "outline simplification" above conflict with supporting this?

Metrics from font.metrics() and font.rasterize() not equal

use std::fs::File;
use std::io::Write;

// Scratch pad for glyphs: ⅞ g
const CHARACTER: char = 'g';
const SIZE: f32 = 50.0;

pub fn main() {
    // Loading and rasterization
    let font = include_bytes!("../resources/Roboto-Regular.ttf") as &[u8];
    let font = fontdue::Font::from_bytes(font, fontdue::FontSettings::default()).unwrap();
    let metrics_0 = font.metrics(CHARACTER, SIZE, 0.0);
    let (metrics, bitmap) = font.rasterize(CHARACTER, SIZE, 0.0);

    dbg!(metrics_0);
    dbg!(metrics);

    // Output
    let mut o = File::create("fontdue.pgm").unwrap();
    let _ = o.write(format!("P5\n{} {}\n255\n", metrics.width, metrics.height).as_bytes());
    let _ = o.write(&bitmap);
}

output:

[examples/simple.rs:15] metrics_0 = Metrics {
    width: 23,
    height: 38,           // <------- this
    advance_width: 28.051758,
    advance_height: 0.0,
    bounds: AABB {
        xmin: 2.34375,
        xmax: 24.658203,
        ymin: -10.400391,
        ymax: 26.904297,
    },
}
[examples/simple.rs:16] metrics = Metrics {
    width: 23,
    height: 39,         // <------- this
    advance_width: 28.051758,
    advance_height: 0.0,
    bounds: AABB {
        xmin: 2.34375,
        xmax: 24.658203,
        ymin: -10.400391,
        ymax: 26.904297,
    },
}

Rasterize coarse

SourceHanSansSC-Regular.otf on logical 24px(Physical 48px)

left is ab-glyph, right is fontdue
image

The smaller the size, the more obvious the effect
on logical 12px(Physical 24px), this is considered the smallest text size.

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.