Skip to content

More dithering algorithms for photo engraving (Stucki, Jarvis, Atkinson, Sierra, Burkes, halftone) #514

Closed

Description

@switch87

Is your feature request related to a problem? Please describe.
For photo engraving the Engrave step offers Floyd–Steinberg and Bayer 2/4/8 only. On a diode laser, error-diffusion kernels that spread the error wider (Stucki, Jarvis–Judice–Ninke) give a smoother, less "wormy" grain in flat areas such as skin tones, and Atkinson keeps more contrast on wood. LightBurn projects that use these modes (<ditherMode Value="stucki"/> in a CutSetting_Img) currently import without any dither setting at all, so the image layer falls back to the default mode.

Describe the solution you'd like

  • Extend DitherAlgorithm with the common error-diffusion kernels: Atkinson, Stucki, Jarvis–Judice–Ninke, Sierra (3-row), Sierra 2-row, Sierra Lite and Burkes.
  • Add two screen-based modes: a clustered-dot ordered dither ("Newsprint") and a classic halftone with round dots, where the cell size (mm) and screen angle are step settings.
  • A generic error-diffusion helper that takes the kernel, with an optional serpentine (alternating direction) scan. Floyd–Steinberg without serpentine keeps using raygeo.image.dither, so existing jobs produce identical output.
  • New Engrave-step rows, only visible where they apply: "Serpentine" for the error-diffusion algorithms, "Halftone Cell Size" and "Halftone Angle" for Halftone. Recipes and cache params follow the new fields.
  • Map LightBurn's ditherMode (and its halftone cells/angle) on import.

Describe alternatives you've considered
Dithering the photo in GIMP first works, but it is an extra step per photo, and the dither then no longer follows the step's spot size and line interval. The error-diffusion loop could also live in raygeo; I'm starting with a row-vectorised NumPy implementation in rayforge/image/dither.py (about 1 s for a 2 MP image, with the error spread to later rows done per row in NumPy) and I'm happy to move the kernels into raygeo if you'd rather have them there.

Additional context
I'm working on this and will report back with a branch.

Activity

  1. knipknap commented on Oct 9, 2026

    @knipknap
    Contributor

    Thanks for the detailed proposal. Expanding the dithering selection is long overdue — the wider error-diffusion kernels (Stucki, Jarvis) genuinely do give smoother flats on diode lasers, and Atkinson's contrast retention on wood is a real effect people ask for. The generic kernel-driven error-diffusion helper with optional serpentine is the right architecture, and keeping plain Floyd–Steinberg on the existing implementation so current jobs produce identical output is important.

    The two screen-based modes are a good addition: a clustered-dot ordered dither and a true halftone with cell size and angle as step settings cover the "newsprint" looks that error diffusion can't produce. Only showing the new rows where they apply, and extending recipes and cache params with the new fields, is exactly right.

    Mapping LightBurn's ditherMode on import fixes a real gap — those projects currently lose their dither setting entirely, which you've correctly identified.

    A row-vectorised NumPy implementation at about a second for 2 MP is acceptable; I'm open to moving the kernels into the geometry engine later if profiling says so, but there's no need to decide that up front. Please go ahead with the branch — happy to review.

  2. added
    rca-doneA root cause analysis was attached
    and removed on Oct 9, 2026
  3. switch87 commented on Oct 13, 2026

    @switch87
    ContributorAuthor

    Implemented in #534 (merged 2026-10-10): the Atkinson, Stucki, Jarvis-Judice-Ninke, Sierra and Burkes kernels with optional serpentine, the Newsprint and Halftone screens, and LightBurn's dither mode on import. Thanks for moving the implementation to raygeo. Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    rca-doneA root cause analysis was attached

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions