def create_animation_frames(deck, image_filename): icon_frames = list() # Open the source image asset. icon = Image.open(os.path.join(ASSETS_PATH, image_filename)) # Iterate through each animation frame of the source image for frame in ImageSequence.Iterator(icon): # We need source frames in RGBA format, convert now before we resize it. icon_frame = frame.convert("RGBA") # Create new key image of the correct dimensions, black background. image = PILHelper.create_image(deck) # Resize the animation frame to best-fit the dimensions of a single key, # and paste it onto our blank frame centered as closely as possible. icon_frame.thumbnail(image.size, Image.LANCZOS) icon_frame_pos = ((image.width - icon_frame.width) // 2, (image.height - icon_frame.height) // 2) image.paste(icon_frame, icon_frame_pos, icon_frame) # Store the rendered animation frame in the device's native image # format for later use, so we don't need to keep converting it. icon_frames.append(PILHelper.to_native_format(deck, image)) # Return an infinite cycle generator that returns the next animation frame # each time it is called. return itertools.cycle(icon_frames)
def crop_key_image_from_deck_sized_image(deck, image, key_spacing, key): key_rows, key_cols = deck.key_layout() key_width, key_height = deck.key_image_format()['size'] spacing_x, spacing_y = key_spacing # Determine which row and column the requested key is located on. row = key // key_cols col = key % key_cols # Compute the starting X and Y offsets into the full size image that the # requested key should display. start_x = col * (key_width + spacing_x) start_y = row * (key_height + spacing_y) # Compute the region of the larger deck image that is occupied by the given # key, and crop out that segment of the full image. region = (start_x, start_y, start_x + key_width, start_y + key_height) segment = image.crop(region) # Create a new key-sized image, and paste in the cropped section of the # larger image. key_image = PILHelper.create_image(deck) key_image.paste(segment) return PILHelper.to_native_format(deck, key_image)
def _render_key_image(deck, icon: str = "", text: str = "", font: str = DEFAULT_FONT, **kwargs): """Renders an individual key image""" image = PILHelper.create_image(deck) draw = ImageDraw.Draw(image) if icon: rgba_icon = Image.open(icon).convert("RGBA") else: rgba_icon = Image.new("RGBA", (300, 300)) icon_width, icon_height = image.width, image.height if text: icon_height -= 20 rgba_icon.thumbnail((icon_width, icon_height), Image.LANCZOS) icon_pos = ((image.width - rgba_icon.width) // 2, 0) image.paste(rgba_icon, icon_pos, rgba_icon) if text: true_font = ImageFont.truetype(os.path.join(FONTS_PATH, font), 14) label_w, label_h = draw.textsize(text, font=true_font) if icon: label_pos = ((image.width - label_w) // 2, image.height - 20) else: label_pos = ((image.width - label_w) // 2, (image.height // 2) - 7) draw.text(label_pos, text=text, font=true_font, fill="white") return PILHelper.to_native_format(deck, image)
def create_animation_frames(deck, image_filename): icon_frames = list() # Open the source image asset icon = Image.open(os.path.join(os.path.dirname(__file__), "Assets", image_filename)) # Create a blank key image in the host image format, which we can # duplicate quickly for each animation frame to save time blank_image = PILHelper.create_image(deck) try: # Extract out each animation frame, resizing and converting to the # native device image format while True: image = blank_image.copy() # Resize the animation frame and paste it into the new image buffer icon_frame = icon.convert("RGBA") icon_frame.thumbnail(image.size, Image.LANCZOS) icon_frame_pos = ((image.width - icon_frame.width) // 2, (image.height - icon_frame.height) // 2) image.paste(icon_frame, icon_frame_pos, icon_frame) # Store the rendered animation frame in the device's native image # format for later use, so we don't need to keep converting it icon_frames.append(PILHelper.to_native_format(deck, image)) # Move to next animation frame in the source image icon.seek(icon.tell() + 1) except EOFError: # End of file, all image frames have been extracted pass # Return an infinite cycle generator that returns the next animation frame # each time it is called return itertools.cycle(icon_frames)
async def render_image_from_file(self, icon: str, label: str): """ Render the image from file into an image with optional label. this funckwargstion code is based on the render helper function from the python-elgato-streamdeck example code. Missing icons are not rendered. """ image = PILHelper.create_image(self.controller.deck) if icon: icon_path = self.asset_path / "icons" / icon if icon_path.is_file(): LOGGER.info(f"Rendering icon {icon}") icon_image = Image.open(str(icon_path)).convert("RGBA") icon_image.thumbnail((image.width, image.height - 20), Image.LANCZOS) icon_pos = ((image.width - icon_image.width) // 2, 0) image.paste(icon_image, icon_pos, icon_image) else: LOGGER.warning(f"Icon {icon} cannot be found") if label: LOGGER.debug("Getting font and rendering label") draw = ImageDraw.Draw(image) font = await self.get_font(self.label_font, 14) label_w, _ = draw.textsize(label, font=font) label_pos = ((image.width - label_w) // 2, image.height - 20) draw.text(label_pos, text=label, font=font, fill="white") return PILHelper.to_native_format(self.controller.deck, image)
def update_key_image(deck, key, state): if key % 2 == 0: filename = 'assets/sharingan.png' else: filename = 'assets/rinnegan.jpg' image = Image.open(filename) image = PILHelper.create_scaled_image(deck, image, margins=[0, 0, 0, 0]) image = PILHelper.to_native_format(deck, image) with deck: deck.set_key_image(key, image)
def render_key_image(deck, icon, font_filename, label_text): image = create_scaled_image(deck, icon, margins=[0, 0, 20, 0]) draw = ImageDraw.Draw(image) font = ImageFont.truetype(font_filename, 14) label_w, label_h = draw.textsize(label_text, font=font) label_pos = ((image.width - label_w) // 2, image.height - 20) draw.text(label_pos, text=label_text, font=font, fill="white") return PILHelper.to_native_format(deck, image)
def render_key_image(deck, icon_filename): # Create new key image of the correct dimensions, black background image = PILHelper.create_image(deck) draw = ImageDraw.Draw(image) # Add image overlay, rescaling the image asset if it is too large to fit # the requested dimensions via a high quality Lanczos scaling algorithm icon = Image.open(icon_filename).convert("RGBA") icon.thumbnail((image.width, image.height), Image.LANCZOS) image.paste(icon) return PILHelper.to_native_format(deck, image)
def render_key_image(self, streamdeck, page_name, key_number, icon_path, text): icon = Image.open(icon_path) image = PILHelper.create_scaled_image(streamdeck, icon, margins=[0, 0, 20, 0]) draw = ImageDraw.Draw(image) label_w, label_h = draw.textsize(text, font=self.font) label_pos = ((image.width - label_w) // 2, image.height - 20) draw.text(label_pos, text=text, font=self.font, fill="white") rendered_image = PILHelper.to_native_format(streamdeck, image) with streamdeck: streamdeck.set_key_image(key_number, rendered_image)
def ActualizarImagen(deck, teclas, tecla, limpiar=False): global folder image = PILHelper.create_image(deck) if not limpiar: nombre = "{}".format(teclas[tecla]['Nombre']) if 'Regresar' in teclas[tecla]: if 'ico' in teclas[tecla]: NombreIcon = "{}".format(teclas[tecla]['ico']) elif 'ico_Regresar' in data: NombreIcon = data['ico_Regresar'] else: NombreIcon = "imagen.png" elif 'Estado' in teclas[tecla]: # print("Hay estado {}".format(teclas[tecla]['Estado'])) if teclas[tecla]['Estado'] and 'icon_true' in teclas[tecla]: NombreIcon = teclas[tecla]['icon_true'] elif not teclas[tecla]['Estado'] and 'icon_false' in teclas[tecla]: NombreIcon = teclas[tecla]['icon_false'] elif 'ico_defecto' in data: NombreIcon = data['ico_defecto'] else: NombreIcon = "imagen.png" elif 'ico' in teclas[tecla]: NombreIcon = "{}".format(teclas[tecla]['ico']) else: if 'ico_defecto' in data: NombreIcon = data['ico_defecto'] else: NombreIcon = "imagen.png" icon = Image.open(NombreIcon).convert("RGBA") icon.thumbnail((image.width, image.height - 20), Image.LANCZOS) icon_posicion = ((image.width - icon.width) // 2, 0) image.paste(icon, icon_posicion, icon) titulo = '' if 'Titulo' in teclas[tecla]: titulo = "{}".format(teclas[tecla]['Titulo']) if not titulo == '': dibujo = ImageDraw.Draw(image) font = ImageFont.truetype(fuente, 14) label_w, label_h = dibujo.textsize(titulo, font=font) label_pos = ((image.width - label_w) // 2, image.height - 20) dibujo.text(label_pos, text=titulo, font=font, fill="white") deck.set_key_image(tecla, PILHelper.to_native_format(deck, image))
def update(self, deck): x = sd.getBoolean(f"Status/{self.key}", False) y = sd.getBoolean(f"Action/{self.key}", False) icon_array = sd.getStringArray("Icons", []) name = icon_array[self.key] image = None if x: image = render_key_image(deck, name + "/active.png") else: image = render_key_image(deck, name + "/inactive.png") if y: image = image_tint(image, tint="#882020") image = PILHelper.to_native_format(deck, image) deck.set_key_image(self.key, image)
def test_key_pattern(deck): test_key_image = PILHelper.create_image(deck) draw = ImageDraw.Draw(test_key_image) draw.rectangle((0, 0) + test_key_image.size, fill=(0x11, 0x22, 0x33), outline=(0x44, 0x55, 0x66)) test_key_image = PILHelper.to_native_format(deck, test_key_image) with deck: deck.open() deck.set_key_image(0, test_key_image) deck.close()
def run(self): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(('127.0.0.1', 5555)) s.listen(1) conn, addr = s.accept() with conn: while True: image = PILHelper.create_image(deck) frame = conn.recv(11664) if not frame: break video = Image.frombytes('RGB', (72, 54), frame, 'raw') image.paste(video, (0, 0)) deck.set_key_image(14, PILHelper.to_native_format(deck, image))
def render_key_image(deck, btn): # Create new key image of the correct dimensions, black background image = PILHelper.create_image(deck) draw = ImageDraw.Draw(image) if btn.selected: draw.rectangle((0, 0, image.width - 1, image.height - 1), fill=btn.selected_color) label_w, label_h = draw.textsize(btn.label) label_pos = ((image.width - label_w) // 2, (image.height - label_h) // 2) draw.text(label_pos, text=btn.label, fill="white") return PILHelper.to_native_format(deck, image)
def getAsset(deck, assetFilename): """ Load an image asset from the given filename. Returned in the native format of `deck` """ image = PILHelper.create_image(deck) # Resize the source image asset to best-fit the dimensions of a single key, # and paste it onto our blank frame centered as closely as possible. icon = Image.open(os.path.join(ASSETS_PATH, assetFilename)).convert("RGBA") icon.thumbnail((image.width, image.height - 20), Image.LANCZOS) icon_pos = ((image.width - icon.width) // 2, 0) image.paste(icon, icon_pos, icon) return PILHelper.to_native_format(deck, image)
def render_key_image(deck, icon_filename, font_filename, label_text): # Resize the source image asset to best-fit the dimensions of a single key, # leaving a margin at the bottom so that we can draw the key title # afterwards. icon = Image.open(icon_filename) image = PILHelper.create_scaled_image(deck, icon, margins=[0, 0, 20, 0]) # Load a custom TrueType font and use it to overlay the key index, draw key # label onto the image. draw = ImageDraw.Draw(image) font = ImageFont.truetype(font_filename, 14) label_w, label_h = draw.textsize(label_text, font=font) label_pos = ((image.width - label_w) // 2, image.height - 20) draw.text(label_pos, text=label_text, font=font, fill="white") return PILHelper.to_native_format(deck, image)
async def render_clock_number(self, number: int) -> Image.Image: LOGGER.info(f"Rendering number {number}") image = PILHelper.create_image(self.controller.deck) text = f"{number:02d}" font = await self.get_font(self.label_font, 50) draw = ImageDraw.Draw(image) w, _h = draw.textsize(text, font=font) h_pos = image.height // 8 pos = ((image.width - w) // 2, h_pos) draw.text(pos, text=text, font=font, fill="white") return PILHelper.to_native_format(self.controller.deck, image)
def getCharacterAsset(deck, character, background='black', color='white'): if character in characterAssets: return characterAssets[character] image = PILHelper.create_image(deck, background=background) # Load a custom TrueType font and use it to overlay the key index, draw key # label onto the image. draw = ImageDraw.Draw(image) font = ImageFont.truetype(os.path.join(ASSETS_PATH, FONT_NAME), 96) label_w, label_h = draw.textsize(character, font=font) label_pos = (0, 0) #((image.width - label_w) // 2, image.height - 20) draw.text(label_pos, text=character, font=font, fill=color) nativeImage = PILHelper.to_native_format(deck, image) characterAssets[character] = nativeImage return nativeImage
def getInitializedDeck(initBrightness=30, deviceNum=0, background='black'): """ Initialize and return the first stream deck device or None. """ streamdecks = DeviceManager().enumerate() if streamdecks and len(streamdecks) >= deviceNum + 1: deck = streamdecks[deviceNum] deck.open() deck.reset() deck.set_brightness(initBrightness) # Blank background of provided color keyImage = PILHelper.to_native_format( deck, PILHelper.create_image(deck, background)) for keyNum in range(deck.key_count()): deck.set_key_image(keyNum, keyImage) return deck print("Unable to open any stream deck devices.") return None
def __getitem__(self, key): if self._pixels is None: image = PILHelper.create_image(self._deck, background=self._color) l_x, l_y, l_w, l_h = self._draw_label(image) v_x, v_y, v_w, v_h = self._draw_value(image) o_x = 0 o_y = (l_y or 0) + (l_h or 0) o_w = image.width o_h = (v_y or image.height) - o_y overlay_pos = (int(o_x), int(o_y)) overlay_size = (int(o_w), int(o_h)) self._draw_overlay(image, overlay_pos, overlay_size) self._pixels = PILHelper.to_native_format(self._deck, image) return self._pixels[key]
def CargarGif(self, accion): """Extra frame de un gif y los guarda en una lista.""" # TODO: Errro con git con estado no se desactiva if "gif_cargado" in accion: self.ListaGif.append(accion) return DirecionGif = BuscarDirecionImagen(accion) if DirecionGif is not None and not DirecionGif.endswith("gif"): return Gif = list() ColorFondo = "black" if "imagen_opciones" in accion: opciones = accion["imagen_opciones"] if "fondo" in opciones: ColorFondo = opciones["fondo"] DirecionGif = RelativoAbsoluto(DirecionGif, self.Deck.Folder) DirecionGif = UnirPath(ObtenerFolderConfig(), DirecionGif) if os.path.exists(DirecionGif): GifArchivo = Image.open(DirecionGif) for frame in ImageSequence.Iterator(GifArchivo): Gif_frame = PILHelper.create_scaled_image( self.Deck, frame, background=ColorFondo) if "cargar_titulo" in accion: TextoCargar = accion["cargar_titulo"] if "archivo" in TextoCargar and "atributo" in TextoCargar: accion["titulo"] = ObtenerValor( TextoCargar["archivo"], TextoCargar["atributo"]) if "titulo" in accion: PonerTexto(Gif_frame, accion, True) ImagenNativa = PILHelper.to_native_format(self.Deck, Gif_frame) Gif.append(ImagenNativa) accion["gif_cargado"] = itertools.cycle(Gif) self.ListaGif.append(accion) else: logger.warning(f"Deck[No Gifs] {DirecionGif}")
def crop_key_image_from_deck_sized_image(deck, image, key): key_width, key_height = deck.key_image_format()['size'] key_rows, key_cols = deck.key_layout() # Determine which row and column the requested key is located on. row = key // key_cols col = key % key_cols # Compute the region of the larger deck image that is occupied by the given # key. region = (col * key_width, row * key_height, (col + 1) * key_width, (row + 1) * key_height) segment = image.crop(region) # Create a new key-sized image, and paste in the cropped section of the # larger image. key_image = PILHelper.create_image(deck) key_image.paste(segment) return PILHelper.to_native_format(deck, key_image)
def render_key_image(deck, icon_filename, font_filename, label_text): # Create new key image of the correct dimensions, black background image = PILHelper.create_image(deck) draw = ImageDraw.Draw(image) # Add image overlay, rescaling the image asset if it is too large to fit # the requested dimensions via a high quality Lanczos scaling algorithm icon = Image.open(icon_filename).convert("RGBA") icon.thumbnail((image.width, image.height - 20), Image.LANCZOS) icon_pos = ((image.width - icon.width) // 2, 0) image.paste(icon, icon_pos, icon) # Load a custom TrueType font and use it to overlay the key index, draw key # label onto the image font = ImageFont.truetype(font_filename, 14) label_w, label_h = draw.textsize(label_text, font=font) label_pos = ((image.width - label_w) // 2, image.height - 20) draw.text(label_pos, text=label_text, font=font, fill="white") return PILHelper.to_native_format(deck, image)
def render_key_image(deck, icon_filename, font_filename, label_text, fill): # Create new key image of the correct dimensions, black background. image = PILHelper.create_image(deck) # Resize the source image asset to best-fit the dimensions of a single key, # and paste it onto our blank frame centered as closely as possible. icon = Image.open(icon_filename).convert("RGBA") icon.thumbnail((image.width, image.height), Image.LANCZOS) icon_pos = ((image.width - icon.width) // 2, (image.height - icon.height) // 2) image.paste(icon, icon_pos, icon) # Load a custom TrueType font and use it to overlay the key index, draw key # label onto the image. draw = ImageDraw.Draw(image) font = ImageFont.truetype(font_filename, 14) label_w, label_h = draw.textsize(label_text, font=font) label_pos = ((image.width - label_w) // 2, image.height - 20) draw.text(label_pos, text=label_text, font=font, fill=fill) return PILHelper.to_native_format(deck, image)
def create_animation_frames(deck, image_filename): icon_frames = list() # Open the source image asset. icon = Image.open(os.path.join(ASSETS_PATH, image_filename)) # Iterate through each animation frame of the source image for frame in ImageSequence.Iterator(icon): # Create new key image of the correct dimensions, black background. frame_image = PILHelper.create_scaled_image(deck, frame) # Pre-convert the generated image to the native format of the StreamDeck # so we don't need to keep converting it when showing it on the device. native_frame_image = PILHelper.to_native_format(deck, frame_image) # Store the rendered animation frame for later user. icon_frames.append(native_frame_image) # Return an infinite cycle generator that returns the next animation frame # each time it is called. return itertools.cycle(icon_frames)
def compose_image(self, overlay_level=0): if not self.compose_image_cache: layers = self.resolved_layers text_lines = self.resolved_text_lines try: if not layers and not text_lines: self.compose_image_cache = (None, None) else: layers = self.sort_layers(layers) if layers else {} if layers: if len(layers) > 1: # if more than one layer, we ignore the image used if no specific layers layers.pop(-1, None) text_lines = self.sort_text_lines( text_lines) if text_lines else {} if text_lines: if len(text_lines) > 1: # if more than one text line, we ignore the one used if no specific lines text_lines.pop(-1, None) if not layers and not text_lines: self.compose_image_cache = None, None else: all_layers = list(layers.values()) + list( text_lines.values()) final_image = Image.new("RGB", self.image_size, "black") for layer in all_layers: try: if (composed := layer.compose()) is None: continue rendered_layer, position_x, position_y, mask = composed except Exception: logger.error( f"[{layer}] Layer could not be rendered", exc_info=logger.level <= logging.DEBUG) continue # we simply ignore a layer that couldn't be created final_image.paste(rendered_layer, (position_x, position_y), mask) self.compose_image_cache = final_image, PILHelper.to_native_format( self.deck.device, final_image)
def render_key(config, deck, icon_filename, font_filename, label): image = PILHelper.create_image(deck) has_label = label is not None and label != "" # Render the image in case it exists. if os.path.exists(icon_filename): icon = Image.open(icon_filename).convert("RGBA") image_height = image.height - 20 if has_label else image.height - 5 image_width = image.width if has_label else image.width - 2 icon.thumbnail((image_width, image_height), Image.LANCZOS) icon_pos = ((image.width - icon.width) // 2, 0) image.paste(icon, icon_pos, icon) # Render the label. if has_label: draw = ImageDraw.Draw(image) font = ImageFont.truetype(font_filename, config.font_size) label_w, label_h = draw.textsize(label, font=font) label_pos = ((image.width - label_w) // 2, image.height - 20) draw.text(label_pos, text=label, font=font, fill="white") return PILHelper.to_native_format(deck, image)
def render_key_image(deck, icon_filename, title, value): # Create new key image of the correct dimensions, black background image = PILHelper.create_image(deck) draw = ImageDraw.Draw(image) # Add image overlay, rescaling the image asset if it is too large to fit # the requested dimensions via a high quality Lanczos scaling algorithm if icon_filename: icon = Image.open(icon_filename).convert("RGBA") icon.thumbnail((image.width, image.height), Image.LANCZOS) image.paste(icon) if value: font = ImageFont.truetype('arial', 22) draw.text((image.width - 5, image.height / 2), text=str(int(value)), font=font, anchor="rs", fill="white") if title: font = ImageFont.truetype('arial', 12) draw.text((image.width / 2, image.height - 5), text=title, font=font, anchor="ms", fill="white") return PILHelper.to_native_format(deck, image)
def __init__(self, manager, deck): self._manager = manager self._deck = deck self._rows = self._deck.KEY_ROWS self._cols = self._deck.KEY_COLS self._btnw = self._deck.KEY_PIXEL_WIDTH self._btnh = self._deck.KEY_PIXEL_HEIGHT self._root = None self._last_key_time = 0 self._deck.open() self._deck.reset() self._deck.set_brightness(50) self._deck.set_key_callback(functools.partial(self.key_change_callback)) highlight_image = Image.new("RGB", (self._btnw, self._btnh), "white") self._highlight_image = PILHelper.to_native_format(self._deck, highlight_image) self._highlight_button = None self._rebuild_layout = True print("Started deck " + self.serial_number())
def ActualizarIcono(Deck, indice, accion): global FuenteIcono global ImagenBase global ListaImagenes ColorFondo = "black" imagenFondo = None if "imagen_opciones" in accion: opciones = accion["imagen_opciones"] if "fondo" in opciones: ColorFondo = opciones["fondo"] if "imagen" in opciones: imagenFondo = opciones["imagen"] ImagenBoton = PILHelper.create_image(Deck, background=ColorFondo) if imagenFondo is not None: PonerImagen(ImagenBoton, imagenFondo, accion, Deck.Folder, True) DirecionImagen = BuscarDirecionImagen(accion) if DirecionImagen is not None: if DirecionImagen.endswith(".gif"): # TODO: Meter proceso gif adentro return None PonerImagen(ImagenBoton, DirecionImagen, accion, Deck.Folder) if "cargar_titulo" in accion: TextoCargar = accion["cargar_titulo"] if "archivo" in TextoCargar and "atributo" in TextoCargar: accion["titulo"] = ObtenerValor(TextoCargar["archivo"], TextoCargar["atributo"]) if "titulo" in accion: PonerTexto(ImagenBoton, accion, DirecionImagen) Deck.set_key_image(indice, PILHelper.to_native_format(Deck, ImagenBoton))