Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

font.outline() renders a glyph in reversed shape #247

Open
kmoon2437 opened this issue Jul 12, 2024 · 0 comments
Open

font.outline() renders a glyph in reversed shape #247

kmoon2437 opened this issue Jul 12, 2024 · 0 comments

Comments

@kmoon2437
Copy link

kmoon2437 commented Jul 12, 2024

I'm using this library with raqote for text rendering. I wrote the code below:

use std::fs::File;
use font_kit::font::Font;
use font_kit::hinting::HintingOptions;
use font_kit::outline::OutlineSink;
use raqote::{
    Path, PathBuilder,
    Point, Source, SolidSource,
    StrokeStyle, LineCap, LineJoin,
    DrawTarget, DrawOptions
};
use pathfinder_geometry::vector::Vector2F;
use pathfinder_geometry::line_segment::LineSegment2F;

pub struct TextPathBuilder {
    pb: PathBuilder,
    font_scale: f32,
    start: Point
}

impl TextPathBuilder {
    pub fn new(font_size: f32, start: Point, units_per_em: u32) -> Self {
        return Self {
            pb: PathBuilder::new(),
            font_scale: font_size / units_per_em as f32,
            start
        };
    }

    fn calc_point(&self, point: f32) -> f32 {
        return point * self.font_scale;
    }

    fn calc_x(&self, point: f32) -> f32 {
        return self.calc_point(point) + self.start.x;
    }

    fn calc_y(&self, point: f32) -> f32 {
        return self.calc_point(point) + self.start.y;
    }

    pub fn finish(self) -> Path {
        return self.pb.finish();
    }
}

impl OutlineSink for TextPathBuilder {
    fn move_to(&mut self, to: Vector2F) {
        self.pb.move_to(self.calc_x(to.x()), self.calc_y(to.y()));
    }

    fn line_to(&mut self, to: Vector2F) {
        self.pb.line_to(self.calc_x(to.x()), self.calc_y(to.y()));
    }

    fn quadratic_curve_to(&mut self, ctrl: Vector2F, to: Vector2F) {
        self.pb.quad_to(self.calc_x(ctrl.x()), self.calc_y(ctrl.y()), self.calc_x(to.x()), self.calc_y(to.y()));
    }

    fn cubic_curve_to(&mut self, ctrl: LineSegment2F, to: Vector2F) {
        self.pb.cubic_to(self.calc_x(ctrl.from().x()), self.calc_y(ctrl.from().y()), self.calc_x(ctrl.to().x()), self.calc_y(ctrl.to().y()), self.calc_x(to.x()), self.calc_y(to.y()));
    }

    fn close(&mut self) {
        self.pb.close();
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut file = File::open("tmp/NotoSansCJK-Medium.otf")?;
    let font = Font::from_file(&mut file, 0)?;

    let mut tpb = TextPathBuilder::new(70.0, Point::new(10.0, 10.0), font.metrics().units_per_em);
    font.outline(font.glyph_for_char('9').unwrap(), HintingOptions::None, &mut tpb)?;
    let path = tpb.finish();

    let mut dt = DrawTarget::new(100, 100);

    let color1 = Source::Solid(SolidSource::from_unpremultiplied_argb(255, 255, 255, 255));
    let color2 = Source::Solid(SolidSource::from_unpremultiplied_argb(255, 0x2a, 0xbd, 0x71));
    let stroke = StrokeStyle {
        cap: LineCap::Butt,
        join: LineJoin::Round,
        width: 10.0,
        miter_limit: 10.0,
        ..Default::default()
    };
    let draw_options = DrawOptions {
        ..Default::default()
    };

    dt.stroke(&path, &color1, &stroke, &draw_options);
    dt.fill(&path, &color2, &draw_options);

    dt.write_png("example.png")?;

    return Ok(());
}

However, the output is reversed "9".

I fixed TextPathBuilder like this:

pub struct TextPathBuilder {
    pb: PathBuilder,
    font_scale: f32,
    font_size: f32,
    start: Point
}

impl TextPathBuilder {
    pub fn new(font_size: f32, start: Point, units_per_em: u32) -> Self {
        return Self {
            pb: PathBuilder::new(),
            font_scale: font_size / units_per_em as f32,
            font_size,
            start
        };
    }

    fn calc_point(&self, point: f32) -> f32 {
        return point * self.font_scale;
    }

    fn calc_x(&self, point: f32) -> f32 {
        return self.calc_point(point) + self.start.x;
    }

    fn calc_y(&self, point: f32) -> f32 {
        return -self.calc_point(point) + self.font_size + self.start.y;
    }

    pub fn finish(self) -> Path {
        return self.pb.finish();
    }
}

and the image is generated correctly.

Did I fix the problem correctly?

@kmoon2437 kmoon2437 changed the title reversed glyph rendered Glyph rendered in reversed shape Jul 12, 2024
@kmoon2437 kmoon2437 changed the title Glyph rendered in reversed shape Glyph is rendered in reversed shape Jul 12, 2024
@kmoon2437 kmoon2437 changed the title Glyph is rendered in reversed shape font.outline() renders a glyph in reversed shape Jul 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant