page_print 0.1.8 → 0.1.10
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 +4 -4
- data/README.md +122 -201
- data/docs/configuration.md +204 -0
- data/docs/production.md +148 -0
- data/ext/page_print/page_print.c +213 -105
- data/lib/page_print/rails_resource_fetcher.rb +4 -1
- data/lib/page_print/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ca32ba67da6a5c3cfe5c66b3eac1242ffc1068ccce7838820d4550fffbe9d73d
|
|
4
|
+
data.tar.gz: 90ad2b4d3612d123f562ebd43098ed110c2ccb608d058409c496ce76e455e25d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 68dc83310a8f0d25281d22f1d66c771c2d87a855c4802690df8ecf2e3bc74127602d405ccc4746ddf4d1495f94aa079aa3cc4668f023ca68bccec3360096b46a
|
|
7
|
+
data.tar.gz: 3fa636884d4c816a4aea7c3b34262a3f21c1d09e59c44cc8b0fde3c2bb145cdfbc26a5a9468c636d92057cfa8736906c671933e0b97f1b2ba1bafd183f21d3d5
|
data/README.md
CHANGED
|
@@ -1,284 +1,205 @@
|
|
|
1
1
|
# PagePrint
|
|
2
2
|
|
|
3
|
+
Fast, in-process HTML-to-PDF rendering for Ruby, powered by [PlutoBook](https://github.com/plutoprint/plutobook).
|
|
4
|
+
|
|
3
5
|
> [!IMPORTANT]
|
|
4
|
-
> PagePrint is
|
|
6
|
+
> PagePrint is still pre-1.0 and is not yet recommended as a drop-in production dependency without application-specific testing. Native packaging and platform compatibility are still being validated. See the [production guide](docs/production.md) before deploying it.
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
PagePrint turns an HTML string into PDF bytes—or writes it directly to a file—through a small native C extension. It is designed for server-generated documents such as invoices, reports, labels, and statements where the HTML is known in advance and does not depend on JavaScript.
|
|
7
9
|
|
|
8
|
-
It exists as a faster, simpler alternative to PDFKit and other `wkhtmltopdf`-based gems. There is no external renderer process to shell out to, and the public Ruby API is intentionally small.
|
|
9
10
|
|
|
10
|
-
##
|
|
11
|
+
## Why PagePrint?
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
PDFKit and Wicked PDF render documents by launching the `wkhtmltopdf` executable. PagePrint instead embeds a purpose-built paged-media renderer in the Ruby process.
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
gem "page_print"
|
|
16
|
-
```
|
|
15
|
+
That gives PagePrint a few useful properties:
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
- **No renderer subprocess:** no executable discovery, shelling out, or process startup per render.
|
|
18
|
+
- **A small Ruby API:** pass HTML in and receive PDF bytes, or write directly to a path.
|
|
19
|
+
- **Print-oriented CSS:** PlutoBook supports paged-media features such as `@page`, page counters, and running headers and footers.
|
|
20
|
+
- **Controlled resource loading:** PagePrint does not fetch unresolved HTTP URLs. Your application decides which stylesheets, images, and fonts may be loaded.
|
|
21
|
+
- **Rails asset integration:** Propshaft and `public/assets` resources work without HTTP requests back into the application.
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
gem install page_print
|
|
22
|
-
```
|
|
23
|
+
### How does it compare with PDFKit and Wicked PDF?
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
PDFKit and Wicked PDF are Ruby integrations for `wkhtmltopdf`; their rendering behavior and operational requirements come from that executable.
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
| | PagePrint / PlutoBook | PDFKit or Wicked PDF / `wkhtmltopdf` |
|
|
28
|
+
| --- | --- | --- |
|
|
29
|
+
| Runtime model | Native library in the Ruby process | External `wkhtmltopdf` executable |
|
|
30
|
+
| Rendering engine | Purpose-built for static documents and CSS paged media | Legacy Qt WebKit browser engine |
|
|
31
|
+
| JavaScript | Not supported | Supported by legacy Qt WebKit |
|
|
32
|
+
| Network access | Denied unless your fetcher supplies the resource | Built in |
|
|
33
|
+
| CSS compatibility | Print-focused and partial; no CSS Grid | Limited by the old WebKit engine |
|
|
34
|
+
| Operational footprint | Native gem and bundled libraries on supported platforms | `wkhtmltopdf` binary plus Qt/WebKit dependencies |
|
|
35
|
+
| Upstream status | PagePrint currently packages PlutoBook 0.19.0 | `wkhtmltopdf` was archived in 2023 |
|
|
27
36
|
|
|
28
|
-
PagePrint is
|
|
37
|
+
PagePrint is a strong fit when you control the templates, value predictable print layout, and do not need JavaScript. Stay with a `wkhtmltopdf`-based gem if your existing templates depend on its JavaScript or WebKit-specific rendering behavior. When migrating, compare representative output carefully because changing engines can alter pagination, fonts, and layout.
|
|
29
38
|
|
|
30
|
-
|
|
39
|
+
The `wkhtmltopdf` project was [archived in 2023](https://github.com/wkhtmltopdf/wkhtmltopdf) and its own [status document](https://github.com/wkhtmltopdf/wkhtmltopdf/blob/master/docs/status.md) describes its Qt 4 / WebKit stack as unsupported and outdated. PlutoBook is purpose-built for static paged output, but has a narrower feature set; review its [feature matrix](https://github.com/plutoprint/plutobook/blob/main/FEATURES.md) before migrating a complex template.
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
Add the gem to your `Gemfile`:
|
|
31
44
|
|
|
32
45
|
```ruby
|
|
33
|
-
|
|
34
|
-
def pdf
|
|
35
|
-
html = render_to_string(template: "prints/pdf", formats: [:html], layout: "pdf")
|
|
36
|
-
pdf = PagePrint.html_to_pdf_string(
|
|
37
|
-
html,
|
|
38
|
-
page_size: :a4,
|
|
39
|
-
margins: :normal,
|
|
40
|
-
media: :print,
|
|
41
|
-
metadata: { title: "Print PDF", author: "PagePrint" }
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
send_data pdf, filename: "print.pdf", type: "application/pdf", disposition: "inline"
|
|
45
|
-
end
|
|
46
|
-
end
|
|
46
|
+
gem "page_print"
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
Then run:
|
|
50
50
|
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
<%= image_tag "logo.png" %>
|
|
51
|
+
```sh
|
|
52
|
+
bundle install
|
|
54
53
|
```
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
You can still override `base_url` explicitly:
|
|
55
|
+
PagePrint requires Ruby 3.2 or newer. Native gems with vendored PlutoBook libraries are published for:
|
|
59
56
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
```
|
|
57
|
+
- `x86_64-linux`
|
|
58
|
+
- `arm64-darwin` (Apple Silicon)
|
|
63
59
|
|
|
64
|
-
|
|
60
|
+
Other platforms build from source and require PlutoBook development headers and libraries. See [Installing on other platforms](docs/production.md#installing-on-other-platforms).
|
|
65
61
|
|
|
66
|
-
|
|
67
|
-
# config/initializers/page_print.rb
|
|
68
|
-
PagePrint.configure do |config|
|
|
69
|
-
config.resource_fetcher = MyResourceFetcher.new
|
|
70
|
-
end
|
|
71
|
-
```
|
|
62
|
+
## Quick start
|
|
72
63
|
|
|
73
|
-
|
|
64
|
+
Require PagePrint and render an HTML string:
|
|
74
65
|
|
|
75
66
|
```ruby
|
|
76
67
|
require "page_print"
|
|
77
|
-
require "tmpdir"
|
|
78
68
|
|
|
79
69
|
html = <<~HTML
|
|
70
|
+
<!doctype html>
|
|
80
71
|
<html>
|
|
72
|
+
<head>
|
|
73
|
+
<meta charset="utf-8">
|
|
74
|
+
<style>
|
|
75
|
+
@page {
|
|
76
|
+
size: A4;
|
|
77
|
+
|
|
78
|
+
@bottom-center {
|
|
79
|
+
content: counter(page) " / " counter(pages);
|
|
80
|
+
color: #666;
|
|
81
|
+
font-size: 10pt;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
body { font-family: sans-serif; }
|
|
86
|
+
</style>
|
|
87
|
+
</head>
|
|
81
88
|
<body>
|
|
82
|
-
<h1>
|
|
83
|
-
<p>
|
|
89
|
+
<h1>Invoice #1042</h1>
|
|
90
|
+
<p>Thank you for your business.</p>
|
|
84
91
|
</body>
|
|
85
92
|
</html>
|
|
86
93
|
HTML
|
|
87
94
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
PagePrint.html_to_pdf(html, output_path, base_url: "https://example.com")
|
|
95
|
+
pdf = PagePrint.render(html, page_size: :a4, margins: :normal)
|
|
91
96
|
```
|
|
92
97
|
|
|
93
|
-
|
|
98
|
+
For large documents, write directly to a file instead of retaining the PDF in a Ruby string:
|
|
94
99
|
|
|
95
100
|
```ruby
|
|
96
|
-
|
|
101
|
+
PagePrint.render_to_file(html, "invoice.pdf", page_size: :a4, margins: :normal)
|
|
97
102
|
```
|
|
98
103
|
|
|
99
|
-
|
|
104
|
+
`render_to_file` returns `true`; `render` returns an `ASCII-8BIT` Ruby string containing the PDF.
|
|
100
105
|
|
|
101
|
-
|
|
102
|
-
pdf = PagePrint.html_to_pdf_string(
|
|
103
|
-
html,
|
|
104
|
-
page_size: { width: 100, height: 150, unit: :mm },
|
|
105
|
-
margins: { top: 5, right: 6, bottom: 7, left: 8, unit: :mm }
|
|
106
|
-
)
|
|
107
|
-
```
|
|
106
|
+
## Rails
|
|
108
107
|
|
|
109
|
-
|
|
108
|
+
PagePrint integrates automatically with Rails applications that use Propshaft. Render a template to HTML, pass it to PagePrint, then send the resulting bytes:
|
|
110
109
|
|
|
111
110
|
```ruby
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
class InvoicesController < ApplicationController
|
|
112
|
+
def show
|
|
113
|
+
html = render_to_string(template: "invoices/show", formats: [:html], layout: "pdf")
|
|
114
|
+
pdf = PagePrint.render(html, page_size: :a4, margins: :normal, metadata: { title: "Invoice ##{params[:id]}", author: "Example Ltd" })
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
send_data pdf, filename: "invoice-#{params[:id]}.pdf", type: "application/pdf", disposition: "inline"
|
|
117
117
|
end
|
|
118
118
|
end
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
Supported keyword options:
|
|
124
|
-
|
|
125
|
-
- `base_url:` string used to resolve relative URLs in the HTML
|
|
126
|
-
- `page_size:` one of `:a3`, `:a4`, `:a5`, `:b4`, `:b5`, `:letter`, `:legal`, `:ledger`, or `{ width:, height:, unit: }`
|
|
127
|
-
- `margins:` one of `:none`, `:normal`, `:narrow`, `:moderate`, `:wide`, or `{ top:, right:, bottom:, left:, unit: }`
|
|
128
|
-
- `media:` one of `:print`, `:screen`
|
|
129
|
-
- `resource_fetcher:` callable that receives a URL and returns `nil` or `{ content:, mime_type:, text_encoding: nil }`
|
|
130
|
-
- `metadata:` hash with `:title`, `:author`, `:subject`, `:keywords`, `:creation_date`, or `:modification_date`
|
|
131
|
-
|
|
132
|
-
Unresolved URLs are not fetched over the network. Provide assets through `resource_fetcher`, or return `nil` to skip a URL.
|
|
133
|
-
|
|
134
|
-
`metadata[:creation_date]` and `metadata[:modification_date]` should be ISO-8601 strings, for example `2026-05-10T12:00:00Z`.
|
|
135
|
-
|
|
136
|
-
Custom dimensions and margins require `unit:`. Supported units are `:pt`, `:pc`, `:in`, `:cm`, `:mm`, and `:px`.
|
|
137
|
-
|
|
138
|
-
## Benchmarking
|
|
139
|
-
|
|
140
|
-
```sh
|
|
141
|
-
RUNS=30 WARMUPS=3 bundle exec ruby benchmark/pdf_renderers.rb
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
Measured on 2026-05-30 with Ruby 3.4.7 on Apple Silicon:
|
|
145
|
-
|
|
146
|
-
| Renderer | Avg wall | P95 wall | Avg CPU | Avg peak RSS | Avg PDF |
|
|
147
|
-
| --- | ---: | ---: | ---: | ---: | ---: |
|
|
148
|
-
| `page_print` | 78.2ms | 89.6ms | 93.4ms | 42.1MB | 33.0KB |
|
|
149
|
-
| PDFKit | 782.2ms | 2127.1ms | 824.8ms | 59.4MB | 27.9KB |
|
|
150
|
-
|
|
151
|
-
For options and CSV output, see `benchmark/README.md`.
|
|
152
|
-
|
|
153
|
-
## Requirements
|
|
154
|
-
|
|
155
|
-
- Ruby 3.2+
|
|
156
|
-
- Native gems are published for `x86_64-linux` and `arm64-darwin`.
|
|
157
|
-
- Native gems vendor PlutoBook but compile the small Ruby extension during install so it links against your local Ruby.
|
|
158
|
-
- Source builds on unsupported platforms require PlutoBook development headers and library files.
|
|
159
|
-
|
|
160
|
-
Supported platforms:
|
|
161
|
-
|
|
162
|
-
| Platform | Install Type |
|
|
163
|
-
| --- | --- |
|
|
164
|
-
| `x86_64-linux` | Vendored PlutoBook, local Ruby extension build |
|
|
165
|
-
| `arm64-darwin` | Vendored PlutoBook, local Ruby extension build |
|
|
166
|
-
| Other platforms | Source build |
|
|
167
|
-
|
|
168
|
-
Source build requirements on macOS with Homebrew:
|
|
169
|
-
|
|
170
|
-
```sh
|
|
171
|
-
brew install plutobook pkg-config
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
If `pkg-config` cannot find `plutobook`, install the gem with explicit include and library paths:
|
|
175
|
-
|
|
176
|
-
```sh
|
|
177
|
-
gem install page_print -- --with-plutobook-include=/path/to/include --with-plutobook-lib=/path/to/lib
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
Native gems bundle PlutoBook and required non-system shared libraries. Optional PlutoBook features for curl, TurboJPEG, and WebP are disabled in native gems to keep the bundled dependency set smaller.
|
|
181
|
-
|
|
182
|
-
## Notes
|
|
183
|
-
|
|
184
|
-
- The extension supports writing to a file path with `html_to_pdf` or returning PDF bytes with `html_to_pdf_string`.
|
|
185
|
-
- JavaScript execution is intentionally unsupported.
|
|
186
|
-
- Native gems disable PlutoBook's optional curl, TurboJPEG, and WebP features.
|
|
121
|
+
Normal asset helpers can be used in the PDF template:
|
|
187
122
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
```sh
|
|
193
|
-
bundle install
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
Compile the native extension into `lib/page_print`:
|
|
197
|
-
|
|
198
|
-
```sh
|
|
199
|
-
bundle exec rake compile
|
|
123
|
+
```erb
|
|
124
|
+
<%= stylesheet_link_tag "pdf" %>
|
|
125
|
+
<%= image_tag "logo.png", alt: "Example Ltd" %>
|
|
200
126
|
```
|
|
201
127
|
|
|
202
|
-
|
|
128
|
+
During a controller action, PagePrint uses `request.base_url` to resolve relative URLs. Its Rails resource fetcher reads `/assets/...` from Propshaft or `public/assets`; it does not make an HTTP request back to Rails.
|
|
203
129
|
|
|
204
|
-
|
|
205
|
-
bundle exec irb -Ilib
|
|
206
|
-
```
|
|
130
|
+
## Assets and network access
|
|
207
131
|
|
|
208
|
-
|
|
132
|
+
PagePrint intentionally does not download unresolved resources. Supply a `resource_fetcher` when non-Rails HTML needs external styles, images, or fonts:
|
|
209
133
|
|
|
210
134
|
```ruby
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
bundle exec ruby -Ilib -e 'require "tmpdir"; require "page_print"; output_path = File.join(Dir.tmpdir, "page_print-output.pdf"); p PagePrint.html_to_pdf("<html><body><h1>Hello</h1></body></html>", output_path, page_size: :letter, margins: :narrow, media: :screen)'
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
Or use the development console, which compiles the native extension first and then starts IRB with `PagePrint` loaded:
|
|
226
|
-
|
|
227
|
-
```sh
|
|
228
|
-
bin/console
|
|
135
|
+
assets = {
|
|
136
|
+
"asset:pdf.css" => {
|
|
137
|
+
content: File.binread("app/assets/stylesheets/pdf.css"),
|
|
138
|
+
mime_type: "text/css"
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
pdf = PagePrint.render(
|
|
143
|
+
"<link rel=\"stylesheet\" href=\"asset:pdf.css\"><h1>Report</h1>",
|
|
144
|
+
resource_fetcher: ->(url) { assets[url] }
|
|
145
|
+
)
|
|
229
146
|
```
|
|
230
147
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
Run the test suite only:
|
|
148
|
+
The fetcher receives each resolved URL and returns `{ content:, mime_type: }` or `nil`. Returning `nil` skips the resource. This makes resource access explicit, but it does not make untrusted HTML safe; see [Security](docs/production.md#security).
|
|
234
149
|
|
|
235
|
-
|
|
236
|
-
bundle exec rake test
|
|
237
|
-
```
|
|
150
|
+
## Configuration
|
|
238
151
|
|
|
239
|
-
|
|
152
|
+
The common rendering options are:
|
|
240
153
|
|
|
241
|
-
```
|
|
242
|
-
|
|
154
|
+
```ruby
|
|
155
|
+
PagePrint.render(
|
|
156
|
+
html,
|
|
157
|
+
base_url: "https://example.test",
|
|
158
|
+
page_size: :letter,
|
|
159
|
+
margins: :narrow,
|
|
160
|
+
media: :print,
|
|
161
|
+
metadata: { title: "Quarterly report" },
|
|
162
|
+
resource_fetcher: fetcher
|
|
163
|
+
)
|
|
243
164
|
```
|
|
244
165
|
|
|
245
|
-
|
|
166
|
+
Defaults are A4 paper, normal margins, and print media. See the [configuration reference](docs/configuration.md) for every preset, custom dimensions, metadata fields, global configuration, and resource fetcher behavior.
|
|
246
167
|
|
|
247
|
-
|
|
168
|
+
## Performance
|
|
248
169
|
|
|
249
|
-
|
|
250
|
-
gem build page_print.gemspec
|
|
251
|
-
gem install ./page_print-*.gem
|
|
252
|
-
```
|
|
170
|
+
The repository includes a reproducible benchmark against PDFKit using the same static HTML input. On May 30, 2026, the recorded run used Ruby 3.4.7 on an Apple Silicon development machine:
|
|
253
171
|
|
|
254
|
-
|
|
172
|
+
| Renderer | Average wall time | P95 wall time | Average peak RSS |
|
|
173
|
+
| --- | ---: | ---: | ---: |
|
|
174
|
+
| PagePrint | 78.2 ms | 89.6 ms | 42.1 MB |
|
|
175
|
+
| PDFKit | 782.2 ms | 2,127.1 ms | 59.4 MB |
|
|
255
176
|
|
|
256
|
-
|
|
177
|
+
These numbers are illustrative, not a capacity guarantee. Rendering cost varies significantly with fonts, images, document length, and host configuration. Run the benchmark—or your own production templates—on the deployment target before sizing infrastructure.
|
|
257
178
|
|
|
258
179
|
```sh
|
|
259
|
-
|
|
180
|
+
RUNS=30 WARMUPS=3 bundle exec ruby benchmark/pdf_renderers.rb
|
|
260
181
|
```
|
|
261
182
|
|
|
262
|
-
|
|
183
|
+
See [benchmark/README.md](benchmark/README.md) for methodology and CSV output.
|
|
263
184
|
|
|
264
|
-
|
|
185
|
+
## Documentation
|
|
265
186
|
|
|
266
|
-
|
|
187
|
+
- [Configuration and API reference](docs/configuration.md)
|
|
188
|
+
- [Production guide](docs/production.md)
|
|
189
|
+
- [Benchmark methodology](benchmark/README.md)
|
|
190
|
+
- [PlutoBook feature matrix](https://github.com/plutoprint/plutobook/blob/main/FEATURES.md)
|
|
267
191
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
```sh
|
|
271
|
-
bundle exec rake package:linux
|
|
272
|
-
```
|
|
192
|
+
## Development
|
|
273
193
|
|
|
274
|
-
|
|
194
|
+
Install dependencies, compile the extension, and run the test suite:
|
|
275
195
|
|
|
276
196
|
```sh
|
|
277
|
-
bundle
|
|
197
|
+
bundle install
|
|
198
|
+
bundle exec rake
|
|
278
199
|
```
|
|
279
200
|
|
|
280
|
-
|
|
201
|
+
Use `bin/console` for an IRB session with the extension compiled and PagePrint loaded.
|
|
281
202
|
|
|
282
|
-
|
|
203
|
+
## License
|
|
283
204
|
|
|
284
|
-
|
|
205
|
+
PagePrint is available under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Configuration and API reference
|
|
2
|
+
|
|
3
|
+
PagePrint exposes two rendering methods and a small set of keyword options.
|
|
4
|
+
|
|
5
|
+
## Rendering methods
|
|
6
|
+
|
|
7
|
+
### `PagePrint.render(html, **options)`
|
|
8
|
+
|
|
9
|
+
Renders a non-empty HTML string and returns the PDF as an `ASCII-8BIT` Ruby string.
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
pdf = PagePrint.render("<h1>Report</h1>")
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### `PagePrint.render_to_file(html, path, **options)`
|
|
16
|
+
|
|
17
|
+
Renders a non-empty HTML string directly to `path` and returns `true`. The destination directory must already exist and be writable.
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
PagePrint.render_to_file("<h1>Report</h1>", "/tmp/report.pdf")
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Writing directly to a file avoids keeping the finished PDF in a Ruby string and is preferable for large documents or background jobs.
|
|
24
|
+
|
|
25
|
+
## Options
|
|
26
|
+
|
|
27
|
+
Both rendering methods accept the same options.
|
|
28
|
+
|
|
29
|
+
| Option | Default | Accepted values |
|
|
30
|
+
| --- | --- | --- |
|
|
31
|
+
| `base_url:` | `nil` outside Rails | A string or `nil` |
|
|
32
|
+
| `page_size:` | `:a4` | A page preset or custom dimensions |
|
|
33
|
+
| `margins:` | `:normal` | A margin preset or custom dimensions |
|
|
34
|
+
| `media:` | `:print` | `:print` or `:screen` |
|
|
35
|
+
| `resource_fetcher:` | Configured global fetcher or `nil` | Any callable, `nil`, or `false` |
|
|
36
|
+
| `metadata:` | `nil` | A metadata hash or `nil` |
|
|
37
|
+
|
|
38
|
+
Unknown options raise `ArgumentError`; values of the wrong type raise `TypeError`.
|
|
39
|
+
|
|
40
|
+
### Base URL
|
|
41
|
+
|
|
42
|
+
`base_url` resolves relative URLs found in the HTML:
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
html = '<link rel="stylesheet" href="/assets/report.css"><h1>Report</h1>'
|
|
46
|
+
PagePrint.render(html, base_url: "https://example.test", resource_fetcher: fetcher)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The fetcher receives `https://example.test/assets/report.css`. A base URL resolves the URL; it does not enable network access.
|
|
50
|
+
|
|
51
|
+
Set an application-wide default when rendering outside Rails:
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
PagePrint.configure do |config|
|
|
55
|
+
config.base_url = "https://example.test"
|
|
56
|
+
end
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
An explicit `base_url:` takes precedence over the configured value.
|
|
60
|
+
|
|
61
|
+
### Page size
|
|
62
|
+
|
|
63
|
+
Available presets:
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
:a3 :a4 :a5 :b4 :b5 :letter :legal :ledger
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Custom dimensions require a width, height, and unit:
|
|
70
|
+
|
|
71
|
+
```ruby
|
|
72
|
+
PagePrint.render(
|
|
73
|
+
html,
|
|
74
|
+
page_size: { width: 100, height: 150, unit: :mm }
|
|
75
|
+
)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Width and height must be greater than zero.
|
|
79
|
+
|
|
80
|
+
### Margins
|
|
81
|
+
|
|
82
|
+
Available presets:
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
:none :normal :narrow :moderate :wide
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Custom margins require all four sides and a unit:
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
PagePrint.render(
|
|
92
|
+
html,
|
|
93
|
+
margins: { top: 5, right: 6, bottom: 7, left: 8, unit: :mm }
|
|
94
|
+
)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Margin values must be zero or greater.
|
|
98
|
+
|
|
99
|
+
Page sizes and margins support these units:
|
|
100
|
+
|
|
101
|
+
```text
|
|
102
|
+
:pt :pc :in :cm :mm :px
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Media type
|
|
106
|
+
|
|
107
|
+
Use `:print` to apply print styles and `:screen` to apply screen styles:
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
PagePrint.render(html, media: :screen)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### PDF metadata
|
|
114
|
+
|
|
115
|
+
Metadata keys and values must be symbols and strings, respectively. A value may also be `nil`.
|
|
116
|
+
|
|
117
|
+
```ruby
|
|
118
|
+
PagePrint.render(
|
|
119
|
+
html,
|
|
120
|
+
metadata: {
|
|
121
|
+
title: "Quarterly report",
|
|
122
|
+
author: "Example Ltd",
|
|
123
|
+
subject: "Q2 results",
|
|
124
|
+
keywords: "finance,quarterly",
|
|
125
|
+
creation_date: "2026-05-10T12:00:00Z",
|
|
126
|
+
modification_date: nil
|
|
127
|
+
}
|
|
128
|
+
)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Supported keys are:
|
|
132
|
+
|
|
133
|
+
- `:title`
|
|
134
|
+
- `:author`
|
|
135
|
+
- `:subject`
|
|
136
|
+
- `:keywords`
|
|
137
|
+
- `:creation_date`
|
|
138
|
+
- `:modification_date`
|
|
139
|
+
|
|
140
|
+
Use ISO 8601 strings for creation and modification dates.
|
|
141
|
+
|
|
142
|
+
## Resource fetchers
|
|
143
|
+
|
|
144
|
+
A resource fetcher is a callable that receives a resolved URL. It must return either `nil` or a hash containing binary `content` and its `mime_type`. `text_encoding` is optional.
|
|
145
|
+
|
|
146
|
+
```ruby
|
|
147
|
+
fetcher = lambda do |url|
|
|
148
|
+
case url
|
|
149
|
+
when "asset:report.css"
|
|
150
|
+
{
|
|
151
|
+
content: File.binread("app/assets/stylesheets/report.css"),
|
|
152
|
+
mime_type: "text/css",
|
|
153
|
+
text_encoding: "utf-8"
|
|
154
|
+
}
|
|
155
|
+
when "asset:logo.png"
|
|
156
|
+
{
|
|
157
|
+
content: File.binread("app/assets/images/logo.png"),
|
|
158
|
+
mime_type: "image/png"
|
|
159
|
+
}
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
PagePrint.render(html, resource_fetcher: fetcher)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Returning `nil` skips the URL. PagePrint does not fall back to an HTTP request. Exceptions raised by the fetcher are propagated to the caller.
|
|
167
|
+
|
|
168
|
+
Configure a default fetcher for every render:
|
|
169
|
+
|
|
170
|
+
```ruby
|
|
171
|
+
PagePrint.configure do |config|
|
|
172
|
+
config.resource_fetcher = MyResourceFetcher.new
|
|
173
|
+
end
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Pass `resource_fetcher: false` or `nil` to disable a configured fetcher for one render.
|
|
177
|
+
|
|
178
|
+
Keep fetchers narrowly scoped. Prefer an allowlist or a fixed asset map over fetching arbitrary URLs supplied by HTML.
|
|
179
|
+
|
|
180
|
+
## Rails behavior
|
|
181
|
+
|
|
182
|
+
When Rails is loaded, PagePrint installs two defaults:
|
|
183
|
+
|
|
184
|
+
1. During controller actions, the current `request.base_url` becomes the default base URL for that request.
|
|
185
|
+
2. `PagePrint::RailsResourceFetcher` resolves URLs under `/assets/` from `public/assets` or Propshaft.
|
|
186
|
+
|
|
187
|
+
An explicit `base_url:` or `resource_fetcher:` still takes precedence. To replace the Rails fetcher globally:
|
|
188
|
+
|
|
189
|
+
```ruby
|
|
190
|
+
# config/initializers/page_print.rb
|
|
191
|
+
PagePrint.configure do |config|
|
|
192
|
+
config.resource_fetcher = MyResourceFetcher.new
|
|
193
|
+
end
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
The built-in Rails fetcher only handles `/assets/...` URLs. Other paths are skipped.
|
|
197
|
+
|
|
198
|
+
## CSS and rendering support
|
|
199
|
+
|
|
200
|
+
PagePrint delegates HTML and CSS support to PlutoBook. It supports print-oriented features including `@page`, page counters, and running headers and footers, but it is not a full web browser. JavaScript and CSS Grid are not supported.
|
|
201
|
+
|
|
202
|
+
Consult the upstream [PlutoBook feature matrix](https://github.com/plutoprint/plutobook/blob/main/FEATURES.md) when designing or migrating templates. Test representative documents after every renderer or font change because pagination can change even when the HTML does not.
|
|
203
|
+
|
|
204
|
+
[Back to the README](../README.md)
|