{"_id":"jspdf-blend-modes","_rev":"3-a8ee520d8518d5944995edb6f15c0a8e","name":"jspdf-blend-modes","dist-tags":{"latest":"0.2.3"},"versions":{"0.2.1":{"name":"jspdf-blend-modes","version":"0.2.1","keywords":["jspdf","svg2pdf","pdf","pdf-export","vector-pdf","blend-mode","blend-modes","mix-blend-mode","multiply","screen","overlay","extgstate","extended-graphics-state","pdf-1.4"],"author":{"name":"Jarvis Luk","email":"lu_junrong@outlook.com"},"license":"MIT","_id":"jspdf-blend-modes@0.2.1","maintainers":[{"name":"jarvisluk","email":"lu_junrong@outlook.com"}],"homepage":"https://github.com/JarvisLuk/jspdf-blend-modes#readme","bugs":{"url":"https://github.com/JarvisLuk/jspdf-blend-modes/issues"},"dist":{"shasum":"0a1fa345966f26bd39d7acbbf5409163a4399c5c","tarball":"https://registry.npmjs.org/jspdf-blend-modes/-/jspdf-blend-modes-0.2.1.tgz","fileCount":16,"integrity":"sha512-26cq0zWTmicO7dizExIlf7wj82vtnRlXLXOsA7QWMyjo6kz7xD9knfijaYz+Jg/zIIQIMl92T6QyltM+zcoDdg==","signatures":[{"sig":"MEUCIGwZomsHbu0RzBGKaVH36wEzuWBcxtg9JUeX1gUb7vFkAiEAzF4R10WZgoKjcUbbXYeV3OblPUnxJKB0xXXDMEmkNIA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":202287},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./gstate":{"types":"./dist/gstate.d.ts","import":"./dist/gstate.js","require":"./dist/gstate.cjs"},"./package.json":"./package.json"},"gitHead":"8295cd9239ddd8505a399bae9cceb043ab78a6fb","scripts":{"dev":"tsup --watch","lint":"eslint \"src/**/*.ts\" \"test/**/*.ts\"","size":"size-limit","test":"vitest run","build":"tsup","format":"prettier --write \"{src,test}/**/*.ts\"","release":"npm run build && npx -y --package=@changesets/cli@^2.27.7 changeset publish","size:why":"size-limit --why","changeset":"npx -y --package=@changesets/cli@^2.27.7 changeset","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run typecheck && npm run test && npm run build && npm run size","version-packages":"npx -y --package=@changesets/cli@^2.27.7 changeset version"},"_npmUser":{"name":"jarvisluk","email":"lu_junrong@outlook.com"},"repository":{"url":"git+https://github.com/JarvisLuk/jspdf-blend-modes.git","type":"git"},"size-limit":[{"gzip":true,"name":"gstate (DOM-free, ESM)","path":"dist/gstate.js","limit":"5 KB","ignore":["jspdf"]},{"gzip":true,"name":"index (full library, ESM)","path":"dist/index.js","limit":"12 KB","ignore":["jspdf","svg2pdf.js"]}],"_npmVersion":"11.11.0","description":"Real PDF 1.4 blend modes for jsPDF and svg2pdf.js — Multiply, Screen, Overlay, … and round-tripping CSS mix-blend-mode from SVG.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.1","publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.2","jspdf":"^2.5.2","eslint":"^8.57.0","vitest":"^1.6.0","prettier":"^3.2.5","happy-dom":"^14.12.0","size-limit":"^12.1.0","svg2pdf.js":"^2.5.0","typescript":"^5.4.5","@types/node":"^20.12.7","@typescript-eslint/parser":"^7.7.0","@size-limit/preset-small-lib":"^12.1.0","@typescript-eslint/eslint-plugin":"^7.7.0"},"peerDependencies":{"jspdf":">=2.5.0 <6.0.0","svg2pdf.js":">=2.5.0 <3.0.0"},"peerDependenciesMeta":{"svg2pdf.js":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/jspdf-blend-modes_0.2.1_1778849603903_0.5961646626439931","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"jspdf-blend-modes","version":"0.2.2","keywords":["jspdf","svg2pdf","pdf","pdf-export","vector-pdf","blend-mode","blend-modes","mix-blend-mode","multiply","screen","overlay","extgstate","extended-graphics-state","pdf-1.4"],"author":{"name":"Jarvis Luk","email":"lu_junrong@outlook.com"},"license":"MIT","_id":"jspdf-blend-modes@0.2.2","maintainers":[{"name":"jarvisluk","email":"lu_junrong@outlook.com"}],"homepage":"https://github.com/jarvisluk/jspdf-blend-modes#readme","bugs":{"url":"https://github.com/jarvisluk/jspdf-blend-modes/issues"},"dist":{"shasum":"3d823281834d71649fd03394fe7455da8e15bb5c","tarball":"https://registry.npmjs.org/jspdf-blend-modes/-/jspdf-blend-modes-0.2.2.tgz","fileCount":16,"integrity":"sha512-lIG258oPVd7bjiJoLcF/72Z820uZ/Jq6asLHRi9B34G58uVJ13Zmbc6s//BZHTniwytpvkecRcprzp01A/B/7A==","signatures":[{"sig":"MEUCIQCOo1b3gvkf8s0JPIMKLdjPK6gnE8LOfmcuHKSrXIiABgIgTenHG8rdi67UvQvorTr90iFPAx4UVj1GALDyvzv5B94=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/jspdf-blend-modes@0.2.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":202782},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./gstate":{"types":"./dist/gstate.d.ts","import":"./dist/gstate.js","require":"./dist/gstate.cjs"},"./package.json":"./package.json"},"gitHead":"af4a75d191a00087376890a8f98778a4b9c58ce9","scripts":{"dev":"tsup --watch","lint":"eslint \"src/**/*.ts\" \"test/**/*.ts\"","size":"size-limit","test":"vitest run","build":"tsup","format":"prettier --write \"{src,test}/**/*.ts\"","release":"npm run build && npx -y --package=@changesets/cli@^2.27.7 changeset publish","size:why":"size-limit --why","changeset":"npx -y --package=@changesets/cli@^2.27.7 changeset","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run typecheck && npm run test && npm run build && npm run size","version-packages":"npx -y --package=@changesets/cli@^2.27.7 changeset version"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:8672bcc7-20b0-487c-b43c-99bb31001e9d"}},"repository":{"url":"git+https://github.com/jarvisluk/jspdf-blend-modes.git","type":"git"},"size-limit":[{"gzip":true,"name":"gstate (DOM-free, ESM)","path":"dist/gstate.js","limit":"5 KB","ignore":["jspdf"]},{"gzip":true,"name":"index (full library, ESM)","path":"dist/index.js","limit":"12 KB","ignore":["jspdf","svg2pdf.js"]}],"_npmVersion":"11.14.1","description":"Real PDF 1.4 blend modes for jsPDF and svg2pdf.js — Multiply, Screen, Overlay, … and round-tripping CSS mix-blend-mode from SVG.","directories":{},"sideEffects":false,"_nodeVersion":"22.14.0","publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.2","jspdf":"^2.5.2","eslint":"^8.57.0","vitest":"^1.6.0","prettier":"^3.2.5","happy-dom":"^14.12.0","size-limit":"^12.1.0","svg2pdf.js":"^2.5.0","typescript":"^5.4.5","@types/node":"^20.12.7","@typescript-eslint/parser":"^7.7.0","@size-limit/preset-small-lib":"^12.1.0","@typescript-eslint/eslint-plugin":"^7.7.0"},"peerDependencies":{"jspdf":">=2.5.0 <6.0.0","svg2pdf.js":">=2.5.0 <3.0.0"},"peerDependenciesMeta":{"svg2pdf.js":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/jspdf-blend-modes_0.2.2_1778852359419_0.4815204595951459","host":"s3://npm-registry-packages-npm-production"}},"0.2.3":{"name":"jspdf-blend-modes","version":"0.2.3","description":"Real PDF 1.4 blend modes for jsPDF and svg2pdf.js — Multiply, Screen, Overlay, … and round-tripping CSS mix-blend-mode from SVG.","license":"MIT","type":"module","keywords":["jspdf","svg2pdf","pdf","pdf-export","vector-pdf","blend-mode","blend-modes","mix-blend-mode","multiply","screen","overlay","extgstate","extended-graphics-state","pdf-1.4"],"author":{"name":"Jarvis Luk","email":"lu_junrong@outlook.com"},"repository":{"type":"git","url":"git+https://github.com/jarvisluk/jspdf-blend-modes.git"},"homepage":"https://github.com/jarvisluk/jspdf-blend-modes#readme","bugs":{"url":"https://github.com/jarvisluk/jspdf-blend-modes/issues"},"engines":{"node":">=18.0.0"},"publishConfig":{"access":"public","provenance":true},"sideEffects":false,"main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./gstate":{"types":"./dist/gstate.d.ts","import":"./dist/gstate.js","require":"./dist/gstate.cjs"},"./package.json":"./package.json"},"scripts":{"build":"tsup","dev":"tsup --watch","typecheck":"tsc --noEmit","lint":"eslint \"src/**/*.ts\" \"test/**/*.ts\"","format":"prettier --write \"{src,test}/**/*.ts\"","test":"vitest run","test:watch":"vitest","size":"size-limit","size:why":"size-limit --why","changeset":"npx -y --package=@changesets/cli@^2.27.7 changeset","version-packages":"npx -y --package=@changesets/cli@^2.27.7 changeset version","release":"npm run build && npx -y --package=@changesets/cli@^2.27.7 changeset publish","prepublishOnly":"npm run typecheck && npm run test && npm run build && npm run size"},"size-limit":[{"name":"gstate (DOM-free, ESM)","path":"dist/gstate.js","limit":"5 KB","gzip":true,"ignore":["jspdf"]},{"name":"index (full library, ESM)","path":"dist/index.js","limit":"12 KB","gzip":true,"ignore":["jspdf","svg2pdf.js"]}],"peerDependencies":{"jspdf":">=2.5.0 <6.0.0","svg2pdf.js":">=2.5.0 <3.0.0"},"peerDependenciesMeta":{"svg2pdf.js":{"optional":true}},"devDependencies":{"@size-limit/preset-small-lib":"^12.1.0","@types/node":"^20.12.7","@typescript-eslint/eslint-plugin":"^7.7.0","@typescript-eslint/parser":"^7.7.0","eslint":"^8.57.0","happy-dom":"^14.12.0","jspdf":"^2.5.2","prettier":"^3.2.5","size-limit":"^12.1.0","svg2pdf.js":"^2.5.0","tsup":"^8.0.2","typescript":"^5.4.5","vitest":"^1.6.0"},"gitHead":"6d794219dfec47d54a3a9a5c6df87b7d19c2a001","_id":"jspdf-blend-modes@0.2.3","_nodeVersion":"22.14.0","_npmVersion":"11.14.1","dist":{"integrity":"sha512-ZhkT6duql5rUmgwEmmH1CDQF54aQkPGVpcHT5n35jePK1pHlV/HeSuI6E9Hhg4WxRXJrCPonGZuRQbqlmkgDiw==","shasum":"b72c31438d3f03a0b37fb9dcb51c3561421ba867","tarball":"https://registry.npmjs.org/jspdf-blend-modes/-/jspdf-blend-modes-0.2.3.tgz","fileCount":16,"unpackedSize":203158,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/jspdf-blend-modes@0.2.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDSjjt5ivWjZ4gCqrF+kyY9RWUunROMPVlgYABxMt4WwAIhALQBmjcDKYzdmd6HA/6cdCTB3Q0BPL5mM3aEo0dgaDq4"}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:8672bcc7-20b0-487c-b43c-99bb31001e9d"}},"directories":{},"maintainers":[{"name":"jarvisluk","email":"lu_junrong@outlook.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/jspdf-blend-modes_0.2.3_1778853849336_0.12590189317420486"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-15T12:53:23.815Z","modified":"2026-05-15T14:04:09.728Z","0.2.1":"2026-05-15T12:53:24.095Z","0.2.2":"2026-05-15T13:39:19.569Z","0.2.3":"2026-05-15T14:04:09.477Z"},"bugs":{"url":"https://github.com/jarvisluk/jspdf-blend-modes/issues"},"author":{"name":"Jarvis Luk","email":"lu_junrong@outlook.com"},"license":"MIT","homepage":"https://github.com/jarvisluk/jspdf-blend-modes#readme","keywords":["jspdf","svg2pdf","pdf","pdf-export","vector-pdf","blend-mode","blend-modes","mix-blend-mode","multiply","screen","overlay","extgstate","extended-graphics-state","pdf-1.4"],"repository":{"type":"git","url":"git+https://github.com/jarvisluk/jspdf-blend-modes.git"},"description":"Real PDF 1.4 blend modes for jsPDF and svg2pdf.js — Multiply, Screen, Overlay, … and round-tripping CSS mix-blend-mode from SVG.","maintainers":[{"name":"jarvisluk","email":"lu_junrong@outlook.com"}],"readme":"# jspdf-blend-modes\n\n[![CI](https://github.com/jarvisluk/jspdf-blend-modes/actions/workflows/ci.yml/badge.svg)](https://github.com/jarvisluk/jspdf-blend-modes/actions/workflows/ci.yml)\n[![npm version](https://img.shields.io/npm/v/jspdf-blend-modes.svg)](https://www.npmjs.com/package/jspdf-blend-modes)\n[![bundle size](https://img.shields.io/bundlephobia/minzip/jspdf-blend-modes?label=gzip)](https://bundlephobia.com/package/jspdf-blend-modes)\n[![license](https://img.shields.io/npm/l/jspdf-blend-modes.svg)](./LICENSE)\n\nReal **PDF 1.4 blend modes** for [jsPDF](https://github.com/parallax/jsPDF) and\n[svg2pdf.js](https://github.com/yWorks/svg2pdf.js) — all 16 modes, plus a\none-call helper that round-trips CSS `mix-blend-mode` from a live SVG into\nthe PDF.\n\n## Install\n\n```bash\nnpm install jspdf-blend-modes jspdf svg2pdf.js\n# or, if you only need the low-level DOM-free API:\nnpm install jspdf-blend-modes jspdf\n```\n\n`jspdf` is a peer dependency; `svg2pdf.js` is an **optional** peer used only\nby `renderSvgWithBlendModes`.\n\n## Quickstart\n\n```ts\nimport { jsPDF } from \"jspdf\";\nimport \"svg2pdf.js\";\nimport { renderSvgWithBlendModes } from \"jspdf-blend-modes\";\n\nconst pdf = new jsPDF({ unit: \"pt\", format: [432, 432] });\nconst svg = document.querySelector<SVGSVGElement>(\"#my-sticker\")!;\n\nawait renderSvgWithBlendModes(pdf, svg, { x: 0, y: 0, width: 432, height: 432 });\npdf.save(\"sticker.pdf\");\n```\n\nLow-level, DOM-free (SSR-safe):\n\n```ts\nimport { withBlendMode } from \"jspdf-blend-modes/gstate\";\n\nawait withBlendMode(pdf, \"Multiply\", () => {\n  pdf.setFillColor(255, 0, 0);\n  pdf.rect(20, 20, 60, 60, \"F\");\n});\n```\n\n## API\n\n- **`jspdf-blend-modes/gstate`** (DOM-free): `registerBlendMode`,\n  `withBlendMode`, `BLEND_MODES`, `cssToPdfBlendMode`, `isBlendMode`.\n- **`jspdf-blend-modes`** (browser): `renderSvgWithBlendModes(pdf, svg, opts)`\n  — opts: `x/y/width/height`, `blendSelector?`, `groupingStrategy?:\n\"by-mode\" | \"by-element\"`, `fixDominantBaseline?`.\n\nAll 16 PDF 1.4 modes: `Normal`, `Multiply`, `Screen`, `Overlay`, `Darken`,\n`Lighten`, `ColorDodge`, `ColorBurn`, `HardLight`, `SoftLight`, `Difference`,\n`Exclusion`, `Hue`, `Saturation`, `Color`, `Luminosity`.\n\n## Compatibility\n\njsPDF `>=2.5.0 <6.0.0` · svg2pdf.js `>=2.5.0 <3.0.0` (peer) · Node 18/20/22.\nAll jsPDF internals are isolated in [`src/internal-api.ts`](./src/internal-api.ts).\n\n## Limitations\n\n- **Z-order across modes.** `groupingStrategy: \"by-mode\"` (the default)\n  collapses all same-mode elements into one pass, which can reorder them\n  relative to elements in *other* mode groups. Pass\n  `groupingStrategy: \"by-element\"` to preserve strict document order at the\n  cost of one extra `pdf.svg(...)` call per blend element.\n- **The high-level API is browser-only.** `renderSvgWithBlendModes` calls\n  `getComputedStyle()` and mounts isolated SVGs off-screen. Node and SSR\n  consumers should import from the DOM-free\n  [`jspdf-blend-modes/gstate`](#api) subpath instead.\n- **The SVG must be in the document tree.** `renderSvgWithBlendModes`\n  throws an actionable error if the SVG isn't connected: both\n  `getComputedStyle` and `getBoundingClientRect` need a live DOM to\n  produce meaningful values. Mount the SVG (off-screen if necessary) before\n  calling, or render it in your UI normally.\n- **ICC color spaces.** Output is sRGB; the library does not set an\n  `OutputIntent`. For PDF/X printing pipelines, set the OutputIntent\n  yourself and validate against your printer's ICC profile.\n- **Isolation boundaries.** PDF blend modes composite against the current\n  transparency group. The library uses the page-level group, which matches\n  CSS for the common cases. If you wrap a blend in a non-`Normal` parent\n  group, results may differ from CSS — file an issue with a reproduction\n  and we can add a `groupSelector` option.\n- **Fonts.** The library does not register fonts for you. If your SVG uses\n  a custom font, register it on the `pdf` instance (`addFileToVFS` /\n  `addFont`) before calling `renderSvgWithBlendModes`.\n- **CSS keywords outside the PDF spec.** Values like `plus-lighter`,\n  `plus-darker`, and `mix-blend-mode: var(--…)` aren't part of the PDF 1.4\n  spec; `cssToPdfBlendMode` returns `null` for those and the matched\n  element is skipped (drawn under `Normal`). Force a specific mode with the\n  predicate form of `blendSelector` if you need an approximation.\n\n## Migrating from a manual ExtGState workaround\n\nIf you've been hand-rolling the ExtGState injection through jsPDF's internal\nevents, the library replaces all of it with a one-liner.\n\n**Before** — direct `internal` access, hand-wired event subscriptions, a\ndummy GState to force `/ExtGState` into the page Resources, and a manual\n`q ... Q` scope around the second-pass render:\n\n```ts\nconst internal = (pdf as any).internal;\ninternal.events.subscribe(\"putResources\", () => {\n  const oid = internal.newObject();\n  internal.write(\"<< /Type /ExtGState /BM /Multiply /ca 1 /CA 1 >>\");\n  internal.write(\"endobj\");\n  // ... separate subscription wires the oid into putGStateDict ...\n});\n// ... force the dictionary to actually be written ...\npdf.addGState(\"__force__\", new (pdf as any).GState({ opacity: 1 }));\n\ninternal.out(\"q /GsMul gs\");\nawait (pdf as any).svg(accentSvg, { x, y, width, height });\ninternal.out(\"Q\");\n```\n\n**After** — low-level helper that handles the registration, the force-emit\nhack, and the scope brackets, and is idempotent:\n\n```ts\nimport { withBlendMode } from \"jspdf-blend-modes/gstate\";\n\nawait withBlendMode(pdf, \"Multiply\", () =>\n  pdf.svg(accentSvg, { x, y, width, height })\n);\n```\n\nOr, if you're round-tripping a CSS `mix-blend-mode` SVG end-to-end, replace\nthe entire two-pass orchestration with `renderSvgWithBlendModes`:\n\n```ts\nimport { renderSvgWithBlendModes } from \"jspdf-blend-modes\";\n\nawait renderSvgWithBlendModes(pdf, svg, {\n  x: 0,\n  y: 0,\n  width: pageWidthPt,\n  height: pageHeightPt\n});\n```\n\nBehavioural notes during migration:\n\n- **No more direct `(pdf as any).internal`** — `withBlendMode` always emits\n  the closing `Q`, even if your callback throws.\n- **Idempotent registration** — call `registerBlendMode(pdf, \"Multiply\")` as\n  many times as you want; the library deduplicates by `(pdf, mode, name)`.\n- **GState names changed** — the default name is `Gs<Mode>` (e.g.\n  `GsMultiply`) instead of the ad-hoc `GsMul`. Pass\n  `registerBlendMode(pdf, \"Multiply\", { name: \"GsMul\" })` if you have\n  consumers parsing the raw bytes who depend on the old name.\n\n## Demo\n\n**Live**: <https://jarvisluk.github.io/jspdf-blend-modes/> — runs all three\nexports of the same SVG side by side and renders each generated PDF inline\nwith [pdf.js](https://mozilla.github.io/pdf.js/), so you can see the\nmultiply blend land or fail without leaving the page.\n\n**Local**:\n\n```bash\nnpm install && cd demo/browser && npm install && npm run dev\n```\n\n## Contributing\n\nContributions are welcome. Please read [CONTRIBUTING.md](./CONTRIBUTING.md)\nfor local setup, coding style, testing expectations, commit-message conventions,\nand the pull request checklist.\n\nThis project follows the [Contributor Covenant](./CODE_OF_CONDUCT.md). For\nsecurity-sensitive reports, please follow [SECURITY.md](./SECURITY.md) instead\nof opening a public issue.\n\n## License\n\n[MIT](./LICENSE)\n","readmeFilename":"README.md"}