Re: [cups] Auto-reformatting shipping labels for a 4x6 thermal printer
Nick Bogdanov <[email protected]> Fri, 23 Jun 2023 22:36:08 -0700
| Newsgroups | gmane.comp.printing.cups.general |
|---|---|
| Message-ID | <CAF-pz-1Zgxh9DvufRmnvmU2h4RJcmO-3Myk2niGFcMnmTxp9PQ@mail.gmail.com> |
On Mon, Jun 19, 2023 at 12:38 PM Alex Korobkin <[email protected]> wrote: > If you really want to deep-dive into this, one way to handle it is to write > your own filter. > Basically, you either register a mime-type conversion > "application/vnd.cups-nick", and tell your CUPS to convert any incoming job > into this type, or,you can modify your printer PPD file to include your > filter, whichever you prefer. > Once the filter receives the incoming job, you can do whatever you want > with it: convert, resize, cut, etc. You'd need to do some scripting or > coding for that, of course. > > Check these links for a good explanation of how filters work: > https://en.opensuse.org/SDB:CUPS_in_a_Nutshell#The_Filter_(includes_the_Driver) > https://en.opensuse.org/SDB:Using_Your_Own_Filters_to_Print_with_CUPS I hacked on this for a little bit and came up with something. It's not great, but I'm going to try it for a while and see how well it works for this use case. Maybe folks on the list have some feedback on how to improve it. This is the first time I've ever tried to edit images programmatically. Since I wanted to be able to submit labels from multiple CUPS-enabled computers (Macbooks and Linux PCs), I set up a centralized IPP server that accepts PDF files and uses a python script to perform the necessary transformations. This was as simple as: ippserver -c ./lconvert.py -f application/pdf -v -p 8100 "Zebra label converter" lconvert.py accepts a shipping label PDF as input, then for each page it uses pdfCropMargins to get rid of all the whitespace (which is a lot if it's on an 8.5x11 page). It leaves 5px around the edge since not all of the label material is printable. It figures out whether the image needs to be rotated, based on the height/width constants in the code. Then it writes out the image as a 203dpi PNG with pixel dimensions matching what the Zebra printer expects, and sends it to zplconvert. Once it has a ZPL-encoded raster image, it gets sent to the printer over TCP/IP. I think this could probably work over USB/serial too but I haven't tested that yet. I did notice that CUPS on macOS required me to provide a dummy PPD file in order to send raw PDF data to ippserver. I copied the PPD file that Linux CUPS autogenerated for me. Not sure why the two OSes behave differently. #!/usr/bin/env python3 DPI = 203 LABEL_WIDTH_IN = 4 LABEL_HEIGHT_IN = 3 DEFAULT_OUTFILE = "zebra.lan:9100" #DEFAULT_OUTFILE = "/tmp/out.zpl" WORKDIR = "work" # pip3 install --user pdfCropMargins import pdfCropMargins # pip3 install pyMuPdf import fitz # from `git clone https://github.com/dionysio/zplconvert` (python3 fork) import zplconvert import logging, os, socket, sys, tempfile def sendfile(dest, data): (host, port) = dest.split(":") ip = socket.gethostbyname(host) with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: sock.connect((ip, int(port))) sock.sendall(bytes(data, "utf-8")) def main(): logging.basicConfig(format='%(asctime)s %(message)s', level=logging.INFO) try: os.mkdir(WORKDIR) except: pass infile = sys.argv[1] if len(sys.argv) >= 3: outfile = sys.argv[2] else: outfile = DEFAULT_OUTFILE logging.info("Processing PDF %s" % infile) (_, cropped) = tempfile.mkstemp(dir=WORKDIR, suffix=".pdf") pdfCropMargins.crop(["-p", "0", "-a", "-5", sys.argv[1], "-o", cropped]) logging.info("Wrote cropped version to %s" % cropped) with fitz.open(cropped) as pdf: for i in range(0, pdf.page_count): page = pdf.load_page(i) logging.info(page) r = page.bound() logging.info("original dimensions: W=%d H=%d" % (r.width, r.height)) if (r.height > r.width and LABEL_WIDTH_IN > LABEL_HEIGHT_IN): page.set_rotation(90) x_scale = LABEL_WIDTH_IN * DPI / r.height y_scale = LABEL_HEIGHT_IN * DPI / r.width else: x_scale = LABEL_WIDTH_IN * DPI / r.width y_scale = LABEL_HEIGHT_IN * DPI / r.height pix = page.get_pixmap(matrix=fitz.Matrix(x_scale, y_scale)) logging.info("output pixmap: %s" % pix) (_, png) = tempfile.mkstemp(dir=WORKDIR, suffix=".png") pix.pil_save(png) logging.info("wrote PNG to %s" % png) converter = zplconvert.ZPLConvert(png) converter.set_black_threshold(64) converter.set_dither(False) zpl = converter.convert(label=True) if outfile.find(":") == -1: with open(outfile, "w") as out: out.write(zpl) logging.info("wrote ZPL data to %s" % outfile) else: sendfile(outfile, zpl) if __name__ == '__main__': main() _______________________________________________ cups mailing list [email protected] https://lists.cups.org/mailman/listinfo/cups