source: trunk/Packages/lazbarcodes/src/lbc_plessey.pas

Last change on this file was 123, checked in by chronos, 3 years ago
  • Added: QR code image visible in contact others tab. It can be saved as image to file.
File size: 6.8 KB
Line 
1{ lbc_plessey - Handles plessey bar codes
2
3 Based on Zint (done by Robin Stuart and the Zint team)
4 http://github.com/zint/zint
5 and Pascal adaption by TheUnknownOnes
6 http://theunknownones.net
7
8 Refactoring: W.Pamler
9
10 The results were checked against https://www.free-barcode-generator.net/msi/
11}
12
13unit lbc_plessey;
14
15{$mode objfpc}{$H+}
16
17interface
18
19uses
20 SysUtils, zint;
21
22function plessey(ASymbol: PZintSymbol; const ASource: String): Integer;
23function msi_plessey(ASymbol: PZintSymbol; const ASource: String): Integer;
24
25implementation
26
27uses
28 lbc_helper;
29
30const
31 SSET = '0123456789ABCDEF';
32
33 // Idea: These are the bits in a nibble: 13 = 0, 31 = 1, LSB at left
34 PlesseyTable: array[0..15] of String = (
35 '13131313', '31131313', '13311313', '31311313', '13133113',
36 '31133113', '13313113', '31313113', '13131331', '31131331',
37 '13311331', '31311331', '13133131', '31133131', '13313131',
38 '31313131'
39 );
40
41 MSITable: array[0..9] of String = (
42 '12121212', '12121221', '12122112', '12122121', '12211212',
43 '12211221', '12212112', '12212121', '21121212', '21121221'
44 );
45
46
47{-------------------------------------------------------------------------------
48 Not MSI/Plessey, but the older Plessey standard
49-------------------------------------------------------------------------------}
50function CheckSum_Plessey(ASource: String): String;
51const
52 grid: array[0..8] of Byte = (1,1,1,1,0,1,0,0,1);
53var
54 i, j, check: Integer;
55 checkptr: array of byte = nil;
56begin
57 SetLength(checkptr, Length(ASource)* 4 + 8);
58
59 for i := 0 to Length(ASource) - 1 do
60 begin
61 j := i+1;
62 check := pos(ASource[j], SSET) - 1;
63 checkptr[4*i] := check and 1;
64 checkptr[4*i+1] := (check shr 1) and 1;
65 checkptr[4*i+2] := (check shr 2) and 1;
66 checkptr[4*i+3] := (check shr 3) and 1;
67 end;
68
69 // CRC check digit code adapted from code by Leonid A. Broukhis
70 // used in GNU Barcode
71 for i := 0 to 4 * Length(ASource) - 1 do
72 begin
73 if (checkptr[i] <> 0) then
74 for j := 0 to 8 do
75 checkptr[i+j] := checkptr[i+j] xor grid[j];
76 end;
77
78 check := 0;
79 for i := 0 to 7 do
80 if checkptr[Length(ASource) * 4 + i] = 1 then
81 check := check or (1 shl i);
82
83 Result := SSET[succ(check and $0F)] + SSET[succ((check and $F0) shr 4)];
84end;
85
86function plessey(ASymbol: PZintSymbol; const ASource: String): Integer;
87begin
88 Result := basic_encoder(ASymbol, ASource,
89 65, SSET, '31311331', PlesseyTable, '331311313', @CheckSum_Plessey, false);
90 if Result = 0 then
91 ASymbol^.SetText(ASource);
92end;
93
94
95{-------------------------------------------------------------------------------
96 MSI Plessey Modulo 10 and Modulo 11 check digit calculation routines
97
98 Algorithm from Barcode Island, http://www.barcodeisland.com/
99 (wp: page no longer available)
100-------------------------------------------------------------------------------}
101function PartialString(ASource: String; OddIndices: boolean): String;
102var
103 i: Integer;
104begin
105 Result := '';
106 if OddIndices then i := 1 else i := 2;
107 while i <= Length(ASource) do
108 begin
109 Result := Result + ASource[i];
110 inc(i, 2);
111 end;
112end;
113
114function SumOfDigits(s: String): Integer;
115var
116 i: Integer;
117begin
118 Result := 0;
119 for i := 1 to Length(s) do
120 Result := Result + StrToInt(s[i]);
121end;
122
123function SumOfDigits(s: String; OddIndices: Boolean): Integer;
124var
125 i: Integer;
126begin
127 Result := 0;
128 if OddIndices then i := 1 else i := 2;
129 while i <= Length(s) do
130 begin
131 Result := Result + StrToInt(s[i]);
132 inc(i, 2);
133 end;
134end;
135
136{ Calculation of a mod 10 check digit.
137 Algorithm from Barcode Island, http://www.barcodeisland.com/
138 (wp: page no longer available) }
139function CheckSum_Plessey_Mod10(ASource: String): String;
140var
141 s: String;
142 sum: Integer;
143 check: Integer;
144begin
145 s := PartialString(ASource, odd(Length(ASource)));
146 s := IntToStr(StrToInt(s)*2);
147 sum := SumOfDigits(s) + SumOfDigits(ASource, not odd(Length(ASource)));
148 check := 10 - sum mod 10;
149 if check = 10 then check := 0;
150 Result := IntToStr(check);
151end;
152
153{ Calculation of two mod 10 check digits.
154 Based on above Barcode Island code. }
155function CheckSum_Plessey_Mod10_Mod10(ASource: String): String;
156var
157 s: String;
158 sum: Integer;
159 check: Integer;
160begin
161 // Calculate first check digit
162 Result := CheckSum_Plessey_Mod10(ASource);
163
164 // Calculate second check digit
165 s := PartialString(ASource, not odd(Length(ASource))) + Result;
166 s := IntToStr(StrToInt(s)*2);
167 sum := SumOfDigits(s) + SumOfDigits(ASource, odd(Length(ASource)));
168 check := 10 - sum mod 10;
169 if check = 10 then check := 0;
170
171 Result := Result + IntToStr(check);
172end;
173
174{ Calculates a Modulo 11 check digit using the system discussed on Wikipedia -
175 see http://en.wikipedia.org/wiki/Talk:MSI_Barcode
176 Uses the IBM weight system }
177function CheckSum_Plessey_Mod11(ASource: String): String;
178var
179 i, sum, weight, check: Integer;
180begin
181 sum := 0;
182 weight := 2;
183 for i := Length(ASource) downto 1 do
184 begin
185 inc(sum, weight * StrToInt(ASource[i]));
186 inc(weight);
187 if weight > 7 then weight := 2;
188 end;
189 check := (11 - sum mod 11) mod 11;
190
191 Result := IntToStr(check);
192end;
193
194{ Calculates a Modulo 11 and a Modulo 10 check digit.
195 Combines the Barcode Island and Wikipedia code
196 Verified against http://www.bokai.com/BarcodeJSP/applet/BarcodeSampleApplet.htm
197 Weighted using the IBM system }
198function Checksum_Plessey_Mod11_Mod10(ASource: String): String;
199var
200 ch1, ch2: string;
201begin
202 // Calculate first digit (mod 11)
203 ch1 := Checksum_Plessey_Mod11(ASource);
204
205 // Calculated second digit (mod 10);
206 ch2 := CheckSum_Plessey_Mod10(ASource + ch1);
207
208 Result := ch1 + ch2;
209end;
210
211
212{ ------------------------------------------------------------------------------
213 Main MSI/Plessey routine
214-------------------------------------------------------------------------------}
215function msi_plessey(ASymbol: PZintSymbol; const ASource: String): Integer;
216var
217 maxlen: Integer;
218 checkSumFunc: TCheckSumFunc;
219begin
220 case ASymbol^.Option_2 of
221 1: begin // one mod 10 check digit
222 checkSumFunc := @CheckSum_Plessey_Mod10;
223 maxlen := 18;
224 end;
225 2: begin // two mod 10 check digits
226 checksumfunc := @CheckSum_Plessey_Mod10_Mod10;
227 maxlen := 18;
228 end;
229 3: begin // one mod 11 check digit
230 checksumfunc := @Checksum_Plessey_Mod11;
231 maxlen := 55;
232 end;
233 4: begin // a mod 11 and a mod 10 check digit
234 checksumfunc := @Checksum_Plessey_Mod11_Mod10;
235 maxLen := 18;
236 end;
237 else
238 begin // no check digits
239 checkSumFunc := nil;
240 maxLen := 55;
241 end;
242 end;
243
244 Result := basic_encoder(ASymbol, ASource,
245 maxlen, NEON, '21', MSITable, '121', checksumFunc, false);
246end;
247
248end.
249
Note: See TracBrowser for help on using the repository browser.