Metadata-Version: 2.5
Name: cihuang
Version: 0.2.2
Summary: A PySide6 SVG editor: open an SVG, click any element to drag it, recolor it, edit its shape attributes or its text
Project-URL: Homepage, https://github.com/CodeOfMe/CiHuang
Project-URL: Documentation, https://github.com/CodeOfMe/CiHuang#readme
Project-URL: Repository, https://github.com/CodeOfMe/CiHuang.git
Project-URL: Issues, https://github.com/CodeOfMe/CiHuang/issues
Project-URL: Changelog, https://github.com/CodeOfMe/CiHuang/blob/main/CHANGELOG.md
Author-email: CodeOfMe <wedonotuse@outlook.com>
License-Expression: GPL-3.0-or-later
License-File: LICENSE
Keywords: annotation,drag-and-drop,editor,graphics,pyside6,qt,recolor,svg,vector-graphics
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: X11 Applications :: Qt
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: End Users/Desktop
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Multimedia :: Graphics
Classifier: Topic :: Multimedia :: Graphics :: Editors :: Vector-Based
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Requires-Dist: pyside6>=6.5.0
Provides-Extra: dev
Requires-Dist: build>=1.0.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
Requires-Dist: pytest>=7.0.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Requires-Dist: twine>=4.0.0; extra == 'dev'
Description-Content-Type: text/markdown

# CiHuang (雌黄) - SVG Element Editor

Click any single element of an SVG and move it, repaint it, reshape it, or rewrite its text.

> **CiHuang (雌黄)** is the yellow mineral scholars once used as correction fluid: you
> brush it over a wrong character and write the right one on top. This tool does the
> same to a drawing -- pick one piece, fix it, leave everything else untouched.

[中文说明](README_CN.md)

## Features

- **Open any SVG** -- a real SVG file is parsed as XML, not flattened to an image.
- **Click to select one element** -- hit-testing walks the elements in reverse paint
  order and tests actual pixels, so you select the shape you see, not its bounding box.
- **Select a group of things** -- Shift-click to add, or drag a marquee box around
  several shapes (for example a figure and its caption), then move them together.
- **Group / ungroup** -- `Ctrl+G` wraps the selection in a `<g>` (clicking then picks
  the whole group, like Inkscape); `Ctrl+Shift+G` dissolves it.
- **Smart Group** -- `Ctrl+Alt+G` clusters objects that sit close together (a figure
  and its caption, say) and groups them automatically.
- **No accidental backdrop grab** -- a click on a full-canvas background reads as a
  click on empty space; select the backdrop from the element list when you mean to.
- **Drag to move** -- the move is written as a `translate(...)` on that element only.
- **Draw new shapes** -- Rect, Ellipse, Line, Arrow and Text tools; pick one and drag
  on the canvas (a click drops a default-sized shape).
- **Connect shapes with arrows** -- the Connect tool draws an edge from one shape to
  another, and the edge follows the shapes when you move them.
- **Repaint** -- set `fill` and `stroke` with a color picker, or clear them to `none`.
- **Reshape** -- an editable table exposes every raw attribute (`cx`, `r`, `d`, `points`,
  `transform`, ...), so any geometry can be changed.
- **Edit text** -- rewrite the content of `<text>` elements.
- **Duplicate / delete / undo / redo**, save as SVG, export to PNG.
- **Scriptable** -- the same operations are available from the CLI, a Python API and an
  OpenAI function-calling tool set.

## Limitations

Worth knowing before you rely on it:

- Hit-testing renders each candidate to a raster capped at 900 px; only elements whose
  bounding box contains the click are rasterised, so it stays quick on large files.
- Editing `<text>` replaces any `<tspan>` children with a single text run.
- Grouping requires the selected elements to share the same parent; the tool does not
  re-order elements across groups.
- Connectors are straight lines between shape centres (clipped to the box edges);
  there is no orthogonal or obstacle-avoiding routing, and you cannot drag an edge's
  handles.
- It does not touch `viewBox`, stylesheets inside `<style>`, or animations.
- `<image>` and `<use>` can be moved and recolored but their referenced content is not
  edited.
- It is an annotator, not a full vector editor: no bezier-point editing, no snapping.

## Requirements

- Python 3.10+
- `PySide6` (installed automatically)

## Installation

From PyPI:

```bash
pip install cihuang
```

From source:

```bash
git clone https://github.com/CodeOfMe/CiHuang.git
cd CiHuang
pip install -e .
```

## Quick Start

```bash
# Open the graphical editor
cihuang gui examples/sample.svg

# Or just list the editable elements of a file
cihuang info examples/sample.svg
```

![CiHuang GUI](images/cihuang-gui.png)

## Usage

### GUI

```bash
cihuang gui drawing.svg
# or, equivalently:
cihuang-gui drawing.svg
```

Left mouse button selects and drags. Drag on empty space to marquee-select; hold
Shift to add to the selection. Middle button pans; the wheel zooms gently and is
limited so the drawing cannot shrink away. `Ctrl+G` groups the selection,
`Ctrl+Shift+G` ungroups it and `Ctrl+Alt+G` smart-groups nearby objects. The right
dock edits fill, stroke, text and raw attributes; the left dock lists every element.

Pick a **Draw** tool to add shapes: drag to size a rect or ellipse, drag a line or
arrow, click to drop text, or use **Connect** and drag from one shape to another to
link them with an arrow. `Esc` returns to Select.

### CLI

```bash
# List elements (add --json for machine output)
cihuang info drawing.svg

# Set the fill of element 3, writing drawing-edited.svg
cihuang fill drawing.svg 3 "#ff6600"

# Recolor the stroke instead, to an explicit output path
cihuang fill drawing.svg 3 "#003366" --stroke -o out.svg

# Clear an element's fill
cihuang fill drawing.svg 3

# Move element 1 by dx=20, dy=-5
cihuang move drawing.svg 1 20 -5

# Rewrite the text of element 5
cihuang text drawing.svg 5 "New label"

# Delete element 0
cihuang remove drawing.svg 0
```

## Python API

```python
from cihuang import SvgDocument, cihuang_set_color

# One-shot, writes drawing-edited.svg
result = cihuang_set_color(input_path="drawing.svg", element_index=3, color="#ff6600")
print(result.success)   # True / False
print(result.data)      # {"output": "...", "index": 3, "prop": "fill", "color": "#ff6600"}

# Or drive the document directly, then save wherever you like
doc = SvgDocument.load("drawing.svg")
doc.push_undo()
doc.set_color(3, "fill", "#ff6600")
doc.translate(3, 20, -5)
doc.set_text(5, "New label")
doc.save("out.svg")
```

## Agent Integration

The `TOOLS` list exposes the same operations for OpenAI function calling.

```python
from cihuang.tools import TOOLS, dispatch

payload = dispatch("cihuang_inspect", {"input_path": "drawing.svg"})
print(payload["success"])
```

## Development

```bash
pip install -e ".[dev]"
ruff format . && ruff check . && pytest
```

## License

GPL-3.0-or-later. See [LICENSE](LICENSE).
