/* * Copyright 2017 DiUS Computing Pty Ltd. All rights reserved. * * Released under GPLv3, see LICENSE for details. * * @author Johny Mattsson */ #include "ql.h" #include "loadpng.h" #include #include #include #include #include #include #include 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] 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" " 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 }; int opt; const char *printer = "/dev/usb/lp0"; while ((opt = getopt(argc, argv, "ip:m:an:CDW:L:Q")) != -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; 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(5); do { if (!ql_read_status(ctx, &status)) { if (!timed_out) // try again, soon { usleep(50); 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; }