Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__pycache__/
18 changes: 18 additions & 0 deletions QUICKSTART.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,24 @@ find . -name "*.pcx" | python3 punchcard-generator.py --stitches 24 --layout mot
- `-d ./output` preserve subfolder structure in output folder
- `--threshold 220` change punch sensitivity
- `--invert` invert pixel-to-punch behavior
- `--jacquard {none,doublebed,birdseye,tuck}` double bed jacquard mode

## 6) Double bed jacquard

For double bed jacquard knitting the punchcard rows are doubled — each design row becomes two punchcard rows (pattern row + backing row). Three backing styles are available:

```bash
# Solid/full-jacquard backing (all stitches punched on backing row)
python3 punchcard-generator.py design.png 24 motif 6 --jacquard doublebed

# Bird's eye backing (alternating checkerboard on backing row)
python3 punchcard-generator.py design.png 24 motif 6 --jacquard birdseye

# Tuck-stitch backing (inverse of pattern on backing row)
python3 punchcard-generator.py design.png 24 motif 6 --jacquard tuck
```

> A 6-row design with `--jacquard doublebed` produces a 12-row card.

## Troubleshooting 🔧

Expand Down
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ This uttility generates SVG files, usable in most diecutting machines, for punch
- 🧵 Supports 12-stitch and 24-stitch card widths
- 🔁 Layout modes: `auto`, `motif`, and `repeat`
- 📏 Vertical repeats for longer pattern runs
- 🧶 Double bed jacquard modes: `doublebed`, `birdseye`, and `tuck`
- 🧪 Batch processing from shell globs and stdin
- ⚙️ Threshold and inversion controls for image-to-punch mapping

Expand Down Expand Up @@ -87,6 +88,7 @@ find . -name "*.pcx" | python3 punchcard-generator.py --stitches 24 --layout mot
- `--stitches {12,24}` card width (default `24`)
- `--layout {auto,motif,repeat}` layout mode (default `auto`)
- `--repeat-height N` vertical repeats (default `1`)
- `--jacquard {none,doublebed,birdseye,tuck}` double bed jacquard mode (default `none`)
- `--threshold 0-255` image threshold (default `255`)
- `--invert` invert punched and non-punched spaces on the card
- `--hole-ratio 0-1` hole size ratio (default `0.55`)
Expand All @@ -97,6 +99,23 @@ find . -name "*.pcx" | python3 punchcard-generator.py --stitches 24 --layout mot
- `repeat`: tiles design across width (design width must divide by card width)
- `auto`: picks `motif` or `repeat` based on width compatibility

## 🧶 Double Bed Jacquard

Double bed jacquard uses both the main bed and the ribber to create a two-layer fabric. Each design row is split into two punchcard rows: the pattern row (colour selection) and a backing row. Use `--jacquard` to enable this mode:

- `none` (default): standard 1:1 punchcard
- `doublebed`: solid/full-jacquard backing — every stitch punched on the backing row
- `birdseye`: bird's eye backing — alternating checkerboard pattern on the backing row
- `tuck`: tuck-stitch backing — inverse of the pattern row on the backing row

```bash
python3 punchcard-generator.py design.png 24 motif 6 --jacquard doublebed
python3 punchcard-generator.py design.png 24 motif 6 --jacquard birdseye
python3 punchcard-generator.py design.png 24 motif 6 --jacquard tuck
```

> **Note:** Double bed jacquard doubles the number of rows on the card. A 6-row motif with `--jacquard doublebed` produces a 12-row card.

## 🤝 Contributing

Ideas, bug reports, and PRs are welcome.
Expand Down
63 changes: 62 additions & 1 deletion punchcard-generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,45 @@ def compose_card_rows(rows, card_stitches, card_layout, repeat_height):
raise ValueError(f"Unsupported card layout '{layout}'")


def build_double_bed_rows(rows, backing="doublebed"):
"""Transform card rows for double bed jacquard knitting.

Each pattern row is doubled into two punchcard rows:
- Row 1 (odd pass): the original pattern row (selects needles for colour A)
- Row 2 (even pass): a backing row whose style is chosen by ``backing``

Backing modes
-------------
doublebed : every stitch punched – solid / full-jacquard backing
birdseye : alternating x-/checkerboard backing (bird's eye)
tuck : inverse of the pattern row (tuck-stitch backing)
"""
if not rows:
return rows

width = len(rows[0])
result = []

for i, row in enumerate(rows):
result.append(row)

if backing == "doublebed":
result.append("x" * width)
elif backing == "birdseye":
# Checkerboard: phase shifts by 1 each pair so the backing forms a
# diagonal bird's eye grid across the fabric.
offset = i % 2
backing_row = "".join("x" if (j + offset) % 2 == 0 else "-" for j in range(width))
result.append(backing_row)
elif backing == "tuck":
tuck_row = "".join("-" if ch == "x" else "x" for ch in row)
result.append(tuck_row)
else:
raise ValueError(f"Unsupported double bed backing mode: '{backing}'")

return result


def write_brother_style_svg(
path,
rows,
Expand Down Expand Up @@ -326,6 +365,7 @@ def generate_punchcard(
card_stitches=None,
card_layout="auto",
card_repeat_height=1,
jacquard="none",
):
img = open_flattened_rgb_image(input_path)
rows, width_cells, height_cells = build_punch_rows(img, threshold=threshold, invert=invert)
Expand All @@ -346,6 +386,9 @@ def generate_punchcard(
)
output_width = card_stitches

if jacquard != "none":
output_rows = build_double_bed_rows(output_rows, backing=jacquard)

if punchcard_mode in ("text", "both"):
txt_path = output_base + ".punch.txt"
write_punch_text(txt_path, output_rows)
Expand Down Expand Up @@ -373,7 +416,8 @@ def generate_punchcard(
print(f"Created: {svg_path}")

if layout_used is not None:
print(f"Card layout: {layout_used}, width: {card_stitches}, rows: {len(output_rows)}")
jacquard_info = f", jacquard: {jacquard}" if jacquard != "none" else ""
print(f"Card layout: {layout_used}, width: {card_stitches}, rows: {len(output_rows)}{jacquard_info}")


def process_file(
Expand All @@ -389,6 +433,7 @@ def process_file(
stitches=24,
layout="auto",
repeat_height=1,
jacquard="none",
):
input_path = input_path.strip()
if not input_path or not os.path.exists(input_path):
Expand Down Expand Up @@ -416,6 +461,7 @@ def process_file(
card_stitches=stitches,
card_layout=layout,
card_repeat_height=repeat_height,
jacquard=jacquard,
)
except Exception as e:
print(f"Error on {input_path}: {e}", file=sys.stderr)
Expand Down Expand Up @@ -483,6 +529,19 @@ def process_file(
default=1,
help="Number of vertical repeats for card pattern. Default: 1.",
)
parser.add_argument(
"--jacquard",
choices=["none", "doublebed", "birdseye", "tuck"],
default="none",
help=(
"Double bed jacquard mode. Each pattern row is doubled: the original row"
" followed by a backing row. "
"none: standard 1:1 card (default). "
"doublebed: full/solid backing (all stitches punched). "
"birdseye: alternating checkerboard backing (bird's eye). "
"tuck: inverse of the pattern row (tuck-stitch backing)."
),
)
parser.add_argument("-help", action="help", help="Show this help message and exit.")

parser.add_argument(
Expand Down Expand Up @@ -561,6 +620,7 @@ def process_file(
stitches=stitches,
layout=layout,
repeat_height=repeat_height,
jacquard=args.jacquard,
)

# 2. Process files passed via pipe (e.g., find . -name '*.pcx' | punchcard)
Expand All @@ -579,6 +639,7 @@ def process_file(
stitches=stitches,
layout=layout,
repeat_height=repeat_height,
jacquard=args.jacquard,
)

# 3. If no input was provided via either method, show the help
Expand Down
Loading