def do_actions(self, events): if self.app.find_print_event( events ) and self.app.previous_picture_file and self.app.printer.is_installed( ): if self.app.nbr_printed >= self.app.config.getint( 'PRINTER', 'max_duplicates'): LOGGER.warning( "Too many duplicates sent to the printer (%s max)", self.app.config.getint('PRINTER', 'max_duplicates')) return with timeit("Send final picture to printer"): self.app.led_print.switch_on() self.app.printer.print_file( self.app.previous_picture_file, self.app.config.getint('PRINTER', 'nbr_copies')) time.sleep(1) # Just to let the LED switched on self.app.nbr_printed += 1 if self.app.nbr_printed >= self.app.config.getint( 'PRINTER', 'max_duplicates'): self.app.window.show_intro(self.app.previous_picture, False) self.app.led_print.switch_off() else: self.app.led_print.blink() event = self.app.find_print_status_event(events) if event: self.app.window.set_print_number(len(event.tasks))
def _post_process_capture(self, capture_data): """Rework capture data. :param capture_data: couple (frame, effect) :type capture_data: tuple """ frame, effect = capture_data image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # Crop to keep aspect ratio of the resolution height, width = image.shape[:2] cropped = sizing.new_size_by_croping_ratio((width, height), self.resolution) image = image[cropped[1]:cropped[3], cropped[0]:cropped[2]] # Resize to fit the resolution height, width = image.shape[:2] size = sizing.new_size_keep_aspect_ratio((width, height), self.resolution, 'outer') image = cv2.resize(image, size, interpolation=cv2.INTER_AREA) if self._capture_hflip: image = cv2.flip(image, 1) if effect != 'none': LOGGER.warning("Effect with OpenCV camera is not implemented") return Image.fromarray(image)
def regenerate_all_images(plugin_manager, config, basepath): """Regenerate the pibboth images from the raw images and the config. """ if not osp.isdir(osp.join(basepath, 'raw')): return capture_choices = config.gettuple('PICTURE', 'captures', int, 2) for captures_folder in os.listdir(osp.join(basepath, 'raw')): captures_folder_path = osp.join(basepath, 'raw', captures_folder) if not osp.isdir(captures_folder_path): continue captures = get_captures(captures_folder_path) LOGGER.info("Generating image from raws in folder %s", captures_folder_path) if len(captures) == capture_choices[0]: idx = 0 elif len(captures) == capture_choices[1]: idx = 1 else: LOGGER.warning( "Folder %s doesn't contain the correct number of pictures", captures_folder_path) continue default_factory = get_picture_factory( captures, config.get('PICTURE', 'orientation')) factory = plugin_manager.hook.pibooth_setup_picture_factory( cfg=config, opt_index=idx, factory=default_factory) picture_file = osp.join(basepath, captures_folder + "_pibooth.jpg") factory.save(picture_file)
def set_config_value(self, section, option, value): """Set camera configuration. """ try: LOGGER.debug('Setting option %s/%s=%s', section, option, value) config = self._cam.get_config() child = config.get_child_by_name(section).get_child_by_name(option) if child.get_type() == gp.GP_WIDGET_RADIO: choices = [c for c in child.get_choices()] else: choices = None data_type = type(child.get_value()) value = data_type(value) # Cast value if choices and value not in choices: if value == 'Memory card' and 'card' in choices: value = 'card' # Fix for Sony ZV-1 elif value == 'Memory card' and 'card+sdram' in choices: value = 'card+sdram' # Fix for Sony ILCE-6400 else: LOGGER.warning( "Invalid value '%s' for option %s (possible choices: %s), trying to set it anyway", value, option, choices) child.set_value(value) self._cam.set_config(config) except gp.GPhoto2Error as ex: LOGGER.error( 'Unsupported option %s/%s=%s (%s), configure your DSLR manually', section, option, value, ex)
def write_exif(filename, capture_nbr, pic_id): """Adding Exif data to image files """ try: im = Image.open(filename) exif_dict = piexif.load(filename) # process im and exif_dict... w, h = im.size exif_dict["0th"][piexif.ImageIFD.XResolution] = (w, 1) exif_dict["0th"][piexif.ImageIFD.YResolution] = (h, 1) exif_dict["0th"][piexif.ImageIFD.Model] = "Fotobox vom Prinsenhof" exif_dict["0th"][piexif.ImageIFD.Make] = "Prinsenhof" exif_dict["0th"][piexif.ImageIFD.Software] = "pibooth" exif_dict["0th"][piexif.ImageIFD.ImageDescription] = "Ein Foto aus der Fotobooth vom Prinsenhof in Porta Westfalica" exif_dict["0th"][piexif.ImageIFD.DocumentName] = "Fotobox Image" exif_dict["0th"][piexif.ImageIFD.Artist] = "bpw23" exif_dict["0th"][piexif.ImageIFD.HostComputer] = "www.prinsenhof.de" exif_dict["0th"][piexif.ImageIFD.ImageNumber] = capture_nbr exif_dict["0th"][piexif.ImageIFD.Copyright] = "www.prinsenhof.de" exif_dict["Exif"][piexif.ExifIFD.ImageUniqueID] = str(pic_id) exif_dict["Exif"][piexif.ExifIFD.CameraOwnerName] = "Prinsenhof" exif_dict["GPS"][piexif.GPSIFD.GPSLatitudeRef] = "N" exif_dict["GPS"][piexif.GPSIFD.GPSLongitudeRef] = "O" #exif_dict["GPS"][piexif.ImageIFD.GPSLatitude] = () #exif_dict["GPS"][piexif.ImageIFD.GPSLongitude] = () exif_bytes = piexif.dump(exif_dict) LOGGER.info("EXIF: adding metadata to image file") im.save(filename, "jpeg", exif=exif_bytes) except Exception as e: LOGGER.warning(f"EXIF: couldn't add exif informations to picture [{e}]")
def __init__(self, filename, clear=False): ConfigParser.__init__(self) self.filename = osp.abspath(osp.expanduser(filename)) if not osp.isfile(self.filename) or clear: LOGGER.info("Generate the configuration file in '%s'", self.filename) dirname = osp.dirname(self.filename) if not osp.isdir(dirname): os.makedirs(dirname) generate_default_config(self.filename) self.read(self.filename) # Handle the language configuration, save it as a class attribute for easy access path = osp.join(osp.dirname(osp.abspath(__file__)), 'pictures') possibles = [ name for name in os.listdir(path) if osp.isdir(osp.join(path, name)) ] language = self.get('GENERAL', 'language') if language not in possibles: LOGGER.warning("Unsupported language '%s', fallback to English", language) PtbConfigParser.language = 'en' else: PtbConfigParser.language = language
def set_config_value(self, section, option, value): """Set camera configuration. This method don't send the updated configuration to the camera (avoid connection flooding if several values have to be changed) """ try: LOGGER.debug('Setting option %s/%s=%s', section, option, value) config = self._cam.get_config() child = config.get_child_by_name(section).get_child_by_name(option) if child.get_type() == gp.GP_WIDGET_RADIO: choices = [c for c in child.get_choices()] else: choices = None data_type = type(child.get_value()) value = data_type(value) # Cast value if choices and value not in choices: LOGGER.warning( "Invalid value '%s' for option %s (possible choices: %s), trying to set it anyway", value, option, choices) child.set_value(value) self._cam.set_config(config) except gp.GPhoto2Error as ex: LOGGER.error( 'Unsupported option %s/%s=%s (%s), configure your DSLR manually', section, option, value, ex)
def _get_authorized_session(self): """Create credentials file if required and open a new session.""" if not os.path.exists(self.credentials_file) or \ os.path.getsize(self.credentials_file) == 0: self._credentials = self._auth() LOGGER.debug( "First use of pibooth-google-photo: generate credentials file %s", self.credentials_file) try: self._save_credentials(self._credentials) except OSError as err: LOGGER.warning( "Can not save Google Photos credentials in '%s': %s", self.credentials_file, err) else: try: self._credentials = Credentials.from_authorized_user_file( self.credentials_file, self.SCOPES) if self._credentials.expired: self._credentials.refresh(Request()) self._save_credentials(self._credentials) except ValueError: LOGGER.debug( "Error loading Google Photos OAuth tokens: incorrect format" ) if self._credentials: return AuthorizedSession(self._credentials) return None
def regenerate_all_images(config): captures_folders = config.getpath('GENERAL', 'directory') capture_choices = config.gettuple('PICTURE', 'captures', int) # Part that fetch the captures for captures_folder in os.listdir(osp.join(captures_folders, 'raw')): captures_folder_path = osp.join(captures_folders, 'raw', captures_folder) captures = get_captures(captures_folder_path) LOGGER.info("Generating image from raws in folder %s" % (captures_folder_path)) backgrounds = config.gettuple('PICTURE', 'backgrounds', ('color', 'path'), 2) if len(captures) == capture_choices[0]: background = backgrounds[0] elif len(captures) == capture_choices[1]: background = backgrounds[1] else: LOGGER.warning( "Folder %s doesn't contain the correct number of pictures" % captures_folder_path) continue overlays = config.gettuple('PICTURE', 'overlays', 'path', 2) if len(captures) == capture_choices[0]: overlay = overlays[0] else: overlay = overlays[1] texts = [ config.get('PICTURE', 'footer_text1').strip('"'), config.get('PICTURE', 'footer_text2').strip('"') ] colors = config.gettuple('PICTURE', 'text_colors', 'color', len(texts)) text_fonts = config.gettuple('PICTURE', 'text_fonts', str, len(texts)) alignments = config.gettuple('PICTURE', 'text_alignments', str, len(texts)) def _setup_maker(m): m.set_background(background) if any(elem != '' for elem in texts): for params in zip(texts, text_fonts, colors, alignments): m.add_text(*params) if config.getboolean('PICTURE', 'captures_cropping'): m.set_cropping() if overlay: m.set_overlay(overlay) if config.getboolean('GENERAL', 'debug'): m.set_outlines() maker = get_picture_maker(captures, config.get('PICTURE', 'orientation'), force_pil=True) _setup_maker(maker) previous_picture_file = osp.join(captures_folders, captures_folder + "_pibooth.jpg") maker.save(previous_picture_file)
def _is_internet(self): """check internet connexion""" try: requests.get('https://www.google.com/').status_code return True except requests.ConnectionError: LOGGER.warning("No internet connection!!!!") return False
def check_ability_I2C(self): """use to disable the plugin if system not able to use I2C like raspberry pi """ try: super().__init__() except ImportError as e: self._DISABLE = True LOGGER.warning( "System not support I2C, 'Pimoroni11x7' plugins is disable")
def do_actions(self, events): if self.app.config.getboolean( 'WINDOW', 'animate' ) and self.app.previous_animated and self.timer.is_timeout(): previous_picture = next(self.app.previous_animated) self.app.window.show_intro( previous_picture, self.app.printer.is_installed() and self.app.nbr_duplicates < self.app.config.getint( 'PRINTER', 'max_duplicates') and not self.app.printer_unavailable) self.timer.start() else: previous_picture = self.app.previous_picture if self.app.find_print_event(events) and self.app.previous_picture_file and self.app.printer.is_installed()\ and not (self.final_display_timer and self.final_display_timer.is_timeout()): if self.app.nbr_duplicates >= self.app.config.getint( 'PRINTER', 'max_duplicates'): LOGGER.warning( "Too many duplicates sent to the printer (%s max)", self.app.config.getint('PRINTER', 'max_duplicates')) return elif self.app.printer_unavailable: LOGGER.warning( "Maximum number of printed pages reached (%s/%s max)", self.app.printer.nbr_printed, self.app.config.getint('PRINTER', 'max_pages')) return with timeit("Send final picture to printer"): self.app.led_print.switch_on() self.app.printer.print_file( self.app.previous_picture_file, self.app.config.getint('PRINTER', 'pictures_per_page')) time.sleep(1) # Just to let the LED switched on self.app.nbr_duplicates += 1 if self.app.nbr_duplicates >= self.app.config.getint( 'PRINTER', 'max_duplicates') or self.app.printer_unavailable: self.app.window.show_intro(previous_picture, False) self.app.led_print.switch_off() else: self.app.led_print.blink() event = self.app.find_print_status_event(events) if event: self.app.window.set_print_number(len(event.tasks), self.app.printer_unavailable) if self.final_display_timer and self.final_display_timer.is_timeout(): self.app.window.show_intro(None, False)
def regenerate_all_images(config): """Regenerate the pibboth images from the raw images and the config """ captures_folders = config.getpath('GENERAL', 'directory') capture_choices = config.gettuple('PICTURE', 'captures', int, 2) backgrounds = config.gettuple('PICTURE', 'backgrounds', ('color', 'path'), 2) overlays = config.gettuple('PICTURE', 'overlays', 'path', 2) texts = [ config.get('PICTURE', 'footer_text1').strip('"'), config.get('PICTURE', 'footer_text2').strip('"') ] colors = config.gettuple('PICTURE', 'text_colors', 'color', len(texts)) text_fonts = config.gettuple('PICTURE', 'text_fonts', str, len(texts)) alignments = config.gettuple('PICTURE', 'text_alignments', str, len(texts)) # Part that fetch the captures for captures_folder in os.listdir(osp.join(captures_folders, 'raw')): captures_folder_path = osp.join(captures_folders, 'raw', captures_folder) if not osp.isdir(captures_folder_path): continue captures = get_captures(captures_folder_path) LOGGER.info("Generating image from raws in folder %s", captures_folder_path) if len(captures) == capture_choices[0]: overlay = overlays[0] background = backgrounds[0] elif len(captures) == capture_choices[1]: overlay = overlays[1] background = backgrounds[1] else: LOGGER.warning( "Folder %s doesn't contain the correct number of pictures", captures_folder_path) continue factory = get_picture_factory(captures, config.get('PICTURE', 'orientation')) factory.set_background(background) if any(elem != '' for elem in texts): for params in zip(texts, text_fonts, colors, alignments): factory.add_text(*params) if config.getboolean('PICTURE', 'captures_cropping'): factory.set_cropping() if overlay: factory.set_overlay(overlay) picture_file = osp.join(captures_folders, captures_folder + "_pibooth.jpg") factory.save(picture_file)
def initialize(self): """Restore the application with initial parameters defined in the configuration file. Only parameters that can be changed at runtime are restored. """ # Handle the language configuration language.CURRENT = self.config.get('GENERAL', 'language') fonts.CURRENT = fonts.get_filename( self.config.gettuple('PICTURE', 'text_fonts', str)[0]) # Set the captures choices choices = self.config.gettuple('PICTURE', 'captures', int) for chx in choices: if chx not in [1, 2, 3, 4]: LOGGER.warning( "Invalid captures number '%s' in config, fallback to '%s'", chx, self.capture_choices) choices = self.capture_choices break self.capture_choices = choices # Reset printed pages number self.printer.nbr_printed = 0 # Handle autostart of the application self.config.enable_autostart( self.config.getboolean('GENERAL', 'autostart')) self.window.arrow_location = self.config.get('WINDOW', 'arrows') self.window.arrow_offset = self.config.getint('WINDOW', 'arrows_x_offset') self.window.drop_cache() # Handle window size size = self.config.gettyped('WINDOW', 'size') if isinstance(size, str) and size.lower() == 'fullscreen': if not self.window.is_fullscreen: self.window.toggle_fullscreen() else: if self.window.is_fullscreen: self.window.toggle_fullscreen() self.window.debug = self.config.getboolean('GENERAL', 'debug') # Handle debug mode if not self.config.getboolean('GENERAL', 'debug'): set_logging_level() # Restore default level self.state_machine.add_failsafe_state(StateFailSafe(2)) else: set_logging_level(logging.DEBUG) self.state_machine.remove_state('failsafe') # Initialize state machine self.state_machine.set_state('wait')
def synchronize_pics(self, local_rep, rep_event): """ Upload Photos to Nextcloud """ if (self.is_connected == False): LOGGER.warning("Synchronize No internet connection") else: #Syncho repertoire nextcloud / upload USER_NC = self.nuser PASS_NC = self.npassword LOCAL_PATH_NC = local_rep REMOTE_PATH_NC = self.nhost + "/remote.php/webdav/" + rep_event nextcloudcmd = "nextcloudcmd" + " -u " + USER_NC + " -p " + PASS_NC + " -s " + LOCAL_PATH_NC + " " + REMOTE_PATH_NC os.system(nextcloudcmd)
def capture(self, effect=None): """Capture a new picture. """ retry = 0 max_retry = 2 while retry < max_retry: try: return super(GpCameraRetry, self).capture(effect) except Exception: LOGGER.warning("Gphoto2 fails to capture, trying again...") retry += 1 raise EnvironmentError( "Gphoto2 fails to capture {} times".format(max_retry))
def initialize(self): """Restore the application with initial parameters defined in the configuration file. Only parameters that can be changed at runtime are restored. """ # Handle the language configuration, save it as a class attribute for easy access language = self.config.get('GENERAL', 'language') if language not in get_supported_languages(): LOGGER.warning("Unsupported language '%s', fallback to English", language) else: PiConfigParser.language = language # Set the captures choices choices = self.config.gettuple('PICTURE', 'captures', int) for chx in choices: if chx not in [1, 2, 3, 4]: LOGGER.warning( "Invalid captures number '%s' in config, fallback to '%s'", chx, self.capture_choices) choices = self.capture_choices break self.capture_choices = choices # Reset printed pages number self.printer.nbr_printed = 0 # Handle autostart of the application self.config.enable_autostart( self.config.getboolean('GENERAL', 'autostart')) self.window.arrow_location = self.config.get('WINDOW', 'arrows') self.window.arrow_offset = self.config.getint('WINDOW', 'arrows_x_offset') self.window.drop_cache() # Handle window size size = self.config.gettyped('WINDOW', 'size') if isinstance(size, str) and size.lower() == 'fullscreen': if not self.window.is_fullscreen: self.window.toggle_fullscreen() else: if self.window.is_fullscreen: self.window.toggle_fullscreen() # Initialize state machine if self.config.getboolean('GENERAL', 'failsafe'): self.state_machine.add_failsafe_state(StateFailSafe(2)) else: self.state_machine.remove_state('failsafe') self.state_machine.set_state('wait')
def _initialize(self): """Camera initialisation """ self._cam = gp.Camera() self._cam.init() try: self.get_config_value('actions', 'viewfinder') self._preview_compatible = True except ValueError: LOGGER.warning("The connected DSLR camera is not compatible with preview") self._preview_compatible = False self.set_config_value('imgsettings', 'iso', self._iso) self.set_config_value('settings', 'capturetarget', 'Memory card')
def reload(self): """Reload current configuration file. """ self.read(self.filename) # Handle the language configuration, save it as a class attribute for easy access language = self.get('GENERAL', 'language') if language not in get_supported_languages(): LOGGER.warning("Unsupported language '%s', fallback to English", language) else: PiConfigParser.language = language # Handle autostart of the application self.enable_autostart(self.getboolean('GENERAL', 'autostart'))
def state_wait_do(self, cfg, app, events): if app.find_print_event(events) and app.previous_picture_file and app.printer.is_installed(): if app.count.remaining_duplicates <= 0: LOGGER.warning("Too many duplicates sent to the printer (%s max)", cfg.getint('PRINTER', 'max_duplicates')) return elif not app.printer.is_ready(): LOGGER.warning("Maximum number of printed pages reached (%s/%s max)", app.count.printed, cfg.getint('PRINTER', 'max_pages')) return self.print_picture(cfg, app)
def _set_config_value(self, section, option, value): """Set camera configuration. This method dont send the updated configuration to the camera (avoid connection flooding if several values to be changed) """ try: LOGGER.debug('Setting option %s/%s=%s', section, option, value) child = self._config.get_child_by_name(section).get_child_by_name(option) choices = [c for c in child.get_choices()] if not choices or value in choices: child.set_value(str(value)) else: LOGGER.warning("Invalid value '%s' for option %s (possible choices: %s)", value, option, choices) except gp.GPhoto2Error: raise ValueError('Unsupported setting {}/{}={}'.format(section, option, value))
def __init__(self, name='default'): self._conn = cups.Connection() if cups else None self._notif_server = NotificationServer(self._conn) self.name = None if not cups: LOGGER.warning("No printer found (pycups not installed)") return # CUPS is not installed elif not name or name.lower() == 'default': self.name = self._conn.getDefault() if not self.name and self._conn.getPrinters(): self.name = list(self._conn.getPrinters().keys())[0] # Take first one elif name in self._conn.getPrinters(): self.name = name if not self.name: LOGGER.warning("No printer found (nothing defined in CUPS)")
def get_translated_text(key): """Return the text corresponding to the key in the language defined in the config. :param key: key in the translation file :type key: str """ if not getattr(PARSER, 'filename', None): raise EnvironmentError("Translation system is not initialized") if PARSER.has_section(CURRENT) and PARSER.has_option(CURRENT, key): return PARSER.get(CURRENT, key).strip('"') elif PARSER.has_option('en', key): LOGGER.warning("Unsupported language '%s', fallback to English", CURRENT) return PARSER.get('en', key).strip('"') LOGGER.debug("No translation defined for '%s/%s' key", CURRENT, key) return None
def do_PUT(self): """Serve a PUT request. """ chunk_size = self.get_chunk_size() if chunk_size == 0: LOGGER.warning("Notification without data received") else: chunk_data = self.get_chunk_data(chunk_size) root = ElementTree.fromstring(chunk_data.decode('utf-8')) for channel in root.iterfind('channel'): for item in reversed([e for e in channel.iterfind('item')]): txt = ElementTree.tostring(item, encoding='utf8') if txt not in NotificationHandler._last_notif: # Print only the new notifications LOGGER.info("%s - %s", item.findtext('pubDate'), item.findtext('title')) NotificationHandler._last_notif.append(txt) self.send_response(200) self.end_headers()
def gp_camera_connected(): """Return True if a camera compatible with gPhoto2 is found. """ if not gp: LOGGER.warning("gphoto2 lib not found!") return False # gPhoto2 is not installed if hasattr(gp, 'gp_camera_autodetect'): # gPhoto2 version 2.5+ cameras = gp.check_result(gp.gp_camera_autodetect()) else: port_info_list = gp.PortInfoList() port_info_list.load() abilities_list = gp.CameraAbilitiesList() abilities_list.load() cameras = abilities_list.detect(port_info_list) if cameras: return True return False
def _specific_initialization(self): """Camera initialization. """ self._gp_logcb = gp.check_result( gp.gp_log_add_func(gp.GP_LOG_VERBOSE, gp_log_callback)) abilities = self._cam.get_abilities() self._preview_compatible = gp.GP_OPERATION_CAPTURE_PREVIEW ==\ abilities.operations & gp.GP_OPERATION_CAPTURE_PREVIEW if not self._preview_compatible: LOGGER.warning( "The connected DSLR camera is not compatible with preview") else: try: self.get_config_value('actions', 'viewfinder') self._preview_viewfinder = True except ValueError: self._preview_viewfinder = False self.set_config_value('imgsettings', 'iso', self.preview_iso) self.set_config_value('settings', 'capturetarget', 'Memory card')
def gp_set_config_value(config, section, option, value): """Set camera configuration. This method don't send the updated configuration to the camera (avoid connection flooding if several values have to be changed) """ try: value = GP_PARAMS.get(PiConfigParser.language, 'en').get(value, value) LOGGER.debug('Setting option %s/%s=%s', section, option, value) child = config.get_child_by_name(section).get_child_by_name(option) choices = [c for c in child.get_choices()] if value not in choices: LOGGER.warning( "Invalid value '%s' for option %s (possible choices: %s), still trying to set it", value, option, choices) child.set_value(str(value)) else: child.set_value(str(value)) except gp.GPhoto2Error: raise ValueError('Unsupported setting {}/{}={}'.format( section, option, value))
def do_PUT(self): """Serve a PUT request and trasfert event to server callback. """ chunk_size = self.get_chunk_size() if chunk_size == 0: LOGGER.warning("Notification without data received") else: chunk_data = self.get_chunk_data(chunk_size) root = ElementTree.fromstring(chunk_data.decode('utf-8')) for channel in root.iterfind('channel'): for item in reversed([e for e in channel.iterfind('item')]): txt = ElementTree.tostring(item, encoding='utf8') if txt not in NotificationHandler._last_notif: NotificationHandler._last_notif.append(txt) self.server.callback( dict((elem.tag, elem.text) for elem in item.iter() if elem.text.strip())) self.send_response(200) self.end_headers()
def _initialize(self): """Camera initialisation """ self._cam = gp.Camera() self._cam.init() abilities = self._cam.get_abilities() self._preview_compatible = gp.GP_OPERATION_CAPTURE_PREVIEW ==\ abilities.operations & gp.GP_OPERATION_CAPTURE_PREVIEW if not self._preview_compatible: LOGGER.warning( "The connected DSLR camera is not compatible with preview") else: try: self.get_config_value('actions', 'viewfinder') self._preview_viewfinder = True except ValueError: self._preview_viewfinder = False self.set_config_value('imgsettings', 'iso', self.iso_preview) self.set_config_value('settings', 'capturetarget', 'Memory card')
def __init__(self, name='default', max_pages=-1): self._conn = cups.Connection() if cups else None self._notifier = Subscriber(self._conn) if cups else None self.name = None self.max_pages = max_pages self.nbr_printed = 0 if not cups: LOGGER.warning( "No printer found (pycups or pycups-notify not installed)") return # CUPS is not installed elif not name or name.lower() == 'default': self.name = self._conn.getDefault() if not self.name and self._conn.getPrinters(): self.name = list( self._conn.getPrinters().keys())[0] # Take first one elif name in self._conn.getPrinters(): self.name = name if not self.name: if name.lower() == 'default': LOGGER.warning( "No printer configured in CUPS (see http://localhost:631)") else: LOGGER.warning( "No printer named '%s' in CUPS (see http://localhost:631)", name) else: LOGGER.info("Connected to printer '%s'", self.name)