1st version
This commit is contained in:
292
src/cli/main.c
Normal file
292
src/cli/main.c
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* ptouch-print — CLI for libptouch
|
||||
*
|
||||
* Author: knb
|
||||
* Email: knb@artif.org
|
||||
*/
|
||||
|
||||
#include "libptouch.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
static void usage(const char *argv0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s [options]\n"
|
||||
" -f, --file PATH 入力ファイル\n"
|
||||
" -w, --width DOTS 1bit ラスター時: 幅(ドット)\n"
|
||||
" -H, --height DOTS 1bit ラスター時: 高さ(ドット)\n"
|
||||
" -t, --threshold N PNG 二値化しきい値 0–255(既定 %u、PNG のみ)\n"
|
||||
" -n, --dry-run 読み込みと check_raster のみ(USB なし)\n"
|
||||
" -S, --status USB 接続プリンタのステータス(テープ種・幅・色等)を表示して終了\n"
|
||||
" -V, --version バージョンを表示して終了\n"
|
||||
" -h, --help このヘルプ\n"
|
||||
"\n"
|
||||
"PNG の場合は幅・高さはファイルから取得(-w/-H 不要)。\n"
|
||||
"1bit packed ラスター(行優先)の場合は -f -w -H が必須。\n"
|
||||
"--status のときは -f は不要(他オプションは無視されます)。\n",
|
||||
argv0, (unsigned)LIBPTOUCH_PNG_DEFAULT_THRESHOLD);
|
||||
}
|
||||
|
||||
/** パスが .png で終わる、または先頭 8 バイトが PNG シグネチャ */
|
||||
static int input_is_png(const char *path)
|
||||
{
|
||||
const char *dot = strrchr(path, '.');
|
||||
if (dot && strcasecmp(dot, ".png") == 0)
|
||||
return 1;
|
||||
|
||||
FILE *fp = fopen(path, "rb");
|
||||
if (!fp)
|
||||
return 0;
|
||||
unsigned char sig[8];
|
||||
size_t n = fread(sig, 1, sizeof(sig), fp);
|
||||
fclose(fp);
|
||||
if (n != sizeof(sig))
|
||||
return 0;
|
||||
static const unsigned char png_magic[8] = { 137, 80, 78, 71,
|
||||
13, 10, 26, 10 };
|
||||
return memcmp(sig, png_magic, sizeof(png_magic)) == 0;
|
||||
}
|
||||
|
||||
static int read_file(const char *path, uint8_t **out, size_t *out_len)
|
||||
{
|
||||
FILE *fp = fopen(path, "rb");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "open %s: %s\n", path, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (fseek(fp, 0, SEEK_END) != 0) {
|
||||
fprintf(stderr, "fseek: %s\n", strerror(errno));
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
long sz = ftell(fp);
|
||||
if (sz < 0) {
|
||||
fprintf(stderr, "ftell: %s\n", strerror(errno));
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
rewind(fp);
|
||||
uint8_t *buf = malloc((size_t)sz);
|
||||
if (!buf) {
|
||||
fprintf(stderr, "malloc failed\n");
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
size_t n = fread(buf, 1, (size_t)sz, fp);
|
||||
fclose(fp);
|
||||
if (n != (size_t)sz) {
|
||||
fprintf(stderr, "short read\n");
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
*out = buf;
|
||||
*out_len = n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *file = NULL;
|
||||
unsigned width = 0, height = 0;
|
||||
unsigned threshold = LIBPTOUCH_PNG_DEFAULT_THRESHOLD;
|
||||
int dry_run = 0;
|
||||
int has_threshold = 0;
|
||||
int want_status = 0;
|
||||
static struct option longopts[] = {
|
||||
{ "width", required_argument, NULL, 'w' },
|
||||
{ "height", required_argument, NULL, 'H' },
|
||||
{ "file", required_argument, NULL, 'f' },
|
||||
{ "threshold", required_argument, NULL, 't' },
|
||||
{ "dry-run", no_argument, NULL, 'n' },
|
||||
{ "status", no_argument, NULL, 'S' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ NULL, 0, NULL, 0 },
|
||||
};
|
||||
|
||||
int c;
|
||||
while ((c = getopt_long(argc, argv, "w:H:f:t:nhSV", longopts, NULL)) !=
|
||||
-1) {
|
||||
switch (c) {
|
||||
case 'w':
|
||||
width = (unsigned)strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
case 'H':
|
||||
height = (unsigned)strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
case 'f':
|
||||
file = optarg;
|
||||
break;
|
||||
case 't':
|
||||
threshold = (unsigned)strtoul(optarg, NULL, 10);
|
||||
if (threshold > 255u) {
|
||||
fprintf(stderr, "-t must be 0..255\n");
|
||||
return 2;
|
||||
}
|
||||
has_threshold = 1;
|
||||
break;
|
||||
case 'n':
|
||||
dry_run = 1;
|
||||
break;
|
||||
case 'S':
|
||||
want_status = 1;
|
||||
break;
|
||||
case 'V':
|
||||
printf("ptouch-print %s\n", LIBPTOUCH_VERSION_STRING);
|
||||
return 0;
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
return 0;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (want_status) {
|
||||
if (file || width || height || dry_run || has_threshold)
|
||||
fprintf(stderr,
|
||||
"warning: options other than --status are ignored\n");
|
||||
|
||||
libptouch_ctx *sctx = libptouch_create();
|
||||
if (!sctx) {
|
||||
fprintf(stderr, "libptouch_create failed\n");
|
||||
return 1;
|
||||
}
|
||||
libptouch_err_t se = libptouch_open_usb(sctx);
|
||||
if (se != LIBPTOUCH_OK) {
|
||||
fprintf(stderr, "open_usb: %s\n", libptouch_strerror(sctx));
|
||||
libptouch_destroy(sctx);
|
||||
return 1;
|
||||
}
|
||||
uint8_t st[LIBPTOUCH_STATUS_LENGTH];
|
||||
se = libptouch_get_status(sctx, st);
|
||||
if (se != LIBPTOUCH_OK) {
|
||||
fprintf(stderr, "get_status: %s\n", libptouch_strerror(sctx));
|
||||
libptouch_close(sctx);
|
||||
libptouch_destroy(sctx);
|
||||
return 1;
|
||||
}
|
||||
libptouch_status_fprint(stdout, st);
|
||||
libptouch_close(sctx);
|
||||
libptouch_destroy(sctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
fprintf(stderr, "-f is required (or use --status)\n");
|
||||
usage(argv[0]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int png = input_is_png(file);
|
||||
if (png) {
|
||||
if (width != 0 || height != 0)
|
||||
fprintf(stderr,
|
||||
"warning: -w/-H ignored for PNG (using image size)\n");
|
||||
} else {
|
||||
if (width == 0 || height == 0) {
|
||||
fprintf(stderr,
|
||||
"1bit raster requires -w and -H (or use a PNG file)\n");
|
||||
usage(argv[0]);
|
||||
return 2;
|
||||
}
|
||||
if (has_threshold)
|
||||
fprintf(stderr,
|
||||
"warning: -t applies to PNG only (ignored)\n");
|
||||
}
|
||||
|
||||
libptouch_ctx *ctx = libptouch_create();
|
||||
if (!ctx) {
|
||||
fprintf(stderr, "libptouch_create failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t *data = NULL;
|
||||
size_t data_len = 0;
|
||||
libptouch_raster_params_t params = { 0, 0, 0 };
|
||||
libptouch_err_t e;
|
||||
|
||||
if (png) {
|
||||
libptouch_png_options_t opt = { .threshold = (uint8_t)threshold };
|
||||
e = libptouch_png_file_to_raster(ctx, file,
|
||||
has_threshold ? &opt : NULL,
|
||||
&data, &data_len, ¶ms);
|
||||
if (e != LIBPTOUCH_OK) {
|
||||
fprintf(stderr, "png_file_to_raster: %s\n",
|
||||
libptouch_strerror(ctx));
|
||||
libptouch_destroy(ctx);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (read_file(file, &data, &data_len) != 0) {
|
||||
libptouch_destroy(ctx);
|
||||
return 1;
|
||||
}
|
||||
params.width_dots = width;
|
||||
params.height_dots = height;
|
||||
params.margin_mm = 0;
|
||||
}
|
||||
|
||||
e = libptouch_check_raster(ctx, data, data_len, ¶ms);
|
||||
if (e != LIBPTOUCH_OK) {
|
||||
fprintf(stderr, "check_raster: %s\n",
|
||||
libptouch_strerror(ctx));
|
||||
libptouch_destroy(ctx);
|
||||
if (png)
|
||||
libptouch_free_raster(data);
|
||||
else
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (dry_run) {
|
||||
printf("dry-run OK: %zu bytes, %ux%u dots\n", data_len,
|
||||
(unsigned)params.width_dots,
|
||||
(unsigned)params.height_dots);
|
||||
libptouch_destroy(ctx);
|
||||
if (png)
|
||||
libptouch_free_raster(data);
|
||||
else
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
e = libptouch_open_usb(ctx);
|
||||
if (e != LIBPTOUCH_OK) {
|
||||
fprintf(stderr, "open_usb: %s\n", libptouch_strerror(ctx));
|
||||
libptouch_destroy(ctx);
|
||||
if (png)
|
||||
libptouch_free_raster(data);
|
||||
else
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
e = libptouch_print_raster(ctx, data, data_len, ¶ms);
|
||||
if (e != LIBPTOUCH_OK) {
|
||||
fprintf(stderr, "print_raster: %s\n",
|
||||
libptouch_strerror(ctx));
|
||||
libptouch_close(ctx);
|
||||
libptouch_destroy(ctx);
|
||||
if (png)
|
||||
libptouch_free_raster(data);
|
||||
else
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
libptouch_close(ctx);
|
||||
libptouch_destroy(ctx);
|
||||
if (png)
|
||||
libptouch_free_raster(data);
|
||||
else
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user