Printer Adjustments

This commit is contained in:
2026-09-07 10:56:01 +10:00
parent 511929d579
commit 28b52145eb
6 changed files with 85 additions and 12 deletions
+8 -2
View File
@@ -179,10 +179,16 @@ the widest roll it will accept — the console warns you if you enter anything w
| DK-11208 | 38 × 90 mm die-cut | Narrower; turn the photo off |
| DK-11209 | 29 × 62 mm die-cut | Name and host only |
**Tell it which roll is loaded.** *Roll loaded in the printer* under **Sites → Edit → Printer**
must match what is physically in the machine. A two-colour job sent to a plain roll is refused
outright: the printer shows **Wrong Roll Type** and nothing comes out. The setting is separate
from the red styling option on purpose — a design choice should not silently change the media
type the printer is told to expect.
**The red option.** Tick *Print the heading and the no-check warning in red* and the site name
and the **No WWCC / VIT** box print red instead of black, which makes a visitor without a check
obvious across a room. It only works on a DK-22251 roll — on any other roll the printer renders
it as grey. Two-colour printing is also far slower than black alone (Brother rate it at roughly
obvious across a room. It needs the roll setting above to be the DK-22251; with a plain roll
selected the badge is drawn in black instead and the console says so. Two-colour printing is also far slower than black alone (Brother rate it at roughly
15 labels a minute against 110), which is irrelevant for one badge at a time but worth knowing.
### Printing from the server
+42 -5
View File
@@ -702,9 +702,9 @@ async function loadSites() {
<dt>Printer</dt>
<dd>${
s.printer.enabled && s.printer.host
? `${esc(s.printer.model)} at ${esc(s.printer.host)}:${s.printer.port}${
s.printer.rotate ? `, rotated ${s.printer.rotate}°` : ''
}${
? `${esc(s.printer.model)} at ${esc(s.printer.host)}:${s.printer.port}, ${
s.printer.label === '62red' ? 'black and red roll' : 'black roll'
}${s.printer.rotate ? `, rotated ${s.printer.rotate}°` : ''}${
s.printerStatus
? s.printerStatus.ok
? ` <span class="pill">last print ok, ${stamp(s.printerStatus.at)}</span>`
@@ -799,14 +799,21 @@ function openSiteModal(site) {
<p class="hint" id="badge-warning" hidden></p>
<label class="inline"><input type="checkbox" name="showPhoto" id="badge-photo" ${site.badge.showPhoto ? 'checked' : ''}> Include the visitor's photo</label>
<label class="inline"><input type="checkbox" name="accent" id="badge-accent" ${site.badge.accent ? 'checked' : ''}> Print the heading and the no-check warning in red</label>
<p class="hint">Red needs a two-colour roll such as the Brother DK-22251. On any other
roll it prints as grey. Two-colour printing is also much slower than black alone.</p>
<p class="hint" id="accent-note"></p>
<p class="hint">Two-colour printing is much slower than black alone.</p>
<h4 class="modal-section">Printer</h4>
<label class="inline"><input type="checkbox" name="printerEnabled" ${site.printer.enabled ? 'checked' : ''}> Print from the server, straight to a network printer</label>
<div class="modal-row">
${field('Printer IP address', 'printerHost', site.printer.host, 'text')}
${field('Port', 'printerPort', site.printer.port, 'number')}
</div>
<label class="modal-field"><span>Roll loaded in the printer</span>
<select name="printerLabel">
<option value="62" ${site.printer.label !== '62red' ? 'selected' : ''}>62 mm continuous, black only</option>
<option value="62red" ${site.printer.label === '62red' ? 'selected' : ''}>62 mm continuous, black and red (DK-22251)</option>
</select></label>
<p class="hint">This must match the roll actually in the machine. Send a two-colour job to a
plain roll and the printer answers <em>Wrong Roll Type</em> and prints nothing.</p>
<div class="modal-row">
${field('Model', 'printerModel', site.printer.model)}
<label class="modal-field"><span>Rotation</span>
@@ -883,6 +890,7 @@ function openSiteModal(site) {
port: Number(data.printerPort) || 9100,
model: data.printerModel,
rotate: Number(data.printerRotate) || 0,
label: data.printerLabel,
},
branding: {
brand: data.brand || null,
@@ -992,6 +1000,35 @@ function wireBannerEditor() {
[pageInput, textInput].forEach((el) => el.addEventListener('input', showContrast));
showContrast();
// Red is only possible on the two-colour roll, so say so as the two settings change.
const accentBox = $('#badge-accent');
const rollSelect = $('#modal-form [name="printerLabel"]');
const accentNote = $('#accent-note');
const showAccentNote = () => {
if (!accentNote) return;
if (!accentBox?.checked) {
accentNote.hidden = false;
accentNote.className = 'hint';
accentNote.textContent = 'Everything prints black.';
return;
}
if (rollSelect?.value === '62red') {
accentNote.hidden = false;
accentNote.className = 'hint';
accentNote.textContent = 'The heading and the no-check warning will print red.';
} else {
accentNote.hidden = false;
accentNote.className = 'hint warn';
accentNote.textContent =
'The roll selected below cannot print red, so these will come out black. Load a DK-22251 and change the roll setting to use colour.';
}
};
accentBox?.addEventListener('change', showAccentNote);
rollSelect?.addEventListener('change', showAccentNote);
showAccentNote();
$('#banner-file').addEventListener('change', (event) => {
const file = event.target.files[0];
if (!file) return;
+5
View File
@@ -27,6 +27,7 @@ CREATE TABLE IF NOT EXISTS sites (
printer_port INTEGER NOT NULL DEFAULT 9100,
printer_model TEXT NOT NULL DEFAULT 'QL-820NWB',
printer_rotate INTEGER NOT NULL DEFAULT 0,
printer_label TEXT NOT NULL DEFAULT '62',
banner_path TEXT,
banner_height INTEGER NOT NULL DEFAULT 64,
banner_align TEXT NOT NULL DEFAULT 'left',
@@ -183,6 +184,10 @@ addColumn('sites', 'printer_host', 'TEXT');
addColumn('sites', 'printer_port', 'INTEGER NOT NULL DEFAULT 9100');
addColumn('sites', 'printer_model', "TEXT NOT NULL DEFAULT 'QL-820NWB'");
addColumn('sites', 'printer_rotate', 'INTEGER NOT NULL DEFAULT 0');
// Which roll is physically loaded. Kept separate from the red styling option:
// the printer refuses a two-colour job on a plain roll, so guessing the media
// from a design setting means a wrong-roll error nobody can explain.
addColumn('sites', 'printer_label', "TEXT NOT NULL DEFAULT '62'");
addColumn('frequent_visitors', 'company', 'TEXT');
db.exec('CREATE INDEX IF NOT EXISTS idx_visits_site ON visits(site_id, signed_out_at)');
+24 -3
View File
@@ -41,9 +41,26 @@ export function isConfigured(site) {
return Boolean(site?.printer_enabled && site?.printer_host);
}
/** brother_ql's label id. The two-colour roll is a different label to the plain one. */
/**
* brother_ql's media id for the roll that is actually loaded.
*
* This is set explicitly rather than inferred from the red styling option. A
* two-colour job sent to a plain roll is rejected by the printer with "Wrong
* Roll Type", which gives no clue that a colour checkbox caused it.
*/
export const ROLL_TYPES = {
'62': '62 mm continuous, black only',
'62red': '62 mm continuous, black and red (DK-22251)',
};
export function labelFor(site) {
return site?.badge_accent ? '62red' : '62';
const label = site?.printer_label;
return Object.hasOwn(ROLL_TYPES, label) ? label : '62';
}
/** Red ink only exists on the two-colour roll; anywhere else it prints dark grey. */
export function accentWillPrintRed(site) {
return Boolean(site?.badge_accent) && labelFor(site) === '62red';
}
/* ------------------------------------------------------------ rendering */
@@ -223,7 +240,8 @@ export async function renderBadgePng(visit, site) {
const design = createCanvas(designW, designH);
const ctx = design.getContext('2d');
const accent = Boolean(site.badge_accent);
// Only paint red when the loaded roll can actually print it.
const accent = accentWillPrintRed(site);
// Measure first, then draw the block centred down the label. Without this the
// content hugs the top and leaves a wide blank strip at the bottom of every badge.
@@ -273,6 +291,9 @@ function explainPrintError(output, host) {
if (/Unknown label|label/i.test(last) && /identifier/i.test(last)) {
return 'The printer rejected the label size. Check the roll loaded matches the badge settings.';
}
if (/wrong roll|WrongMedia|media/i.test(last)) {
return 'The printer says the roll is wrong. Check "Roll loaded in the printer" matches what is actually in the machine — a black and red job is refused on a plain roll.';
}
return last || 'The printer did not accept the job.';
}
+5 -2
View File
@@ -397,7 +397,7 @@ router.patch('/sites/:id', (req, res) => {
badge_height_mm = ?, badge_show_photo = ?, badge_accent = ?, badge_note = ?,
colour_brand = ?, colour_signout = ?, colour_page = ?, colour_text = ?,
banner_height = ?, banner_align = ?, printer_enabled = ?, printer_host = ?,
printer_port = ?, printer_model = ?, printer_rotate = ? WHERE id = ?`
printer_port = ?, printer_model = ?, printer_rotate = ?, printer_label = ? WHERE id = ?`
).run(
clean(req.body?.name ?? site.name, 100) || site.name,
req.body?.slug ? uniqueSlug(req.body.slug, site.id) : site.slug,
@@ -432,7 +432,10 @@ router.patch('/sites/:id', (req, res) => {
printerCfg.model !== undefined ? clean(printerCfg.model, 40) || 'QL-820NWB' : site.printer_model,
printerCfg.rotate !== undefined
? ([0, 90, 180, 270].includes(Number(printerCfg.rotate)) ? Number(printerCfg.rotate) : 0)
: site.printer_rotate
: site.printer_rotate,
printerCfg.label !== undefined
? (Object.hasOwn(printer.ROLL_TYPES, printerCfg.label) ? printerCfg.label : '62')
: site.printer_label
, site.id);
res.json(shapeSite(db.prepare('SELECT * FROM sites WHERE id = ?').get(site.id)));
+1
View File
@@ -65,6 +65,7 @@ export function shapeSite(site) {
port: site.printer_port || 9100,
model: site.printer_model || 'QL-820NWB',
rotate: site.printer_rotate || 0,
label: site.printer_label || '62',
},
badge: {
enabled: Boolean(site.badge_enabled),