""" Mock gphoto2 module for Windows testing and development. Simulates gphoto2 API behavior to allow the app to run without a camera. """ import numpy as np import cv2 from dataclasses import dataclass # --- Constants (simulate gphoto2 enums) --- GP_WIDGET_WINDOW = 0 GP_WIDGET_SECTION = 1 GP_WIDGET_TEXT = 2 GP_WIDGET_RANGE = 3 GP_WIDGET_TOGGLE = 4 GP_WIDGET_RADIO = 5 GP_WIDGET_MENU = 6 GP_WIDGET_BUTTON = 7 GP_WIDGET_DATE = 8 GP_OPERATION_NONE = 0x00 GP_OPERATION_CAPTURE_IMAGE = 0x01 GP_OPERATION_CAPTURE_VIDEO = 0x02 GP_OPERATION_CAPTURE_AUDIO = 0x04 GP_OPERATION_CAPTURE_PREVIEW = 0x08 GP_OPERATION_CONFIG = 0x10 GP_OPERATION_TRIGGER_CAPTURE = 0x20 # --- Error class --- class GPhoto2Error(Exception): pass # --- Mock camera configuration widget --- class MockWidget: def __init__(self, name, label, wtype, value=None, choices=None): self._name = name self._label = label self._type = wtype self._value = value self._choices = choices or [] self._children = [] def get_id(self): return id(self) def get_name(self): return self._name def get_label(self): return self._label def get_type(self): return self._type def get_value(self): return self._value def set_value(self, value): if self._choices and value not in self._choices: raise GPhoto2Error(f"Invalid value '{value}' for widget '{self._name}'") self._value = value def get_choices(self): return self._choices def count_children(self): return len(self._children) def get_child(self, i): return self._children[i] def add_child(self, child): self._children.append(child) # --- Mock classes for detection / abilities --- @dataclass class MockCameraInfo: name: str port: str class MockCameraList: def __init__(self): self._cameras = [ MockCameraInfo("Mock Camera 1", "usb:001,002"), MockCameraInfo("Mock Camera 2", "usb:001,003") ] def count(self): return len(self._cameras) def get_name(self, i): return self._cameras[i].name def get_value(self, i): return self._cameras[i].port class CameraAbilities: def __init__(self, operations): self.operations = operations class CameraAbilitiesList: def load(self): pass def lookup_model(self, name): return 0 def get_abilities(self, index): return CameraAbilities( GP_OPERATION_CAPTURE_IMAGE | GP_OPERATION_CAPTURE_PREVIEW | GP_OPERATION_CONFIG ) class PortInfoList: def load(self): pass def lookup_path(self, path): return 0 def __getitem__(self, index): return f"MockPortInfo({index})" # --- Mock Camera class --- class Camera: def __init__(self): self.initialized = False self.port_info = None def init(self): self.initialized = True def exit(self): self.initialized = False def set_port_info(self, info): self.port_info = info def get_config(self): # Simulate config tree root = MockWidget("root", "Root", GP_WIDGET_WINDOW) iso = MockWidget("iso", "ISO", GP_WIDGET_MENU, "100", ["100", "200", "400", "800"]) shutter = MockWidget("shutter", "Shutter Speed", GP_WIDGET_MENU, "1/60", ["1/30", "1/60", "1/125"]) wb = MockWidget("whitebalance", "White Balance", GP_WIDGET_RADIO, "Auto", ["Auto", "Daylight", "Tungsten"]) root.add_child(iso) root.add_child(shutter) root.add_child(wb) return root def set_single_config(self, name, widget): # Simulate saving a setting print(f"[mock_gphoto] Setting '{name}' = '{widget.get_value()}'") def capture_preview(self): # Generate a fake image (OpenCV compatible) frame = np.zeros((480, 640, 3), dtype=np.uint8) cv2.putText(frame, "Mock Preview", (150, 240), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) _, buf = cv2.imencode(".jpg", frame) class MockFile: def get_data_and_size(self_inner): return buf.tobytes() return MockFile() # --- Mock detection functions --- def gp_camera_autodetect(): return MockCameraList() def check_result(value): # gphoto2.check_result usually raises error if return < 0 return value # --- API aliases to match gphoto2 --- GP_ERROR = -1 gp_camera_autodetect = gp_camera_autodetect check_result = check_result Camera = Camera CameraAbilitiesList = CameraAbilitiesList PortInfoList = PortInfoList GPhoto2Error = GPhoto2Error