Fix déformation photos + miroir Canon EOS
- _pfit() : helper scale+crop centré pygame sans déformer - ImageOps.fit() partout : vignettes, galerie, composite (recadrage centré au lieu de resize qui écrase) - eosremoterelease 'Immediate' : déclenche l'obturateur Canon en restant en LV, évite la levée/baisse de miroir à chaque prise Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -91,6 +91,18 @@ THEMES = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ── Helpers image ────────────────────────────────────────────────────────────
|
||||||
|
def _pfit(surf, w, h):
|
||||||
|
"""Scale + crop centré d'une surface pygame pour remplir (w, h) sans déformer."""
|
||||||
|
sw, sh = surf.get_size()
|
||||||
|
if sw == w and sh == h:
|
||||||
|
return surf
|
||||||
|
scale = max(w / sw, h / sh)
|
||||||
|
nw, nh = max(w, int(sw * scale)), max(h, int(sh * scale))
|
||||||
|
scaled = pygame.transform.scale(surf, (nw, nh))
|
||||||
|
x, y = (nw - w) // 2, (nh - h) // 2
|
||||||
|
return scaled.subsurface((x, y, w, h)).copy()
|
||||||
|
|
||||||
# ── Utilitaire USB ───────────────────────────────────────────────────────────
|
# ── Utilitaire USB ───────────────────────────────────────────────────────────
|
||||||
def _usb_reset_done():
|
def _usb_reset_done():
|
||||||
"""Reset USB des DSLR via unbind/bind sysfs pour libérer tout claim obsolète."""
|
"""Reset USB des DSLR via unbind/bind sysfs pour libérer tout claim obsolète."""
|
||||||
@@ -764,8 +776,18 @@ class PB:
|
|||||||
if self.cam is None:
|
if self.cam is None:
|
||||||
raise RuntimeError("camera None")
|
raise RuntimeError("camera None")
|
||||||
if self.cap_demande:
|
if self.cap_demande:
|
||||||
# Capture tethered LV : trigger_capture + wait_for_event
|
# Déclenchement sans mouvement miroir :
|
||||||
# → le miroir reste levé (déjà en liveview)
|
# eosremoterelease garde le LV actif sur Canon EOS
|
||||||
|
triggered = False
|
||||||
|
try:
|
||||||
|
cfg_c = self.cam.get_config()
|
||||||
|
rl = cfg_c.get_child_by_name('eosremoterelease')
|
||||||
|
rl.set_value('Immediate')
|
||||||
|
self.cam.set_config(cfg_c)
|
||||||
|
triggered = True
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if not triggered:
|
||||||
self.cam.trigger_capture()
|
self.cam.trigger_capture()
|
||||||
ch = None
|
ch = None
|
||||||
deadline = time.time() + 15
|
deadline = time.time() + 15
|
||||||
@@ -776,6 +798,13 @@ class PB:
|
|||||||
self.cam.file_get(ev_data.folder, ev_data.name, gp.GP_FILE_TYPE_NORMAL, cf)
|
self.cam.file_get(ev_data.folder, ev_data.name, gp.GP_FILE_TYPE_NORMAL, cf)
|
||||||
nom = f"photo_{datetime.now().strftime('%Y%m%d_%H%M%S_%f')}.jpg"
|
nom = f"photo_{datetime.now().strftime('%Y%m%d_%H%M%S_%f')}.jpg"
|
||||||
ch = str(PHOTOS_DIR/nom); cf.save(ch); break
|
ch = str(PHOTOS_DIR/nom); cf.save(ch); break
|
||||||
|
# Réinitialise le remote release
|
||||||
|
try:
|
||||||
|
cfg_c = self.cam.get_config()
|
||||||
|
rl = cfg_c.get_child_by_name('eosremoterelease')
|
||||||
|
rl.set_value('None')
|
||||||
|
self.cam.set_config(cfg_c)
|
||||||
|
except: pass
|
||||||
self.cap_result=ch; self.cap_demande=False; self.cap_done.set()
|
self.cap_result=ch; self.cap_demande=False; self.cap_done.set()
|
||||||
errs = 0
|
errs = 0
|
||||||
else:
|
else:
|
||||||
@@ -846,7 +875,7 @@ class PB:
|
|||||||
if ch:
|
if ch:
|
||||||
self.photos.append(ch); self.compteur+=1; self._sav_cpt()
|
self.photos.append(ch); self.compteur+=1; self._sav_cpt()
|
||||||
try:
|
try:
|
||||||
img = ImageOps.exif_transpose(Image.open(ch).convert("RGB")).resize((strip_bw, thumb_h), Image.LANCZOS)
|
img = ImageOps.fit(ImageOps.exif_transpose(Image.open(ch).convert("RGB")), (strip_bw, thumb_h), Image.LANCZOS)
|
||||||
self._prev_thumbs.append(pygame.image.fromstring(img.tobytes(), img.size, "RGB"))
|
self._prev_thumbs.append(pygame.image.fromstring(img.tobytes(), img.size, "RGB"))
|
||||||
except:
|
except:
|
||||||
self._prev_thumbs.append(None)
|
self._prev_thumbs.append(None)
|
||||||
@@ -867,7 +896,7 @@ class PB:
|
|||||||
fw = (W - _PELL_GAP*(nb+1)) // nb
|
fw = (W - _PELL_GAP*(nb+1)) // nb
|
||||||
for ch in self.photos[:nb]:
|
for ch in self.photos[:nb]:
|
||||||
try:
|
try:
|
||||||
img=ImageOps.exif_transpose(Image.open(ch).convert("RGB")).resize((fw,_PELL_FH),Image.LANCZOS)
|
img=ImageOps.fit(ImageOps.exif_transpose(Image.open(ch).convert("RGB")),(fw,_PELL_FH),Image.LANCZOS)
|
||||||
surfs.append(pygame.image.fromstring(img.tobytes(),img.size,"RGB"))
|
surfs.append(pygame.image.fromstring(img.tobytes(),img.size,"RGB"))
|
||||||
except: surfs.append(None)
|
except: surfs.append(None)
|
||||||
elif self.format in ("bande3x2","bande4x2"):
|
elif self.format in ("bande3x2","bande4x2"):
|
||||||
@@ -875,14 +904,14 @@ class PB:
|
|||||||
pw = W // nb; sh = (H - 150) // 2
|
pw = W // nb; sh = (H - 150) // 2
|
||||||
for ch in self.photos[:nb]:
|
for ch in self.photos[:nb]:
|
||||||
try:
|
try:
|
||||||
img=ImageOps.exif_transpose(Image.open(ch).convert("RGB")).resize((pw,sh),Image.LANCZOS)
|
img=ImageOps.fit(ImageOps.exif_transpose(Image.open(ch).convert("RGB")),(pw,sh),Image.LANCZOS)
|
||||||
surfs.append(pygame.image.fromstring(img.tobytes(),img.size,"RGB"))
|
surfs.append(pygame.image.fromstring(img.tobytes(),img.size,"RGB"))
|
||||||
except: surfs.append(None)
|
except: surfs.append(None)
|
||||||
else: # grille_4
|
else: # grille_4
|
||||||
gw,gh=W//2-15,H//2-75
|
gw,gh=W//2-15,H//2-75
|
||||||
for ch in self.photos[:4]:
|
for ch in self.photos[:4]:
|
||||||
try:
|
try:
|
||||||
img=Image.open(ch).convert("RGB").resize((gw,gh),Image.LANCZOS)
|
img=ImageOps.fit(Image.open(ch).convert("RGB"),(gw,gh),Image.LANCZOS)
|
||||||
surfs.append(pygame.image.fromstring(img.tobytes(),img.size,"RGB"))
|
surfs.append(pygame.image.fromstring(img.tobytes(),img.size,"RGB"))
|
||||||
except: surfs.append(None)
|
except: surfs.append(None)
|
||||||
self.gal_surfs=surfs; self.gal_ready=True
|
self.gal_surfs=surfs; self.gal_ready=True
|
||||||
@@ -907,7 +936,7 @@ class PB:
|
|||||||
top = 80
|
top = 80
|
||||||
for i, ch in enumerate(photos[:nb]):
|
for i, ch in enumerate(photos[:nb]):
|
||||||
try:
|
try:
|
||||||
img = ImageOps.exif_transpose(Image.open(ch).convert("RGB")).resize((pw, sh), Image.LANCZOS)
|
img = ImageOps.fit(ImageOps.exif_transpose(Image.open(ch).convert("RGB")), (pw, sh), Image.LANCZOS)
|
||||||
canvas.paste(img, (i * pw, top))
|
canvas.paste(img, (i * pw, top))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"composite pellicule: {e}")
|
print(f"composite pellicule: {e}")
|
||||||
@@ -916,7 +945,7 @@ class PB:
|
|||||||
sh = (H - 150) // 2
|
sh = (H - 150) // 2
|
||||||
for i, ch in enumerate(photos[:nb]):
|
for i, ch in enumerate(photos[:nb]):
|
||||||
try:
|
try:
|
||||||
img = ImageOps.exif_transpose(Image.open(ch).convert("RGB")).resize((pw, sh), Image.LANCZOS)
|
img = ImageOps.fit(ImageOps.exif_transpose(Image.open(ch).convert("RGB")), (pw, sh), Image.LANCZOS)
|
||||||
canvas.paste(img, (i * pw, 5))
|
canvas.paste(img, (i * pw, 5))
|
||||||
canvas.paste(img, (i * pw, sh + 10))
|
canvas.paste(img, (i * pw, sh + 10))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -927,7 +956,7 @@ class PB:
|
|||||||
pos = [(5, 5), (W // 2 + 5, 5), (5, H // 2 - 65), (W // 2 + 5, H // 2 - 65)]
|
pos = [(5, 5), (W // 2 + 5, 5), (5, H // 2 - 65), (W // 2 + 5, H // 2 - 65)]
|
||||||
for i, ch in enumerate(photos[:4]):
|
for i, ch in enumerate(photos[:4]):
|
||||||
try:
|
try:
|
||||||
img = Image.open(ch).convert("RGB").resize((gw, gh), Image.LANCZOS)
|
img = ImageOps.fit(Image.open(ch).convert("RGB"), (gw, gh), Image.LANCZOS)
|
||||||
canvas.paste(img, pos[i])
|
canvas.paste(img, pos[i])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"composite grille: {e}")
|
print(f"composite grille: {e}")
|
||||||
@@ -1189,7 +1218,7 @@ class PB:
|
|||||||
# Photo prise
|
# Photo prise
|
||||||
th = self._prev_thumbs[i]
|
th = self._prev_thumbs[i]
|
||||||
if th:
|
if th:
|
||||||
ts = th if th.get_size() == (fw, fh) else pygame.transform.scale(th, (fw, fh))
|
ts = _pfit(th, fw, fh)
|
||||||
self.scr.blit(ts, (fx, fy))
|
self.scr.blit(ts, (fx, fy))
|
||||||
# Léger grain/vignette pellicule
|
# Léger grain/vignette pellicule
|
||||||
vig = pygame.Surface((fw, fh), pygame.SRCALPHA)
|
vig = pygame.Surface((fw, fh), pygame.SRCALPHA)
|
||||||
@@ -1259,7 +1288,7 @@ class PB:
|
|||||||
if i < len(self._prev_thumbs):
|
if i < len(self._prev_thumbs):
|
||||||
th = self._prev_thumbs[i]
|
th = self._prev_thumbs[i]
|
||||||
if th:
|
if th:
|
||||||
ts = th if th.get_size() == (bw, bh) else pygame.transform.scale(th, (bw, bh))
|
ts = _pfit(th, bw, bh)
|
||||||
self.scr.blit(ts, (bx, by))
|
self.scr.blit(ts, (bx, by))
|
||||||
pygame.draw.rect(self.scr, T["prim"], (bx, by, bw, bh), 2)
|
pygame.draw.rect(self.scr, T["prim"], (bx, by, bw, bh), 2)
|
||||||
tick = self.F["xs"].render("✓", True, T["prim"])
|
tick = self.F["xs"].render("✓", True, T["prim"])
|
||||||
@@ -1350,7 +1379,7 @@ class PB:
|
|||||||
fx=gap+i*(fw+gap); fy=frame_y
|
fx=gap+i*(fw+gap); fy=frame_y
|
||||||
surf=self.gal_surfs[i] if i<len(self.gal_surfs) else None
|
surf=self.gal_surfs[i] if i<len(self.gal_surfs) else None
|
||||||
if surf:
|
if surf:
|
||||||
ts=pygame.transform.scale(surf,(fw,fh))
|
ts=_pfit(surf,fw,fh)
|
||||||
self.scr.blit(ts,(fx,fy))
|
self.scr.blit(ts,(fx,fy))
|
||||||
pygame.draw.rect(self.scr,T["prim"],(fx,fy,fw,fh),2)
|
pygame.draw.rect(self.scr,T["prim"],(fx,fy,fw,fh),2)
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user