Raster inputs use placeholder stitch generator (silently produces degenerate output) #77

Closed
opened 2026-06-24 00:11:39 +00:00 by Mark · 0 comments
Owner

Bug

EmbroideryPipeline._emit_machine_file() (in src/main_pipeline.py) has this branch:

if from_raster:
    stitches = convert_to_stitches(paths, config)
else:
    stitches = self._generate_stitches_from_paths(paths, config)
    ...

The from_raster=True branch calls convert_to_stitches() from src/embroidery_converter/stitch_generator.py, which is a stub:

def convert_to_stitches(paths: list[PathData], config: dict) -> list[tuple[float, float, str]]:
    # Placeholder implementation
    # This will be replaced with the actual conversion logic
    stitches = []
    for path in paths:
        for x, y in path.coordinates:
            stitches.append((x, y, "normal"))
    return stitches

It returns every SVG coordinate as a "normal" stitch. No satin, no fill differentiation, no pull compensation, no underlay. Output looks correct superficially (a PES file is produced) but the stitches are wrong: not what a real embroidery machine expects, and not what the SAAS service contract claims to deliver.

Impact

This is the primary path for the SAAS service — uploads are rasters (PNG/JPG), not SVG. Every digitize from the service would silently produce degenerate output if this branch ran.

The branch is in _emit_machine_file() which is called by process_bytes(). It's also the natural target of the new digitize_to_stitches() method (separate issue), so the bug propagates.

Fix

Remove the from_raster branch entirely. Type-aware generation (_generate_stitches_from_paths) should run for both raster-derived SVG and direct SVG input. Raster conversion produces SVG that should be classified like any other SVG.

If there's a reason from_raster was treated differently (e.g. performance, file-size blowup), capture that in the comment but keep type-aware generation as the default.

Also fix convert_to_stitches() — either:

  • Implement it properly so it does type-aware generation itself (delegating to the type-aware generators), or
  • Remove it entirely and have callers use _generate_stitches_from_paths.

Acceptance

  • A raster input produces stitch objects with type in {satin, fill, running} (not all normal).
  • tests/test_main.py covers raster->digitize end-to-end and asserts non-trivial stitch-type distribution.
  • The _emit_machine_file function no longer references from_raster for stitch generation decisions.

Blocks

  • Mark/easystitch-service#1 — service contract requires stitchObjects[].type in {satin, fill, running}. Without this fix, every raster input to the service would produce wrong output.

Notes

  • The bug's hiding mechanism is the placeholder comment "This will be replaced with the actual conversion logic" — at some point that replacement was forgotten.
  • The from_raster flag may still be useful for other decisions (e.g. SVG cleanup heuristics) but not for stitch generation.
## Bug `EmbroideryPipeline._emit_machine_file()` (in `src/main_pipeline.py`) has this branch: ```python if from_raster: stitches = convert_to_stitches(paths, config) else: stitches = self._generate_stitches_from_paths(paths, config) ... ``` The `from_raster=True` branch calls `convert_to_stitches()` from `src/embroidery_converter/stitch_generator.py`, which is a **stub**: ```python def convert_to_stitches(paths: list[PathData], config: dict) -> list[tuple[float, float, str]]: # Placeholder implementation # This will be replaced with the actual conversion logic stitches = [] for path in paths: for x, y in path.coordinates: stitches.append((x, y, "normal")) return stitches ``` It returns every SVG coordinate as a `"normal"` stitch. **No satin, no fill differentiation, no pull compensation, no underlay.** Output looks correct superficially (a PES file is produced) but the stitches are wrong: not what a real embroidery machine expects, and not what the SAAS service contract claims to deliver. ## Impact This is the primary path for the SAAS service — uploads are rasters (PNG/JPG), not SVG. Every digitize from the service would silently produce degenerate output if this branch ran. The branch is in `_emit_machine_file()` which is called by `process_bytes()`. It's also the natural target of the new `digitize_to_stitches()` method (separate issue), so the bug propagates. ## Fix Remove the `from_raster` branch entirely. Type-aware generation (`_generate_stitches_from_paths`) should run for both raster-derived SVG and direct SVG input. Raster conversion produces SVG that should be classified like any other SVG. If there's a reason `from_raster` was treated differently (e.g. performance, file-size blowup), capture that in the comment but keep type-aware generation as the default. Also fix `convert_to_stitches()` — either: - Implement it properly so it does type-aware generation itself (delegating to the type-aware generators), or - Remove it entirely and have callers use `_generate_stitches_from_paths`. ## Acceptance - A raster input produces stitch objects with `type in {satin, fill, running}` (not all `normal`). - `tests/test_main.py` covers raster->digitize end-to-end and asserts non-trivial stitch-type distribution. - The `_emit_machine_file` function no longer references `from_raster` for stitch generation decisions. ## Blocks - `Mark/easystitch-service#1` — service contract requires `stitchObjects[].type in {satin, fill, running}`. Without this fix, every raster input to the service would produce wrong output. ## Notes - The bug's hiding mechanism is the placeholder comment "This will be replaced with the actual conversion logic" — at some point that replacement was forgotten. - The `from_raster` flag may still be useful for *other* decisions (e.g. SVG cleanup heuristics) but not for stitch generation.
Mark closed this issue 2026-06-24 13:49:02 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Mark/easystitch#77
No description provided.