Add SVG support
parent
bb13ef5937
commit
d9792187fd
|
@ -1,5 +1,7 @@
|
||||||
libsailfishapp-launcher
|
libsailfishapp-launcher
|
||||||
|
sailfish-svg2png
|
||||||
pyotherside-qml-plugin-python3-qt5
|
pyotherside-qml-plugin-python3-qt5
|
||||||
python3-base
|
python3-base
|
||||||
python3-imaging
|
python3-imaging
|
||||||
python3-requests
|
python3-requests
|
||||||
|
python3-lxml
|
||||||
|
|
100
src/main.py
100
src/main.py
|
@ -4,31 +4,56 @@ from PIL.Image import Image as ImageType
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from glob import glob
|
from glob import glob
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
from subprocess import getstatusoutput
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
from functools import lru_cache
|
||||||
import requests
|
import requests
|
||||||
import base64
|
import base64
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import logging
|
import logging
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
ICON_SIZE = (256, 256)
|
||||||
|
|
||||||
logging_filename = os.path.join(os.path.expanduser("~"),
|
logging_filename = os.path.join(os.path.expanduser("~"),
|
||||||
".local",
|
".local",
|
||||||
"share",
|
"share",
|
||||||
"org.kirbylife",
|
"dev.kirbylife",
|
||||||
"harbour-muchkin",
|
"harbour-muchkin",
|
||||||
"muchkin.log")
|
"muchkin.log")
|
||||||
os.makedirs(os.path.dirname(logging_filename), exist_ok=True)
|
os.makedirs(os.path.dirname(logging_filename), exist_ok=True)
|
||||||
logging.basicConfig(filename=logging_filename, filemode="w", level=logging.DEBUG)
|
logging.basicConfig(filename=logging_filename, filemode="w", level=logging.DEBUG)
|
||||||
|
|
||||||
|
@lru_cache(maxsize=50)
|
||||||
def download_icon(url) -> ImageType:
|
def download_icon(url) -> ImageType:
|
||||||
response = requests.get(url)
|
response = requests.get(url)
|
||||||
img = Image.open(BytesIO(response.content))
|
img = Image.open(BytesIO(response.content))
|
||||||
|
img.thumbnail(ICON_SIZE)
|
||||||
img = img.convert("RGBA")
|
img = img.convert("RGBA")
|
||||||
return img
|
return img
|
||||||
|
|
||||||
|
@lru_cache(maxsize=50)
|
||||||
def base64_to_img(base64_bytes: bytes) -> ImageType:
|
def base64_to_img(base64_bytes: bytes) -> ImageType:
|
||||||
img_bytes = base64.b64decode(base64_bytes)
|
img_bytes = base64.b64decode(base64_bytes)
|
||||||
img_buffer = BytesIO(img_bytes)
|
img_buffer = BytesIO(img_bytes)
|
||||||
img = Image.open(img_buffer)
|
img = Image.open(img_buffer)
|
||||||
|
img.thumbnail(ICON_SIZE)
|
||||||
|
img = img.convert("RGBA")
|
||||||
|
return img
|
||||||
|
|
||||||
|
@lru_cache(maxsize=50)
|
||||||
|
def svg_to_img(svg_url: str) -> ImageType:
|
||||||
|
response = requests.get(svg_url)
|
||||||
|
with tempfile.TemporaryDirectory() as d:
|
||||||
|
with open(os.path.join(d, "icon.svg"), "w") as f:
|
||||||
|
f.write(response.text)
|
||||||
|
status, output = getstatusoutput(f"sailfish_svg2png -z 16 {d} {d}")
|
||||||
|
logging.info("Converted svg to png")
|
||||||
|
logging.info(f"sailfish_svg2png status {status}: {output}")
|
||||||
|
|
||||||
|
img = Image.open(os.path.join(d, "icon.png"))
|
||||||
|
img.thumbnail(ICON_SIZE)
|
||||||
img = img.convert("RGBA")
|
img = img.convert("RGBA")
|
||||||
return img
|
return img
|
||||||
|
|
||||||
|
@ -42,9 +67,12 @@ def avg_colors(img):
|
||||||
counter[pixel] += 1
|
counter[pixel] += 1
|
||||||
return counter.most_common(1)[0][0]
|
return counter.most_common(1)[0][0]
|
||||||
|
|
||||||
def add_background(img: ImageType, bg_tuple: tuple) -> ImageType:
|
def add_background(img: ImageType, bg_tuple: tuple, size: float) -> ImageType:
|
||||||
|
img = img.copy()
|
||||||
|
size = size / 100
|
||||||
bg = Image.new("RGBA", img.size, bg_tuple)
|
bg = Image.new("RGBA", img.size, bg_tuple)
|
||||||
bg.paste(img, (0, 0), img)
|
img.thumbnail((value * size for value in img.size))
|
||||||
|
bg.paste(img, ((bg.size[0] - img.size[0]) // 2, (bg.size[1] - img.size[1]) // 2), img)
|
||||||
return bg
|
return bg
|
||||||
|
|
||||||
def crop_to_circle(im, template):
|
def crop_to_circle(im, template):
|
||||||
|
@ -70,9 +98,7 @@ def parse_file(desktop_path):
|
||||||
output = {}
|
output = {}
|
||||||
with open(desktop_path, "r") as f:
|
with open(desktop_path, "r") as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
if not line:
|
if not line or line.startswith("["):
|
||||||
continue
|
|
||||||
if line.startswith("["):
|
|
||||||
continue
|
continue
|
||||||
key, value = line.split("=", 1)
|
key, value = line.split("=", 1)
|
||||||
output[key] = value.strip()
|
output[key] = value.strip()
|
||||||
|
@ -97,21 +123,23 @@ def get_web_icons():
|
||||||
|
|
||||||
return list(map(parse_file, apps))
|
return list(map(parse_file, apps))
|
||||||
|
|
||||||
def sailify(raw_str, pattern):
|
def sailify(raw_str, pattern, size) -> str:
|
||||||
try:
|
url_parsed = urlparse(raw_str)
|
||||||
# New versions of Sailfish has the url on the icons
|
if url_parsed.scheme == "data":
|
||||||
img = download_icon(raw_str)
|
|
||||||
logging.info("Downloaded from url: " + raw_str)
|
|
||||||
except requests.exceptions.InvalidSchema:
|
|
||||||
# The old ones converted the icon to base64
|
# The old ones converted the icon to base64
|
||||||
base64_bytes = raw_str.replace("data:image/png;base64,", "", 1).encode()
|
base64_bytes = raw_str.replace("data:image/png;base64,", "", 1).encode()
|
||||||
img = base64_to_img(base64_bytes)
|
img = base64_to_img(base64_bytes)
|
||||||
logging.info("Converted from base64")
|
logging.info("Converted from base64")
|
||||||
except Exception as e:
|
# New versions of Sailfish has the url on the icons
|
||||||
logging.error(e)
|
elif url_parsed.path.split("/")[-1].split(".")[-1].upper() == "SVG":
|
||||||
raise e
|
img = svg_to_img(raw_str)
|
||||||
|
logging.info("Downloaded from url: " + raw_str)
|
||||||
|
else:
|
||||||
|
img = download_icon(raw_str)
|
||||||
|
logging.info("Downloaded from url: " + raw_str)
|
||||||
|
|
||||||
bg_tuple = avg_colors(img)
|
bg_tuple = avg_colors(img)
|
||||||
img = add_background(img, bg_tuple)
|
img = add_background(img, bg_tuple, size)
|
||||||
img = crop_to_circle(img, pattern)
|
img = crop_to_circle(img, pattern)
|
||||||
output_buffer = BytesIO()
|
output_buffer = BytesIO()
|
||||||
img.save(output_buffer, format="PNG")
|
img.save(output_buffer, format="PNG")
|
||||||
|
@ -133,43 +161,3 @@ def save_icon(app):
|
||||||
f.write(new_content)
|
f.write(new_content)
|
||||||
logging.info("Icon saved on: " + app["path"])
|
logging.info("Icon saved on: " + app["path"])
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def main():
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
while True:
|
|
||||||
apps = get_web_icons()
|
|
||||||
while True:
|
|
||||||
for n, app in enumerate(apps):
|
|
||||||
print(f"{n}) {app['Name']}")
|
|
||||||
index = input("select an application (the index):\n>>> ")
|
|
||||||
index = int(index)
|
|
||||||
if index >= len(apps):
|
|
||||||
print("Select a valid index")
|
|
||||||
continue
|
|
||||||
break
|
|
||||||
app = apps[index]
|
|
||||||
|
|
||||||
if app["Icon"] == "icon-launcher-bookmark":
|
|
||||||
print("this webapp is using the generic icon of a bookmark and not a favicon so it is not possible to modify")
|
|
||||||
continue
|
|
||||||
|
|
||||||
while True:
|
|
||||||
pattern = input("Enter the pattern (0 = round, 1 = peak):\n>>> ")
|
|
||||||
if len(pattern) != 4:
|
|
||||||
print("it is necessary to enter 4 characters")
|
|
||||||
pattern = tuple(map(int, pattern))
|
|
||||||
new_icon = sailify(app.get("old_icon", app["Icon"]), pattern)
|
|
||||||
# Backup the original .desktop
|
|
||||||
shutil.copyfile(app["path"], app["path"] + "_backup")
|
|
||||||
app["old_icon"] = app.get("old_icon", app["Icon"])
|
|
||||||
app["Icon"] = new_icon
|
|
||||||
new_content = deparse_file(app)
|
|
||||||
with open(app["path"], "w") as f:
|
|
||||||
f.write(new_content)
|
|
||||||
print(f"{app['Name']} sailified correctly")
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
|
|
Loading…
Reference in New Issue