Repository navigation
feat(barcode): EAN/UPC extended guard tails via bwip-raw canvas #142
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -197,6 +197,58 @@ function bwipScale1D( | |
|
|
||
| export { eanCheckDigit, upceCheckDigit } from "../../lib/barcodeCheckDigits"; | ||
|
|
||
| /** Sub-pixel overlap so adjacent module rects don't leave hairline gaps. */ | ||
| const RAW_BAR_SEAM = 0.4; | ||
|
|
||
| interface BwipRawLinear { | ||
| sbs?: number[]; | ||
| bbs?: number[]; | ||
| } | ||
|
|
||
| /** Bars + extended guard tails in one fillRect pass via bwip raw | ||
| * geometry. `includetext: true` makes bwip mark guards with `bbs<0`; | ||
| * we never draw text it would emit. */ | ||
| export function renderEanUpcRawCanvas( | ||
| type: EanUpcType, | ||
| text: string, | ||
| modulePxInt: number, | ||
| barHeightPx: number, | ||
| tailHeightPx: number, | ||
| ): HTMLCanvasElement | null { | ||
| if (modulePxInt <= 0 || barHeightPx <= 0) return null; | ||
| let stack: BwipRawLinear[]; | ||
| try { | ||
| stack = bwipjs.raw({ bcid: type, text, includetext: true } as never) as BwipRawLinear[]; | ||
| } catch { | ||
| return null; | ||
| } | ||
| const g = stack?.[0]; | ||
| if (!g?.sbs) return null; | ||
| let totalModules = 0; | ||
| for (const w of g.sbs) totalModules += w; | ||
| const canvas = document.createElement("canvas"); | ||
| canvas.width = totalModules * modulePxInt; | ||
| canvas.height = barHeightPx + Math.max(0, tailHeightPx); | ||
| const ctx = canvas.getContext("2d"); | ||
| if (!ctx) return null; | ||
| ctx.fillStyle = "#000000"; | ||
| let cx = 0; | ||
| let isBar = true; | ||
| let barIdx = 0; | ||
| for (const w of g.sbs) { | ||
| const wPx = w * modulePxInt; | ||
| if (isBar) { | ||
| const isGuard = (g.bbs?.[barIdx] ?? 0) < 0; | ||
| const h = isGuard ? canvas.height : barHeightPx; | ||
| ctx.fillRect(cx, 0, wPx + RAW_BAR_SEAM, h); | ||
| barIdx++; | ||
| } | ||
| cx += wPx; | ||
| isBar = !isBar; | ||
| } | ||
| return canvas; | ||
| } | ||
|
Comment on lines
+211
to
+250
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update export function renderEanUpcRawCanvas(
type: EanUpcType,
text: string,
modulePxInt: number,
barHeightPx: number,
tailHeightPx: number,
extendGuards: boolean,
): HTMLCanvasElement | null {
const barH = Math.round(barHeightPx);
const tailH = Math.round(tailHeightPx);
if (modulePxInt <= 0 || barH <= 0) return null;
let stack: BwipRawLinear[];
try {
stack = bwipjs.raw({ bcid: type, text, includetext: true } as never) as BwipRawLinear[];
} catch {
return null;
}
const g = stack?.[0];
if (!g?.sbs) return null;
let totalModules = 0;
for (const w of g.sbs) totalModules += w;
if (totalModules <= 0) return null;
const canvas = document.createElement("canvas");
canvas.width = totalModules * modulePxInt;
canvas.height = barH + Math.max(0, tailH);
const ctx = canvas.getContext("2d");
if (!ctx) return null;
ctx.fillStyle = "#000000";
let cx = 0;
let isBar = true;
let barIdx = 0;
for (const w of g.sbs) {
const wPx = w * modulePxInt;
if (isBar) {
const isGuard = extendGuards && (g.bbs?.[barIdx] ?? 0) < 0;
const h = isGuard ? canvas.height : barH;
ctx.fillRect(cx, 0, wPx + RAW_BAR_SEAM, h);
barIdx++;
}
cx += wPx;
isBar = !isBar;
}
return canvas;
} |
||
|
|
||
| // Forcing Code B keeps module count in sync with Labelary (^BC default). | ||
| // Returns null for chars outside ASCII 32..126. | ||
| function toCode128BRaw(text: string): string | null { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When
printInterpretationis disabled (printInterpEnabledis false), the EAN/UPC layout still reserves the 13-dot text zone at the bottom of the barcode to match the firmware-reserved footprint. However, passingtailHeightPx = 0torenderEanUpcRawCanvasresults in a canvas height of onlybarHeightPx. Since theKImageheight is unconditionally set toub.barH + EAN_TEXT_ZONE_DOTS, the canvas image gets vertically stretched by ~13%, causing blurry rendering and overlapping the reserved text zone.To fix this, we should always pass the full
EAN_TEXT_ZONE_DOTSheight astailHeightPxto ensure the canvas height matches theKImageheight, and passprintInterpEnabledas a boolean flag to control whether the guard tails actually extend into this zone.