# Changelog

All notable changes to this project are documented in this file.

# 1.0.4 - 2026-09-29

# Changed

  • Documentation only: the README's Documentation list links each page on the documentation site, so readers on GitHub and PyPI land there. The code is the same as 1.0.3.

# 1.0.3 - 2026-09-29

# Changed

  • Documentation only: the README becomes a short entrance to the documentation site at https://offerrall.github.io/pygrbl-build/, and docs/overview.md holds the introduction: the algorithms, speed, lazy output and pairing with pygrbl-streamer. docs/output.md merges into the overview, without the hand-kept list of public names.
  • New docs/limitations.md gathers what each algorithm does not do and the platforms with prebuilt wheels. The previous README said a C compiler was always required; it is needed only where no wheel exists.
  • RELEASING.md moves to docs/releasing.md.
  • Every example imports what it needs; the Bounds and framing example was missing svg_gcode and SvgProfile. The dead pygrbl-server link is gone.
  • pyproject.toml: [project.urls] with the documentation site, repository, issues and changelog; a Python 3.14 classifier, matching the wheels; a shorter description.
  • The code is the same as 1.0.2.

# 1.0.2 - 2026-09-29

# Changed

  • Metadata only: the distribution name is spelled pygrbl-build, PyPI's canonical form, in pyproject.toml and the docs. pip install pygrbl-build and import pygrbl_build are unchanged. The code is the same as 1.0.1, apart from the version in the G-code header (; pygrbl_build v1.0.2).

# 1.0.1 - 2026-09-29

# Changed

  • Documentation only: the README keeps an overview and a short example, the guides move to docs/ (raster, vector, bounds and framing, output), and the release notes for maintainers move to RELEASING.md. The README title no longer carries the version. The code is the same as 1.0.0.

# 1.0.0 - 2026-09-22

# Added

  • Jarvis raster engraving (jarvis_gcode + JarvisProfile): converts color or grayscale images to a 1-bit dot pattern using the Jarvis-Judice-Ninke error-diffusion kernel in C, then emits horizontal raster G-code through the existing native engine. Supports image paths, encoded bytes, bytearrays and Pillow images.
  • Jarvis settings for resolution, feed, laser power, grayscale formula and channel weights, brightness, contrast, white clip, bidirectional scanning, overscan and M3/M4 mode.
  • Regression tests for Jarvis diffusion at image edges, binary power, transparency, input formats and profile validation.

# Changed

  • Publishing a GitHub release now publishes the built distributions to PyPI after the wheel and source distribution jobs pass. The publish job checks that the release tag matches the package version. Pushes and manual runs continue to produce build artifacts only.

# Fixed

  • Profiles and framing G-code reject NaN and infinite numeric values before those values can reach generated G-code.

Jarvis currently supports horizontal raster passes. Its diffusion kernel follows LaserGRBL's behavior, while image resizing uses Pillow, so complete byte-for-byte parity with LaserGRBL is not guaranteed.

# 0.4.1 - 2026-09-09

# Changed

  • Line-to-Line raster output now uses GRBL's modal motion state: each scan row emits one G1 after its G0, then omits redundant G1 words from the remaining linear moves. Motion, power, coordinates, lazy iteration and constant-memory behaviour are unchanged while the serial payload is smaller.

# 0.4.0 - 2026-09-04

# Added

  • All image APIs (l2l_gcode, img2vector_gcode, and img2svg) now accept encoded image bytes, bytearray, and loaded PIL.Image.Image instances in addition to file paths.
  • svg_gcode now accepts SVG XML as str, bytes, or bytearray in addition to file paths.
  • In-memory inputs receive the same traceability header as paths: encoded bytes are hashed directly, while Pillow images are hashed from their mode, size, and pixel content.

# Changed

  • Exported ImageSource and SvgSource type aliases describing every accepted input.

# 0.3.0 - 2026-06-19

# Added

  • G-code bounds & framing (get_bounding_box + generate_framing_gcode): the gcode-bounds library folded in as a second C extension (_gcode_parser), same C parser as the original (fast_atof + line scan, 500MB+ files in seconds). get_bounding_box computes the (min_x, max_x, min_y, max_y) extent of some G-code; generate_framing_gcode traces that box (the framing pass) so the operator can confirm placement before engraving. Rapid moves to the origin (G0 with X0/Y0) are skipped so the library's own home moves don't expand the box.
  • get_bounding_box accepts the G-code as a file path (str/Path, opened and streamed in C) or as raw content already in memory (bytes/bytearray, or a multi-line str), so it no longer has to exist on disk. The Python wrapper decides which route to take; a new C entry point (get_bounding_box_buffer) parses the in-memory buffer with the same per-line logic as the file path.

# 0.2.0 - 2026-06-16

# Added

  • Image to SVG algorithm (img2svg + Img2SvgProfile): traces a raster image to a standard vector SVG, reusing the same Potrace core and image preprocessing as img2vector_gcode but skipping the biarc/G-code stages. The contours are written as a single filled <path> with fill-rule="evenodd", so inner contours become holes (the filled black silhouette potrace.exe produces). viewBox is in pixels while width/height carry the physical size in mm, and the bitmap is not Y-flipped, keeping the image's natural top-down orientation. Img2SvgProfile carries only the tracing and binarization knobs (no feed/power/laser-mode fields). Pure Python, Pillow only.

# 0.1.0 - 2026-06-16

# Added

  • Image vector algorithm (img2vector_gcode + Img2VectorProfile): outline tracing from a raster image, a faithful Python port of LaserGRBL's "Vectorize!" mode. The image is reduced to black/white (resize, grayscale, white-clip, optional threshold), Potrace traces its outlines as closed contours, and each cubic Bezier is approximated by biarcs and emitted as G2/G3 arcs (with a G1 fallback). Pure Python, Pillow only. Outlines only — interior filling is not ported yet.