inkscape.isoCoucheGreyScale/README.md
2026-10-01 19:12:46 +02:00

254 lines
13 KiB
Markdown

# Iso-couches par nuances de gris — extension Inkscape
<table>
<tr>
<td width="50%" valign="top">
<img src="docs/exemple.png" alt="Une image de relief flou, sa découpe en 16 niveaux de gris, et les mêmes 16 niveaux au trait seul" width="420">
</td>
<td valign="top">
Extension Inkscape 1.x qui transforme une image bitmap en planches à découper
et à empiler, un calque par nuance de gris. L'image est lissée, quantifiée en quelques
niveaux (16 par défaut), puis chaque aplat est bordé d'un contour fermé et
souple, à la manière des courbes de niveau d'une carte. Le résultat se découpe
en strates (une feuille par niveau) ou se réduit à un dessin au trait.
De gauche à droite : l'image de départ, ses 16 niveaux remplis chacun de son
gris (16 calques), et les mêmes 16 niveaux en remplissage blanc et trait noir.
</td>
</tr>
</table>
Le lissage respecte les contours : sur un portrait, la peau et les cheveux sont
aplanis mais les yeux, la bouche et le bord du visage restent nets, et les
16 niveaux suffisent à reconstruire le visage.
## Sommaire
- [Fonctionnalités](#fonctionnalités)
- [Installation](#installation)
- [Utilisation](#utilisation)
- [Paramètres](#paramètres)
- [Structure du projet](#structure-du-projet)
- [Développement](#développement)
## Fonctionnalités
- Entrée : une ou plusieurs images bitmap sélectionnées (PNG, JPEG…),
incorporées ou liées, y compris dans un groupe sélectionné. Les couleurs sont
lues comme des gris, la transparence comme du blanc.
- Lissage qui respecte les contours (filtre guidé) : les textures sont
aplanies, les transitions marquées restent nettes, ce qui garde un visage
reconnaissable. Un flou gaussien simple reste disponible pour les reliefs
abstraits.
- Quantification à seuils réguliers, de 2 à 64 niveaux, après étirement de la
plage de gris de l'image.
- Contours tracés au sous-pixel sur l'image lissée (« marching squares »), puis
simplifiés et convertis en courbes de Bézier : pas d'escalier de pixels.
- Toutes les formes sont fermées : là où un niveau touche le bord de l'image,
son contour longe ce bord, en lignes droites.
- Un calque Inkscape par niveau, nommé « Planche n° 1 », « Planche n° 2 »…
du fond vers l'avant, créé au-dessus de l'image : autant de nouveaux calques
que de niveaux de gris. Plusieurs images sélectionnées partagent les mêmes
calques.
- Planches à empiler : la planche n° 1 couvre toute l'image et chaque planche
suivante, plus petite, se pose devant la précédente (la plus claire devant,
ou la plus sombre devant), pour construire un relief en strates.
- Repère d'assemblage : chaque planche porte, en plus de son trait de découpe
(rouge), le contour de la planche suivante (noir), au tracé exact de sa
découpe, pour savoir où la coller.
- Variante « Son gris seul » : chaque calque contient l'aplat de son gris,
bordé sur tous ses côtés ; les planches pavent l'image sans se recouvrir et
ne portent pas de repère. Les contours sont exactement les frontières de
l'image quantifiée.
- Formes écrites en coordonnées du document, sans transformation, même pour
une image tournée, étirée ou placée dans un calque transformé.
- Remplissage au choix (gris du niveau, couleur unique, aucun) et trait
facultatif.
- Interface traduite en français et en anglais, selon la langue d'Inkscape
(anglais pour toute autre langue).
- Script de déploiement Windows.
## Installation
Aucune dépendance à installer : l'extension utilise `inkex`, `numpy` et
`Pillow`, tous fournis avec Inkscape.
### Windows
```powershell
.\deploy.ps1 # copie dans %APPDATA%\inkscape\extensions\GrayIsoLayers
.\deploy.ps1 -Uninstall # retire l'extension
.\deploy.ps1 -Force # déploie même si Inkscape est ouvert
```
Inkscape doit être fermé pendant la copie, puis relancé.
### Manuelle
Copier dans un sous-dossier du répertoire des extensions utilisateur
(`%APPDATA%\inkscape\extensions` sous Windows, `~/.config/inkscape/extensions`
sous Linux, `~/Library/Application Support/org.inkscape.Inkscape/config/inkscape/extensions`
sous macOS) :
- `gray_iso_layers.inx`, `gray_iso_layers.py`, `gray_iso_layers_core.py` ;
- `images/parameters_en.png` ;
- le dossier `locale/`.
## Utilisation
1. Importer une image (**Fichier > Importer**) et la sélectionner.
2. Lancer **Extensions > AlexDesign > Iso-couches par nuances de gris…**
(*Gray Iso-Layers*).
3. Régler le nombre de niveaux et le lissage, puis **Appliquer**.
Le résultat est une série de calques « Planche n° 1 », « Planche n° 2 »…
ajoutés juste au-dessus du calque de l'image, un par niveau de gris. La
planche n° 1 est au fond, la dernière devant. Par défaut, les planches
s'empilent : la planche n° 1, la plus sombre, couvre toute l'image et les
suivantes se posent devant elle. Chaque calque contient deux chemins : la
« Découpe » de la planche (trait rouge) et le « Repère de la planche n° … »
suivante (trait noir, sans remplissage). Avec le contenu « Son gris seul »,
chaque planche est l'aplat de son gris et il n'y a pas de repère. Un niveau dont toutes
les formes sont plus petites que le plus petit îlot conservé garde son calque,
vide.
### Conseils
- **Découpe laser** : choisir « Aucun remplissage » ; il ne reste que les
traits de découpe (rouge) et de marquage (noir), à affecter chacun à son
réglage dans le logiciel de la machine. Découper un calque par feuille.
- **Dessin au trait, comme une carte topographique** : remplissage « Couleur
unique » blanche (ou « Aucun remplissage »), trait noir, repère décoché.
- **Contours trop chargés, petits îlots** : augmenter le lissage ou le plus
petit îlot conservé.
- **Contours anguleux** : augmenter le lissage ou la simplification.
- **Détails perdus, visage méconnaissable** : réduire le lissage (0,5 à 1 %),
laisser « Préserver les contours » coché, augmenter la résolution de calcul.
- **Portrait** : un fond uni donne le meilleur résultat ; un fond en dégradé
produit des anneaux, puisque chaque nuance du dégradé devient un aplat.
- **Image liée introuvable** : l'incorporer (clic droit > Incorporer l'image).
- Une image de bruit flou (nuages, relief) donne les motifs les plus proches
d'une carte de courbes de niveau.
## Paramètres
![Schéma des paramètres](docs/parametres.png)
Onglet **Niveaux**
| Paramètre | Défaut | Rôle |
| --- | --- | --- |
| Nombre de niveaux de gris | 16 | Nombre d'aplats, donc de calques produits (2 à 64). |
| Contenu de chaque planche | Empilées, la plus claire devant | « Empilées, la plus claire devant » : planche n° 1 = la plus sombre, toute l'image. « Empilées, la plus sombre devant » : planche n° 1 = la plus claire, toute l'image. « Son gris seul » : planches côte à côte, sans recouvrement, planche n° 1 = le gris le plus sombre. |
| Reporter sur chaque planche le contour de la suivante | oui | Repère d'assemblage tracé dans la couleur de marquage (planches empilées uniquement). |
| Lissage (% du grand côté de l'image) | 1 | Lissage appliqué avant la découpe : plus il est fort, plus les contours sont ronds et simples. |
| Préserver les contours lors du lissage | oui | Aplanit la peau et les textures mais garde nettes les transitions marquées (portraits, photos). Décoché : flou gaussien simple, mieux adapté aux reliefs abstraits. |
| Résolution de calcul (points sur le grand côté) | 800 | Taille à laquelle l'image est rééchantillonnée pour le calcul. |
| Plus petit îlot ou trou conservé (% de la surface de l'image) | 0,02 | Les formes plus petites sont écartées. |
| Simplification (points de calcul) | 0,4 | Écart maximal toléré lors de la suppression de nœuds ; 0 les conserve tous. |
| Lisser les contours avec des courbes de Bézier | oui | Sinon, les contours sont des polygones. |
Onglet **Style**
| Paramètre | Défaut | Rôle |
| --- | --- | --- |
| Remplissage | Gris de chaque niveau | Gris du niveau, couleur unique ou aucun remplissage. |
| Couleur de remplissage | blanc | Utilisée par le mode « Couleur unique ». |
| Épaisseur du trait (0 = sans trait) | 0,2 | Dans l'unité choisie ; commune à la découpe et au marquage. |
| Unité | mm | Unité de l'épaisseur du trait. |
| Couleur du trait de découpe | rouge | Contour de la planche. |
| Couleur du trait de marquage | noir | Repère de la planche suivante. |
| Conserver l'image d'origine | oui | Sinon l'image est supprimée. |
## Structure du projet
```text
gray_iso_layers.inx Boîte de dialogue (textes source en anglais)
gray_iso_layers.py Couche inkex : lecture de l'image, écriture du SVG
gray_iso_layers_core.py Noyau de calcul, sans inkex (numpy seul)
i18n.py Extraction / mise à jour / compilation des traductions
po/ Catalogues grayisolayers.pot, en.po, fr.po
locale/ Catalogues compilés (.mo), déployés
images/parameters_en.png Schéma de l'onglet « Help »
docs/schema_parametres.py Générateur du schéma (fr pour le README, en pour le dialogue)
docs/parametres.png Schéma du README
docs/exemple.png Illustrations du README (relief, portrait)
docs/exemple-portrait.png
doc/patern.jpg Motif qui a servi de modèle
doc/personne.jpg Portrait d'essai
test_gray_iso_layers.py Tests pytest
deploy.ps1 Déploiement / désinstallation Windows
```
API du noyau (`gray_iso_layers_core.py`). Un champ est un tableau numpy 2D de
gris (0 noir, 1 blanc) ; un anneau est un tableau `(n, 2)` de points, en
échantillons du champ.
| Fonction | Rôle |
| --- | --- |
| `gaussian_blur(field, sigma)` | Flou gaussien séparable, bords prolongés. |
| `box_blur(field, radius)` | Moyenne sur une fenêtre carrée. |
| `edge_preserving_blur(field, radius, contrast)` | Lissage qui respecte les contours (filtre guidé). |
| `smooth(field, blur, preserve_edges)` | Lissage avant découpe, puis étirement sur 0..1. |
| `normalize(field)` | Étire le champ sur 0..1. |
| `thresholds(levels)` | Seuils réguliers séparant les niveaux. |
| `contour_rings(field, threshold, above=True)` | Contours fermés de la région au-dessus (ou au-dessous) du seuil. |
| `ring_area(ring)` | Aire d'un anneau. |
| `simplify_ring(ring, tolerance)` / `simplify_chain(chain, tolerance)` | Simplification de Douglas-Peucker d'un anneau fermé, d'une ligne ouverte. |
| `contour_lines(field, threshold, tolerance, min_area)` | Ligne de niveau d'un seuil : boucles fermées et lignes ouvertes aboutissant au bord. |
| `region_rings(field, lines, inside)` | Contour fermé d'une région bornée par des lignes de niveau, refermé le long du bord de l'image. |
| `iso_boards(field, levels, blur, min_area, tolerance, shapes, preserve_edges)` | Une planche par niveau : liste de `(niveau, gris, anneaux, repère)`, le repère étant la ligne de niveau qui borde la planche suivante. |
| `iso_layers(…)` | Comme `iso_boards`, sans les repères. |
| `image_ring(width, height)` | Rectangle de l'image. |
| `scale_rings(rings, scale_x, scale_y, offset_x, offset_y)` | Passage au repère de destination. |
| `lines_to_d(lines, smooth, box, precision, matrix)` / `scale_lines(…)` | Écriture et mise à l'échelle d'une ligne de niveau (boucles fermées et lignes ouvertes). |
| `rings_to_d(rings, smooth, box, precision, matrix)` | Données `d` d'un chemin SVG, bords de l'image gardés droits, transformation affine facultative. |
| `parse_color(value)` / `gray_to_hex(gray)` | Couleurs. |
## Développement
```powershell
pip install pytest numpy pillow
python -m pytest -q
```
Sans `inkex` : 41 tests passent, 13 sont ignorés. Avec `inkex` :
```powershell
pip install lxml tinycss2 cssselect2 cssselect
$env:PYTHONPATH = 'C:\Program Files\Inkscape\share\inkscape\extensions'
python -m pytest -q # 54 tests passent
```
Les tests couvrent le noyau (lissage qui respecte les contours, contours d'un cône et d'une rampe, fermeture le
long des bords, cas selle, simplification, aplats conformes à l'image
quantifiée, frontières communes aux aplats voisins, feuilles à empiler, îlots
écartés, écriture des chemins), l'extension de bout en bout (un calque par niveau, repères d'assemblage, image incorporée, liée ou
tournée, groupe sélectionné, styles, messages d'erreur) et la cohérence des traductions et du
`.inx`.
### Traductions
Les textes source sont en anglais, dans le `.inx` et dans les `_("...")` du
`.py`. Après toute modification :
```powershell
python i18n.py # extrait, met à jour po/*.po, compile locale/
```
Compléter les `msgstr` vides de `po/fr.po`, puis relancer la commande. Pour
ajouter une langue, l'ajouter à `LANGUAGES` dans `i18n.py`.
### Schéma des paramètres
```powershell
python docs/schema_parametres.py
```
Produit `docs/parametres.png` (français, README) et `images/parameters_en.png`
(anglais, onglet « Help »), tracés avec les fonctions du noyau. L'export PNG
passe par `inkscape.com`.