Fix impression pellicule : la feuille -div2 doit etre envoyee a taille pleine
La PageSize CUPS w288h432-div2 declare la meme taille de page que w288h432 (confirme par le PPD Mitsubishi) : le K60 coupe la feuille pleine apres impression, il ne duplique pas une image fournie a taille reduite. On envoyait la bande seule (600x1800) sous cette PageSize, donc CUPS l'etirait pour remplir la feuille 1200x1800 puis le K60 la coupait en 2 — d'ou la photo etiree et coupee au lieu de 2 bandes identiques. Ajoute aussi le miroir horizontal sur le preview live (selfie) et un flou de chargement pendant le bref delai de remontee du miroir DSLR apres capture, pour eviter l'impression d'image figee sur la photo precedente.
This commit is contained in:
@@ -15,8 +15,13 @@ FORMATS = {
|
|||||||
"10x15": {"cups": "w288h432", "px": (1200, 1800)},
|
"10x15": {"cups": "w288h432", "px": (1200, 1800)},
|
||||||
"15x15": {"cups": "w432h432", "px": (1800, 1800)},
|
"15x15": {"cups": "w432h432", "px": (1800, 1800)},
|
||||||
"15x20": {"cups": "w432h576", "px": (1800, 2400)},
|
"15x20": {"cups": "w432h576", "px": (1800, 2400)},
|
||||||
"10x15-2up": {"cups": "w288h432-div2", "px": (600, 1800)}, # 1 strip 5x15cm, printer duplique
|
# "-div2" declare en CUPS la MEME taille de page que le format plein (le PPD le confirme :
|
||||||
"15x20-2up": {"cups": "w432h576-div2", "px": (900, 2400)}, # 1 strip 7.5x20cm, printer duplique
|
# PaperDimension identique pour w288h432 et w288h432-div2). Le K60 ne duplique pas une
|
||||||
|
# image fournie a taille reduite : il imprime la feuille entiere telle qu'envoyee puis la
|
||||||
|
# coupe en 2 apres impression. "px" = taille d'une bande seule, "px_page" = feuille entiere
|
||||||
|
# a envoyer a lp (bande dupliquee cote a cote par _dupliquer_page).
|
||||||
|
"10x15-2up": {"cups": "w288h432-div2", "px": (600, 1800), "px_page": (1200, 1800)},
|
||||||
|
"15x20-2up": {"cups": "w432h576-div2", "px": (900, 2400), "px_page": (1800, 2400)},
|
||||||
}
|
}
|
||||||
|
|
||||||
ERREUR_FICHIER = "fichier_introuvable"
|
ERREUR_FICHIER = "fichier_introuvable"
|
||||||
@@ -104,6 +109,22 @@ def _preparer_image(chemin: Path, largeur: int, hauteur: int,
|
|||||||
return Path(tmp.name)
|
return Path(tmp.name)
|
||||||
|
|
||||||
|
|
||||||
|
def _dupliquer_page(chemin: Path, taille_page: tuple[int, int]) -> Path:
|
||||||
|
"""Colle la bande 2 fois cote a cote pour remplir la feuille entiere.
|
||||||
|
|
||||||
|
Necessaire pour les formats "-div2" : le K60 coupe la feuille imprimee en 2
|
||||||
|
apres impression, il ne duplique pas une image fournie a taille reduite.
|
||||||
|
"""
|
||||||
|
from PIL import Image
|
||||||
|
img = Image.open(chemin)
|
||||||
|
page = Image.new("RGB", taille_page, (255, 255, 255))
|
||||||
|
page.paste(img, (0, 0))
|
||||||
|
page.paste(img, (img.width, 0))
|
||||||
|
tmp = tempfile.NamedTemporaryFile(suffix=".jpg", delete=False)
|
||||||
|
page.save(tmp.name, "JPEG", quality=95, dpi=(300, 300))
|
||||||
|
return Path(tmp.name)
|
||||||
|
|
||||||
|
|
||||||
def _statut(nom: str) -> str:
|
def _statut(nom: str) -> str:
|
||||||
"""Retourne 'idle', 'printing', 'stopped' ou 'inconnue'."""
|
"""Retourne 'idle', 'printing', 'stopped' ou 'inconnue'."""
|
||||||
code, out, _ = _run(["lpstat", "-p", nom])
|
code, out, _ = _run(["lpstat", "-p", nom])
|
||||||
@@ -205,7 +226,13 @@ def imprimer(
|
|||||||
return {"succes": False, "erreur": ERREUR_FICHIER, "message": "Fichier photo introuvable"}
|
return {"succes": False, "erreur": ERREUR_FICHIER, "message": "Fichier photo introuvable"}
|
||||||
|
|
||||||
chemin_print = _preparer_image(chemin_photo, largeur, hauteur, fmt_base, cadre, orientation)
|
chemin_print = _preparer_image(chemin_photo, largeur, hauteur, fmt_base, cadre, orientation)
|
||||||
tmp_cree = chemin_print != chemin_photo
|
tmp_a_supprimer = [chemin_print] if chemin_print != chemin_photo else []
|
||||||
|
|
||||||
|
px_page = fmt.get("px_page")
|
||||||
|
if px_page:
|
||||||
|
chemin_page = _dupliquer_page(chemin_print, px_page)
|
||||||
|
tmp_a_supprimer.append(chemin_page)
|
||||||
|
chemin_print = chemin_page
|
||||||
|
|
||||||
if _statut(imprimante) == "stopped":
|
if _statut(imprimante) == "stopped":
|
||||||
log.warning(f"Imprimante {imprimante} arrêtée — réactivation")
|
log.warning(f"Imprimante {imprimante} arrêtée — réactivation")
|
||||||
@@ -261,5 +288,5 @@ def imprimer(
|
|||||||
"message": "Impression échouée après 3 tentatives",
|
"message": "Impression échouée après 3 tentatives",
|
||||||
}
|
}
|
||||||
finally:
|
finally:
|
||||||
if tmp_cree:
|
for tmp in tmp_a_supprimer:
|
||||||
chemin_print.unlink(missing_ok=True)
|
tmp.unlink(missing_ok=True)
|
||||||
|
|||||||
@@ -325,6 +325,11 @@ html, body {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
|
transform: scaleX(-1); /* miroir selfie : ce que voit l'utilisateur en se posant */
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-live img.preview-chargement {
|
||||||
|
filter: blur(8px) brightness(0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cadre-guide-recadrage {
|
.cadre-guide-recadrage {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||||||
<meta name="google" content="notranslate">
|
<meta name="google" content="notranslate">
|
||||||
<meta http-equiv="Content-Language" content="fr">
|
<meta http-equiv="Content-Language" content="fr">
|
||||||
<link rel="stylesheet" href="/css/style.css?v=3">
|
<link rel="stylesheet" href="/css/style.css?v=4">
|
||||||
<link rel="stylesheet" href="/css/themes.css">
|
<link rel="stylesheet" href="/css/themes.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -739,7 +739,7 @@
|
|||||||
|
|
||||||
<script src="/js/websocket.js?v=3"></script>
|
<script src="/js/websocket.js?v=3"></script>
|
||||||
<script src="/js/app.js?v=4"></script>
|
<script src="/js/app.js?v=4"></script>
|
||||||
<script src="/js/camera.js?v=8"></script>
|
<script src="/js/camera.js?v=9"></script>
|
||||||
<script src="/js/effects.js?v=3"></script>
|
<script src="/js/effects.js?v=3"></script>
|
||||||
<script src="/js/gallery.js?v=3"></script>
|
<script src="/js/gallery.js?v=3"></script>
|
||||||
<script src="/js/share.js?v=5"></script>
|
<script src="/js/share.js?v=5"></script>
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ function lancerPreview() {
|
|||||||
if (previewActif) return;
|
if (previewActif) return;
|
||||||
previewActif = true;
|
previewActif = true;
|
||||||
afficherErreurPreview(false);
|
afficherErreurPreview(false);
|
||||||
|
// Flou le temps que la 1ere frame fraiche arrive (le miroir DSLR doit remonter
|
||||||
|
// apres la capture precedente) : evite l'impression d'image figee sur l'ancienne photo.
|
||||||
|
document.getElementById('img-preview')?.classList.add('preview-chargement');
|
||||||
wsEnvoyer({ type: 'preview_start' });
|
wsEnvoyer({ type: 'preview_start' });
|
||||||
resetPreviewTimeout();
|
resetPreviewTimeout();
|
||||||
}
|
}
|
||||||
@@ -72,7 +75,10 @@ wsOnMessage('preview', (msg) => {
|
|||||||
if (!previewActif) return;
|
if (!previewActif) return;
|
||||||
const img = document.getElementById('img-preview');
|
const img = document.getElementById('img-preview');
|
||||||
if (img) {
|
if (img) {
|
||||||
img.onload = positionnerGuideRecadrage;
|
img.onload = () => {
|
||||||
|
img.classList.remove('preview-chargement');
|
||||||
|
positionnerGuideRecadrage();
|
||||||
|
};
|
||||||
img.src = msg.image;
|
img.src = msg.image;
|
||||||
}
|
}
|
||||||
afficherErreurPreview(false);
|
afficherErreurPreview(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user