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

@@ -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, &params, 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, &params);
if (e != LIBPTOUCH_OK) {
fprintf(stderr, "check_raster: %s\n",

View File

@@ -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)

View File

@@ -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 に渡す。 */

View File

@@ -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, "");

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -16,6 +16,7 @@
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
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, "");

View File

@@ -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;
}

View File

@@ -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;
}