Mise a jour theme GRUB + logo copydev + test pygame

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-06 22:43:21 +02:00
parent 1120513309
commit 6451f5774c
17 changed files with 257 additions and 25 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 360 B

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 B

After

Width:  |  Height:  |  Size: 99 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 B

After

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

After

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

After

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 B

After

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

After

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 B

After

Width:  |  Height:  |  Size: 78 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 B

After

Width:  |  Height:  |  Size: 99 B

View File

@@ -1,35 +1,25 @@
# Theme GRUB tactile - Triple Boot Terra
title-text: ""
desktop-color: "#1a1a2e"
desktop-image: "background.png"
desktop-color: "#0f1428"
message-color: "#ffffff"
message-bg-color: "#000000"
terminal-font: "DejaVu Sans Bold 24"
+ boot_menu {
left = 10%
top = 15%
width = 80%
height = 70%
item_font = "DejaVu Sans Bold 36"
item_color = "#cccccc"
selected_item_font = "DejaVu Sans Bold 42"
left = 15%
top = 25%
width = 70%
height = 60%
item_font = "DejaVu Sans Bold 48"
item_color = "#aabbcc"
selected_item_font = "DejaVu Sans Bold 48"
selected_item_color = "#ffffff"
item_height = 120
item_padding = 20
item_spacing = 30
item_icon_space = 30
icon_width = 96
icon_height = 96
item_height = 160
item_padding = 30
item_spacing = 20
item_icon_space = 40
icon_width = 128
icon_height = 128
selected_item_pixmap_style = "select_*.png"
}
+ label {
left = 0
top = 90%
width = 100%
height = 30
text = "Toucher pour selectionner - Appuyer sur Entree pour demarrer"
font = "DejaVu Sans 18"
color = "#888888"
align = "center"
}

View File

@@ -0,0 +1,242 @@
#!/usr/bin/env python3
"""
Prototype photobooth Pygame.
- Bouton -> liveview -> 3 2 1 -> photo x4 -> grille 4 photos
"""
import time
import threading
import io
import os
from pathlib import Path
from datetime import datetime
import pygame
import gphoto2 as gp
from PIL import Image
# Config
LARGEUR, HAUTEUR = 1920, 1280
NB_PHOTOS = 4
DUREE_COMPTE = 3
DOSSIER_PHOTOS = Path("/tmp/photobooth_test")
DOSSIER_PHOTOS.mkdir(exist_ok=True)
# Couleurs
NOIR = (0, 0, 0)
BLANC = (255, 255, 255)
ROSE = (233, 30, 99)
GRIS = (40, 40, 40)
class Photobooth:
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((LARGEUR, HAUTEUR), pygame.FULLSCREEN)
pygame.display.set_caption("Photobooth")
self.clock = pygame.time.Clock()
self.font_grand = pygame.font.SysFont(None, 300)
self.font_moyen = pygame.font.SysFont(None, 100)
self.font_petit = pygame.font.SysFont(None, 60)
# Camera
self.cam = gp.Camera()
self.cam.init()
# Etat
self.etat = "accueil" # accueil, preview, compte, capture, galerie
self.frame_courante = None
self.frame_lock = threading.Lock()
self.preview_actif = False
# Capture via le thread preview (evite le baisse de miroir)
self.capture_demande = False
self.capture_resultat = None
self.capture_done = threading.Event()
self.photos = []
self.num_photo = 0
self.chiffre_compte = 0
# Thread preview
self.thread_preview = threading.Thread(target=self._loop_preview, daemon=True)
self.thread_preview.start()
def _loop_preview(self):
while True:
if self.preview_actif:
try:
if self.capture_demande:
try:
chemin_cam = self.cam.capture(gp.GP_CAPTURE_IMAGE)
cf = gp.CameraFile()
self.cam.file_get(chemin_cam.folder, chemin_cam.name, gp.GP_FILE_TYPE_NORMAL, cf)
nom = f"photo_{datetime.now().strftime('%H%M%S_%f')}.jpg"
chemin = str(DOSSIER_PHOTOS / nom)
cf.save(chemin)
self.capture_resultat = chemin
print(f"Photo capturee: {chemin}")
except Exception as e:
print(f"Erreur capture: {e}")
self.capture_resultat = None
self.capture_demande = False
self.capture_done.set()
else:
f = self.cam.capture_preview()
data = bytes(f.get_data_and_size())
surf = pygame.image.load(io.BytesIO(data))
surf = pygame.transform.scale(surf, (LARGEUR, HAUTEUR))
with self.frame_lock:
self.frame_courante = surf
except Exception as e:
print(f"Preview erreur: {e}")
time.sleep(0.3) # Camera peut etre occupee apres capture
else:
time.sleep(0.05)
def capturer_photo(self):
"""Demande une capture au thread preview (miroir reste leve)."""
self.capture_resultat = None
self.capture_done.clear()
self.capture_demande = True
ok = self.capture_done.wait(timeout=10)
if not ok:
print("Timeout capture")
self.capture_demande = False
return self.capture_resultat
def dessiner_accueil(self):
self.screen.fill(NOIR)
txt = self.font_moyen.render("PHOTOBOOTH", True, ROSE)
self.screen.blit(txt, (LARGEUR//2 - txt.get_width()//2, 300))
# Bouton
btn = pygame.Rect(LARGEUR//2 - 300, HAUTEUR//2, 600, 150)
pygame.draw.rect(self.screen, ROSE, btn, border_radius=20)
t = self.font_moyen.render("COMMENCER", True, BLANC)
self.screen.blit(t, (btn.centerx - t.get_width()//2, btn.centery - t.get_height()//2))
return btn
def dessiner_preview(self):
with self.frame_lock:
if self.frame_courante:
self.screen.blit(self.frame_courante, (0, 0))
else:
self.screen.fill(NOIR)
# Info
t = self.font_petit.render(f"Photo {self.num_photo+1}/{NB_PHOTOS} - Souriez!", True, BLANC)
self.screen.blit(t, (20, 20))
def dessiner_compte(self):
with self.frame_lock:
if self.frame_courante:
self.screen.blit(self.frame_courante, (0, 0))
else:
self.screen.fill(NOIR)
# Overlay sombre
overlay = pygame.Surface((LARGEUR, HAUTEUR), pygame.SRCALPHA)
overlay.fill((0, 0, 0, 100))
self.screen.blit(overlay, (0, 0))
# Chiffre
txt = self.font_grand.render(str(self.chiffre_compte), True, BLANC)
self.screen.blit(txt, (LARGEUR//2 - txt.get_width()//2, HAUTEUR//2 - txt.get_height()//2))
def dessiner_galerie(self):
self.screen.fill(NOIR)
if not self.photos:
t = self.font_petit.render("Aucune photo", True, BLANC)
self.screen.blit(t, (LARGEUR//2 - t.get_width()//2, HAUTEUR//2))
else:
# 4 photos en grille 2x2
w, h = LARGEUR//2 - 20, HAUTEUR//2 - 20
positions = [(10, 10), (LARGEUR//2+10, 10), (10, HAUTEUR//2+10), (LARGEUR//2+10, HAUTEUR//2+10)]
for i, chemin in enumerate(self.photos[:4]):
if i >= len(positions):
break
try:
# PIL pour redimensionner efficacement les grands JPEG Canon
img = Image.open(chemin).convert('RGB')
img = img.resize((w, h), Image.LANCZOS)
surf = pygame.image.fromstring(img.tobytes(), img.size, 'RGB')
self.screen.blit(surf, positions[i])
except Exception as e:
print(f"Erreur galerie photo {i}: {e}")
# Bouton recommencer
btn = pygame.Rect(LARGEUR//2 - 200, HAUTEUR - 120, 400, 100)
pygame.draw.rect(self.screen, ROSE, btn, border_radius=15)
t = self.font_petit.render("RECOMMENCER", True, BLANC)
self.screen.blit(t, (btn.centerx - t.get_width()//2, btn.centery - t.get_height()//2))
return btn
def lancer_sequence(self):
"""Lance la séquence 4 photos dans un thread."""
def sequence():
self.photos = []
for i in range(NB_PHOTOS):
self.num_photo = i
# Preview
self.preview_actif = True
self.etat = "preview"
time.sleep(1.5)
# Compte a rebours
self.etat = "compte"
for c in range(DUREE_COMPTE, 0, -1):
self.chiffre_compte = c
time.sleep(1)
# Flash + capture (miroir reste leve, liveview continue)
self.etat = "capture"
chemin = self.capturer_photo()
if chemin:
self.photos.append(chemin)
print(f"Photo {i+1} : {chemin}")
time.sleep(0.3)
# Galerie
self.preview_actif = False
self.etat = "galerie"
threading.Thread(target=sequence, daemon=True).start()
def run(self):
btn_accueil = None
btn_galerie = None
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
pos = pygame.mouse.get_pos()
if self.etat == "accueil" and btn_accueil and btn_accueil.collidepoint(pos):
self.lancer_sequence()
if self.etat == "galerie" and btn_galerie and btn_galerie.collidepoint(pos):
self.etat = "accueil"
self.photos = []
if self.etat == "accueil":
btn_accueil = self.dessiner_accueil()
btn_galerie = None
elif self.etat == "preview":
self.dessiner_preview()
elif self.etat == "compte":
self.dessiner_compte()
elif self.etat == "capture":
self.dessiner_compte() # Reste sur le liveview pendant la capture
elif self.etat == "galerie":
btn_galerie = self.dessiner_galerie()
btn_accueil = None
pygame.display.flip()
self.clock.tick(30)
self.preview_actif = False
self.cam.exit()
pygame.quit()
if __name__ == "__main__":
app = Photobooth()
app.run()