summaryrefslogblamecommitdiffstats
path: root/src/main.c
blob: ea55e6dad184db4f8024da9b886dc075691843f4 (plain) (tree)



















                                                              

                         

 

                 



















                                                                                                                                      

 
                                
 















































































                                                                                                






                                          






























                                                                                            







                                                                          









                                                                                          
                                                             






















                                                                                          
 
/*
 * Copyright 2017 DiUS Computing Pty Ltd. All rights reserved.
 *
 * Released under GPLv3, see LICENSE for details.
 *
 * @author Johny Mattsson <jmattsson@dius.com.au>
 */
#include "ql.h"
#include "loadpng.h"
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>

static bool timed_out = false;
void on_alarm(int ignored)
{
	(void)ignored;
	timed_out = true;
}

void syntax(void)
{
	fprintf(stderr,
		"Syntax:\n"
		"  qlprint [-p lp] -i\n"
		"          [-p lp] [-m margin] [-a] [-C|-D] [-W width] [-L length] [-Q] [-n num] [-t threshold] [-x timeout] png...\n"
		"Where:\n"
		"  -p lp         Printer port (default /dev/usb/lp0)\n"
		"  -i            Print status information only, then exit\n"
		"  -m margin     Margin (dots)\n"
		"  -a            Enable auto-cut\n"
		"  -C            Request continuous-length-tape when printing (error if not)\n"
		"  -D            Request die-cut-labels when printing (error if not)\n"
		"  -W width      Request particular width media when printing (error if not)\n"
		"  -L length     Request particular length media when printing (error if not)\n"
		"  -Q            Prioritise quality of speed\n"
		"  -n num        Print num copies\n"
		"  -t threshold  Threshold for black-vs-white (default 128, i.e. 0-127=black)\n"
		"  -x timeout    Time to wait for successful print, in seconds (default 5)\n"
		"  png...        One or more png files to print\n" "\n");

	exit(EXIT_FAILURE);
}

int main(int argc, char *argv[])
{
	bool info_only = false;
	int32_t margin = -1;
	bool autocut = false;
	int num = 1;
	ql_print_cfg_t cfg = {
		.threshold = 0x80,
		.flags = 0
	};
	const char *printer = "/dev/usb/lp0";
	unsigned timeout = 5;
	int opt;
	while ((opt = getopt(argc, argv, "ip:m:an:CDW:L:Qx:")) != -1) {
		switch (opt) {
		case 'i':
			info_only = true;
			break;
		case 'p':
			printer = optarg;
			break;
		case 'm':
			margin = atoi(optarg);
			break;
		case 'a':
			autocut = true;
			break;
		case 'n':
			num = atoi(optarg);
			break;
		case 'C':
			cfg.media_type = QL_MEDIA_TYPE_CONTINUOUS;
			cfg.flags |= QL_PRINT_CFG_MEDIA_TYPE;
			break;
		case 'D':
			cfg.media_type = QL_MEDIA_TYPE_DIECUT_LABELS;
			cfg.flags |= QL_PRINT_CFG_MEDIA_TYPE;
			break;
		case 'W':
			cfg.media_width = atoi(optarg);
			cfg.flags |= QL_PRINT_CFG_MEDIA_WIDTH;
			break;
		case 'L':
			cfg.media_length = atoi(optarg);
			cfg.flags |= QL_PRINT_CFG_MEDIA_LENGTH;
			break;
		case 'Q':
			cfg.flags |= QL_PRINT_CFG_QUALITY_PRIO;
			break;
		case 'x':
			timeout = atoi(optarg);
			break;
		default:
			syntax();
		}
	}

	if (optind >= argc && !info_only)
		syntax();

	ql_ctx_t ctx = ql_open(printer);
	if (!ctx) {
		fprintf(stderr, "Unable to open '%s': %s\n", printer, strerror(errno));
		return EXIT_FAILURE;
	}

	if (!ql_init(ctx)) {
		fprintf(stderr, "Failed to send initialisation sequence to printer: %s\n",
			strerror(errno));
		return EXIT_FAILURE;
	}

	if (!ql_request_status(ctx)) {
		fprintf(stderr, "Failed to request status from printer: %s\n", strerror(errno));
		return EXIT_FAILURE;
	}

	ql_status_t status = { 0, };
	if (!ql_read_status(ctx, &status)) {
		fprintf(stderr, "Failed to read status from printer: %s\n", strerror(errno));
		return EXIT_FAILURE;
	}

/*
for (int i = 0; i < 32; ++i)
  printf("%02hhx ", ((char *)&status)[i]);
printf("\n");
*/

	if (info_only) {
		ql_decode_print_status(stdout, &status,
				       QL_DECODE_MODEL | QL_DECODE_MEDIA | QL_DECODE_ERROR |
				       QL_DECODE_MODE);
		return EXIT_SUCCESS;
	}

	if (margin >= 0 && !ql_set_margin(ctx, (uint16_t) margin)) {
		fprintf(stderr, "Failed to set margin: %s\n", strerror(errno));
		return EXIT_FAILURE;
	}
	if (autocut && (!ql_set_mode(ctx, QL_MODE_AUTOCUT)
			|| !ql_set_autocut_every_n(ctx, argc - optind))) {
		fprintf(stderr, "Failed to set autocut: %s\n", strerror(errno));
		return EXIT_FAILURE;
	}

	if (ql_needs_mode_switch(&status) && !ql_switch_to_raster_mode(ctx)) {
		fprintf(stderr, "Failed to set raster mode: %s\n", strerror(errno));
		return EXIT_FAILURE;
	}

	signal(SIGALRM, on_alarm);
	while (num--) {
		cfg.first_page = true;
		for (int i = optind; i < argc; ++i) {
			ql_raster_image_t *img = loadpng(argv[i]);
			if (!img) {
				fprintf(stderr, "Failed to load image '%s'\n", argv[i]);
				return EXIT_FAILURE;
			}
/*
for(int i = 0; i < img->height; ++i)
{
  for(int j = 0; j < img->width; ++j)
    printf("%c", img->data[i*img->width + j] < cfg.threshold ? '#' : '.');
  printf("\n");
}
*/
			if (!ql_print_raster_image(ctx, &status, img, &cfg)) {
				fprintf(stderr, "Failed to print '%s' (%ux%u)\n", argv[i],
					img->width, img->height);
				return EXIT_FAILURE;
			}
			alarm(timeout);
			do {
				if (!ql_read_status(ctx, &status)) {
					if (!timed_out)	// try again, soon
					{
						usleep(5000);
						continue;
					}
					fprintf(stderr, "Printer stopped responding!\n");
					return EXIT_FAILURE;
				}
				if (status.err_info_1 || status.err_info_2) {
					fprintf(stderr, "Printer reported error(s): %s\n",
						ql_decode_errors(&status));
					return EXIT_FAILURE;
				}
			} while (status.status_type != QL_STATUS_TYPE_PRINTING_DONE);
			alarm(0);

			printf("%s (%ux%u) OK\n", argv[i], img->width, img->height);

			free(img);
			cfg.first_page = false;
		}
	}

	ql_close(ctx);

	return EXIT_SUCCESS;
}