# libptouch（Ruby 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` で選びます。

## 前提

1. リポジトリルートで共有ライブラリをビルドする（`libptouch.so` が `build/` に生成されます）。

   ```bash
   cmake -S .. -B ../build
   cmake --build ../build
   ```

2. Ruby 3.0 以上と `ffi` gem。

## インストール（開発時）

```bash
cd ruby
bundle install   # または gem install ffi
bundle exec rubocop   # 任意: スタイルチェック（.rubocop.yml）
gem build libptouch.gemspec
gem install ./libptouch-1.0.0.gem
```

ビルド済みの `../build/libptouch.so` を自動で読みに行きます。別のパスにある場合は環境変数で指定できます。

```bash
export LIBPTOUCH_LIB=/usr/local/lib/libptouch.so
```

（`cmake --install` で共有ライブラリをインストールした場合は、通常は `libptouch` 名でローダが解決します。）

## コマンド `ptouch-label`（PNG/SVG）

C の `ptouch-print` と同様の流れで、**PNG/SVG 入力**（`-w`/`-H` や 1bit ラスターは扱いません）を扱います。`gem install` 後は PATH に `ptouch-label` が入ります。
SVG は現在装着テープの印字可能幅に合わせて自動拡大・縮小します（USB 接続が必要）。
後方互換のため `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` 定数と同じ）。
また、`--template`（SVG）と `--data`（JSON/YAML）を使うと `data-field` 属性をキーにした差込印刷が可能です。
`--trim-right[=DOTS]` を付けると、libptouch 側の共通処理でラベル右側の空白ドット列を削減します。`DOTS` 省略時は左余白ドット数を使い、取得失敗時は `0` にフォールバックします。

開発ツリーからそのまま試す例:

```bash
bundle exec ruby -I lib exe/ptouch-label --help
bundle exec ruby -I lib exe/ptouch-label -n -f ../samples/your.png
bundle exec ruby -I lib exe/ptouch-label -n -f ../samples/your.svg
bundle exec ruby -I lib exe/ptouch-label -n -f ../samples/your.svg --trim-right
bundle exec ruby -I lib exe/ptouch-label -n -f ../samples/your.svg --trim-right=20
bundle exec ruby -I lib exe/ptouch-label -n --template ../samples/your_template.svg --data ../samples/your_data.yml
bundle exec ruby -I lib exe/ptouch-label --media-info
bundle exec ruby -I lib exe/ptouch-label --status -p 0x2062
bundle exec ruby -I lib exe/ptouch-label -f ../samples/your.png -p 0x20af
```

## 使用例

```ruby
require "libptouch"

Libptouch::Context.new.tap do |ctx|
  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_hash[:tape_kind]   # => {:code=>..., :label=>"ラミネートテープ"} など
  p ctx.status_hash[:model]       # => {:code=>..., :name=>"PT-P750W"} など（対応機種のみ名前あり）
  p ctx.status_hash[:status_kind] # => 状態（ステータス種類）
ensure
  ctx.dispose
end
```

生の 32 バイトだけある場合は `Libptouch.parse_status(raw)` で同じ Hash 形式に展開できます（中身は `libptouch_status_fprint` と同じ区分）。

PNG からラスターへ:

```ruby
ctx = Libptouch::Context.new
data, w, h = ctx.png_file_to_raster("/path/to/label.png")
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.dispose
```

SVG から現在テープ幅に合わせてラスターへ:

```ruby
ctx = Libptouch::Context.new
ctx.open_usb
data, w, h = ctx.svg_file_to_raster_fit_current_tape("/path/to/label.svg")
ctx.print_raster(data, width_dots: w, height_dots: h, margin_mm: 0)
ctx.dispose
```

**解像度:** P750W / P710BT はラスター幅方向が **180 dpi**、P900W 系は **360 dpi**（C の `libptouch_print` / 各機種ラスター PDF に合わせて画像を用意してください）。

## API の範囲

- 実行ファイル `ptouch-label`（互換: `ptouch-print-png`）… PNG/SVG（`-f`, `-t`, `-p`, `-n`, `-M`, `-S`, `-V`, `-h`, `--template`, `--data`, `--trim-right[=DOTS]`）。`-M` は現在テープ情報（幅 mm・DPI 等）を JSON 出力、`-S` はステータス JSON 出力、`--trim-right` は右側空白列を削減
- `Libptouch::Context` … `open_usb` / `open_usb_vid_pid` / `close` / `dispose`
- `check_raster` / `print_raster` / `png_file_to_raster` / `svg_file_to_raster_fit_current_tape` / `status_bytes` / `status_hash` / `current_media_info`
- `current_media_info` には `print_dpi` / `feed_dpi` / `tape_width_mm` / `printable_height_dots` / `min_feed_mm` などを含む（テープ幅方向は `printable_height_dots`）
- `Libptouch.parse_status(raw)` … 32 バイトを Hash に展開（機種・テープ幅・**テープ種類**・色・**状態（status_kind）**・エラービット・`raw_hex` など）
- C の `libptouch_status_fprint`（`FILE *`）は FFI からはバインドしていません。テキスト出力の代わりに `parse_status` / `status_hash` を使ってください。
