# typst-rb Ruby binding to [typst](https://github.com/typst/typst), a new markup-based typesetting system that is powerful and easy to learn. ## Installation ```bash gem install typst ``` ## Usage ```ruby require "typst" ``` ### Hello World ```ruby Typst(body: %{hello world}).compile(:pdf).write("hello_world.pdf") ``` ### Open a local typst file named `example.typ` ```ruby t = Typst("example.typ") ``` ### Use a typst string ```ruby t = Typst(body: %{hello world}) ``` ### Use a zipped typst file ```ruby t = Typst(zip: "test/main.typ.zip") ``` ### Open a remote typst file ```ruby require "open-uri" URI.open("https://github.com/actsasflinn/typst-rb/raw/refs/heads/main/README.typ") do |u| Typst(body: u.read).compile(:pdf).write("remote_readme.pdf") end ``` ### Open a remote zipped typst file ```ruby require "open-uri" URI.open("https://github.com/actsasflinn/typst-rb/raw/refs/heads/main/test/hello.typ.zip") do |u| Tempfile.create do |f| f.write(u.read) f.rewind Typst(zip: f).compile(:pdf).write("remote_zipped.pdf") end end ``` ### Compile to PDF ```ruby doc = t.compile(:pdf) ``` ### Compile to PDF selecting the typst supported PdfStandard ```ruby doc = t.compile(:pdf, pdf_standards: ["2.0"]) ``` ### Compile to SVG ```ruby doc = t.compile(:svg) ``` ### Compile to PNG ```ruby doc = t.compile(:png) ``` ### Compile to PNG and set PPI ```ruby doc = t.compile(:png, ppi: 72) ``` ### Compile to HTML (using Typst expirmental HTML) ```ruby doc = t.compile(:html_experimental) ``` ### Or return content as an array of bytes ```ruby pdf_bytes = Typst("readme.typ").compile(:pdf).bytes # => [37, 80, 68, 70, 45, 49, 46, 55, 10, 37, 128 ...] ``` ### Write the output to a file Note: for multi-page documents using formats other than PDF and HTML, pages write to multiple files, e.g. `readme_0.png`, `readme_1.png` ```ruby doc.write("filename.pdf") ``` ### Return PDF, SVG, PNG or HTML content as an array of pages ```ruby Typst("readme.typ").compile(:pdf).pages # => ["%PDF-1.7\n%\x80\x80\x80\x80\n\n1 0 obj\n<<\n /Type /Pages\n /Count 3\n /Kids [160 0 R 162 ... Typst("readme.typ").compile(:svg).pages # => [" ["\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x04\xA7\x00\x00\x06\x94\b\ ... Typst("readme.typ").compile(:html_experimental).pages # => ["\n\n \n \n "John", "age" => 35}, {"name" => "Xoliswa", "age" => 45}] data = { "persons" => people.to_json } Typst(body: sys_inputs_example, sys_inputs: data).compile(:pdf).write("sys_inputs_example.pdf") ``` ### Apply inputs to typst to product multiple PDFs ```ruby t = Typst(body: sys_inputs_example) people.each do |person| t.with_inputs({ "persons" => [person].to_json }).compile(:pdf).write("#{person['name']}.pdf") end ``` ### A more complex example of compiling from string using other dependency typst template, svg and font resources all in memory ```ruby main = %{ #import "template.typ": * #show: template.with() #lorem(50) #image("icon.svg") } template = %{ #let template(body) = { set text(12pt, font: "Example") body } } icon = File.read("icon.svg") font_bytes = File.read("Example.ttf") Typst(body: main, dependencies: { "template.typ" => template, "icon.svg" => icon }, fonts: { "Example.ttf" => font_bytes }).compile(:pdf) ``` ### Use a zip file with an alternatively named main typst file ```ruby Typst(zip: "test/main.typ.zip", main_file: "hello.typ").compile(:pdf) ``` ### Use a package from the [Typst Universe](https://typst.app/universe) Your package_example.typ file... ```typst #import "@preview/wordometer:0.1.5": word-count, total-words #show: word-count In this document, there are #total-words words all up. #word-count(total => [ The number of words in this block is #total.words and there are #total.characters letters. ]) ``` ...compiles just like anything else ```ruby Typst("package_example.typ").compile(:pdf).write("package_example.pdf") ``` ### Query a typst document ```ruby Typst("readme.typ").query("heading").result # => # [{"func" => "heading", # "level" => 1, # "depth" => 1, # ... Typst("readme.typ").query("heading", format: "json").result(raw: true) # => "[\n {\n \"func\": \"heading\",\n \"level\": 1,\n \"depth\": ..." Typst("readme.typ").query("heading", format: "yaml").result(raw: true) # => "- func: heading\n level: 1\n depth: 1\n offset: 0\n numbering: ..." # Query results as JSON string Typst("test/test.typ").query("heading").to_s # => "[\n {\n \"func\": \"heading\",\n \"level\": 1,\n \"depth\": 1,\n \"offset\": 0,\n ... # Query results as YAML string Typst("test/test.typ").query("heading", format: "yaml").to_s # => "- func: heading\n level: 1\n depth: 1\n offset: 0\n numbering: null\n supplement:\n ... ``` ### clear the compilation cache ```ruby # Evict all entries whose age is larger than or equal to `max_age` max_age = 10 Typst::clear_cache(max_age) ``` ## Contributors & Acknowledgements typst-rb is based on [typst-py](https://github.com/messense/typst-py) by [messense](https://github.com/messense)\ clear_cache was contributed by [NRicciVestmark](https://github.com/NRicciVestmark)\ CI improvements were contributed by [am1006](https://github.com/am1006)\ Defect resolutions by [adam12](https://github.com/adam12) and [walterdavis](https://github.com/walterdavis)\ Design suggestions by [alec-c4](https://github.com/alec-c4) ## License This work is released under the Apache-2.0 license. A copy of the license is provided in the [LICENSE](./LICENSE) file.