source: trunk/Packages/lazbarcodes/src/lbc_2of5.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: 9.9 KB
Line 
1{ lbc_2of5.pas - Handles "two-of-five" code variants
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 Generated bar codes checked against
11 https://products.aspose.app/barcode/de/generate/
12}
13
14unit lbc_2of5;
15
16{$mode objfpc}{$H+}
17
18interface
19
20uses
21 zint;
22
23{ Code 2 of 5 Matrix }
24function matrix_two_of_five(ASymbol: PZintSymbol; const ASource: String): Integer;
25
26{ Code 2 of 5 IATA }
27function iata_two_of_five(ASymbol: PZintSymbol; const ASource: String): Integer;
28
29{ Code 2 of 5 Industrial }
30function industrial_two_of_five(ASymbol: PZintSymbol; const ASource: String): Integer;
31
32{ Code 2 of 5 Data Logic }
33function logic_two_of_five(ASymbol: PZintSymbol; const ASource: String): Integer;
34
35{ Code 2 of 5 Interleaved }
36function interleaved_two_of_five(ASymbol: PZintSymbol; const ASource: String): Integer;
37
38{ ITF-14 }
39function itf14(ASymbol: PZintSymbol; const ASource: String): Integer;
40
41{ Deutsche Post Identcode }
42function dpident(ASymbol: PZintSymbol; const ASource: String): Integer;
43
44{ Deutsche Post Leitcode }
45function dpleit(ASymbol: PZintSymbol; const ASource: String): Integer;
46
47
48implementation
49
50uses
51 SysUtils, lbc_helper;
52
53const
54 C25MatrixTable: array[0..9] of String = (
55 '113311', '311131', '131131', '331111', '113131',
56 '313111', '133111', '111331', '311311', '131311'
57 );
58
59 C25IndustTable: array[0..9] of String = (
60 '1111313111', '3111111131',
61 '1131111131', '3131111111',
62 '1111311131', '3111311111',
63 '1131311111', '1111113131',
64 '3111113111', '1131113111'
65 );
66
67 C25InterTable: array[0..9] of String = (
68 '11331', '31113', '13113', '33111', '11313',
69 '31311', '13311', '11133', '31131', '13131'
70 );
71
72function check_digit(count: Integer): Char; inline;
73begin
74 Result := itoc((10 - count mod 10) mod 10);
75end;
76
77{ Calculates the check digit for ITF-14 It is the same method as used for EAN-13 }
78function CheckSum_EAN13(ASource: String): String;
79var
80 i,n, sum: Integer;
81begin
82 sum := 0;
83 for i := Length(ASource) downto 1 do
84 begin
85 n := ctoi(ASource[i]);
86 inc(sum, n);
87 if odd(i) then
88 Inc(sum, 2 * n);
89 end;
90 Result := check_digit(sum);
91end;
92
93{ Calculates the check sum digit for Deutsche Post codes. }
94function CheckSum_DP(ASource: String): String;
95var
96 i, n, sum: Integer;
97begin
98 sum := 0;
99 for i := Length(ASource) downto 1 do
100 begin
101 n := ctoi(ASource[i]);
102 inc(sum, 4*n);
103 if not odd(i) then
104 inc(sum, 5*n);
105 end;
106 Result := check_digit(sum);
107end;
108
109
110{ Basic encoder for interleaved two-of-five barcodes - they all work in
111 the same way, only with different parameters:
112 MaxLen - maximum length of input string
113 AllowedChars - a string containing the allowed characters for this barcode type
114 StartCode - starting code pattern
115 CharCodes - code pattern for each allowed character
116 StopCode - ending code pattern.
117 CheckCharsFunc - function to calculate a checksum
118}
119function basic_interleaved_two_of_five(ASymbol: PZIntSymbol; const ASource: String;
120 MaxLen: Integer; const AllowedChars, StartCode: String;
121 const CharCodes: array of string; const StopCode: String;
122 CheckSumFunc: TCheckSumFunc): Integer;
123var
124 i, j: Integer;
125 src, dest, bars, spaces: String;
126begin
127 if Length(ASource) > MaxLen then
128 begin
129 ASymbol^.SetErrorText('Input too long (max ' + IntToStr(MaxLen) + ' digits).');
130 Result := ERROR_TOO_LONG;
131 exit;
132 end;
133
134 Result := is_sane(AllowedChars, ASource);
135 if Result = ERROR_INVALID_DATA then
136 begin
137 ASymbol^.SetErrorText('Invalid characters in data.');
138 exit;
139 end;
140
141 src := ASource;
142
143 // Add check digit(s) if a calculation function is provided
144 if CheckSumFunc <> nil then
145 src := src + CheckSumFunc(src);
146
147 // Input must be an even number of characters for Interlaced 2 of 5 to work:
148 // if an odd number of characters has been entered then add a leading zero.
149 if odd(Length(src)) then
150 src := '0' + src;
151
152 // START character
153 dest := StartCode;
154
155 // Add encoded input string characters, but in an interleaved way
156 i := 1;
157 while i <= Length(src) do
158 begin
159 // Look up the bars and the spaces and put them in two strings
160 bars := '';
161 lookup(AllowedChars, CharCodes, src[i], bars);
162 spaces := '';
163 lookup(AllowedChars, CharCodes, src[i + 1], spaces);
164
165 // Then merge (interlace) the strings together
166 for j := 1 to 5 do
167 dest := dest + bars[j] + spaces[j];
168
169 Inc(i, 2);
170 end;
171
172 // STOP character
173 dest := dest + StopCode;
174
175 // Create symbol
176 expand(ASymbol, dest);
177
178 // Store human-readable text
179 ASymbol^.SetText(src);
180end;
181
182
183{-------------------------------------------------------------------------------
184 Code 2 of 5 Standard (Code 2 of 5 Matrix)
185-------------------------------------------------------------------------------}
186function matrix_two_of_five(ASymbol: PZintSymbol; const ASource: String): Integer;
187begin
188 Result := basic_encoder(ASymbol, ASource,
189 80, NEON, '411111', C25MatrixTable, '41111', nil, false
190 );
191end;
192
193{-------------------------------------------------------------------------------
194 Code 2 of 5 Industrial
195-------------------------------------------------------------------------------}
196function industrial_two_of_five(ASymbol: PZintSymbol; const ASource: String): Integer;
197begin
198 Result := basic_encoder(ASymbol, ASource,
199 45, NEON, '313111', C25IndustTable, '31113', nil, false
200 );
201end;
202
203{-------------------------------------------------------------------------------
204 Code 2 of 5 IATA
205-------------------------------------------------------------------------------}
206function iata_two_of_five(ASymbol: PZintSymbol; const ASource: string): Integer;
207begin
208 Result := basic_encoder(ASymbol, ASource,
209 45, NEON, '1111', C25IndustTable, '311', nil, false
210 );
211end;
212
213{-------------------------------------------------------------------------------
214 Code 2 of 5 Data Logic
215-------------------------------------------------------------------------------}
216function logic_two_of_five(ASymbol: PZintSymbol; const ASource: String): Integer;
217begin
218 Result := basic_encoder(ASymbol, ASource,
219 80, NEON, '1111', C25MatrixTable, '311', nil, false
220 );
221end;
222
223
224{-------------------------------------------------------------------------------
225 Code 2 of 5 Interleaved
226-------------------------------------------------------------------------------}
227function interleaved_two_of_five(ASymbol: PZintSymbol; const ASource: String): Integer;
228begin
229 Result := basic_interleaved_two_of_five(ASymbol, ASource,
230 89, NEON, '1111', C25InterTable, '311', nil);
231end;
232
233
234{-------------------------------------------------------------------------------
235 ITF-14
236-------------------------------------------------------------------------------}
237function itf14(ASymbol: PZintSymbol; const ASource: String): Integer;
238const
239 MaxLength = 13;
240var
241 n: Integer; // number of filler zeros
242 src: String;
243begin
244 if Length(ASource) < MaxLength then
245 begin
246 n := MaxLength - Length(ASource);
247 src := StringOfChar('0', n) + ASource;
248 end else
249 src := ASource;
250
251 Result := basic_interleaved_two_of_five(ASymbol, src,
252 MaxLength, NEON, '1111', C25InterTable, '311', @CheckSum_EAN13);
253end;
254
255
256{-------------------------------------------------------------------------------
257 Deutsche Post Leitcode
258
259 Deutsche Post Leitcode encodes a string of 14 digits, as follows:
260 - Five-digit postal code
261 - Three-digit street identifier
262 - Three-digit house number
263 - Two-digit product code
264 - One-digit check digit
265 (https://barcodeguide.seagullscientific.com/Content/Symbologies/Leitcode.htm)
266-------------------------------------------------------------------------------}
267function dpleit(ASymbol: PZintSymbol; const ASource: String): Integer;
268const
269 MaxLength = 13;
270var
271 n: Integer; // Number of filler zeros
272 s: String;
273begin
274 if Length(ASource) < MaxLength then
275 begin
276 n := MaxLength - Length(ASource);
277 s := StringOfChar('0', n) + ASource;
278 end else
279 s := ASource;
280
281 Result := basic_interleaved_two_of_five(ASymbol, s,
282 MaxLength, NEON, '1111', C25InterTable, '311', @CheckSum_DP);
283
284 // Grouped output: "12345678901234" --> "12345.678.901.23 4"
285 if (Result = 0) and (ASymbol^.Option and OPTION_GROUPED_CHARS = OPTION_GROUPED_CHARS) then
286 begin
287 s := ASymbol^.GetText;
288 Insert(' ', s, 14);
289 Insert('.', s, 12);
290 Insert('.', s, 9);
291 Insert('.', s, 6);
292 ASymbol^.SetText(s);
293 end;
294end;
295
296{-------------------------------------------------------------------------------
297 Deutsche Post Identcode
298
299 Deutsche Post Identcode encodes a string of (11 or) 12 digits, as follows:
300 - Two-digit mail center distribution identifier
301 - Three-digit customer code
302 - Six-digit delivery identifier
303 - One-digit check digit (optional - here it is always included.)
304 (https://barcodeguide.seagullscientific.com/Content/Symbologies/Identcode.htm)
305-------------------------------------------------------------------------------}
306function dpident(ASymbol: PZintSymbol; const ASource: string): Integer;
307const
308 MaxLength = 11;
309var
310 n: Integer; // Number of filler zeros
311 s: String;
312begin
313 if Length(ASource) < MaxLength then
314 begin
315 n := MaxLength - Length(ASource);
316 s := StringOfChar('0', n) + ASource;
317 end else
318 s := ASource;
319
320 Result := basic_interleaved_two_of_five(ASymbol, s,
321 MaxLength, NEON, '1111', C25InterTable, '311', @CheckSum_DP);
322
323 // Grouped output: "12345678901" --> "12.345 678.901 2"
324 if (Result = 0) and (ASymbol^.Option and OPTION_GROUPED_CHARS = OPTION_GROUPED_CHARS) then
325 begin
326 s := ASymbol^.GetText;
327 Insert(' ', s, 12);
328 Insert('.', s, 9);
329 Insert(' ', s, 6);
330 Insert('. ', s, 3);
331 ASymbol^.SetText(s);
332 end;
333end;
334
335end.
336
Note: See TracBrowser for help on using the repository browser.