ruby binding 追加
- FFI gem (libptouch)、exe ptouch-print-png(PNG のみ) - ステータス 32 バイトを Hash に展開(parse_status / status_hash) - CMake: libptouch 共有ライブラリ(ptouch_shared) - RuboCop、gemspec(homepage / source_code_uri) Made-with: Cursor
This commit is contained in:
182
ruby/lib/libptouch/cli/png_print.rb
Normal file
182
ruby/lib/libptouch/cli/png_print.rb
Normal file
@@ -0,0 +1,182 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "json"
|
||||
require "optparse"
|
||||
|
||||
require "libptouch"
|
||||
|
||||
module Libptouch
|
||||
module Cli
|
||||
# PNG のみを扱う 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
|
||||
end
|
||||
|
||||
return usage_error("-f is required (or use --status)") if opts[:file].to_s.empty?
|
||||
|
||||
path = opts[:file]
|
||||
return usage_error("not a PNG file: #{path}") unless png_file?(path)
|
||||
|
||||
run_print(path, opts)
|
||||
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 parse(argv)
|
||||
o = {
|
||||
file: nil,
|
||||
threshold: nil,
|
||||
dry_run: false,
|
||||
status: false,
|
||||
version: false,
|
||||
help: false
|
||||
}
|
||||
parser = OptionParser.new do |p|
|
||||
p.banner = usage_banner
|
||||
p.separator ""
|
||||
p.on("-f", "--file PATH", "入力 PNG ファイル") { |v| o[:file] = v }
|
||||
p.on("-t", "--threshold N", Integer,
|
||||
"二値化しきい値 0–255(既定 #{Libptouch::PNG_DEFAULT_THRESHOLD})") do |v|
|
||||
o[:threshold] = v
|
||||
end
|
||||
p.on("-n", "--dry-run", "読み込みと検証のみ(USB なし)") { o[:dry_run] = true }
|
||||
p.on("-S", "--status", "USB プリンタのステータスを JSON で表示して終了") { o[:status] = true }
|
||||
p.on("-V", "--version", "バージョンを表示して終了") { o[:version] = true }
|
||||
p.on("-h", "--help", "このヘルプ") { o[:help] = true }
|
||||
end
|
||||
parser.parse!(argv)
|
||||
|
||||
unless o[:threshold].nil? || (0..255).cover?(o[:threshold])
|
||||
warn "-t must be 0..255"
|
||||
return nil
|
||||
end
|
||||
|
||||
o
|
||||
end
|
||||
|
||||
def usage_banner
|
||||
<<~BANNER
|
||||
Usage: ptouch-print-png [options]
|
||||
|
||||
PNG のみ対応。幅・高さは画像から取得します(-w/-H はありません)。
|
||||
--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
|
||||
o = {
|
||||
file: nil,
|
||||
threshold: nil,
|
||||
dry_run: false,
|
||||
status: false,
|
||||
version: false,
|
||||
help: false
|
||||
}
|
||||
p = OptionParser.new do |parser|
|
||||
parser.banner = "ptouch-print-png [options]"
|
||||
parser.on("-f", "--file PATH", "入力 PNG ファイル") { |v| o[:file] = v }
|
||||
parser.on("-t", "--threshold N", Integer,
|
||||
"二値化しきい値 0–255(既定 #{Libptouch::PNG_DEFAULT_THRESHOLD})") do |v|
|
||||
o[:threshold] = v
|
||||
end
|
||||
parser.on("-n", "--dry-run", "読み込みと検証のみ(USB なし)") { o[:dry_run] = true }
|
||||
parser.on("-S", "--status", "USB プリンタのステータスを JSON で表示して終了") { o[:status] = true }
|
||||
parser.on("-V", "--version", "バージョンを表示して終了") { o[:version] = true }
|
||||
parser.on("-h", "--help", "このヘルプ") { o[:help] = true }
|
||||
end
|
||||
p.help
|
||||
end
|
||||
|
||||
def run_status
|
||||
ctx = nil
|
||||
begin
|
||||
ctx = Libptouch::Context.new
|
||||
ctx.open_usb
|
||||
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)
|
||||
ctx = nil
|
||||
begin
|
||||
ctx = Libptouch::Context.new
|
||||
threshold = opts[:threshold]
|
||||
data, width, height = if 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, #{width}x#{height} dots"
|
||||
return 0
|
||||
end
|
||||
|
||||
ctx.open_usb
|
||||
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
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user