diff --git a/src/printer.js b/src/printer.js index 3a8f402..952f4b4 100644 --- a/src/printer.js +++ b/src/printer.js @@ -6,6 +6,7 @@ import { execFile } from 'node:child_process'; import { createCanvas, loadImage, GlobalFonts } from '@napi-rs/canvas'; import config from './config.js'; import { photoAbsolutePath } from './photos.js'; +import { ditherPhoto } from './printing/dither.js'; import { printPng, printerHealth } from './printing/ql-print.js'; /** @@ -114,6 +115,17 @@ async function drawBadge(ctx, widthDots, heightDots, visit, site, accent, startY } const photoSize = photo ? Math.round(unit * (portrait ? 0.52 : 0.5)) : 0; + + // Thermal heads print pure black or nothing, so a photo has to be reduced to + // 1-bit before it lands on the canvas — otherwise the plane conversion + // thresholds it into a solid blob. Done once here rather than at each draw + // site, and at exactly photoSize: rescaling a dithered image resamples the + // dot pattern back into greys and undoes the whole thing. + // + // Skipped on the measuring pass, which never paints. + if (photo && photoSize > 0 && startY !== null) { + photo = ditherPhoto(photo, photoSize); + } let cursorY = startY === null ? pad : startY; let textLeft = pad; let textWidth = widthDots - pad * 2;