Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/components/Canvas/BarcodeObject.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,13 @@ export function BarcodeObject({
!ObjectRegistry[obj.type]?.interpretationLocked &&
!!(obj.props as { printInterpretation?: boolean }).printInterpretation;
const printInterp = isUpright && printInterpEnabled;
// Cross-type access: this block runs for every barcode and reads moduleWidth
// generically (textFontSize is computed for HRI text rendering downstream).
// Unlike buildBwipOptions, this function isn't switch-structured by obj.type,
// so per-case narrowing would require restructuring the whole block. The
// cast + fallback stays as the documented boundary between cross-type code
// and the per-type required-typed schemas (2D types without moduleWidth fall
// through with the default; their branches don't render HRI text anyway).
const moduleWidth =
(obj.props as { moduleWidth?: number }).moduleWidth ?? 2;
const textFontSize = Math.max(dotsToPx(moduleWidth * 10, scale, dpmm), 6);
Expand Down
53 changes: 35 additions & 18 deletions src/components/Canvas/bwipHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,23 @@ export function get1DBwipScale(
return Math.max(1, Math.round(dotsToPx(moduleWidth, scale, dpmm)));
}

/**
* Render-scale for 1D barcodes: integer-aligned per-module scale when the
* caller supplies the canvas scale + dpmm, otherwise the BWIP_SCALE default.
* Wrapping the branch lets per-type cases pass their own (narrowed,
* required-typed) `moduleWidth` instead of going through a cast at the
* generic top of buildBwipOptions.
*/
function bwipScale1D(
moduleWidth: number,
renderScale: number | undefined,
renderDpmm: number | undefined,
): number {
return renderScale != null && renderDpmm != null
? get1DBwipScale(moduleWidth, renderScale, renderDpmm)
: BWIP_SCALE;
}

export function eanCheckDigit(digits: string, w0: number, w1: number): string {
let sum = 0;
for (let i = 0; i < digits.length; i++)
Expand Down Expand Up @@ -232,14 +249,6 @@ export function buildBwipOptions(
const bcid = BCID[obj.type];
if (!bcid) return null;

// For 1D barcodes, choose an integer-aligned scale so module widths map
// exactly to display pixels (no fractional upscaling / anti-aliasing).
const mw = (obj.props as { moduleWidth?: number }).moduleWidth ?? 2;
const scale1D =
renderScale != null && renderDpmm != null
? get1DBwipScale(mw, renderScale, renderDpmm)
: BWIP_SCALE;

// bwip-js takes the same N/R/I/B letters ZPL does for symbol orientation;
// emitting it post-build means the produced bitmap is already rotated and
// its dimensions are the post-rotation extents — no Konva-side rotation math
Expand All @@ -254,26 +263,28 @@ export function buildBwipOptions(
case "upca":
case "upce": {
const p = obj.props;
const scale = bwipScale1D(p.moduleWidth, renderScale, renderDpmm);
let text: string;
if (obj.type === "upce") {
const r = p.content || "000000";
text = r.length === 6 ? `0${r}` : r;
} else {
text = p.content || "0";
}
opts = { bcid, text, scale: scale1D, height: 10 };
opts = { bcid, text, scale, height: 10 };
break;
}
case "code128": {
const p = obj.props as { content?: string };
const p = obj.props;
const scale = bwipScale1D(p.moduleWidth, renderScale, renderDpmm);
const text = p.content || "0";
// Note: ZPL ^BC e=Y (checkDigit) only prints the MOD-10 digit in the
// interpretation line — it does NOT append it to the encoded barcode data.
const rawB = toCode128BRaw(text);
if (rawB) {
opts = { bcid, text: rawB, raw: true, scale: scale1D, height: 10 };
opts = { bcid, text: rawB, raw: true, scale, height: 10 };
} else {
opts = { bcid, text, scale: scale1D, height: 10 };
opts = { bcid, text, scale, height: 10 };
}
break;
}
Expand All @@ -286,6 +297,7 @@ export function buildBwipOptions(
case "codabar":
case "plessey": {
const p = obj.props;
const scale = bwipScale1D(p.moduleWidth, renderScale, renderDpmm);
// Code39/Codabar/Plessey only encode uppercase letters. Zebra firmware
// (and Labelary) silently uppercase lowercase input; bwip-js does not and
// throws instead, which would crash the canvas for any imported ZPL with
Expand All @@ -294,35 +306,39 @@ export function buildBwipOptions(
const needsUpper = obj.type === "code39" || obj.type === "codabar" || obj.type === "plessey";
const raw = p.content || "0";
const text = needsUpper ? raw.toUpperCase() : raw;
opts = { bcid, text, scale: scale1D, height: 10 };
opts = { bcid, text, scale, height: 10 };
break;
}
case "msi": {
const p = obj.props;
const scale = bwipScale1D(p.moduleWidth, renderScale, renderDpmm);
// Zebra always encodes a Mod10 check digit in MSI regardless of the ^BM e=N
// parameter (which only suppresses it in the interpretation line).
opts = { bcid, text: p.content || "0", scale: scale1D, height: 10, includecheck: true };
opts = { bcid, text: p.content || "0", scale, height: 10, includecheck: true };
break;
}
case "postal": {
const p = obj.props;
opts = { bcid, text: p.content || "0", scale: scale1D, height: 10 };
const scale = bwipScale1D(p.moduleWidth, renderScale, renderDpmm);
opts = { bcid, text: p.content || "0", scale, height: 10 };
break;
}
case "logmars": {
const p = obj.props;
const scale = bwipScale1D(p.moduleWidth, renderScale, renderDpmm);
// LOGMARS is a Code39 subset; same uppercase rule applies.
opts = {
bcid,
text: (p.content || "0").toUpperCase(),
scale: scale1D,
scale,
height: 10,
includecheck: true,
};
break;
}
case "gs1databar": {
const p = obj.props;
const scale = bwipScale1D(p.moduleWidth, renderScale, renderDpmm);
const sym = p.symbology;
const isExpanded = GS1_DATABAR_EXPANDED_SYMBOLOGIES.has(sym);
// bwip-js needs (AI)data parens; canonical model stores raw digits.
Expand All @@ -333,7 +349,7 @@ export function buildBwipOptions(
opts = {
bcid: GS1_DATABAR_BCID[sym],
text,
scale: scale1D,
scale,
height: 10,
paddingheight: 2,
...(sym === 7 ? { segments: p.segments ?? GS1_DATABAR_DEFAULT_SEGMENTS } : {}),
Expand All @@ -342,13 +358,14 @@ export function buildBwipOptions(
}
case "planet": {
const p = obj.props;
const scale = bwipScale1D(p.moduleWidth, renderScale, renderDpmm);
let raw = (p.content || "0").replace(/\D/g, "");
if (raw.length < 11) raw = raw.padStart(11, "0");
else if (raw.length === 12) raw = raw.padStart(13, "0");
opts = {
bcid,
text: raw,
scale: scale1D,
scale,
height: 10,
includecheck: true,
};
Expand Down