typst 0.14.2.1 → 0.14.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 77a2b80d3ddc7e3b8a2fd44c365b3a7c9464383894bb3a61e869d87085baa8a2
4
- data.tar.gz: ce2e709afe2b9b76f73292ec13df74815ac0ff7dc7fc4636a58d73b7122ad391
3
+ metadata.gz: bdc56381647f2be411648ebbf5525576c5c6a259257cafd29de225dbd50da25c
4
+ data.tar.gz: 414023a808e3081a46e5e3ca64aa44920aedc41bbeca7c7004557e2a76b682f9
5
5
  SHA512:
6
- metadata.gz: b0e845ea82c232ed88b4dd6c159b814aad54199ff85829a7edb18a42346abf887e138345efca9e1ab1a2ca8b379b161bda3448162cd128f811b342815a7f0b85
7
- data.tar.gz: 73c99e328ea7aa5ba58d574b7b7770b86355f97787e2df6de4a4578913ae7d72082e11309309ae2ccd2f3882ceba26a482e60de8b25dc188a78e678ca41c99b7
6
+ metadata.gz: bf751aa8cfe5c0cb9f7433728f61ef1882af9fdea3b0aa031fa87e906a6be1880b1832a74597871911751fc912fb93f2f8946d4b8fd022c175828865d428938c
7
+ data.tar.gz: 62d507c32cdd32be9cf125350953a57971968e5aff1b43604d506e640901a327b940ab51c5becb6e4890ce1c8f656c4adb0a8bae19e1b3b217a6d82c8cddfb80
data/README.md CHANGED
@@ -16,56 +16,82 @@ require "typst"
16
16
 
17
17
  # Compile a typst file and write the output to a PDF file
18
18
  Typst("readme.typ").compile(:pdf).write("readme.pdf")
19
+ ```
19
20
 
20
- # Use a typst file `readme.typ`
21
+ ### Use a typst file `readme.typ`
22
+ ```ruby
21
23
  t = Typst("readme.typ")
24
+ ```
22
25
 
23
- # Use a typst string
26
+ ### Use a typst string
27
+ ```ruby
24
28
  t = Typst(body: %{hello world})
29
+ ```
25
30
 
26
- # Use a typst file in a zip file
31
+ ### Use a typst file in a zip file
32
+ ```ruby
27
33
  t = Typst(zip: "test/main.typ.zip")
34
+ ```
28
35
 
29
- # Compile to PDF
30
- f = t.compile(:pdf)
36
+ ### Compile to PDF
37
+ ```ruby
38
+ doc = t.compile(:pdf)
39
+ ```
31
40
 
32
- # Compile to SVG
33
- f = t.compile(:svg)
41
+ ### Compile to PDF selecting the typst supported PdfStandard
42
+ ```ruby
43
+ doc = t.compile(:pdf, pdf_standards: ["2.0"])
44
+ ```
34
45
 
35
- # Compile to PNG
36
- f = t.compile(:png)
46
+ ### Compile to SVG
47
+ ```ruby
48
+ doc = t.compile(:svg)
49
+ ```
37
50
 
38
- # Compile to SVGs enveloped in HTML
39
- # Depracation warning: this feature will go away once Typst HTML moves out of experimental
40
- f = t.compile(:html, title: "Typst+Ruby")
51
+ ### Compile to PNG
52
+ ```ruby
53
+ doc = t.compile(:png)
54
+ ```
41
55
 
42
- # Compile to HTML (using Typst expirmental HTML)
43
- f = t.compile(:html_experimental)
56
+ ### Compile to PNG and set PPI
57
+ ```ruby
58
+ doc = t.compile(:png, ppi: 72)
59
+ ```
44
60
 
45
- # Access PDF or HTML output as a string
46
- # Note: For PDF and PNG this will give data, for SVG and HTML this will give markup
47
- Typst("readme.typ").compile(:pdf).document
48
- # => "%PDF-1.7\n%\x80\x80\x80\x80\n\n4 0 obj\n<<\n /Type /Font\n /Subtype ..."
49
- Typst("readme.typ").compile(:html).document
50
- # => "\n<!DOCTYPE html>\n<html>\n<head>\n<title>main</title>\n</head>\n<body>\n<svg class=\"typst-doc\" ...
61
+ ### Compile to HTML (using Typst expirmental HTML)
62
+ ```ruby
63
+ doc = t.compile(:html_experimental)
64
+ ```
51
65
 
52
- # Or return content as an array of bytes
66
+ ### Or return content as an array of bytes
67
+ ```ruby
53
68
  pdf_bytes = Typst("readme.typ").compile(:pdf).bytes
54
69
  # => [37, 80, 68, 70, 45, 49, 46, 55, 10, 37, 128 ...]
70
+ ```
71
+
72
+ ### Write the output to a file
73
+ 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`
74
+ ```ruby
75
+ doc.write("filename.pdf")
76
+ ```
55
77
 
56
- # Write the output to a file
57
- # Note: for multi-page documents using formats other than PDF, pages write to multiple files, e.g. `readme_0.png`, `readme_1.png`
58
- f.write("filename.pdf")
78
+ ### Return PDF, SVG, PNG or HTML content as an array of pages
79
+ ```ruby
80
+ Typst("readme.typ").compile(:pdf).pages
81
+ # => ["%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 ...
59
82
 
60
- # Return SVG, HTML or PNG content as an array of pages
61
83
  Typst("readme.typ").compile(:svg).pages
62
- # => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ..."
63
- Typst("readme.typ").compile(:html).pages
64
- # => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ..."
84
+ # => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ...
85
+
65
86
  Typst("readme.typ").compile(:png).pages
66
87
  # => ["\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x04\xA7\x00\x00\x06\x94\b\ ...
67
88
 
68
- # Pass values into typst using sys_inputs
89
+ Typst("readme.typ").compile(:html_experimental).pages
90
+ # => ["<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" ...
91
+ ```
92
+
93
+ ### Pass values into typst using sys_inputs
94
+ ```ruby
69
95
  sys_inputs_example = %{
70
96
  #let persons = json(bytes(sys.inputs.persons))
71
97
 
@@ -76,15 +102,18 @@ sys_inputs_example = %{
76
102
  people = [{"name" => "John", "age" => 35}, {"name" => "Xoliswa", "age" => 45}]
77
103
  data = { "persons" => people.to_json }
78
104
  Typst(body: sys_inputs_example, sys_inputs: data).compile(:pdf).write("sys_inputs_example.pdf")
105
+ ```
79
106
 
80
- # Apply inputs to typst to product multiple PDFs
81
-
107
+ ### Apply inputs to typst to product multiple PDFs
108
+ ```ruby
82
109
  t = Typst(body: sys_inputs_example)
83
110
  people.each do |person|
84
111
  t.with_inputs({ "persons" => [person].to_json }).compile(:pdf).write("#{person['name']}.pdf")
85
112
  end
113
+ ```
86
114
 
87
- # A more complex example of compiling from string
115
+ ### A more complex example of compiling from string using other dependency typst template, svg and font resources all in memory
116
+ ```ruby
88
117
  main = %{
89
118
  #import "template.typ": *
90
119
 
@@ -106,27 +135,65 @@ icon = File.read("icon.svg")
106
135
  font_bytes = File.read("Example.ttf")
107
136
 
108
137
  Typst(body: main, dependencies: { "template.typ" => template, "icon.svg" => icon }, fonts: { "Example.ttf" => font_bytes }).compile(:pdf)
138
+ ```
109
139
 
110
- # From a zip with a named main typst file
140
+ ### From a zip with a named main typst file
141
+ ```ruby
111
142
  Typst(zip: "test/main.typ.zip", main_file: "hello.typ").compile(:pdf)
143
+ ```
144
+
145
+ ### Use a package from the [Typst Universe](https://typst.app/universe)
146
+ Your package_example.typ file...
147
+ ```typst
148
+ #import "@preview/wordometer:0.1.5": word-count, total-words
149
+ #show: word-count
150
+
151
+ In this document, there are #total-words words all up.
152
+
153
+ #word-count(total => [
154
+ The number of words in this block is #total.words
155
+ and there are #total.characters letters.
156
+ ])
157
+ ```
158
+ ...compiles just like anything else
159
+ ```ruby
160
+ Typst("package_example.typ").compile(:pdf).write("package_example.pdf")
161
+ ```
112
162
 
113
- Typst::Query.new("heading", "readme.typ").result
163
+ ### Query a typst document
164
+ ```ruby
165
+ Typst("readme.typ").query("heading").result
114
166
  # =>
115
167
  # [{"func" => "heading",
116
168
  # "level" => 1,
117
169
  # "depth" => 1,
118
170
  # ...
119
171
 
120
- Typst::Query.new("heading", "readme.typ", format: "json").result(raw: true)
172
+ Typst("readme.typ").query("heading", format: "json").result(raw: true)
121
173
  # => "[\n {\n \"func\": \"heading\",\n \"level\": 1,\n \"depth\": ..."
122
174
 
123
- Typst::Query.new("heading", "readme.typ", format: "yaml").result(raw: true)
175
+ Typst("readme.typ").query("heading", format: "yaml").result(raw: true)
124
176
  # => "- func: heading\n level: 1\n depth: 1\n offset: 0\n numbering: ..."
125
177
 
178
+ # Query results as JSON string
179
+ Typst("test/test.typ").query("heading").to_s
180
+ # => "[\n {\n \"func\": \"heading\",\n \"level\": 1,\n \"depth\": 1,\n \"offset\": 0,\n ...
181
+
182
+ # Query results as YAML string
183
+ Typst("test/test.typ").query("heading", format: "yaml").to_s
184
+ # => "- func: heading\n level: 1\n depth: 1\n offset: 0\n numbering: null\n supplement:\n ...
185
+ ```
186
+
187
+ ### clear the compilation cache
188
+ ```ruby
189
+ # Evict all entries whose age is larger than or equal to `max_age`
190
+ max_age = 10
191
+ Typst::clear_cache(max_age)
126
192
  ```
127
193
 
128
194
  ## Contributors & Acknowledgements
129
- typst-rb is based on [typst-py](https://github.com/messense/typst-py) by [messense](https://github.com/messense)
195
+ typst-rb is based on [typst-py](https://github.com/messense/typst-py) by [messense](https://github.com/messense)\
196
+ clear_cache was contributed by [NRicciVestmark](https://github.com/NRicciVestmark)
130
197
 
131
198
  ## License
132
199
 
data/README.typ CHANGED
@@ -1,6 +1,11 @@
1
-
1
+ #set document(title: [typst.rb README])
2
2
  #show link: underline
3
3
  #show link: set text(blue)
4
+ #show raw.where(block: true): block.with(
5
+ fill: luma(240),
6
+ inset: 10pt,
7
+ radius: 4pt,
8
+ )
4
9
 
5
10
  = typst-rb
6
11
 
@@ -19,56 +24,82 @@ require "typst"
19
24
 
20
25
  # Compile a typst file and write the output to a PDF file
21
26
  Typst("readme.typ").compile(:pdf).write("readme.pdf")
27
+ ```
22
28
 
23
- # Use a typst file `readme.typ`
29
+ === Use a typst file `readme.typ`
30
+ ```ruby
24
31
  t = Typst("readme.typ")
32
+ ```
25
33
 
26
- # Use a typst string
34
+ === Use a typst string
35
+ ```ruby
27
36
  t = Typst(body: %{hello world})
37
+ ```
28
38
 
29
- # Use a typst file in a zip file
39
+ === Use a typst file in a zip file
40
+ ```ruby
30
41
  t = Typst(zip: "test/main.typ.zip")
42
+ ```
31
43
 
32
- # Compile to PDF
33
- f = t.compile(:pdf)
44
+ === Compile to PDF
45
+ ```ruby
46
+ doc = t.compile(:pdf)
47
+ ```
34
48
 
35
- # Compile to SVG
36
- f = t.compile(:svg)
49
+ === Compile to PDF selecting the typst supported PdfStandard
50
+ ```ruby
51
+ doc = t.compile(:pdf, pdf_standards: ["2.0"])
52
+ ```
37
53
 
38
- # Compile to PNG
39
- f = t.compile(:png)
54
+ === Compile to SVG
55
+ ```ruby
56
+ doc = t.compile(:svg)
57
+ ```
40
58
 
41
- # Compile to SVGs enveloped in HTML
42
- # Depracation warning: this feature will go away once Typst HTML moves out of experimental
43
- f = t.compile(:html, title: "Typst+Ruby")
59
+ === Compile to PNG
60
+ ```ruby
61
+ doc = t.compile(:png)
62
+ ```
44
63
 
45
- # Compile to HTML (using Typst expirmental HTML)
46
- f = t.compile(:html_experimental)
64
+ === Compile to PNG and set PPI
65
+ ```ruby
66
+ doc = t.compile(:png, ppi: 72)
67
+ ```
47
68
 
48
- # Access PDF or HTML output as a string
49
- # Note: For PDF and PNG this will give data, for SVG and HTML this will give markup
50
- Typst("readme.typ").compile(:pdf).document
51
- # => "%PDF-1.7\n%\x80\x80\x80\x80\n\n4 0 obj\n<<\n /Type /Font\n /Subtype ..."
52
- Typst("readme.typ").compile(:html).document
53
- # => "\n<!DOCTYPE html>\n<html>\n<head>\n<title>main</title>\n</head>\n<body>\n<svg class=\"typst-doc\" ...
69
+ === Compile to HTML (using Typst expirmental HTML)
70
+ ```ruby
71
+ doc = t.compile(:html_experimental)
72
+ ```
54
73
 
55
- # Or return content as an array of bytes
74
+ === Or return content as an array of bytes
75
+ ```ruby
56
76
  pdf_bytes = Typst("readme.typ").compile(:pdf).bytes
57
77
  # => [37, 80, 68, 70, 45, 49, 46, 55, 10, 37, 128 ...]
78
+ ```
58
79
 
59
- # Write the output to a file
60
- # Note: for multi-page documents using formats other than PDF, pages write to multiple files, e.g. `readme_0.png`, `readme_1.png`
61
- f.write("filename.pdf")
80
+ === Write the output to a file
81
+ 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`
82
+ ```ruby
83
+ doc.write("filename.pdf")
84
+ ```
85
+
86
+ === Return PDF, SVG, PNG or HTML content as an array of pages
87
+ ```ruby
88
+ Typst("readme.typ").compile(:pdf).pages
89
+ # => ["%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 ...
62
90
 
63
- # Return SVG, HTML or PNG content as an array of pages
64
91
  Typst("readme.typ").compile(:svg).pages
65
- # => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ..."
66
- Typst("readme.typ").compile(:html).pages
67
- # => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ..."
92
+ # => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ...
93
+
68
94
  Typst("readme.typ").compile(:png).pages
69
95
  # => ["\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x04\xA7\x00\x00\x06\x94\b\ ...
70
96
 
71
- # Pass values into typst using sys_inputs
97
+ Typst("readme.typ").compile(:html_experimental).pages
98
+ # => ["<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" ...
99
+ ```
100
+
101
+ === Pass values into typst using sys_inputs
102
+ ```ruby
72
103
  sys_inputs_example = %{
73
104
  #let persons = json(bytes(sys.inputs.persons))
74
105
 
@@ -79,15 +110,18 @@ sys_inputs_example = %{
79
110
  people = [{"name" => "John", "age" => 35}, {"name" => "Xoliswa", "age" => 45}]
80
111
  data = { "persons" => people.to_json }
81
112
  Typst(body: sys_inputs_example, sys_inputs: data).compile(:pdf).write("sys_inputs_example.pdf")
113
+ ```
82
114
 
83
- # Apply inputs to typst to product multiple PDFs
84
-
115
+ === Apply inputs to typst to product multiple PDFs
116
+ ```ruby
85
117
  t = Typst(body: sys_inputs_example)
86
118
  people.each do |person|
87
119
  t.with_inputs({ "persons" => [person].to_json }).compile(:pdf).write("#{person['name']}.pdf")
88
120
  end
121
+ ```
89
122
 
90
- # A more complex example of compiling from string
123
+ === A more complex example of compiling from string using other dependency typst template, svg and font resources all in memory
124
+ ```ruby
91
125
  main = %{
92
126
  #import "template.typ": *
93
127
 
@@ -109,27 +143,65 @@ icon = File.read("icon.svg")
109
143
  font_bytes = File.read("Example.ttf")
110
144
 
111
145
  Typst(body: main, dependencies: { "template.typ" => template, "icon.svg" => icon }, fonts: { "Example.ttf" => font_bytes }).compile(:pdf)
146
+ ```
112
147
 
113
- # From a zip with a named main typst file
148
+ === From a zip with a named main typst file
149
+ ```ruby
114
150
  Typst(zip: "test/main.typ.zip", main_file: "hello.typ").compile(:pdf)
151
+ ```
152
+
153
+ === Use a package from the #link("https://typst.app/universe")[Typst Universe]
154
+ Your package_example.typ file...
155
+ ```typst
156
+ #import "@preview/wordometer:0.1.5": word-count, total-words
157
+ #show: word-count
158
+
159
+ In this document, there are #total-words words all up.
160
+
161
+ #word-count(total => [
162
+ The number of words in this block is #total.words
163
+ and there are #total.characters letters.
164
+ ])
165
+ ```
166
+ ...compiles just like anything else
167
+ ```ruby
168
+ Typst("package_example.typ").compile(:pdf).write("package_example.pdf")
169
+ ```
115
170
 
116
- Typst::Query.new("heading", "readme.typ").result
171
+ === Query a typst document
172
+ ```ruby
173
+ Typst("readme.typ").query("heading").result
117
174
  # =>
118
175
  # [{"func" => "heading",
119
176
  # "level" => 1,
120
177
  # "depth" => 1,
121
178
  # ...
122
179
 
123
- Typst::Query.new("heading", "readme.typ", format: "json").result(raw: true)
180
+ Typst("readme.typ").query("heading", format: "json").result(raw: true)
124
181
  # => "[\n {\n \"func\": \"heading\",\n \"level\": 1,\n \"depth\": ..."
125
182
 
126
- Typst::Query.new("heading", "readme.typ", format: "yaml").result(raw: true)
183
+ Typst("readme.typ").query("heading", format: "yaml").result(raw: true)
127
184
  # => "- func: heading\n level: 1\n depth: 1\n offset: 0\n numbering: ..."
128
185
 
186
+ # Query results as JSON string
187
+ Typst("test/test.typ").query("heading").to_s
188
+ # => "[\n {\n \"func\": \"heading\",\n \"level\": 1,\n \"depth\": 1,\n \"offset\": 0,\n ...
189
+
190
+ # Query results as YAML string
191
+ Typst("test/test.typ").query("heading", format: "yaml").to_s
192
+ # => "- func: heading\n level: 1\n depth: 1\n offset: 0\n numbering: null\n supplement:\n ...
193
+ ```
194
+
195
+ === clear the compilation cache
196
+ ```ruby
197
+ # Evict all entries whose age is larger than or equal to `max_age`
198
+ max_age = 10
199
+ Typst::clear_cache(max_age)
129
200
  ```
130
201
 
131
202
  == Contributors & Acknowledgements
132
- typst-rb is based on #link("https://github.com/messense/typst-py")[typst-py] by #link("https://github.com/messense")[messense]
203
+ typst-rb is based on #link("https://github.com/messense/typst-py")[typst-py] by #link("https://github.com/messense")[messense]\
204
+ clear_cache was contributed by #link("https://github.com/NRicciVestmark")[NRicciVestmark]
133
205
 
134
206
  == License
135
207
 
data/ext/typst/Cargo.toml CHANGED
@@ -49,4 +49,4 @@ walkdir = "2.4.0"
49
49
 
50
50
  # enable rb-sys feature to test against Ruby head. This is only needed if you
51
51
  # want to work with the unreleased, in-development, next version of Ruby
52
- rb-sys = { version = "0.9.123", default-features = false, features = ["stable-api-compiled-fallback"] }
52
+ rb-sys = { version = "0.9.124", default-features = false, features = ["stable-api-compiled-fallback"] }
@@ -6,7 +6,6 @@ use typst::diag::{Severity, SourceDiagnostic, StrResult, Warned};
6
6
  use typst::foundations::Datetime;
7
7
  use typst_html::HtmlDocument;
8
8
  use typst::layout::PagedDocument;
9
- //use typst::syntax::{FileId, Source, Span};
10
9
  use typst::syntax::{FileId, Lines, Span};
11
10
  use typst::{World, WorldExt};
12
11
 
@@ -14,6 +14,6 @@ impl<T: Display> Progress for SlientDownload<T> {
14
14
 
15
15
  /// Returns a new downloader.
16
16
  pub fn downloader() -> Downloader {
17
- let user_agent = concat!("typst-py/", env!("CARGO_PKG_VERSION"));
17
+ let user_agent = concat!("typst-rb/", env!("CARGO_PKG_VERSION"));
18
18
  Downloader::new(user_agent)
19
19
  }
data/ext/typst/src/lib.rs CHANGED
@@ -6,6 +6,7 @@ use std::collections::HashMap;
6
6
  use query::{query as typst_query, QueryCommand, SerializationFormat};
7
7
  use typst::foundations::{Dict, Value};
8
8
  use typst_library::Feature;
9
+ use typst_pdf::PdfStandard;
9
10
  use world::SystemWorld;
10
11
 
11
12
  mod compiler;
@@ -144,6 +145,7 @@ fn to_png(
144
145
  resource_path: PathBuf,
145
146
  ignore_system_fonts: bool,
146
147
  sys_inputs: HashMap<String, String>,
148
+ ppi: Option<f32>,
147
149
  ) -> Result<Vec<Vec<u8>>, Error> {
148
150
  let input = input.canonicalize()
149
151
  .map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?;
@@ -185,7 +187,7 @@ fn to_png(
185
187
  .map_err(|msg| magnus::Error::new(ruby.exception_arg_error(), msg.to_string()))?;
186
188
 
187
189
  let bytes = world
188
- .compile(Some("png"), None, &Vec::new())
190
+ .compile(Some("png"), ppi, &Vec::new())
189
191
  .map_err(|msg| magnus::Error::new(ruby.exception_arg_error(), msg.to_string()))?;
190
192
 
191
193
  Ok(bytes)
@@ -199,6 +201,7 @@ fn to_pdf(
199
201
  resource_path: PathBuf,
200
202
  ignore_system_fonts: bool,
201
203
  sys_inputs: HashMap<String, String>,
204
+ pdf_standards: Vec<String>,
202
205
  ) -> Result<Vec<Vec<u8>>, Error> {
203
206
  let input = input.canonicalize()
204
207
  .map_err(|err| magnus::Error::new(ruby.exception_arg_error(), err.to_string()))?;
@@ -239,8 +242,37 @@ fn to_pdf(
239
242
  .build()
240
243
  .map_err(|msg| magnus::Error::new(ruby.exception_arg_error(), msg.to_string()))?;
241
244
 
245
+ let pdf_standards_lookup: HashMap::<&str, PdfStandard> = HashMap::from([
246
+ ("1.4", PdfStandard::V_1_4),
247
+ ("1.5", PdfStandard::V_1_5),
248
+ ("1.6", PdfStandard::V_1_6),
249
+ ("1.7", PdfStandard::V_1_7),
250
+ ("2.0", PdfStandard::V_2_0),
251
+ ("a-1a", PdfStandard::A_1a),
252
+ ("a-1b", PdfStandard::A_1b),
253
+ ("a-2a", PdfStandard::A_2a),
254
+ ("a-2b", PdfStandard::A_2b),
255
+ ("a-2u", PdfStandard::A_2u),
256
+ ("a-3a", PdfStandard::A_3a),
257
+ ("a-3b", PdfStandard::A_3b),
258
+ ("a-3u", PdfStandard::A_3u),
259
+ ("a-4", PdfStandard::A_4),
260
+ ("a-4e", PdfStandard::A_4e),
261
+ ("a-4f", PdfStandard::A_4f),
262
+ ("ua-1", PdfStandard::Ua_1),
263
+ ]);
264
+
265
+ let mut pdf_standards_vec = Vec::<PdfStandard>::new();
266
+ for pdf_standard in pdf_standards.iter() {
267
+ let result = pdf_standards_lookup.get(pdf_standard.as_str());
268
+ match result {
269
+ Some(value) => pdf_standards_vec.push(*value),
270
+ _ => return Err(magnus::Error::new(ruby.exception_arg_error(), "Unknown PdfStandard")),
271
+ }
272
+ }
273
+
242
274
  let pdf_bytes = world
243
- .compile(Some("pdf"), None, &Vec::new())
275
+ .compile(Some("pdf"), None, &pdf_standards_vec)
244
276
  .map_err(|msg| magnus::Error::new(ruby.exception_arg_error(), msg.to_string()))?;
245
277
 
246
278
  Ok(pdf_bytes)
@@ -320,15 +352,20 @@ fn query(
320
352
  }
321
353
  }
322
354
 
355
+ fn clear_cache(_ruby: &Ruby, max_age: usize) {
356
+ comemo::evict(max_age);
357
+ }
358
+
323
359
  #[magnus::init]
324
360
  fn init(ruby: &Ruby) -> Result<(), Error> {
325
361
  env_logger::init();
326
362
 
327
363
  let module = ruby.define_module("Typst")?;
328
- module.define_singleton_method("_to_pdf", function!(to_pdf, 6))?;
364
+ module.define_singleton_method("_to_pdf", function!(to_pdf, 7))?;
329
365
  module.define_singleton_method("_to_svg", function!(to_svg, 6))?;
330
- module.define_singleton_method("_to_png", function!(to_png, 6))?;
366
+ module.define_singleton_method("_to_png", function!(to_png, 7))?;
331
367
  module.define_singleton_method("_to_html", function!(to_html, 6))?;
332
368
  module.define_singleton_method("_query", function!(query, 10))?;
369
+ module.define_singleton_method("_clear_cache", function!(clear_cache, 1))?;
333
370
  Ok(())
334
371
  }
@@ -8,7 +8,7 @@ use typst::layout::PagedDocument;
8
8
  use typst::syntax::Span;
9
9
  use typst::syntax::SyntaxMode;
10
10
  use typst::World;
11
- use typst_eval::eval_string; //{eval_string, EvalMode};
11
+ use typst_eval::eval_string;
12
12
 
13
13
  use crate::world::SystemWorld;
14
14
 
@@ -3,7 +3,6 @@ use std::path::{Path, PathBuf};
3
3
  use std::sync::{Mutex, OnceLock};
4
4
 
5
5
  use chrono::{DateTime, Datelike, Local};
6
- //use rustc_hash::FxHashMap;
7
6
  use ecow::eco_format;
8
7
  use typst::diag::{FileError, FileResult, StrResult};
9
8
  use typst::foundations::{Bytes, Datetime, Dict};
data/lib/base.rb CHANGED
@@ -34,74 +34,44 @@ module Typst
34
34
  options[:dependencies] ||= {}
35
35
  options[:fonts] ||= {}
36
36
  options[:sys_inputs] ||= {}
37
+ options[:resource_path] ||= File.dirname(__FILE__)
38
+ options[:ignore_system_fonts] ||= false
37
39
 
38
40
  self.options = options
39
41
  end
40
42
 
41
43
  def typst_args
42
- [options[:file], options[:root], options[:font_paths], File.dirname(__FILE__), false, options[:sys_inputs].map{ |k,v| [k.to_s,v.to_s] }.to_h]
44
+ [options[:file], options[:root], options[:font_paths], options[:resource_path], options[:ignore_system_fonts], options[:sys_inputs].map{ |k,v| [k.to_s,v.to_s] }.to_h]
43
45
  end
44
46
 
45
- def self.from_s(main_source, **options)
46
- dependencies = options[:dependencies] ||= {}
47
- fonts = options[:fonts] ||= {}
48
-
49
- Dir.mktmpdir do |tmp_dir|
50
- tmp_main_file = Pathname.new(tmp_dir).join("main.typ")
51
- File.write(tmp_main_file, main_source)
52
-
53
- dependencies.each do |dep_name, dep_source|
54
- tmp_dep_file = Pathname.new(tmp_dir).join(dep_name)
55
- File.write(tmp_dep_file, dep_source)
56
- end
57
-
58
- relative_font_path = Pathname.new(tmp_dir).join("fonts")
59
- fonts.each do |font_name, font_bytes|
60
- Pathname.new(relative_font_path).mkpath
61
- tmp_font_file = relative_font_path.join(font_name)
62
- File.write(tmp_font_file, font_bytes)
63
- end
47
+ def typst_pdf_args
48
+ options[:pdf_standards] ||= []
49
+ [*typst_args, options[:pdf_standards]]
50
+ end
64
51
 
65
- options[:file] = tmp_main_file
66
- options[:root] = tmp_dir
67
- options[:font_paths] = [relative_font_path]
52
+ def typst_png_args
53
+ [*typst_args, options[:ppi]]
54
+ end
68
55
 
69
- if options[:format]
70
- Typst::formats[options[:format]].new(**options)
56
+ def self.from_s(main_source, **options)
57
+ Typst::build_world_from_s(main_source, **options) do |opts|
58
+ from_options = options.merge(opts)
59
+ if from_options[:format]
60
+ Typst::formats[from_options[:format]].new(**from_options)
71
61
  else
72
- new(**options)
62
+ new(**from_options)
73
63
  end
74
64
  end
75
65
  end
76
66
 
77
- def self.from_zip(zip_file_path, main_file = nil, **options)
78
- options[:dependencies] ||= {}
79
- options[:fonts] ||= {}
80
-
81
- Zip::File.open(zip_file_path) do |zipfile|
82
- file_names = zipfile.dir.glob("*").collect{ |f| f.name }
83
- case
84
- when file_names.include?(main_file) then tmp_main_file = main_file
85
- when file_names.include?("main.typ") then tmp_main_file = "main.typ"
86
- when file_names.size == 1 then tmp_main_file = file_names.first
87
- else raise "no main file found"
88
- end
89
- main_source = zipfile.file.read(tmp_main_file)
90
- file_names.delete(tmp_main_file)
91
- file_names.delete("fonts/")
92
-
93
- file_names.each do |dep_name|
94
- options[:dependencies][dep_name] = zipfile.file.read(dep_name)
95
- end
96
-
97
- font_file_names = zipfile.dir.glob("fonts/*").collect{ |f| f.name }
98
- font_file_names.each do |font_name|
99
- options[:fonts][Pathname.new(font_name).basename.to_s] = zipfile.file.read(font_name)
67
+ def self.from_zip(zip_file_path, main_file = "main.typ", **options)
68
+ Typst::build_world_from_zip(zip_file_path, main_file, **options) do |opts|
69
+ from_options = options.merge(opts)
70
+ if from_options[:format]
71
+ Typst::formats[from_options[:format]].new(**from_options)
72
+ else
73
+ new(**from_options)
100
74
  end
101
-
102
- options[:main_file] = tmp_main_file
103
-
104
- from_s(main_source, **options)
105
75
  end
106
76
  end
107
77
 
@@ -138,32 +108,35 @@ module Typst
138
108
  if options.has_key?(:file)
139
109
  Typst::formats[format].new(**options).compiled
140
110
  elsif options.has_key?(:body)
141
- Typst::formats[format].from_s(options[:body], **options).compiled
111
+ Typst::build_world_from_s(self.options[:body], **options) do |opts|
112
+ Typst::formats[format].new(**options.merge(opts)).compiled
113
+ end
142
114
  elsif options.has_key?(:zip)
143
- Typst::formats[format].from_zip(options[:zip], options[:main_file], **options).compiled
115
+ main_file = options[:main_file]
116
+ Typst::build_world_from_zip(options[:zip], main_file, **options) do |opts|
117
+ Typst::formats[format].new(**options.merge(opts)).compiled
118
+ end
144
119
  else
145
120
  raise "No input given"
146
121
  end
147
122
  end
148
123
 
149
- def write(output)
150
- STDERR.puts "DEPRECATION WARNING: this method will go away in a future version"
151
- compiled.write(output)
152
- end
153
-
154
- def document
155
- STDERR.puts "DEPRECATION WARNING: this method will go away in a future version"
156
- compiled.document
157
- end
124
+ def query(selector, field: nil, one: false, format: "json")
125
+ query_options = { field: field, one: one, format: format }
158
126
 
159
- def bytes
160
- STDERR.puts "DEPRECATION WARNING: this method will go away in a future version"
161
- compiled.bytes
162
- end
163
-
164
- def pages
165
- STDERR.puts "DEPRECATION WARNING: this method will go away in a future version"
166
- compiled.pages
127
+ if self.options.has_key?(:file)
128
+ Typst::Query.new(selector, self.options[:file], **query_options.merge(self.options.slice(:root, :font_paths, :resource_path, :ignore_system_fonts, :sys_inputs)))
129
+ elsif self.options.has_key?(:body)
130
+ Typst::build_world_from_s(self.options[:body], **self.options) do |opts|
131
+ Typst::Query.new(selector, opts[:file], **query_options.merge(opts.slice(:root, :font_paths, :resource_path, :ignore_system_fonts, :sys_inputs)))
132
+ end
133
+ elsif self.options.has_key?(:zip)
134
+ Typst::build_world_from_zip(self.options[:zip], **self.options) do |opts|
135
+ Typst::Query.new(selector, opts[:file], **query_options.merge(opts.slice(:root, :font_paths, :resource_path, :ignore_system_fonts, :sys_inputs)))
136
+ end
137
+ else
138
+ raise "No input given"
139
+ end
167
140
  end
168
141
  end
169
142
  end
data/lib/document.rb CHANGED
@@ -6,15 +6,23 @@ module Typst
6
6
  @bytes = bytes
7
7
  end
8
8
 
9
- def write(out)
9
+ def write_some(filename)
10
10
  if pages.size == 1
11
- File.write(out, pages.first, mode: "wb")
11
+ write_one(filename)
12
12
  else
13
- pages.each_with_index do |page, i|
14
- fn = File.basename(out, ".*") + "_{{n}}" + File.extname(out) unless out.include?("{{n}}")
15
- fn = fn.gsub("{{n}}", (i+1).to_s)
16
- File.write(fn, page, mode: "wb")
17
- end
13
+ write_paged(filename)
14
+ end
15
+ end
16
+
17
+ def write_one(filename)
18
+ File.write(filename, pages.first, mode: "wb")
19
+ end
20
+
21
+ def write_paged(base_filename)
22
+ pages.each_with_index do |page, i|
23
+ paged_filename = File.basename(base_filename, ".*") + "_{{n}}" + File.extname(base_filename) unless base_filename.include?("{{n}}")
24
+ paged_filename = paged_filename.gsub("{{n}}", (i+1).to_s)
25
+ File.write(paged_filename, page, mode: "wb")
18
26
  end
19
27
  end
20
28
 
@@ -5,7 +5,9 @@ module Typst
5
5
  @compiled = HtmlExperimentalDocument.new(Typst::_to_html(*self.typst_args))
6
6
  end
7
7
  end
8
- class HtmlExperimentalDocument < Document; end
8
+ class HtmlExperimentalDocument < Document
9
+ alias_method :write, :write_one
10
+ end
9
11
 
10
12
  register_format(html_experimental: HtmlExperimental)
11
13
  end
data/lib/formats/pdf.rb CHANGED
@@ -2,10 +2,12 @@ module Typst
2
2
  class Pdf < Base
3
3
  def initialize(*options)
4
4
  super(*options)
5
- @compiled = PdfDocument.new(Typst::_to_pdf(*self.typst_args))
5
+ @compiled = PdfDocument.new(Typst::_to_pdf(*self.typst_pdf_args))
6
6
  end
7
7
  end
8
- class PdfDocument < Document; end
8
+ class PdfDocument < Document
9
+ alias_method :write, :write_one
10
+ end
9
11
 
10
12
  register_format(pdf: Pdf)
11
13
  end
data/lib/formats/png.rb CHANGED
@@ -2,10 +2,12 @@ module Typst
2
2
  class Png < Base
3
3
  def initialize(*options)
4
4
  super(*options)
5
- @compiled = PngDocument.new(Typst::_to_png(*self.typst_args))
5
+ @compiled = PngDocument.new(Typst::_to_png(*self.typst_png_args))
6
6
  end
7
7
  end
8
- class PngDocument < Document; end
8
+ class PngDocument < Document
9
+ alias_method :write, :write_some
10
+ end
9
11
 
10
12
  register_format(png: Png)
11
13
  end
data/lib/formats/svg.rb CHANGED
@@ -5,7 +5,9 @@ module Typst
5
5
  @compiled = SvgDocument.new(Typst::_to_svg(*self.typst_args))
6
6
  end
7
7
  end
8
- class SvgDocument < Document; end
8
+ class SvgDocument < Document
9
+ alias_method :write, :write_some
10
+ end
9
11
 
10
12
  register_format(svg: Svg)
11
13
  end
data/lib/query.rb CHANGED
@@ -2,10 +2,9 @@ module Typst
2
2
  class Query < Base
3
3
  attr_accessor :format
4
4
 
5
- def initialize(selector, input, field: nil, one: false, format: "json", root: ".", font_paths: [], sys_inputs: {})
6
- super(input, root: root, font_paths: font_paths, sys_inputs: sys_inputs)
5
+ def initialize(selector, input, field: nil, one: false, format: "json", root: ".", font_paths: [], resource_path: ".", ignore_system_fonts: false, sys_inputs: {})
7
6
  self.format = format
8
- @result = Typst::_query(selector, field, one, format, input, root, font_paths, File.dirname(__FILE__), false, sys_inputs)
7
+ @result = Typst::_query(selector, field, one, format, input, root, font_paths, resource_path, ignore_system_fonts, sys_inputs)
9
8
  end
10
9
 
11
10
  def result(raw: false)
@@ -15,5 +14,9 @@ module Typst
15
14
  else @result
16
15
  end
17
16
  end
17
+
18
+ def to_s
19
+ @result
20
+ end
18
21
  end
19
22
  end
data/lib/typst.rb CHANGED
@@ -8,23 +8,87 @@ module Typst
8
8
  def self.register_format(**format)
9
9
  @@formats.merge!(format)
10
10
  end
11
-
11
+
12
12
  def self.formats
13
13
  @@formats
14
14
  end
15
- end
16
15
 
16
+ def self.clear_cache(max_age = 0)
17
+ Typst::_clear_cache(max_age)
18
+ end
19
+
20
+ def self.build_world_from_s(main_source, **options, &blk)
21
+ dependencies = options[:dependencies] ||= {}
22
+ fonts = options[:fonts] ||= {}
23
+
24
+ Dir.mktmpdir do |tmp_dir|
25
+ tmp_main_file = Pathname.new(tmp_dir).join("main.typ")
26
+ File.write(tmp_main_file, main_source)
27
+
28
+ dependencies.each do |dep_name, dep_source|
29
+ tmp_dep_file = Pathname.new(tmp_dir).join(dep_name)
30
+ File.binwrite(tmp_dep_file, dep_source)
31
+ end
32
+
33
+ relative_font_path = Pathname.new(tmp_dir).join("fonts")
34
+ relative_font_path.mkpath
35
+ fonts.each do |font_name, font_bytes|
36
+ tmp_font_file = relative_font_path.join(font_name)
37
+ File.binwrite(tmp_font_file, font_bytes)
38
+ end
39
+
40
+ options[:file] = tmp_main_file
41
+ options[:root] = tmp_dir
42
+ options[:font_paths] = [relative_font_path]
43
+
44
+ blk.call(options)
45
+ end
46
+ end
47
+
48
+ def self.build_world_from_zip(zip_file_path, main_file = "main.typ", **options, &blk)
49
+ options[:dependencies] ||= {}
50
+ options[:fonts] ||= {}
51
+
52
+ Zip::File.open(zip_file_path) do |zipfile|
53
+ file_names = zipfile.dir.glob("*").collect{ |f| f.name }
54
+ case
55
+ when file_names.include?(main_file) then tmp_main_file = main_file
56
+ when file_names.include?("main.typ") then tmp_main_file = "main.typ"
57
+ when file_names.size == 1 then tmp_main_file = file_names.first
58
+ else raise "no main file found"
59
+ end
60
+ main_source = zipfile.file.read(tmp_main_file)
61
+ file_names.delete(tmp_main_file)
62
+ file_names.delete("fonts/")
63
+
64
+ file_names.each do |dep_name|
65
+ options[:dependencies][dep_name] = zipfile.file.read(dep_name)
66
+ end
67
+
68
+ font_file_names = zipfile.dir.glob("fonts/*").collect{ |f| f.name }
69
+ font_file_names.each do |font_name|
70
+ options[:fonts][Pathname.new(font_name).basename.to_s] = zipfile.file.read(font_name)
71
+ end
72
+
73
+ options[:main_file] = tmp_main_file
74
+
75
+ build_world_from_s(main_source, **options, &blk)
76
+ end
77
+ end
78
+ end
17
79
 
18
- require "cgi"
80
+ require "cgi/escape"
19
81
  require "pathname"
20
82
  require "tmpdir"
21
83
  require "zip/filesystem"
84
+ require "json"
85
+ require "yaml"
22
86
 
23
87
  begin
24
88
  # native precompiled gems package shared libraries in <gem_dir>/lib/typst/<ruby_version>
25
89
  RUBY_VERSION =~ /(\d+\.\d+)/
26
90
  require_relative "typst/#{Regexp.last_match(1)}/typst"
27
- rescue LoadError => e
91
+ rescue LoadError
28
92
  require_relative "typst/typst"
29
93
  end
30
94
 
@@ -34,5 +98,4 @@ require_relative "document"
34
98
  require_relative "formats/pdf"
35
99
  require_relative "formats/svg"
36
100
  require_relative "formats/png"
37
- require_relative "formats/html"
38
101
  require_relative "formats/html_experimental"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: typst
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.2.1
4
+ version: 0.14.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Flinn
@@ -18,7 +18,7 @@ dependencies:
18
18
  version: '0.9'
19
19
  - - ">="
20
20
  - !ruby/object:Gem::Version
21
- version: 0.9.123
21
+ version: 0.9.124
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -28,7 +28,7 @@ dependencies:
28
28
  version: '0.9'
29
29
  - - ">="
30
30
  - !ruby/object:Gem::Version
31
- version: 0.9.123
31
+ version: 0.9.124
32
32
  - !ruby/object:Gem::Dependency
33
33
  name: rubyzip
34
34
  requirement: !ruby/object:Gem::Requirement
@@ -71,6 +71,34 @@ dependencies:
71
71
  - - "~>"
72
72
  - !ruby/object:Gem::Version
73
73
  version: '3.6'
74
+ - !ruby/object:Gem::Dependency
75
+ name: os
76
+ requirement: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '1.1'
81
+ type: :development
82
+ prerelease: false
83
+ version_requirements: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '1.1'
88
+ - !ruby/object:Gem::Dependency
89
+ name: pngcheck
90
+ requirement: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '0.3'
95
+ type: :development
96
+ prerelease: false
97
+ version_requirements: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '0.3'
74
102
  email: flinn@actsasflinn.com
75
103
  executables: []
76
104
  extensions:
@@ -106,14 +134,12 @@ files:
106
134
  - lib/fonts/NewCM10-Regular.otf
107
135
  - lib/fonts/NewCMMath-Book.otf
108
136
  - lib/fonts/NewCMMath-Regular.otf
109
- - lib/formats/html.rb
110
137
  - lib/formats/html_experimental.rb
111
138
  - lib/formats/pdf.rb
112
139
  - lib/formats/png.rb
113
140
  - lib/formats/svg.rb
114
141
  - lib/query.rb
115
142
  - lib/typst.rb
116
- - lib/typst/typst.bundle
117
143
  homepage: https://github.com/actsasflinn/typst-rb
118
144
  licenses:
119
145
  - Apache-2.0
@@ -132,7 +158,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
132
158
  - !ruby/object:Gem::Version
133
159
  version: '0'
134
160
  requirements: []
135
- rubygems_version: 3.6.9
161
+ rubygems_version: 4.0.4
136
162
  specification_version: 4
137
163
  summary: Ruby binding to typst, a new markup-based typesetting system that is powerful
138
164
  and easy to learn.
data/lib/formats/html.rb DELETED
@@ -1,35 +0,0 @@
1
- module Typst
2
- class Html < Base
3
- def initialize(*options)
4
- super(*options)
5
- title = CGI::escapeHTML(@options[:title] || File.basename(@options[:file], ".*"))
6
- @compiled = HtmlDocument.new(Typst::_to_svg(*self.typst_args), title)
7
- end
8
- end
9
-
10
- class HtmlDocument < Document
11
- attr_accessor :title
12
-
13
- def initialize(bytes, title)
14
- super(bytes)
15
- self.title = title
16
- end
17
-
18
- def markup
19
- %{
20
- <!DOCTYPE html>
21
- <html>
22
- <head>
23
- <title>#{title}</title>
24
- </head>
25
- <body>
26
- #{pages.join("<br />")}
27
- </body>
28
- </html>
29
- }
30
- end
31
- alias_method :document, :markup
32
- end
33
-
34
- register_format(html: Html)
35
- end
Binary file