diff --git a/Makefile.am b/Makefile.am index 23e8539..1708425 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ AUTOMAKE_OPTIONS = subdir-objects AM_CPPFLAGS= -DLOCALEDIR='"$(localedir)"' -AM_CFLAGS=-g -std=c11 -Wall -O3 -I$(top_srcdir)/include +AM_CFLAGS=-g -std=c11 -Wall -Wextra -Wunused -O3 -I$(top_srcdir)/include -fPIC SUBDIRS = po ACLOCAL_AMFLAGS = -I m4 EXTRA_DIST = config.rpath m4/ChangeLog Makefile.old diff --git a/README b/README index b46803a..6bde175 100644 --- a/README +++ b/README @@ -16,7 +16,7 @@ https://mockmoon-cybernetics.ch/computer/p-touch2430pc/ Compile instructions: -autoreconf -i +./autogen.sh ./configure --prefix=/usr make diff --git a/build-aux/git-version-gen b/build-aux/git-version-gen index b56731d..23afd31 100755 --- a/build-aux/git-version-gen +++ b/build-aux/git-version-gen @@ -1,3 +1,3 @@ #!/bin/sh -GIT_VERSION=$(git --no-pager describe --tags --dirty |sed 's/\([^-]*-g\)/r\1/;s/-/./g;s/v//g') +GIT_VERSION=$(git --no-pager describe --always --tags --dirty |sed 's/\([^-]*-g\)/r\1/;s/-/./g;s/v//g') echo -ne ${GIT_VERSION} diff --git a/include/ptouch.h b/include/ptouch.h index 75b17e1..ad4e72d 100644 --- a/include/ptouch.h +++ b/include/ptouch.h @@ -1,7 +1,7 @@ /* ptouch-print - Print labels with images or text on a Brother P-Touch - Copyright (C) 2015-2017 Dominic Radermacher + Copyright (C) 2015-2019 Dominic Radermacher This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as @@ -25,9 +25,9 @@ struct _pt_tape_info { uint8_t px; /* Printing area in px */ }; -#define FLAG_NONE 0 -#define FLAG_UNSUP_RASTER 1 -#define FLAG_FORCE_TIFF 2 +#define FLAG_NONE (0x00) +#define FLAG_UNSUP_RASTER (0x01) +#define FLAG_RASTER_PACKBITS (0x02) struct _pt_dev_info { int vid; /* USB vendor ID */ @@ -38,26 +38,52 @@ struct _pt_dev_info { }; typedef struct _pt_dev_info *pt_dev_info; +struct __attribute__((packed, aligned(4))) _ptouch_stat { + uint8_t printheadmark; // 0x80 + uint8_t size; // 0x20 + uint8_t brother_code; // "B" + uint8_t series_code; // "0" + uint8_t model; + uint8_t country; // "0" + uint16_t reserved_1; + uint16_t error; // table 1 and 2 + uint8_t media_width; // tape width in mm + uint8_t media_type; // table 4 + uint8_t ncol; // 0 + uint8_t fonts; // 0 + uint8_t jp_fonts; // 0 + uint8_t mode; + uint8_t density; // 0 + uint8_t media_len; // table length, always 0 + uint8_t status_type; // table 5 + uint8_t phase_type; + uint16_t phase_number; // table 6 + uint8_t notif_number; + uint8_t exp; // 0 + uint8_t tape_color; // table 8 + uint8_t text_color; // table 9 + uint32_t hw_setting; + uint16_t reserved_2; +}; +typedef struct _ptouch_stat *pt_dev_stat; + struct _ptouch_dev { libusb_device_handle *h; - uint8_t raw[32]; - uint8_t tape_width_mm; - uint8_t tape_width_px; - uint8_t status; - uint8_t media_type; pt_dev_info devinfo; + pt_dev_stat status; + uint8_t tape_width_px; }; typedef struct _ptouch_dev *ptouch_dev; int ptouch_open(ptouch_dev *ptdev); int ptouch_close(ptouch_dev ptdev); -int ptouch_send(ptouch_dev ptdev, uint8_t *data, int len); +int ptouch_send(ptouch_dev ptdev, uint8_t *data, size_t len); int ptouch_init(ptouch_dev ptdev); int ptouch_lf(ptouch_dev ptdev); int ptouch_ff(ptouch_dev ptdev); -int ptouch_cutmark(ptouch_dev ptdev); int ptouch_eject(ptouch_dev ptdev); int ptouch_getstatus(ptouch_dev ptdev); int ptouch_getmaxwidth(ptouch_dev ptdev); +int ptouch_enable_packbits(ptouch_dev ptdev); int ptouch_rasterstart(ptouch_dev ptdev); -int ptouch_sendraster(ptouch_dev ptdev, uint8_t *data, int len); +int ptouch_sendraster(ptouch_dev ptdev, uint8_t *data, size_t len); diff --git a/src/libptouch.c b/src/libptouch.c index a8068da..4a089c8 100644 --- a/src/libptouch.c +++ b/src/libptouch.c @@ -1,7 +1,7 @@ /* libptouch - functions to help accessing a brother ptouch - Copyright (C) 2013-2017 Dominic Radermacher + Copyright (C) 2013-2019 Dominic Radermacher This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as @@ -45,13 +45,11 @@ struct _pt_tape_info tape_info[]= { struct _pt_dev_info ptdevs[] = { {0x04f9, 0x202d, "PT-2430PC", 128, FLAG_NONE}, /* 180dpi, maximum 128px */ - {0x04f9, 0x2007, "PT-2420PC", 128, FLAG_FORCE_TIFF}, /* 180dpi, 128px, maximum tape width 24mm, must send TIFF compressed pixel data */ + {0x04f9, 0x2007, "PT-2420PC", 128, FLAG_RASTER_PACKBITS}, /* 180dpi, 128px, maximum tape width 24mm, must send TIFF compressed pixel data */ {0x04f9, 0x202c, "PT-1230PC", 76, FLAG_NONE}, /* 180dpi, supports tapes up to 12mm - I don't know how much pixels it can print! */ {0x04f9, 0x2061, "PT-P700", 120, FLAG_UNSUP_RASTER}, /* DOES NOT WORK */ - {0x04f9, 0x2073, "PT-D450VP", 120, FLAG_UNSUP_RASTER}, /* DOES NOT WORK */ - /* Notes about the PT-D450VP: Tape detecting works, but printing does - not. The tape is just blank. I assume, the printer does not understand - the sent rasterdata. I'm also unsure about how many dots width we have */ + {0x04f9, 0x2073, "PT-D450VP", 128, FLAG_RASTER_PACKBITS}, + /* Notes about the PT-D450VP: I'm unsure if print width really is 128px */ {0x04f9, 0x2041, "PT-2730PC", 128, FLAG_NONE}, /* 180dpi, maximum 128px, max tape width 24mm - reported to work with some quirks */ /* Notes about the PT-2730PC: was reported to need 48px whitespace within png-images before content is actually printed - can not check this */ @@ -77,6 +75,10 @@ int ptouch_open(ptouch_dev *ptdev) fprintf(stderr, _("out of memory\n")); return -1; } + if (((*ptdev)->status=malloc(sizeof(struct _ptouch_stat))) == NULL) { + fprintf(stderr, _("out of memory\n")); + return -1; + } if ((libusb_init(NULL)) < 0) { fprintf(stderr, _("libusb_init() failed\n")); return -1; @@ -130,19 +132,19 @@ int ptouch_close(ptouch_dev ptdev) return 0; } -int ptouch_send(ptouch_dev ptdev, uint8_t *data, int len) +int ptouch_send(ptouch_dev ptdev, uint8_t *data, size_t len) { - int r,tx; + int r, tx; - if (ptdev == NULL) { + if ((ptdev == NULL) || (len > 128)) { return -1; } - if ((r=libusb_bulk_transfer(ptdev->h, 0x02, data, len, &tx, 0)) != 0) { + if ((r=libusb_bulk_transfer(ptdev->h, 0x02, data, (int)len, &tx, 0)) != 0) { fprintf(stderr, _("write error: %s\n"), libusb_error_name(r)); return -1; } - if (tx != len) { - fprintf(stderr, _("write error: could send only %i of %i bytes\n"), tx, len); + if (tx != (int)len) { + fprintf(stderr, _("write error: could send only %i of %ld bytes\n"), tx, len); return -1; } return 0; @@ -154,6 +156,12 @@ int ptouch_init(ptouch_dev ptdev) return ptouch_send(ptdev, (uint8_t *)cmd, strlen(cmd)); } +int ptouch_enable_packbits(ptouch_dev ptdev) +{ /* 4D 00 = disable compression */ + char cmd[] = "M\x02"; /* 4D 02 = enable packbits compression mode */ + return ptouch_send(ptdev, (uint8_t *)cmd, strlen(cmd)); +} + int ptouch_rasterstart(ptouch_dev ptdev) { char cmd[] = "\x1b\x69\x52\x01"; /* 1B 69 52 01 = Select graphics transfer mode = Raster */ @@ -181,34 +189,6 @@ int ptouch_eject(ptouch_dev ptdev) return ptouch_send(ptdev, (uint8_t *)cmd, strlen(cmd)); } -/* print a "cut here" mark (it's just a dashed line) */ -#define CUTMARK_SPACING 5 -int ptouch_cutmark(ptouch_dev ptdev) -{ - uint8_t buf[32]; - int i,len=16; - - for (i=0; iraw, buf, 32); - if (buf[8] != 0) { - fprintf(stderr, _("Error 1 = %02x\n"), buf[8]); - } - if (buf[9] != 0) { - fprintf(stderr, _("Error 2 = %02x\n"), buf[9]); - } - ptdev->tape_width_mm=buf[10]; + memcpy(ptdev->status, buf, 32); ptdev->tape_width_px=0; for (i=0; tape_info[i].mm > 0; i++) { if (tape_info[i].mm == buf[10]) { @@ -263,8 +236,6 @@ int ptouch_getstatus(ptouch_dev ptdev) if (ptdev->tape_width_px == 0) { fprintf(stderr, _("unknown tape width of %imm, please report this.\n"), buf[10]); } - ptdev->media_type=buf[11]; - ptdev->status=buf[18]; return 0; } } @@ -292,25 +263,24 @@ int ptouch_getmaxwidth(ptouch_dev ptdev) return ptdev->tape_width_px; } -int ptouch_sendraster(ptouch_dev ptdev, uint8_t *data, int len) +int ptouch_sendraster(ptouch_dev ptdev, uint8_t *data, size_t len) { - uint8_t buf[70]; + uint8_t buf[64]; int rc; - if (len > ptdev->devinfo->max_px / 8) { + if (len > (size_t)(ptdev->devinfo->max_px / 8)) { return -1; } - buf[0]=0x47; - if (ptdev->devinfo->flags & FLAG_FORCE_TIFF) { - /* Fake compression by encoding a single uncompressed run */ - buf[1] = len + 1; - buf[2] = 0; - buf[3] = len - 1; - memcpy(buf + 4, data, len); - rc = ptouch_send(ptdev, buf, len + 4); + if (ptdev->devinfo->flags & FLAG_RASTER_PACKBITS) { + /* Fake compression by encoding a single uncompressed run */ + buf[1] = (uint8_t)(len + 1); + buf[2] = 0; + buf[3] = (uint8_t)(len - 1); + memcpy(buf + 4, data, len); + rc = ptouch_send(ptdev, buf, len + 4); } else { - buf[1] = len; + buf[1] = (uint8_t)len; buf[2] = 0; memcpy(buf + 3, data, len); rc = ptouch_send(ptdev, buf, len + 3); diff --git a/src/ptouch-print.c b/src/ptouch-print.c index 86b4462..440b20e 100644 --- a/src/ptouch-print.c +++ b/src/ptouch-print.c @@ -1,7 +1,7 @@ /* ptouch-print - Print labels with images or text on a Brother P-Touch - Copyright (C) 2015-2017 Dominic Radermacher + Copyright (C) 2015-2019 Dominic Radermacher This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as @@ -39,7 +39,10 @@ int find_fontsize(int want_px, char *font, char *text); int needed_width(char *text, char *font, int fsz); int print_img(ptouch_dev ptdev, gdImage *im); int write_png(gdImage *im, const char *file); +gdImage *img_append(gdImage *in_1, gdImage *in_2); +gdImage *img_cutmark(int tape_width); gdImage *render_text(char *font, char *line[], int lines, int tape_width); +void unsupported_printer(ptouch_dev ptdev); void usage(char *progname); int parse_args(int argc, char **argv); @@ -55,11 +58,14 @@ int fontsize=0; void rasterline_setpixel(uint8_t rasterline[16], int pixel) { - rasterline[15-(pixel/8)] |= 1<<(pixel%8); + if (pixel > 128) { + return; + } + rasterline[15-(pixel/8)] |= (uint8_t)(1<<(pixel%8)); return; } -void unsupported_printer(ptouch_dev ptdev) +void unsupported_printer(__attribute__((unused)) ptouch_dev ptdev) { printf(_("your printer unfortunately is not supported by this tool\n")); printf(_("the rasterdata a transferred in some other (unknown) format\n")); @@ -71,6 +77,10 @@ int print_img(ptouch_dev ptdev, gdImage *im) int d,i,k,offset,tape_width; uint8_t rasterline[16]; + if (!im) { + printf(_("nothing to print\n")); + return -1; + } if ((ptdev->devinfo->flags & FLAG_UNSUP_RASTER) == FLAG_UNSUP_RASTER) { unsupported_printer(ptdev); } @@ -83,6 +93,10 @@ int print_img(ptouch_dev ptdev, gdImage *im) return -1; } offset=64-(gdImageSY(im)/2); /* always print centered */ + if ((ptdev->devinfo->flags & FLAG_RASTER_PACKBITS) == FLAG_RASTER_PACKBITS) { + printf("enable PackBits mode\n"); + ptouch_enable_packbits(ptdev); + } if (ptouch_rasterstart(ptdev) != 0) { printf(_("ptouch_rasterstart() failed\n")); return -1; @@ -95,7 +109,7 @@ int print_img(ptouch_dev ptdev, gdImage *im) } } if (ptouch_sendraster(ptdev, rasterline, 16) != 0) { - printf(_("ptouch_send() failed\n")); + printf(_("ptouch_sendraster() failed\n")); return -1; } } @@ -246,6 +260,68 @@ gdImage *render_text(char *font, char *line[], int lines, int tape_width) return im; } +gdImage *img_append(gdImage *in_1, gdImage *in_2) +{ + gdImage *out=NULL; + int width=0; + int i_1_x=0; + int length=0; + + if (in_1 != NULL) { + width=gdImageSY(in_1); + length=gdImageSX(in_1); + i_1_x=gdImageSX(in_1); + } + if (in_2 != NULL) { + length += gdImageSX(in_2); + /* width should be the same, but let's be sure */ + if (gdImageSY(in_2) > width) { + width=gdImageSY(in_2); + } + } + if ((width == 0) || (length == 0)) { + return NULL; + } + out=gdImageCreatePalette(length, width); + if (out == NULL) { + return NULL; + } + gdImageColorAllocate(out, 255, 255, 255); + gdImageColorAllocate(out, 0, 0, 0); + printf("created new img width dimensionx %d * %d\n", length, width); + if (in_1 != NULL) { + gdImageCopy(out, in_1, 0, 0, 0, 0, gdImageSX(in_1), gdImageSY(in_1)); + printf("copied part 1\n"); + } + if (in_2 != NULL) { + gdImageCopy(out, in_2, i_1_x, 0, 0, 0, gdImageSX(in_2), gdImageSY(in_2)); + printf("copied part 2\n"); + } + return out; +} + +gdImage *img_cutmark(int tape_width) +{ + gdImage *out=NULL; + int style_dashed[6]; + + out=gdImageCreatePalette(9, tape_width); + if (out == NULL) { + return NULL; + } + gdImageColorAllocate(out, 255, 255, 255); + int black=gdImageColorAllocate(out, 0, 0, 0); + style_dashed[0]=gdTransparent; + style_dashed[1]=gdTransparent; + style_dashed[2]=gdTransparent; + style_dashed[3]=black; + style_dashed[4]=black; + style_dashed[5]=black; + gdImageSetStyle(out, style_dashed, 6); + gdImageLine(out, 5, 0, 5, tape_width-1, gdStyled); + return out; +} + void usage(char *progname) { printf("usage: %s [options] \n", progname); @@ -322,6 +398,7 @@ int main(int argc, char *argv[]) int i, lines = 0, tape_width; char *line[MAX_LINES]; gdImage *im=NULL; + gdImage *out=NULL; ptouch_dev ptdev=NULL; setlocale(LC_ALL, ""); @@ -366,9 +443,16 @@ int main(int argc, char *argv[]) } } else if (strcmp(&argv[i][1], "-info") == 0) { printf(_("maximum printing width for this tape is %ipx\n"), tape_width); + printf("media type = %02x\n", ptdev->status->media_type); + printf("media width = %d mm\n", ptdev->status->media_width); + printf("tape color = %02x\n", ptdev->status->tape_color); + printf("text color = %02x\n", ptdev->status->text_color); + printf("error = %04x\n", ptdev->status->error); exit(0); } else if (strcmp(&argv[i][1], "-image") == 0) { im=image_load(argv[++i]); + out=img_append(out, im); + gdImageDestroy(im); } else if (strcmp(&argv[i][1], "-text") == 0) { for (lines=0; (lines < MAX_LINES) && (i < argc); lines++) { if ((i+1 >= argc) || (argv[i+1][0] == '-')) { @@ -377,28 +461,33 @@ int main(int argc, char *argv[]) i++; line[lines]=argv[i]; } + if (lines) { + if ((im=render_text(font_file, line, lines, tape_width)) == NULL) { + printf(_("could not render text\n")); + return 1; + } + out=img_append(out, im); + gdImageDestroy(im); + } } else if (strcmp(&argv[i][1], "-cutmark") == 0) { - ptouch_cutmark(ptdev); + im=img_cutmark(tape_width); + out=img_append(out, im); + gdImageDestroy(im); } else { usage(argv[0]); } } - - if (lines) { - if ((im=render_text(font_file, line, lines, tape_width)) == NULL) { - printf(_("could not render text\n")); - return 1; - } - } - - if (save_png) { - write_png(im, save_png); - } else { - print_img(ptdev, im); - if (ptouch_eject(ptdev) != 0) { - printf(_("ptouch_eject() failed\n")); - return -1; + if (out) { + if (save_png) { + write_png(out, save_png); + } else { + print_img(ptdev, out); + if (ptouch_eject(ptdev) != 0) { + printf(_("ptouch_eject() failed\n")); + return -1; + } } + gdImageDestroy(out); } gdImageDestroy(im); ptouch_close(ptdev);