mirror of
https://github.com/Steffo99/emblematic.git
synced 2024-11-21 14:24:18 +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",
|
||||
"module": "emblematic",
|
||||
"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
|
||||
# TODO: Add whatever dependency your image may require
|
||||
RUN apk add --update build-base python3-dev py-pip musl-dev
|
||||
RUN pip install "poetry"
|
||||
|
||||
FROM system AS workdir
|
||||
# TODO: Use the name of your project
|
||||
WORKDIR /usr/src/emblematic
|
||||
|
||||
FROM workdir AS dependencies
|
||||
|
@ -20,9 +16,8 @@ RUN poetry install
|
|||
|
||||
FROM package AS entrypoint
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
ENTRYPOINT ["poetry", "run", "python", "-m"]
|
||||
# TODO: Set the name of your Python module
|
||||
CMD ["emblematic"]
|
||||
ENTRYPOINT ["poetry", "run", "python", "-m", "emblematic"]
|
||||
CMD []
|
||||
|
||||
FROM entrypoint AS labels
|
||||
# TODO: Set a Docker image title
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
Simple icon generator
|
||||
|
||||
\[ **[Documentation]** | **[Available on PyPI]** | [Repository] \]
|
||||
\[ **[Documentation]** | **[PyPI]** | [Repository] \]
|
||||
|
||||
<!-- Add an image or some examples here, if available! -->
|
||||
|
||||
|
||||
[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/
|
||||
|
|
|
@ -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_mapping = {
|
||||
"python": ("https://docs.python.org/3.10", None),
|
||||
"poetry":
|
||||
}
|
||||
# Manpages URL
|
||||
manpages_url = "https://man.archlinux.org/"
|
||||
|
|
|
@ -15,7 +15,8 @@ Table of contents
|
|||
.. toctree::
|
||||
|
||||
installation
|
||||
|
||||
usage
|
||||
api
|
||||
|
||||
|
||||
============
|
||||
|
|
|
@ -40,7 +40,7 @@ Using pip
|
|||
$ # On Fish
|
||||
$ source .venv/bin/activate.fish
|
||||
|
||||
.. code-block:: wincon
|
||||
.. code-block:: doscon
|
||||
|
||||
> ; On Windows
|
||||
> .venv/Scripts/activate.ps1
|
||||
|
@ -50,7 +50,7 @@ Using pip
|
|||
|
||||
To install |this| using :mod:`pip`:
|
||||
|
||||
#. Add |this| to your `requirements.txt` file:
|
||||
#. Add |this| to your ``requirements.txt`` file:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
|
@ -75,6 +75,7 @@ To install |this| using :mod:`pipx`:
|
|||
|
||||
$ pipx install emblematic
|
||||
|
||||
|
||||
===========
|
||||
From source
|
||||
===========
|
||||
|
@ -133,7 +134,7 @@ To contribute to |this|, you need to setup the project's environment using :mod:
|
|||
|
||||
.. hint::
|
||||
|
||||
Setting ``virtualenvs.in-project`` to :data:`True` is recommended!
|
||||
It is recommended to set ``virtualenvs.in-project`` to :data:`True`!
|
||||
|
||||
.. 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__ = (
|
||||
# "",
|
||||
"compose",
|
||||
"files",
|
||||
)
|
||||
|
|
|
@ -1,37 +1,84 @@
|
|||
"""
|
||||
Command-line interface for :mod:`emblematic`.
|
||||
|
||||
Implemented with :mod:`click`.
|
||||
"""
|
||||
|
||||
import click
|
||||
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(
|
||||
"-o", "--output-file", "output_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,
|
||||
"-b", "--background", "bg_file",
|
||||
type=click.File(mode="r"),
|
||||
required=True,
|
||||
help="SVG file to be used as background.",
|
||||
)
|
||||
@click.option(
|
||||
"-f", "--foreground-file", "foreground_file",
|
||||
help="File to use as the foreground of the icon.",
|
||||
"-i", "--icon", "icon_paths",
|
||||
type=click.Path(exists=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):
|
||||
background_soup = bs4.BeautifulSoup(background_file, "lxml-xml")
|
||||
foreground_soup = bs4.BeautifulSoup(foreground_file, "lxml-xml")
|
||||
@click.option(
|
||||
"-f", "--fill", "icon_fill",
|
||||
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
|
||||
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)
|
||||
output_dir = pathlib.Path(output_dir)
|
||||
|
||||
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__":
|
||||
|
|
|
@ -1,36 +1,43 @@
|
|||
"""
|
||||
Module containing the functions used to generate ``<svg>`` icons from other ``<svg>`` :class:`bs4.Tag`.
|
||||
"""
|
||||
|
||||
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.")
|
||||
if fg.name != "svg":
|
||||
if icon.name != "svg":
|
||||
raise ValueError("fg is not a <svg> tag.")
|
||||
|
||||
bg = bg.__copy__()
|
||||
bg.attrs["id"] = "emblematic-bg"
|
||||
bg.attrs["width"] = "100%"
|
||||
bg.attrs["height"] = "100%"
|
||||
background = background.__copy__()
|
||||
background.attrs["id"] = "emblematic-background"
|
||||
background.attrs["width"] = "100%"
|
||||
background.attrs["height"] = "100%"
|
||||
|
||||
fg = fg.__copy__()
|
||||
fg.attrs["id"] = "emblematic-fg"
|
||||
fg.attrs["width"] = "63%"
|
||||
fg.attrs["height"] = "63%"
|
||||
fg.attrs["preserveAspectRation"] = "xMidYMid meet"
|
||||
fg.attrs["transform"] = "translate(185, 185)"
|
||||
icon = icon.__copy__()
|
||||
icon.attrs["id"] = "emblematic-icon"
|
||||
icon.attrs["width"] = "63%"
|
||||
icon.attrs["height"] = "63%"
|
||||
icon.attrs["preserveAspectRatio"] = "xMidYMid meet"
|
||||
icon.attrs["transform"] = "translate(370, 370)"
|
||||
|
||||
doc = bs4.BeautifulSoup("""
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2000 2000">
|
||||
</svg>
|
||||
""")
|
||||
""", features="lxml-xml")
|
||||
container: bs4.Tag = doc.svg
|
||||
container.append(bg)
|
||||
container.append(fg)
|
||||
container.append(background)
|
||||
container.append(icon)
|
||||
|
||||
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.
|
||||
# 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.
|
||||
# See the list at: https://pypi.org/classifiers/
|
||||
classifiers = [
|
||||
"Programming Language :: Python :: 3",
|
||||
"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
|
||||
|
|
Loading…
Reference in a new issue