189 lines
7.0 KiB
Python
189 lines
7.0 KiB
Python
import cv2
|
||
from pyzbar.pyzbar import decode
|
||
import numpy as np
|
||
from PIL import ImageFont, ImageDraw, Image
|
||
import os
|
||
import subprocess
|
||
import requests
|
||
import pygetwindow as gw
|
||
import pyautogui
|
||
import time
|
||
|
||
# Nach 2 Sekunden suchen wir das Fenster
|
||
time.sleep(2)
|
||
for w in gw.getWindowsWithTitle("QR Scanner"): # oder z. B. "pygame", "Loader", etc.
|
||
w.activate()
|
||
w.maximize() # optional
|
||
pyautogui.click(w.left + 100, w.top + 100) # sicherer Klick ins Fenster
|
||
break
|
||
|
||
API_URL = "https://hag.putschgi.ch/Yb54CO5Ypybx/api/qr.php?action=verify_hash"
|
||
API_SECRET = "ddlKC6sgE4EMvsU9VQeIVeYrsPGpE104"
|
||
|
||
# Fenstergröße & Farben
|
||
window_width, window_height = 1920, 1080
|
||
# Habegger Gold
|
||
COLOR_GREEN = (0, 255, 0)
|
||
COLOR_YELLOW = (0, 255, 255)
|
||
COLOR_BACKGROUND = (45, 46, 47) # HTML-Farbe #2d2e2f
|
||
COLOR_WHITE = (255, 255, 255)
|
||
COLOR_GOLD = (131, 188, 214) # BGR für Habegger-Gold
|
||
|
||
# Font & Logo
|
||
FONT_PATH = os.path.join("fonts", "Tisa Sans Pro Regular.ttf"
|
||
"") # Alternativ: Georgia.ttf, falls vorhanden
|
||
FONT_SIZE = 48
|
||
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
|
||
logo_path = "images/habegger_logo_goldbar_whitefont.png" # Logo mit sichtbarem Text
|
||
logo_pil = Image.open(logo_path).convert("RGBA")
|
||
logo_pil.thumbnail((300, 100))
|
||
logo_pil = Image.alpha_composite(Image.new("RGBA", logo_pil.size, (0, 0, 0, 0)), logo_pil)
|
||
logo_img = np.array(logo_pil)
|
||
logo_img = cv2.cvtColor(logo_img, cv2.COLOR_RGBA2BGRA)
|
||
|
||
def draw_unicode_text(cv2_image, text, position, color=COLOR_WHITE):
|
||
img_pil = Image.fromarray(cv2_image)
|
||
draw = ImageDraw.Draw(img_pil)
|
||
draw.text(position, text, font=font, fill=color)
|
||
return np.array(img_pil)
|
||
|
||
def parse_qr_data(data):
|
||
from urllib.parse import urlparse, parse_qs
|
||
if "?code=" in data:
|
||
parsed = urlparse(data)
|
||
query = parse_qs(parsed.query)
|
||
code = query.get("code", [""])[0]
|
||
return code
|
||
return None
|
||
|
||
|
||
def start_game(mail, name):
|
||
with open("last_user.txt", "w", encoding="utf-8-sig") as f:
|
||
f.write(f"{mail}\n{name}")
|
||
subprocess.run(["python", "loader_game.py"])
|
||
|
||
# Endlosschleife für den Scanner
|
||
while True:
|
||
detected_color = COLOR_GOLD
|
||
detected_time = None
|
||
cap = cv2.VideoCapture(0)
|
||
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
|
||
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
|
||
|
||
# Rahmenfarbe wird später im Loop anhand der Zeit gesetzt
|
||
last_display_text = ""
|
||
start_timer = None
|
||
game_started = False
|
||
|
||
while True:
|
||
success, frame = cap.read()
|
||
if not success:
|
||
break
|
||
|
||
decoded_objects = decode(frame)
|
||
if not decoded_objects:
|
||
inverted_frame = cv2.bitwise_not(frame)
|
||
decoded_objects = decode(inverted_frame)
|
||
|
||
# QR-Status zurücksetzen nach 5 Sek.
|
||
if detected_time and time.time() - detected_time >= 5.0:
|
||
detected_color = COLOR_GOLD
|
||
frame_color = COLOR_GOLD
|
||
|
||
if decoded_objects:
|
||
detected_time = time.time()
|
||
|
||
for obj in decoded_objects:
|
||
points = obj.polygon
|
||
if len(points) > 4:
|
||
hull = cv2.convexHull(np.array([point for point in points], dtype=np.float32))
|
||
points = hull.reshape(-1, 2)
|
||
for i in range(len(points)):
|
||
pt1 = tuple(points[i])
|
||
pt2 = tuple(points[(i + 1) % len(points)])
|
||
cv2.line(frame, pt1, pt2, COLOR_GREEN, 3)
|
||
|
||
data = obj.data.decode("utf-8")
|
||
code = parse_qr_data(data)
|
||
if not code:
|
||
detected_color = COLOR_YELLOW
|
||
detected_time = time.time()
|
||
last_display_text = "Kein gültiger QR-Code erkannt."
|
||
break
|
||
|
||
try:
|
||
res = requests.post(API_URL, json={"code": code, "auth": API_SECRET}, timeout=5)
|
||
print("RAW Response:", res.text)
|
||
result = res.json()
|
||
|
||
except Exception as e:
|
||
detected_color = COLOR_YELLOW
|
||
detected_time = time.time()
|
||
last_display_text = f"API Fehler: {e}"
|
||
break
|
||
|
||
if not result.get("valid"):
|
||
detected_color = COLOR_YELLOW
|
||
last_display_text = "Ungültiger Code."
|
||
elif result.get("registered"):
|
||
name = result.get("name", "Unbekannt")
|
||
detected_color = COLOR_GREEN
|
||
last_display_text = f"Hallo {name}!"
|
||
start_timer = time.time()
|
||
game_started = True
|
||
last_mail = code
|
||
last_name = name
|
||
else:
|
||
detected_color = COLOR_YELLOW
|
||
last_display_text = "QR gültig, aber nicht registriert."
|
||
detected_time = time.time()
|
||
break
|
||
|
||
if start_timer and time.time() - start_timer >= 5.0:
|
||
cap.release()
|
||
cv2.destroyAllWindows()
|
||
start_game(last_mail, last_name)
|
||
break
|
||
|
||
display_frame = np.full((window_height, window_width, 3), COLOR_BACKGROUND, dtype=np.uint8)
|
||
cam_h, cam_w = frame.shape[:2]
|
||
x_offset = (window_width - cam_w) // 2
|
||
y_offset = (window_height - cam_h) // 2
|
||
display_frame[y_offset:y_offset+cam_h, x_offset:x_offset+cam_w] = frame
|
||
|
||
display_frame = draw_unicode_text(display_frame,
|
||
"Scanne deinen QR-Code um das Spiel zu starten.",
|
||
(80, 100), COLOR_WHITE)
|
||
|
||
if last_display_text:
|
||
display_frame = draw_unicode_text(display_frame, last_display_text,
|
||
(80, window_height - 100), COLOR_WHITE)
|
||
|
||
# Kamera-Rahmen
|
||
if detected_time and time.time() - detected_time < 5.0:
|
||
current_color = detected_color
|
||
else:
|
||
current_color = COLOR_GOLD
|
||
|
||
cv2.rectangle(display_frame, (x_offset, y_offset),
|
||
(x_offset + cam_w, y_offset + cam_h), current_color, 6)
|
||
|
||
# Logo oben rechts ohne Alpha-Blending-Probleme
|
||
logo_pos = (window_width - logo_img.shape[1] - 40, 40)
|
||
overlay = np.zeros_like(display_frame, dtype=np.uint8)
|
||
overlay[logo_pos[1]:logo_pos[1]+logo_img.shape[0], logo_pos[0]:logo_pos[0]+logo_img.shape[1]] = logo_img[:, :, :3]
|
||
mask = logo_img[:, :, 3] # alpha channel
|
||
for c in range(3):
|
||
display_frame[logo_pos[1]:logo_pos[1]+logo_img.shape[0], logo_pos[0]:logo_pos[0]+logo_img.shape[1], c] = (
|
||
logo_img[:, :, c] * (mask / 255.0) + display_frame[logo_pos[1]:logo_pos[1]+logo_img.shape[0], logo_pos[0]:logo_pos[0]+logo_img.shape[1], c] * (1.0 - mask / 255.0)).astype(np.uint8)
|
||
|
||
cv2.namedWindow("QR Scanner", cv2.WINDOW_NORMAL)
|
||
cv2.setWindowProperty("QR Scanner", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
|
||
cv2.imshow("QR Scanner", display_frame)
|
||
|
||
key = cv2.waitKey(1)
|
||
if key == 27 or key == ord('q'):
|
||
cap.release()
|
||
cv2.destroyAllWindows()
|
||
exit()
|