Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
16 changes: 16 additions & 0 deletions src/barcodes/code128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,22 @@ pub fn prepare_ucc_mode_data(content: &str) -> String {
format!("{}{}{}", ESCAPE_FNC_1, padded, check)
}

/// Prepare field data and human-readable text for ^BC mode D (UCC/EAN mode).
///
/// Parentheses and spaces are retained in the interpretation line but omitted
/// from the encoded symbol. The ZPL `>8` invocation inserts FNC1 into the
/// symbol and is not itself printable field data.
pub fn prepare_ean_mode_data(content: &str) -> (String, String) {
let fnc1 = ESCAPE_FNC_1.to_string();
let encoded: String = content
.replace(">8", &fnc1)
.chars()
.filter(|c| *c != '(' && *c != ')' && *c != ' ')
.collect();
let display = content.replace(">8", "");
(format!("{}{}", ESCAPE_FNC_1, encoded), display)
}

/// GS1 Mod-10 check digit calculation.
/// Rightmost digit gets weight 3, alternating 3/1 from right to left.
fn gs1_mod10_check(digits: &str) -> char {
Expand Down
22 changes: 10 additions & 12 deletions src/drawers/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,31 +520,29 @@ impl Renderer {
}
_ => {
// Modes U and D (UCC/EAN) automatically insert FNC1 at start per ZPL spec
let content_to_encode = match bc.barcode.mode {
let (content_to_encode, display_text) = match bc.barcode.mode {
BarcodeMode::Ucc => {
// Mode U: truncate to 19 digits, append GS1 Mod-10 check digit, prepend FNC1
barcodes::code128::prepare_ucc_mode_data(content)
(
barcodes::code128::prepare_ucc_mode_data(content),
content.clone(),
)
}
BarcodeMode::Ean => {
// Mode D: FNC1 prepended automatically; >8 in data = embedded FNC1 separator
// for chaining GS1 application identifiers; parentheses and spaces stripped
// from encoding but preserved in display text per ZPL spec.
let fnc1 = barcodes::code128::ESCAPE_FNC_1.to_string();
let for_encoding: String = content
.replace(">8", &fnc1)
.chars()
.filter(|c| *c != '(' && *c != ')' && *c != ' ')
.collect();
format!("{}{}", barcodes::code128::ESCAPE_FNC_1, for_encoding)
// from encoding but preserved in display text per ZPL spec. Invocation
// codes affect the symbol only and must not be printed as glyphs.
barcodes::code128::prepare_ean_mode_data(content)
}
_ => content.clone(),
_ => (content.clone(), content.clone()),
};
let img = barcodes::code128::encode_auto(
&content_to_encode,
bc.barcode.height,
bc.width,
)?;
(img, content.clone())
(img, display_text)
}
};

Expand Down
Binary file added testdata/diffs/code128_mode_d_fnc1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added testdata/diffs/code128_mode_d_fnc1_diff.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion testdata/diffs/diff_report_unit.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
║ barcode128_rotated │ zpl │ 0.24% │ 813x1626 │ 813x1626 │ GOOD(<1%) ║
║ cf_font_designator │ zpl │ 0.38% │ 813x1626 │ 812x1624 │ GOOD(<1%) ║
║ cf_font_no_orientation │ zpl │ 0.43% │ 813x1626 │ 812x1624 │ GOOD(<1%) ║
║ code128_mode_d_fnc1 │ zpl │ 0.74% │ 813x1626 │ 812x1624 │ GOOD(<1%) ║
║ cp850_hex_chars │ zpl │ 0.56% │ 813x1626 │ 812x1624 │ GOOD(<1%) ║
║ dhlparceluk_dhl_text │ zpl │ 0.45% │ 813x1626 │ 813x1626 │ GOOD(<1%) ║
║ dhlparceluk_ver │ zpl │ 0.05% │ 813x1626 │ 813x1626 │ GOOD(<1%) ║
Expand Down Expand Up @@ -66,5 +67,5 @@
║ usps_priority_mail │ zpl │ 0.54% │ 813x1626 │ 813x1626 │ GOOD(<1%) ║
║ usps_test_merchant │ zpl │ 0.16% │ 813x1626 │ 813x1626 │ GOOD(<1%) ║
╠══════════════════════════════════════════════════════════════════════════════╣
║ Summary: 62 total │ 8 perfect │ 44 good │ 7 minor │ 3 moderate │ 0 high │ 0 skip │ 0 err
║ Summary: 63 total │ 8 perfect │ 45 good │ 7 minor │ 3 moderate │ 0 high │ 0 skip │ 0 err
╚══════════════════════════════════════════════════════════════════════════════╝
Binary file added testdata/unit/code128_mode_d_fnc1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions testdata/unit/code128_mode_d_fnc1.zpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
^XA
^PW812^LL400
^BY2,2.5,145
^FO30,30
^BCN,,Y,N,N,D
^FD(91)0005886>8(10)0000410549>8(99)05^FS
^XZ
4 changes: 4 additions & 0 deletions tests/e2e_golden.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ fn golden_barcode128_mode_d() {
golden_zpl_with_tolerance("barcode128_mode_d", 2.0);
}
#[test]
fn golden_code128_mode_d_fnc1() {
golden_zpl_with_tolerance("code128_mode_d_fnc1", 1.0);
}
#[test]
fn golden_barcode128_mode_n() {
golden_zpl_with_tolerance("barcode128_mode_n", 2.0);
}
Expand Down
13 changes: 13 additions & 0 deletions tests/unit_barcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,19 @@ fn code39_empty_input_handled() {
let _result = code39::encode("", 100, 3, 2);
}

#[test]
fn code128_ean_mode_keeps_ai_formatting_but_hides_fnc1_invocations() {
let (encoded, display) = code128::prepare_ean_mode_data("(91)0005886>8(10)0000410549>8(99)05");
let fnc1 = code128::ESCAPE_FNC_1;

assert_eq!(
encoded,
format!("{fnc1}910005886{fnc1}100000410549{fnc1}9905")
);
assert_eq!(display, "(91)0005886(10)0000410549(99)05");
assert!(!display.contains(">8"));
}

// --- EAN-13 ---

#[test]
Expand Down
Loading