mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-13 22:35:16 +03:00
Auto-build: opencode (powershell) from da6ac2b
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
---
|
||||
name: img-grid
|
||||
description: Наложить пронумерованную сетку на изображение. Используй при анализе скриншота макета или печатной формы — измерить пропорции колонок перед генерацией табличного документа
|
||||
argument-hint: <ImagePath> [-c COLS]
|
||||
allowed-tools:
|
||||
- Bash
|
||||
- Read
|
||||
---
|
||||
|
||||
# /img-grid — Сетка для анализа макета
|
||||
|
||||
Накладывает пронумерованную сетку на изображение печатной формы. Позволяет точно определить границы колонок, их пропорции и span-ы для генерации макета табличного документа.
|
||||
|
||||
## Использование
|
||||
|
||||
```
|
||||
/img-grid <ImagePath> [-c COLS] [-o OUTPUT]
|
||||
```
|
||||
|
||||
## Параметры
|
||||
|
||||
| Параметр | Обязательный | По умолчанию | Описание |
|
||||
|-----------|:------------:|--------------|-----------------------------------------------|
|
||||
| ImagePath | да | — | Путь к изображению (PNG, JPG) |
|
||||
| -c COLS | нет | 50 | Количество вертикальных делений |
|
||||
| -r ROWS | нет | авто | Количество горизонтальных делений (авто = квадратные ячейки) |
|
||||
| -o OUTPUT | нет | `<name>-grid.<ext>` | Путь для результата |
|
||||
|
||||
## Команда
|
||||
|
||||
```bash
|
||||
python ".opencode/skills/img-grid/scripts/overlay-grid.py" "<ImagePath>" [-c 50] [-o "<OutputPath>"]
|
||||
```
|
||||
|
||||
Требуется Python 3 с библиотекой Pillow (`pip install Pillow`).
|
||||
|
||||
## Что делает
|
||||
|
||||
1. Рисует полупрозрачные вертикальные (красные) и горизонтальные (синие) линии
|
||||
2. Нумерует линии в отдельных полях сверху и слева (не перекрывает содержимое)
|
||||
3. Каждая 5-я и 10-я линия выделены ярче для удобства счёта
|
||||
|
||||
## Как использовать результат
|
||||
|
||||
### 1. Определить границы колонок
|
||||
|
||||
Посмотреть на изображение с сеткой и записать координаты вертикальных границ каждой колонки таблицы (в номерах grid-линий).
|
||||
|
||||
### 2. Найти базовую решётку
|
||||
|
||||
Если на форме несколько таблиц с разной раскладкой (например, шапка документа и основная таблица), объединить все граничные точки. Каждый сегмент между соседними границами — одна колонка MXL.
|
||||
|
||||
Пример для М-11:
|
||||
- Шапка: границы 0, 2, 4, 9, 14, 21, 28, 34, 40, 48
|
||||
- Таблица: границы 0, 2, 4, 11, 16, 19, 23, 28, 32, 36, 42, 48
|
||||
- Объединение: 0, 2, 4, 9, 11, 14, 16, 19, 21, 23, 28, 32, 34, 36, 40, 42, 48
|
||||
- Результат: **16 базовых колонок** с пропорциями 2, 2, 5, 2, 3, 2, 3, 2, 2, 5, 4, 2, 2, 4, 2, 6
|
||||
|
||||
### 3. Записать в JSON DSL
|
||||
|
||||
```json
|
||||
{
|
||||
"columns": 16,
|
||||
"page": "A4-landscape",
|
||||
"columnWidths": {
|
||||
"1": "2x", "2": "2x", "3": "5x", "4": "2x", "5": "3x",
|
||||
"6": "2x", "7": "3x", "8": "2x", "9": "2x", "10": "5x",
|
||||
"11": "4x", "12": "2x", "13": "2x", "14": "4x", "15": "2x", "16": "6x"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Поле `"page"` позволяет компилятору автоматически вычислить абсолютные ширины из пропорций.
|
||||
|
||||
### 4. Скомпилировать
|
||||
|
||||
`/mxl-compile` → `/mxl-validate` → `/mxl-info`
|
||||
@@ -0,0 +1,115 @@
|
||||
"""Overlay a numbered grid on an image to help determine column/row proportions.
|
||||
|
||||
Usage: python overlay-grid.py <image> [-c COLS] [-r ROWS] [-o OUTPUT]
|
||||
|
||||
The grid helps an LLM count "squares" to determine exact column widths
|
||||
and positions when analyzing printed forms for MXL template generation.
|
||||
|
||||
Numbers are rendered in a dedicated margin band outside the image content,
|
||||
so they never overlap with the form and remain readable at any grid density.
|
||||
"""
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
MARGIN_TOP = 20
|
||||
MARGIN_LEFT = 24
|
||||
|
||||
|
||||
def main():
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
sys.stderr.reconfigure(encoding="utf-8")
|
||||
parser = argparse.ArgumentParser(description="Overlay numbered grid on image")
|
||||
parser.add_argument("image", help="Input image path")
|
||||
parser.add_argument("-c", "--cols", type=int, default=50,
|
||||
help="Number of vertical divisions (default: 50)")
|
||||
parser.add_argument("-r", "--rows", type=int, default=0,
|
||||
help="Number of horizontal divisions (0 = auto, match cell aspect ratio)")
|
||||
parser.add_argument("-o", "--output", help="Output path (default: <name>-grid.<ext>)")
|
||||
args = parser.parse_args()
|
||||
|
||||
src = Image.open(args.image).convert("RGBA")
|
||||
sw, sh = src.size
|
||||
|
||||
cols = args.cols
|
||||
step_x = sw / cols
|
||||
rows = args.rows
|
||||
if rows == 0:
|
||||
rows = round(sh / step_x)
|
||||
step_y = sh / rows
|
||||
|
||||
# Canvas with margins for labels
|
||||
cw = MARGIN_LEFT + sw
|
||||
ch = MARGIN_TOP + sh
|
||||
canvas = Image.new("RGBA", (cw, ch), (255, 255, 255, 255))
|
||||
canvas.paste(src, (MARGIN_LEFT, MARGIN_TOP))
|
||||
|
||||
overlay = Image.new("RGBA", (cw, ch), (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(overlay)
|
||||
|
||||
# Font for labels in margin
|
||||
label_font_size = 12
|
||||
try:
|
||||
label_font = ImageFont.truetype("arial.ttf", label_font_size)
|
||||
except Exception:
|
||||
label_font = ImageFont.load_default()
|
||||
|
||||
# --- Vertical lines + numbers in top margin ---
|
||||
for i in range(cols + 1):
|
||||
x = MARGIN_LEFT + round(i * step_x)
|
||||
major = i % 10 == 0
|
||||
mid = i % 5 == 0
|
||||
|
||||
alpha = 160 if major else (110 if mid else 40)
|
||||
lw = 2 if major else 1
|
||||
draw.line([(x, MARGIN_TOP), (x, ch)], fill=(255, 0, 0, alpha), width=lw)
|
||||
|
||||
# Labels: always show multiples of 5; show all if spacing allows
|
||||
show_label = major or mid or step_x >= 20
|
||||
if show_label:
|
||||
label = str(i)
|
||||
bbox = label_font.getbbox(label)
|
||||
tw = bbox[2] - bbox[0]
|
||||
tx = x - tw // 2
|
||||
ty = 2
|
||||
color = (200, 0, 0, 255) if (major or mid) else (200, 0, 0, 180)
|
||||
draw.text((tx, ty), label, fill=color, font=label_font)
|
||||
|
||||
# --- Horizontal lines + numbers in left margin ---
|
||||
for j in range(rows + 1):
|
||||
y = MARGIN_TOP + round(j * step_y)
|
||||
major = j % 10 == 0
|
||||
mid = j % 5 == 0
|
||||
|
||||
alpha = 160 if major else (110 if mid else 20)
|
||||
lw = 2 if major else 1
|
||||
draw.line([(MARGIN_LEFT, y), (cw, y)], fill=(0, 0, 200, alpha), width=lw)
|
||||
|
||||
show_label = major or mid or step_y >= 20
|
||||
if show_label:
|
||||
label = str(j)
|
||||
bbox = label_font.getbbox(label)
|
||||
tw = bbox[2] - bbox[0]
|
||||
tx = MARGIN_LEFT - tw - 3
|
||||
ty = y - label_font_size // 2
|
||||
color = (0, 0, 200, 255) if (major or mid) else (0, 0, 200, 180)
|
||||
draw.text((tx, ty), label, fill=color, font=label_font)
|
||||
|
||||
result = Image.alpha_composite(canvas, overlay).convert("RGB")
|
||||
|
||||
if args.output:
|
||||
out = args.output
|
||||
else:
|
||||
name, ext = os.path.splitext(args.image)
|
||||
out = f"{name}-grid{ext}"
|
||||
|
||||
result.save(out)
|
||||
print(f"Grid: {cols} x {rows} cells")
|
||||
print(f"Cell size: {step_x:.1f} x {step_y:.1f} px")
|
||||
print(f"Image: {sw} x {sh} px")
|
||||
print(f"Saved: {out}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user