npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

svg-cmyk-pdf

v1.0.0

Published

Convert cleaned line-art SVGs into print-ready CMYK PDFs where every mark is a tint of one spot-color Separation — the Illustrator "Recolor to rich black" step as a batch job. Purpose-built single-page PDF writer (Separation, tiling patterns, axial shadin

Readme

svg-cmyk-pdf

Convert cleaned line-art SVGs into print-ready CMYK PDFs where every mark is a tint of one spot-color Separation — the Illustrator "Recolor to rich black" step, as a batch job.

A rinsed line-art SVG (see svg-color-rinse) is black ink on paper: solid blacks, a handful of surviving grays, maybe a ben-day dot pattern or a soft linear gradient. SVG can't hold CMYK separations, so the last step used to be manual: open each file in Illustrator, map black to a warm Rich Black spot swatch, let the grays fall onto its tints, save a PDF. This tool writes that PDF directly:

svg-cmyk-pdf art.svg          # writes art.pdf alongside
art.svg:
  page 491.52 x 329.64 pt (4096 x 2747 px @ 600 dpi)
  spot "Rich Black Line Art Warm" C1 = 20/30/20/100
  ink: paper [175x]  16.67% [137x]  33.33% [59x]  50% [50x]  100% [349x]
  wrote art.pdf (278 KB)

Open the result in Acrobat and check Output Preview: a single spot plate named "Rich Black Line Art Warm" plus paper white. No overprint, no stray process colors, geometry still vectors.

The color model

The PDF mirrors what Illustrator produces when you recolor line art to a rich-black spot swatch — one page, two colorspaces:

  • CS0 — DeviceCMYK (or an ICCBased CMYK space with --icc): used only for paper white, 0 0 0 0 k, which knocks out anything beneath it (knockout is the point — overprint is never set).
  • CS1 — a Separation spot color, default name "Rich Black Line Art Warm", alternate space CS0, with an exponential (FunctionType 2) tint transform: tint 0 → 0/0/0/0, tint 1 → the rich-black formula (default CMYK 20/30/20/100).

Every fill becomes one of:

| SVG fill | PDF paint | |---|---| | white / near-white | 0 0 0 0 k in CS0 (paper, knockout) | | black (including a missing fill attribute — black per the SVG spec) | CS1 at tint 1 | | gray | CS1 at tint 1 − luma/255 (Rec.601), quantized (see --tints) | | url(#pattern) ben-day fill | paper base fill, then the same path filled again with an uncolored tiling pattern (PaintType 2) whose cell holds only the dark mark, painted at the mark's tint | | url(#linearGradient) | an axial shading pattern (ShadingType 2) in the Separation space — the stops' grays become the tint function |

So the separation stays a single ink end to end: dots, gradients, grays and solids all print on the same plate set, and paper stays paper.

Geometry is never rasterized and never rescaled: path coordinates stay in SVG user units and the page CTM does all the mapping — including the non-uniform stretch of preserveAspectRatio="none" exports (a 4096×2747 image over a square viewBox stays stretched, on purpose). --dpi (default 600) sets how SVG pixels map to points: pt = px / dpi × 72.

Install

# run without installing
npx svg-cmyk-pdf art.svg

# or install globally
npm install -g svg-cmyk-pdf
svg-cmyk-pdf art.svg

# or from a clone
npm install && node svg-cmyk-pdf.mjs art.svg

Requires Node 20+. One dependency (svgpath, for path-data parsing and arc flattening); the PDF writer is purpose-built and dependency-free.

Batch a whole folder

Directories are processed recursively for .svg. Existing .pdf outputs are skipped, so re-running a batch is idempotent — --force overwrites:

svg-cmyk-pdf --out print-pdfs/ vectorized/
svg-cmyk-pdf --force --out print-pdfs/ vectorized/

Tune the ink

# a heavier warm black, under a different plate name
svg-cmyk-pdf --formula 40,60,40,100 --name "Rich Black Heavy" art.svg

# snap stragglers before quantizing (svg-color-rinse semantics):
# tint >= 80% becomes solid, <= 10% becomes paper
svg-cmyk-pdf --gates art.svg          # bare flag = 80,10
svg-cmyk-pdf --gates 75,12 art.svg

# more tint steps, or none at all
svg-cmyk-pdf --tints 9 art.svg
svg-cmyk-pdf --tints 0 art.svg        # keep exact per-color tints

Surviving mid tints are quantized to --tints N evenly spaced levels i/(N+1) — the default 5 gives 16.7% / 33.3% / 50% / 66.7% / 83.3%, a palette that survives dot gain better than eleven nearly identical grays. The per-file report lists exactly which tints were used and how often.

ICC profiles

--icc swaps the Separation's alternate space (and paper white) from DeviceCMYK to an ICCBased CMYK space, so previews and any late conversion use real press numbers. It takes a .icc path, a name to search for in the system/Adobe profile folders, or auto (GRACoL → SWOP → Generic CMYK):

svg-cmyk-pdf --icc auto art.svg
svg-cmyk-pdf --icc "GRACoL2013" art.svg
svg-cmyk-pdf --icc ~/profiles/press.icc art.svg

The spot plate values themselves are always exactly your formula — the profile only describes what CMYK means downstream, it never rewrites plates (same philosophy as lineart-rich-black).

Options

| flag | default | meaning | |---|---|---| | --formula C,M,Y,K | 20,30,20,100 | plate percentages for solid ink (the Separation's C1) | | --name "..." | Rich Black Line Art Warm | spot color (separation) name | | --tints N | 5 | quantize mid tints to N levels i/(N+1); 0 disables | | --gates [B,W] | off | snap tints ≥ B% to solid and ≤ W% to paper before quantizing; bare flag = 80,10 | | --dpi N | 600 | SVG pixels per inch; page points = px / dpi × 72 | | --icc <path\|name\|auto> | off | ICCBased CMYK alternate space (searched like lineart-rich-black) | | --out <dir> | alongside input | output directory | | --force | off | overwrite existing .pdf outputs (default: skip) | | --help | | print usage |

Scope and limitations

v1 is deliberately narrow — it targets rinsed vectorizer output (Recraft and friends, optionally stamped by svg-silver-age-bg), not arbitrary SVG:

  • Elements: <path> (full path grammar — relative/shorthand/arcs all handled; a missing fill attribute means black, which inverted-structure exports rely on), <rect>, <ellipse>, <circle>, <polygon>, transparent <g>, and <defs> containing <pattern> and <linearGradient>.
  • Patterns must be patternUnits="userSpaceOnUse" with the cell geometry in user units (the shape svg-silver-age-bg stamps: a paper rect plus a dark ellipse/rect/polygon/stroked-stripe mark).
  • Gradients must be gradientUnits="userSpaceOnUse"; 2-stop gradients become a single exponential function, more stops become a stitching function, gradientTransform matrices are honored. A gradient using anything beyond that (objectBoundingBox units, spreadMethod other than pad, href inheritance, radial gradients) falls back to a solid fill at the stops' average tint, with a warning naming the gradient.
  • Colors are #rgb/#rrggbb/rgb(); tint is 1 − luma/255. Saturated colors shouldn't exist after rinsing — they're warned about and mapped through luma anyway.
  • Strokes are supported as ink (stroke/stroke-width), which is what the stripes pattern cell uses.
  • Out of scope — text, images, masks, clip paths, filters, CSS stylesheets, element transforms on non-path elements: each is skipped with a per-element warning and a non-zero summary count, never silently.

One rendering note: tiling patterns are written with TilingType 2 (no distortion). TilingType 1 permits rasterizers to round the tile step to whole device pixels, and on a full page of ben-day dots that rounding error accumulates into visible drift (macOS Quartz does exactly this).

Verifying output

  • macOS: sips -g all out.pdf sanity-checks the file; Preview renders the spot color via its alternate space (expect the warm cast — that's the formula showing).
  • Acrobat: Output Preview → Separations should list your spot name; toggling it off must blank all ink; paper areas must show 0/0/0/0.
  • The test suite parses written PDFs back with a minimal reader (test/pdf-reader.mjs) and asserts the object graph, not just that a file appeared.

Companions

  • svg-color-rinse — snap the near-blacks and near-whites a vectorizer scatters into clean #000000/#ffffff anchors. Run it first; this tool assumes rinsed input.
  • svg-silver-age-bg — stamp a deterministic ben-day/motif comic background as its own layer. Its patterns are exactly the <pattern> shapes this tool converts.
  • lineart-rich-black — the raster sibling: B/W line-art PNGs to CMYK TIFFs with the same rich-black formula and gates semantics.

Development

npm install   # svgpath
npm test      # node --test against the synthetic fixtures in test/fixtures/

License

MIT