Metadata-Version: 2.4
Name: colony-print
Version: 0.21.0
Summary: Colony Print Infra-structure
Home-page: http://colony-print.hive.pt
Author: Hive Solutions Lda.
Author-email: development@hive.pt
License: Apache License, Version 2.0
Keywords: colony print native
Classifier: Development Status :: 5 - Production/Stable
Classifier: Topic :: Utilities
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3.0
Classifier: Programming Language :: Python :: 3.1
Classifier: Programming Language :: Python :: 3.2
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Description-Content-Type: text/markdown
Requires-Dist: appier
Requires-Dist: appier-extras
Requires-Dist: jinja2
Requires-Dist: pillow
Requires-Dist: reportlab<3.5.54; python_version >= "3.0" and python_version < "3.6"
Requires-Dist: reportlab<4.4.3; python_version >= "3.6" and python_version < "3.9"
Requires-Dist: reportlab; python_version < "3.0" or python_version >= "3.9"
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license
Dynamic: requires-dist
Dynamic: summary

# [Colony Print Infra-structure](http://colony-print.hive.pt)

Small web app for printing Colony-based documents.

This project includes two main components:

* The Web App end-point that provides XML to Binie conversion `colony_print.controllers`
* The structure conversion infra-structure (Visitors, AST, etc.) `colony_print.printing`

## Features

* Cloud printing, with minimal configuration
* Multiple engine support (npcolony, gravo, text)
* XMPL to Binie conversion
* PDF generation with custom fonts and images
* [GDI](https://en.wikipedia.org/wiki/Graphics_Device_Interface) printing (Windows) via [Colony NPAPI (npcolony)](https://github.com/hivesolutions/colony-npapi)
* [CUPS](https://en.wikipedia.org/wiki/CUPS) printing (Linux) via [Colony NPAPI (npcolony)](https://github.com/hivesolutions/colony-npapi)
* Windows installer for the nodes, which update themselves from PyPI (see [Windows Node](#windows-node))

## Binie Specification

For a detailed understanding of the Binie file format used in this project, refer to the [Binie File Format Specification](doc/binie.md). This document outlines the structure and organization of the Binie file format, which is essential for developing compatible applications and tools.

## XMPL Specification

The XML Markup Language for Printing (XMPL) is integral to our document processing pipeline. For an in-depth understanding of the XMPL structure and its seamless convertibility to Binie, see the [XMPL File Format Specification](doc/xmpl.md).

## Installation

### Pre-requisites

```bash
apt-get install gcc python-dev
pip install --upgrade appier netius pillow reportlab
```

### Run Server

```bash
pip install colony_print
python -m colony_print.main
```

### Run Node

```bash
pip install colony_print
BASE_URL=$BASE_URL \
SECRET_KEY=$SECRET_KEY \
NODE_ID=$NODE_ID \
NODE_NAME=$NODE_NAME \
NODE_LOCATION=$NODE_LOCATION \
python -m colony_print.node
```

### Fonts

To be able to use new fonts (other than the ones provided by the system), one must install them into the `/usr/share/fonts/truetype` directory so they are exposed and ready to be used by the PDF generation infra-structure. For example, Calibri is one type of font that should be exported to a UNIX machine as many colony-generated documents use it.

The `/usr/share/fonts/truetype` install path is shared by the PDF generation engine.
Linux (CUPS) nodes need the same fonts to lay out the Binie documents they print. They look for the font files by name in the same paths and, as Windows does, fall back to the closest installed font found through fontconfig (`fc-match`), so installing Calibri (or the metric compatible Carlito font) keeps the layout identical to the Windows one. The same applies to the barcode fonts of the documents (e.g. the `2 of 5` font of the Omni product labels, looked up as `2 of 5.ttf`), whose barcodes are otherwise printed as the letters they are encoded with.
The `gravo` engine receives its fonts on a per print job basis through the `extra_fonts` field of the gravo print payload (see [Gravo Print Payload](#gravo-print-payload)) and stages them on a per job temporary directory, so the two flows are independent and operators should not confuse them.

### Engines

There are currently three engines available for printing in Colony Print:

* `npcolony` - The [Colony NPAPI](https://github.com/hivesolutions/colony-npapi) engine, which is used for GDI printing on Windows and CUPS printing on Linux.
* `gravo` - Which allows engraving of text and signatures using [Gravo Pilot](https://github.com/hivesolutions/gravo-pilot). Accepts an `extra_fonts` mapping in the print payload to ship `.f3s` font payloads to the engraving software on a per print job basis (see [Gravo Print Payload](#gravo-print-payload)).
* `text` - A simple virtual printer text engine that prints text to a simple plain text file and returns the file.

### Print Request

Every engine is reached through the same print endpoint and request envelope. A job is submitted to `/nodes/<id>/print` (or `/nodes/<id>/printers/<printer>/print` to target a specific printer) with the following fields:

| Field      | Type   | Required | Notes                                                                                                      |
| ---------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------- |
| `data`     | string | yes\*    | Raw document data, base64 encoded by the server before dispatch. Mutually exclusive with `data_b64`.       |
| `data_b64` | string | yes\*    | Base64 encoded document data, the engine specific payload described below. Mutually exclusive with `data`. |
| `name`     | string | no       | Human readable job name. Defaults to the generated job identifier.                                         |
| `type`     | string | no       | Target engine: `npcolony` (default), `gravo` or `text`.                                                    |
| `format`   | string | no       | Expected document format (e.g. `binie`, `pdf`). Validated against the node format when provided.           |
| `options`  | object | no       | Extra per job options (see table below). Keys outside the supported set are discarded.                     |

\* Exactly one of `data` or `data_b64` must be provided.

The `options` map is filtered to the following keys:

| Option            | Type    | Scope      | Notes                                                                                      |
| ----------------- | ------- | ---------- | ------------------------------------------------------------------------------------------ |
| `scale`           | number  | npcolony   | Accepted for compatibility, currently not applied by the npcolony engine.                  |
| `quality`         | number  | npcolony   | Accepted for compatibility, currently not applied by the npcolony engine.                  |
| `media`           | string  | npcolony   | Paper size requested to CUPS (e.g. `80x297mm`, `RP80x297` or `Custom.80x200mm`).           |
| `scaling`         | string  | npcolony   | CUPS print scaling: `auto`, `auto-fit`, `fit`, `fill` or `none`.                           |
| `save_output`     | boolean | email mode | When `true` the generated PDF is returned (base64) in the job result. Defaults to `false`. |
| `send_email`      | boolean | email mode | Whether to send the result email. Defaults to `true`.                                      |
| `email_address`   | string  | email mode | Single recipient address (alias of `email_receiver`).                                      |
| `email_receiver`  | string  | email mode | Single recipient address.                                                                  |
| `email_receivers` | array   | email mode | List of recipient addresses.                                                               |
| `email_override`  | boolean | email mode | When `true` the provided receivers replace the node default receivers. Defaults to `true`. |

The `save_output` and `email_*` options only take effect on nodes running in `email` mode (`NODE_MODE=email`).

### npcolony Print Payload

The `npcolony` engine is the default and prints through [Colony NPAPI](https://github.com/hivesolutions/colony-npapi) using GDI on Windows and CUPS on Linux. Its payload is the binary print document carried in `data_b64`, typically a [Binie](doc/binie.md) document produced by the XMPL to Binie conversion, dispatched directly to the target printer. There are no JSON fields: the printing behaviour is tuned through the options and the optional `format` field described in [Print Request](#print-request).

On Windows the Binie document is drawn directly through GDI. Linux (CUPS) nodes only print PDF documents, so they convert Binie jobs (with the `binie` format, or without a format when the payload is a valid Binie document) into a PDF laid out with the same rules as GDI: the paper size of the document when it defines one and the printer accepts it as a custom paper size (as the Windows driver of the printer does), and the printer's default paper size otherwise (e.g. a label printed on an A4 printer comes out at its real size in the top left corner of the page), with the content laid out from the top left corner of the printable area of the page and printed without scaling. The `media` option doesn't apply to them, as their pages are always laid out for that paper size. PDF documents and any other data are sent to CUPS untouched.

### Linux (CUPS) Printing

The printer of the job (or `NODE_PRINTER` when the job has none) selects the CUPS queue, and `default`, the default value of `NODE_PRINTER`, selects the default queue (or the only queue, when none is the default). Jobs for a queue that does not exist, or that CUPS refuses, fail with an error instead of being reported as printed.

Each queue should use a driver for its printer and a default paper size that matches the loaded paper, as that size is used for the Binie documents that do not define one, or whose size the printer does not accept as a custom paper size (e.g. `lpadmin -p receipt -o PageSize=RP80x297`):

* Receipt printers - the vendor CUPS driver (e.g. the Epson TM series driver), with its paper reduction options enabled to avoid feeding blank paper at the end of the receipt.
* Label printers - the label drivers shipped with CUPS (Zebra, Dymo) or the vendor ones, with the default size set to the loaded label.
* Office printers - driverless (IPP Everywhere) queues.

The custom paper sizes a printer accepts, and their margins, are the ones of the PPD of its queue, as reported by npcolony. With npcolony versions that don't report them, a Binie document only uses its own size when it matches the default paper size of the queue.

In `email` mode the PDF document is written to the output file (print to file) instead of being printed, as it happens with the PDF printer on Windows.

### Gravo Print Payload

The `gravo` engine accepts a JSON payload submitted as base64 to the print endpoint. The accepted fields are documented below:

| Field         | Type            | Required | Notes                                                                                                                                                                                                                                       |
| ------------- | --------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `text`        | string or array | yes      | Either a plain string for single font runs or a multifont array of `[font, char]` pairs for mixed font runs.                                                                                                                                |
| `font`        | string          | no       | Default font name. Defaults to `HELVETICA 1L`.                                                                                                                                                                                              |
| `font_size`   | number          | no       | Default font size in the engraving software's unit.                                                                                                                                                                                         |
| `width`       | number          | no       | Engraving area width. Defaults to `80`.                                                                                                                                                                                                     |
| `height`      | number          | no       | Engraving area height. Defaults to `100`.                                                                                                                                                                                                   |
| `margins`     | array           | no       | Four element `[left, right, top, bottom]` margin array.                                                                                                                                                                                     |
| `dry_run`     | boolean         | no       | When `true` the engraving job is composed but not sent to the machine. Defaults to `false`.                                                                                                                                                 |
| `record`      | boolean         | no       | When `true` a video of the engraving session is captured and returned with the screenshots. Defaults to `false`.                                                                                                                            |
| `check_path`  | boolean         | no       | When `true` the engraving path is traced with the laser light only, without engraving the material, for test verification. Defaults to `false`.                                                                                             |
| `debug`       | boolean         | no       | When `true` the response includes the captured gravo pilot logs. Defaults to `false`.                                                                                                                                                       |
| `extra_fonts` | object          | no       | Mapping of font name to the base64 encoded `.f3s` payload that should be installed for the duration of the engraving session. Each entry is staged on a per job temporary directory and forwarded to gravo pilot's `extra_fonts` parameter. |

### Text Print Payload

The `text` engine is a virtual printer that does not talk to any physical device. Its payload is the plain text content carried in `data_b64`; the engine writes it to a `document.txt` file and returns that file (base64 encoded) in the job result. It has no JSON fields and ignores the printer, format and option values, which makes it convenient for testing and for capturing print output without hardware.

## Windows Node

Windows 10 and 11 (64 bit) nodes are installed with a `setup.exe` installer. It installs everything the node needs: an embedded Python, colony-print, [Colony NPAPI (npcolony)](https://github.com/hivesolutions/colony-npapi) for the native (GDI) printing, and their dependencies. The node runs as the `colony-print-node` Windows service, which starts with the machine and updates itself from [PyPI](https://pypi.org) every time it starts.

### Building the Installer

```powershell
.\windows\build.ps1 -Python C:\Python314\python.exe
```

The build requires a 64 bit Python (the embedded Python is the same version), whose version must have the digest of its embedded distribution pinned in `build.ps1` (currently 3.14.8, the digest of another version is published by python.org), and [Inno Setup 6](https://jrsoftware.org/isinfo.php), as npcolony and the other dependencies are installed from their PyPI wheels (nothing is compiled). It creates the installer (`dist\colony-print-node-setup-<version>.exe`), which bundles the packages, so that it installs the node without internet access. The `Windows Workflow` builds it on every push (the `colony-print-node-windows` artifact) and smoke tests the installer on a Windows runner. When a release is published, it also attaches the installer to the release, for which the tag of the release must match the version in `setup.py` (e.g. `0.21.0`). A failed attach can be retried by running the workflow manually with the tag of the release.

### Installing

The installer asks for the server URL and the secret key, which it verifies against the server. It then asks for the mode (`normal` or `email`), the node name, location and printer, and, in email mode, the email receivers and the Mailme key. The node ID is derived from the name and kept on later installs. It may also run silently (e.g. for mass deployment), with the configuration given as parameters:

```powershell
colony-print-node-setup-0.20.0.exe /VERYSILENT /URL=https://print.example.com/ /KEY=$SECRET_KEY /NAME="Shop 1" /LOCATION=Porto /PRINTER="EPSON TM-T20II Receipt"
```

| Parameter    | Configuration          | Notes                                                                            |
| ------------ | ---------------------- | -------------------------------------------------------------------------------- |
| `/URL`       | `BASE_URL`             | URL of the Colony Print server.                                                  |
| `/KEY`       | `SECRET_KEY`           | Secret key of the server, written to the setup log with `/LOG` (see `/CONFIG`).  |
| `/NAME`      | `NODE_NAME`            | Defaults to the computer name.                                                   |
| `/ID`        | `NODE_ID`              | Defaults to the name in lower case, with dashes (e.g. `shop-1`).                 |
| `/LOCATION`  | `NODE_LOCATION`        | Optional.                                                                        |
| `/PRINTER`   | `NODE_PRINTER`         | Printer of the jobs that don't select one.                                       |
| `/MODE`      | `NODE_MODE`            | `normal` (default) or `email`.                                                   |
| `/EMAILS`    | `NODE_EMAIL_RECEIVERS` | Email receivers, separated by `;` (email mode).                                  |
| `/MAILMEKEY` | `MAILME_KEY`           | Mailme key (email mode).                                                         |
| `/MAILMEURL` | `MAILME_BASE_URL`      | Optional Mailme URL (email mode).                                                |
| `/CONFIG`    |                        | Path to a `config.env` file with the values of the parameters that aren't given. |

The parameters that aren't given keep the values of the existing configuration, so running a new installer over a node only replaces its files. The installer exits with code `10` when the service could not be installed or started.

The service runs under the system account, so it only sees the printers installed for all users and has no default printer. The installer suggests the default printer of the user running it, and the printer should be set, otherwise the jobs that don't select one fail. In email mode the printer must be a PDF printer (e.g. `Microsoft Print to PDF`), as the jobs are printed to PDF files.

The node is installed in `C:\Program Files\Colony Print Node` (other directories are refused, as the service runs its files as the system account). Its configuration (`config.env`) and logs are in `C:\ProgramData\Colony Print Node`, which only the system account and the administrators can access, as it holds the secret key. A data directory (or configuration) owned by, or accessible to, any other user (e.g. created by a user before the install) is never used, the installer removes it and creates the data directory already restricted. The installer verifies the owner and the access with PowerShell when the service isn't installed, and stops (removing nothing) when it can't verify them. Changes to `config.env` apply on the next start of the service (`Restart-Service colony-print-node`). Uninstalling keeps the configuration and the logs.

### Self-Update

Every time the service starts, the node updates colony-print and npcolony to their newest versions in PyPI (`pip install --upgrade`), only installing their wheels (nothing is compiled in the node) and skipping the versions that don't support its Python (`Requires-Python`). Their dependencies are only updated when required. pip ignores its configuration files (e.g. `C:\ProgramData\pip\pip.ini`, which any user may create), but may be configured with `PIP_*` values in `config.env` (e.g. `PIP_PROXY`). A failed update (e.g. without internet access) only logs a warning and never prevents the node from running, as it keeps the installed packages, and the service runs the boot script from a copy outside of the packages (`C:\Program Files\Colony Print Node\boot.py`), so a broken or interrupted update never prevents it from starting.

The update is configured in `config.env`:

| Configuration           | Notes                                                                                             |
| ----------------------- | ------------------------------------------------------------------------------------------------- |
| `NODE_UPDATE`           | `0` disables the update.                                                                          |
| `NODE_VERSION`          | Version of colony-print, an exact version (e.g. `0.21.0`) or a specifier (e.g. `<0.22`, `==0.21.*`). |
| `NODE_NPCOLONY_VERSION` | Version of npcolony, as `NODE_VERSION`.                                                           |
| `NODE_INDEX_URL`        | URL of the package index to use instead of PyPI (e.g. a private mirror).                          |

The versions pin a node (or roll it back), as the node installs the newest version they allow, including an older one.

## Admin UI

A React-based admin interface is available under `frontends/admin/` for monitoring nodes, jobs and printers.

```bash
cd frontends/admin
npm install
npm run build
```

The built assets are output to `src/colony_print/static/admin-ui/` and served at `/admin-ui` when the server is running.

## Development

To run a localhost development server, use the following commands:

```bash
PORT=8686 \
PYTHONPATH=$BASE_PATH/colony_print/src python \
$BASE_PATH/colony_print/src/colony_print/main.py
```

## License

Colony Print Infra-structure is currently licensed under the [Apache License, Version 2.0](http://www.apache.org/licenses/).

## Build Automation

[![Build Status](https://github.com/hivesolutions/colony-print/workflows/Main%20Workflow/badge.svg)](https://github.com/hivesolutions/colony-print/actions)
[![PyPi Status](https://img.shields.io/pypi/v/colony-print.svg)](https://pypi.python.org/pypi/colony-print)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://www.apache.org/licenses/)
