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.2.tar.gz (162.2 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.2-py3-none-any.whl (157.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: rosette_halftone-1.0.2.tar.gz
  • Upload date:
  • Size: 162.2 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.2.tar.gz
Algorithm Hash digest
SHA256 b4631f4d331bbd0102e8fd6df16adf2ab87764964013ec270aa41b1cfd4bcdf9
MD5 42d016a39054e84d2cafa1250847d8f4
BLAKE2b-256 c6fb3dbeac6b0c8958e62ef0538192b85bce2ec96f6b8f4a44062b5184b2c47b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for rosette_halftone-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 479c613e25b7f995ec3a07b14831c725e65a16cc58b990a56f42c6bb22ceb498
MD5 29b51fa08e41211b901e056b599d4679
BLAKE2b-256 07f9a3edcc6caa633a801050ffd83c6ad2894936a7d21e7f0bba793a4873d763

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