diff options
-rw-r--r-- | README.rst | 162 | ||||
-rw-r--r-- | bruder/__init__.py (renamed from bruder.py) | 17 | ||||
-rw-r--r-- | bruder/__main__.py | 2 | ||||
-rw-r--r-- | pyproject.toml | 40 | ||||
-rw-r--r-- | svg_util.py | 2 |
5 files changed, 215 insertions, 8 deletions
diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..906ac66 --- /dev/null +++ b/README.rst @@ -0,0 +1,162 @@ +Bruder: Print pictures as collages with label tape printers +=========================================================== + +``bruder`` is a tool that helps you create collages out of label tape printed with a label printer such as Brother's +P-touch devices. + +``bruder dither`` takes an SVG file with your design and some lines representing the labels' locations, and +outputs a list of dithered PNG files, one for each label, ready for printing. Optionally, ``bruder print`` can also directly +print these rendered images for you using the ``ptouch-print`` tool. + +For creating and tweaking your design, ``bruder`` has several helper utilities built-in. ``bruder template`` will generate a +template with a label tape layout you give it that you can use to base your design off of. ``bruder preview`` will render +a preview that approximates how the printed labels will look when you lay them out. ``bruder assembly`` will render an +assembly diagram with labels indicating each label tape's number in the order output by ``bruder dither`` or `bruder +print`. + +Quick start +----------- + +1. Install ``bruder`` from PyPI using `pip install bruder`, and install ``usvg``, ``resvg``, ``didder`` and ``ptouch-print`` as + shown below under Dependencies_. +2. Run ``bruder template template.svg`` to create a template with pre-generated label tape areas. The default tape width + is 24mm, but you can adjust this as you wish. +3. Create a new SVG document and design your artwork in it. +4. Copy the label tape areas from the template into your artwork SVG and save the resulting SVG. ``bruder`` will later + identify these areas by their color. You can copy or delete these, change the length of them, and move and rotate + them as you wish. Just make sure you don't skew or shear them and that you don't change their width so that they + still match the width of the tape that's physically in the printer you're using. +5. Run ``bruder preview artwork_with_label_areas.svg`` on this SVG to render a preview image. By default, ``bruder`` will + open this preview image in your browser. If that doesn't work, run ``bruder preview [input].svg preview_out.svg`` to + write it to `preview_out.svg` and open that file with an SVG viewer of your choice. Adjust the content of your design + as necessary. +6. Run ``bruder print artwork_with_label_areas.svg`` to print your artwork to a brother P-touch label printer connected + via USB. + +Dependencies +------------ + +usvg + ``usvg`` can be installed using ``cargo install usvg``. + + ``usvg`` is used by ``bruder`` to simplify the input SVG file before processing it. + +resvg + ``resvg`` can be installed using ``cargo install resvg``. + + ``bruder`` uses ``resvg`` to rasterize the SVG file. + +didder + ``didder`` can be installed from source at `https://github.com/makew0rld/didder <https://github.com/makew0rld/didder>`__. + + ``bruder`` uses ``didder`` to dither the rasterized input, because these thermal label printers can only print two + colors and do not support grayscale. + +ptouch-print (optional) + ``ptouch-print`` can be installed from source at `https://git.familie-radermacher.ch/linux/ptouch-print.git <https://git.familie-radermacher.ch/linux/ptouch-print.git>`__. + + ``bruder`` uses ``ptouch-print`` when you ask it to print the generated labels using ``bruder print``. You can also use + ``bruder dither`` to just generate a pile of PNGs, and use something else to print them. + +Command-Line Interface Usage +---------------------------- + +You can override where ``bruder`` looks for ``usvg``, ``resvg``, ``didder`` and ``ptouch-print`` by passing the full path to a +binary through the environment variables ``USVG``, ``RESVG``, ``DIDDER`` and ``PTOUCH_PRINT``. + +You can override didder's dithering settings by passing the environment variable `DIDDER_ARGS`. The default value used +when this variable is not set is `edm --serpentine FloydSteinberg`. + +.. code-block:: shell + + bigdata~/p/bruder <3 python -m bruder --help + Usage: python -m bruder [OPTIONS] COMMAND [ARGS]... + + Options: + --help Show this message and exit. + + Commands: + assembly + dither + preview + print + template + +``bruder template`` +~~~~~~~~~~~~~~~~~~~ + +.. code-block:: shell + + bigdata~/p/bruder <3 python -m bruder template --help + Usage: python -m bruder template [OPTIONS] [OUTPUT_SVG] + + Options: + --num-rows INTEGER Number of tapes + --tape-width FLOAT Width of tape + --tape-border FLOAT Width of empty border at the edges of the tape in mm + --tape-spacing FLOAT Space between tapes + --tape-length FLOAT Length of tape segments + --magic-color TEXT SVG color of tape + --help Show this message and exit. + +``bruder preview`` +~~~~~~~~~~~~~~~~~~ + +.. code-block:: shell + + bigdata~/p/bruder <3 python -m bruder preview --help + Usage: python -m bruder preview [OPTIONS] [INPUT_SVG] [OUTPUT_SVG] + + Options: + --magic-color TEXT SVG color of tape + --dpi FLOAT Printer bitmap resolution in DPI + --pixel-height INTEGER Printer tape vertical pixel height + --help Show this message and exit. + +``bruder dither`` +~~~~~~~~~~~~~~~~~ + +.. code-block:: shell + + bigdata~/p/bruder <3 python -m bruder dither --help + Usage: python -m bruder dither [OPTIONS] [INPUT_SVG] OUTPUT_DIR + + Options: + --magic-color TEXT SVG color of tape + --dpi FLOAT Printer bitmap resolution in DPI + --pixel-height INTEGER Printer tape vertical pixel height + --help Show this message and exit. + +``bruder print`` +~~~~~~~~~~~~~~~~ + +.. code-block:: shell + + bigdata~/p/bruder <3 python -m bruder print --help + Usage: python -m bruder print [OPTIONS] [INPUT_SVG] + + Options: + --magic-color TEXT SVG color of tape + --dpi FLOAT Printer bitmap resolution in DPI + --pixel-height INTEGER Printer tape vertical pixel height + --confirm / --no-confirm Ask for confirmation before printing each tape + --tape TEXT The index numbers of which tapes to print. Comma- + separate list, each entry is either a single + number or a "3-5" style range where both ends are + included. + --help Show this message and exit. + +``bruder assembly`` +~~~~~~~~~~~~~~~~~~~ + +.. code-block:: shell + + bigdata~/p/bruder <3 python -m bruder assembly --help + Usage: python -m bruder assembly [OPTIONS] [INPUT_SVG] [OUTPUT_SVG] + + Options: + --magic-color TEXT SVG color of tape + --dpi FLOAT Printer bitmap resolution in DPI + --pixel-height INTEGER Printer tape vertical pixel height + --help Show this message and exit. + diff --git a/bruder.py b/bruder/__init__.py index 1b46033..f6f9ab5 100644 --- a/bruder.py +++ b/bruder/__init__.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 import tempfile -import shutil import webbrowser import re import base64 @@ -19,6 +18,9 @@ from bs4 import BeautifulSoup from svg_util import * +__version__ = "v1.0.0-rc1" + + def run_cargo_command(binary, *args, **kwargs): # By default, try a number of options: candidates = [ @@ -161,7 +163,8 @@ def do_dither(soup, magic_color, dpi, pixel_height): tmp_svg.flush() run_cargo_command('resvg', tmp_svg.name, tmp_png.name, width=round(Inch(path_len, 'mm')*dpi), height=pixel_height) - run_command('didder', 'edm', '--serpentine', 'FloydSteinberg', palette='black white', i=tmp_png.name, o=tmp_dither.name) + args = shlex.split(os.environ.get('DIDDER_ARGS', 'edm --serpentine FloydSteinberg')) + run_command('didder', *args, palette='black white', i=tmp_png.name, o=tmp_dither.name) yield (x1, y1, path_angle, stroke_w, path_len), tmp_dither.read() @@ -212,7 +215,7 @@ def cli(): @click.option('--tape-border', type=float, default=3, help='Width of empty border at the edges of the tape in mm') @click.option('--tape-spacing', type=float, default=2, help='Space between tapes') @click.option('--tape-length', type=float, default=250, help='Length of tape segments') -@click.option('--magic-color', type=str, default='#cc0000', help='SVG color of tape') +@click.option('--magic-color', type=str, default='#cc0301', help='SVG color of tape') @click.argument('output_svg', type=click.File(mode='w'), default='-') def template(num_rows, tape_width, tape_border, tape_spacing, tape_length, magic_color, output_svg): pitch = tape_width + tape_spacing @@ -234,7 +237,7 @@ def template(num_rows, tape_width, tape_border, tape_spacing, tape_length, magic @cli.command('print') -@click.option('--magic-color', type=str, default='#cc0000', help='SVG color of tape') +@click.option('--magic-color', type=str, default='#cc0301', help='SVG color of tape') @click.option('--dpi', type=float, default=180, help='Printer bitmap resolution in DPI') @click.option('--pixel-height', type=int, default=127, help='Printer tape vertical pixel height') @click.option('--confirm/--no-confirm', default=True, help='Ask for confirmation before printing each tape') @@ -268,7 +271,7 @@ def cli_print(input_svg, tape, magic_color, dpi, pixel_height, confirm): @cli.command() -@click.option('--magic-color', type=str, default='#cc0000', help='SVG color of tape') +@click.option('--magic-color', type=str, default='#cc0301', help='SVG color of tape') @click.option('--dpi', type=float, default=180, help='Printer bitmap resolution in DPI') @click.option('--pixel-height', type=int, default=127, help='Printer tape vertical pixel height') @click.argument('input_svg', type=click.File(mode='r'), default='-') @@ -278,7 +281,7 @@ def preview(input_svg, output_svg, magic_color, dpi, pixel_height): @cli.command() -@click.option('--magic-color', type=str, default='#cc0000', help='SVG color of tape') +@click.option('--magic-color', type=str, default='#cc0301', help='SVG color of tape') @click.option('--dpi', type=float, default=180, help='Printer bitmap resolution in DPI') @click.option('--pixel-height', type=int, default=127, help='Printer tape vertical pixel height') @click.argument('input_svg', type=click.File(mode='r'), default='-') @@ -288,7 +291,7 @@ def assembly(input_svg, output_svg, magic_color, dpi, pixel_height): @cli.command() -@click.option('--magic-color', type=str, default='#cc0000', help='SVG color of tape') +@click.option('--magic-color', type=str, default='#cc0301', help='SVG color of tape') @click.option('--dpi', type=float, default=180, help='Printer bitmap resolution in DPI') @click.option('--pixel-height', type=int, default=127, help='Printer tape vertical pixel height') @click.argument('input_svg', type=click.File(mode='r'), default='-') diff --git a/bruder/__main__.py b/bruder/__main__.py new file mode 100644 index 0000000..aa0ea12 --- /dev/null +++ b/bruder/__main__.py @@ -0,0 +1,2 @@ +import bruder +bruder.cli() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..f71352a --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,40 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[tool.setuptools] +py-modules = ['bruder'] + +[project] +name = "bruder" +version = "v1.0.0-rc1" +description = "Print pictures as collages using label tape printers" +readme = "README.rst" +authors = [{name = "jaseg", email = "code@jaseg.de"}] +license = {text = "GPLv2+ or LGPLv2.1+"} +requires-python = ">=3.10" +keywords = ['graphics', 'svg', 'printing', 'printer', 'label', 'label printer', 'brother', 'p-touch', 'dithering', + 'image processing', 'collage'] +dependencies = ['click', 'beautifulsoup4'] +classifiers = [ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'Intended Audience :: End Users/Desktop', + 'License :: OSI Approved :: BSD License', + 'Natural Language :: English', + 'Operating System :: POSIX', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', + 'Topic :: Multimedia :: Graphics :: Editors :: Vector-Based', + 'Topic :: Multimedia :: Graphics :: Presentation', + 'Topic :: Printing', + 'Topic :: Scientific/Engineering :: Image Processing', + 'Topic :: System :: Hardware :: Universal Serial Bus (USB) :: Printer', + 'Topic :: Utilities', +] + +[project.urls] +homepage = "https://github.com/jaseg/bruder" + diff --git a/svg_util.py b/svg_util.py index 6f6ac5f..009e9a5 100644 --- a/svg_util.py +++ b/svg_util.py @@ -6,7 +6,7 @@ from dataclasses import dataclass @dataclass(frozen=True, slots=True) class LengthUnit: - """ Convenience length unit class. Used in :py:class:`.GraphicObject` and :py:class:`.Aperture` to store lenght + """ Convenience length unit class. Used in :py:class:`.GraphicObject` and :py:class:`.Aperture` to store length information. Provides a number of useful unit conversion functions. Singleton, use only global instances ``utils.MM`` and ``utils.Inch``. |