This commit is contained in:
2025-08-12 15:04:01 +08:00
parent df3f5f5269
commit 6708fb8eeb
544 changed files with 75169 additions and 17 deletions
@@ -0,0 +1,127 @@
import Barcode from "../Barcode.js";
import { SHIFT, SET_A, SET_B, MODULO, STOP, FNC1, SET_BY_CODE, SWAP, BARS } from './constants';
// This is the master class,
// it does require the start code to be included in the string
class CODE128 extends Barcode {
constructor(data, options) {
super(data.substring(1), options);
// Get array of ascii codes from data
this.bytes = data.split('')
.map(char => char.charCodeAt(0));
}
valid() {
// ASCII value ranges 0-127, 200-211
return /^[\x00-\x7F\xC8-\xD3]+$/.test(this.data);
}
// The public encoding function
encode() {
const bytes = this.bytes;
// Remove the start code from the bytes and set its index
const startIndex = bytes.shift() - 105;
// Get start set by index
const startSet = SET_BY_CODE[startIndex];
if (startSet === undefined) {
throw new RangeError('The encoding does not start with a start character.');
}
if (this.shouldEncodeAsEan128() === true) {
bytes.unshift(FNC1);
}
// Start encode with the right type
const encodingResult = CODE128.next(bytes, 1, startSet);
return {
text:
this.text === this.data
? this.text.replace(/[^\x20-\x7E]/g, '')
: this.text,
data:
// Add the start bits
CODE128.getBar(startIndex) +
// Add the encoded bits
encodingResult.result +
// Add the checksum
CODE128.getBar((encodingResult.checksum + startIndex) % MODULO) +
// Add the end bits
CODE128.getBar(STOP)
};
}
// GS1-128/EAN-128
shouldEncodeAsEan128() {
let isEAN128 = this.options.ean128 || false;
if (typeof isEAN128 === 'string') {
isEAN128 = isEAN128.toLowerCase() === 'true';
}
return isEAN128;
}
// Get a bar symbol by index
static getBar(index) {
return BARS[index] ? BARS[index].toString() : '';
}
// Correct an index by a set and shift it from the bytes array
static correctIndex(bytes, set) {
if (set === SET_A) {
const charCode = bytes.shift();
return charCode < 32 ? charCode + 64 : charCode - 32;
} else if (set === SET_B) {
return bytes.shift() - 32;
} else {
return (bytes.shift() - 48) * 10 + bytes.shift() - 48;
}
}
static next(bytes, pos, set) {
if (!bytes.length) {
return { result: '', checksum: 0 };
}
let nextCode, index;
// Special characters
if (bytes[0] >= 200){
index = bytes.shift() - 105;
const nextSet = SWAP[index];
// Swap to other set
if (nextSet !== undefined) {
nextCode = CODE128.next(bytes, pos + 1, nextSet);
}
// Continue on current set but encode a special character
else {
// Shift
if ((set === SET_A || set === SET_B) && index === SHIFT) {
// Convert the next character so that is encoded correctly
bytes[0] = (set === SET_A)
? bytes[0] > 95 ? bytes[0] - 96 : bytes[0]
: bytes[0] < 32 ? bytes[0] + 96 : bytes[0];
}
nextCode = CODE128.next(bytes, pos + 1, set);
}
}
// Continue encoding
else {
index = CODE128.correctIndex(bytes, set);
nextCode = CODE128.next(bytes, pos + 1, set);
}
// Get the correct binary encoding and calculate the weight
const enc = CODE128.getBar(index);
const weight = index * pos;
return {
result: enc + nextCode.result,
checksum: weight + nextCode.checksum
};
}
}
export default CODE128;
@@ -0,0 +1,14 @@
import CODE128 from './CODE128.js';
import { A_START_CHAR, A_CHARS } from './constants';
class CODE128A extends CODE128 {
constructor(string, options) {
super(A_START_CHAR + string, options);
}
valid() {
return (new RegExp(`^${A_CHARS}+$`)).test(this.data);
}
}
export default CODE128A;
@@ -0,0 +1,14 @@
import CODE128 from './CODE128.js';
import { B_START_CHAR, B_CHARS } from './constants';
class CODE128B extends CODE128 {
constructor(string, options) {
super(B_START_CHAR + string, options);
}
valid() {
return (new RegExp(`^${B_CHARS}+$`)).test(this.data);
}
}
export default CODE128B;
@@ -0,0 +1,14 @@
import CODE128 from './CODE128.js';
import { C_START_CHAR, C_CHARS } from './constants';
class CODE128C extends CODE128 {
constructor(string, options) {
super(C_START_CHAR + string, options);
}
valid() {
return (new RegExp(`^${C_CHARS}+$`)).test(this.data);
}
}
export default CODE128C;
@@ -0,0 +1,15 @@
import CODE128 from './CODE128';
import autoSelectModes from './auto';
class CODE128AUTO extends CODE128{
constructor(data, options){
// ASCII value ranges 0-127, 200-211
if (/^[\x00-\x7F\xC8-\xD3]+$/.test(data)) {
super(autoSelectModes(data), options);
} else{
super(data, options);
}
}
}
export default CODE128AUTO;
@@ -0,0 +1,68 @@
import { A_START_CHAR, B_START_CHAR, C_START_CHAR, A_CHARS, B_CHARS, C_CHARS } from './constants';
// Match Set functions
const matchSetALength = (string) => string.match(new RegExp(`^${A_CHARS}*`))[0].length;
const matchSetBLength = (string) => string.match(new RegExp(`^${B_CHARS}*`))[0].length;
const matchSetC = (string) => string.match(new RegExp(`^${C_CHARS}*`))[0];
// CODE128A or CODE128B
function autoSelectFromAB(string, isA){
const ranges = isA ? A_CHARS : B_CHARS;
const untilC = string.match(new RegExp(`^(${ranges}+?)(([0-9]{2}){2,})([^0-9]|$)`));
if (untilC) {
return (
untilC[1] +
String.fromCharCode(204) +
autoSelectFromC(string.substring(untilC[1].length))
);
}
const chars = string.match(new RegExp(`^${ranges}+`))[0];
if (chars.length === string.length) {
return string;
}
return (
chars +
String.fromCharCode(isA ? 205 : 206) +
autoSelectFromAB(string.substring(chars.length), !isA)
);
}
// CODE128C
function autoSelectFromC(string) {
const cMatch = matchSetC(string);
const length = cMatch.length;
if (length === string.length) {
return string;
}
string = string.substring(length);
// Select A/B depending on the longest match
const isA = matchSetALength(string) >= matchSetBLength(string);
return cMatch + String.fromCharCode(isA ? 206 : 205) + autoSelectFromAB(string, isA);
}
// Detect Code Set (A, B or C) and format the string
export default (string) => {
let newString;
const cLength = matchSetC(string).length;
// Select 128C if the string start with enough digits
if (cLength >= 2) {
newString = C_START_CHAR + autoSelectFromC(string);
} else {
// Select A/B depending on the longest match
const isA = matchSetALength(string) > matchSetBLength(string);
newString = (isA ? A_START_CHAR : B_START_CHAR) + autoSelectFromAB(string, isA);
}
return newString.replace(
/[\xCD\xCE]([^])[\xCD\xCE]/, // Any sequence between 205 and 206 characters
(match, char) => String.fromCharCode(203) + char
);
};
@@ -0,0 +1,71 @@
// constants for internal usage
export const SET_A = 0;
export const SET_B = 1;
export const SET_C = 2;
// Special characters
export const SHIFT = 98;
export const START_A = 103;
export const START_B = 104;
export const START_C = 105;
export const MODULO = 103;
export const STOP = 106;
export const FNC1 = 207;
// Get set by start code
export const SET_BY_CODE = {
[START_A]: SET_A,
[START_B]: SET_B,
[START_C]: SET_C,
};
// Get next set by code
export const SWAP = {
101: SET_A,
100: SET_B,
99: SET_C,
};
export const A_START_CHAR = String.fromCharCode(208); // START_A + 105
export const B_START_CHAR = String.fromCharCode(209); // START_B + 105
export const C_START_CHAR = String.fromCharCode(210); // START_C + 105
// 128A (Code Set A)
// ASCII characters 00 to 95 (0–9, A–Z and control codes), special characters, and FNC 1–4
export const A_CHARS = "[\x00-\x5F\xC8-\xCF]";
// 128B (Code Set B)
// ASCII characters 32 to 127 (0–9, A–Z, a–z), special characters, and FNC 1–4
export const B_CHARS = "[\x20-\x7F\xC8-\xCF]";
// 128C (Code Set C)
// 00–99 (encodes two digits with a single code point) and FNC1
export const C_CHARS = "(\xCF*[0-9]{2}\xCF*)";
// CODE128 includes 107 symbols:
// 103 data symbols, 3 start symbols (A, B and C), and 1 stop symbol (the last one)
// Each symbol consist of three black bars (1) and three white spaces (0).
export const BARS = [
11011001100, 11001101100, 11001100110, 10010011000, 10010001100,
10001001100, 10011001000, 10011000100, 10001100100, 11001001000,
11001000100, 11000100100, 10110011100, 10011011100, 10011001110,
10111001100, 10011101100, 10011100110, 11001110010, 11001011100,
11001001110, 11011100100, 11001110100, 11101101110, 11101001100,
11100101100, 11100100110, 11101100100, 11100110100, 11100110010,
11011011000, 11011000110, 11000110110, 10100011000, 10001011000,
10001000110, 10110001000, 10001101000, 10001100010, 11010001000,
11000101000, 11000100010, 10110111000, 10110001110, 10001101110,
10111011000, 10111000110, 10001110110, 11101110110, 11010001110,
11000101110, 11011101000, 11011100010, 11011101110, 11101011000,
11101000110, 11100010110, 11101101000, 11101100010, 11100011010,
11101111010, 11001000010, 11110001010, 10100110000, 10100001100,
10010110000, 10010000110, 10000101100, 10000100110, 10110010000,
10110000100, 10011010000, 10011000010, 10000110100, 10000110010,
11000010010, 11001010000, 11110111010, 11000010100, 10001111010,
10100111100, 10010111100, 10010011110, 10111100100, 10011110100,
10011110010, 11110100100, 11110010100, 11110010010, 11011011110,
11011110110, 11110110110, 10101111000, 10100011110, 10001011110,
10111101000, 10111100010, 11110101000, 11110100010, 10111011110,
10111101110, 11101011110, 11110101110, 11010000100, 11010010000,
11010011100, 1100011101011
];
@@ -0,0 +1,6 @@
import CODE128 from './CODE128_AUTO.js';
import CODE128A from './CODE128A.js';
import CODE128B from './CODE128B.js';
import CODE128C from './CODE128C.js';
export {CODE128, CODE128A, CODE128B, CODE128C};