mirror of
https://github.com/Steffo99/emblematic.git
synced 2024-11-21 22:34:19 +00:00
Things work correctly now
This commit is contained in:
parent
c08acba846
commit
c7b949cadb
16 changed files with 216 additions and 94 deletions
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
|
@ -10,7 +10,7 @@
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"module": "emblematic",
|
"module": "emblematic",
|
||||||
"justMyCode": true,
|
"justMyCode": true,
|
||||||
"args": ["--output-file=output.svg", "--background-file=/store/Documents/Workspaces/RYGhub/logos/current/bg.svg", "--foreground-file=/home/steffo/Pictures/Font Awesome/svgs/solid/apple-whole.svg"]
|
"args": ["basic", "--background=/store/Documents/Workspaces/RYGhub/logos/current/watermark.svg", "--icon=/home/steffo/Pictures/Font Awesome/svgs", "--fill=#feedb4", "--output-dir=/home/steffo/Workspaces/Steffo99/emblematic-1/output"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
# TODO: If you're building a library, remove this file!
|
|
||||||
|
|
||||||
FROM python:3-alpine AS system
|
FROM python:3-alpine AS system
|
||||||
# TODO: Add whatever dependency your image may require
|
|
||||||
RUN apk add --update build-base python3-dev py-pip musl-dev
|
RUN apk add --update build-base python3-dev py-pip musl-dev
|
||||||
RUN pip install "poetry"
|
RUN pip install "poetry"
|
||||||
|
|
||||||
FROM system AS workdir
|
FROM system AS workdir
|
||||||
# TODO: Use the name of your project
|
|
||||||
WORKDIR /usr/src/emblematic
|
WORKDIR /usr/src/emblematic
|
||||||
|
|
||||||
FROM workdir AS dependencies
|
FROM workdir AS dependencies
|
||||||
|
@ -20,9 +16,8 @@ RUN poetry install
|
||||||
|
|
||||||
FROM package AS entrypoint
|
FROM package AS entrypoint
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
ENTRYPOINT ["poetry", "run", "python", "-m"]
|
ENTRYPOINT ["poetry", "run", "python", "-m", "emblematic"]
|
||||||
# TODO: Set the name of your Python module
|
CMD []
|
||||||
CMD ["emblematic"]
|
|
||||||
|
|
||||||
FROM entrypoint AS labels
|
FROM entrypoint AS labels
|
||||||
# TODO: Set a Docker image title
|
# TODO: Set a Docker image title
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
Simple icon generator
|
Simple icon generator
|
||||||
|
|
||||||
\[ **[Documentation]** | **[Available on PyPI]** | [Repository] \]
|
\[ **[Documentation]** | **[PyPI]** | [Repository] \]
|
||||||
|
|
||||||
<!-- Add an image or some examples here, if available! -->
|
<!-- Add an image or some examples here, if available! -->
|
||||||
|
|
||||||
|
|
||||||
[Documentation]: https://emblematic.readthedocs.io/latest/
|
[Documentation]: https://emblematic.readthedocs.io/latest/
|
||||||
[Available on PyPI]: https://pypi.org/project/emblematic
|
[PyPI]: https://pypi.org/project/emblematic
|
||||||
[Repository]: https://github.com/Steffo99/emblematic/
|
[Repository]: https://github.com/Steffo99/emblematic/
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
version: "3.9"
|
|
||||||
|
|
||||||
services:
|
|
||||||
emblematic:
|
|
||||||
image: "ghcr.io/Steffo99/emblematic:latest"
|
|
||||||
restart: unless-stopped
|
|
||||||
env_file:
|
|
||||||
- "stack.env"
|
|
17
docs/source/api.rst
Normal file
17
docs/source/api.rst
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
*******************************************************************************
|
||||||
|
API reference
|
||||||
|
*******************************************************************************
|
||||||
|
|
||||||
|
|
||||||
|
============
|
||||||
|
``.compose``
|
||||||
|
============
|
||||||
|
|
||||||
|
.. automodule:: emblematic.compose
|
||||||
|
|
||||||
|
|
||||||
|
==========
|
||||||
|
``.files``
|
||||||
|
==========
|
||||||
|
|
||||||
|
.. automodule:: emblematic.files
|
|
@ -96,7 +96,6 @@ nitpicky = False
|
||||||
# Intersphinx URLs
|
# Intersphinx URLs
|
||||||
intersphinx_mapping = {
|
intersphinx_mapping = {
|
||||||
"python": ("https://docs.python.org/3.10", None),
|
"python": ("https://docs.python.org/3.10", None),
|
||||||
"poetry":
|
|
||||||
}
|
}
|
||||||
# Manpages URL
|
# Manpages URL
|
||||||
manpages_url = "https://man.archlinux.org/"
|
manpages_url = "https://man.archlinux.org/"
|
||||||
|
|
|
@ -15,7 +15,8 @@ Table of contents
|
||||||
.. toctree::
|
.. toctree::
|
||||||
|
|
||||||
installation
|
installation
|
||||||
|
usage
|
||||||
|
api
|
||||||
|
|
||||||
|
|
||||||
============
|
============
|
||||||
|
|
|
@ -40,7 +40,7 @@ Using pip
|
||||||
$ # On Fish
|
$ # On Fish
|
||||||
$ source .venv/bin/activate.fish
|
$ source .venv/bin/activate.fish
|
||||||
|
|
||||||
.. code-block:: wincon
|
.. code-block:: doscon
|
||||||
|
|
||||||
> ; On Windows
|
> ; On Windows
|
||||||
> .venv/Scripts/activate.ps1
|
> .venv/Scripts/activate.ps1
|
||||||
|
@ -50,7 +50,7 @@ Using pip
|
||||||
|
|
||||||
To install |this| using :mod:`pip`:
|
To install |this| using :mod:`pip`:
|
||||||
|
|
||||||
#. Add |this| to your `requirements.txt` file:
|
#. Add |this| to your ``requirements.txt`` file:
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
|
@ -75,6 +75,7 @@ To install |this| using :mod:`pipx`:
|
||||||
|
|
||||||
$ pipx install emblematic
|
$ pipx install emblematic
|
||||||
|
|
||||||
|
|
||||||
===========
|
===========
|
||||||
From source
|
From source
|
||||||
===========
|
===========
|
||||||
|
@ -133,7 +134,7 @@ To contribute to |this|, you need to setup the project's environment using :mod:
|
||||||
|
|
||||||
.. hint::
|
.. hint::
|
||||||
|
|
||||||
Setting ``virtualenvs.in-project`` to :data:`True` is recommended!
|
It is recommended to set ``virtualenvs.in-project`` to :data:`True`!
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
|
|
BIN
docs/source/ryg6-ice-cream.png
Normal file
BIN
docs/source/ryg6-ice-cream.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 320 KiB |
55
docs/source/usage.rst
Normal file
55
docs/source/usage.rst
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
*******************************************************************************
|
||||||
|
Usage
|
||||||
|
*******************************************************************************
|
||||||
|
|
||||||
|
:mod:`emblematic` currently supports only a single mode of operation.
|
||||||
|
|
||||||
|
|
||||||
|
=======================
|
||||||
|
Generate a basic emblem
|
||||||
|
=======================
|
||||||
|
|
||||||
|
A *basic emblem* can be generated by running:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
$ emblematic basic --background="./bg.svg" --icon="./icon.svg" --fill="#feedb4" --output-dir="./output/"
|
||||||
|
|
||||||
|
It is composed by:
|
||||||
|
|
||||||
|
1. taking the SVG background image contained in the file given as the ``--background`` option, such as the following:
|
||||||
|
|
||||||
|
.. figure:: ryg6-bg.svg
|
||||||
|
:width: 150
|
||||||
|
:height: 150
|
||||||
|
|
||||||
|
2. overlaying a rescaled version of the SVG foreground icon contained in the file given as the ``--icon`` option, filled with the color given in the ``--fill`` option, such as the following:
|
||||||
|
|
||||||
|
.. figure:: fontawesome-ice-cream.svg
|
||||||
|
:width: 150
|
||||||
|
:height: 150
|
||||||
|
|
||||||
|
3. converting the resulting document to a 2000x2000 PNG file for better compatibility with applications (very few support correctly the ``preserveAspectRatio`` property):
|
||||||
|
|
||||||
|
.. figure:: ryg6-ice-cream.png
|
||||||
|
:width: 150
|
||||||
|
:height: 150
|
||||||
|
|
||||||
|
|
||||||
|
---------------------------------
|
||||||
|
Multiple emblems with one command
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
Multiple emblem files can be generated at once.
|
||||||
|
|
||||||
|
* Pass the ``--icon`` parameter multiple times to generate emblems with the same settings but different icons:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
$ emblematic basic --background="./bg.svg" --icon="./icon1.svg" --icon="./icon2.svg" --icon="./icon3.svg" --fill="#feedb4" --output-dir="./output/"
|
||||||
|
|
||||||
|
* Pass a directory as the ``--icon`` parameter to render all contained files matched by the ``**/*.svg`` glob:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
$ emblematic basic --background="./bg.svg" --icon="./fontawesome/" --fill="#feedb4" --output-dir="./output/"
|
|
@ -1,5 +1,8 @@
|
||||||
# If you are building a **library**, use this file to export objects!
|
from . import compose
|
||||||
|
from . import files
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
# "",
|
"compose",
|
||||||
|
"files",
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,37 +1,84 @@
|
||||||
|
"""
|
||||||
|
Command-line interface for :mod:`emblematic`.
|
||||||
|
|
||||||
|
Implemented with :mod:`click`.
|
||||||
|
"""
|
||||||
|
|
||||||
import click
|
import click
|
||||||
import bs4
|
import bs4
|
||||||
|
import pathlib
|
||||||
|
import cairosvg
|
||||||
|
|
||||||
|
from .files import get_svgs
|
||||||
|
from .compose import compose_basic
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.group()
|
||||||
|
def main():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@main.command("basic")
|
||||||
@click.option(
|
@click.option(
|
||||||
"-o", "--output-file", "output_file",
|
"-b", "--background", "bg_file",
|
||||||
help="File to output the icon to.",
|
|
||||||
required=True,
|
|
||||||
type=click.File(mode="w"),
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"-b", "--background-file", "background_file",
|
|
||||||
help="File to use as the background of the icon.",
|
|
||||||
required=True,
|
|
||||||
type=click.File(mode="r"),
|
type=click.File(mode="r"),
|
||||||
|
required=True,
|
||||||
|
help="SVG file to be used as background.",
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"-f", "--foreground-file", "foreground_file",
|
"-i", "--icon", "icon_paths",
|
||||||
help="File to use as the foreground of the icon.",
|
type=click.Path(exists=True),
|
||||||
required=True,
|
required=True,
|
||||||
type=click.File(mode="r"),
|
multiple=True,
|
||||||
|
help="SVG files or directories of files to be used as foreground.",
|
||||||
)
|
)
|
||||||
def main(output_file, background_file, foreground_file):
|
@click.option(
|
||||||
background_soup = bs4.BeautifulSoup(background_file, "lxml-xml")
|
"-f", "--fill", "icon_fill",
|
||||||
foreground_soup = bs4.BeautifulSoup(foreground_file, "lxml-xml")
|
type=str,
|
||||||
|
required=True,
|
||||||
|
help="The color to fill icons with."
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"-o", "--output-dir", "output_dir",
|
||||||
|
type=click.Path(exists=True, file_okay=False, dir_okay=True),
|
||||||
|
required=True,
|
||||||
|
help="The directory where output files should be placed in."
|
||||||
|
)
|
||||||
|
def basic(bg_file, icon_paths, icon_fill, output_dir):
|
||||||
|
icon_paths = map(pathlib.Path, icon_paths)
|
||||||
|
icon_paths = map(get_svgs, icon_paths)
|
||||||
|
icon_paths = sum(icon_paths, start=[])
|
||||||
|
|
||||||
foreground_tag = foreground_soup.path
|
output_dir = pathlib.Path(output_dir)
|
||||||
foreground_scaled_tag = bs4.BeautifulSoup("""<g id="icon" transform="matrix(2,0,0,2,-4.3209502e-5,512)"></g>""", "lxml-xml")
|
|
||||||
foreground_scaled_tag.g.append(foreground_tag)
|
|
||||||
|
|
||||||
background_soup.svg.append(foreground_scaled_tag)
|
bg_doc = bs4.BeautifulSoup(bg_file, features="lxml-xml")
|
||||||
|
bg = bg_doc.svg
|
||||||
|
|
||||||
|
for icon_path in icon_paths:
|
||||||
|
icon_path: pathlib.Path
|
||||||
|
output_path = output_dir.joinpath(f"{icon_path.stem}.png")
|
||||||
|
|
||||||
|
with open(icon_path) as icon_file:
|
||||||
|
click.echo(icon_path, nl=False)
|
||||||
|
icon_doc = bs4.BeautifulSoup(icon_file, features="lxml-xml")
|
||||||
|
icon = icon_doc.svg
|
||||||
|
icon.path.attrs["fill"] = icon_fill
|
||||||
|
|
||||||
|
click.echo(" → ", nl=False)
|
||||||
|
svg_doc = compose_basic(background=bg, icon=icon)
|
||||||
|
|
||||||
|
click.echo(" → ", nl=False)
|
||||||
|
svg_bytes = bytes(svg_doc.prettify(), encoding="utf8")
|
||||||
|
|
||||||
|
click.echo(" → ", nl=False)
|
||||||
|
png_bytes = cairosvg.svg2png(bytestring=svg_bytes)
|
||||||
|
|
||||||
|
with open(output_path, mode="wb") as output_file:
|
||||||
|
click.echo(output_path, nl=False)
|
||||||
|
output_file.write(png_bytes)
|
||||||
|
|
||||||
|
click.echo()
|
||||||
|
|
||||||
output_file.write(background_soup.prettify())
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -1,36 +1,43 @@
|
||||||
|
"""
|
||||||
|
Module containing the functions used to generate ``<svg>`` icons from other ``<svg>`` :class:`bs4.Tag`.
|
||||||
|
"""
|
||||||
|
|
||||||
import bs4
|
import bs4
|
||||||
|
|
||||||
|
|
||||||
def compose_basic(bg: bs4.Tag, fg: bs4.Tag) -> bs4.Tag:
|
def compose_basic(background: bs4.Tag, icon: bs4.Tag) -> bs4.Tag:
|
||||||
"""
|
"""
|
||||||
Create a nice icon from the given background ``<svg>`` and the given foreground ``<svg>``.
|
Create a new and nice ``<svg>`` icon from the given background ``<svg>`` and the given foreground ``<svg>``.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if bg.name != "svg":
|
if background.name != "svg":
|
||||||
raise ValueError("bg is not a <svg> tag.")
|
raise ValueError("bg is not a <svg> tag.")
|
||||||
if fg.name != "svg":
|
if icon.name != "svg":
|
||||||
raise ValueError("fg is not a <svg> tag.")
|
raise ValueError("fg is not a <svg> tag.")
|
||||||
|
|
||||||
bg = bg.__copy__()
|
background = background.__copy__()
|
||||||
bg.attrs["id"] = "emblematic-bg"
|
background.attrs["id"] = "emblematic-background"
|
||||||
bg.attrs["width"] = "100%"
|
background.attrs["width"] = "100%"
|
||||||
bg.attrs["height"] = "100%"
|
background.attrs["height"] = "100%"
|
||||||
|
|
||||||
fg = fg.__copy__()
|
icon = icon.__copy__()
|
||||||
fg.attrs["id"] = "emblematic-fg"
|
icon.attrs["id"] = "emblematic-icon"
|
||||||
fg.attrs["width"] = "63%"
|
icon.attrs["width"] = "63%"
|
||||||
fg.attrs["height"] = "63%"
|
icon.attrs["height"] = "63%"
|
||||||
fg.attrs["preserveAspectRation"] = "xMidYMid meet"
|
icon.attrs["preserveAspectRatio"] = "xMidYMid meet"
|
||||||
fg.attrs["transform"] = "translate(185, 185)"
|
icon.attrs["transform"] = "translate(370, 370)"
|
||||||
|
|
||||||
doc = bs4.BeautifulSoup("""
|
doc = bs4.BeautifulSoup("""
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2000 2000">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
|
|
||||||
</svg>
|
</svg>
|
||||||
""")
|
""", features="lxml-xml")
|
||||||
container: bs4.Tag = doc.svg
|
container: bs4.Tag = doc.svg
|
||||||
container.append(bg)
|
container.append(background)
|
||||||
container.append(fg)
|
container.append(icon)
|
||||||
|
|
||||||
return doc
|
return doc
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
"compose_basic",
|
||||||
|
)
|
||||||
|
|
22
emblematic/files.py
Normal file
22
emblematic/files.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
"""
|
||||||
|
Module containing functions to operate on files or directories.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
|
||||||
|
def get_svgs(path: pathlib.Path):
|
||||||
|
"""
|
||||||
|
Find all SVGs in the given path.
|
||||||
|
"""
|
||||||
|
if not path.exists():
|
||||||
|
raise ValueError("Given path does not exist.")
|
||||||
|
if not path.is_dir():
|
||||||
|
return [path]
|
||||||
|
|
||||||
|
return list(path.glob("**/*.svg"))
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
"get_svgs",
|
||||||
|
)
|
|
@ -1,22 +0,0 @@
|
||||||
"""
|
|
||||||
Module containing function to process `Font Awesome <https://fontawesome.com/>`_ SVG icons.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import typing as t
|
|
||||||
import bs4
|
|
||||||
import pathlib
|
|
||||||
|
|
||||||
|
|
||||||
def get_icons(path: pathlib.Path):
|
|
||||||
if not path.exists():
|
|
||||||
raise ValueError("Given path does not exist.")
|
|
||||||
if not path.is_dir():
|
|
||||||
raise ValueError("Given path is not a directory.")
|
|
||||||
|
|
||||||
svgs = path.joinpath("svgs")
|
|
||||||
return svgs.glob("**/*.svg")
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
|
||||||
"get_icons",
|
|
||||||
)
|
|
|
@ -57,19 +57,24 @@ documentation = "https://emblematic.readthedocs.io/latest/"
|
||||||
|
|
||||||
# Up to five keywords related to your project.
|
# Up to five keywords related to your project.
|
||||||
# See also: https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/#keywords
|
# See also: https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/#keywords
|
||||||
#keywords = [
|
keywords = [
|
||||||
# "",
|
"icon",
|
||||||
# "",
|
"avatar",
|
||||||
# "",
|
"emblem",
|
||||||
# "",
|
"logo",
|
||||||
# "",
|
"symbol",
|
||||||
#]
|
]
|
||||||
|
|
||||||
# Any number of trove classifiers that apply to your project.
|
# Any number of trove classifiers that apply to your project.
|
||||||
# See the list at: https://pypi.org/classifiers/
|
# See the list at: https://pypi.org/classifiers/
|
||||||
classifiers = [
|
classifiers = [
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3.10",
|
"Programming Language :: Python :: 3.10",
|
||||||
|
"Development Status :: 3 - Alpha",
|
||||||
|
"Environment :: Console",
|
||||||
|
"License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)",
|
||||||
|
"Topic :: Multimedia :: Graphics",
|
||||||
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
|
|
||||||
# ADVANCED: specify the packages exported by your project
|
# ADVANCED: specify the packages exported by your project
|
||||||
|
|
Loading…
Reference in a new issue