import sys import cv2 import json import time import os from ftplib import FTP from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QVBoxLayout from PyQt6.QtGui import QImage, QPixmap, QPainter, QFont, QColor from PyQt6.QtCore import QTimer, Qt import qrcode CONFIG_PATH = "config.json" def load_config(): with open(CONFIG_PATH) as f: return json.load(f) def save_config(cfg): with open(CONFIG_PATH, "w") as f: json.dump(cfg, f, indent=2) CONFIG = load_config() def create_capture(index): cap = cv2.VideoCapture(index, cv2.CAP_MSMF) if not cap.isOpened(): return None cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) for _ in range(20): ret, frame = cap.read() if ret and frame is not None: return cap cap.release() return None def find_cameras(): working = [] for i in range(10): cap = create_capture(i) if cap is not None: working.append(i) cap.release() return working class CameraSelect(QWidget): def __init__(self, cameras): super().__init__() self.setWindowTitle("Kamera auswählen") self.setGeometry(200, 200, 400, 300) self.selected = None layout = QVBoxLayout() for cam in cameras: btn = QPushButton(f"Kamera {cam}") btn.clicked.connect(lambda _, c=cam: self.select(c)) layout.addWidget(btn) self.setLayout(layout) def select(self, cam): self.selected = cam self.close() LIVE, COUNTDOWN, PHOTO, QR = range(4) class PhotoApp(QWidget): def __init__(self): super().__init__() self.setWindowTitle("Photo Booth") self.showFullScreen() self.label = QLabel(self) self.label.setGeometry(0, 0, 1920, 1080) self.cap = None self.init_camera() self.state = LIVE self.current_frame = None self.photo = None self.qr_img = None self.countdown = 0 self.timer = QTimer() self.timer.timeout.connect(self.update_frame) self.timer.start(30) self.countdown_timer = QTimer() self.countdown_timer.timeout.connect(self.update_countdown) def init_camera(self): cams = find_cameras() if not cams: sys.exit(1) last = CONFIG.get("camera", {}).get("last_used") if last in cams: cam_index = last else: selector = CameraSelect(cams) selector.show() while selector.isVisible(): QApplication.processEvents() cam_index = selector.selected if cam_index is None: sys.exit(1) CONFIG["camera"]["last_used"] = cam_index save_config(CONFIG) self.cap = create_capture(cam_index) if self.cap is None: sys.exit(1) def update_frame(self): if not self.cap: return ret, frame = self.cap.read() if not ret or frame is None: return self.current_frame = frame if self.state == LIVE: self.draw(frame, "Drücke 1 für Foto") elif self.state == COUNTDOWN: self.draw(frame, str(self.countdown), big=True) elif self.state == PHOTO: self.draw(self.photo, "2=Speichern | 3=Drucken") elif self.state == QR: self.draw(self.qr_img, "QR Code scannen") def draw(self, frame, text="", big=False): rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch = rgb.shape img = QImage(rgb.data, w, h, ch * w, QImage.Format.Format_RGB888).copy() pix = QPixmap.fromImage(img) painter = QPainter(pix) painter.fillRect(0, 900, 1920, 180, QColor(0, 0, 0, 120)) painter.setPen(Qt.GlobalColor.white) if big: painter.setFont(QFont("Arial", 200)) painter.drawText(pix.rect(), Qt.AlignmentFlag.AlignCenter, text) else: painter.setFont(QFont("Arial", 40)) painter.drawText(50, 1000, text) if self.countdown > 0 and not big: painter.drawText(1700, 1000, str(self.countdown)) painter.end() self.label.setPixmap(pix) def keyPressEvent(self, event): key = event.text() if key == CONFIG["buttons"]["capture"]: self.start_countdown() elif key == CONFIG["buttons"]["save"]: self.save_photo() elif key == CONFIG["buttons"]["print"]: self.print_photo() def start_countdown(self): if self.state != LIVE: return self.state = COUNTDOWN self.countdown = 3 self.countdown_timer.start(1000) def take_photo(self): self.photo = self.current_frame.copy() self.state = PHOTO self.countdown = 60 def save_photo(self): if self.state != PHOTO: return url = self.upload(self.photo) self.make_qr(url) self.state = QR self.start_qr_timer() def print_photo(self): if self.state != PHOTO: return url = self.upload(self.photo) self.make_qr(url) self.print_image() self.state = QR self.start_qr_timer() def update_countdown(self): self.countdown -= 1 if self.state == COUNTDOWN and self.countdown == 0: self.take_photo() elif self.countdown <= 0: self.reset() def start_qr_timer(self): self.countdown = 30 self.countdown_timer.start(1000) def reset(self): self.state = LIVE self.countdown = 0 self.photo = None self.qr_img = None self.countdown_timer.stop() def upload(self, img): filename = f"{int(time.time())}.jpg" path = os.path.join(CONFIG["photo_path"], filename) os.makedirs(CONFIG["photo_path"], exist_ok=True) cv2.imwrite(path, img) ftp = FTP(CONFIG["ftp"]["host"]) ftp.login(CONFIG["ftp"]["user"], CONFIG["ftp"]["password"]) with open(path, "rb") as f: ftp.storbinary(f"STOR {filename}", f) ftp.quit() return CONFIG["ftp"]["base_url"] + filename def make_qr(self, url): img = qrcode.make(url) img.save("qr.png") self.qr_img = cv2.imread("qr.png") def print_image(self): temp = "print.jpg" cv2.imwrite(temp, self.photo) if os.name == "nt": os.startfile(temp, "print") else: os.system(f"lp {temp}") def closeEvent(self, event): if self.cap: self.cap.release() cv2.destroyAllWindows() event.accept() if __name__ == "__main__": app = QApplication(sys.argv) win = PhotoApp() win.show() sys.exit(app.exec())