Skip to content

Commit

Permalink
Add image render tests
Browse files Browse the repository at this point in the history
Add tests that will match rendered words/paragraphs against reference
images.

Use env var `GENERATE_IMAGES` to write the initial reference images to
the repository.
  • Loading branch information
dovreshef committed Sep 23, 2023
1 parent e2adc1e commit 0c7c44a
Show file tree
Hide file tree
Showing 8 changed files with 318 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ harness = false
members = ["examples/*"]

[dev-dependencies]
tiny-skia = "0.11"
criterion = { version = "0.5.1", default-features = false, features = [
"cargo_bench_support",
] }
Expand Down
131 changes: 131 additions & 0 deletions fonts/FrankRuehlCLM-LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
This package is distributed under the terms of GNU General Public License
version 2 (see file GNU-GPL).
---------------------------------------------------------------------

Shofar font family is Copyright 2011-2012 by Yoram Gnat ([email protected])
Latin glyphs and punctuation Copyright (URW)++,Copyright 1999 by (URW)++ Design
& Development;
Hebrew Cantillation marks GSUB and GPOS OpenType positioning rules copyright
(c) 2010 by Yoram Gnat ([email protected])
Inspired by the Hebrew OpenType Layout logic copyright (c) 2003 & 2007,
Ralph Hancock & John Hudson published under the MIT License.
As a special exception, if you create a document which uses this font, and
embed this font or unaltered portions of this font into the document, this
font does not by itself cause the resulting document to be covered by the
GNU General Public License. This exception does not however invalidate any
other reasons why the document might be covered by the GNU General Public
License. If you modify this font, you may extend this exception to your
version of the font, but you are not obligated to do so. If you do not wish
to do so, delete this exception statement from your version.

Keter YG font family is Copyright 2009 by Yoram Gnat ([email protected])
Hebrew OpenType Layout logic copyright (c) 2003 & 2007, Ralph Hancock &
John Hudson. This layout logic for Biblical Hebrew is open source software
under the MIT License; for details contact copyright holders
at <[email protected]>.
As a special exception, if you create a document which uses this font, and
embed this font or unaltered portions of this font into the document, this
font does not by itself cause the resulting document to be covered by the
GNU General Public License. This exception does not however invalidate any
other reasons why the document might be covered by the GNU General Public
License. If you modify this font, you may extend this exception to your
version of the font, but you are not obligated to do so. If you do not wish
to do so, delete this exception statement from your version.

Hadasim font family is copyright 2010 by Yoram Gnat ([email protected]).
Latin and parts of general punctuation marks based on modified forms from
the LiberationSerif font, created by Digitized data 2007 Ascender
Corporation. All rights reserved.
As a special exception, if you create a document which uses this font, and
embed this font or unaltered portions of this font into the document, this
font does not by itself cause the resulting document to be covered by the
GNU General Public License. This exception does not however invalidate any
other reasons why the document might be covered by the GNU General Public
License. If you modify this font, you may extend this exception to your
version of the font, but you are not obligated to do so. If you do not wish
to do so, delete this exception statement from your version.

Simple font family is copyright 2007-2010 by Yoram Gnat
([email protected]). Latin glyphs, digits and punctuation copyright 1999
by (URW)++ Design & Development. All rights reserved.
Hebrew vowel marks positioning algorithms Copyright 2010 by Yoram Gnat 2010.
([email protected].
As a special exception, if you create a document which uses this font, and
embed this font or unaltered portions of this font into the document, this
font does not by itself cause the resulting document to be covered by the
GNU General Public License. This exception does not however invalidate any
other reasons why the document might be covered by the GNU General Public
License. If you modify this font, you may extend this exception to your
version of the font, but you are not obligated to do so. If you do not wish
to do so, delete this exception statement from your version.

Stam Ashkenaz font is copyright 2007-2010 by Yoram Gnat ([email protected]).
As a special exception, if you create a document which uses this font, and
embed this font or unaltered portions of this font into the document, this
font does not by itself cause the resulting document to be covered by the
GNU General Public License. This exception does not however invalidate any
other reasons why the document might be covered by the GNU General Public
License. If you modify this font, you may extend this exception to your
version of the font, but you are not obligated to do so. If you do not wish
to do so, delete this exception statement from your version.

Stam Sefarad font is copyright 2008-2010 by Yoram Gnat ([email protected]).
As a special exception, if you create a document which uses this font, and
embed this font or unaltered portions of this font into the document, this
font does not by itself cause the resulting document to be covered by the
GNU General Public License. This exception does not however invalidate any
other reasons why the document might be covered by the GNU General Public
License. If you modify this font, you may extend this exception to your
version of the font, but you are not obligated to do so. If you do not wish
to do so, delete this exception statement from your version.

Miriam font family is copyright 2004-2010 by Maxim Iorsh
([email protected]). All rights reserved.

Yehuda font family is copyright 2004 by Maxim Iorsh
([email protected]). All rights reserved.

Drugulin font family (Hebrew glyphs) is copyright 2003,2004 by Maxim Iorsh
([email protected]). Latin glyphs, digits and punctuation
contained in the Drugulin font family are part of Nimbus Roman No9 L font
family and are copyright 1999 by (URW)++ Design & Development.
All rights reserved.

Ellinia font family is copyright 2003,2004 by Maxim Iorsh
([email protected]). All rights reserved.

Caladings collection is copyright 2003,2004 by Maxim Iorsh
([email protected]). All rights reserved.

Digital version of Aharoni font family (Hebrew glyphs, numerals and part
of punctuation) is copyright 2002-2004 by Maxim Iorsh
([email protected]). Latin glyphs, digits and part of punctuation
contained in the Aharoni font family are part of URW Gothic L font family
and are copyright 1999 by (URW)++ Design & Development.
All rights reserved.

Digital version of David font family (Hebrew glyphs, numerals and part of
punctuation) is copyright 2002-2017 by Maxim Iorsh
([email protected]). Latin glyphs and part of punctuation
contained in the David font family are part of Bitstream Charter font
family and are copyright 1990 as an unpublished work by Bitstream Inc. All
rights reserved. See also file LICENSE-BITSTREAM.

Frank-Ruehl font family (Hebrew glyphs) is copyright 2002-2011 by Maxim
Iorsh ([email protected]). Latin glyphs, digits and punctuation
contained in the Frank-Ruehl font family are part of Century Schoolbook L
font family and are copyright 1999 by (URW)++ Design & Development. All
rights reserved.

Nachlieli font family (Hebrew glyphs) is copyright 2002-2017 by Maxim
Iorsh ([email protected]). Latin glyphs, digits and punctuation
contained in the Nachlieli font family are part of Nimbus Sans L font
family and are copyright 1999 by (URW)++ Design & Development. All
rights reserved.

Miriam Mono font family (Hebrew glyphs) is copyright 2002-2004 by Maxim
Iorsh ([email protected]). Hebrew vowel marks positioning algorithms
implementation by Yoram Gnat ([email protected]), 2010.
Latin glyphs, digits and punctuation contained in the Miriam Mono font
family are part of Nimbus Mono L font family and are copyright 1999 by
(URW)++ Design & Development. All rights reserved.
Binary file added fonts/FrankRuehlCLM-Medium.ttf
Binary file not shown.
144 changes: 144 additions & 0 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
use std::path::PathBuf;

use cosmic_text::{
fontdb::Database, Attrs, Buffer, Color, Family, FontSystem, Metrics, Shaping, SwashCache,
};
use tiny_skia::{Paint, Pixmap, Rect, Transform};

/// The test configuration.
/// The text in the test will be rendered as image using the font specified. The font will be
/// loaded from the `fonts` directory in this repository.
/// The image will then be compared to an image with the name `name` under the `tests/images`
/// directory in this repository.
/// If the images do not match the test will fail.
/// NOTE: if an environment file `GENERATE_IMAGES` is set, the test will create and save
/// the images instead.
#[derive(Debug)]
pub struct DrawTestCfg {
/// The name of the test.
/// Will be used for the image name under the `tests/images` directory in this repository.
name: String,
/// The name of the font file to be used.
/// Expected to be found under the `fonts` directory in this repository.
font_file_name: String,
text: String,
font_size: f32,
line_height: f32,
canvas_width: u32,
canvas_height: u32,
}

impl Default for DrawTestCfg {
fn default() -> Self {
Self {
name: "default".into(),
font_file_name: "FiraMono-Medium.ttf".into(),
text: "".into(),
font_size: 16.0,
line_height: 20.0,
canvas_width: 300,
canvas_height: 300,
}
}
}

impl DrawTestCfg {
pub fn new(
name: impl Into<String>,
font_file_name: impl Into<String>,
text: impl Into<String>,
) -> Self {
Self {
name: name.into(),
font_file_name: font_file_name.into(),
text: text.into(),
..Default::default()
}
}

pub fn font_size(mut self, font_size: f32, line_height: f32) -> Self {
self.font_size = font_size;
self.line_height = line_height;
self
}

pub fn canvas(mut self, width: u32, height: u32) -> Self {
self.canvas_width = width;
self.canvas_height = height;
self
}

pub fn validate_text_rendering(self) {
let repo_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
// Create a db with just this font to make sure we either test it or fail
let font_path = PathBuf::from(&repo_dir)
.join("fonts")
.join(&self.font_file_name);
let mut font_db = Database::new();
font_db.load_font_file(font_path).unwrap();
// Get the font config so we can choose it later for the buffer
let font_face = font_db.faces().next().unwrap();
let (family, lang) = font_face.families[0].clone();
let attrs = Attrs::new()
.family(Family::Name(&family))
.weight(font_face.weight)
.style(font_face.style)
.stretch(font_face.stretch);
let mut font_system = FontSystem::new_with_locale_and_db(lang.to_string(), font_db);

let mut swash_cache = SwashCache::new();
let metrics = Metrics::new(self.font_size, self.line_height);
let mut buffer = Buffer::new(&mut font_system, metrics);
let mut buffer = buffer.borrow_with(&mut font_system);
let margins = 5;
buffer.set_size(
(self.canvas_width - margins * 2) as f32,
(self.canvas_height - margins * 2) as f32,
);
buffer.set_text(&self.text, attrs, Shaping::Advanced);
buffer.shape_until_scroll();

// Black
let text_color = Color::rgb(0x00, 0x00, 0x00);

let mut pixmap = Pixmap::new(self.canvas_width, self.canvas_height).unwrap();
pixmap.fill(tiny_skia::Color::WHITE);

buffer.draw(&mut swash_cache, text_color, |x, y, w, h, color| {
let mut paint = Paint::default();
paint.set_color_rgba8(color.r(), color.g(), color.b(), color.a());
let rect = Rect::from_xywh(
(x + margins as i32) as f32,
(y + margins as i32) as f32,
w as f32,
h as f32,
)
.unwrap();
pixmap.fill_rect(rect, &paint, Transform::identity(), None);
});

let image_name = format!("{}.png", self.name);
let reference_image_path = PathBuf::from(&repo_dir)
.join("tests")
.join("images")
.join(image_name);

let generate_images = std::env::var("GENERATE_IMAGES")
.map(|v| {
let val = v.trim().to_ascii_lowercase();
["t", "true", "1"].iter().any(|&v| v == val)
})
.unwrap_or_default();

if generate_images {
pixmap.save_png(reference_image_path).unwrap();
} else {
let reference_image_data = std::fs::read(reference_image_path).unwrap();
let image_data = pixmap.encode_png().unwrap();
assert_eq!(
reference_image_data, image_data,
"rendering failed of {self:?}"
)
}
}
}
3 changes: 3 additions & 0 deletions tests/images/a_hebrew_paragraph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions tests/images/a_hebrew_word.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions tests/images/some_english_mixed_with_hebrew.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 33 additions & 0 deletions tests/shaping_and_rendering.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use common::DrawTestCfg;

mod common;

#[test]
fn test_hebrew_word_rendering() {
DrawTestCfg::new("a_hebrew_word", "FrankRuehlCLM-Medium.ttf", "בדיקה")
.font_size(24., 26.)
.canvas(70, 40)
.validate_text_rendering();
}

#[test]
fn test_hebrew_paragraph_rendering() {
let paragraph = "השועל החום המהיר קופץ מעל הכלב העצלן";
DrawTestCfg::new("a_hebrew_paragraph", "FrankRuehlCLM-Medium.ttf", paragraph)
.font_size(36., 40.)
.canvas(400, 110)
.validate_text_rendering();
}

#[test]
fn test_english_mixed_with_hebrew_paragraph_rendering() {
let paragraph = "Many computer programs fail to display bidirectional text correctly. For example, this page is mostly LTR English script, and here is the RTL Hebrew name Sarah: שרה, spelled sin (ש) on the right, resh (ר) in the middle, and heh (ה) on the left.";
DrawTestCfg::new(
"some_english_mixed_with_hebrew",
"FrankRuehlCLM-Medium.ttf",
paragraph,
)
.font_size(16., 20.)
.canvas(400, 120)
.validate_text_rendering();
}

0 comments on commit 0c7c44a

Please sign in to comment.