From 32ab12f66167dadfa498320e538e72196d4d515c Mon Sep 17 00:00:00 2001 From: knb Date: Thu, 16 Apr 2026 14:49:08 +0900 Subject: [PATCH] =?UTF-8?q?ptouch-label=20CLI=E3=82=92=E8=BF=BD=E5=8A=A0?= =?UTF-8?q?=E3=81=97=E3=81=A6=E5=B7=AE=E8=BE=BC=E5=8D=B0=E5=88=B7=E3=82=92?= =?UTF-8?q?=E6=8B=A1=E5=BC=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit コマンド名を機能に合わせて整理し、SVGテンプレート+JSON/YAMLの差込印刷とメディア情報取得を使いやすくする。 Made-with: Cursor --- reference/note.adoc | 0 ruby/README.md | 22 +- ruby/exe/ptouch-label | 6 + ruby/exe/ptouch-print-png | 4 +- ruby/lib/libptouch/cli/label_print.rb | 361 ++++++++++++++++++++++++++ ruby/lib/libptouch/cli/png_print.rb | 249 +----------------- ruby/lib/libptouch/context.rb | 2 +- ruby/libptouch.gemspec | 2 +- samples/README.md | 9 +- samples/merge_data.json | 5 + samples/merge_data.yml | 3 + samples/merge_template.svg | 9 + 12 files changed, 412 insertions(+), 260 deletions(-) create mode 100644 reference/note.adoc create mode 100644 ruby/exe/ptouch-label create mode 100644 ruby/lib/libptouch/cli/label_print.rb create mode 100644 samples/merge_data.json create mode 100644 samples/merge_data.yml create mode 100644 samples/merge_template.svg diff --git a/reference/note.adoc b/reference/note.adoc new file mode 100644 index 0000000..e69de29 diff --git a/ruby/README.md b/ruby/README.md index 3b6da2f..360755f 100644 --- a/ruby/README.md +++ b/ruby/README.md @@ -31,21 +31,25 @@ export LIBPTOUCH_LIB=/usr/local/lib/libptouch.so (`cmake --install` で共有ライブラリをインストールした場合は、通常は `libptouch` 名でローダが解決します。) -## コマンド `ptouch-print-png`(PNG/SVG) +## コマンド `ptouch-label`(PNG/SVG) -C の `ptouch-print` と同様の流れで、**PNG/SVG 入力**(`-w`/`-H` や 1bit ラスターは扱いません)を扱います。`gem install` 後は PATH に `ptouch-print-png` が入ります。 +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` 属性をキーにした差込印刷が可能です。 開発ツリーからそのまま試す例: ```bash -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.svg -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 +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 --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 ``` ## 使用例 @@ -92,9 +96,9 @@ ctx.dispose ## API の範囲 -- 実行ファイル `ptouch-print-png` … PNG/SVG(`-f`, `-t`, `-p`, `-n`, `-S`, `-V`, `-h`)。ステータスは JSON(`status_bytes` を `parse_status` したもの、`raw_bytes` 除く) +- 実行ファイル `ptouch-label`(互換: `ptouch-print-png`)… PNG/SVG(`-f`, `-t`, `-p`, `-n`, `-M`, `-S`, `-V`, `-h`, `--template`, `--data`)。`-M` は現在テープ情報(幅 mm・DPI 等)を JSON 出力、`-S` はステータス JSON 出力 - `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` / `min_feed_mm` などを含む +- `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` を使ってください。 diff --git a/ruby/exe/ptouch-label b/ruby/exe/ptouch-label new file mode 100644 index 0000000..c5258af --- /dev/null +++ b/ruby/exe/ptouch-label @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "libptouch/cli/label_print" + +exit Libptouch::Cli::LabelPrint.run(ARGV) diff --git a/ruby/exe/ptouch-print-png b/ruby/exe/ptouch-print-png index 7fe6462..c5258af 100755 --- a/ruby/exe/ptouch-print-png +++ b/ruby/exe/ptouch-print-png @@ -1,6 +1,6 @@ #!/usr/bin/env ruby # frozen_string_literal: true -require "libptouch/cli/png_print" +require "libptouch/cli/label_print" -exit Libptouch::Cli::PngPrint.run(ARGV) +exit Libptouch::Cli::LabelPrint.run(ARGV) diff --git a/ruby/lib/libptouch/cli/label_print.rb b/ruby/lib/libptouch/cli/label_print.rb new file mode 100644 index 0000000..c89ff5f --- /dev/null +++ b/ruby/lib/libptouch/cli/label_print.rb @@ -0,0 +1,361 @@ +# frozen_string_literal: true + +require "json" +require "optparse" +require "rexml/document" +require "tempfile" +require "yaml" + +require "libptouch" + +module Libptouch + module Cli + # PNG/SVG を扱う ptouch-print 相当の CLI(1bit ラスター経路なし)。 + module LabelPrint + module_function + + def run(argv) + opts = parse(argv) + return 2 if opts.nil? + + return run_version if opts[:version] + return run_help if opts[:help] + + return run_media_info(opts) if opts[:media_info] + + if opts[:status] + warn_unused_file_options(opts) + return run_status(opts) + end + + if opts[:template] || opts[:data] + return usage_error("--template and --data must be used together") if opts[:template].to_s.empty? || opts[:data].to_s.empty? + return usage_error("-f and --template/--data cannot be used together") unless opts[:file].to_s.empty? + return run_template_print(opts) + end + + return usage_error("-f is required (or use --template/--data, or --status)") if opts[:file].to_s.empty? + + path = opts[:file] + kind = image_kind(path) + return usage_error("not a PNG/SVG file: #{path}") if kind.nil? + + run_print(path, opts, kind) + end + + def png_file?(path) + return true if path.downcase.end_with?(".png") + + File.open(path, "rb") do |f| + sig = f.read(8) + sig == "\x89PNG\r\n\x1a\n".b + end + rescue Errno::ENOENT, Errno::EACCES => e + warn "open #{path}: #{e.message}" + false + end + + def svg_file?(path) + path.downcase.end_with?(".svg") + end + + def image_kind(path) + return :png if png_file?(path) + return :svg if svg_file?(path) + + nil + end + + def parse(argv) + 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, + template: nil, + data: nil, + threshold: nil, + usb_pid: nil, + usb_pid_invalid: false, + dry_run: false, + media_info: false, + status: false, + version: false, + help: false + } + 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.separator "" + p.on("-f", "--file PATH", "入力 PNG/SVG ファイル") { |v| opts_hash[:file] = v } + p.on("--template PATH", "差込用 SVG テンプレート") { |v| opts_hash[:template] = v } + p.on("--data PATH", "差込データ JSON/YAML ファイル") { |v| opts_hash[:data] = v } + p.on("-t", "--threshold N", Integer, + "二値化しきい値 0–255(既定 #{Libptouch::PNG_DEFAULT_THRESHOLD}、PNG/SVG)") do |v| + opts_hash[:threshold] = v + end + p.on("-p", "--pid PID", pid_option_description) do |v| + apply_usb_pid_option(opts_hash, v) + end + p.on("-n", "--dry-run", "読み込みと検証のみ(USB なし)") { opts_hash[:dry_run] = true } + p.on("-M", "--media-info", "現在テープの幅(mm)・DPI・最小余白(mm)を JSON で表示して終了") do + opts_hash[:media_info] = true + end + p.on("-S", "--status", "USB プリンタのステータスを JSON で表示して終了") do + opts_hash[:status] = true + end + p.on("-V", "--version", "バージョンを表示して終了") { opts_hash[:version] = true } + p.on("-h", "--help", "このヘルプ") { opts_hash[:help] = true } + end + end + + def usage_banner + <<~BANNER + Usage: ptouch-label [options] + + PNG/SVG 対応。幅・高さは画像から取得します(-w/-H はありません)。 + または --template/--data で SVG 差込印刷ができます。 + SVG は現在テープ幅に合わせて自動拡大・縮小します(USB 接続必須)。 + --status / --media-info のときは -f は不要です。 + BANNER + end + + def warn_unused_file_options(opts) + return unless opts[:file] || opts[:template] || opts[:data] || opts[:dry_run] || !opts[:threshold].nil? + + warn "warning: options other than --status are ignored" + end + + def run_version + puts "ptouch-label #{Libptouch::VERSION}" + 0 + end + + def run_help + puts usage_banner + puts "" + puts parser_help_text + 0 + end + + def parser_help_text + opts_hash = default_cli_opts + p = OptionParser.new do |parser| + parser.banner = "ptouch-label [options]" + parser.on("-f", "--file PATH", "入力 PNG/SVG ファイル") { |v| opts_hash[:file] = v } + parser.on("--template PATH", "差込用 SVG テンプレート") { |v| opts_hash[:template] = v } + parser.on("--data PATH", "差込データ JSON/YAML ファイル") { |v| opts_hash[:data] = v } + parser.on("-t", "--threshold N", Integer, + "二値化しきい値 0–255(既定 #{Libptouch::PNG_DEFAULT_THRESHOLD}、PNG/SVG)") do |v| + opts_hash[:threshold] = v + end + parser.on("-p", "--pid PID", pid_option_description) do |v| + apply_usb_pid_option(opts_hash, v) + end + parser.on("-n", "--dry-run", "読み込みと検証のみ(USB なし)") { opts_hash[:dry_run] = true } + parser.on("-M", "--media-info", "現在テープの幅(mm)・DPI・最小余白(mm)を JSON で表示して終了") do + opts_hash[:media_info] = true + end + 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 + p.help + end + + 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_template_print(opts) + svg_text = render_svg_template(opts[:template], load_merge_data(opts[:data])) + Tempfile.create(["ptouch-merge-", ".svg"]) do |tmp| + tmp.binmode + tmp.write(svg_text) + tmp.flush + run_print(tmp.path, opts, :svg) + end + rescue REXML::ParseException => e + warn "template parse error: #{e.message}" + 1 + rescue Errno::ENOENT, Errno::EACCES => e + warn e.message + 1 + rescue JSON::ParserError, Psych::SyntaxError => e + warn "data parse error: #{e.message}" + 1 + rescue ArgumentError => e + warn "data error: #{e.message}" + 1 + end + + def load_merge_data(path) + text = File.read(path, encoding: "UTF-8") + ext = File.extname(path).downcase + parsed = if ext == ".json" + JSON.parse(text) + else + YAML.safe_load(text, permitted_classes: [], aliases: false) + end + unless parsed.is_a?(Hash) + raise ArgumentError, "data must be a key-value object/hash" + end + + parsed.transform_keys(&:to_s) + end + + def render_svg_template(path, data) + xml = File.read(path, encoding: "UTF-8") + doc = REXML::Document.new(xml) + doc.elements.each("//text[@data-field]") do |el| + # If descendants also have data-field (e.g. tspan placeholders), + # keep node structure and let element-level replacements handle them. + next if el.elements[".//*[@data-field]"] + + key = el.attributes["data-field"].to_s + next unless data.key?(key) + + replace_text_element_content(el, data[key].to_s) + end + doc.elements.each("//tspan[@data-field]") do |el| + key = el.attributes["data-field"].to_s + next unless data.key?(key) + + replace_text_element_content(el, data[key].to_s) + end + out = +"" + formatter = REXML::Formatters::Default.new + formatter.write(doc, out) + out + end + + def replace_text_element_content(text_element, value) + # Remove all child nodes first so mixed content (, text nodes, etc.) + # gets replaced consistently by merge data. + text_element.children.to_a.each { |child| text_element.delete(child) } + text_element.add(REXML::Text.new(value, true)) + end + + def run_status(opts) + ctx = nil + begin + ctx = Libptouch::Context.new + open_usb_for_opts(ctx, opts) + h = Libptouch.parse_status(ctx.status_bytes) + h.delete(:raw_bytes) + puts JSON.pretty_generate(h) + 0 + rescue Libptouch::Error => e + warn "get_status: #{e.message}" + 1 + ensure + ctx&.dispose + end + end + + def run_media_info(opts) + warn_unused_file_options(opts) + ctx = nil + begin + ctx = Libptouch::Context.new + open_usb_for_opts(ctx, opts) + puts JSON.pretty_generate(ctx.current_media_info) + 0 + rescue Libptouch::Error => e + warn "media_info: #{e.message}" + 1 + ensure + ctx&.dispose + end + end + + def run_print(path, opts, kind) + ctx = nil + begin + ctx = Libptouch::Context.new + threshold = opts[:threshold] + data, width, height = if kind == :svg + open_usb_for_opts(ctx, opts) + if threshold.nil? + ctx.svg_file_to_raster_fit_current_tape(path) + else + ctx.svg_file_to_raster_fit_current_tape(path, threshold: threshold) + end + elsif threshold.nil? + ctx.png_file_to_raster(path) + else + ctx.png_file_to_raster(path, threshold: threshold) + end + + ctx.check_raster(data, width_dots: width, height_dots: height) + + if opts[:dry_run] + puts "dry-run OK: #{data.bytesize} bytes, src #{width}x#{height} dots (print lengthxwidth #{width}x#{height})" + return 0 + end + + open_usb_for_opts(ctx, opts) if kind == :png + ctx.print_raster(data, width_dots: width, height_dots: height) + 0 + rescue Libptouch::Error => e + warn e.message + 1 + ensure + ctx&.dispose + end + end + + def usage_error(msg) + warn msg + warn "(try ptouch-label --help)" + 2 + end + end + end +end diff --git a/ruby/lib/libptouch/cli/png_print.rb b/ruby/lib/libptouch/cli/png_print.rb index 2f2fc64..913fb30 100644 --- a/ruby/lib/libptouch/cli/png_print.rb +++ b/ruby/lib/libptouch/cli/png_print.rb @@ -1,251 +1,8 @@ -# frozen_string_literal: true - -require "json" -require "optparse" - -require "libptouch" +# Backward-compatibility shim. +require "libptouch/cli/label_print" module Libptouch module Cli - # PNG/SVG を扱う ptouch-print 相当の CLI(1bit ラスター経路なし)。 - module PngPrint - module_function - - def run(argv) - opts = parse(argv) - return 2 if opts.nil? - - return run_version if opts[:version] - return run_help if opts[:help] - - if opts[:status] - warn_unused_file_options(opts) - return run_status(opts) - end - - return usage_error("-f is required (or use --status)") if opts[:file].to_s.empty? - - path = opts[:file] - kind = image_kind(path) - return usage_error("not a PNG/SVG file: #{path}") if kind.nil? - - run_print(path, opts, kind) - end - - def png_file?(path) - return true if path.downcase.end_with?(".png") - - File.open(path, "rb") do |f| - sig = f.read(8) - sig == "\x89PNG\r\n\x1a\n".b - end - rescue Errno::ENOENT, Errno::EACCES => e - warn "open #{path}: #{e.message}" - false - end - - def svg_file?(path) - path.downcase.end_with?(".svg") - end - - def image_kind(path) - return :png if png_file?(path) - return :svg if svg_file?(path) - - nil - end - - def parse(argv) - 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, - threshold: nil, - usb_pid: nil, - usb_pid_invalid: false, - dry_run: false, - status: false, - version: false, - help: false - } - 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.separator "" - p.on("-f", "--file PATH", "入力 PNG/SVG ファイル") { |v| opts_hash[:file] = v } - p.on("-t", "--threshold N", Integer, - "二値化しきい値 0–255(既定 #{Libptouch::PNG_DEFAULT_THRESHOLD}、PNG/SVG)") do |v| - opts_hash[:threshold] = v - end - p.on("-p", "--pid PID", pid_option_description) do |v| - apply_usb_pid_option(opts_hash, v) - end - p.on("-n", "--dry-run", "読み込みと検証のみ(USB なし)") { opts_hash[:dry_run] = true } - p.on("-S", "--status", "USB プリンタのステータスを JSON で表示して終了") do - opts_hash[:status] = true - end - p.on("-V", "--version", "バージョンを表示して終了") { opts_hash[:version] = true } - p.on("-h", "--help", "このヘルプ") { opts_hash[:help] = true } - end - end - - def usage_banner - <<~BANNER - Usage: ptouch-print-png [options] - - PNG/SVG 対応。幅・高さは画像から取得します(-w/-H はありません)。 - SVG は現在テープ幅に合わせて自動拡大・縮小します(USB 接続必須)。 - --status のときは -f は不要です。 - BANNER - end - - def warn_unused_file_options(opts) - return unless opts[:file] || opts[:dry_run] || !opts[:threshold].nil? - - warn "warning: options other than --status are ignored" - end - - def run_version - puts "ptouch-print-png #{Libptouch::VERSION}" - 0 - end - - def run_help - puts usage_banner - puts "" - puts parser_help_text - 0 - end - - def parser_help_text - opts_hash = default_cli_opts - p = OptionParser.new do |parser| - parser.banner = "ptouch-print-png [options]" - parser.on("-f", "--file PATH", "入力 PNG/SVG ファイル") { |v| opts_hash[:file] = v } - parser.on("-t", "--threshold N", Integer, - "二値化しきい値 0–255(既定 #{Libptouch::PNG_DEFAULT_THRESHOLD}、PNG/SVG)") do |v| - opts_hash[:threshold] = v - end - parser.on("-p", "--pid PID", pid_option_description) do |v| - apply_usb_pid_option(opts_hash, v) - end - 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 - p.help - end - - 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 - begin - ctx = Libptouch::Context.new - open_usb_for_opts(ctx, opts) - h = Libptouch.parse_status(ctx.status_bytes) - h.delete(:raw_bytes) - puts JSON.pretty_generate(h) - 0 - rescue Libptouch::Error => e - warn "get_status: #{e.message}" - 1 - ensure - ctx&.dispose - end - end - - def run_print(path, opts, kind) - ctx = nil - begin - ctx = Libptouch::Context.new - threshold = opts[:threshold] - data, width, height = if kind == :svg - open_usb_for_opts(ctx, opts) - if threshold.nil? - ctx.svg_file_to_raster_fit_current_tape(path) - else - ctx.svg_file_to_raster_fit_current_tape(path, threshold: threshold) - end - elsif threshold.nil? - ctx.png_file_to_raster(path) - else - ctx.png_file_to_raster(path, threshold: threshold) - end - - ctx.check_raster(data, width_dots: width, height_dots: height) - - if opts[:dry_run] - puts "dry-run OK: #{data.bytesize} bytes, src #{width}x#{height} dots (print lengthxwidth #{width}x#{height})" - return 0 - end - - open_usb_for_opts(ctx, opts) if kind == :png - ctx.print_raster(data, width_dots: width, height_dots: height) - 0 - rescue Libptouch::Error => e - warn e.message - 1 - ensure - ctx&.dispose - end - end - - def usage_error(msg) - warn msg - warn "(try ptouch-print-png --help)" - 2 - end - end + PngPrint = LabelPrint end end diff --git a/ruby/lib/libptouch/context.rb b/ruby/lib/libptouch/context.rb index 463d611..dc6e246 100644 --- a/ruby/lib/libptouch/context.rb +++ b/ruby/lib/libptouch/context.rb @@ -134,7 +134,7 @@ module Libptouch print_dpi: info[:print_dpi], feed_dpi: info[:feed_dpi], tape_width_mm: info[:tape_width_mm], - printable_dots: info[:printable_dots], + printable_height_dots: info[:printable_dots], left_margin_dots: info[:left_margin_dots], right_margin_dots: info[:right_margin_dots], min_feed_dots: info[:min_feed_dots], diff --git a/ruby/libptouch.gemspec b/ruby/libptouch.gemspec index 2296f1a..fd5f35a 100644 --- a/ruby/libptouch.gemspec +++ b/ruby/libptouch.gemspec @@ -25,7 +25,7 @@ Gem::Specification.new do |spec| spec.files = Dir.chdir(__dir__) { Dir["lib/**/*.rb", "exe/*", "README.md"] } spec.bindir = "exe" - spec.executables = ["ptouch-print-png"] + spec.executables = ["ptouch-label", "ptouch-print-png"] spec.require_paths = ["lib"] spec.add_dependency "ffi", "~> 1.15" diff --git a/samples/README.md b/samples/README.md index 22635c0..8ad2b90 100644 --- a/samples/README.md +++ b/samples/README.md @@ -1,9 +1,16 @@ # samples -試験・デモ用のサンプル画像(PNG など)を置くディレクトリです。リポジトリに含める場合はライセンス・著作権に注意してください。 +試験・デモ用のサンプル画像(PNG/SVG)や差込印刷データ(JSON/YAML)を置くディレクトリです。リポジトリに含める場合はライセンス・著作権に注意してください。 例(ドライラン): ```bash ./build/ptouch-print -n -f samples/your.png ``` + +差込印刷の例(Ruby CLI): + +```bash +ruby -I ruby/lib ruby/exe/ptouch-label -n --template samples/merge_template.svg --data samples/merge_data.yml +ruby -I ruby/lib ruby/exe/ptouch-label -n --template samples/merge_template.svg --data samples/merge_data.json +``` diff --git a/samples/merge_data.json b/samples/merge_data.json new file mode 100644 index 0000000..2ba76f5 --- /dev/null +++ b/samples/merge_data.json @@ -0,0 +1,5 @@ +{ + "title": "出荷ラベル", + "left": "品番 ABC-123", + "right": "数量 24" +} diff --git a/samples/merge_data.yml b/samples/merge_data.yml new file mode 100644 index 0000000..44042fa --- /dev/null +++ b/samples/merge_data.yml @@ -0,0 +1,3 @@ +title: "出荷ラベル" +left: "品番 ABC-123" +right: "数量 24" diff --git a/samples/merge_template.svg b/samples/merge_template.svg new file mode 100644 index 0000000..09dbe64 --- /dev/null +++ b/samples/merge_template.svg @@ -0,0 +1,9 @@ + + + TITLE + + LEFT + / + RIGHT + +