From d649b1b01486195a345a9012eed0fc289d883531 Mon Sep 17 00:00:00 2001 From: knb Date: Sun, 12 Apr 2026 08:52:54 +0900 Subject: [PATCH] 1st version --- .gitignore | 7 + CMakeLists.txt | 47 + LICENSE | 21 + README.md | 96 ++ aB.png | Bin 0 -> 8339 bytes include/libptouch.h | 128 +++ include/libptouch_version.h.in | 17 + reference/cv_ptp900_jpn_raster_102.pdf | Bin 0 -> 1110215 bytes samples/README.md | 9 + src/cli/main.c | 292 ++++++ src/libptouch.c | 1164 ++++++++++++++++++++++++ udev/99-ptouch-label-brother.rules | 16 + 12 files changed, 1797 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 LICENSE create mode 100644 aB.png create mode 100644 include/libptouch.h create mode 100644 include/libptouch_version.h.in create mode 100644 reference/cv_ptp900_jpn_raster_102.pdf create mode 100644 samples/README.md create mode 100644 src/cli/main.c create mode 100644 src/libptouch.c create mode 100644 udev/99-ptouch-label-brother.rules diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..be1630e --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +build/ + +*.o +*.a +ptouch-print +*.so +*.dylib diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..78a6e0c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,47 @@ +# ptouch_label — build (libptouch, ptouch-print) +# +# Author: knb +# Email: knb@artif.org + +cmake_minimum_required(VERSION 3.16) +project(ptouch_label VERSION 1.0.0 LANGUAGES C) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) + +include(GNUInstallDirs) + +find_package(PkgConfig REQUIRED) +pkg_check_modules(LIBUSB REQUIRED IMPORTED_TARGET libusb-1.0) +find_package(PNG REQUIRED) + +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/include/libptouch_version.h.in" + "${CMAKE_CURRENT_BINARY_DIR}/include/libptouch_version.h" + @ONLY +) + +add_library(ptouch STATIC src/libptouch.c) +target_include_directories(ptouch PUBLIC + "$" + "$" + "$" +) +target_link_libraries(ptouch PRIVATE PkgConfig::LIBUSB PNG::PNG) +if(NOT MSVC) + target_compile_options(ptouch PRIVATE -Wall -Wextra -Wpedantic) +endif() + +add_executable(ptouch-print src/cli/main.c) +target_include_directories(ptouch-print PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include") +target_link_libraries(ptouch-print PRIVATE ptouch PkgConfig::LIBUSB) +if(NOT MSVC) + target_compile_options(ptouch-print PRIVATE -Wall -Wextra -Wpedantic) +endif() + +install(TARGETS ptouch ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}") +install(TARGETS ptouch-print RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") +install(FILES + "${CMAKE_CURRENT_SOURCE_DIR}/include/libptouch.h" + "${CMAKE_CURRENT_BINARY_DIR}/include/libptouch_version.h" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e7d4932 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 ptouch_label contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index e69de29..d2f554e 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,96 @@ +# ptouch_label + +**バージョン 1.0.0**(初回リリース) + +Brother P-touch シリーズ向けのラベル印刷用 **C コアライブラリ(libptouch)** と、動作確認用 **CLI(`ptouch-print`)** のリポジトリです。 + +保有機種: **PT-P900W**(USB・ラスターコマンド)。 + +## レイアウト + +| パス | 内容 | +|------|------| +| `include/libptouch.h` | 公開 API | +| `src/libptouch.c` | ライブラリ本体(スタブ) | +| `src/cli/main.c` | `ptouch-print` エントリ | +| `samples/` | 試験用サンプル画像の置き場(PNG 等) | +| `reference/` | 仕様・参考資料(例: ラスター PDF) | + +## ビルド + +依存: **CMake 3.16+**、**libusb-1.0**、**libpng**(開発パッケージ例: `libusb-1.0-0-dev`、`libpng-dev`)。 + +```bash +cmake -S . -B build +cmake --build build +``` + +成果物(`build/` 以下): + +- `libptouch.a` — 静的ライブラリ +- `ptouch-print` — CLI + +## CLI の使い方(雛形) + +**PNG**(拡張子 `.png` または PNG シグネチャ)の場合は幅・高さは画像から取得します。任意で `-t`(0–255)で二値化しきい値を指定できます。 + +**1bit packed ラスター**(行優先、行あたり `ceil(width/8)` バイト × 行数)の場合は `-f` に加え `-w` / `-H` が必須です。 + +印刷時、`libptouch_print_raster` は内部でラスターを**転置**してから送ります(`-T` / `-M` などのオプションはありません。鏡像のみの変換は行いません)。 + +```bash +# PNG — 検証のみ(USB 不要) +./build/ptouch-print -n -f label.png + +# PNG — しきい値を指定 +./build/ptouch-print -n -f label.png -t 160 + +# 1bit ラスター — 検証のみ +./build/ptouch-print -n -f sample.raster -w 128 -H 64 + +# プリンタステータス(テープ幅・種類・色・エラービット等、PDF の 32 バイト応答) +./build/ptouch-print --status + +# USB 接続時 +./build/ptouch-print -f label.png +./build/ptouch-print -f sample.raster -w 128 -H 64 +``` + +`-n`(`--dry-run`)では読み込みと `libptouch_check_raster` まで実行します。 + +## libptouch API(概要) + +- バージョン — `LIBPTOUCH_VERSION_MAJOR` / `MINOR` / `PATCH` / `LIBPTOUCH_VERSION_STRING`(`libptouch_version.h`、CMake の `project(VERSION …)` と同期) +- `libptouch_create` / `libptouch_destroy` — コンテキスト +- `libptouch_open_usb` / `libptouch_open_usb_vid_pid` / `libptouch_close` — USB(libusb・VID/PID) +- `libptouch_get_status` / `libptouch_status_fprint` — ステータス情報リクエスト(ESC i S)の応答 +- `libptouch_check_raster` — ラスターバッファの検証のみ +- `libptouch_png_file_to_raster` / `libptouch_free_raster` — PNG を 1bit ラスターに変換(libpng) +- `libptouch_print_raster` — ラスター印刷(USB・PDF のコマンド列、内部で転置) +- `libptouch_strerror` / `libptouch_last_error` — エラー情報 + +ラスター形式は `include/libptouch.h` のコメントに合わせてください。 + +## PT-P900W / Linux でのメモ + +- 接続は **libusb-1.0** のみ。機種ごとに **VID/PID**(`lsusb` 等)を調べ、`libptouch_open_usb_vid_pid` に渡すか、既定の PT-P900W なら `libptouch_open_usb` を使います。 +- ラスターコマンドの詳細は **`reference/` の PDF** および Brother 公開資料に沿って `src/libptouch.c` に実装してください。 + +### Ubuntu で sudo なしで USB を開く(udev) + +既定の **04f9:2085**(PT-P900W)向けルールを `udev/99-ptouch-label-brother.rules` に置いています。 + +```bash +sudo cp udev/99-ptouch-label-brother.rules /etc/udev/rules.d/ +sudo udevadm control --reload-rules +sudo udevadm trigger +sudo usermod -aG plugdev "$USER" +``` + +**再ログイン**するか、端末で `newgrp plugdev` のあと試すか、USB を**抜き差し**してください。`groups` に `plugdev` が含まれていれば、`./build/ptouch-print --status` などを sudo なしで実行できます。 + +別の Brother 機種(別 PID)のときは、`lsusb` の ID に合わせて同ファイルに行を追加してください。 + +## ライセンス + +[MIT License](LICENSE)(`LICENSE` ファイルを参照)。 diff --git a/aB.png b/aB.png new file mode 100644 index 0000000000000000000000000000000000000000..d32ac9fa2cbb88108ee183997802325360243838 GIT binary patch literal 8339 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 bw|0 +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** 不透明コンテキスト(接続状態・最終エラー文字列を保持) */ +typedef struct libptouch_ctx libptouch_ctx; + +typedef enum { + LIBPTOUCH_OK = 0, + LIBPTOUCH_ERR_NOMEM = 1, + LIBPTOUCH_ERR_ARG = 2, + LIBPTOUCH_ERR_USB = 3, + LIBPTOUCH_ERR_IO = 4, + LIBPTOUCH_ERR_UNSUPPORTED = 5, + LIBPTOUCH_ERR_NOT_FOUND = 6, + LIBPTOUCH_ERR_IMAGE = 7, +} libptouch_err_t; + +/** lsusb 例: PT-P900W — Brother Industries, Ltd (04f9:2085) */ +#define LIBPTOUCH_USB_VID_BROTHER 0x04f9u +#define LIBPTOUCH_USB_PID_PTP900W 0x2085u + +libptouch_ctx *libptouch_create(void); +void libptouch_destroy(libptouch_ctx *ctx); + +/** 人が読める英語メッセージ(スレッド非安全: ctx ごと) */ +const char *libptouch_strerror(const libptouch_ctx *ctx); +libptouch_err_t libptouch_last_error(const libptouch_ctx *ctx); + +/** + * USB でプリンタを開く(VID/PID で先頭の一致デバイスを開く。libusb のみ)。 + */ +libptouch_err_t libptouch_open_usb_vid_pid(libptouch_ctx *ctx, uint16_t vid, + uint16_t pid); + +/** + * 既定機種(@ref LIBPTOUCH_USB_VID_BROTHER / @ref LIBPTOUCH_USB_PID_PTP900W)を開く。 + * 別機種は @ref libptouch_open_usb_vid_pid に機種ごとの VID/PID を渡す。 + */ +libptouch_err_t libptouch_open_usb(libptouch_ctx *ctx); + +void libptouch_close(libptouch_ctx *ctx); + +typedef struct { + uint32_t width_dots; /**< ラスター幅(ドット) */ + uint32_t height_dots; /**< ラスター高さ(ドット・走査方向は実装と機種に依存) */ + uint8_t margin_mm; /**< 余白など(機種・仕様に合わせて使用) */ +} libptouch_raster_params_t; + +/** + * バッファサイズとパラメータの整合性のみ検査(USB 不要)。--dry-run 用。 + */ +libptouch_err_t libptouch_check_raster(libptouch_ctx *ctx, + const uint8_t *data, size_t data_len, + const libptouch_raster_params_t *params); + +/** + * 1 ビット packed ラスターを USB で印刷(cv_ptp900_jpn_raster_102.pdf 準拠)。 + * 印字前にステータスでテープ幅を読み、印刷可能ドット内に画像を中央配置する。 + * width_dots は装着テープの印刷可能幅以下であること。360dpi 相当のドット列を想定。 + * @param margin_mm 余白(フィード)量。0 のとき PDF の最小 1mm(14 ドット)相当を送る。 + * 印刷時は内部でドット列を転置する(テープ幅方向とバッファの縦横の対応)。 + * @param data 1 行あたり width_dots ビットを ceil(width_dots/8) バイトで並べた連続領域 + * @param data_len 期待値: height * row_bytes, row_bytes = (width_dots + 7) / 8 + */ +libptouch_err_t libptouch_print_raster(libptouch_ctx *ctx, + const uint8_t *data, size_t data_len, + const libptouch_raster_params_t *params); + +/** 二値化の既定しきい値(輝度 0–255、これ未満を黒ドット) */ +#define LIBPTOUCH_PNG_DEFAULT_THRESHOLD 128u + +typedef struct { + uint8_t threshold; /**< 輝度がこれ未満なら黒(1)、以上なら白(0) */ +} libptouch_png_options_t; + +/** + * PNG ファイルを読み、1bit packed ラスターに変換する(libpng)。 + * @param out_raster malloc 済みバッファのポインタを返す。不要時は @ref libptouch_free_raster で解放。 + */ +libptouch_err_t libptouch_png_file_to_raster(libptouch_ctx *ctx, const char *path, + const libptouch_png_options_t *options, + uint8_t **out_raster, size_t *out_raster_bytes, + libptouch_raster_params_t *out_params); + +void libptouch_free_raster(uint8_t *raster); + +/** ステータス情報リクエスト(ESC i S)の応答バイト数(cv_ptp900_jpn_raster_102.pdf) */ +#define LIBPTOUCH_STATUS_LENGTH 32u + +/** + * プリンタからステータスを読む(USB オープン済みであること)。 + * 送信: 初期化 ESC @ のあと ESC i S。応答は @ref LIBPTOUCH_STATUS_LENGTH バイト固定。 + */ +libptouch_err_t libptouch_get_status(libptouch_ctx *ctx, + uint8_t *status /* length @ref LIBPTOUCH_STATUS_LENGTH */); + +/** ステータス 32 バイトを人が読める形で出力(テープ幅・種類・色など) */ +void libptouch_status_fprint(FILE *fp, + const uint8_t *status /* length @ref LIBPTOUCH_STATUS_LENGTH */); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBPTOUCH_H */ diff --git a/include/libptouch_version.h.in b/include/libptouch_version.h.in new file mode 100644 index 0000000..59009a0 --- /dev/null +++ b/include/libptouch_version.h.in @@ -0,0 +1,17 @@ +/* + * libptouch_version.h — generated from this template by CMake + * + * Author: knb + * Email: knb@artif.org + */ + +#ifndef LIBPTOUCH_VERSION_H +#define LIBPTOUCH_VERSION_H + +/** リリースバージョン(CMake project(VERSION …) と同期) */ +#define LIBPTOUCH_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ +#define LIBPTOUCH_VERSION_MINOR @PROJECT_VERSION_MINOR@ +#define LIBPTOUCH_VERSION_PATCH @PROJECT_VERSION_PATCH@ +#define LIBPTOUCH_VERSION_STRING "@PROJECT_VERSION@" + +#endif diff --git a/reference/cv_ptp900_jpn_raster_102.pdf b/reference/cv_ptp900_jpn_raster_102.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e44b468db3e15c1756e1be7deaff2cc04b44025e GIT binary patch literal 1110215 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�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