aliftype / raqq

Raqq (رَقّ) is a manuscript Kufic typeface
https://aliftype.com/raqq
GNU Affero General Public License v3.0
41 stars 2 forks source link

Shaping issues for letters at the end of a line. + Coloring issues. #26

Closed asibahi closed 6 months ago

asibahi commented 6 months ago

Hello.

First, thanks for the font. Your work is an inspiration.

I have been playing with the font in my Arabic justification experiments (which can be found here) , and I noticed some odd behaviors for shaping when it is the last letter in a line. I do not know if this is an issue with the font or if it is an issue somewhere in my code.

The image in the repo has an example of what I am talking about in the ي at the end of دري .

image

You will see that the Yea's dots are .. shifted a bit

Here is another example with a different word : على

image

I also notice it when a word ending with ل like كل or مثل at the end of a line. I am using the latest release of Raqq. I am not sure what version of Harfbuzz I am using. (Everything related to C libraries is entirely confusing to me).


Regarding coloring : Again I have no knowledge if this is a font issue or a tech stack issue:

When drawing the glyphs with a different color than white I encounter odd artifacts on some letters like seen in this image.

noor_49

I managed to work around by actually drawing the letters as transparent and just overlaying that over another image with text's color, so it is not an issue. But thought it was worth pointing out.

Thanks again.

khaledhosny commented 6 months ago

I noticed some odd behaviors for shaping when it is the last letter in a line.

Fonts know nothing about line end, so I don’t think there is a font issue here. Using hb-view, the word looks fine:

When drawing the glyphs with a different color than white I encounter odd artifacts on some letters like seen in this image.

This might be caused by differences in path direction between glyphs. Can you try the latest commit?

khaledhosny commented 6 months ago

Cool project, BTW, the justification looks really nice. I should give it a try.

asibahi commented 6 months ago

Thanks for the kind words. Much appreciated.

This is with the latest commit font. Same issue with colors.

noor_52

regarding the shaping issue, I noticed that it occurs when I pass to HarfBuzz a trimmed string. The code sample below: the commented out line is where it affects it. I ended up trimming only the last line (because it renders a tofu if I dont?) but shifting all the other lines by the last space's x_advance.

    let hb_buffer = hb::UnicodeBuffer::new().add_str_item(TEXT, &TEXT[start_bp..end_bp]);
    // let hb_buffer = hb::UnicodeBuffer::new().add_str_item(TEXT, TEXT[start_bp..end_bp].trim());
    let hb_output = hb::shape(&hb_font, hb_buffer, &[]);

You will notice in the image above how the ي in دري is shifted slightly leftwards.

khaledhosny commented 6 months ago

This is with the latest commit font. Same issue with colors.

How do I reproduce this using your repo? I tried this change:

diff --git a/src/main.rs b/src/main.rs
index cecda22..4c22533 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -32,8 +32,8 @@ const _OFF_BLACK: [u8; 4] = [0x20, 0x20, 0x20, 0xFF];
 const _GOLD_ORNG: [u8; 4] = [0xB4, 0x89, 0x39, 0xFF];
 const _NAVY_BLUE: [u8; 4] = [0x13, 0x2A, 0x4A, 0xFF];

-const TXT_COLOR: image::Rgba<u8> = image::Rgba(_BLACK);
-const BKG_COLOR: image::Rgba<u8> = image::Rgba(_OFF_WHITE);
+const TXT_COLOR: image::Rgba<u8> = image::Rgba(_GOLD_ORNG);
+const BKG_COLOR: image::Rgba<u8> = image::Rgba(_NAVY_BLUE);

 fn main() -> Result<(), Box<dyn std::error::Error>> {
     let font_data = std::fs::read("fonts/Raqq.ttf")?;

But I don’t get any color artifacts: noor_50

regarding the shaping issue, I noticed that it occurs when I pass to HarfBuzz a trimmed string. The code sample below: the commented out line is where it affects it. I ended up trimming only the last line (because it renders a tofu if I dont?) but shifting all the other lines by the last space's x_advance.

I don’t know much about Rust to get what this code is doing.

asibahi commented 6 months ago

This branch reproduces the issue: https://github.com/asibahi/noor/tree/reproduce_color_artifacts

The difference between this one and master is that master draws the letters as transparent ([0, 0, 0, 0]) and overlays it over the text color.

This branch reproduces the shaping artifacts: https://github.com/asibahi/noor/tree/reproduce_shaping_artifact .

كل عام وأنتم بخير

khaledhosny commented 6 months ago

This branch reproduces the issue: https://github.com/asibahi/noor/tree/reproduce_color_artifacts

The difference between this one and master is that master draws the letters as transparent ([0, 0, 0, 0]) and overlays it over the text color.

I fixed the issue with س (which was a genuine bug), the other artifacts look like a bug in the rendering library/rasterizer not being able to handle overlapping paths.

khaledhosny commented 6 months ago

This branch reproduces the shaping artifacts: https://github.com/asibahi/noor/tree/reproduce_shaping_artifact .

Like I said, I don’t know much rust, but it seems like a bug in ab_glyph. It looks like if a zero-width glyph is constructed at x=0 position, the min x of the next glyph bounds are wrong.

This patch that avoids x ever being zero by initializing it to the margin value, seems to workaround this issue:

diff --git a/src/main.rs b/src/main.rs
index 7bd41c6..1bae0a6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -131,7 +131,7 @@ fn write_in_image(

     let ascent = ab_scaled_font.ascent();

-    let mut caret = 0;
+    let mut caret = MARGIN as f32;

     let mut colored_glyphs = vec![];

@@ -143,12 +143,12 @@ fn write_in_image(
         let gl = ab::GlyphId(info.codepoint as u16).with_scale_and_position(
             ab_scale,
             ab::point(
-                (caret + position.x_offset) as f32 * scale_factor.horizontal,
+                caret + (position.x_offset as f32 * scale_factor.horizontal),
                 ascent - (position.y_offset as f32 * scale_factor.vertical),
             ),
         );

-        caret += position.x_advance;
+        caret += position.x_advance as f32 * scale_factor.horizontal;

         let Some(outlined_glyph) = ab_font.outline_glyph(gl) else {
             // gl is whitespace
@@ -156,7 +156,7 @@ fn write_in_image(
         };

         let bb = outlined_glyph.px_bounds();
-        let bbx = bb.min.x as u32 + MARGIN;
+        let bbx = bb.min.x as u32;
         let bby = bb.min.y as u32 + MARGIN + line as u32 * LINE_HEIGHT;

         if let Some(colored_glyph) = ab_font
khaledhosny commented 6 months ago

Closing this as it is neither a font nor a shaping issue.