pdfcrate 0.1.1-x86_64-linux
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 +7 -0
- data/Gemfile +9 -0
- data/LICENSE +21 -0
- data/README.md +177 -0
- data/ext/pdfcrate/extconf.rb +3 -0
- data/lib/pdfcrate/3.3/pdfcrate.so +0 -0
- data/lib/pdfcrate/3.4/pdfcrate.so +0 -0
- data/lib/pdfcrate/version.rb +3 -0
- data/lib/pdfcrate.rb +86 -0
- data/pdfcrate.gemspec +43 -0
- metadata +87 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 1084b07c72613fef85f5fef3c8847137df9e1303c79a660a6b18a306685faff7
|
|
4
|
+
data.tar.gz: ed296301f9eaddc69ce6dfdd4a5c57bb761d5d0e75fa0d584a39dab6f01025dd
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 64b62b849f1f18425d44a76ad324ad7bff993a556f022ebfda05e72ca46111d99112f8bf27e78c4bf76185fb12cf96a5c130b137c8cb47eb5298c762ed88a1cb
|
|
7
|
+
data.tar.gz: 3b94fe5eb559320dc072801c7c393ed0e0d22477027a81bd2523042dd094121680a47e10959d5011fa260f3c1805b29e505f88d89b28f2a354902df317deba54
|
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 pdfcrate contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# pdfcrate
|
|
2
|
+
|
|
3
|
+
> **Warning**: This project is under active development. The API is unstable and subject to breaking changes. **Do not use in production environments.**
|
|
4
|
+
|
|
5
|
+
A Rust library for creating and manipulating PDF documents with a focus on ease of use and comprehensive text layout support.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Layout-based document creation** - Cursor-based layout with automatic text flow, margins, and bounding boxes
|
|
10
|
+
- **Rich text formatting** - Bold, italic, colors, alignment (left/center/right/justify)
|
|
11
|
+
- **Font support** - 14 standard PDF fonts + TrueType/OpenType embedding with text shaping
|
|
12
|
+
- **Font fallback** - Automatic fallback for mixed-language text (CJK, emoji, etc.)
|
|
13
|
+
- **Tables** - Full-featured tables with borders, cell styles, column spans, and overflow handling
|
|
14
|
+
- **Images** - PNG and JPEG embedding with fit/fill modes
|
|
15
|
+
- **SVG rendering** - Embed SVG graphics directly
|
|
16
|
+
- **Links and outlines** - Hyperlinks, internal links, and document bookmarks
|
|
17
|
+
- **Forms** - Interactive form fields (text, checkbox, radio, dropdown)
|
|
18
|
+
- **WASM support** - Works in WebAssembly environments (tested with Cloudflare Workers)
|
|
19
|
+
- **Python bindings** - Use pdfcrate from Python via PyO3
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
Add to your `Cargo.toml`:
|
|
24
|
+
|
|
25
|
+
```toml
|
|
26
|
+
[dependencies]
|
|
27
|
+
pdfcrate = "0.1"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
```rust
|
|
33
|
+
use pdfcrate::prelude::*;
|
|
34
|
+
|
|
35
|
+
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
36
|
+
Document::generate("hello.pdf", |doc| {
|
|
37
|
+
doc.title("Hello PDF").author("pdfcrate");
|
|
38
|
+
|
|
39
|
+
doc.font("Helvetica-Bold").size(24.0);
|
|
40
|
+
doc.text("Hello, World!");
|
|
41
|
+
|
|
42
|
+
doc.move_down(20.0);
|
|
43
|
+
|
|
44
|
+
doc.font("Helvetica").size(12.0);
|
|
45
|
+
doc.text_wrap("This is a simple PDF document created with pdfcrate. \
|
|
46
|
+
Text automatically wraps within the page margins.");
|
|
47
|
+
|
|
48
|
+
Ok(())
|
|
49
|
+
})?;
|
|
50
|
+
|
|
51
|
+
Ok(())
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Examples
|
|
56
|
+
|
|
57
|
+
### Custom Fonts
|
|
58
|
+
|
|
59
|
+
```rust
|
|
60
|
+
use pdfcrate::prelude::*;
|
|
61
|
+
|
|
62
|
+
Document::generate("custom_font.pdf", |doc| {
|
|
63
|
+
// Embed a TrueType font
|
|
64
|
+
let font = doc.embed_font_file("fonts/MyFont.ttf")?;
|
|
65
|
+
|
|
66
|
+
doc.font(&font).size(16.0);
|
|
67
|
+
doc.text("Text with custom font!");
|
|
68
|
+
|
|
69
|
+
Ok(())
|
|
70
|
+
})?;
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Font Fallback for CJK
|
|
74
|
+
|
|
75
|
+
```rust
|
|
76
|
+
use pdfcrate::prelude::*;
|
|
77
|
+
|
|
78
|
+
Document::generate("multilingual.pdf", |doc| {
|
|
79
|
+
let cjk_font = doc.embed_font_file("fonts/NotoSansCJK.ttf")?;
|
|
80
|
+
|
|
81
|
+
// Configure fallback fonts
|
|
82
|
+
doc.fallback_fonts(vec![cjk_font]);
|
|
83
|
+
|
|
84
|
+
doc.font("Helvetica").size(14.0);
|
|
85
|
+
doc.text_wrap("English text mixed with 中文 and 日本語");
|
|
86
|
+
|
|
87
|
+
Ok(())
|
|
88
|
+
})?;
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Tables
|
|
92
|
+
|
|
93
|
+
```rust
|
|
94
|
+
use pdfcrate::prelude::*;
|
|
95
|
+
|
|
96
|
+
Document::generate("table.pdf", |doc| {
|
|
97
|
+
let table = Table::new(&[100.0, 150.0, 100.0])
|
|
98
|
+
.header(&["Name", "Description", "Price"])
|
|
99
|
+
.row(&["Item 1", "First item", "$10.00"])
|
|
100
|
+
.row(&["Item 2", "Second item", "$20.00"])
|
|
101
|
+
.borders(BorderStyle::all(0.5, Color::BLACK));
|
|
102
|
+
|
|
103
|
+
doc.table(&table);
|
|
104
|
+
|
|
105
|
+
Ok(())
|
|
106
|
+
})?;
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Images
|
|
110
|
+
|
|
111
|
+
```rust
|
|
112
|
+
use pdfcrate::prelude::*;
|
|
113
|
+
|
|
114
|
+
Document::generate("with_image.pdf", |doc| {
|
|
115
|
+
// Embed and draw image
|
|
116
|
+
doc.image_fit("photo.png", [0.0, 0.0], 200.0, 150.0)?;
|
|
117
|
+
|
|
118
|
+
Ok(())
|
|
119
|
+
})?;
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Python
|
|
123
|
+
|
|
124
|
+
pdfcrate provides Python bindings via [PyO3](https://pyo3.rs/) and [maturin](https://www.maturin.rs/).
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# Install in development mode
|
|
128
|
+
uv run maturin develop --features python
|
|
129
|
+
|
|
130
|
+
# Run the showcase
|
|
131
|
+
uv run python examples/showcase.py
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
from pdfcrate import Document, Margin, Color, TextFragment
|
|
136
|
+
|
|
137
|
+
doc = Document(margin=Margin(36, 36, 36, 36))
|
|
138
|
+
doc.title("Hello from Python")
|
|
139
|
+
|
|
140
|
+
doc.font("Helvetica", 24)
|
|
141
|
+
doc.text("Hello, World!")
|
|
142
|
+
|
|
143
|
+
doc.move_down(20)
|
|
144
|
+
doc.font("Helvetica", 12)
|
|
145
|
+
doc.text("Created with pdfcrate Python bindings.")
|
|
146
|
+
|
|
147
|
+
doc.save("hello.pdf")
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Feature Flags
|
|
151
|
+
|
|
152
|
+
All features are pure Rust and WASM-compatible.
|
|
153
|
+
|
|
154
|
+
| Feature | Default | Description |
|
|
155
|
+
|---------|---------|-------------|
|
|
156
|
+
| `std` | Yes | Standard library support (file I/O) |
|
|
157
|
+
| `png` | Yes | PNG image support (JPEG is always supported) |
|
|
158
|
+
| `fonts` | Yes | TrueType/OpenType font embedding |
|
|
159
|
+
| `text-shaping` | Yes | Complex text shaping via rustybuzz |
|
|
160
|
+
| `svg` | Yes | SVG rendering support |
|
|
161
|
+
| `barcode` | Yes | QR code and barcode generation |
|
|
162
|
+
| `python` | No | Python bindings (PyO3) |
|
|
163
|
+
|
|
164
|
+
To use minimal features:
|
|
165
|
+
|
|
166
|
+
```toml
|
|
167
|
+
[dependencies]
|
|
168
|
+
pdfcrate = { version = "0.1", default-features = false }
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Minimum Supported Rust Version (MSRV)
|
|
172
|
+
|
|
173
|
+
Rust 1.87 or later.
|
|
174
|
+
|
|
175
|
+
## License
|
|
176
|
+
|
|
177
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
Binary file
|
|
Binary file
|
data/lib/pdfcrate.rb
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "pdfcrate/version"
|
|
4
|
+
require "pdfcrate/pdfcrate"
|
|
5
|
+
|
|
6
|
+
module Pdfcrate
|
|
7
|
+
# Prawn::View-compatible mixin: delegates method calls to self.document
|
|
8
|
+
module View
|
|
9
|
+
def document
|
|
10
|
+
@document
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def method_missing(name, *args, **kwargs, &block)
|
|
16
|
+
return super unless document.respond_to?(name)
|
|
17
|
+
|
|
18
|
+
if kwargs.empty?
|
|
19
|
+
document.send(name, *args, &block)
|
|
20
|
+
else
|
|
21
|
+
document.send(name, *args, **kwargs, &block)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def respond_to_missing?(name, include_private = false)
|
|
26
|
+
document.respond_to?(name) || super
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Extend GridProxy with bounding_box method that delegates to Document
|
|
31
|
+
class GridProxy
|
|
32
|
+
attr_accessor :_document
|
|
33
|
+
|
|
34
|
+
def bounding_box(&block)
|
|
35
|
+
raise "GridProxy must be associated with a Document" unless _document
|
|
36
|
+
|
|
37
|
+
if is_span
|
|
38
|
+
_document.grid_span_bounding_box(row, col, end_row, end_col, &block)
|
|
39
|
+
else
|
|
40
|
+
_document.grid_cell_bounding_box(row, col, &block)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class Document
|
|
46
|
+
# Override grid to attach document reference
|
|
47
|
+
alias_method :_grid_raw, :grid
|
|
48
|
+
|
|
49
|
+
def grid(*args)
|
|
50
|
+
proxy = _grid_raw(*args)
|
|
51
|
+
proxy._document = self
|
|
52
|
+
proxy
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Grid cell bounding box - uses grid layout coordinates
|
|
56
|
+
def grid_cell_bounding_box(row, col, &block)
|
|
57
|
+
_grid_cell_bb(row, col, &block)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def grid_span_bounding_box(r1, c1, r2, c2, &block)
|
|
61
|
+
_grid_span_bb(r1, c1, r2, c2, &block)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# font_families.update() compatibility
|
|
65
|
+
# Returns a FontFamiliesUpdater that intercepts .update()
|
|
66
|
+
class FontFamiliesUpdater
|
|
67
|
+
def initialize(doc)
|
|
68
|
+
@doc = doc
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def update(families)
|
|
72
|
+
families.each do |name, styles|
|
|
73
|
+
kwargs = {}
|
|
74
|
+
styles.each do |style, path|
|
|
75
|
+
kwargs[style] = path
|
|
76
|
+
end
|
|
77
|
+
@doc.register_font_family(name, **kwargs)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def font_families
|
|
83
|
+
FontFamiliesUpdater.new(self)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
data/pdfcrate.gemspec
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
require_relative 'lib/pdfcrate/version'
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |spec|
|
|
4
|
+
spec.name = "pdfcrate"
|
|
5
|
+
spec.version = Pdfcrate::VERSION
|
|
6
|
+
spec.authors = ["ratazzi"]
|
|
7
|
+
spec.email = ["ratazzi@gmail.com"]
|
|
8
|
+
|
|
9
|
+
spec.summary = "Ruby bindings for pdfcrate PDF generation library"
|
|
10
|
+
spec.description = "A Ruby gem providing Prawn-compatible API bindings to the pdfcrate Rust PDF generation library using Magnus."
|
|
11
|
+
spec.homepage = "https://github.com/ratazzi/pdfcrate"
|
|
12
|
+
spec.license = "MIT"
|
|
13
|
+
spec.required_ruby_version = ">= 3.1.0"
|
|
14
|
+
|
|
15
|
+
spec.files = Dir[
|
|
16
|
+
'lib/**/*.rb',
|
|
17
|
+
'ext/**/*.{rb,rs,toml}',
|
|
18
|
+
'ext/**/src/**/*.rs',
|
|
19
|
+
'README.md',
|
|
20
|
+
'LICENSE',
|
|
21
|
+
'Gemfile',
|
|
22
|
+
'*.gemspec'
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
spec.files += Dir['lib/**/*.{bundle,so,dll}'] if spec.respond_to?(:platform) && spec.platform != "ruby"
|
|
26
|
+
|
|
27
|
+
spec.require_paths = ["lib"]
|
|
28
|
+
|
|
29
|
+
spec.extensions = ["ext/pdfcrate/extconf.rb"] if !spec.respond_to?(:platform) || spec.platform == "ruby"
|
|
30
|
+
|
|
31
|
+
if !spec.respond_to?(:platform) || spec.platform == "ruby"
|
|
32
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
|
33
|
+
spec.add_development_dependency "rake-compiler", "~> 1.2"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
spec.add_dependency "rb_sys", "~> 0.9.124"
|
|
37
|
+
|
|
38
|
+
spec.metadata = {
|
|
39
|
+
"source_code_uri" => "https://github.com/ratazzi/pdfcrate",
|
|
40
|
+
"rubygems_mfa_required" => "true",
|
|
41
|
+
"cargo_crate_name" => "pdfcrate-ruby"
|
|
42
|
+
}
|
|
43
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: pdfcrate
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.1
|
|
5
|
+
platform: x86_64-linux
|
|
6
|
+
authors:
|
|
7
|
+
- ratazzi
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-03-04 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rake
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '13.0'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '13.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake-compiler
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '1.2'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '1.2'
|
|
41
|
+
description: A Ruby gem providing Prawn-compatible API bindings to the pdfcrate Rust
|
|
42
|
+
PDF generation library using Magnus.
|
|
43
|
+
email:
|
|
44
|
+
- ratazzi@gmail.com
|
|
45
|
+
executables: []
|
|
46
|
+
extensions: []
|
|
47
|
+
extra_rdoc_files: []
|
|
48
|
+
files:
|
|
49
|
+
- Gemfile
|
|
50
|
+
- LICENSE
|
|
51
|
+
- README.md
|
|
52
|
+
- ext/pdfcrate/extconf.rb
|
|
53
|
+
- lib/pdfcrate.rb
|
|
54
|
+
- lib/pdfcrate/3.3/pdfcrate.so
|
|
55
|
+
- lib/pdfcrate/3.4/pdfcrate.so
|
|
56
|
+
- lib/pdfcrate/version.rb
|
|
57
|
+
- pdfcrate.gemspec
|
|
58
|
+
homepage: https://github.com/ratazzi/pdfcrate
|
|
59
|
+
licenses:
|
|
60
|
+
- MIT
|
|
61
|
+
metadata:
|
|
62
|
+
source_code_uri: https://github.com/ratazzi/pdfcrate
|
|
63
|
+
rubygems_mfa_required: 'true'
|
|
64
|
+
cargo_crate_name: pdfcrate-ruby
|
|
65
|
+
post_install_message:
|
|
66
|
+
rdoc_options: []
|
|
67
|
+
require_paths:
|
|
68
|
+
- lib
|
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
70
|
+
requirements:
|
|
71
|
+
- - ">="
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
version: '3.3'
|
|
74
|
+
- - "<"
|
|
75
|
+
- !ruby/object:Gem::Version
|
|
76
|
+
version: 3.5.dev
|
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0'
|
|
82
|
+
requirements: []
|
|
83
|
+
rubygems_version: 3.5.23
|
|
84
|
+
signing_key:
|
|
85
|
+
specification_version: 4
|
|
86
|
+
summary: Ruby bindings for pdfcrate PDF generation library
|
|
87
|
+
test_files: []
|