Skip to main content

Convert color images to CMYK-separated halftone SVG files for screen printing and risograph

Project description

Rosette

PyPI Python License: AGPL-3.0

Convert a color image into CMYK-separated halftone SVG files — one per channel, each a pure vector circle halftone at the correct screen angle.

Built for screen printing, risograph, and any print workflow where you need clean per-channel separations as scalable vector art.

A web-based version of this tool for monochrome halftones can be found at palettary.com/halftone.


What Rosette Does

Rosette takes a color image and produces four standalone SVG plates plus a composite preview:

File Contents
cyan.svg Cyan channel halftone dots
magenta.svg Magenta channel halftone dots
yellow.svg Yellow channel halftone dots
black.svg Black channel halftone dots
sample.png All channels composited — a quick calibration preview

Each SVG contains only that channel's dots as <circle> elements on a transparent background. Load them into Inkscape or Illustrator, or send them directly to a print workflow.

Unlike raster-output halftone tools, Rosette's plates are resolution-independent — scale them to any print size without quality loss. Isolated per-channel vector plates are the whole point: a composited raster preview can't be burned to a screen or sent to a riso drum, but these SVGs can.


Installation

Available on PyPI as rosette-halftone:

pip install rosette-halftone

The installed command is rosette. Requires Python 3.10+. Dependencies: Pillow, NumPy, Click.

Linux note: modern Debian/Ubuntu block pip install outside a virtual environment ("externally-managed-environment"). The easiest fix is pipx, which installs CLI tools globally in their own isolated environments:

sudo apt install pipx
pipx ensurepath
pipx install rosette-halftone

Usage

rosette IMAGE [OPTIONS]

IMAGE is a PNG, JPG, TIFF, or WEBP file.

Options

Option Default Description
--dots INTEGER 100 Dots per row (controls grid density)
--preset TEXT us Screen angle preset (see table below)
--angles C M Y K Manual per-channel angles in degrees; overrides --preset
--profile TEXT math CMYK conversion method: math or swop (see below)
--gamma FLOAT 1.5 Dot density curve. Higher = lighter, more open halftone; lower = heavier
--tac FLOAT 220 Total Area Coverage limit (%) — caps total ink per pixel
--min-radius FLOAT 0 Minimum dot radius as a fraction of max radius (0–1)
--channels TEXT cmyk Channels to generate: any combo of c, m, y, k
--resample TEXT linear Sampling kernel: nearest, linear, lanczos2, lanczos3, spline36
--output DIR ./output Output directory
--zip off Package all output (SVGs + sample.png) into a single ZIP

Choosing a conversion profile (--profile)

Rosette offers two ways to split RGB into CMYK:

  • math (default) — a direct geometric formula (K = 1 − max(R,G,B), with C/M/Y as the remainder). Produces moderate, neutral, predictable ink values. Recommended for screen printing and risograph, where inks and stocks differ from commercial offset.
  • swop — ICC-accurate conversion through the bundled Artifex CMYK SWOP profile via lcms2. If the input image has an embedded ICC profile (AdobeRGB, Display P3, etc.) it is honored; otherwise sRGB is assumed. SWOP is calibrated for coated offset stock and runs ink heavy by design — pair it with lower --tac and higher --gamma. Choose this when handing files to an offset prepress workflow that expects SWOP separations.

Images that are already CMYK (e.g. CMYK TIFFs) are used as-is with either setting.

Tuning dot weight (--gamma)

Gamma reshapes how ink density maps to dot size, exactly like a press operator adjusting for dot gain:

  • --gamma 1.0 — straight mapping; dense, heavy plates
  • --gamma 1.5 — the default; opens highlights into clean dot gradients
  • --gamma 2.0 — light and airy; can blow out highlights on bright images
  • Below 1.0 — pushes coverage heavier (bold, inky look)

Dark, shadow-heavy images often benefit from 1.5–2.0 to recover detail. Bright images may want 1.0–1.3. There is no upper clamp — but beyond ~3.0 most images lose too much ink to read.

Limiting total ink (--tac)

Total Area Coverage caps the sum C+M+Y+K per pixel, scaling all four channels down proportionally (hue is preserved). Guidelines: screen printing 160–200, risograph 180–220, coated offset up to 300. The default 220 suits most screen/riso work.

Setting dot density (--dots) and LPI

Because Rosette outputs SVG, LPI is not fixed at generation time — it's determined by how large you print the file. The relationship is simple:

--dots = target LPI × print width in inches

Target LPI 4" wide 5" wide 8.5" wide 11" wide 17" wide
35 lpi 140 175 298 385 595
45 lpi 180 225 383 495 765
55 lpi 220 275 468 605 935
65 lpi 260 325 553 715 1105
85 lpi 340 425 723 935 1445

Typical ranges by process: screen printing 35–65 lpi · risograph 50–106 lpi · offset 85–150 lpi.

Image resolution note: for clean dot gradients, your input image should be at least --dots × 2 pixels wide. Below that, cell size drops under 2px and the blur/sampling pipeline has too little data to work with.

About sample.png

sample.png is a quick composite of all active channels rendered at a fixed scale — --dots × 4 pixels wide — so each dot cell is about 4px across and the image reads correctly at 100% zoom regardless of input resolution. Use it to sanity-check dot size, screen angles, and tonal range before opening the SVG plates.

It is a calibration aid, not a print proof: it approximates ink overlap with a simple CMYK→RGB conversion and won't match the color fidelity of a press proof or a dedicated raster halftone tool. Judge final quality from the SVG plates themselves.

Examples

# Basic — math profile, US angles, 100 dots per row, gamma 1.5
rosette photo.jpg

# Higher density, EU angle preset
rosette photo.jpg --preset eu --dots 150

# Dark image — open up the shadows
rosette nightshot.jpg --dots 150 --gamma 1.75

# ICC SWOP separation for offset prepress, with ink limiting
rosette photo.jpg --profile swop --tac 180 --gamma 1.5

# CMY only, no black plate, custom output directory
rosette photo.jpg --channels cmy --output ./separations

# High-density black-only plate (single-color screen print)
rosette photo.jpg --channels k --dots 200 --output ./black-plate

# Manual screen angles
rosette photo.jpg --angles 15 75 0 45

# Package everything into a ZIP
rosette photo.jpg --zip

CMYK Screen Angles

Halftone screens are rotated to prevent moiré patterns when the four color layers overlap. The classic approach assigns each channel a different angle:

Preset C M Y K Notes
us 15 75 0 45 US standard — default
eu 15 45 0 75 European standard
alt-a 15 45 30 45
alt-b 45 15 0 75
alt-c 45 75 0 15
alt-d 75 15 0 45
alt-e 75 45 0 15
alt-f 75 15 60 45

Why it matters: when two halftone screens at similar angles are overlaid, their dot patterns interfere and produce a visible grid artifact (moiré). Traditional offset printing separates the dominant inks (K and M) by 30°, with C 15° from K and Y on the least-visible 0° angle. Different presets trade off moiré characteristics — try eu if us shows artifacts on your specific press or paper.

For risograph and screen printing, angle choice also affects ink mixing behavior. Experimenting with the alt presets can produce different visual texture in overlapping color areas.


How It Works

  1. Load and convert — Pillow opens the image and converts RGB to CMYK using the selected --profile: the geometric math formula (default), or ICC conversion through the bundled Artifex SWOP profile via ImageCms/lcms2 (honoring any embedded input profile). CMYK input files skip conversion entirely.
  2. TAC limiting — any pixel where C+M+Y+K exceeds the --tac threshold is scaled down proportionally, preserving hue.
  3. Pre-blur — each channel is Gaussian-blurred at radius = cell_size/2 before sampling, smoothing tonal transitions into clean dot gradients.
  4. Rotated grid — a dot grid is generated at the channel's screen angle, sized to cover the full image diagonal so no edge is missed at any rotation.
  5. Sampling — each dot's ink density is sampled from the blurred channel at the dot centre using the --resample kernel (bilinear by default).
  6. Gamma & radius mapping — density passes through the --gamma curve, then maps to dot radius with area-proportional (square-root) scaling so ink coverage stays linear with density. Maximum radius is cell_size × 0.47, keeping adjacent dots from merging in SVG solid-fill rendering.
  7. Output — each channel becomes a standalone SVG of <circle> elements on a transparent background, plus a fixed-scale sample.png composite for calibration.

License

AGPL-3.0-or-later. See LICENSE.

Acknowledgements

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rosette_halftone-1.0.1.tar.gz (162.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rosette_halftone-1.0.1-py3-none-any.whl (157.5 kB view details)

Uploaded Python 3

File details

Details for the file rosette_halftone-1.0.1.tar.gz.

File metadata

  • Download URL: rosette_halftone-1.0.1.tar.gz
  • Upload date:
  • Size: 162.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for rosette_halftone-1.0.1.tar.gz
Algorithm Hash digest
SHA256 e0cec199758b4dc207a487a553bdee62232f8b25b35b0df4f09be85b983da73a
MD5 7916d6f3aba035285f37b8d85b1d7a0d
BLAKE2b-256 2227e6ed9416943fe7b628447cd3e2f4489b13f08479878e69afd9ec0352da14

See more details on using hashes here.

File details

Details for the file rosette_halftone-1.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for rosette_halftone-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 72baa25e3f4852dda0d6eb85977ecabf77f93660904224804b11dc2c8182f2ff
MD5 cb1d573aa268fc6ad95b96ed30b2412a
BLAKE2b-256 192bf1f4ab71fd1b9a6371c0239fc5a42e4d66c2cdc6a4ce65e4d01ca2a4dc38

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page