add cut bitmask option and debug dump support

Replace auto-cut toggle with --cut bit flags (default 011), wire flags through C/Ruby APIs, and document the new cut/debug-dump behavior in both READMEs.

Made-with: Cursor
This commit is contained in:
knb
2026-04-20 04:22:27 +09:00
parent bfd6adda42
commit e10a430f9e
19 changed files with 255 additions and 38 deletions

View File

@@ -32,4 +32,9 @@ module Libptouch
FAMILY_UNKNOWN = 0
FAMILY_P700 = 1
FAMILY_P900 = 2
RASTER_FLAG_AUTO_CUT = 0x01
RASTER_FLAG_HALF_CUT = 0x02
RASTER_FLAG_CHAIN_PRINT = 0x04
RASTER_FLAGS_DEFAULT = RASTER_FLAG_HALF_CUT | RASTER_FLAG_CHAIN_PRINT
end

View File

@@ -25,7 +25,9 @@ module Libptouch
layout :width_dots, :uint32,
:height_dots, :uint32,
:margin_mm, :uint8,
:_pad, [:uint8, 3]
:flags, :uint8,
:reserved0, :uint8,
:reserved1, :uint8
end
class MediaInfo < FFI::Struct
@@ -52,6 +54,7 @@ module Libptouch
end
attach_function :libptouch_create, [], :pointer
attach_function :libptouch_set_debug_dump_path, %i[pointer string], :void
attach_function :libptouch_printer_family_label, [:uint32], :string
attach_function :libptouch_destroy, [:pointer], :void
attach_function :libptouch_strerror, [:pointer], :string

View File

@@ -76,8 +76,10 @@ module Libptouch
return nil unless threshold_option_ok?(opts_hash)
return nil unless trim_right_option_ok?(opts_hash)
return nil unless usb_pid_option_ok?(opts_hash)
return nil if opts_hash[:cut_invalid]
opts_hash.delete(:usb_pid_invalid)
opts_hash.delete(:cut_invalid)
opts_hash
end
@@ -94,7 +96,9 @@ module Libptouch
media_info: false,
status: false,
version: false,
help: false
help: false,
cut_flags: Libptouch::RASTER_FLAGS_DEFAULT,
debug_dump: nil
}
end
@@ -138,6 +142,19 @@ module Libptouch
false
end
def apply_cut_option(opts_hash, bits)
unless bits.is_a?(String) && bits.match?(/\A[01]{3}\z/)
warn "--cut must be 3 bits (e.g. 010: auto/half/chain)"
opts_hash[:cut_invalid] = true
return
end
flags = 0
flags |= Libptouch::RASTER_FLAG_AUTO_CUT if bits[0] == "1"
flags |= Libptouch::RASTER_FLAG_HALF_CUT if bits[1] == "1"
flags |= Libptouch::RASTER_FLAG_CHAIN_PRINT if bits[2] == "1"
opts_hash[:cut_flags] = flags
end
def build_cli_parser(opts_hash)
OptionParser.new do |p|
p.banner = usage_banner
@@ -152,6 +169,12 @@ module Libptouch
p.on("-p", "--pid PID", pid_option_description) do |v|
apply_usb_pid_option(opts_hash, v)
end
p.on("--cut BITS", "3bit: [auto][half][chain]。既定 011") do |v|
apply_cut_option(opts_hash, v)
end
p.on("--debug-dump PATH", "デバッグ: 印字バイト列を PATH に保存1 印刷ごとに上書き)") do |v|
opts_hash[:debug_dump] = v
end
p.on("-n", "--dry-run", "読み込みと検証のみUSB なし)") { opts_hash[:dry_run] = true }
p.on("--trim-right[=DOTS]", Integer,
"右側空白を削減。DOTS省略時は左余白失敗時 0") do |v|
@@ -212,6 +235,12 @@ module Libptouch
parser.on("-p", "--pid PID", pid_option_description) do |v|
apply_usb_pid_option(opts_hash, v)
end
parser.on("--cut BITS", "3bit: [auto][half][chain]。既定 011") do |v|
apply_cut_option(opts_hash, v)
end
parser.on("--debug-dump PATH", "印字バイト列を PATH に保存") do |v|
opts_hash[:debug_dump] = v
end
parser.on("-n", "--dry-run", "読み込みと検証のみUSB なし)") { opts_hash[:dry_run] = true }
parser.on("--trim-right[=DOTS]", Integer,
"右側空白を削減。DOTS省略時は左余白失敗時 0") do |v|
@@ -486,6 +515,7 @@ module Libptouch
ctx = nil
begin
ctx = Libptouch::Context.new
ctx.debug_dump_path = opts[:debug_dump] if opts[:debug_dump]
usb_opened = false
threshold = opts[:threshold]
data, width, height = if kind == :svg
@@ -508,11 +538,13 @@ module Libptouch
data,
width_dots: width,
height_dots: height,
right_padding_dots: trim_pad
right_padding_dots: trim_pad,
cut_flags: opts[:cut_flags]
)
end
ctx.check_raster(data, width_dots: width, height_dots: height)
ctx.check_raster(data, width_dots: width, height_dots: height,
cut_flags: opts[:cut_flags])
if opts[:dry_run]
puts "dry-run OK: #{data.bytesize} bytes, src #{width}x#{height} dots (print lengthxwidth #{width}x#{height})"
@@ -520,7 +552,8 @@ module Libptouch
end
open_usb_for_opts(ctx, opts) if kind == :png && !usb_opened
ctx.print_raster(data, width_dots: width, height_dots: height)
ctx.print_raster(data, width_dots: width, height_dots: height,
cut_flags: opts[:cut_flags])
0
rescue Libptouch::Error => e
warn e.message

View File

@@ -36,6 +36,11 @@ module Libptouch
self
end
def debug_dump_path=(path)
Binding.libptouch_set_debug_dump_path(@native, path.nil? || path.to_s.empty? ? nil : path.to_s)
self
end
def close
Binding.libptouch_close(@native) if @native && !@native.null?
self
@@ -47,11 +52,14 @@ module Libptouch
@native = nil
end
def check_raster(data, width_dots:, height_dots:, margin_mm: 0)
def check_raster(data, width_dots:, height_dots:, margin_mm: 0, cut_flags: RASTER_FLAGS_DEFAULT)
params = Binding::RasterParams.new
params[:width_dots] = width_dots
params[:height_dots] = height_dots
params[:margin_mm] = margin_mm
params[:flags] = cut_flags
params[:reserved0] = 0
params[:reserved1] = 0
buf = FFI::MemoryPointer.new(:uint8, data.bytesize)
buf.put_bytes(0, data)
raise_on_error(Binding.libptouch_check_raster(@native, buf, data.bytesize,
@@ -59,11 +67,14 @@ module Libptouch
self
end
def print_raster(data, width_dots:, height_dots:, margin_mm: 0)
def print_raster(data, width_dots:, height_dots:, margin_mm: 0, cut_flags: RASTER_FLAGS_DEFAULT)
params = Binding::RasterParams.new
params[:width_dots] = width_dots
params[:height_dots] = height_dots
params[:margin_mm] = margin_mm
params[:flags] = cut_flags
params[:reserved0] = 0
params[:reserved1] = 0
buf = FFI::MemoryPointer.new(:uint8, data.bytesize)
buf.put_bytes(0, data)
raise_on_error(Binding.libptouch_print_raster(@native, buf, data.bytesize,
@@ -115,11 +126,15 @@ module Libptouch
[bytes, out_params[:width_dots], out_params[:height_dots]]
end
def trim_right_blank_columns(data, width_dots:, height_dots:, margin_mm: 0, right_padding_dots: 0)
def trim_right_blank_columns(data, width_dots:, height_dots:, margin_mm: 0,
right_padding_dots: 0, cut_flags: RASTER_FLAGS_DEFAULT)
in_params = Binding::RasterParams.new
in_params[:width_dots] = width_dots
in_params[:height_dots] = height_dots
in_params[:margin_mm] = margin_mm
in_params[:flags] = cut_flags
in_params[:reserved0] = 0
in_params[:reserved1] = 0
in_buf = FFI::MemoryPointer.new(:uint8, data.bytesize)
in_buf.put_bytes(0, data)
out_pp = FFI::MemoryPointer.new(:pointer)