feat: increase font scaling and add inline product name rendering for improved thermal printer legibility
This commit is contained in:
parent
71b7461f41
commit
e667ef3bac
@ -41,7 +41,7 @@ export class HtmlToImageConverter {
|
|||||||
clone.style.backgroundColor = 'white';
|
clone.style.backgroundColor = 'white';
|
||||||
clone.style.color = 'black';
|
clone.style.color = 'black';
|
||||||
clone.style.fontFamily = 'monospace, Courier, "Courier New"';
|
clone.style.fontFamily = 'monospace, Courier, "Courier New"';
|
||||||
clone.style.fontSize = '12px';
|
clone.style.fontSize = '15px';
|
||||||
clone.style.lineHeight = '1.4';
|
clone.style.lineHeight = '1.4';
|
||||||
|
|
||||||
// Create a temporary container to measure height
|
// Create a temporary container to measure height
|
||||||
@ -113,15 +113,15 @@ export class HtmlToImageConverter {
|
|||||||
ctx.fillRect(0, 0, width, height);
|
ctx.fillRect(0, 0, width, height);
|
||||||
ctx.fillStyle = 'black';
|
ctx.fillStyle = 'black';
|
||||||
ctx.textBaseline = 'top';
|
ctx.textBaseline = 'top';
|
||||||
ctx.font = '12px monospace';
|
ctx.font = '16px monospace';
|
||||||
|
|
||||||
const padding = 10;
|
const padding = 10;
|
||||||
const lineHeight = 16;
|
|
||||||
const maxWidth = width - (padding * 2);
|
const maxWidth = width - (padding * 2);
|
||||||
let y = padding;
|
let y = padding;
|
||||||
|
|
||||||
// Helper function to wrap text
|
// Helper function to wrap text
|
||||||
const wrapText = (text, maxWidth) => {
|
const wrapText = (text, maxWidth, fontSize) => {
|
||||||
|
ctx.font = `${ctx.font.includes('bold') ? 'bold' : 'normal'} ${fontSize}px monospace`;
|
||||||
const words = text.split(' ');
|
const words = text.split(' ');
|
||||||
const lines = [];
|
const lines = [];
|
||||||
let currentLine = '';
|
let currentLine = '';
|
||||||
@ -146,11 +146,12 @@ export class HtmlToImageConverter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Helper to draw text with alignment
|
// Helper to draw text with alignment
|
||||||
const drawText = (text, align = 'left', bold = false) => {
|
const drawText = (text, align = 'left', bold = false, fontSize = 16) => {
|
||||||
if (!text || !text.trim()) return;
|
if (!text || !text.trim()) return;
|
||||||
|
|
||||||
ctx.font = `${bold ? 'bold' : 'normal'} 12px monospace`;
|
ctx.font = `${bold ? 'bold' : 'normal'} ${fontSize}px monospace`;
|
||||||
const lines = wrapText(text, maxWidth);
|
const localLineHeight = Math.round(fontSize * 1.3);
|
||||||
|
const lines = wrapText(text, maxWidth, fontSize);
|
||||||
|
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
let x = padding;
|
let x = padding;
|
||||||
@ -163,7 +164,7 @@ export class HtmlToImageConverter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx.fillText(line, x, y);
|
ctx.fillText(line, x, y);
|
||||||
y += lineHeight;
|
y += localLineHeight;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -175,7 +176,7 @@ export class HtmlToImageConverter {
|
|||||||
ctx.strokeStyle = 'black';
|
ctx.strokeStyle = 'black';
|
||||||
ctx.lineWidth = 1;
|
ctx.lineWidth = 1;
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
y += lineHeight;
|
y += 8;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Extract and render content recursively
|
// Extract and render content recursively
|
||||||
@ -195,9 +196,20 @@ export class HtmlToImageConverter {
|
|||||||
const fontWeight = style.fontWeight;
|
const fontWeight = style.fontWeight;
|
||||||
const isBold = fontWeight === 'bold' || parseInt(fontWeight) >= 600;
|
const isBold = fontWeight === 'bold' || parseInt(fontWeight) >= 600;
|
||||||
|
|
||||||
|
// Get font size and scale it up for high legibility on thermal printer
|
||||||
|
let fontSize = 16;
|
||||||
|
const fontSizeStr = style.fontSize;
|
||||||
|
if (fontSizeStr) {
|
||||||
|
const parsed = parseFloat(fontSizeStr);
|
||||||
|
if (!isNaN(parsed) && parsed > 0) {
|
||||||
|
fontSize = Math.max(12, Math.round(parsed * 1.35));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const localLineHeight = Math.round(fontSize * 1.3);
|
||||||
|
|
||||||
// Handle special elements
|
// Handle special elements
|
||||||
if (tagName === 'BR') {
|
if (tagName === 'BR') {
|
||||||
y += lineHeight;
|
y += localLineHeight;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,6 +218,22 @@ export class HtmlToImageConverter {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Special optimization: If the element is a product-name, print quantity and name inline
|
||||||
|
if (el.classList && el.classList.contains('product-name')) {
|
||||||
|
const qtyEl = el.querySelector('.qty') || el.querySelector('span:first-child');
|
||||||
|
const nameEl = el.querySelector('.text-wrap') || el.querySelector('span:nth-child(2)') || el.querySelector('span:last-child');
|
||||||
|
const qtyText = qtyEl ? qtyEl.textContent.trim() : '';
|
||||||
|
let nameText = nameEl ? nameEl.textContent.trim() : '';
|
||||||
|
if (!nameText && !qtyEl && el.textContent) {
|
||||||
|
nameText = el.textContent.trim();
|
||||||
|
}
|
||||||
|
if (qtyText || nameText) {
|
||||||
|
const combined = qtyText ? `${qtyText} ${nameText}` : nameText;
|
||||||
|
drawText(combined, textAlign, isBold, fontSize);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if element has only text content (no child elements)
|
// Check if element has only text content (no child elements)
|
||||||
const hasOnlyText = Array.from(el.childNodes).every(
|
const hasOnlyText = Array.from(el.childNodes).every(
|
||||||
node => node.nodeType === Node.TEXT_NODE
|
node => node.nodeType === Node.TEXT_NODE
|
||||||
@ -214,7 +242,7 @@ export class HtmlToImageConverter {
|
|||||||
if (hasOnlyText) {
|
if (hasOnlyText) {
|
||||||
const text = el.textContent.trim();
|
const text = el.textContent.trim();
|
||||||
if (text) {
|
if (text) {
|
||||||
drawText(text, textAlign, isBold);
|
drawText(text, textAlign, isBold, fontSize);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Process children
|
// Process children
|
||||||
@ -222,7 +250,7 @@ export class HtmlToImageConverter {
|
|||||||
if (child.nodeType === Node.TEXT_NODE) {
|
if (child.nodeType === Node.TEXT_NODE) {
|
||||||
const text = child.textContent.trim();
|
const text = child.textContent.trim();
|
||||||
if (text) {
|
if (text) {
|
||||||
drawText(text, textAlign, isBold);
|
drawText(text, textAlign, isBold, fontSize);
|
||||||
}
|
}
|
||||||
} else if (child.nodeType === Node.ELEMENT_NODE) {
|
} else if (child.nodeType === Node.ELEMENT_NODE) {
|
||||||
processElement(child);
|
processElement(child);
|
||||||
@ -232,7 +260,7 @@ export class HtmlToImageConverter {
|
|||||||
|
|
||||||
// Add spacing after block elements
|
// Add spacing after block elements
|
||||||
if (display === 'block' || tagName === 'DIV' || tagName === 'P' || tagName === 'TABLE') {
|
if (display === 'block' || tagName === 'DIV' || tagName === 'P' || tagName === 'TABLE') {
|
||||||
y += lineHeight / 2;
|
y += localLineHeight / 2;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -247,7 +275,7 @@ export class HtmlToImageConverter {
|
|||||||
const lines = allText.split('\n').filter(l => l.trim());
|
const lines = allText.split('\n').filter(l => l.trim());
|
||||||
y = padding;
|
y = padding;
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
drawText(line.trim());
|
drawText(line.trim(), 'left', false, 16);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user