matmair / brother_ql-inventree

Python package for the raster language protocol of the Brother QL series label printers
GNU General Public License v3.0
26 stars 10 forks source link

sending times out when printing multiple labels on QL1110-NWB (102x152 die-cut labels) #50

Open simonkuehling opened 4 months ago

simonkuehling commented 4 months ago

Hi,

sending a larger print job to the QL1110-NWB printer often runs into a timeout of the write command (which is 10s as far as I can tell from the code). The timeout looks to be tied to the amount of bytes transferred to the printer - somewhere up to 280k bytes still works, ~400k bytes trip the timeout. To reproduce this, the following cli.py line can be used:

python cli.py -b network -m QL-1110NWB -p tcp://192.168.178.53 print -l 102x152 -c --lq ~/test.png ~/test.png ~/test.png ~/test.png ~/test.png

test.png is a 1164x1660 px PNG image (shipping labels in my case).

INFO:brother_ql.backends.helpers:Sending instructions to the printer. Total: 406925 bytes.
Traceback (most recent call last):
  File "/home/simon/.local/lib/python3.10/site-packages/brother_ql/cli.py", line 166, in <module>
    cli()
  File "/usr/lib/python3/dist-packages/click/core.py", line 1128, in __call__
    return self.main(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/click/core.py", line 1053, in main
    rv = self.invoke(ctx)
  File "/usr/lib/python3/dist-packages/click/core.py", line 1659, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/lib/python3/dist-packages/click/core.py", line 1395, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/lib/python3/dist-packages/click/core.py", line 754, in invoke
    return __callback(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/click/decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/home/simon/.local/lib/python3.10/site-packages/brother_ql/cli.py", line 146, in print_cmd
    send(instructions=instructions, printer_identifier=printer, backend_identifier=backend, blocking=True)
  File "/home/simon/.local/lib/python3.10/site-packages/brother_ql/backends/helpers.py", line 61, in send
    printer.write(instructions)
  File "/home/simon/.local/lib/python3.10/site-packages/brother_ql/backends/generic.py", line 33, in write
    self._write(data)
  File "/home/simon/.local/lib/python3.10/site-packages/brother_ql/backends/network.py", line 67, in _write
    self.s.sendall(data)
TimeoutError: timed out

In a script I am using I am currently working around this by sending the instructions in blocks of 50kB like this:

   def print_images(self, images):
        instructions = convert(self.qlr, images, label='102x152', rotate='0', hq=False, compress=True)

        printer_id = f'tcp://{self.ip_address}'
        backend_id = 'network'

        try:
            self.send_in_blocks(instructions, printer_id, backend_id)
            logging.debug("Druckauftrag gesendet")
        except Exception as e:
            logging.error(f"Fehler beim Senden des Druckauftrags: {str(e)}")

    def send_in_blocks(self, instructions, printer_id, backend_id):
        for i in range(0, len(instructions), self.block_size):
            end = min(i + self.block_size, len(instructions))
            block = instructions[i:end]
            send(
                instructions=block,
                printer_identifier=printer_id,
                backend_identifier=backend_id,
                blocking=True
            )
            time.sleep(0.1)  # Kurze Pause, um sicherzustellen, dass der Drucker den Block verarbeitet hat

I could not find out if the printer is just slow in receiving the data generally or if it pauses in between to print the first label in order to free up memory for more data to be transmitted. Which means that I am not too sure if my solution is the proper way to handle this or if it just happens to work in my setup right now...

Maybe something along these lines should be implemented in the library?

vulpes2 commented 3 months ago

These printers have really small buffers, so they can be easily filled up if you're printing multiple large images. The network backend doesn't support bidirectional communication at the moment, so there's no way for the library to know the printer's buffer is full. The blocking option for send() has no effect if the network backend is used.