diff options
| author | Laurenz <laurmaedje@gmail.com> | 2019-10-16 21:31:14 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2019-10-16 21:31:14 +0200 |
| commit | f2f05e07b0ff2d98e3c822b2618d02281ed1078c (patch) | |
| tree | 6f4f8fa046af49c319d68c012a078f3489ab92aa /tests | |
| parent | a3c667895e4e5d5673931415397523b9615008d3 (diff) | |
Implement space extension (multipage) ➕
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/layouting.rs | 114 | ||||
| -rw-r--r-- | tests/layouts/pagebreaks.typ | 2 | ||||
| -rw-r--r-- | tests/layouts/shakespeare-right.tps | 88 | ||||
| -rw-r--r-- | tests/layouts/shakespeare.tpl (renamed from tests/layouts/shakespeare.tps) | 0 | ||||
| -rw-r--r-- | tests/layouts/shakespeare.typ | 8 | ||||
| -rw-r--r-- | tests/layouts/styles.typ (renamed from tests/layouts/styles.tps) | 5 | ||||
| -rw-r--r-- | tests/render.py | 73 |
7 files changed, 165 insertions, 125 deletions
diff --git a/tests/layouting.rs b/tests/layouting.rs index 75aaa66b..f77c6e85 100644 --- a/tests/layouting.rs +++ b/tests/layouting.rs @@ -3,12 +3,16 @@ use std::io::{BufWriter, Read, Write}; use std::process::Command; use std::time::Instant; +use regex::{Regex, Captures}; + use typst::export::pdf::PdfExporter; use typst::layout::LayoutAction; use typst::toddle::query::FileSystemFontProvider; +use typst::size::{Size, Size2D, SizeBox}; +use typst::style::PageStyle; use typst::Typesetter; -const CACHE_DIR: &str = "test-cache"; +const CACHE_DIR: &str = "tests/cache"; fn main() { let mut perfect_match = false; @@ -31,6 +35,10 @@ fn main() { for entry in fs::read_dir("tests/layouts/").unwrap() { let path = entry.unwrap().path(); + if path.extension() != Some(std::ffi::OsStr::new("typ")) { + continue; + } + let name = path.file_stem().unwrap().to_str().unwrap(); let matches = if perfect_match { @@ -51,36 +59,47 @@ fn main() { /// Create a _PDF_ with a name from the source code. fn test(name: &str, src: &str) { - print!("Testing: {}", name); + println!("Testing: {}", name); + + let (src, size) = preprocess(src); let mut typesetter = Typesetter::new(); let provider = FileSystemFontProvider::from_listing("fonts/fonts.toml").unwrap(); typesetter.add_font_provider(provider.clone()); + if let Some(dimensions) = size { + typesetter.set_page_style(PageStyle { + dimensions, + margins: SizeBox::zero() + }); + } + let start = Instant::now(); // Layout into box layout. - let tree = typesetter.parse(src).unwrap(); - let layout = typesetter.layout(&tree).unwrap(); + let tree = typesetter.parse(&src).unwrap(); + let layouts = typesetter.layout(&tree).unwrap(); let end = Instant::now(); let duration = end - start; - println!(" [{:?}]", duration); + println!(" => {:?}", duration); + println!(); // Write the serialed layout file. - let path = format!("{}/serialized/{}.box", CACHE_DIR, name); + let path = format!("{}/serialized/{}.lay", CACHE_DIR, name); let mut file = File::create(path).unwrap(); // Find all used fonts and their filenames. let mut map = Vec::new(); let mut loader = typesetter.loader().borrow_mut(); - let single = &layout.layouts[0]; - for action in &single.actions { - if let LayoutAction::SetFont(index, _) = action { - if map.iter().find(|(i, _)| i == index).is_none() { - let (_, provider_index) = loader.get_provider_and_index(*index); - let filename = provider.get_path(provider_index).to_str().unwrap(); - map.push((*index, filename)); + for layout in &layouts { + for action in &layout.actions { + if let LayoutAction::SetFont(index, _) = action { + if map.iter().find(|(i, _)| i == index).is_none() { + let (_, provider_index) = loader.get_provider_and_index(*index); + let filename = provider.get_path(provider_index).to_str().unwrap(); + map.push((*index, filename)); + } } } } @@ -91,7 +110,8 @@ fn test(name: &str, src: &str) { for (index, path) in map { writeln!(file, "{} {}", index, path).unwrap(); } - single.serialize(&mut file).unwrap(); + + layouts.serialize(&mut file).unwrap(); // Render the layout into a PNG. Command::new("python") @@ -104,5 +124,69 @@ fn test(name: &str, src: &str) { let path = format!("{}/pdf/{}.pdf", CACHE_DIR, name); let file = BufWriter::new(File::create(path).unwrap()); let exporter = PdfExporter::new(); - exporter.export(&layout, typesetter.loader(), file).unwrap(); + exporter.export(&layouts, typesetter.loader(), file).unwrap(); +} + +fn preprocess<'a>(src: &'a str) -> (String, Option<Size2D>) { + let include_regex = Regex::new(r"\{include:((.|\.|\-)*)\}").unwrap(); + let lorem_regex = Regex::new(r"\{lorem:(\d*)\}").unwrap(); + let size_regex = Regex::new(r"\{(size:(([\d\w]*)\*([\d\w]*)))\}").unwrap(); + + let mut size = None; + + let mut preprocessed = size_regex.replace_all(&src, |cap: &Captures| { + let width_str = cap.get(3).unwrap().as_str(); + let height_str = cap.get(4).unwrap().as_str(); + + let width = width_str.parse::<Size>().unwrap(); + let height = height_str.parse::<Size>().unwrap(); + + size = Some(Size2D::new(width, height)); + + "".to_string() + }).to_string(); + + let mut changed = true; + while changed { + changed = false; + preprocessed = include_regex.replace_all(&preprocessed, |cap: &Captures| { + changed = true; + let filename = cap.get(1).unwrap().as_str(); + + let path = format!("tests/layouts/{}", filename); + let mut file = File::open(path).unwrap(); + let mut buf = String::new(); + file.read_to_string(&mut buf).unwrap(); + buf + }).to_string(); + } + + preprocessed= lorem_regex.replace_all(&preprocessed, |cap: &Captures| { + let num_str = cap.get(1).unwrap().as_str(); + let num_words = num_str.parse::<usize>().unwrap(); + + generate_lorem(num_words) + }).to_string(); + + (preprocessed, size) +} + +fn generate_lorem(num_words: usize) -> String { + const LOREM: [&str; 69] = [ + "Lorem", "ipsum", "dolor", "sit", "amet,", "consectetur", "adipiscing", "elit.", "Etiam", + "suscipit", "porta", "pretium.", "Donec", "eu", "lorem", "hendrerit,", "scelerisque", + "lectus", "at,", "consequat", "ligula.", "Nulla", "elementum", "massa", "et", "viverra", + "consectetur.", "Donec", "blandit", "metus", "ut", "ipsum", "commodo", "congue.", "Nullam", + "auctor,", "mi", "vel", "tristique", "venenatis,", "nisl", "nunc", "tristique", "diam,", + "aliquam", "pellentesque", "lorem", "massa", "vel", "neque.", "Sed", "malesuada", "ante", + "nisi,", "sit", "amet", "auctor", "risus", "fermentum", "in.", "Sed", "blandit", "mollis", + "mi,", "non", "tristique", "nisi", "fringilla", "at." + ]; + + let mut buf = String::new(); + for i in 0 .. num_words { + buf.push_str(LOREM[i % LOREM.len()]); + buf.push(' '); + } + buf } diff --git a/tests/layouts/pagebreaks.typ b/tests/layouts/pagebreaks.typ new file mode 100644 index 00000000..6887613f --- /dev/null +++ b/tests/layouts/pagebreaks.typ @@ -0,0 +1,2 @@ +{size:200pt*200pt} +{lorem:400} diff --git a/tests/layouts/shakespeare-right.tps b/tests/layouts/shakespeare-right.tps deleted file mode 100644 index db670fdf..00000000 --- a/tests/layouts/shakespeare-right.tps +++ /dev/null @@ -1,88 +0,0 @@ -[align: right][ - [bold][Scene 5: _The Tower of London_] - - [italic][Enter Mortimer, brought in a chair, and Gaolers.] - - *Mortimer.* Kind keepers of my weak decaying age, - Let dying Mortimer here rest himself. - Even like a man new haled from the rack, - So fare my limbs with long imprisonment; - And these grey locks, the pursuivants of death, - Nestor-like aged in an age of care, - Argue the end of Edmund Mortimer. - These eyes, like lamps whose wasting oil is spent, - Wax dim, as drawing to their exigent; - Weak shoulders, overborne with burdening grief, - And pithless arms, like to a withered vine - That droops his sapless branches to the ground. - Yet are these feet, whose strengthless stay is numb, - Unable to support this lump of clay, - Swift-winged with desire to get a grave, - As witting I no other comfort have. - But tell me, keeper, will my nephew come? - - *First Keeper.* Richard Plantagenet, my lord, will come. - We sent unto the Temple, unto his chamber; - And answer was return'd that he will come. - - *Mortimer.* Enough; my soul shall then be satisfied. - Poor gentleman! his wrong doth equal mine. - Since Henry Monmouth first began to reign, - Before whose glory I was great in arms, - This loathsome sequestration have I had; - And even since then hath Richard been obscur'd, - Depriv'd of honour and inheritance. - But now the arbitrator of despairs, - Just Death, kind umpire of men's miseries, - With sweet enlargement doth dismiss me hence. - I would his troubles likewise were expir'd, - That so he might recover what was lost. - - - [italic][Enter Richard Plantagenet] - - *First Keeper.* My lord, your loving nephew now is come. - - *Mortimer.* Richard Plantagenet, my friend, is he come? - - *Plantagenet.* Ay, noble uncle, thus ignobly us'd, - Your nephew, late despised Richard, comes. - - *Mortimer.* Direct mine arms I may embrace his neck - And in his bosom spend my latter gasp. - O, tell me when my lips do touch his cheeks, - That I may kindly give one fainting kiss. - And now declare, sweet stem from York's great stock, - Why didst thou say of late thou wert despis'd? - - *Plantagenet.* First, lean thine aged back against mine arm; - And, in that ease, I'll tell thee my disease. - This day, in argument upon a case, - Some words there grew 'twixt Somerset and me; - Among which terms he us'd his lavish tongue - And did upbraid me with my father's death; - Which obloquy set bars before my tongue, - Else with the like I had requited him. - Therefore, good uncle, for my father's sake, - In honour of a true Plantagenet, - And for alliance sake, declare the cause - My father, Earl of Cambridge, lost his head. - - *Mortimer.* That cause, fair nephew, that imprison'd me - And hath detain'd me all my flow'ring youth - Within a loathsome dungeon, there to pine, - Was cursed instrument of his decease. - - *Plantagenet.* Discover more at large what cause that was, - For I am ignorant and cannot guess. - - *Mortimer.* I will, if that my fading breath permit - And death approach not ere my tale be done. - Henry the Fourth, grandfather to this king, - Depos'd his nephew Richard, Edward's son, - The first-begotten and the lawful heir - Of Edward king, the third of that descent; - During whose reign the Percies of the north, - Finding his usurpation most unjust, - Endeavour'd my advancement to the throne ... -] diff --git a/tests/layouts/shakespeare.tps b/tests/layouts/shakespeare.tpl index e0839302..e0839302 100644 --- a/tests/layouts/shakespeare.tps +++ b/tests/layouts/shakespeare.tpl diff --git a/tests/layouts/shakespeare.typ b/tests/layouts/shakespeare.typ new file mode 100644 index 00000000..09edd361 --- /dev/null +++ b/tests/layouts/shakespeare.typ @@ -0,0 +1,8 @@ +// Basic unboxed +{include:shakespeare.tpl} + +// Boxed, but still left-aligned +[align: left][{include:shakespeare.tpl}] + +// Boxed, and right-aligned +[align: right][{include:shakespeare.tpl}] diff --git a/tests/layouts/styles.tps b/tests/layouts/styles.typ index ef5d4e3b..767a0b73 100644 --- a/tests/layouts/styles.tps +++ b/tests/layouts/styles.typ @@ -1,8 +1,5 @@ _Multiline:_ -Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy -eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam -voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet -clita kasd gubergren, no sea takimata sanctus est. +{lorem:45} _Emoji:_ Hello World! 🌍 diff --git a/tests/render.py b/tests/render.py index e52054c1..4cb1e000 100644 --- a/tests/render.py +++ b/tests/render.py @@ -5,36 +5,73 @@ from PIL import Image, ImageDraw, ImageFont BASE = os.path.dirname(__file__) -CACHE_DIR = os.path.join(BASE, "../test-cache/"); +CACHE_DIR = os.path.join(BASE, "cache/"); def main(): assert len(sys.argv) == 2, "usage: python render.py <name>" name = sys.argv[1] - filename = os.path.join(CACHE_DIR, f"serialized/{name}.box") + filename = os.path.join(CACHE_DIR, f"serialized/{name}.lay") with open(filename, encoding="utf-8") as file: lines = [line[:-1] for line in file.readlines()] - fonts = {} - font_count = int(lines[0]) - for i in range(font_count): - parts = lines[1 + i].split(' ', 1) - index = int(parts[0]) - path = parts[1] - fonts[index] = os.path.join(BASE, "../fonts", path) + renderer = MultiboxRenderer(lines) + renderer.render() + image = renderer.export() - width, height = (float(s) for s in lines[font_count + 1].split()) + pathlib.Path(os.path.join(CACHE_DIR, "rendered")).mkdir(parents=True, exist_ok=True) + image.save(CACHE_DIR + "rendered/" + name + ".png") - renderer = Renderer(fonts, width, height) - for command in lines[font_count + 2:]: - renderer.execute(command) - pathlib.Path(os.path.join(CACHE_DIR, "rendered")).mkdir(parents=True, exist_ok=True) - renderer.export(name) +class MultiboxRenderer: + def __init__(self, lines): + self.combined = None + + self.fonts = {} + font_count = int(lines[0]) + for i in range(font_count): + parts = lines[i + 1].split(' ', 1) + index = int(parts[0]) + path = parts[1] + self.fonts[index] = os.path.join(BASE, "../fonts", path) + + self.content = lines[font_count + 1:] + + def render(self): + images = [] + + layout_count = int(self.content[0]) + start = 1 + + for _ in range(layout_count): + width, height = (float(s) for s in self.content[start].split()) + action_count = int(self.content[start + 1]) + start += 2 + + renderer = BoxRenderer(self.fonts, width, height) + for i in range(action_count): + command = self.content[start + i] + renderer.execute(command) + + images.append(renderer.export()) + start += action_count + + width = max(image.width for image in images) + 20 + height = sum(image.height for image in images) + 10 * (len(images) + 1) + + self.combined = Image.new('RGBA', (width, height)) + + cursor = 10 + for image in images: + self.combined.paste(image, (10, cursor)) + cursor += 10 + image.height + + def export(self): + return self.combined -class Renderer: +class BoxRenderer: def __init__(self, fonts, width, height): self.fonts = fonts self.size = (pix(width), pix(height)) @@ -102,8 +139,8 @@ class Renderer: else: raise Exception("invalid command") - def export(self, name): - self.img.save(CACHE_DIR + "rendered/" + name + ".png") + def export(self): + return self.img def pix(points): |
