ptouch-label CLIを追加して差込印刷を拡張
コマンド名を機能に合わせて整理し、SVGテンプレート+JSON/YAMLの差込印刷とメディア情報取得を使いやすくする。 Made-with: Cursor
This commit is contained in:
361
ruby/lib/libptouch/cli/label_print.rb
Normal file
361
ruby/lib/libptouch/cli/label_print.rb
Normal file
@@ -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 (<tspan>, 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
|
||||
@@ -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
|
||||
|
||||
@@ -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],
|
||||
|
||||
Reference in New Issue
Block a user