flipperzero-firmware/scripts/flipper/assets/icon.py

114 lines
3.0 KiB
Python

import logging
import argparse
import subprocess
import io
import os
import sys
ICONS_SUPPORTED_FORMATS = ["png"]
class Image:
def __init__(self, width: int, height: int, data: bytes):
self.width = width
self.height = height
self.data = data
def write(self, filename):
with open(filename, "wb") as file:
file.write(self.data)
def data_as_carray(self):
return (
"{" + "".join("0x{:02x},".format(img_byte) for img_byte in self.data) + "}"
)
def is_file_an_icon(filename):
extension = filename.lower().split(".")[-1]
return extension in ICONS_SUPPORTED_FORMATS
class ImageTools:
__pil_unavailable = False
__hs2_unavailable = False
@staticmethod
def is_processing_slow():
try:
from PIL import Image, ImageOps
import heatshrink2
return False
except ImportError as e:
return True
def __init__(self):
self.logger = logging.getLogger()
def png2xbm(self, file):
if self.__pil_unavailable:
return subprocess.check_output(["convert", file, "xbm:-"])
try:
from PIL import Image, ImageOps
except ImportError as e:
self.__pil_unavailable = True
self.logger.info("pillow module is missing, using convert cli util")
return self.png2xbm(file)
with Image.open(file) as im:
with io.BytesIO() as output:
bw = im.convert("1")
bw = ImageOps.invert(bw)
bw.save(output, format="XBM")
return output.getvalue()
def xbm2hs(self, data):
if self.__hs2_unavailable:
return subprocess.check_output(
["heatshrink", "-e", "-w8", "-l4"], input=data
)
try:
import heatshrink2
except ImportError as e:
self.__hs2_unavailable = True
self.logger.info("heatshrink2 module is missing, using heatshrink cli util")
return self.xbm2hs(data)
return heatshrink2.compress(data, window_sz2=8, lookahead_sz2=4)
__tools = ImageTools()
def file2image(file):
output = __tools.png2xbm(file)
assert output
# Extract data from text
f = io.StringIO(output.decode().strip())
width = int(f.readline().strip().split(" ")[2])
height = int(f.readline().strip().split(" ")[2])
data = f.read().strip().replace("\n", "").replace(" ", "").split("=")[1][:-1]
data_str = data[1:-1].replace(",", " ").replace("0x", "")
data_bin = bytearray.fromhex(data_str)
# Encode icon data with LZSS
data_encoded_str = __tools.xbm2hs(data_bin)
assert data_encoded_str
data_enc = bytearray(data_encoded_str)
data_enc = bytearray([len(data_enc) & 0xFF, len(data_enc) >> 8]) + data_enc
# Use encoded data only if its lenght less than original, including header
if len(data_enc) < len(data_bin) + 1:
data = b"\x01\x00" + data_enc
else:
data = b"\x00" + data_bin
return Image(width, height, data)