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

Panic when targeting Canvas larger than glyph with SubpixelAa option in Freetype. #252

Closed
lte678 opened this issue Oct 5, 2024 · 1 comment

Comments

@lte678
Copy link
Contributor

lte678 commented Oct 5, 2024

As stated in the title, when trying to rasterize a glyph to a canvas that is (significantly) larger than the glyph bitmap itself and using the SubpixelAa option, then a panic occurs:
(The stacktrace has differing line numbers due to local modifications!)

range end index 1188 out of range for slice of length 1152
stack backtrace:
   0: rust_begin_unwind
             at /rustc/59e2c01c2217a01546222e4d9ff4e6695ee8a1db/library/std/src/panicking.rs:658:5
   1: core::panicking::panic_fmt
             at /rustc/59e2c01c2217a01546222e4d9ff4e6695ee8a1db/library/core/src/panicking.rs:74:14
   2: core::slice::index::slice_end_index_len_fail_rt
             at /rustc/59e2c01c2217a01546222e4d9ff4e6695ee8a1db/library/core/src/slice/index.rs:64:5
   3: core::slice::index::slice_end_index_len_fail
             at /rustc/59e2c01c2217a01546222e4d9ff4e6695ee8a1db/library/core/src/slice/index.rs:57:5
   4: <core::ops::range::Range<usize> as core::slice::index::SliceIndex<[T]>>::index
             at /rustc/59e2c01c2217a01546222e4d9ff4e6695ee8a1db/library/core/src/slice/index.rs:457:13
   5: core::slice::index::<impl core::ops::index::Index<I> for [T]>::index
             at /rustc/59e2c01c2217a01546222e4d9ff4e6695ee8a1db/library/core/src/slice/index.rs:16:9
   6: font_kit::canvas::Canvas::blit_from_with
             at ./src/canvas.rs:200:44
   7: font_kit::canvas::Canvas::blit_from
             at ./src/canvas.rs:116:17
   8: font_kit::loaders::freetype::Font::rasterize_glyph
             at ./src/loaders/freetype.rs:866:25
   9: tests::rasterize_glyph_with_full_hinting_subpixel
             at ./tests/tests.rs:852:5
  10: tests::rasterize_glyph_with_full_hinting_subpixel::{{closure}}
             at ./tests/tests.rs:820:52
  11: core::ops::function::FnOnce::call_once
             at /rustc/59e2c01c2217a01546222e4d9ff4e6695ee8a1db/library/core/src/ops/function.rs:250:5
  12: core::ops::function::FnOnce::call_once
             at /rustc/59e2c01c2217a01546222e4d9ff4e6695ee8a1db/library/core/src/ops/function.rs:250:5

Here is a test to reproduce the issue:

pub fn rasterize_glyph_with_full_hinting_subpixel() {
    let font = SystemSource::new()
        .select_best_match(&[FamilyName::SansSerif], &Properties::new())
        .unwrap()
        .load()
        .unwrap();
    let glyph_id = font.glyph_for_char('L').unwrap();
    let size = 32.0;
    let raster_rect = font
        .raster_bounds(
            glyph_id,
            size,
            Transform2F::default(),
            HintingOptions::Full(size),
            RasterizationOptions::SubpixelAa,
        )
        .unwrap();
    let origin: Vector2F = -raster_rect.origin().to_f32();
    
    // Test with larger canvas
    // It works with the commented out line
    // let mut canvas = Canvas::new(raster_rect.size(), Format::Rgb24);
    let mut canvas = Canvas::new(Vector2I::new(100, 100), Format::Rgb24);
    font.rasterize_glyph(
        &mut canvas,
        glyph_id,
        size,
        Transform2F::from_translation(origin),
        HintingOptions::Full(size),
        RasterizationOptions::SubpixelAa,
    )
    .unwrap();
    check_L_shape(&canvas);
}

I was able to fix the issue by setting the bitmap size to be let bitmap_size = Vector2I::new(bitmap_width / 3, bitmap_height); in the FT_PIXEL_MODE_LCD case in the Freetype rasterize_glyph function. It seems that the width returned in the bitmap structure is returned in bytes instead of pixels (https://freetype.org/freetype2/docs/reference/ft2-basic_types.html, FT_PIXEL_MODE_LCD) so needs to be divided by three before passing along to blit_from which expects bitmap_size to be in pixels.

This issue does not appear in the examples, since we are always blitting to a canvas that is exactly the right size, so the source buffer is cropped suitably to prevent it from overflowing.

If I can get some confirmation on this, then I will try to open up a pull request with the failing test and a fix.

lte678 added a commit to lte678/font-kit that referenced this issue Oct 12, 2024
github-merge-queue bot pushed a commit that referenced this issue Oct 12, 2024
* Add failing test for #252

* Change bytes_per_pixel to usize.

* Add checks to avoid confusing runtime exceptions.

* Fix bitmap_size in FreeType rasterize_glyph for MODE_LCD*

* Fix buffer checks in blit_from

* Revert "Change bytes_per_pixel to usize."

This reverts commit a8231d7.

* Fix missing cast due to revert
@lte678
Copy link
Contributor Author

lte678 commented Oct 12, 2024

Fixed in #254

@lte678 lte678 closed this as completed Oct 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