diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..1d19ed3 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,45 @@ +name: Build documentation +on: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Install python + uses: actions/setup-python@v4 + with: + python-version: 3.x + - name: Setup cache + uses: actions/cache@v2 + with: + key: ${{ github.ref }} + path: .cache + - name: Setup dependencies + run: pip install -r docs/requirements.txt + - name: Build docs + run: mkdocs build --strict + - name: Upload artifact + uses: actions/upload-pages-artifact@v1 + with: + path: ./site + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v1 diff --git a/README.md b/README.md new file mode 100644 index 0000000..2062db2 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# niimprint +An open-source library and client for Niimbot printers + +### Fork changelog & differences from original version + +- Tested on Niimbot B1, B18, B21, D11, D110 and Python 3.11 +- Added transport abstraction: switch between bluetooth and USB (serial) +- Disabled checksum calculation for image encoding (works fine without it so far) +- Switched to [click](https://click.palletsprojects.com/) CLI library instead of argparse +- Integrated [pyproject.toml](https://pip.pypa.io/en/stable/reference/build-system/pyproject-toml/) and [poetry](https://python-poetry.org) +- Integrated [pre-commit](https://pre-commit.com/) and [ruff](https://docs.astral.sh/ruff/), re-formatted all files +- Miscellaneous refactoring / file renaming / etc. + +## Installation and usage + +Check out [**documentation**](https://andbondstyle.github.io/niimprint/). + +## Licence + +[MIT](https://choosealicense.com/licenses/mit/). Originally developed by [kjy00302](https://github.com/kjy00302), forked & enhanced by [AndBondStyle](https://github.com/AndBondStyle) diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 0000000..28c5b78 --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,22 @@ +--- +hide: + - navigation +--- + +## Image orientation + +Generally, the image comes out of the printer with the same orientation you see it on your screen. +You can have your input image rotated as you like, but adjust its orientation by passing `-r <...>` flag. + +See the image below for clarification. + +[![](./img/image_orientation.png)]() + + + +## Image resolution + +As far as we've tested, Niimbot printers have **8 pixels per mm** (~203 dpi) resolution. The CLI prints the image you provided as-is, without any checks of the actual label size, so be careful. However the script will check if the image width is too big for selected printer. The maximum width in pixels is usually slightly less than specified maximum width in mm: + +- **B21, B1, B18**: max 384 pixels (almost equal to 50 mm * 8 px/mm = 400) +- **D11**: max 96 pixels (almost equal to 15 mm * 8 px/mm = 120) diff --git a/docs/hardware.md b/docs/hardware.md new file mode 100644 index 0000000..7fb83f6 --- /dev/null +++ b/docs/hardware.md @@ -0,0 +1,24 @@ +--- +hide: + - navigation +--- + +# Supported printers + +- D11 +- D110 +- B21 +- B1 +- B18 + +# Tapes + +=== "D11 / D110" + + | Tape type | Printable dimensions (mm) | Pixels | Notes | + |-----------|---------------------------|--------|-------------| + | T14*22 | 13.5×21.5 | 96*172 | | + | T12*22 | 11.5×21.5 | 94*168 | | + | T12*30 | 11.7×29.8 | 94*228 | | + | TT14*50 | 13.9×49.9 | 96*380 | Transparent | + | T14*40 | 12x32 | 96*228 | «Bubble B» | diff --git a/examples/B21_30x15_result.png b/docs/img/B21_30x15_result.png similarity index 100% rename from examples/B21_30x15_result.png rename to docs/img/B21_30x15_result.png diff --git a/examples/B21_80x50_result.png b/docs/img/B21_80x50_result.png similarity index 100% rename from examples/B21_80x50_result.png rename to docs/img/B21_80x50_result.png diff --git a/examples/image_orientation.png b/docs/img/image_orientation.png similarity index 100% rename from examples/image_orientation.png rename to docs/img/image_orientation.png diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..e52920f --- /dev/null +++ b/docs/index.md @@ -0,0 +1,66 @@ +--- +hide: + - navigation + - toc +--- + +# Niimbot Printer Client + +## Installation + +Recommended method is to use [poetry](https://python-poetry.org) and install with `poetry install`. +However `requirements.txt` is also provided for convenience. + +Project is tested on Python 3.11, but should work on other versions. + +## Usage + +Just run `niimprint --help` + +### Print and tape notes + +* `TT14*50` is prone to overfeeding. Roll it for 1.5mm back after each printed label. +* «Bubble B» stickers have variable dimensions and colors (green, blue, teal, pink, yellow — in that order). + Be careful with layouts. +* Almost all stickers have rounded corners, count it when designing layouts. +* Note that different print densities will vary the pixel size, so count at least 2-5 pixels from the edges + to avoid clipping. +* **Always** use good dithering (Floyd-Steinberg, Sierra, Burkes) for grayscale images. + +## Examples + +### B21, USB connection, 30x15 mm (240x120 px) label + +``` +python niimprint -c usb -a /dev/ttyACM0 -r 90 -i examples/B21_30x15mm_240x120px.png +``` + +![](./img/B21_30x15_result.png) + +### B21, Bluetooth connection, 80x50 mm (640x384 px) label + +``` +python niimprint -c bluetooth -a "E2:E1:08:03:09:87" -r 90 -i examples/B21_80x50mm_640x384px.png +``` + +![](./img/B21_80x50_result.png) + + +## USB connection + +For USB connection, you can omit the `--addr` argument and let the script auto-detect the serial port. +However, it will fail if there're multiple available ports. + +On linux, serial ports can be found at `/dev/ttyUSB*`, `/dev/ttyACM*` or `/dev/serial/*`. +On windows, they will be named like `COM1`, `COM2` etc. Check the device manager to choose the correct one. + +## Bluetooth connection + +It seems like B21 (and maybe other models?) has two bluetooth addresses. +For me, they start with `C2:E1` and `E2:E1` respectively. + +!!! warning "Double-check bluetooth address" + + Connection works only if you disconnect from `C2:E1` and connect to `E2:E1`. + +Also after connecting to `E2:E1` via bluetoothctl I always get `org.bluez.Error.NotAvailable br-connection-profile-unavailable` error, but printing works fine regardless. diff --git a/docs/protocol.md b/docs/protocol.md new file mode 100644 index 0000000..bf37436 --- /dev/null +++ b/docs/protocol.md @@ -0,0 +1,68 @@ +--- +hide: + - navigation +--- + +## Packet structure + +Niimbot uses simple TLV packet with preamble, postamble and checksum. + +Every field of packet uses big endian. + + |5555|c2|01|02|c1|aaaa| + │ │ │ │ │ └ Postamble (constant) + │ │ │ │ └─── Checksum (xor sum of type, length and value) + │ │ │ └────── Value + │ │ └───────── Length (of data) + │ └──────────── Type + └───────────────── Preamble (constant) + +## Line encoding packets +Niimbot uses three types of packet to print image. + +All three packet type has repeat count. So, repetition of same data can be reduced to one packet. + +Currently niimprint's encoder only uses line packet without optimization. + +_(Common packet fields are omitted for clarity.)_ + +### Blank packet +Blank packet (packet type 0x84) encodes blank line. + + |5555|84|03|0000|0a|8d|aaaa| + │ └ Repeat count + └───── Line count + +This packet will print 10 blank lines. + +### Line packet +line packet (packet type 0x85) encodes line as bitmap. + + |5555|85|12|000a|00|01|0f|02|0000000000000001fffe0000|91|aaaa + │ │ │ │ │ └ Bitmap data + │ │ │ │ └─── Repeat count + │ │ │ └────── Pixel count (right) (bit count of 0x00000000) + │ │ └───────── Pixel count (middle) (bit count of 0x00000001) + │ └──────────── Pixel count (left) (bit count of 0xfffe0000) + └───────────────── Line count + +This packet will print 2 bitmap lines. + +### Points packet +points packet (packet type 0x83) encodes line as array of 1D points. + + 5555|83|0e|000c|00|01|03|07|003f0040004d004e|f8|aaaa| + │ │ │ │ │ └ Point data (0x003f, 0x0040, 0x004d, 0x004e) + │ │ │ │ └─── Repeat count + │ │ │ └────── Pixel count (right) + │ │ └───────── Pixel count (middle) + │ └──────────── Pixel count (left) + └───────────────── Line count + +This packet will print 7 lines with points. + +### Todo + +!!! question + + How does B21 encodes more then 96 pixels? diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..32bd08c --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,5 @@ +cairosvg~=2.7.1 +mkdocs-material~=9.4.14 +mkdocs-minify-plugin~=0.7.1 +pillow~=10.1.0 + diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..c57f712 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,120 @@ +site_name: niimprint +site_url: https://orhideous.github.io/niimprint +edit_uri: blob/main/docs/ # Change the master branch to main as we are using main as a main branch +site_author: niimprint authors +site_description: >- + Python app for Niimbot label printers. + +# Repository +repo_name: orhideous/niimprint +repo_url: https://github.com/orhideous/niimprint + +# Copyright +copyright: Copyright © 2024 niimprint authors + +# Configuration +theme: + name: material + features: + - announce.dismiss + - content.action.edit + - content.action.view + - content.code.annotate + - content.code.copy + # - content.tabs.link + - content.tooltips + # - header.autohide + # - navigation.expand + - navigation.footer + - navigation.indexes + # - navigation.instant + # - navigation.prune + - navigation.sections + - navigation.tabs + # - navigation.tabs.sticky + - navigation.top + - navigation.tracking + - search.highlight + - search.share + - search.suggest + - toc.follow + # - toc.integrate + palette: + - scheme: default + primary: white + toggle: + icon: material/brightness-7 + name: Switch to dark mode + - scheme: slate + toggle: + icon: material/brightness-4 + name: Switch to light mode + font: + text: Roboto + code: Roboto Mono + favicon: assets/favicon.png + +# Plugins +plugins: + - search: + separator: '[\s\-,:!=\[\]()"`/]+|\.(?!\d)|&[lg]t;|(?!\b)(?=[A-Z][a-z])' + - minify: + minify_html: true + - social: {} + +# Customization +extra: + annotate: + json: [.s2] + social: + - icon: fontawesome/brands/github + link: https://github.com/orhideous/niimprint + +# Extensions +markdown_extensions: + - abbr + - admonition + - attr_list + - def_list + - footnotes + - md_in_html + - toc: + permalink: true + - pymdownx.arithmatex: + generic: true + - pymdownx.betterem: + smart_enable: all + - pymdownx.caret + - pymdownx.details + - pymdownx.emoji: + emoji_generator: !!python/name:material.extensions.emoji.to_svg + emoji_index: !!python/name:material.extensions.emoji.twemoji + - pymdownx.highlight: + anchor_linenums: true + line_spans: __span + pygments_lang_class: true + - pymdownx.inlinehilite + - pymdownx.keys + - pymdownx.magiclink: + repo_url_shorthand: true + user: squidfunk + repo: mkdocs-material + - pymdownx.mark + - pymdownx.smartsymbols + - pymdownx.superfences: + custom_fences: + - name: mermaid + class: mermaid + format: !!python/name:pymdownx.superfences.fence_code_format + - pymdownx.tabbed: + alternate_style: true + - pymdownx.tasklist: + custom_checkbox: true + - pymdownx.tilde + +# Page tree +nav: + - Home: index.md + - FAQ: faq.md + - Printers & Tapes: hardware.md + - Protocol: protocol.md diff --git a/readme.md b/readme.md deleted file mode 100644 index a6b2c34..0000000 --- a/readme.md +++ /dev/null @@ -1,78 +0,0 @@ -# `niimprint` — Niimbot Printer Client - -**Fork changelog & differences from original version:** - -- Tested on Niimbot B1, B18, B21, D11, D110 and Python 3.11 -- Added transport abstraction: switch between bluetooth and USB (serial) -- Disabled checksum calculation for image encoding (works fine without it so far) -- Switched to [click](https://click.palletsprojects.com/) CLI library instead of argparse -- Integrated [pyproject.toml](https://pip.pypa.io/en/stable/reference/build-system/pyproject-toml/) and [poetry](https://python-poetry.org) -- Integrated [pre-commit](https://pre-commit.com/) and [ruff](https://docs.astral.sh/ruff/), re-formatted all files -- Miscellaneous refactoring / file renaming / etc. - -## Installation - -Recommended method is to use [poetry](https://python-poetry.org) and install with `poetry install`. However `requirements.txt` is also provided for convenience. Project is tested on Python 3.11, but should work on other versions. - -## Usage - -``` -$ python niimprint --help - -Usage: niimprint [OPTIONS] - -Options: - -m, --model [b1|b18|b21|d11|d110] Niimbot printer model [default: b21] - -c, --conn [usb|bluetooth] Connection type [default: usb] - -a, --addr TEXT Bluetooth MAC address OR serial device path - -d, --density INTEGER RANGE Print density [default: 5; 1<=x<=5] - -r, --rotate [0|90|180|270] Image rotation (clockwise) [default: 0] - -i, --image PATH Image path [required] - -v, --verbose Enable verbose logging - --help Show this message and exit. -``` - -### Image orientation: - -Generally, the image comes out of the printer with the same orientation you see it on your screen. You can have your input image rotated as you like, but adjust its orientation by passing `-r <...>` flag. See the image below for clarification. - -[![](examples/image_orientation.png)]() - - - -### Image resolution: - -As far as we've tested, Niimbot printers have **8 pixels per mm** (~203 dpi) resolution. The CLI prints the image you provided as-is, without any checks of the actual label size, so be careful. However the script will check if the image width is too big for selected printer. The maximum width in pixels is usually slightly less than specified maximum width in mm: - -- **B21, B1, B18**: max 384 pixels (almost equal to 50 mm * 8 px/mm = 400) -- **D11**: max 96 pixels (almost equal to 15 mm * 8 px/mm = 120) - -### USB connection: - -For USB connection, you can omit the `--addr` argument and let the script auto-detect the serial port. However, it will fail if there're multiple available ports. On linux, serial ports can be found at `/dev/ttyUSB*`, `/dev/ttyACM*` or `/dev/serial/*`. On windows, they will be named like `COM1`, `COM2` etc. Check the device manager to choose the correct one. - -### Bluetooth connection: - -It seems like B21 (and maybe other models?) has two bluetooth adresses. For me, they start with `C2:E1` and `E2:E1` respectively. Connection works only if you disconnect from `C2:E1` and connect to `E2:E1`. Also after connecting to `E2:E1` via bluetoothctl I always get `org.bluez.Error.NotAvailable br-connection-profile-unavailable` error, but printing works fine regardless. - -## Examples - -**B21, USB connection, 30x15 mm (240x120 px) label** - -``` -python niimprint -c usb -a /dev/ttyACM0 -r 90 -i examples/B21_30x15mm_240x120px.png -``` - -[![](examples/B21_30x15_result.png)]() - -**B21, Bluetooth connection, 80x50 mm (640x384 px) label** - -``` -python niimprint -c bluetooth -a "E2:E1:08:03:09:87" -r 90 -i examples/B21_80x50mm_640x384px.png -``` - -[![](examples/B21_80x50_result.png)]() - -## Licence - -[MIT](https://choosealicense.com/licenses/mit/). Originally developed by [kjy00302](https://github.com/kjy00302), forked & enhanced by [AndBondStyle](https://github.com/AndBondStyle)