diff --git a/.gitignore b/.gitignore index 3e8abbc..489ead6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ build/ +tmp/ ruby/*.gem ruby/.rubocop_cache/ diff --git a/README.md b/README.md index 469090a..2c5feb1 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,8 @@ ctest --test-dir build --output-on-failure **SVG**(拡張子 `.svg`)の場合は現在装着中テープの印字可能ドット幅に合わせて自動拡大・縮小します(USB 接続が必要)。 `--trim-right[=DOTS]` で右側空白列を削減できます(DOTS 省略時は左余白ドット、取得失敗時は 0)。 任意で `-t`(0–255)で二値化しきい値を指定できます。 +`--cut BITS` でカット系フラグを指定できます(`[auto-cut][half-cut][chain-print]`、例 `010`)。 +指定なしの既定は `011`(オートカットしない / ハーフカットする / つなげて印刷する)です。 **1bit packed ラスター**(行優先、行あたり `ceil(width/8)` バイト × 行数)の場合は `-f` に加え `-w` / `-H` が必須です。 @@ -64,6 +66,12 @@ ctest --test-dir build --output-on-failure # PNG — しきい値を指定 ./build/ptouch-print -n -f label.png -t 160 +# カットフラグを指定(auto=0, half=1, chain=0) +./build/ptouch-print -n -f label.png --cut 010 + +# デバッグ: USB に送る印字データをファイル保存 +./build/ptouch-print -f label.png --debug-dump print_job.bin + # 1bit ラスター — 検証のみ ./build/ptouch-print -n -f sample.raster -w 128 -H 64 @@ -90,6 +98,7 @@ ctest --test-dir build --output-on-failure - `libptouch_get_status` / `libptouch_status_fprint` — ステータス情報リクエスト(ESC i S)の応答 - `libptouch_get_current_media_info` — 現在テープ幅(mm)・印字可能幅(dots)・DPI・最小余白(mm)を取得 - `libptouch_check_raster` — ラスターバッファの検証のみ +- `libptouch_set_debug_dump_path` — USB bulk OUT へ送った印字データをファイル保存(デバッグ用) - `libptouch_png_file_to_raster` / `libptouch_free_raster` — PNG を 1bit ラスターに変換(libpng) - `libptouch_svg_file_to_raster_fit_current_tape` — SVG を現在テープ幅に合わせて 1bit ラスターへ変換(librsvg + cairo、USB 必須) - `libptouch_print_raster` — ラスター印刷(USB・PDF のコマンド列、内部で転置) diff --git a/include/libptouch.h b/include/libptouch.h index 3a71ccf..8fc06e3 100644 --- a/include/libptouch.h +++ b/include/libptouch.h @@ -84,10 +84,33 @@ libptouch_err_t libptouch_open_usb(libptouch_ctx *ctx); void libptouch_close(libptouch_ctx *ctx); +/** + * デバッグ用: USB bulk OUT へ実際に送ったバイト列を path に保存する。 + * 各 @ref libptouch_print_raster ごとにファイルを上書きし直す(ジョブ先頭のチャンクで wb)。 + * path が NULL または空文字で無効化。転送が成功したチャンクのみ追記する。 + */ +void libptouch_set_debug_dump_path(libptouch_ctx *ctx, const char *path); + +/** @ref libptouch_raster_params_t.flags 用: ESC i M bit6 でオートカット ON */ +#define LIBPTOUCH_RASTER_FLAG_AUTO_CUT 0x01u +/** @ref libptouch_raster_params_t.flags 用: ESC i K bit2 でハーフカット ON */ +#define LIBPTOUCH_RASTER_FLAG_HALF_CUT 0x02u +/** @ref libptouch_raster_params_t.flags 用: ChainPrint する(ESC i K bit3=0) */ +#define LIBPTOUCH_RASTER_FLAG_CHAIN_PRINT 0x04u +/** 既定: 011(オートカットしない・ハーフカットする・つなげて印刷する) */ +#define LIBPTOUCH_RASTER_FLAGS_DEFAULT \ + (LIBPTOUCH_RASTER_FLAG_HALF_CUT | LIBPTOUCH_RASTER_FLAG_CHAIN_PRINT) + typedef struct { - uint32_t width_dots; /**< ラスター幅(ドット) */ + uint32_t width_dots; /**< ラスター幅(ドット) */ uint32_t height_dots; /**< ラスター高さ(ドット・走査方向は実装と機種に依存) */ - uint8_t margin_mm; /**< 余白など(機種・仕様に合わせて使用) */ + uint8_t margin_mm; /**< 余白など(機種・仕様に合わせて使用) */ + /** + * LIBPTOUCH_RASTER_FLAG_*。未使用ビットは 0。 + * 既定は @ref LIBPTOUCH_RASTER_FLAGS_DEFAULT(011: オートカットしない・ハーフカットする・つなげて印刷する)。 + */ + uint8_t flags; + uint8_t _reserved[2]; /**< 将来用。0 にすること */ } libptouch_raster_params_t; typedef struct { @@ -135,6 +158,8 @@ libptouch_err_t libptouch_trim_right_blank_columns( * width_dots は装着テープの印刷可能幅以下であること。系統は @ref libptouch_get_current_media_info * の printer_family で判別できる(P900 系は主に 360dpi 相当ドット列、P700 系は 180dpi 相当)。 * @param margin_mm 余白(フィード)量。0 のとき PDF の最小 1mm(14 ドット)相当を送る。 + * @param params->flags bit0=オートカット、bit1=ハーフカット、bit2=チェーンプリントする。 + * 指定なしは @ref LIBPTOUCH_RASTER_FLAGS_DEFAULT(011)。 * 印刷時は内部でドット列を転置する(テープ幅方向とバッファの縦横の対応)。 * @param data 1 行あたり width_dots ビットを ceil(width_dots/8) バイトで並べた連続領域 * @param data_len 期待値: height * row_bytes, row_bytes = (width_dots + 7) / 8 diff --git a/ruby/README.md b/ruby/README.md index 7f16e7f..3a8985b 100644 --- a/ruby/README.md +++ b/ruby/README.md @@ -39,6 +39,8 @@ SVG は現在装着テープの印字可能幅に合わせて自動拡大・縮 また、`--template`(SVG)と `--data`(JSON/YAML)を使うと `data-field` 属性をキーにした差込印刷が可能です。 `data-kb-placeholder="qr"` / `data-kb-placeholder="barcode"` を付けた SVG 要素(`x/y/width/height` 必須)には、対応する `data-field` 値から QR / Code128 バーコードを生成して差し込みできます。 `--trim-right[=DOTS]` を付けると、libptouch 側の共通処理でラベル右側の空白ドット列を削減します。`DOTS` 省略時は左余白ドット数を使い、取得失敗時は `0` にフォールバックします。 +`--cut BITS` は 3bit(`[auto-cut][half-cut][chain-print]`)で、例 `010` のように指定します。既定は `011` です。 +`--debug-dump PATH` を付けると USB へ送る印字データをファイル保存します(1 印刷ごとに上書き)。 開発ツリーからそのまま試す例: @@ -48,6 +50,8 @@ 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 -f ../samples/your.png --cut 010 +bundle exec ruby -I lib exe/ptouch-label -f ../samples/your.png --debug-dump print_job.bin 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 @@ -98,7 +102,7 @@ ctx.dispose ## 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` は右側空白列を削減 +- 実行ファイル `ptouch-label`(互換: `ptouch-print-png`)… PNG/SVG(`-f`, `-t`, `-p`, `-n`, `-M`, `-S`, `-V`, `-h`, `--template`, `--data`, `--trim-right[=DOTS]`, `--cut BITS`, `--debug-dump PATH`)。`-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`) diff --git a/ruby/lib/libptouch.rb b/ruby/lib/libptouch.rb index dcbcede..3d720fe 100644 --- a/ruby/lib/libptouch.rb +++ b/ruby/lib/libptouch.rb @@ -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 diff --git a/ruby/lib/libptouch/binding.rb b/ruby/lib/libptouch/binding.rb index 87f3f09..c510dd8 100644 --- a/ruby/lib/libptouch/binding.rb +++ b/ruby/lib/libptouch/binding.rb @@ -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 diff --git a/ruby/lib/libptouch/cli/label_print.rb b/ruby/lib/libptouch/cli/label_print.rb index cc64f52..0c8c1f7 100644 --- a/ruby/lib/libptouch/cli/label_print.rb +++ b/ruby/lib/libptouch/cli/label_print.rb @@ -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 diff --git a/ruby/lib/libptouch/context.rb b/ruby/lib/libptouch/context.rb index 5dc0eea..0fcde0d 100644 --- a/ruby/lib/libptouch/context.rb +++ b/ruby/lib/libptouch/context.rb @@ -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) diff --git a/src/cli/main.c b/src/cli/main.c index caafcf0..6e62cee 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -27,6 +27,9 @@ static void usage(const char *argv0) " -n, --dry-run 読み込みと check_raster のみ(USB なし)\n" " -v, --verbose 印刷前情報と印刷後ステータスを標準出力\n" " -p, --pid HEX USB 製品 ID(既定: P900W の 0x2085)。例: P750W 0x2062、P710BT 0x20af\n" + " --cut BITS 3bit 指定: [auto-cut][half-cut][chain-print] (例: 010)\n" + " 既定: 011(オートカットしない、ハーフカットする、つなげて印刷する)\n" + " --debug-dump PATH デバッグ: USB に送った印字データをファイルへ保存(1 印刷ごとに上書き)\n" " -S, --status ステータスを表示して終了\n" " -V, --version バージョンを表示して終了\n" " -h, --help このヘルプ\n" @@ -103,6 +106,25 @@ static int read_file(const char *path, uint8_t **out, size_t *out_len) return 0; } +static int parse_cut_bits(const char *s, uint8_t *out_flags) +{ + if (!s || strlen(s) != 3u) + return -1; + for (int i = 0; i < 3; i++) { + if (s[i] != '0' && s[i] != '1') + return -1; + } + uint8_t flags = 0u; + if (s[0] == '1') + flags |= LIBPTOUCH_RASTER_FLAG_AUTO_CUT; + if (s[1] == '1') + flags |= LIBPTOUCH_RASTER_FLAG_HALF_CUT; + if (s[2] == '1') + flags |= LIBPTOUCH_RASTER_FLAG_CHAIN_PRINT; + *out_flags = flags; + return 0; +} + static void verbose_print_pre_print_info(libptouch_ctx *ctx, const libptouch_raster_params_t *params, size_t data_len) @@ -115,6 +137,11 @@ static void verbose_print_pre_print_info(libptouch_ctx *ctx, printf("raster size: %ux%u dots (length x width)\n", (unsigned)params->width_dots, (unsigned)params->height_dots); printf("margin_mm: %u\n", (unsigned)params->margin_mm); + printf("raster flags: 0x%02X (auto-cut %s, half-cut %s, chain-print %s)\n", + (unsigned)params->flags, + (params->flags & LIBPTOUCH_RASTER_FLAG_AUTO_CUT) ? "on" : "off", + (params->flags & LIBPTOUCH_RASTER_FLAG_HALF_CUT) ? "on" : "off", + (params->flags & LIBPTOUCH_RASTER_FLAG_CHAIN_PRINT) ? "on" : "off"); libptouch_media_info_t mi; if (libptouch_get_current_media_info(ctx, &mi) == LIBPTOUCH_OK) { @@ -183,6 +210,8 @@ int main(int argc, char **argv) unsigned trim_right_dots = 0; int has_threshold = 0; int want_status = 0; + uint8_t cut_flags = LIBPTOUCH_RASTER_FLAGS_DEFAULT; + const char *debug_dump_path = NULL; static struct option longopts[] = { { "width", required_argument, NULL, 'w' }, { "height", required_argument, NULL, 'H' }, @@ -195,6 +224,8 @@ int main(int argc, char **argv) { "status", no_argument, NULL, 'S' }, { "version", no_argument, NULL, 'V' }, { "help", no_argument, NULL, 'h' }, + { "cut", required_argument, NULL, 1000 }, + { "debug-dump", required_argument, NULL, 1001 }, { NULL, 0, NULL, 0 }, }; @@ -246,6 +277,16 @@ int main(int argc, char **argv) return 2; } break; + case 1000: + if (parse_cut_bits(optarg, &cut_flags) != 0) { + fprintf(stderr, + "--cut must be 3 bits (e.g. 010: auto/half/chain)\n"); + return 2; + } + break; + case 1001: + debug_dump_path = optarg; + break; case 'S': want_status = 1; break; @@ -329,10 +370,12 @@ int main(int argc, char **argv) fprintf(stderr, "libptouch_create failed\n"); return 1; } + if (debug_dump_path) + libptouch_set_debug_dump_path(ctx, debug_dump_path); uint8_t *data = NULL; size_t data_len = 0; - libptouch_raster_params_t params = { 0, 0, 0 }; + libptouch_raster_params_t params = { 0 }; libptouch_err_t e; int usb_opened = 0; int data_from_lib = 0; @@ -406,7 +449,7 @@ int main(int argc, char **argv) uint8_t *trimmed = NULL; size_t trimmed_len = 0; - libptouch_raster_params_t trimmed_params = { 0, 0, 0 }; + libptouch_raster_params_t trimmed_params = { 0 }; e = libptouch_trim_right_blank_columns( ctx, data, data_len, ¶ms, pad, &trimmed, &trimmed_len, &trimmed_params); @@ -430,6 +473,10 @@ int main(int argc, char **argv) data_from_lib = 1; } + params.flags = cut_flags; + params._reserved[0] = 0u; + params._reserved[1] = 0u; + e = libptouch_check_raster(ctx, data, data_len, ¶ms); if (e != LIBPTOUCH_OK) { fprintf(stderr, "check_raster: %s\n", diff --git a/src/lib/libptouch_core.c b/src/lib/libptouch_core.c index 034c06e..3d21d2b 100644 --- a/src/lib/libptouch_core.c +++ b/src/lib/libptouch_core.c @@ -55,9 +55,29 @@ void libptouch_destroy(libptouch_ctx *ctx) if (!ctx) return; libptouch_close(ctx); + free(ctx->debug_dump_path); free(ctx); } +void libptouch_set_debug_dump_path(libptouch_ctx *ctx, const char *path) +{ + if (!ctx) + return; + free(ctx->debug_dump_path); + ctx->debug_dump_path = NULL; + ctx->debug_dump_truncate_next = 0; + if (!path || !path[0]) + return; + ctx->debug_dump_path = strdup(path); +} + +void ptouch_debug_dump_begin_print_job(libptouch_ctx *ctx) +{ + if (!ctx) + return; + ctx->debug_dump_truncate_next = 1; +} + const char *libptouch_strerror(const libptouch_ctx *ctx) { if (!ctx) diff --git a/src/lib/libptouch_internal.h b/src/lib/libptouch_internal.h index 4c27026..f098677 100644 --- a/src/lib/libptouch_internal.h +++ b/src/lib/libptouch_internal.h @@ -23,8 +23,13 @@ struct libptouch_ctx { uint8_t bulk_out_ep; uint8_t bulk_in_ep; uint16_t usb_pid; /* 0 if USB not open; used to pick 128- vs 560-dot raster */ + char *debug_dump_path; /* strdup; NULL = 印字データのファイル保存なし */ + int debug_dump_truncate_next; /* 次の bulk 書き込みでファイルを切り詰め(ジョブ先頭) */ }; +/** 1 回の libptouch_print_raster ジョブの先頭で呼ぶ(最初の bulk 前) */ +void ptouch_debug_dump_begin_print_job(libptouch_ctx *ctx); + /* ctx に最終エラー(コードとメッセージ)を記録する。公開 API のエラー返却前に使う。 */ void ptouch_set_error(libptouch_ctx *ctx, libptouch_err_t code, const char *msg); /* libusb のエラー番号を人が読めるメッセージにして ptouch_set_error に渡す。 */ diff --git a/src/lib/libptouch_png.c b/src/lib/libptouch_png.c index 4c45d74..24ca8ed 100644 --- a/src/lib/libptouch_png.c +++ b/src/lib/libptouch_png.c @@ -36,9 +36,8 @@ libptouch_err_t libptouch_png_file_to_raster(libptouch_ctx *ctx, const char *pat *out_raster = NULL; *out_raster_bytes = 0; - out_params->width_dots = 0; - out_params->height_dots = 0; - out_params->margin_mm = 0; + memset(out_params, 0, sizeof(*out_params)); + out_params->flags = LIBPTOUCH_RASTER_FLAGS_DEFAULT; FILE *fp = fopen(path, "rb"); if (!fp) { @@ -157,6 +156,7 @@ libptouch_err_t libptouch_png_file_to_raster(libptouch_ctx *ctx, const char *pat out_params->width_dots = (uint32_t)width; out_params->height_dots = (uint32_t)height; out_params->margin_mm = 0; + out_params->flags = LIBPTOUCH_RASTER_FLAGS_DEFAULT; *out_raster = out; *out_raster_bytes = total; ptouch_set_error(ctx, LIBPTOUCH_OK, ""); diff --git a/src/lib/libptouch_print.c b/src/lib/libptouch_print.c index 5fd300c..117b8b3 100644 --- a/src/lib/libptouch_print.c +++ b/src/lib/libptouch_print.c @@ -156,11 +156,14 @@ libptouch_err_t libptouch_print_raster(libptouch_ctx *ctx, pos += sizeof(raster_mode); uint8_t esc_iz[13]; - ptouch_fill_esc_iz(esc_iz, prof, media_kind, media_w, lines); + ptouch_fill_esc_iz(esc_iz, prof, media_w, lines); memcpy(head + pos, esc_iz, sizeof(esc_iz)); pos += sizeof(esc_iz); - static const uint8_t esc_im[] = { 0x1B, 0x69, 0x4D, 0x40 }; + /* ESC i M: bit6 オートカット(reference/印字データ.md)。既定オフ。 */ + uint8_t esc_im_n1 = + (params->flags & LIBPTOUCH_RASTER_FLAG_AUTO_CUT) ? 0x40u : 0x00u; + uint8_t esc_im[] = { 0x1B, 0x69, 0x4D, esc_im_n1 }; memcpy(head + pos, esc_im, sizeof(esc_im)); pos += sizeof(esc_im); @@ -174,7 +177,9 @@ libptouch_err_t libptouch_print_raster(libptouch_ctx *ctx, pos += sizeof(esc_ia); } - uint8_t esc_ik[] = { 0x1B, 0x69, 0x4B, ptouch_esc_ik_value(head_dots) }; + uint8_t esc_ik_n1 = + ptouch_esc_ik_extended_mode(ctx->usb_pid, params->flags); + uint8_t esc_ik[] = { 0x1B, 0x69, 0x4B, esc_ik_n1 }; memcpy(head + pos, esc_ik, sizeof(esc_ik)); pos += sizeof(esc_ik); @@ -190,6 +195,7 @@ libptouch_err_t libptouch_print_raster(libptouch_ctx *ctx, memcpy(head + pos, mode_m, sizeof(mode_m)); pos += sizeof(mode_m); + ptouch_debug_dump_begin_print_job(ctx); v = ptouch_bulk_send_job(ctx, head, pos, "print preamble"); if (v != LIBPTOUCH_OK) { free(transposed); diff --git a/src/lib/libptouch_protocol.c b/src/lib/libptouch_protocol.c index 8072747..c1ef5b8 100644 --- a/src/lib/libptouch_protocol.c +++ b/src/lib/libptouch_protocol.c @@ -13,7 +13,7 @@ void ptouch_fill_gf_header(uint8_t out[3], size_t line_payload_bytes) } void ptouch_fill_esc_iz(uint8_t out[13], const ptouch_printer_profile_t *prof, - uint8_t media_kind, uint8_t media_width, uint32_t raster_lines) + uint8_t media_width, uint32_t raster_lines) { uint8_t page_byte = 0x00u; if (prof && prof->family == LIBPTOUCH_FAMILY_P900) @@ -23,9 +23,9 @@ void ptouch_fill_esc_iz(uint8_t out[13], const ptouch_printer_profile_t *prof, out[1] = 0x69u; out[2] = 0x7Au; /* PI flags: enable media/width/length with quality bit for broad compatibility. */ - out[3] = 0x8Eu; + out[3] = 0x84u; /* Use status media-kind byte directly (e.g., 0x01 laminated, 0x03 non-laminate). */ - out[4] = media_kind; + out[4] = 0x00u; out[5] = media_width; out[6] = 0x00u; out[7] = (uint8_t)(raster_lines & 0xFFu); @@ -36,8 +36,22 @@ void ptouch_fill_esc_iz(uint8_t out[13], const ptouch_printer_profile_t *prof, out[12] = 0x00u; /* fixed */ } -uint8_t ptouch_esc_ik_value(unsigned head_dots) +uint8_t ptouch_esc_ik_extended_mode(uint16_t usb_pid, uint8_t raster_flags) { - /* Preserve legacy 560-dot behaviour (0x0C), 128-dot uses 0x08. */ - return head_dots > 128u ? 0x0Cu : 0x08u; + uint8_t n1 = 0x00u; + int want_half = (raster_flags & LIBPTOUCH_RASTER_FLAG_HALF_CUT) != 0; + int want_chain = (raster_flags & LIBPTOUCH_RASTER_FLAG_CHAIN_PRINT) != 0; + + /* + * reference/印字データ.md: + * - bit2: ハーフカット + * - bit3: ChainPrint しない + */ + if (usb_pid == LIBPTOUCH_USB_PID_PTP710BT) + want_half = 0; /* PT-P710BT はハーフカット非対応 */ + if (want_half) + n1 |= 0x04u; + if (!want_chain) + n1 |= 0x08u; + return n1; } diff --git a/src/lib/libptouch_protocol.h b/src/lib/libptouch_protocol.h index e3f3d72..6b73e42 100644 --- a/src/lib/libptouch_protocol.h +++ b/src/lib/libptouch_protocol.h @@ -13,8 +13,8 @@ void ptouch_fill_gf_header(uint8_t out[3], size_t line_payload_bytes); * P700 は 00h)。prof が NULL のときは 00h。 */ void ptouch_fill_esc_iz(uint8_t out[13], const ptouch_printer_profile_t *prof, - uint8_t media_kind, uint8_t media_width, - uint32_t raster_lines); -uint8_t ptouch_esc_ik_value(unsigned head_dots); + uint8_t media_width, uint32_t raster_lines); +/** ESC i K の n1: flags(オート/ハーフ/チェーン)と機種制約から算出。 */ +uint8_t ptouch_esc_ik_extended_mode(uint16_t usb_pid, uint8_t raster_flags); #endif /* LIBPTOUCH_PROTOCOL_H */ diff --git a/src/lib/libptouch_svg.c b/src/lib/libptouch_svg.c index e92446c..43a70e7 100644 --- a/src/lib/libptouch_svg.c +++ b/src/lib/libptouch_svg.c @@ -16,6 +16,7 @@ #include #include #include +#include libptouch_err_t libptouch_svg_file_to_raster_fit_current_tape( libptouch_ctx *ctx, const char *path, @@ -51,9 +52,8 @@ libptouch_err_t libptouch_svg_file_to_raster_fit_current_tape( *out_raster = NULL; *out_raster_bytes = 0; - out_params->width_dots = 0; - out_params->height_dots = 0; - out_params->margin_mm = 0; + memset(out_params, 0, sizeof(*out_params)); + out_params->flags = LIBPTOUCH_RASTER_FLAGS_DEFAULT; uint8_t st[LIBPTOUCH_STATUS_LENGTH]; libptouch_err_t v = libptouch_get_status(ctx, st); @@ -203,6 +203,7 @@ libptouch_err_t libptouch_svg_file_to_raster_fit_current_tape( out_params->width_dots = out_w; out_params->height_dots = out_h; out_params->margin_mm = 0; + out_params->flags = LIBPTOUCH_RASTER_FLAGS_DEFAULT; *out_raster = out; *out_raster_bytes = total; ptouch_set_error(ctx, LIBPTOUCH_OK, ""); diff --git a/src/lib/libptouch_trim.c b/src/lib/libptouch_trim.c index 7ec254b..7f48441 100644 --- a/src/lib/libptouch_trim.c +++ b/src/lib/libptouch_trim.c @@ -79,6 +79,9 @@ libptouch_err_t libptouch_trim_right_blank_columns( out_params->width_dots = new_width; out_params->height_dots = height; out_params->margin_mm = in_params->margin_mm; + out_params->flags = in_params->flags; + out_params->_reserved[0] = in_params->_reserved[0]; + out_params->_reserved[1] = in_params->_reserved[1]; ptouch_set_error(ctx, LIBPTOUCH_OK, ""); return LIBPTOUCH_OK; } diff --git a/src/lib/libptouch_usb.c b/src/lib/libptouch_usb.c index f3d43bd..21514a2 100644 --- a/src/lib/libptouch_usb.c +++ b/src/lib/libptouch_usb.c @@ -194,5 +194,14 @@ libptouch_err_t ptouch_bulk_send_job(libptouch_ctx *ctx, const uint8_t *buf, ptouch_set_error(ctx, LIBPTOUCH_ERR_USB, msg); return LIBPTOUCH_ERR_USB; } + if (ctx->debug_dump_path && ctx->debug_dump_path[0]) { + FILE *fp = fopen(ctx->debug_dump_path, + ctx->debug_dump_truncate_next ? "wb" : "ab"); + if (fp) { + (void)fwrite(buf, 1, len, fp); + (void)fclose(fp); + } + ctx->debug_dump_truncate_next = 0; + } return LIBPTOUCH_OK; } diff --git a/tests/protocol_regression_test.c b/tests/protocol_regression_test.c index 6228f2e..52fc7da 100644 --- a/tests/protocol_regression_test.c +++ b/tests/protocol_regression_test.c @@ -1,5 +1,7 @@ #include "libptouch_protocol.h" +#include "libptouch.h" + #include #include @@ -38,23 +40,38 @@ int main(void) fail |= expect_int("gf70_n2", gf[2], 0x00); uint8_t iz[13]; - ptouch_fill_esc_iz(iz, &prof_fixture_p700, 0x01u, 0x0Cu, 70u); + ptouch_fill_esc_iz(iz, &prof_fixture_p700, 0x0Cu, 70u); fail |= expect_int("iz_cmd_0", iz[0], 0x1B); fail |= expect_int("iz_cmd_1", iz[1], 0x69); fail |= expect_int("iz_cmd_2", iz[2], 0x7A); - fail |= expect_int("iz_n1_flags", iz[3], 0x8E); - fail |= expect_int("iz_media_kind_passthrough", iz[4], 0x01); + fail |= expect_int("iz_n1_flags", iz[3], 0x84); + fail |= expect_int("iz_media_kind_fixed", iz[4], 0x00); fail |= expect_int("iz_media_width", iz[5], 0x0C); fail |= expect_int("iz_lines_lsb", iz[7], 70); fail |= expect_int("iz_page_control_p700", iz[11], 0x00); fail |= expect_int("iz_last_fixed", iz[12], 0x00); - ptouch_fill_esc_iz(iz, &prof_fixture_p900, 0x01u, 0x0Cu, 70u); + ptouch_fill_esc_iz(iz, &prof_fixture_p900, 0x0Cu, 70u); fail |= expect_int("iz_page_control_p900_single", iz[11], 0x02); - /* ESC i K mode byte: 128-dot vs 560-dot families */ - fail |= expect_int("esc_ik_128", ptouch_esc_ik_value(128u), 0x08); - fail |= expect_int("esc_ik_560", ptouch_esc_ik_value(560u), 0x0C); + /* ESC i K: bit2=ハーフカット、bit3=ChainPrintしない */ + fail |= expect_int( + "esc_ik_p750w_half_chain", + (int)ptouch_esc_ik_extended_mode( + LIBPTOUCH_USB_PID_PTP750W, LIBPTOUCH_RASTER_FLAGS_DEFAULT), + 0x04); + fail |= expect_int( + "esc_ik_p710bt_no_half", + (int)ptouch_esc_ik_extended_mode( + LIBPTOUCH_USB_PID_PTP710BT, LIBPTOUCH_RASTER_FLAGS_DEFAULT), + 0x00); + fail |= expect_int( + "esc_ik_p900w_auto_half_no_chain", + (int)ptouch_esc_ik_extended_mode( + LIBPTOUCH_USB_PID_PTP900W, + LIBPTOUCH_RASTER_FLAG_AUTO_CUT | + LIBPTOUCH_RASTER_FLAG_HALF_CUT), + 0x0C); return fail ? EXIT_FAILURE : EXIT_SUCCESS; }