@qrcommunication/gigapdf-lib 0.1.0 → 0.8.0

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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,219 @@ All notable changes to `@qrcommunication/gigapdf-lib` are documented here.
4
4
  The format follows [Keep a Changelog](https://keepachangelog.com/) and the
5
5
  project adheres to [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [0.8.0] - 2026-06-16
8
+
9
+ ### Added
10
+
11
+ - **AES PDF encryption** (`doc.saveEncrypted`). The Standard Security Handler can
12
+ now *write* **AES-128 (V4/R4)** and **AES-256 (V5/R6)** in addition to RC4, with
13
+ **separate user and owner passwords**:
14
+ - `saveEncrypted(password, fileId, { algorithm: "aes256" | "aes128" | "rc4",
15
+ ownerPassword, permissions, keySeed })` — defaults to **AES-256**.
16
+ - AES-256 needs a **secret 32-byte file key** (the engine has no RNG): the SDK
17
+ generates it with Web Crypto, or you pass `keySeed`. The decryption side
18
+ already read AESV2/AESV3; `openEncrypted` now also accepts the **owner**
19
+ password for R6 (Algorithm 2.A).
20
+ - ABI `gp_save_encrypted` gains `owner`, `key` and an `algorithm` selector.
21
+
22
+ ### Changed
23
+
24
+ - **Breaking (SDK):** `saveEncrypted(password, fileId, permissions?)` →
25
+ `saveEncrypted(password, fileId, opts?)`. Pass `{ permissions }` (and
26
+ `{ algorithm: "rc4" }` to keep the previous RC4 behaviour).
27
+
28
+ ## [0.7.0] - 2026-06-15
29
+
30
+ ### Added
31
+
32
+ - **Complete viewer zoom controls** (`@qrcommunication/gigapdf-lib/viewer`):
33
+ `fitWidth()`, `fitPage()`, `actualSize()`, `setZoom()` / `setZoomPercent()` and a
34
+ `zoom` getter; a toolbar **preset drop-down** (Fit width · Fit page · 50–400 %)
35
+ with a live `%` readout; `Ctrl`/`⌘` + mouse-wheel zoom; and a `0` keyboard
36
+ shortcut. A chosen **fit mode is sticky** — it re-applies when the viewport
37
+ resizes (via `ResizeObserver`) and when paging to a page of a different
38
+ orientation.
39
+ - **Editor rulers & margins** (`@qrcommunication/gigapdf-lib/editor`): every page
40
+ shows graduated **millimetre rulers** (top + left) and four **margin guides**
41
+ dragged **live** from handles in the ruler bands — or set via the palette's
42
+ `T R B L` mm fields and the `setMargins()` / `getMargins()` / `showRulers()`
43
+ API. Guides are drawn in page-point coordinates (on a second SVG layer) and kept
44
+ a constant on-screen size at any zoom.
45
+
46
+ ## [0.6.0] - 2026-06-15
47
+
48
+ ### Added
49
+
50
+ - **Full page control for HTML→PDF** via `htmlRenderWith(html, fonts, options)`:
51
+ - **named paper sizes** — `pageSize: "A4" | "a3-landscape" | "letter" | …`
52
+ (ISO A0–A6, ISO B4/B5, US Letter/Legal/Tabloid/Executive; `-landscape`
53
+ suffix swaps the axes). `giga.pageSize(name)` resolves one to `{ w, h }`
54
+ points.
55
+ - **per-side margins** — `margin: number | { top, right, bottom, left }`.
56
+ - **running header & footer** — `header` / `footer` are full HTML+CSS
57
+ snippets painted in the page margins on every page, with `{{page}}` /
58
+ `{{pages}}` substitution and configurable `startPageNumber`,
59
+ `headerOffset` / `footerOffset`.
60
+ - **`htmlNeededFontsWith(html, header, footer)`** — phase-1 font discovery that
61
+ also scans the header/footer HTML so their Google fonts are fetched.
62
+ - New ABI exports: `gp_html_render_opts`, `gp_html_needed_fonts_ex`,
63
+ `gp_page_size`.
64
+
65
+ ### Images & SVG
66
+
67
+ - **SVG → native PDF vector** via `doc.addSvg(page, src, x, y, w, h)` (ABI
68
+ `gp_add_svg`): shapes (`rect`/`circle`/`ellipse`/`line`/`polyline`/`polygon`),
69
+ `<path>` (full `d` grammar with **exact `A` arc→Bézier conversion**), `<g>`
70
+ groups, `transform`, `viewBox`, `fill`/`stroke`/`stroke-width`/`opacity`, and
71
+ **gradients** (`<linearGradient>`/`<radialGradient>` → native PDF axial/radial
72
+ shadings, with stops, `gradientUnits`, `gradientTransform` and `href`
73
+ inheritance) — crisp at any zoom, not rasterized. In the HTML renderer, inline
74
+ `<svg>` and `data:image/svg+xml` `<img>` sources render as native vector.
75
+ - **PNG transparency in the rasterizer**: `renderPage`/thumbnails now honour an
76
+ image's `/SMask` (soft mask) as per-pixel alpha instead of treating it as
77
+ opaque, so transparent PNGs composite correctly in every conversion (not just
78
+ HTML→PDF).
79
+ - **Colour emoji** (COLR v0 + CPAL): when a text run uses a colour font (e.g.
80
+ `font-family: "Noto Color Emoji"`), emoji are drawn as native vector colour
81
+ layers in the HTML renderer — crisp, and rasterized for free. **Apple `sbix`
82
+ bitmap emoji** are placed as PNG glyph bitmaps. Non-colour characters in the
83
+ run still render as text. (COLRv1 gradient glyphs and `CBDT/CBLC` strikes are
84
+ not yet drawn.)
85
+
86
+ ### Viewer
87
+
88
+ - **`@qrcommunication/gigapdf-lib/viewer`** — a new zero-dependency browser
89
+ document viewer (`GigaPdfViewer`) built on the engine (no pdf.js): opens PDF,
90
+ Office (docx/xlsx/pptx, legacy, ODF) and HTML (auto-detected, converted
91
+ in-engine), renders pages with `renderPage`, **detects per-page orientation**
92
+ and adapts, with navigation, zoom, a thumbnail rail, keyboard control and a
93
+ **fullscreen presentation mode**.
94
+ - **`@qrcommunication/gigapdf-lib/editor`** — an interactive **editing canvas**
95
+ (`GigaPdfEditor`) extending the viewer: an SVG overlay per page with tools
96
+ (text, rectangle, ellipse, line, freehand ink, image, highlight, redaction),
97
+ select·move·delete, and `applyEdits()` that **bakes edits into the real PDF**
98
+ through the engine (then re-renders); `save()` returns the result.
99
+
100
+ ### CSS
101
+
102
+ - HTML→PDF renderer gained `min-width` / `max-width`, `height` / `min-height`,
103
+ `box-sizing`, `text-indent` (first-line indent), `visibility: hidden`,
104
+ `opacity` (backgrounds/borders/text rules), and `text-decoration: line-through`
105
+ / `overline`. See [`docs/HTML-CSS.md`](../docs/HTML-CSS.md).
106
+
107
+ ## [0.5.0] - 2026-06-15
108
+
109
+ ### Changed
110
+
111
+ - **Suspendable JavaScript VM** for `<script>` execution (`htmlRender` /
112
+ `runInlineScripts`). `function*` and `async` bodies now compile to a
113
+ resumable bytecode machine, so:
114
+ - **generators are truly lazy** — an infinite `while (true) { yield … }` is
115
+ fine, `.next(v)` feeds a value back into the suspended `yield`, and `yield*`
116
+ delegates lazily;
117
+ - **`await` yields to the event loop** with spec microtask ordering (the
118
+ synchronous tail runs before a deferred continuation), instead of draining
119
+ the queue synchronously;
120
+ - **full control flow** can span a `yield`/`await` — `try`/`catch`/`finally`
121
+ (the handler survives suspension; a rejected `await` in a `try` is caught),
122
+ `for…of`/`for…in`, `switch`, labelled `break`/`continue`, destructuring,
123
+ compound assignment, and `...spread`.
124
+
125
+ No API change — existing `htmlRender`/`runInlineScripts` calls simply behave
126
+ correctly for script-driven, generator/async-heavy templates. A body the VM
127
+ can't compile (e.g. `try`/`catch` around a `yield`/`await`) transparently
128
+ falls back to the previous eager/synchronous model.
129
+
130
+ ## [0.4.0] - 2026-06-15
131
+
132
+ ### Added
133
+
134
+ - **AcroForm field creation.** Build interactive forms from scratch — no
135
+ `pdf-lib`. New `GigaPdfDoc` methods, each taking a `[x0,y0,x1,y1]` rectangle
136
+ and an optional [`FieldStyle`](src/index.ts) (font size, text/border/background
137
+ colour, border width):
138
+ - `addTextField(page, name, rect, value?, { maxLen, multiline, password, style })`
139
+ - `addCheckbox(page, name, rect, checked?, { export, style })`
140
+ - `addRadioGroup(page, name, options: RadioOption[], { selected, style })`
141
+ - `addComboBox(page, name, rect, options, { selected, editable, style })`
142
+ - `addListBox(page, name, rect, options, { selected, multi, style })`
143
+
144
+ Every widget is given a real `/AP` appearance stream (text baseline, a vector
145
+ tick for checkboxes, a filled dot for radios) **and** the form is flagged
146
+ `NeedAppearances`, so fields display immediately and stay faithful when edited.
147
+ - **Advanced flexbox + real grid** in the HTML renderer:
148
+ - `flex-direction: column`, `justify-content` (start/center/end/space-between/
149
+ space-around) and per-item `flex-grow` (proportional column widths);
150
+ - `display: grid` with `grid-template-columns` (fixed column count; children
151
+ wrap into rows). `float` still maps to inline-block.
152
+ - **ES module syntax** is now parsed transparently by the JS engine (`import` is
153
+ elided, `export` declarations run as normal statements).
154
+
155
+ ## [0.3.0] - 2026-06-15
156
+
157
+ ### Added
158
+
159
+ - **JavaScript engine** (zero-dependency, pure Rust → WASM). A document's inline
160
+ `<script>`s now execute **before layout** inside `htmlRender` /
161
+ `htmlNeededFonts` — no Chromium/Playwright — so script-driven content renders.
162
+ The engine covers:
163
+ - Language: classes + `super`, closures, destructuring, spread, optional
164
+ chaining, template literals, `for…of`, generators (`function*`/`yield`,
165
+ eager), `async`/`await` + `Promise` (deterministic synchronous microtask
166
+ model), `try/catch/finally`, labelled loops, `arguments`.
167
+ - Built-ins: `Object`/`Array`/`String`/`Number`/`Boolean`/`Math`/`JSON`/
168
+ `console`/`Map`/`Set`/`RegExp` (a from-scratch backtracking regex engine)/
169
+ `Error`, plus `parseInt`/`parseFloat`/`setTimeout`/`queueMicrotask`.
170
+ - DOM bindings: `document.getElementById`/`getElementsByTagName`/
171
+ `querySelector(All)` (combinators `>`/`+`/`~`, attribute selectors), and on
172
+ elements `textContent`/`innerHTML`/`getAttribute`/`setAttribute`/
173
+ `appendChild`/`removeChild`/`classList`/`style`/`children`.
174
+ - **Page breaks** in the HTML renderer: CSS `page-break-before|after: always`,
175
+ `break-before|after: page`, a `<pagebreak>` element, or `class="page-break"`
176
+ start the following content on a new page.
177
+ - **CSS flexbox** (`display: flex` / `inline-flex`) — a basic equal-column row;
178
+ `grid` falls back to block flow and `float` to inline-block.
179
+
180
+ ### Notes
181
+
182
+ - `htmlRender` / `htmlNeededFonts` are unchanged in signature — they simply run
183
+ the document's scripts first. No new SDK call is required.
184
+
185
+ ## [0.2.0] - 2026-06-15
186
+
187
+ ### Added
188
+
189
+ - Vector drawing primitives on `GigaPdfDoc`: `drawLine`, `addEllipse`,
190
+ `addPolygon`, and `addPath` — the latter accepts arbitrary SVG path data
191
+ (`M`/`L`/`H`/`V`/`C`/`S`/`Q`/`T`/`A`/`Z`, absolute & relative), converting
192
+ quadratic Béziers to cubics and flipping the Y axis like `pdf-lib`'s
193
+ `drawSvgPath`. Covers freeform/polygon/triangle shapes.
194
+ - `addImage`: embed PNG or JPEG rasters as image XObjects. JPEG is stored
195
+ losslessly via `/DCTDecode`; PNG is decoded in-engine (zero-dependency) with
196
+ its alpha channel honoured through a `/SMask` soft mask.
197
+ - `opacity` (fill + stroke alpha through a transient `/ExtGState`) on every
198
+ shape and image (`addRectangle`, `drawLine`, `addEllipse`, `addPolygon`,
199
+ `addPath`, `addImage`).
200
+ - `toOdp`: convert a PDF to an editable OpenDocument Presentation (`.odp`) —
201
+ one slide per page with positioned text boxes, pictures and shapes. This
202
+ completes **bidirectional ODF** (`.odt` / `.ods` / `.odp` both ways, the
203
+ reverse via `officeToPdf`), round-trip validated through LibreOffice Impress.
204
+ - **HTML → PDF rendering engine** (`htmlNeededFonts` + `htmlRender`): a
205
+ zero-dependency in-engine pipeline — HTML parser → CSS cascade (selectors,
206
+ specificity, inheritance, UA defaults) → block / inline / table layout with
207
+ pagination → paint — that renders HTML + CSS to PDF **without a headless
208
+ browser**. Text is set in **embedded Google fonts** resolved against the full
209
+ catalogue (real glyphs + metrics → identical or nearest match). Validated
210
+ end-to-end: Roboto downloaded, embedded (`emb=yes`, Identity-H) and the output
211
+ opens in LibreOffice. JavaScript execution is not included (a separate engine).
212
+
213
+ ### Changed
214
+
215
+ - `addRectangle` gains a trailing optional `opacity` argument — backward
216
+ compatible (defaults to `1`).
217
+
218
+ [0.2.0]: https://github.com/qrcommunication/gigapdf-lib/releases/tag/v0.2.0
219
+
7
220
  ## [0.1.0] - 2026-06-14
8
221
 
9
222
  ### Added
package/README.md CHANGED
@@ -36,7 +36,7 @@ doc.redact(1, 72, 700, 180, 14); // physically remove content in a region
36
36
  doc.addHighlight(1, 72, 690, 252, 704, 0xffff00);
37
37
 
38
38
  // Convert
39
- const docx = doc.toDocx(); // also: toPptx/toOdt/toXlsx/toOds/toHtml/toText/toRtf/toPdfA
39
+ const docx = doc.toDocx(); // also: toPptx/toOdp/toOdt/toXlsx/toOds/toHtml/toText/toRtf/toPdfA
40
40
  const png = doc.renderPage(1, 2); // rasterize a page
41
41
 
42
42
  // Save
@@ -52,6 +52,27 @@ const fromHtml = giga.htmlToPdf("<h1>Hello</h1>");
52
52
  const fromRtf = giga.rtfToPdf(rtfString);
53
53
  ```
54
54
 
55
+ ### Build an interactive form (no `pdf-lib`)
56
+
57
+ ```ts
58
+ // Coordinates are PDF user space (origin bottom-left): [x0, y0, x1, y1].
59
+ doc.addTextField(1, "fullname", [50, 700, 300, 720], "", { maxLen: 60 });
60
+ doc.addCheckbox(1, "subscribe", [50, 670, 64, 684], true, { export: "Yes" });
61
+ doc.addRadioGroup(1, "plan", [
62
+ { export: "Basic", rect: [50, 640, 64, 654] },
63
+ { export: "Pro", rect: [80, 640, 94, 654] },
64
+ ], { selected: "Pro" });
65
+ doc.addComboBox(1, "country", [50, 610, 200, 626], ["FR", "US", "DE"], { selected: "FR" });
66
+ doc.addListBox(1, "langs", [50, 540, 200, 600], ["en", "fr", "de"], { multi: true });
67
+
68
+ // Optional per-field styling.
69
+ doc.addTextField(1, "vat", [50, 510, 200, 528], "", {
70
+ style: { fontSize: 11, color: 0x102030, border: 0x888888, background: 0xf5f5f5 },
71
+ });
72
+
73
+ const filled = doc.fields(); // read them straight back: kind + value + options
74
+ ```
75
+
55
76
  ### Fonts (host performs the network fetch)
56
77
 
57
78
  ```ts
@@ -84,16 +105,43 @@ Or call `GigaPdfEngine.load(bytes)` with bytes you read yourself.
84
105
  `txtToPdf`/`htmlToPdf`/`rtfToPdf`/`officeToPdf`, `fontCatalog`/`fontRequestUrl`/`parseCssFontUrl`.
85
106
  - **`GigaPdfDoc`** — text intelligence (`textRuns`, `structuredText`, `search`,
86
107
  `ocr`, `ocrText`, `elements`, `elementAt`), editing (`replaceText`,
87
- `removeElement`, `moveElement`, `duplicateElement`, `addRectangle`, `redact`),
88
- pages (`rotatePage`, `deletePage`, `movePage`, `appendPages`, `extractPages`),
108
+ `removeElement`, `moveElement`, `duplicateElement`, `redact`), vector drawing
109
+ (`addRectangle`, `drawLine`, `addEllipse`, `addPolygon`, `addPath` (SVG path),
110
+ `addImage` (PNG/JPEG, alpha + opacity)), pages (`rotatePage`, `deletePage`,
111
+ `movePage`, `appendPages`, `extractPages`, `resizePage`, `addPage`, `copyPage`,
112
+ `pageInfo`),
89
113
  `renderPage`, fonts (`embedFont`, `addText`, `neededFonts`), conversions
90
- (`toText/Html/Docx/Pptx/Odt/Xlsx/Ods/Rtf/PdfA`), security (`saveEncrypted`,
114
+ (`toText/Html/Docx/Pptx/Odp/Odt/Xlsx/Ods/Rtf/PdfA`), security (`saveEncrypted`,
91
115
  `sign`), metadata (`getMetadata`, `setMetadata`), annotations (`addSquare`,
92
116
  `addHighlight`, `addLineAnnotation`, `addFreeText`, `addUnderline`,
93
117
  `addStrikeOut`, `addInk`, `addStamp`, `annotations`, `removeAnnotation`,
94
118
  `flattenAnnotations`), links (`links`, `addUriLink`, `addGotoLink`), outline
95
- (`outline`, `setOutline`), and forms (`fields`, `setTextField`, `setCheckbox`,
96
- `setRadio`, `setChoice`).
119
+ (`outline`, `setOutline`), forms — read/fill (`fields`, `setTextField`,
120
+ `setCheckbox`, `setRadio`, `setChoice`) **and create**
121
+ (`addTextField`, `addCheckbox`, `addRadioGroup`, `addComboBox`, `addListBox`,
122
+ each with an optional `FieldStyle`), and optional-content layers (`layers`,
123
+ `addLayer`, `setLayerVisibility`, `setLayerLocked`, `removeLayer`).
124
+ - **HTML rendering engine** (on `GigaPdfEngine`) — `htmlNeededFonts(html)`
125
+ returns the Google fonts to download (phase 1); `htmlRender(html, fonts,
126
+ pageW?, pageH?, margin?)` renders HTML + CSS to PDF with those fonts embedded
127
+ (phase 2). **No headless browser.** Block / inline / table / **flex**
128
+ (`flex-direction`, `justify-content`, `flex-grow`) / **grid**
129
+ (`grid-template-columns`) layout, selector cascade, pagination, and forced page
130
+ breaks via CSS `page-break-before|after: always` / `break-*: page` or a
131
+ `<pagebreak>` tag. **See the exhaustive list of supported HTML elements, CSS
132
+ properties, units, colours and selectors in
133
+ [`docs/HTML-CSS.md`](https://github.com/QrCommunication/gigapdf-lib/blob/main/docs/HTML-CSS.md).**
134
+ - **JavaScript** — a document's inline `<script>`s run **before layout** through
135
+ a built-in zero-dependency JS engine (no Chromium/Playwright), so script-driven
136
+ content is rendered. It covers classes + `super`, closures, destructuring,
137
+ `RegExp`, `Map`/`Set`, `Symbol`, `eval`/`Function`, and DOM bindings
138
+ (`document.getElementById`, `querySelector(All)` with `>`/`+`/`~`/`[attr]`,
139
+ `textContent`, `innerHTML`, `createElement`/`appendChild`, `classList`,
140
+ `style`). `function*`/`async` bodies compile to a **suspendable bytecode VM**,
141
+ so generators are **truly lazy** (infinite generators, bidirectional
142
+ `.next(v)`, `yield*`) and `await` **yields** with spec microtask ordering. This
143
+ happens automatically inside `htmlRender`/`htmlNeededFonts` — no extra call
144
+ needed.
97
145
 
98
146
  Every method is fully typed. Always `close()` a document when done to free the
99
147
  WASM handle.