libptouch の更新に追従
This commit is contained in:
@@ -24,6 +24,7 @@ configure_file(
|
|||||||
set(LIBPTOUCH_SOURCES
|
set(LIBPTOUCH_SOURCES
|
||||||
src/lib/libptouch_core.c
|
src/lib/libptouch_core.c
|
||||||
src/lib/libptouch_usb.c
|
src/lib/libptouch_usb.c
|
||||||
|
src/lib/libptouch_layout.c
|
||||||
src/lib/libptouch_print.c
|
src/lib/libptouch_print.c
|
||||||
src/lib/libptouch_status.c
|
src/lib/libptouch_status.c
|
||||||
src/lib/libptouch_png.c
|
src/lib/libptouch_png.c
|
||||||
|
|||||||
11
README.md
11
README.md
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Brother P-touch シリーズ向けのラベル印刷用 **C コアライブラリ(libptouch)** と、動作確認用 **CLI(`ptouch-print`)** のリポジトリです。
|
Brother P-touch シリーズ向けのラベル印刷用 **C コアライブラリ(libptouch)** と、動作確認用 **CLI(`ptouch-print`)** のリポジトリです。
|
||||||
|
|
||||||
保有機種: **PT-P900W**(USB・ラスターコマンド)。
|
対象機種: **PT-P900W**(560 ドットヘッド)、**PT-P750W** / **PT-P710BT**(128 ドットヘッド・USB)。`libptouch_open_usb_vid_pid` に各機種の VID/PID を渡す(P900W 既定は `libptouch_open_usb`)。P750/P710 のラスター仕様は `reference/cv_ptp750w_710bt_jpn_raster_102.pdf`。
|
||||||
|
|
||||||
## レイアウト
|
## レイアウト
|
||||||
|
|
||||||
@@ -60,6 +60,10 @@ cmake --build build
|
|||||||
# USB 接続時
|
# USB 接続時
|
||||||
./build/ptouch-print -f label.png
|
./build/ptouch-print -f label.png
|
||||||
./build/ptouch-print -f sample.raster -w 128 -H 64
|
./build/ptouch-print -f sample.raster -w 128 -H 64
|
||||||
|
|
||||||
|
# PT-P750W / PT-P710BT(`lsusb` の PID に合わせる)
|
||||||
|
./build/ptouch-print --status -p 0x2062
|
||||||
|
./build/ptouch-print -f label.png -p 0x20af
|
||||||
```
|
```
|
||||||
|
|
||||||
`-n`(`--dry-run`)では読み込みと `libptouch_check_raster` まで実行します。
|
`-n`(`--dry-run`)では読み込みと `libptouch_check_raster` まで実行します。
|
||||||
@@ -79,12 +83,13 @@ cmake --build build
|
|||||||
|
|
||||||
## PT-P900W / Linux でのメモ
|
## PT-P900W / Linux でのメモ
|
||||||
|
|
||||||
- 接続は **libusb-1.0** のみ。機種ごとに **VID/PID**(`lsusb` 等)を調べ、`libptouch_open_usb_vid_pid` に渡すか、既定の PT-P900W なら `libptouch_open_usb` を使います。
|
- 接続は **libusb-1.0** のみ。機種ごとに **VID/PID**(`lsusb` 等)を調べ、`libptouch_open_usb_vid_pid` に渡すか、既定の PT-P900W なら `libptouch_open_usb` を使います。PT-P750W は **04f9:2062**、PT-P710BT は **04f9:20af**(`include/libptouch.h` の定数参照)。
|
||||||
|
- PT-P750W / PT-P710BT ではラスター幅方向は **180 dpi**(P900W は 360 dpi)。PNG から印刷する場合は解像度に合わせて画像を用意してください。
|
||||||
- ラスターコマンドの詳細は **`reference/` の PDF** および Brother 公開資料に沿って `src/lib/libptouch_*.c` に実装してください。
|
- ラスターコマンドの詳細は **`reference/` の PDF** および Brother 公開資料に沿って `src/lib/libptouch_*.c` に実装してください。
|
||||||
|
|
||||||
### Ubuntu で sudo なしで USB を開く(udev)
|
### Ubuntu で sudo なしで USB を開く(udev)
|
||||||
|
|
||||||
既定の **04f9:2085**(PT-P900W)向けルールを `udev/99-ptouch-label-brother.rules` に置いています。
|
**04f9:2085**(PT-P900W)、**04f9:2062**(PT-P750W)、**04f9:20af**(PT-P710BT)向けルールを `udev/99-ptouch-label-brother.rules` に置いています。
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo cp udev/99-ptouch-label-brother.rules /etc/udev/rules.d/
|
sudo cp udev/99-ptouch-label-brother.rules /etc/udev/rules.d/
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
/**
|
/**
|
||||||
* libptouch — Brother P-touch ラスター印刷 (USB) 用 C API
|
* libptouch — Brother P-touch ラスター印刷 (USB) 用 C API
|
||||||
*
|
*
|
||||||
* 対象例: PT-P900W(ラスターコマンド)。実装は src/lib/libptouch_*.c を参照。
|
* 対象例: PT-P900W(560 ドットヘッド)、PT-P750W / PT-P710BT(128 ドットヘッド)。
|
||||||
|
* 実装は src/lib/libptouch_*.c を参照。
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef LIBPTOUCH_H
|
#ifndef LIBPTOUCH_H
|
||||||
@@ -41,6 +42,9 @@ typedef enum {
|
|||||||
/** lsusb 例: PT-P900W — Brother Industries, Ltd (04f9:2085) */
|
/** lsusb 例: PT-P900W — Brother Industries, Ltd (04f9:2085) */
|
||||||
#define LIBPTOUCH_USB_VID_BROTHER 0x04f9u
|
#define LIBPTOUCH_USB_VID_BROTHER 0x04f9u
|
||||||
#define LIBPTOUCH_USB_PID_PTP900W 0x2085u
|
#define LIBPTOUCH_USB_PID_PTP900W 0x2085u
|
||||||
|
/** PT-P750W / PT-P710BT(cv_ptp750w_710bt_jpn_raster_102.pdf Appendix A) */
|
||||||
|
#define LIBPTOUCH_USB_PID_PTP750W 0x2062u
|
||||||
|
#define LIBPTOUCH_USB_PID_PTP710BT 0x20afu
|
||||||
|
|
||||||
libptouch_ctx *libptouch_create(void);
|
libptouch_ctx *libptouch_create(void);
|
||||||
void libptouch_destroy(libptouch_ctx *ctx);
|
void libptouch_destroy(libptouch_ctx *ctx);
|
||||||
@@ -77,9 +81,10 @@ libptouch_err_t libptouch_check_raster(libptouch_ctx *ctx,
|
|||||||
const libptouch_raster_params_t *params);
|
const libptouch_raster_params_t *params);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1 ビット packed ラスターを USB で印刷(cv_ptp900_jpn_raster_102.pdf 準拠)。
|
* 1 ビット packed ラスターを USB で印刷(各機種のラスター PDF 準拠)。
|
||||||
* 印字前にステータスでテープ幅を読み、印刷可能ドット内に画像を中央配置する。
|
* 印字前にステータスでテープ幅を読み、印刷可能ドット内に画像を中央配置する。
|
||||||
* width_dots は装着テープの印刷可能幅以下であること。360dpi 相当のドット列を想定。
|
* width_dots は装着テープの印刷可能幅以下であること。PT-P900 系は幅 360dpi、
|
||||||
|
* PT-P750W / PT-P710BT は幅 180dpi(cv_ptp750w_710bt_jpn_raster_102.pdf)のドット列を想定。
|
||||||
* @param margin_mm 余白(フィード)量。0 のとき PDF の最小 1mm(14 ドット)相当を送る。
|
* @param margin_mm 余白(フィード)量。0 のとき PDF の最小 1mm(14 ドット)相当を送る。
|
||||||
* 印刷時は内部でドット列を転置する(テープ幅方向とバッファの縦横の対応)。
|
* 印刷時は内部でドット列を転置する(テープ幅方向とバッファの縦横の対応)。
|
||||||
* @param data 1 行あたり width_dots ビットを ceil(width_dots/8) バイトで並べた連続領域
|
* @param data 1 行あたり width_dots ビットを ceil(width_dots/8) バイトで並べた連続領域
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# libptouch(Ruby gem)
|
# libptouch(Ruby gem)
|
||||||
|
|
||||||
[ptouch_label](../) の **libptouch** を [ffi](https://github.com/ffi/ffi) 経由で使うための Gem です。
|
[ptouch_label](../) の **libptouch** を [ffi](https://github.com/ffi/ffi) 経由で使うための Gem です。C ライブラリと同様、**PT-P900W**(既定 USB PID)、**PT-P750W** / **PT-P710BT** などは `open_usb_vid_pid` または CLI の `-p` で選びます。
|
||||||
|
|
||||||
## 前提
|
## 前提
|
||||||
|
|
||||||
@@ -35,11 +35,15 @@ export LIBPTOUCH_LIB=/usr/local/lib/libptouch.so
|
|||||||
|
|
||||||
C の `ptouch-print` と同様の流れですが、**PNG 入力のみ**(`-w`/`-H` や 1bit ラスターは扱いません)。`gem install` 後は PATH に `ptouch-print-png` が入ります。
|
C の `ptouch-print` と同様の流れですが、**PNG 入力のみ**(`-w`/`-H` や 1bit ラスターは扱いません)。`gem install` 後は PATH に `ptouch-print-png` が入ります。
|
||||||
|
|
||||||
|
オプションは C 側に合わせ、**`-p` / `--pid`** で USB 製品 ID(16 進可)を指定できます。省略時は PT-P900W(`Libptouch::USB_PID_PTP900W` = `0x2085`)。例: PT-P750W `0x2062`、PT-P710BT `0x20af`(`libptouch.h` / `Libptouch` 定数と同じ)。
|
||||||
|
|
||||||
開発ツリーからそのまま試す例:
|
開発ツリーからそのまま試す例:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bundle exec ruby -I lib exe/ptouch-print-png --help
|
bundle exec ruby -I lib exe/ptouch-print-png --help
|
||||||
bundle exec ruby -I lib exe/ptouch-print-png -n -f ../samples/your.png
|
bundle exec ruby -I lib exe/ptouch-print-png -n -f ../samples/your.png
|
||||||
|
bundle exec ruby -I lib exe/ptouch-print-png --status -p 0x2062
|
||||||
|
bundle exec ruby -I lib exe/ptouch-print-png -f ../samples/your.png -p 0x20af
|
||||||
```
|
```
|
||||||
|
|
||||||
## 使用例
|
## 使用例
|
||||||
@@ -49,8 +53,11 @@ require "libptouch"
|
|||||||
|
|
||||||
Libptouch::Context.new.tap do |ctx|
|
Libptouch::Context.new.tap do |ctx|
|
||||||
ctx.open_usb
|
ctx.open_usb
|
||||||
|
# PT-P750W など別 PID のとき:
|
||||||
|
# ctx.open_usb_vid_pid(Libptouch::USB_VID_BROTHER, Libptouch::USB_PID_PTP750W)
|
||||||
p ctx.status_bytes.bytesize # => 32
|
p ctx.status_bytes.bytesize # => 32
|
||||||
p ctx.status_hash[:tape_kind] # => {:code=>..., :label=>"ラミネートテープ"} など
|
p ctx.status_hash[:tape_kind] # => {:code=>..., :label=>"ラミネートテープ"} など
|
||||||
|
p ctx.status_hash[:model] # => {:code=>..., :name=>"PT-P750W"} など(対応機種のみ名前あり)
|
||||||
p ctx.status_hash[:status_kind] # => 状態(ステータス種類)
|
p ctx.status_hash[:status_kind] # => 状態(ステータス種類)
|
||||||
ensure
|
ensure
|
||||||
ctx.dispose
|
ctx.dispose
|
||||||
@@ -64,14 +71,16 @@ PNG からラスターへ:
|
|||||||
```ruby
|
```ruby
|
||||||
ctx = Libptouch::Context.new
|
ctx = Libptouch::Context.new
|
||||||
data, w, h = ctx.png_file_to_raster("/path/to/label.png")
|
data, w, h = ctx.png_file_to_raster("/path/to/label.png")
|
||||||
ctx.open_usb
|
ctx.open_usb_vid_pid(Libptouch::USB_VID_BROTHER, Libptouch::USB_PID_PTP750W)
|
||||||
ctx.print_raster(data, width_dots: w, height_dots: h, margin_mm: 0)
|
ctx.print_raster(data, width_dots: w, height_dots: h, margin_mm: 0)
|
||||||
ctx.dispose
|
ctx.dispose
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**解像度:** P750W / P710BT はラスター幅方向が **180 dpi**、P900W 系は **360 dpi**(C の `libptouch_print` / 各機種ラスター PDF に合わせて画像を用意してください)。
|
||||||
|
|
||||||
## API の範囲
|
## API の範囲
|
||||||
|
|
||||||
- 実行ファイル `ptouch-print-png` … PNG のみ(`-f`, `-t`, `-n`, `-S`, `-V`, `-h`)。ステータスは JSON(`status_bytes` を `parse_status` したもの、`raw_bytes` 除く)
|
- 実行ファイル `ptouch-print-png` … PNG のみ(`-f`, `-t`, `-p`, `-n`, `-S`, `-V`, `-h`)。ステータスは JSON(`status_bytes` を `parse_status` したもの、`raw_bytes` 除く)
|
||||||
- `Libptouch::Context` … `open_usb` / `open_usb_vid_pid` / `close` / `dispose`
|
- `Libptouch::Context` … `open_usb` / `open_usb_vid_pid` / `close` / `dispose`
|
||||||
- `check_raster` / `print_raster` / `png_file_to_raster` / `status_bytes` / `status_hash`
|
- `check_raster` / `print_raster` / `png_file_to_raster` / `status_bytes` / `status_hash`
|
||||||
- `Libptouch.parse_status(raw)` … 32 バイトを Hash に展開(機種・テープ幅・**テープ種類**・色・**状態(status_kind)**・エラービット・`raw_hex` など)
|
- `Libptouch.parse_status(raw)` … 32 バイトを Hash に展開(機種・テープ幅・**テープ種類**・色・**状態(status_kind)**・エラービット・`raw_hex` など)
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ module Libptouch
|
|||||||
|
|
||||||
USB_VID_BROTHER = 0x04f9
|
USB_VID_BROTHER = 0x04f9
|
||||||
USB_PID_PTP900W = 0x2085
|
USB_PID_PTP900W = 0x2085
|
||||||
|
USB_PID_PTP750W = 0x2062
|
||||||
|
USB_PID_PTP710BT = 0x20af
|
||||||
|
|
||||||
STATUS_LENGTH = 32
|
STATUS_LENGTH = 32
|
||||||
PNG_DEFAULT_THRESHOLD = 128
|
PNG_DEFAULT_THRESHOLD = 128
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ module Libptouch
|
|||||||
|
|
||||||
if opts[:status]
|
if opts[:status]
|
||||||
warn_unused_file_options(opts)
|
warn_unused_file_options(opts)
|
||||||
return run_status
|
return run_status(opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
return usage_error("-f is required (or use --status)") if opts[:file].to_s.empty?
|
return usage_error("-f is required (or use --status)") if opts[:file].to_s.empty?
|
||||||
@@ -44,35 +44,78 @@ module Libptouch
|
|||||||
end
|
end
|
||||||
|
|
||||||
def parse(argv)
|
def parse(argv)
|
||||||
o = {
|
opts_hash = default_cli_opts
|
||||||
|
build_cli_parser(opts_hash).parse!(argv)
|
||||||
|
return nil unless threshold_option_ok?(opts_hash)
|
||||||
|
return nil unless usb_pid_option_ok?(opts_hash)
|
||||||
|
|
||||||
|
opts_hash.delete(:usb_pid_invalid)
|
||||||
|
opts_hash
|
||||||
|
end
|
||||||
|
|
||||||
|
def default_cli_opts
|
||||||
|
{
|
||||||
file: nil,
|
file: nil,
|
||||||
threshold: nil,
|
threshold: nil,
|
||||||
|
usb_pid: nil,
|
||||||
|
usb_pid_invalid: false,
|
||||||
dry_run: false,
|
dry_run: false,
|
||||||
status: false,
|
status: false,
|
||||||
version: false,
|
version: false,
|
||||||
help: false
|
help: false
|
||||||
}
|
}
|
||||||
parser = OptionParser.new do |p|
|
end
|
||||||
|
|
||||||
|
def pid_option_description
|
||||||
|
p900 = Libptouch::USB_PID_PTP900W
|
||||||
|
p750 = Libptouch::USB_PID_PTP750W
|
||||||
|
p710 = Libptouch::USB_PID_PTP710BT
|
||||||
|
"USB 製品 ID(16 進可)。既定 P900W 0x#{p900.to_s(16)}; " \
|
||||||
|
"P750W 0x#{p750.to_s(16)}; P710BT 0x#{p710.to_s(16)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def apply_usb_pid_option(opts_hash, pid_str)
|
||||||
|
opts_hash[:usb_pid] = Integer(pid_str, 0)
|
||||||
|
rescue ArgumentError
|
||||||
|
warn "invalid --pid: #{pid_str.inspect}"
|
||||||
|
opts_hash[:usb_pid_invalid] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
def threshold_option_ok?(opts_hash)
|
||||||
|
return true if opts_hash[:threshold].nil? || (0..255).cover?(opts_hash[:threshold])
|
||||||
|
|
||||||
|
warn "-t must be 0..255"
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def usb_pid_option_ok?(opts_hash)
|
||||||
|
return false if opts_hash[:usb_pid_invalid]
|
||||||
|
return true if opts_hash[:usb_pid].nil?
|
||||||
|
return true if opts_hash[:usb_pid].between?(1, 0xFFFF)
|
||||||
|
|
||||||
|
warn "-p/--pid must be 1..0xFFFF"
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_cli_parser(opts_hash)
|
||||||
|
OptionParser.new do |p|
|
||||||
p.banner = usage_banner
|
p.banner = usage_banner
|
||||||
p.separator ""
|
p.separator ""
|
||||||
p.on("-f", "--file PATH", "入力 PNG ファイル") { |v| o[:file] = v }
|
p.on("-f", "--file PATH", "入力 PNG ファイル") { |v| opts_hash[:file] = v }
|
||||||
p.on("-t", "--threshold N", Integer,
|
p.on("-t", "--threshold N", Integer,
|
||||||
"二値化しきい値 0–255(既定 #{Libptouch::PNG_DEFAULT_THRESHOLD})") do |v|
|
"二値化しきい値 0–255(既定 #{Libptouch::PNG_DEFAULT_THRESHOLD})") do |v|
|
||||||
o[:threshold] = v
|
opts_hash[:threshold] = v
|
||||||
end
|
end
|
||||||
p.on("-n", "--dry-run", "読み込みと検証のみ(USB なし)") { o[:dry_run] = true }
|
p.on("-p", "--pid PID", pid_option_description) do |v|
|
||||||
p.on("-S", "--status", "USB プリンタのステータスを JSON で表示して終了") { o[:status] = true }
|
apply_usb_pid_option(opts_hash, v)
|
||||||
p.on("-V", "--version", "バージョンを表示して終了") { o[:version] = true }
|
|
||||||
p.on("-h", "--help", "このヘルプ") { o[:help] = true }
|
|
||||||
end
|
end
|
||||||
parser.parse!(argv)
|
p.on("-n", "--dry-run", "読み込みと検証のみ(USB なし)") { opts_hash[:dry_run] = true }
|
||||||
|
p.on("-S", "--status", "USB プリンタのステータスを JSON で表示して終了") do
|
||||||
unless o[:threshold].nil? || (0..255).cover?(o[:threshold])
|
opts_hash[:status] = true
|
||||||
warn "-t must be 0..255"
|
end
|
||||||
return nil
|
p.on("-V", "--version", "バージョンを表示して終了") { opts_hash[:version] = true }
|
||||||
|
p.on("-h", "--help", "このヘルプ") { opts_hash[:help] = true }
|
||||||
end
|
end
|
||||||
|
|
||||||
o
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def usage_banner
|
def usage_banner
|
||||||
@@ -103,34 +146,40 @@ module Libptouch
|
|||||||
end
|
end
|
||||||
|
|
||||||
def parser_help_text
|
def parser_help_text
|
||||||
o = {
|
opts_hash = default_cli_opts
|
||||||
file: nil,
|
|
||||||
threshold: nil,
|
|
||||||
dry_run: false,
|
|
||||||
status: false,
|
|
||||||
version: false,
|
|
||||||
help: false
|
|
||||||
}
|
|
||||||
p = OptionParser.new do |parser|
|
p = OptionParser.new do |parser|
|
||||||
parser.banner = "ptouch-print-png [options]"
|
parser.banner = "ptouch-print-png [options]"
|
||||||
parser.on("-f", "--file PATH", "入力 PNG ファイル") { |v| o[:file] = v }
|
parser.on("-f", "--file PATH", "入力 PNG ファイル") { |v| opts_hash[:file] = v }
|
||||||
parser.on("-t", "--threshold N", Integer,
|
parser.on("-t", "--threshold N", Integer,
|
||||||
"二値化しきい値 0–255(既定 #{Libptouch::PNG_DEFAULT_THRESHOLD})") do |v|
|
"二値化しきい値 0–255(既定 #{Libptouch::PNG_DEFAULT_THRESHOLD})") do |v|
|
||||||
o[:threshold] = v
|
opts_hash[:threshold] = v
|
||||||
end
|
end
|
||||||
parser.on("-n", "--dry-run", "読み込みと検証のみ(USB なし)") { o[:dry_run] = true }
|
parser.on("-p", "--pid PID", pid_option_description) do |v|
|
||||||
parser.on("-S", "--status", "USB プリンタのステータスを JSON で表示して終了") { o[:status] = true }
|
apply_usb_pid_option(opts_hash, v)
|
||||||
parser.on("-V", "--version", "バージョンを表示して終了") { o[:version] = true }
|
end
|
||||||
parser.on("-h", "--help", "このヘルプ") { o[:help] = true }
|
parser.on("-n", "--dry-run", "読み込みと検証のみ(USB なし)") { opts_hash[:dry_run] = true }
|
||||||
|
parser.on("-S", "--status", "USB プリンタのステータスを JSON で表示して終了") do
|
||||||
|
opts_hash[:status] = true
|
||||||
|
end
|
||||||
|
parser.on("-V", "--version", "バージョンを表示して終了") { opts_hash[:version] = true }
|
||||||
|
parser.on("-h", "--help", "このヘルプ") { opts_hash[:help] = true }
|
||||||
end
|
end
|
||||||
p.help
|
p.help
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_status
|
def open_usb_for_opts(ctx, opts)
|
||||||
|
if opts[:usb_pid]
|
||||||
|
ctx.open_usb_vid_pid(Libptouch::USB_VID_BROTHER, opts[:usb_pid])
|
||||||
|
else
|
||||||
|
ctx.open_usb
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_status(opts)
|
||||||
ctx = nil
|
ctx = nil
|
||||||
begin
|
begin
|
||||||
ctx = Libptouch::Context.new
|
ctx = Libptouch::Context.new
|
||||||
ctx.open_usb
|
open_usb_for_opts(ctx, opts)
|
||||||
h = Libptouch.parse_status(ctx.status_bytes)
|
h = Libptouch.parse_status(ctx.status_bytes)
|
||||||
h.delete(:raw_bytes)
|
h.delete(:raw_bytes)
|
||||||
puts JSON.pretty_generate(h)
|
puts JSON.pretty_generate(h)
|
||||||
@@ -161,7 +210,7 @@ module Libptouch
|
|||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
|
|
||||||
ctx.open_usb
|
open_usb_for_opts(ctx, opts)
|
||||||
ctx.print_raster(data, width_dots: width, height_dots: height)
|
ctx.print_raster(data, width_dots: width, height_dots: height)
|
||||||
0
|
0
|
||||||
rescue Libptouch::Error => e
|
rescue Libptouch::Error => e
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ module Libptouch
|
|||||||
raw = out_pp.read_pointer
|
raw = out_pp.read_pointer
|
||||||
raise Libptouch::Error.new(OK, "null raster from PNG") if raw.null?
|
raise Libptouch::Error.new(OK, "null raster from PNG") if raw.null?
|
||||||
|
|
||||||
len = out_len.read_size_t
|
len = out_len.get(:size_t, 0)
|
||||||
bytes = raw.read_bytes(len)
|
bytes = raw.read_bytes(len)
|
||||||
Binding.libptouch_free_raster(raw)
|
Binding.libptouch_free_raster(raw)
|
||||||
[bytes, out_params[:width_dots], out_params[:height_dots]]
|
[bytes, out_params[:width_dots], out_params[:height_dots]]
|
||||||
|
|||||||
@@ -104,7 +104,9 @@ module Libptouch
|
|||||||
0x6F => "PT-P900W",
|
0x6F => "PT-P900W",
|
||||||
0x70 => "PT-P950NW",
|
0x70 => "PT-P950NW",
|
||||||
0x71 => "PT-P900",
|
0x71 => "PT-P900",
|
||||||
0x78 => "PT-P910BT"
|
0x78 => "PT-P910BT",
|
||||||
|
0x68 => "PT-P750W",
|
||||||
|
0x76 => "PT-P710BT"
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
MEDIA_WIDTH = {
|
MEDIA_WIDTH = {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ Gem::Specification.new do |spec|
|
|||||||
spec.summary = "FFI bindings for libptouch (Brother P-touch USB raster printing)"
|
spec.summary = "FFI bindings for libptouch (Brother P-touch USB raster printing)"
|
||||||
spec.description = [
|
spec.description = [
|
||||||
"Ruby wrapper around the ptouch_label C library libptouch.",
|
"Ruby wrapper around the ptouch_label C library libptouch.",
|
||||||
|
"Supports PT-P900W, PT-P750W, PT-P710BT and related open_usb_vid_pid / --pid.",
|
||||||
"Requires libptouch shared library (libusb, libpng)."
|
"Requires libptouch shared library (libusb, libpng)."
|
||||||
].join(" ")
|
].join(" ")
|
||||||
spec.license = "MIT"
|
spec.license = "MIT"
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ static void usage(const char *argv0)
|
|||||||
" -H, --height DOTS 1bit ラスター時: 高さ(ドット)\n"
|
" -H, --height DOTS 1bit ラスター時: 高さ(ドット)\n"
|
||||||
" -t, --threshold N PNG 二値化しきい値 0–255(既定 %u、PNG のみ)\n"
|
" -t, --threshold N PNG 二値化しきい値 0–255(既定 %u、PNG のみ)\n"
|
||||||
" -n, --dry-run 読み込みと check_raster のみ(USB なし)\n"
|
" -n, --dry-run 読み込みと check_raster のみ(USB なし)\n"
|
||||||
|
" -p, --pid HEX USB 製品 ID(既定: P900W の 0x2085)。例: P750W 0x2062、P710BT 0x20af\n"
|
||||||
" -S, --status USB 接続プリンタのステータス(テープ種・幅・色等)を表示して終了\n"
|
" -S, --status USB 接続プリンタのステータス(テープ種・幅・色等)を表示して終了\n"
|
||||||
" -V, --version バージョンを表示して終了\n"
|
" -V, --version バージョンを表示して終了\n"
|
||||||
" -h, --help このヘルプ\n"
|
" -h, --help このヘルプ\n"
|
||||||
@@ -95,6 +96,7 @@ int main(int argc, char **argv)
|
|||||||
const char *file = NULL;
|
const char *file = NULL;
|
||||||
unsigned width = 0, height = 0;
|
unsigned width = 0, height = 0;
|
||||||
unsigned threshold = LIBPTOUCH_PNG_DEFAULT_THRESHOLD;
|
unsigned threshold = LIBPTOUCH_PNG_DEFAULT_THRESHOLD;
|
||||||
|
unsigned usb_pid_arg = 0;
|
||||||
int dry_run = 0;
|
int dry_run = 0;
|
||||||
int has_threshold = 0;
|
int has_threshold = 0;
|
||||||
int want_status = 0;
|
int want_status = 0;
|
||||||
@@ -104,6 +106,7 @@ int main(int argc, char **argv)
|
|||||||
{ "file", required_argument, NULL, 'f' },
|
{ "file", required_argument, NULL, 'f' },
|
||||||
{ "threshold", required_argument, NULL, 't' },
|
{ "threshold", required_argument, NULL, 't' },
|
||||||
{ "dry-run", no_argument, NULL, 'n' },
|
{ "dry-run", no_argument, NULL, 'n' },
|
||||||
|
{ "pid", required_argument, NULL, 'p' },
|
||||||
{ "status", no_argument, NULL, 'S' },
|
{ "status", no_argument, NULL, 'S' },
|
||||||
{ "version", no_argument, NULL, 'V' },
|
{ "version", no_argument, NULL, 'V' },
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
@@ -111,7 +114,7 @@ int main(int argc, char **argv)
|
|||||||
};
|
};
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
while ((c = getopt_long(argc, argv, "w:H:f:t:nhSV", longopts, NULL)) !=
|
while ((c = getopt_long(argc, argv, "w:H:f:t:p:nhSV", longopts, NULL)) !=
|
||||||
-1) {
|
-1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'w':
|
case 'w':
|
||||||
@@ -134,6 +137,13 @@ int main(int argc, char **argv)
|
|||||||
case 'n':
|
case 'n':
|
||||||
dry_run = 1;
|
dry_run = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'p':
|
||||||
|
usb_pid_arg = (unsigned)strtoul(optarg, NULL, 0);
|
||||||
|
if (usb_pid_arg == 0u || usb_pid_arg > 0xFFFFu) {
|
||||||
|
fprintf(stderr, "-p/--pid must be 1..0xFFFF\n");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'S':
|
case 'S':
|
||||||
want_status = 1;
|
want_status = 1;
|
||||||
break;
|
break;
|
||||||
@@ -159,7 +169,12 @@ int main(int argc, char **argv)
|
|||||||
fprintf(stderr, "libptouch_create failed\n");
|
fprintf(stderr, "libptouch_create failed\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
libptouch_err_t se = libptouch_open_usb(sctx);
|
libptouch_err_t se =
|
||||||
|
usb_pid_arg != 0
|
||||||
|
? libptouch_open_usb_vid_pid(
|
||||||
|
sctx, LIBPTOUCH_USB_VID_BROTHER,
|
||||||
|
(uint16_t)usb_pid_arg)
|
||||||
|
: libptouch_open_usb(sctx);
|
||||||
if (se != LIBPTOUCH_OK) {
|
if (se != LIBPTOUCH_OK) {
|
||||||
fprintf(stderr, "open_usb: %s\n", libptouch_strerror(sctx));
|
fprintf(stderr, "open_usb: %s\n", libptouch_strerror(sctx));
|
||||||
libptouch_destroy(sctx);
|
libptouch_destroy(sctx);
|
||||||
@@ -258,7 +273,10 @@ int main(int argc, char **argv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
e = libptouch_open_usb(ctx);
|
e = usb_pid_arg != 0
|
||||||
|
? libptouch_open_usb_vid_pid(ctx, LIBPTOUCH_USB_VID_BROTHER,
|
||||||
|
(uint16_t)usb_pid_arg)
|
||||||
|
: libptouch_open_usb(ctx);
|
||||||
if (e != LIBPTOUCH_OK) {
|
if (e != LIBPTOUCH_OK) {
|
||||||
fprintf(stderr, "open_usb: %s\n", libptouch_strerror(ctx));
|
fprintf(stderr, "open_usb: %s\n", libptouch_strerror(ctx));
|
||||||
libptouch_destroy(ctx);
|
libptouch_destroy(ctx);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ struct libptouch_ctx {
|
|||||||
int claimed_interface; /* -1 if none */
|
int claimed_interface; /* -1 if none */
|
||||||
uint8_t bulk_out_ep;
|
uint8_t bulk_out_ep;
|
||||||
uint8_t bulk_in_ep;
|
uint8_t bulk_in_ep;
|
||||||
|
uint16_t usb_pid; /* 0 if USB not open; used to pick 128- vs 560-dot raster */
|
||||||
};
|
};
|
||||||
|
|
||||||
void ptouch_set_error(libptouch_ctx *ctx, libptouch_err_t code, const char *msg);
|
void ptouch_set_error(libptouch_ctx *ctx, libptouch_err_t code, const char *msg);
|
||||||
|
|||||||
159
src/lib/libptouch_layout.c
Normal file
159
src/lib/libptouch_layout.c
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
* libptouch — layout tables and profile resolution (Brother raster PDFs)
|
||||||
|
*
|
||||||
|
* Author: knb
|
||||||
|
* Email: knb@artif.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libptouch_layout.h"
|
||||||
|
|
||||||
|
/* --- cv_ptp900_jpn_raster_102.pdf: TZe / その他(HS 以外で共通レイアウトを使う帯) --- */
|
||||||
|
static const ptouch_layout_row_t layout_tze_560[] = {
|
||||||
|
{ 0x04, 248, 48, 264 },
|
||||||
|
{ 0x06, 240, 64, 256 },
|
||||||
|
{ 0x09, 219, 106, 235 },
|
||||||
|
{ 0x0C, 197, 150, 213 },
|
||||||
|
{ 0x12, 155, 234, 171 },
|
||||||
|
{ 0x18, 112, 320, 128 },
|
||||||
|
{ 0x24, 45, 454, 61 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const ptouch_layout_row_t layout_hs_560[] = {
|
||||||
|
{ 0x06, 244, 56, 260 },
|
||||||
|
{ 0x09, 224, 96, 240 },
|
||||||
|
{ 0x0C, 206, 132, 222 },
|
||||||
|
{ 0x12, 166, 212, 182 },
|
||||||
|
{ 0x18, 144, 256, 160 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* --- cv_ptp750w_710bt_jpn_raster_102.pdf --- */
|
||||||
|
static const ptouch_layout_row_t layout_tze_128[] = {
|
||||||
|
{ 0x04, 52, 24, 52 },
|
||||||
|
{ 0x06, 48, 32, 48 },
|
||||||
|
{ 0x09, 39, 50, 39 },
|
||||||
|
{ 0x0C, 29, 70, 29 },
|
||||||
|
{ 0x12, 8, 112, 8 },
|
||||||
|
{ 0x18, 0, 128, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const ptouch_layout_row_t layout_hs_128[] = {
|
||||||
|
{ 0x06, 50, 28, 50 },
|
||||||
|
{ 0x09, 40, 48, 40 },
|
||||||
|
{ 0x0C, 31, 66, 31 },
|
||||||
|
{ 0x12, 11, 106, 11 },
|
||||||
|
{ 0x18, 0, 128, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint16_t pids_128pin[] = {
|
||||||
|
LIBPTOUCH_USB_PID_PTP750W,
|
||||||
|
LIBPTOUCH_USB_PID_PTP710BT,
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t models_128pin[] = {
|
||||||
|
0x68, /* PT-P750W */
|
||||||
|
0x76, /* PT-P710BT */
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const ptouch_printer_profile_t ptouch_layout_profiles[] = {
|
||||||
|
{
|
||||||
|
.usb_pids = pids_128pin,
|
||||||
|
.model_codes = models_128pin,
|
||||||
|
.is_default = 0,
|
||||||
|
.head_width_dots = 128u,
|
||||||
|
.margin_feed_dpi = 180.0,
|
||||||
|
.margin_feed_max_dots = 900u,
|
||||||
|
.tze = layout_tze_128,
|
||||||
|
.tze_count = sizeof(layout_tze_128) / sizeof(layout_tze_128[0]),
|
||||||
|
.hs = layout_hs_128,
|
||||||
|
.hs_count = sizeof(layout_hs_128) / sizeof(layout_hs_128[0]),
|
||||||
|
.doc_ref = "cv_ptp750w_710bt_jpn_raster_102.pdf",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.usb_pids = NULL,
|
||||||
|
.model_codes = NULL,
|
||||||
|
.is_default = 1,
|
||||||
|
.head_width_dots = 560u,
|
||||||
|
.margin_feed_dpi = 360.0,
|
||||||
|
.margin_feed_max_dots = 1800u,
|
||||||
|
.tze = layout_tze_560,
|
||||||
|
.tze_count = sizeof(layout_tze_560) / sizeof(layout_tze_560[0]),
|
||||||
|
.hs = layout_hs_560,
|
||||||
|
.hs_count = sizeof(layout_hs_560) / sizeof(layout_hs_560[0]),
|
||||||
|
.doc_ref = "cv_ptp900_jpn_raster_102.pdf (560-dot family)",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int pid_in_list(const uint16_t *list, uint16_t pid)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
|
return 0;
|
||||||
|
for (; *list; list++) {
|
||||||
|
if (*list == pid)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int model_in_list(const uint8_t *list, uint8_t code)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
|
return 0;
|
||||||
|
for (; *list; list++) {
|
||||||
|
if (*list == code)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ptouch_printer_profile_t *ptouch_layout_resolve_profile(uint16_t usb_pid,
|
||||||
|
uint8_t status_model_byte)
|
||||||
|
{
|
||||||
|
const ptouch_printer_profile_t *fallback = NULL;
|
||||||
|
|
||||||
|
for (size_t i = 0;
|
||||||
|
i < sizeof(ptouch_layout_profiles) / sizeof(ptouch_layout_profiles[0]);
|
||||||
|
i++) {
|
||||||
|
const ptouch_printer_profile_t *p = &ptouch_layout_profiles[i];
|
||||||
|
if (p->is_default) {
|
||||||
|
fallback = p;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (pid_in_list(p->usb_pids, usb_pid) ||
|
||||||
|
model_in_list(p->model_codes, status_model_byte))
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
static libptouch_err_t layout_lookup_table(const ptouch_layout_row_t *table, size_t n,
|
||||||
|
uint8_t media_wbyte, uint16_t *left,
|
||||||
|
uint16_t *print_dots, uint16_t *right)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
if (table[i].media_wbyte != media_wbyte)
|
||||||
|
continue;
|
||||||
|
*left = table[i].left_dots;
|
||||||
|
*print_dots = table[i].print_dots;
|
||||||
|
*right = table[i].right_dots;
|
||||||
|
return LIBPTOUCH_OK;
|
||||||
|
}
|
||||||
|
return LIBPTOUCH_ERR_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
libptouch_err_t ptouch_layout_from_status(const ptouch_printer_profile_t *prof,
|
||||||
|
uint8_t media_kind, uint8_t media_wbyte,
|
||||||
|
uint16_t *left_dots, uint16_t *print_dots,
|
||||||
|
uint16_t *right_dots)
|
||||||
|
{
|
||||||
|
if (!prof || !left_dots || !print_dots || !right_dots)
|
||||||
|
return LIBPTOUCH_ERR_ARG;
|
||||||
|
|
||||||
|
int is_hs = (media_kind == 0x11u || media_kind == 0x17u);
|
||||||
|
const ptouch_layout_row_t *table = is_hs ? prof->hs : prof->tze;
|
||||||
|
size_t n = is_hs ? prof->hs_count : prof->tze_count;
|
||||||
|
|
||||||
|
return layout_lookup_table(table, n, media_wbyte, left_dots, print_dots,
|
||||||
|
right_dots);
|
||||||
|
}
|
||||||
50
src/lib/libptouch_layout.h
Normal file
50
src/lib/libptouch_layout.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* libptouch — tape width → printable dots (data tables per printer family)
|
||||||
|
*
|
||||||
|
* Author: knb
|
||||||
|
* Email: knb@artif.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBPTOUCH_LAYOUT_H
|
||||||
|
#define LIBPTOUCH_LAYOUT_H
|
||||||
|
|
||||||
|
#include "libptouch.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/** One row: status byte st[10] (media width code) when it matches this tape width slot */
|
||||||
|
typedef struct ptouch_layout_row {
|
||||||
|
uint8_t media_wbyte;
|
||||||
|
uint16_t left_dots;
|
||||||
|
uint16_t print_dots;
|
||||||
|
uint16_t right_dots;
|
||||||
|
} ptouch_layout_row_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Printer family: USB PID / status model byte select a profile; tables supply layouts.
|
||||||
|
* New models: add a row to @ref ptouch_layout_profiles or add TZe/HS rows to existing tables.
|
||||||
|
*/
|
||||||
|
typedef struct ptouch_printer_profile {
|
||||||
|
const uint16_t *usb_pids; /* 0-terminated; NULL = do not match on PID */
|
||||||
|
const uint8_t *model_codes; /* 0-terminated; NULL = do not match on status[4] */
|
||||||
|
int is_default; /* 1 = fallback when no other profile matches */
|
||||||
|
unsigned head_width_dots; /* 128 or 560; full raster width for pack/GF payload */
|
||||||
|
double margin_feed_dpi; /* ESC i d feed dots per inch (PDF) */
|
||||||
|
unsigned margin_feed_max_dots;
|
||||||
|
const ptouch_layout_row_t *tze;
|
||||||
|
size_t tze_count;
|
||||||
|
const ptouch_layout_row_t *hs;
|
||||||
|
size_t hs_count;
|
||||||
|
const char *doc_ref;
|
||||||
|
} ptouch_printer_profile_t;
|
||||||
|
|
||||||
|
const ptouch_printer_profile_t *ptouch_layout_resolve_profile(uint16_t usb_pid,
|
||||||
|
uint8_t status_model_byte);
|
||||||
|
|
||||||
|
libptouch_err_t ptouch_layout_from_status(const ptouch_printer_profile_t *prof,
|
||||||
|
uint8_t media_kind, uint8_t media_wbyte,
|
||||||
|
uint16_t *left_dots, uint16_t *print_dots,
|
||||||
|
uint16_t *right_dots);
|
||||||
|
|
||||||
|
#endif /* LIBPTOUCH_LAYOUT_H */
|
||||||
@@ -6,96 +6,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "libptouch_internal.h"
|
#include "libptouch_internal.h"
|
||||||
|
#include "libptouch_layout.h"
|
||||||
|
|
||||||
#include <libusb.h>
|
#include <libusb.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
/* cv_ptp900_jpn_raster_102.pdf: テープ幅から印刷可能ドット */
|
static void pack_line(uint8_t *line, size_t line_bytes, unsigned head_dots,
|
||||||
static libptouch_err_t layout_from_status(uint8_t media_kind, uint8_t media_wbyte,
|
const uint8_t *row, uint32_t width_dots, uint16_t left_dots,
|
||||||
uint16_t *left, uint16_t *print_dots,
|
uint16_t print_dots)
|
||||||
uint16_t *right)
|
|
||||||
{
|
{
|
||||||
if (media_kind == 0x11u || media_kind == 0x17u) {
|
memset(line, 0, line_bytes);
|
||||||
switch (media_wbyte) {
|
|
||||||
case 0x06:
|
|
||||||
*left = 244;
|
|
||||||
*print_dots = 56;
|
|
||||||
*right = 260;
|
|
||||||
return LIBPTOUCH_OK;
|
|
||||||
case 0x09:
|
|
||||||
*left = 224;
|
|
||||||
*print_dots = 96;
|
|
||||||
*right = 240;
|
|
||||||
return LIBPTOUCH_OK;
|
|
||||||
case 0x0C:
|
|
||||||
*left = 206;
|
|
||||||
*print_dots = 132;
|
|
||||||
*right = 222;
|
|
||||||
return LIBPTOUCH_OK;
|
|
||||||
case 0x12:
|
|
||||||
*left = 166;
|
|
||||||
*print_dots = 212;
|
|
||||||
*right = 182;
|
|
||||||
return LIBPTOUCH_OK;
|
|
||||||
case 0x18:
|
|
||||||
*left = 144;
|
|
||||||
*print_dots = 256;
|
|
||||||
*right = 160;
|
|
||||||
return LIBPTOUCH_OK;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (media_wbyte) {
|
|
||||||
case 0x04:
|
|
||||||
*left = 248;
|
|
||||||
*print_dots = 48;
|
|
||||||
*right = 264;
|
|
||||||
return LIBPTOUCH_OK;
|
|
||||||
case 0x06:
|
|
||||||
*left = 240;
|
|
||||||
*print_dots = 64;
|
|
||||||
*right = 256;
|
|
||||||
return LIBPTOUCH_OK;
|
|
||||||
case 0x09:
|
|
||||||
*left = 219;
|
|
||||||
*print_dots = 106;
|
|
||||||
*right = 235;
|
|
||||||
return LIBPTOUCH_OK;
|
|
||||||
case 0x0C:
|
|
||||||
*left = 197;
|
|
||||||
*print_dots = 150;
|
|
||||||
*right = 213;
|
|
||||||
return LIBPTOUCH_OK;
|
|
||||||
case 0x12:
|
|
||||||
*left = 155;
|
|
||||||
*print_dots = 234;
|
|
||||||
*right = 171;
|
|
||||||
return LIBPTOUCH_OK;
|
|
||||||
case 0x18:
|
|
||||||
*left = 112;
|
|
||||||
*print_dots = 320;
|
|
||||||
*right = 128;
|
|
||||||
return LIBPTOUCH_OK;
|
|
||||||
case 0x24:
|
|
||||||
*left = 45;
|
|
||||||
*print_dots = 454;
|
|
||||||
*right = 61;
|
|
||||||
return LIBPTOUCH_OK;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
(void)media_kind;
|
|
||||||
return LIBPTOUCH_ERR_UNSUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* cv_ptp900_jpn_raster_102.pdf: 2.3.5 ラスターライン(全 560 ドット = 70 バイト) */
|
|
||||||
static void pack_line_560(uint8_t line[70], const uint8_t *row, uint32_t width_dots,
|
|
||||||
uint16_t left_dots, uint16_t print_dots)
|
|
||||||
{
|
|
||||||
memset(line, 0, 70u);
|
|
||||||
if (width_dots > (uint32_t)print_dots)
|
if (width_dots > (uint32_t)print_dots)
|
||||||
return;
|
return;
|
||||||
uint32_t start = (uint32_t)left_dots +
|
uint32_t start = (uint32_t)left_dots +
|
||||||
@@ -106,7 +28,7 @@ static void pack_line_560(uint8_t line[70], const uint8_t *row, uint32_t width_d
|
|||||||
if (((row[ubyte] >> ubit) & 1u) == 0)
|
if (((row[ubyte] >> ubit) & 1u) == 0)
|
||||||
continue;
|
continue;
|
||||||
uint32_t dot = start + x;
|
uint32_t dot = start + x;
|
||||||
if (dot >= 560u)
|
if (dot >= (uint32_t)head_dots)
|
||||||
break;
|
break;
|
||||||
uint32_t b = dot / 8u;
|
uint32_t b = dot / 8u;
|
||||||
uint32_t bi = 7u - (dot % 8u);
|
uint32_t bi = 7u - (dot % 8u);
|
||||||
@@ -158,11 +80,19 @@ libptouch_err_t libptouch_print_raster(libptouch_ctx *ctx,
|
|||||||
if (v != LIBPTOUCH_OK)
|
if (v != LIBPTOUCH_OK)
|
||||||
return v;
|
return v;
|
||||||
|
|
||||||
|
const ptouch_printer_profile_t *prof =
|
||||||
|
ptouch_layout_resolve_profile(ctx->usb_pid, st[4]);
|
||||||
|
if (!prof) {
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_UNSUPPORTED,
|
||||||
|
"no layout profile for this printer");
|
||||||
|
return LIBPTOUCH_ERR_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t media_kind = st[11];
|
uint8_t media_kind = st[11];
|
||||||
uint8_t media_w = st[10];
|
uint8_t media_w = st[10];
|
||||||
uint16_t left_dots, print_dots, right_dots;
|
uint16_t left_dots, print_dots, right_dots;
|
||||||
v = layout_from_status(media_kind, media_w, &left_dots, &print_dots,
|
v = ptouch_layout_from_status(prof, media_kind, media_w, &left_dots,
|
||||||
&right_dots);
|
&print_dots, &right_dots);
|
||||||
if (v != LIBPTOUCH_OK) {
|
if (v != LIBPTOUCH_OK) {
|
||||||
ptouch_set_error(ctx, LIBPTOUCH_ERR_UNSUPPORTED,
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_UNSUPPORTED,
|
||||||
"tape width/layout not supported for this media "
|
"tape width/layout not supported for this media "
|
||||||
@@ -171,6 +101,10 @@ libptouch_err_t libptouch_print_raster(libptouch_ctx *ctx,
|
|||||||
}
|
}
|
||||||
(void)right_dots;
|
(void)right_dots;
|
||||||
|
|
||||||
|
unsigned head_dots = prof->head_width_dots;
|
||||||
|
size_t line_payload = (size_t)((head_dots + 7u) / 8u);
|
||||||
|
size_t gf_packet = 3u + line_payload;
|
||||||
|
|
||||||
uint32_t wd = params->width_dots;
|
uint32_t wd = params->width_dots;
|
||||||
uint32_t ht = params->height_dots;
|
uint32_t ht = params->height_dots;
|
||||||
uint8_t *transposed = transpose_raster_alloc(data, wd, ht, &wd, &ht);
|
uint8_t *transposed = transpose_raster_alloc(data, wd, ht, &wd, &ht);
|
||||||
@@ -191,15 +125,17 @@ libptouch_err_t libptouch_print_raster(libptouch_ctx *ctx,
|
|||||||
return LIBPTOUCH_ERR_ARG;
|
return LIBPTOUCH_ERR_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double margin_dpi = prof->margin_feed_dpi;
|
||||||
|
unsigned margin_max = prof->margin_feed_max_dots;
|
||||||
unsigned margin_dots = 14u;
|
unsigned margin_dots = 14u;
|
||||||
if (params->margin_mm > 0) {
|
if (params->margin_mm > 0) {
|
||||||
margin_dots = (unsigned)((double)params->margin_mm * 360.0 /
|
margin_dots = (unsigned)((double)params->margin_mm * margin_dpi /
|
||||||
25.4 +
|
25.4 +
|
||||||
0.5);
|
0.5);
|
||||||
if (margin_dots < 14u)
|
if (margin_dots < 14u)
|
||||||
margin_dots = 14u;
|
margin_dots = 14u;
|
||||||
if (margin_dots > 1800u)
|
if (margin_dots > margin_max)
|
||||||
margin_dots = 1800u;
|
margin_dots = margin_max;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t lines = ht;
|
uint32_t lines = ht;
|
||||||
@@ -263,19 +199,29 @@ libptouch_err_t libptouch_print_raster(libptouch_ctx *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t row_b = ((size_t)wd + 7u) / 8u;
|
size_t row_b = ((size_t)wd + 7u) / 8u;
|
||||||
uint8_t gbuf[73];
|
|
||||||
static const uint8_t g_hdr[] = { 0x47, 0x46, 0x00 };
|
static const uint8_t g_hdr[] = { 0x47, 0x46, 0x00 };
|
||||||
|
|
||||||
|
uint8_t *gbuf = (uint8_t *)malloc(gf_packet);
|
||||||
|
if (!gbuf) {
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_NOMEM,
|
||||||
|
"raster line buffer");
|
||||||
|
free(transposed);
|
||||||
|
return LIBPTOUCH_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
for (uint32_t y = 0; y < lines; y++) {
|
for (uint32_t y = 0; y < lines; y++) {
|
||||||
const uint8_t *row = src + (size_t)y * row_b;
|
const uint8_t *row = src + (size_t)y * row_b;
|
||||||
pack_line_560(gbuf + 3, row, wd, left_dots, print_dots);
|
pack_line(gbuf + 3, line_payload, head_dots, row, wd, left_dots,
|
||||||
|
print_dots);
|
||||||
memcpy(gbuf, g_hdr, sizeof(g_hdr));
|
memcpy(gbuf, g_hdr, sizeof(g_hdr));
|
||||||
v = ptouch_bulk_send_job(ctx, gbuf, sizeof(gbuf), "raster line");
|
v = ptouch_bulk_send_job(ctx, gbuf, gf_packet, "raster line");
|
||||||
if (v != LIBPTOUCH_OK) {
|
if (v != LIBPTOUCH_OK) {
|
||||||
|
free(gbuf);
|
||||||
free(transposed);
|
free(transposed);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
free(gbuf);
|
||||||
|
|
||||||
static const uint8_t print_end[] = { 0x1A };
|
static const uint8_t print_end[] = { 0x1A };
|
||||||
v = ptouch_bulk_send_job(ctx, print_end, sizeof(print_end), "print end");
|
v = ptouch_bulk_send_job(ctx, print_end, sizeof(print_end), "print end");
|
||||||
|
|||||||
@@ -75,6 +75,12 @@ static void fprint_model(FILE *fp, uint8_t code)
|
|||||||
case 0x78:
|
case 0x78:
|
||||||
name = "PT-P910BT";
|
name = "PT-P910BT";
|
||||||
break;
|
break;
|
||||||
|
case 0x68:
|
||||||
|
name = "PT-P750W";
|
||||||
|
break;
|
||||||
|
case 0x76:
|
||||||
|
name = "PT-P710BT";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ libptouch_err_t libptouch_open_usb_vid_pid(libptouch_ctx *ctx, uint16_t vid,
|
|||||||
(void)libusb_clear_halt(h, ctx->bulk_out_ep);
|
(void)libusb_clear_halt(h, ctx->bulk_out_ep);
|
||||||
(void)libusb_clear_halt(h, ctx->bulk_in_ep);
|
(void)libusb_clear_halt(h, ctx->bulk_in_ep);
|
||||||
|
|
||||||
|
ctx->usb_pid = pid;
|
||||||
ctx->usb_open = 1;
|
ctx->usb_open = 1;
|
||||||
ptouch_set_error(ctx, LIBPTOUCH_OK, "");
|
ptouch_set_error(ctx, LIBPTOUCH_OK, "");
|
||||||
return LIBPTOUCH_OK;
|
return LIBPTOUCH_OK;
|
||||||
@@ -141,6 +142,7 @@ void libptouch_close(libptouch_ctx *ctx)
|
|||||||
}
|
}
|
||||||
ctx->bulk_out_ep = 0;
|
ctx->bulk_out_ep = 0;
|
||||||
ctx->bulk_in_ep = 0;
|
ctx->bulk_in_ep = 0;
|
||||||
|
ctx->usb_pid = 0;
|
||||||
ctx->usb_open = 0;
|
ctx->usb_open = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
# Brother P-touch — libusb でユーザから開けるようにする (Ubuntu 等)
|
# Brother P-touch — libusb でユーザから開けるようにする (Ubuntu 等)
|
||||||
# PT-P900W: lsusb で ID 04f9:2085
|
# PT-P900W: lsusb で ID 04f9:2085
|
||||||
|
# PT-P750W: 04f9:2062 PT-P710BT: 04f9:20af(Brother ラスター PDF Appendix A)
|
||||||
#
|
#
|
||||||
# 設置:
|
# 設置:
|
||||||
# sudo cp udev/99-ptouch-label-brother.rules /etc/udev/rules.d/
|
# sudo cp udev/99-ptouch-label-brother.rules /etc/udev/rules.d/
|
||||||
@@ -11,6 +12,8 @@
|
|||||||
# GROUP=plugdev … 従来どおり plugdev に所属していれば読み書き可
|
# GROUP=plugdev … 従来どおり plugdev に所属していれば読み書き可
|
||||||
|
|
||||||
SUBSYSTEM=="usb", ATTR{idVendor}=="04f9", ATTR{idProduct}=="2085", MODE="0660", GROUP="plugdev", TAG+="uaccess"
|
SUBSYSTEM=="usb", ATTR{idVendor}=="04f9", ATTR{idProduct}=="2085", MODE="0660", GROUP="plugdev", TAG+="uaccess"
|
||||||
|
SUBSYSTEM=="usb", ATTR{idVendor}=="04f9", ATTR{idProduct}=="2062", MODE="0660", GROUP="plugdev", TAG+="uaccess"
|
||||||
|
SUBSYSTEM=="usb", ATTR{idVendor}=="04f9", ATTR{idProduct}=="20af", MODE="0660", GROUP="plugdev", TAG+="uaccess"
|
||||||
|
|
||||||
# 他機種を使う場合は lsusb の ID を足す例(コメントを外して複製):
|
# 他機種を使う場合は lsusb の ID を足す例(コメントを外して複製):
|
||||||
# SUBSYSTEM=="usb", ATTR{idVendor}=="04f9", ATTR{idProduct}=="2086", MODE="0660", GROUP="plugdev", TAG+="uaccess"
|
# SUBSYSTEM=="usb", ATTR{idVendor}=="04f9", ATTR{idProduct}=="2086", MODE="0660", GROUP="plugdev", TAG+="uaccess"
|
||||||
|
|||||||
Reference in New Issue
Block a user