Files
Jules NényandClaude Opus 5.5 731531dbe2 Test axonométrique du 27/09 : pipeline de fabrication et prototype
pipeline/axo : extraction du Rhino, recalage sur la planche (1:640), maisons,
arbres (positions réelles des blocs, couleurs de la planche), scène en mètres,
sols depuis le PDF Illustrator vectoriel (calques pilotés), bulles de la page 15,
planche de l'eau nettoyée. prototypes/axo-test : la page de test et son assembleur.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 16:46:14 +02:00

63 lines
3.4 KiB
Python

"""06 — Les deux sols du quartier (2035 et aujourd'hui), depuis le plan vectoriel Illustrator.
Entrées : TRANSFO_TOTAL.pdf (Illustrator, 155 calques), la planche de fond du concours (lavis),
la texture de papier aquarelle, transfo.json (recalage), scene.json (axes des routes).
Sorties : lignes2035.png, lignesauj.png, sol2035.jpg, solauj.jpg.
Principe : on éteint dans le PDF les calques qui deviendront des objets 3D (arbres, ombres,
personnages) ; pour « aujourd'hui », on éteint aussi tous les calques « 8_ NEW » et « 10_NEW ».
Le lavis (jardins vert pâle, routes grises, forêt ou champ) est multiplié sous les traits,
avec un grain de papier passe-haut (les grandes taches de la texture sont retirées).
Usage : python 06_sols.py <TOTAL.pdf> <texture_papier.jpeg> [dpi=155]
"""
import sys, json
import numpy as np
import pymupdf
from PIL import Image, ImageDraw, ImageFilter
PDF, PAPIER = sys.argv[1], sys.argv[2]
DPI = int(sys.argv[3]) if len(sys.argv) > 3 else 155
T = json.load(open("transfo.json")); s = T["s"] # px/m à 100 dpi
SC = json.load(open("scene.json"))
def rendre(eteindre, sortie):
doc = pymupdf.open(PDF)
for u in doc.layer_ui_configs():
if eteindre(u["text"]):
doc.set_layer_ui_config(u["number"], action=2) # 2 = éteint
doc[0].get_pixmap(dpi=DPI).save(sortie)
objets_3d = lambda t: any(k in t for k in ["FORET", "VEGETATION", "ombres", "OMBRES", "PERSOS", "Calque 37"]) or t == "0"
rendre(objets_3d, "lignes2035.png")
rendre(lambda t: objets_3d(t) or t.startswith("8_ NEW") or t.startswith("10_NEW"), "lignesauj.png")
L35 = Image.open("lignes2035.png").convert("RGB"); Wt, Ht = L35.size; k = Wt / 1654
tex = Image.open(PAPIER).convert("L").resize((Wt // 2, Ht // 2))
t = np.asarray(tex).astype(np.float32); lo = np.asarray(tex.filter(ImageFilter.GaussianBlur(14))).astype(np.float32)
g = np.clip((t - lo) / ((t - lo).std() + 1e-6), -2.5, 2.5)
g = np.asarray(Image.fromarray(((g + 2.5) / 5 * 255).astype(np.uint8)).resize((Wt, Ht), Image.BILINEAR)).astype(np.float32) / 255 - 0.5
pap = 1.0 + 0.035 * g
routes = {n: [(x * s + 827, z * s + 585) for x, z in pts] for n, pts in SC["routes"].items()}
largeur = {"principale": 9.5, "verticale": 7.5, "anneau": 6.5, "liaison_anneau": 6.5, "droite": 7.0}
foret = [(1335, 0), (1654, 0), (1654, 780), (1565, 752), (1160, 596), (1330, 40)] # relevé sur la planche
def lavis(couleur_est):
w = Image.new("RGB", (Wt, Ht), (239, 240, 219)); d = ImageDraw.Draw(w)
d.polygon([(x * k, y * k) for x, y in foret], fill=couleur_est)
for n, pts in routes.items():
wpx = largeur[n] * s * k
d.line([(x * k, y * k) for x, y in pts], fill=(229, 229, 224), width=int(wpx), joint="curve")
for x, y in pts:
d.ellipse([x * k - wpx / 2, y * k - wpx / 2, x * k + wpx / 2, y * k + wpx / 2], fill=(229, 229, 224))
return np.asarray(w.filter(ImageFilter.GaussianBlur(2))).astype(np.float32) * pap[..., None]
def composer(lignes, lav, sortie):
l = np.asarray(lignes.convert("RGB").resize((Wt, Ht))).astype(np.float32) / 255
Image.fromarray(np.clip(lav * l, 0, 255).astype(np.uint8)).save(sortie, quality=80, optimize=True, progressive=True)
composer(L35, lavis((226, 236, 212)), "sol2035.jpg") # forêt nourricière
composer(Image.open("lignesauj.png"), lavis((241, 236, 214)), "solauj.jpg") # aujourd'hui : un champ
print("sols écrits", Wt, "x", Ht)