/components/lazreport/source/barcode.pas

http://github.com/graemeg/lazarus · Pascal · 1645 lines · 1219 code · 203 blank · 223 comment · 79 complexity · fcedb6deb92b4773f1f56c85f3cc1717 MD5 · raw file

  1. unit Barcode;
  2. {
  3. Barcode Component
  4. Version 1.5 (23 Apr 1999)
  5. Copyright 1998-99 Andreas Schmidt and friends
  6. Freeware
  7. for use with Delphi 2/3/4
  8. this component is for private use only !
  9. i'am not responsible for wrong barcodes
  10. bug-reports, enhancements:
  11. mailto:shmia@bizerba.de or a_j_schmidt@rocketmail.com
  12. get latest version from
  13. http://members.tripod.de/AJSchmidt/index.html
  14. thanx to Nikolay Simeonov, Wolfgang Koranda, Norbert Waas,
  15. Richard Hugues and Olivier Guilbaud.
  16. Diese Komponente darf nur in privaten Projekten verwendet werden.
  17. Die Weitergabe von veränderte Dateien ist nicht zulässig.
  18. Für die Korrektheit der erzeugten Barcodes kann keine Garantie
  19. übernommen werden.
  20. Anregungen, Bug-Reports, Danksagungen an:
  21. mailto:shmia@bizerba.de
  22. History:
  23. ----------------------------------------------------------------------
  24. Version 1.0:
  25. - initial release
  26. Version 1.1:
  27. - more comments
  28. - changed function Code_93Extended (now correct ?)
  29. Version 1.2:
  30. - Bugs (found by Nikolay Simeonov) removed
  31. Version 1.3:
  32. - EAN8/EAN13 added by Wolfgang Koranda (wkoranda@csi.com)
  33. Version 1.4:
  34. - Bug (found by Norbert Waas) removed
  35. Component must save the Canvas-properties Font,Pen and Brush
  36. Version 1.5:
  37. - Bug (found by Richard Hugues) removed
  38. Last line of barcode was 1 Pixel too wide
  39. Version 1.6:
  40. - new read-only property 'Width'
  41. Todo (missing features)
  42. -----------------------
  43. - Wrapper Class for Quick Reports
  44. }
  45. interface
  46. {$I lr_vers.inc}
  47. uses
  48. SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
  49. type
  50. TBarcodeType = (bcCode_2_5_interleaved,
  51. bcCode_2_5_industrial,
  52. bcCode_2_5_matrix,
  53. bcCode39,
  54. bcCode39Extended,
  55. bcCode128A,
  56. bcCode128B,
  57. bcCode128C,
  58. bcCode93,
  59. bcCode93Extended,
  60. bcCodeMSI,
  61. bcCodePostNet,
  62. bcCodeCodabar,
  63. bcCodeEAN8,
  64. bcCodeEAN13
  65. );
  66. TBarLineType = (white, black, black_half); // for internal use only
  67. // black_half means a black line with 2/5 height (used for PostNet)
  68. { TBarcode }
  69. TBarcode = class(TComponent)
  70. private
  71. { Private-Deklarationen }
  72. FHeight: integer;
  73. FText: string;
  74. FTop: integer;
  75. FLeft: integer;
  76. FModul: integer;
  77. FRatio: double;
  78. FTyp: TBarcodeType;
  79. FCheckSum: boolean;
  80. FShowText: boolean;
  81. FAngle: double;
  82. FCodetext: string;
  83. modules: array[0..3] of shortint;
  84. procedure OneBarProps(code: char; out aWidth: integer; out lt: TBarLineType);
  85. procedure DoLines(Data: string; Canvas: TCanvas);
  86. function Code_2_5_interleaved: string;
  87. function Code_2_5_industrial: string;
  88. function Code_2_5_matrix: string;
  89. function Code_39: string;
  90. function Code_39Extended: string;
  91. function Code_128: string;
  92. function Code_93: string;
  93. function Code_93Extended: string;
  94. function Code_MSI: string;
  95. function Code_PostNet: string;
  96. function Code_Codabar: string;
  97. function Code_EAN8: string;
  98. function Code_EAN13: string;
  99. function GetTypText: string;
  100. procedure MakeModules;
  101. procedure SetModul(v: integer);
  102. function GetWidth: integer;
  103. procedure SetText(AValue: string);
  104. function CleanEANValue(const AValue: string; const ASize:Byte): string;
  105. protected
  106. { Protected-Deklarationen }
  107. function MakeData: string;
  108. public
  109. { Public-Deklarationen }
  110. constructor Create(aOwner: TComponent); override;
  111. procedure DrawBarcode(Canvas: TCanvas);
  112. procedure DrawText(Canvas: TCanvas);
  113. function BarcodeTypeChecked(AType: TBarcodeType): boolean;
  114. property CodeText: string read FCodetext write FCodeText;
  115. published
  116. { Published-Deklarationen }
  117. // Height of Barcode (Pixel)
  118. property Height: integer read FHeight write FHeight;
  119. property Text: string read FText write SetText;
  120. property Top: integer read FTop write FTop;
  121. property Left: integer read FLeft write FLeft;
  122. // Width of the smallest line in a Barcode
  123. property Modul: integer read FModul write SetModul;
  124. property Ratio: double read FRatio write FRatio;
  125. property Typ: TBarcodeType read FTyp write FTyp default bcCode_2_5_interleaved;
  126. // build CheckSum ?
  127. property Checksum: boolean read FCheckSum write FCheckSum default False;
  128. // 0 - 360 degree
  129. property Angle: double read FAngle write FAngle;
  130. property ShowText: boolean read FShowText write FShowText default False;
  131. property Width: integer read GetWidth;
  132. end;
  133. // procedure Register; // Removed by TZ
  134. implementation
  135. {
  136. converts a string from '321' to the internal representation '715'
  137. i need this function because some pattern tables have a different
  138. format :
  139. '00111'
  140. converts to '05161'
  141. }
  142. function Convert(s: string): string;
  143. var
  144. i, v: integer;
  145. t: string;
  146. begin
  147. t := '';
  148. for i := 1 to Length(s) do
  149. begin
  150. v := Ord(s[i]) - 1;
  151. if odd(i) then
  152. Inc(v, 5);
  153. t := t + Chr(v);
  154. end;
  155. Convert := t;
  156. end;
  157. (*
  158. * Berechne die Quersumme aus einer Zahl x
  159. * z.B.: Quersumme von 1234 ist 10
  160. *)
  161. function quersumme(x: integer): integer;
  162. var
  163. sum: integer;
  164. begin
  165. sum := 0;
  166. while x > 0 do
  167. begin
  168. sum := sum + (x mod 10);
  169. x := x div 10;
  170. end;
  171. Result := sum;
  172. end;
  173. {
  174. Rotate a Point by Angle 'alpha'
  175. }
  176. function Rotate2D(p: TPoint; alpha: double): TPoint;
  177. var
  178. sinus, cosinus: extended;
  179. begin
  180. sinus := sin(alpha);
  181. cosinus := cos(alpha);
  182. Result.x := Round(p.x * cosinus + p.y * sinus);
  183. Result.y := Round(-p.x * sinus + p.y * cosinus);
  184. end;
  185. {
  186. Move Point a by Vector b
  187. }
  188. function Translate2D(a, b: TPoint): TPoint;
  189. begin
  190. Result.x := a.x + b.x;
  191. Result.y := a.y + b.y;
  192. end;
  193. constructor TBarcode.Create(aOwner: TComponent);
  194. begin
  195. inherited Create(aOwner);
  196. FAngle := 0.0;
  197. FRatio := 2.0;
  198. FModul := 1;
  199. FTyp := bcCodeEAN13;
  200. FCheckSum := False;
  201. FShowText := False;
  202. end;
  203. function TBarcode.GetTypText: string;
  204. const
  205. bcNames: array[bcCode_2_5_interleaved..bcCodeEAN13] of string =
  206. (
  207. ('2_5_interleaved'),
  208. ('2_5_industrial'),
  209. ('2_5_matrix'),
  210. ('Code39'),
  211. ('Code39 Extended'),
  212. ('Code128A'),
  213. ('Code128B'),
  214. ('Code128C'),
  215. ('Code93'),
  216. ('Code93 Extended'),
  217. ('MSI'),
  218. ('PostNet'),
  219. ('Codebar'),
  220. ('EAN8'),
  221. ('EAN13')
  222. );
  223. begin
  224. Result := bcNames[FTyp];
  225. end;
  226. // set Modul Width
  227. procedure TBarcode.SetModul(v: integer);
  228. begin
  229. if (v >= 1) and (v < 50) then
  230. FModul := v;
  231. end;
  232. {
  233. calculate the width and the linetype of a sigle bar
  234. Code Line-Color Width Height
  235. ------------------------------------------------------------------
  236. '0' white 100% full
  237. '1' white 100%*Ratio full
  238. '2' white 150%*Ratio full
  239. '3' white 200%*Ratio full
  240. '5' black 100% full
  241. '6' black 100%*Ratio full
  242. '7' black 150%*Ratio full
  243. '8' black 200%*Ratio full
  244. 'A' black 100% 2/5 (used for PostNet)
  245. 'B' black 100%*Ratio 2/5 (used for PostNet)
  246. 'C' black 150%*Ratio 2/5 (used for PostNet)
  247. 'D' black 200%*Ratio 2/5 (used for PostNet)
  248. }
  249. procedure TBarcode.OneBarProps(code: char; out aWidth: integer; out lt: TBarLineType);
  250. begin
  251. case code of
  252. '0':
  253. begin
  254. aWidth := modules[0];
  255. lt := white;
  256. end;
  257. '1':
  258. begin
  259. aWidth := modules[1];
  260. lt := white;
  261. end;
  262. '2':
  263. begin
  264. aWidth := modules[2];
  265. lt := white;
  266. end;
  267. '3':
  268. begin
  269. aWidth := modules[3];
  270. lt := white;
  271. end;
  272. '5':
  273. begin
  274. aWidth := modules[0];
  275. lt := black;
  276. end;
  277. '6':
  278. begin
  279. aWidth := modules[1];
  280. lt := black;
  281. end;
  282. '7':
  283. begin
  284. aWidth := modules[2];
  285. lt := black;
  286. end;
  287. '8':
  288. begin
  289. aWidth := modules[3];
  290. lt := black;
  291. end;
  292. 'A':
  293. begin
  294. aWidth := modules[0];
  295. lt := black_half;
  296. end;
  297. 'B':
  298. begin
  299. aWidth := modules[1];
  300. lt := black_half;
  301. end;
  302. 'C':
  303. begin
  304. aWidth := modules[2];
  305. lt := black_half;
  306. end;
  307. 'D':
  308. begin
  309. aWidth := modules[3];
  310. lt := black_half;
  311. end;
  312. else
  313. begin
  314. // something went wrong :-(
  315. // mistyped pattern table
  316. raise Exception.CreateFmt('%s: internal Error', [self.ClassName]);
  317. end;
  318. end;
  319. end;
  320. function TBarcode.MakeData: string;
  321. begin
  322. // calculate the with of the different lines (modules)
  323. MakeModules;
  324. // get the pattern of the barcode
  325. case Typ of
  326. bcCode_2_5_interleaved:
  327. Result := Code_2_5_interleaved;
  328. bcCode_2_5_industrial:
  329. Result := Code_2_5_industrial;
  330. bcCode_2_5_matrix:
  331. Result := Code_2_5_matrix;
  332. bcCode39:
  333. Result := Code_39;
  334. bcCode39Extended:
  335. Result := Code_39Extended;
  336. bcCode128A,
  337. bcCode128B,
  338. bcCode128C:
  339. Result := Code_128;
  340. bcCode93:
  341. Result := Code_93;
  342. bcCode93Extended:
  343. Result := Code_93Extended;
  344. bcCodeMSI:
  345. Result := Code_MSI;
  346. bcCodePostNet:
  347. Result := Code_PostNet;
  348. bcCodeCodabar:
  349. Result := Code_Codabar;
  350. bcCodeEAN8:
  351. Result := Code_EAN8;
  352. bcCodeEAN13:
  353. Result := Code_EAN13;
  354. else
  355. raise Exception.CreateFmt('%s: wrong BarcodeType', [self.ClassName]);
  356. end;
  357. //Showmessage(Format('Data <%s>', [Result]));
  358. end;
  359. function TBarcode.GetWidth: integer;
  360. var
  361. Data: string;
  362. i: integer;
  363. w: integer;
  364. lt: TBarLineType;
  365. begin
  366. Result := 0;
  367. // get barcode pattern
  368. Data := MakeData;
  369. for i := 1 to Length(Data) do // examine the pattern string
  370. begin
  371. OneBarProps(Data[i], w, lt);
  372. Inc(Result, w);
  373. end;
  374. end;
  375. procedure TBarcode.SetText(AValue: string);
  376. begin
  377. if FText=AValue then Exit;
  378. FText:=AValue;
  379. FCodeText:=AValue;
  380. end;
  381. ////////////////////////////// EAN /////////////////////////////////////////
  382. function getEAN(Nr: string): string;
  383. var
  384. i, fak, sum: integer;
  385. tmp: string;
  386. begin
  387. sum := 0;
  388. tmp := copy(nr, 1, Length(Nr) - 1);
  389. fak := Length(tmp);
  390. for i := 1 to length(tmp) do
  391. begin
  392. if (fak mod 2) = 0 then
  393. sum := sum + (StrToInt(tmp[i]) * 1)
  394. else
  395. sum := sum + (StrToInt(tmp[i]) * 3);
  396. Dec(fak);
  397. end;
  398. if (sum mod 10) = 0 then
  399. Result := tmp + '0'
  400. else
  401. Result := tmp + IntToStr(10 - (sum mod 10));
  402. end;
  403. ////////////////////////////// EAN8 /////////////////////////////////////////
  404. // Pattern for Barcode EAN Zeichensatz A
  405. // L1 S1 L2 S2
  406. const
  407. tabelle_EAN_A: array['0'..'9', 1..4] of char =
  408. (
  409. ('2', '6', '0', '5'), // 0
  410. ('1', '6', '1', '5'), // 1
  411. ('1', '5', '1', '6'), // 2
  412. ('0', '8', '0', '5'), // 3
  413. ('0', '5', '2', '6'), // 4
  414. ('0', '6', '2', '5'), // 5
  415. ('0', '5', '0', '8'), // 6
  416. ('0', '7', '0', '6'), // 7
  417. ('0', '6', '0', '7'), // 8
  418. ('2', '5', '0', '6') // 9
  419. );
  420. // Pattern for Barcode EAN Zeichensatz C
  421. // S1 L1 S2 L2
  422. const
  423. tabelle_EAN_C: array['0'..'9', 1..4] of char =
  424. (
  425. ('7', '1', '5', '0'), // 0
  426. ('6', '1', '6', '0'), // 1
  427. ('6', '0', '6', '1'), // 2
  428. ('5', '3', '5', '0'), // 3
  429. ('5', '0', '7', '1'), // 4
  430. ('5', '1', '7', '0'), // 5
  431. ('5', '0', '5', '3'), // 6
  432. ('5', '2', '5', '1'), // 7
  433. ('5', '1', '5', '2'), // 8
  434. ('7', '0', '5', '1') // 9
  435. );
  436. function TBarcode.Code_EAN8: string;
  437. var
  438. i, j: integer;
  439. begin
  440. FCodeText := CleanEANValue(FText, 8);
  441. Result := '505'; // Startcode
  442. for i := 1 to 4 do
  443. for j := 1 to 4 do
  444. begin
  445. Result := Result + tabelle_EAN_A[FCodeText[i], j];
  446. end;
  447. Result := Result + '05050'; // Trennzeichen
  448. for i := 5 to 8 do
  449. for j := 1 to 4 do
  450. begin
  451. Result := Result + tabelle_EAN_C[FCodeText[i], j];
  452. end;
  453. Result := Result + '505'; // Stopcode
  454. end;
  455. ////////////////////////////// EAN13 ///////////////////////////////////////
  456. // Pattern for Barcode EAN Zeichensatz B
  457. // L1 S1 L2 S2
  458. const
  459. tabelle_EAN_B: array['0'..'9', 1..4] of char =
  460. (
  461. ('0', '5', '1', '7'), // 0
  462. ('0', '6', '1', '6'), // 1
  463. ('1', '6', '0', '6'), // 2
  464. ('0', '5', '3', '5'), // 3
  465. ('1', '7', '0', '5'), // 4
  466. ('0', '7', '1', '5'), // 5
  467. ('3', '5', '0', '5'), // 6
  468. ('1', '5', '2', '5'), // 7
  469. ('2', '5', '1', '5'), // 8
  470. ('1', '5', '0', '7') // 9
  471. );
  472. // Zuordung der Paraitaetsfolgen für EAN13
  473. const
  474. tabelle_ParityEAN13: array[0..9, 1..6] of char =
  475. (
  476. ('A', 'A', 'A', 'A', 'A', 'A'), // 0
  477. ('A', 'A', 'B', 'A', 'B', 'B'), // 1
  478. ('A', 'A', 'B', 'B', 'A', 'B'), // 2
  479. ('A', 'A', 'B', 'B', 'B', 'A'), // 3
  480. ('A', 'B', 'A', 'A', 'B', 'B'), // 4
  481. ('A', 'B', 'B', 'A', 'A', 'B'), // 5
  482. ('A', 'B', 'B', 'B', 'A', 'A'), // 6
  483. ('A', 'B', 'A', 'B', 'A', 'B'), // 7
  484. ('A', 'B', 'A', 'B', 'B', 'A'), // 8
  485. ('A', 'B', 'B', 'A', 'B', 'A') // 9
  486. );
  487. function TBarcode.Code_EAN13: string;
  488. var
  489. i, j, LK: integer;
  490. tmp: string;
  491. begin
  492. FCodeText := CleanEanValue(FText, 13);
  493. LK := StrToInt(FCodeText[1]);
  494. tmp := copy(FCodeText, 2, 12);
  495. Result := '505'; // Startcode
  496. for i := 1 to 6 do
  497. begin
  498. case tabelle_ParityEAN13[LK, i] of
  499. 'A':
  500. for j := 1 to 4 do
  501. Result := Result + tabelle_EAN_A[tmp[i], j];
  502. 'B':
  503. for j := 1 to 4 do
  504. Result := Result + tabelle_EAN_B[tmp[i], j];
  505. 'C':
  506. for j := 1 to 4 do
  507. Result := Result + tabelle_EAN_C[tmp[i], j];
  508. end;
  509. end;
  510. Result := Result + '05050'; // Trennzeichen
  511. for i := 7 to 12 do
  512. for j := 1 to 4 do
  513. begin
  514. Result := Result + tabelle_EAN_C[tmp[i], j];
  515. end;
  516. Result := Result + '505'; // Stopcode
  517. end;
  518. // Pattern for Barcode 2 of 5
  519. const
  520. tabelle_2_5: array['0'..'9', 1..5] of char =
  521. (
  522. ('0', '0', '1', '1', '0'), // 0
  523. ('1', '0', '0', '0', '1'), // 1
  524. ('0', '1', '0', '0', '1'), // 2
  525. ('1', '1', '0', '0', '0'), // 3
  526. ('0', '0', '1', '0', '1'), // 4
  527. ('1', '0', '1', '0', '0'), // 5
  528. ('0', '1', '1', '0', '0'), // 6
  529. ('0', '0', '0', '1', '1'), // 7
  530. ('1', '0', '0', '1', '0'), // 8
  531. ('0', '1', '0', '1', '0') // 9
  532. );
  533. function TBarcode.Code_2_5_interleaved: string;
  534. var
  535. i, j: integer;
  536. c: char;
  537. begin
  538. Result := '5050'; // Startcode
  539. for i := 1 to Length(FText) div 2 do
  540. begin
  541. for j := 1 to 5 do
  542. begin
  543. if tabelle_2_5[FText[i * 2 - 1], j] = '1' then
  544. c := '6'
  545. else
  546. c := '5';
  547. Result := Result + c;
  548. if tabelle_2_5[FText[i * 2], j] = '1' then
  549. c := '1'
  550. else
  551. c := '0';
  552. Result := Result + c;
  553. end;
  554. end;
  555. Result := Result + '605'; // Stopcode
  556. end;
  557. function TBarcode.Code_2_5_industrial: string;
  558. var
  559. i, j: integer;
  560. begin
  561. Result := '606050'; // Startcode
  562. for i := 1 to Length(FText) do
  563. begin
  564. for j := 1 to 5 do
  565. begin
  566. if tabelle_2_5[FText[i], j] = '1' then
  567. Result := Result + '60'
  568. else
  569. Result := Result + '50';
  570. end;
  571. end;
  572. Result := Result + '605060'; // Stopcode
  573. end;
  574. function TBarcode.Code_2_5_matrix: string;
  575. var
  576. i, j: integer;
  577. c: char;
  578. begin
  579. Result := '705050'; // Startcode
  580. for i := 1 to Length(FText) do
  581. begin
  582. for j := 1 to 5 do
  583. begin
  584. if tabelle_2_5[FText[i], j] = '1' then
  585. c := '1'
  586. else
  587. c := '0';
  588. // Falls i ungerade ist dann mache Lücke zu Strich
  589. if odd(j) then
  590. c := chr(Ord(c) + 5);
  591. Result := Result + c;
  592. end;
  593. Result := Result + '0'; // Lücke zwischen den Zeichen
  594. end;
  595. Result := Result + '70505'; // Stopcode
  596. end;
  597. function TBarcode.Code_39: string;
  598. type
  599. TCode39 = record
  600. c: char;
  601. Data: array[0..9] of char;
  602. chk: shortint;
  603. end;
  604. const
  605. tabelle_39: array[0..43] of TCode39 = (
  606. (c: '0'; Data: '505160605'; chk: 0),
  607. (c: '1'; Data: '605150506'; chk: 1),
  608. (c: '2'; Data: '506150506'; chk: 2),
  609. (c: '3'; Data: '606150505'; chk: 3),
  610. (c: '4'; Data: '505160506'; chk: 4),
  611. (c: '5'; Data: '605160505'; chk: 5),
  612. (c: '6'; Data: '506160505'; chk: 6),
  613. (c: '7'; Data: '505150606'; chk: 7),
  614. (c: '8'; Data: '605150605'; chk: 8),
  615. (c: '9'; Data: '506150605'; chk: 9),
  616. (c: 'A'; Data: '605051506'; chk: 10),
  617. (c: 'B'; Data: '506051506'; chk: 11),
  618. (c: 'C'; Data: '606051505'; chk: 12),
  619. (c: 'D'; Data: '505061506'; chk: 13),
  620. (c: 'E'; Data: '605061505'; chk: 14),
  621. (c: 'F'; Data: '506061505'; chk: 15),
  622. (c: 'G'; Data: '505051606'; chk: 16),
  623. (c: 'H'; Data: '605051605'; chk: 17),
  624. (c: 'I'; Data: '506051600'; chk: 18),
  625. (c: 'J'; Data: '505061605'; chk: 19),
  626. (c: 'K'; Data: '605050516'; chk: 20),
  627. (c: 'L'; Data: '506050516'; chk: 21),
  628. (c: 'M'; Data: '606050515'; chk: 22),
  629. (c: 'N'; Data: '505060516'; chk: 23),
  630. (c: 'O'; Data: '605060515'; chk: 24),
  631. (c: 'P'; Data: '506060515'; chk: 25),
  632. (c: 'Q'; Data: '505050616'; chk: 26),
  633. (c: 'R'; Data: '605050615'; chk: 27),
  634. (c: 'S'; Data: '506050615'; chk: 28),
  635. (c: 'T'; Data: '505060615'; chk: 29),
  636. (c: 'U'; Data: '615050506'; chk: 30),
  637. (c: 'V'; Data: '516050506'; chk: 31),
  638. (c: 'W'; Data: '616050505'; chk: 32),
  639. (c: 'X'; Data: '515060506'; chk: 33),
  640. (c: 'Y'; Data: '615060505'; chk: 34),
  641. (c: 'Z'; Data: '516060505'; chk: 35),
  642. (c: '-'; Data: '515050606'; chk: 36),
  643. (c: '.'; Data: '615050605'; chk: 37),
  644. (c: ' '; Data: '516050605'; chk: 38),
  645. (c: '*'; Data: '515060605'; chk: 0),
  646. (c: '$'; Data: '515151505'; chk: 39),
  647. (c: '/'; Data: '515150515'; chk: 40),
  648. (c: '+'; Data: '515051515'; chk: 41),
  649. (c: '%'; Data: '505151515'; chk: 42)
  650. );
  651. function FindIdx(z: char): integer;
  652. var
  653. i: integer;
  654. begin
  655. Result := -1;
  656. for i := 0 to High(tabelle_39) do
  657. begin
  658. if z = tabelle_39[i].c then
  659. begin
  660. Result := i;
  661. Break;
  662. end;
  663. end;
  664. end;
  665. var
  666. i, idx: integer;
  667. vChecksum: integer;
  668. begin
  669. vChecksum := 0;
  670. // Startcode
  671. Result := tabelle_39[FindIdx('*')].Data + '0';
  672. for i := 1 to Length(FText) do
  673. begin
  674. idx := FindIdx(FText[i]);
  675. if idx < 0 then
  676. continue;
  677. Result := Result + tabelle_39[idx].Data + '0';
  678. Inc(vChecksum, tabelle_39[idx].chk);
  679. end;
  680. // Calculate Checksum Data
  681. if FCheckSum then
  682. begin
  683. vChecksum := vChecksum mod 43;
  684. for i := 0 to High(tabelle_39) do
  685. if vChecksum = tabelle_39[i].chk then
  686. begin
  687. Result := Result + tabelle_39[i].Data + '0';
  688. exit;
  689. end;
  690. end;
  691. // Stopcode
  692. Result := Result + tabelle_39[FindIdx('*')].Data;
  693. end;
  694. function TBarcode.Code_39Extended: string;
  695. const
  696. code39x: array[0..127] of string[2] =
  697. (
  698. ('%U'), ('$A'), ('$B'), ('$C'), ('$D'), ('$E'), ('$F'), ('$G'),
  699. ('$H'), ('$I'), ('$J'), ('$K'), ('$L'), ('$M'), ('$N'), ('$O'),
  700. ('$P'), ('$Q'), ('$R'), ('$S'), ('$T'), ('$U'), ('$V'), ('$W'),
  701. ('$X'), ('$Y'), ('$Z'), ('%A'), ('%B'), ('%C'), ('%D'), ('%E'),
  702. (' '), ('/A'), ('/B'), ('/C'), ('/D'), ('/E'), ('/F'), ('/G'),
  703. ('/H'), ('/I'), ('/J'), ('/K'), ('/L'), ('/M'), ('/N'), ('/O'),
  704. ('0'), ('1'), ('2'), ('3'), ('4'), ('5'), ('6'), ('7'),
  705. ('8'), ('9'), ('/Z'), ('%F'), ('%G'), ('%H'), ('%I'), ('%J'),
  706. ('%V'), ('A'), ('B'), ('C'), ('D'), ('E'), ('F'), ('G'),
  707. ('H'), ('I'), ('J'), ('K'), ('L'), ('M'), ('N'), ('O'),
  708. ('P'), ('Q'), ('R'), ('S'), ('T'), ('U'), ('V'), ('W'),
  709. ('X'), ('Y'), ('Z'), ('%K'), ('%L'), ('%M'), ('%N'), ('%O'),
  710. ('%W'), ('+A'), ('+B'), ('+C'), ('+D'), ('+E'), ('+F'), ('+G'),
  711. ('+H'), ('+I'), ('+J'), ('+K'), ('+L'), ('+M'), ('+N'), ('+O'),
  712. ('+P'), ('+Q'), ('+R'), ('+S'), ('+T'), ('+U'), ('+V'), ('+W'),
  713. ('+X'), ('+Y'), ('+Z'), ('%P'), ('%Q'), ('%R'), ('%S'), ('%T')
  714. );
  715. var
  716. save: string;
  717. i: integer;
  718. begin
  719. save := FText;
  720. FText := '';
  721. for i := 1 to Length(save) do
  722. begin
  723. if Ord(save[i]) <= 127 then
  724. FText := FText + code39x[Ord(save[i])];
  725. end;
  726. Result := Code_39;
  727. FText := save;
  728. end;
  729. {
  730. Code 128
  731. }
  732. function TBarcode.Code_128: string;
  733. type
  734. TCode128 = record
  735. a, b: char;
  736. c: string[2];
  737. Data: string[6];
  738. end;
  739. const
  740. tabelle_128: array[0..102] of TCode128 = (
  741. (a: ' '; b: ' '; c: '00'; Data: '212222'; ),
  742. (a: '!'; b: '!'; c: '01'; Data: '222122'; ),
  743. (a: '"'; b: '"'; c: '02'; Data: '222221'; ),
  744. (a: '#'; b: '#'; c: '03'; Data: '121223'; ),
  745. (a: '$'; b: '$'; c: '04'; Data: '121322'; ),
  746. (a: '%'; b: '%'; c: '05'; Data: '131222'; ),
  747. (a: '&'; b: '&'; c: '06'; Data: '122213'; ),
  748. (a: ''''; b: ''''; c: '07'; Data: '122312'; ),
  749. (a: '('; b: '('; c: '08'; Data: '132212'; ),
  750. (a: ')'; b: ')'; c: '09'; Data: '221213'; ),
  751. (a: '*'; b: '*'; c: '10'; Data: '221312'; ),
  752. (a: '+'; b: '+'; c: '11'; Data: '231212'; ),
  753. (a: ','; b: ','; c: '12'; Data: '112232'; ),
  754. (a: '-'; b: '-'; c: '13'; Data: '122132'; ),
  755. (a: '.'; b: '.'; c: '14'; Data: '122231'; ),
  756. (a: '/'; b: '/'; c: '15'; Data: '113222'; ),
  757. (a: '0'; b: '0'; c: '16'; Data: '123122'; ),
  758. (a: '1'; b: '1'; c: '17'; Data: '123221'; ),
  759. (a: '2'; b: '2'; c: '18'; Data: '223211'; ),
  760. (a: '3'; b: '3'; c: '19'; Data: '221132'; ),
  761. (a: '4'; b: '4'; c: '20'; Data: '221231'; ),
  762. (a: '5'; b: '5'; c: '21'; Data: '213212'; ),
  763. (a: '6'; b: '6'; c: '22'; Data: '223112'; ),
  764. (a: '7'; b: '7'; c: '23'; Data: '312131'; ),
  765. (a: '8'; b: '8'; c: '24'; Data: '311222'; ),
  766. (a: '9'; b: '9'; c: '25'; Data: '321122'; ),
  767. (a: ':'; b: ':'; c: '26'; Data: '321221'; ),
  768. (a: ';'; b: ';'; c: '27'; Data: '312212'; ),
  769. (a: '<'; b: '<'; c: '28'; Data: '322112'; ),
  770. (a: '='; b: '='; c: '29'; Data: '322211'; ),
  771. (a: '>'; b: '>'; c: '30'; Data: '212123'; ),
  772. (a: '?'; b: '?'; c: '31'; Data: '212321'; ),
  773. (a: '@'; b: '@'; c: '32'; Data: '232121'; ),
  774. (a: 'A'; b: 'A'; c: '33'; Data: '111323'; ),
  775. (a: 'B'; b: 'B'; c: '34'; Data: '131123'; ),
  776. (a: 'C'; b: 'C'; c: '35'; Data: '131321'; ),
  777. (a: 'D'; b: 'D'; c: '36'; Data: '112313'; ),
  778. (a: 'E'; b: 'E'; c: '37'; Data: '132113'; ),
  779. (a: 'F'; b: 'F'; c: '38'; Data: '132311'; ),
  780. (a: 'G'; b: 'G'; c: '39'; Data: '211313'; ),
  781. (a: 'H'; b: 'H'; c: '40'; Data: '231113'; ),
  782. (a: 'I'; b: 'I'; c: '41'; Data: '231311'; ),
  783. (a: 'J'; b: 'J'; c: '42'; Data: '112133'; ),
  784. (a: 'K'; b: 'K'; c: '43'; Data: '112331'; ),
  785. (a: 'L'; b: 'L'; c: '44'; Data: '132131'; ),
  786. (a: 'M'; b: 'M'; c: '45'; Data: '113123'; ),
  787. (a: 'N'; b: 'N'; c: '46'; Data: '113321'; ),
  788. (a: 'O'; b: 'O'; c: '47'; Data: '133121'; ),
  789. (a: 'P'; b: 'P'; c: '48'; Data: '313121'; ),
  790. (a: 'Q'; b: 'Q'; c: '49'; Data: '211331'; ),
  791. (a: 'R'; b: 'R'; c: '50'; Data: '231131'; ),
  792. (a: 'S'; b: 'S'; c: '51'; Data: '213113'; ),
  793. (a: 'T'; b: 'T'; c: '52'; Data: '213311'; ),
  794. (a: 'U'; b: 'U'; c: '53'; Data: '213131'; ),
  795. (a: 'V'; b: 'V'; c: '54'; Data: '311123'; ),
  796. (a: 'W'; b: 'W'; c: '55'; Data: '311321'; ),
  797. (a: 'X'; b: 'X'; c: '56'; Data: '331121'; ),
  798. (a: 'Y'; b: 'Y'; c: '57'; Data: '312113'; ),
  799. (a: 'Z'; b: 'Z'; c: '58'; Data: '312311'; ),
  800. (a: '['; b: '['; c: '59'; Data: '332111'; ),
  801. (a: '\'; b: '\'; c: '60'; Data: '314111'; ),
  802. (a: ']'; b: ']'; c: '61'; Data: '221411'; ),
  803. (a: '^'; b: '^'; c: '62'; Data: '431111'; ),
  804. (a: '_'; b: '_'; c: '63'; Data: '111224'; ),
  805. (a: ' '; b: '`'; c: '64'; Data: '111422'; ),
  806. (a: ' '; b: 'a'; c: '65'; Data: '121124'; ),
  807. (a: ' '; b: 'b'; c: '66'; Data: '121421'; ),
  808. (a: ' '; b: 'c'; c: '67'; Data: '141122'; ),
  809. (a: ' '; b: 'd'; c: '68'; Data: '141221'; ),
  810. (a: ' '; b: 'e'; c: '69'; Data: '112214'; ),
  811. (a: ' '; b: 'f'; c: '70'; Data: '112412'; ),
  812. (a: ' '; b: 'g'; c: '71'; Data: '122114'; ),
  813. (a: ' '; b: 'h'; c: '72'; Data: '122411'; ),
  814. (a: ' '; b: 'i'; c: '73'; Data: '142112'; ),
  815. (a: ' '; b: 'j'; c: '74'; Data: '142211'; ),
  816. (a: ' '; b: 'k'; c: '75'; Data: '241211'; ),
  817. (a: ' '; b: 'l'; c: '76'; Data: '221114'; ),
  818. (a: ' '; b: 'm'; c: '77'; Data: '413111'; ),
  819. (a: ' '; b: 'n'; c: '78'; Data: '241112'; ),
  820. (a: ' '; b: 'o'; c: '79'; Data: '134111'; ),
  821. (a: ' '; b: 'p'; c: '80'; Data: '111242'; ),
  822. (a: ' '; b: 'q'; c: '81'; Data: '121142'; ),
  823. (a: ' '; b: 'r'; c: '82'; Data: '121241'; ),
  824. (a: ' '; b: 's'; c: '83'; Data: '114212'; ),
  825. (a: ' '; b: 't'; c: '84'; Data: '124112'; ),
  826. (a: ' '; b: 'u'; c: '85'; Data: '124211'; ),
  827. (a: ' '; b: 'v'; c: '86'; Data: '411212'; ),
  828. (a: ' '; b: 'w'; c: '87'; Data: '421112'; ),
  829. (a: ' '; b: 'x'; c: '88'; Data: '421211'; ),
  830. (a: ' '; b: 'y'; c: '89'; Data: '212141'; ),
  831. (a: ' '; b: 'z'; c: '90'; Data: '214121'; ),
  832. (a: ' '; b: '{'; c: '91'; Data: '412121'; ),
  833. (a: ' '; b: '|'; c: '92'; Data: '111143'; ),
  834. (a: ' '; b: '}'; c: '93'; Data: '111341'; ),
  835. (a: ' '; b: '~'; c: '94'; Data: '131141'; ),
  836. (a: ' '; b: ' '; c: '95'; Data: '114113'; ),
  837. (a: ' '; b: ' '; c: '96'; Data: '114311'; ),
  838. (a: ' '; b: ' '; c: '97'; Data: '411113'; ),
  839. (a: ' '; b: ' '; c: '98'; Data: '411311'; ),
  840. (a: ' '; b: ' '; c: '99'; Data: '113141'; ),
  841. (a: ' '; b: ' '; c: ' '; Data: '114131'; ),
  842. (a: ' '; b: ' '; c: ' '; Data: '311141'; ),
  843. (a: ' '; b: ' '; c: ' '; Data: '411131'; )
  844. );
  845. StartA = '211412';
  846. StartB = '211214';
  847. StartC = '211232';
  848. Stop = '2331112';
  849. // find Code 128 Codeset A or B
  850. function Find_Code128AB(c: char): integer;
  851. var
  852. i: integer;
  853. v: char;
  854. begin
  855. for i := 0 to High(tabelle_128) do
  856. begin
  857. if FTyp = bcCode128A then
  858. v := tabelle_128[i].a
  859. else
  860. v := tabelle_128[i].b;
  861. if c = v then
  862. begin
  863. Result := i;
  864. exit;
  865. end;
  866. end;
  867. Result := -1;
  868. end;
  869. var
  870. i, idx: integer;
  871. startcode, tmp: string;
  872. vChecksum: integer;
  873. begin
  874. vChecksum := 0; // Added by TZ
  875. case FTyp of
  876. bcCode128A:
  877. begin
  878. vChecksum := 103;
  879. startcode := StartA;
  880. FCodeText := FText;
  881. end;
  882. bcCode128B:
  883. begin
  884. vChecksum := 104;
  885. startcode := StartB;
  886. FCodeText := FText;
  887. end;
  888. bcCode128C:
  889. begin
  890. vChecksum := 105;
  891. startcode := StartC;
  892. // make sure we have an even numeric only string
  893. FCodeText := '';
  894. for i := 1 to Length(FText) do
  895. if not (FText[i] in ['0'..'9']) then
  896. FCodeText := FCodeText + '0'
  897. else
  898. FCodeText := FCodeText + FText[i];
  899. if Odd(Length(FText)) then
  900. FCodeText := '0' + FText;
  901. end;
  902. end;
  903. Result := Convert(startcode); // Startcode
  904. if FTyp = bcCode128C then
  905. begin
  906. tmp := '';
  907. i := 1;
  908. while i<Length(FCodeText) do
  909. begin
  910. tmp := tmp + chr( StrToIntDef(Copy(FCodeText, i, 2), 0) );
  911. inc(i,2);
  912. end;
  913. end else
  914. tmp := FCodeText;
  915. for i := 1 to Length(tmp) do
  916. begin
  917. if FTyp = bcCode128C then
  918. idx := Ord(tmp[i])
  919. else begin
  920. idx := Find_Code128AB(tmp[i]);
  921. if idx < 0 then
  922. idx := Find_Code128AB(' ');
  923. end;
  924. Result := Result + Convert(tabelle_128[idx].Data);
  925. Inc(vChecksum, idx * i);
  926. end;
  927. vChecksum := vChecksum mod 103;
  928. Result := Result + Convert(tabelle_128[vChecksum].Data);
  929. Result := Result + Convert(Stop); // Stopcode
  930. end;
  931. function TBarcode.Code_93: string;
  932. type
  933. TCode93 = record
  934. c: char;
  935. Data: array[0..5] of char;
  936. end;
  937. const
  938. tabelle_93: array[0..46] of TCode93 = (
  939. (c: '0'; Data: '131112'),
  940. (c: '1'; Data: '111213'),
  941. (c: '2'; Data: '111312'),
  942. (c: '3'; Data: '111411'),
  943. (c: '4'; Data: '121113'),
  944. (c: '5'; Data: '121212'),
  945. (c: '6'; Data: '121311'),
  946. (c: '7'; Data: '111114'),
  947. (c: '8'; Data: '131211'),
  948. (c: '9'; Data: '141111'),
  949. (c: 'A'; Data: '211113'),
  950. (c: 'B'; Data: '211212'),
  951. (c: 'C'; Data: '211311'),
  952. (c: 'D'; Data: '221112'),
  953. (c: 'E'; Data: '221211'),
  954. (c: 'F'; Data: '231111'),
  955. (c: 'G'; Data: '112113'),
  956. (c: 'H'; Data: '112212'),
  957. (c: 'I'; Data: '112311'),
  958. (c: 'J'; Data: '122112'),
  959. (c: 'K'; Data: '132111'),
  960. (c: 'L'; Data: '111123'),
  961. (c: 'M'; Data: '111222'),
  962. (c: 'N'; Data: '111321'),
  963. (c: 'O'; Data: '121122'),
  964. (c: 'P'; Data: '131121'),
  965. (c: 'Q'; Data: '212112'),
  966. (c: 'R'; Data: '212211'),
  967. (c: 'S'; Data: '211122'),
  968. (c: 'T'; Data: '211221'),
  969. (c: 'U'; Data: '221121'),
  970. (c: 'V'; Data: '222111'),
  971. (c: 'W'; Data: '112122'),
  972. (c: 'X'; Data: '112221'),
  973. (c: 'Y'; Data: '122121'),
  974. (c: 'Z'; Data: '123111'),
  975. (c: '-'; Data: '121131'),
  976. (c: '.'; Data: '311112'),
  977. (c: ' '; Data: '311211'),
  978. (c: '$'; Data: '321111'),
  979. (c: '/'; Data: '112131'),
  980. (c: '+'; Data: '113121'),
  981. (c: '%'; Data: '211131'),
  982. (c: '['; Data: '121221'), // only used for Extended Code 93
  983. (c: ']'; Data: '312111'), // only used for Extended Code 93
  984. (c: '{'; Data: '311121'), // only used for Extended Code 93
  985. (c: '}'; Data: '122211') // only used for Extended Code 93
  986. );
  987. // find Code 93
  988. function Find_Code93(c: char): integer;
  989. var
  990. i: integer;
  991. begin
  992. for i := 0 to High(tabelle_93) do
  993. begin
  994. if c = tabelle_93[i].c then
  995. begin
  996. Result := i;
  997. exit;
  998. end;
  999. end;
  1000. Result := -1;
  1001. end;
  1002. var
  1003. i, idx: integer;
  1004. checkC, checkK, // Checksums
  1005. weightC, weightK: integer;
  1006. begin
  1007. Result := Convert('111141'); // Startcode
  1008. for i := 1 to Length(FText) do
  1009. begin
  1010. idx := Find_Code93(FText[i]);
  1011. if idx < 0 then
  1012. raise Exception.CreateFmt('%s:Code93 bad Data <%s>', [self.ClassName, FText]);
  1013. Result := Result + Convert(tabelle_93[idx].Data);
  1014. end;
  1015. checkC := 0;
  1016. checkK := 0;
  1017. weightC := 1;
  1018. weightK := 2;
  1019. for i := Length(FText) downto 1 do
  1020. begin
  1021. idx := Find_Code93(FText[i]);
  1022. Inc(checkC, idx * weightC);
  1023. Inc(checkK, idx * weightK);
  1024. Inc(weightC);
  1025. if weightC > 20 then
  1026. weightC := 1;
  1027. Inc(weightK);
  1028. if weightK > 15 then
  1029. weightC := 1;
  1030. end;
  1031. Inc(checkK, checkC);
  1032. checkC := checkC mod 47;
  1033. checkK := checkK mod 47;
  1034. Result := Result + Convert(tabelle_93[checkC].Data) +
  1035. Convert(tabelle_93[checkK].Data);
  1036. Result := Result + Convert('1111411'); // Stopcode
  1037. end;
  1038. function TBarcode.Code_93Extended: string;
  1039. const
  1040. code93x: array[0..127] of string[2] =
  1041. (
  1042. (']U'), ('[A'), ('[B'), ('[C'), ('[D'), ('[E'), ('[F'), ('[G'),
  1043. ('[H'), ('[I'), ('[J'), ('[K'), ('[L'), ('[M'), ('[N'), ('[O'),
  1044. ('[P'), ('[Q'), ('[R'), ('[S'), ('[T'), ('[U'), ('[V'), ('[W'),
  1045. ('[X'), ('[Y'), ('[Z'), (']A'), (']B'), (']C'), (']D'), (']E'),
  1046. (' '), ('{A'), ('{B'), ('{C'), ('{D'), ('{E'), ('{F'), ('{G'),
  1047. ('{H'), ('{I'), ('{J'), ('{K'), ('{L'), ('{M'), ('{N'), ('{O'),
  1048. ('0'), ('1'), ('2'), ('3'), ('4'), ('5'), ('6'), ('7'),
  1049. ('8'), ('9'), ('{Z'), (']F'), (']G'), (']H'), (']I'), (']J'),
  1050. (']V'), ('A'), ('B'), ('C'), ('D'), ('E'), ('F'), ('G'),
  1051. ('H'), ('I'), ('J'), ('K'), ('L'), ('M'), ('N'), ('O'),
  1052. ('P'), ('Q'), ('R'), ('S'), ('T'), ('U'), ('V'), ('W'),
  1053. ('X'), ('Y'), ('Z'), (']K'), (']L'), (']M'), (']N'), (']O'),
  1054. (']W'), ('}A'), ('}B'), ('}C'), ('}D'), ('}E'), ('}F'), ('}G'),
  1055. ('}H'), ('}I'), ('}J'), ('}K'), ('}L'), ('}M'), ('}N'), ('}O'),
  1056. ('}P'), ('}Q'), ('}R'), ('}S'), ('}T'), ('}U'), ('}V'), ('}W'),
  1057. ('}X'), ('}Y'), ('}Z'), (']P'), (']Q'), (']R'), (']S'), (']T')
  1058. );
  1059. var
  1060. // save:array[0..254] of char;
  1061. // old:string;
  1062. save: string;
  1063. i: integer;
  1064. begin
  1065. // CharToOem(PChar(FText), save);
  1066. save := FText;
  1067. FText := '';
  1068. for i := 0 to Length(save) - 1 do
  1069. begin
  1070. if Ord(save[i]) <= 127 then
  1071. FText := FText + code93x[Ord(save[i])];
  1072. end;
  1073. //Showmessage(Format('Text: <%s>', [FText]));
  1074. Result := Code_93;
  1075. FText := save;
  1076. end;
  1077. function TBarcode.Code_MSI: string;
  1078. const
  1079. tabelle_MSI: array['0'..'9'] of string[8] =
  1080. (
  1081. ('51515151'), // '0'
  1082. ('51515160'), // '1'
  1083. ('51516051'), // '2'
  1084. ('51516060'), // '3'
  1085. ('51605151'), // '4'
  1086. ('51605160'), // '5'
  1087. ('51606051'), // '6'
  1088. ('51606060'), // '7'
  1089. ('60515151'), // '8'
  1090. ('60515160') // '9'
  1091. );
  1092. var
  1093. i: integer;
  1094. check_even, check_odd, vChecksum: integer;
  1095. begin
  1096. Result := '60'; // Startcode
  1097. check_even := 0;
  1098. check_odd := 0;
  1099. for i := 1 to Length(FText) do
  1100. begin
  1101. if odd(i - 1) then
  1102. check_odd := check_odd * 10 + Ord(FText[i])
  1103. else
  1104. check_even := check_even + Ord(FText[i]);
  1105. Result := Result + tabelle_MSI[FText[i]];
  1106. end;
  1107. vChecksum := quersumme(check_odd * 2) + check_even;
  1108. vChecksum := vChecksum mod 10;
  1109. if vChecksum > 0 then
  1110. vChecksum := 10 - vChecksum;
  1111. Result := Result + tabelle_MSI[chr(Ord('0') + vChecksum)];
  1112. Result := Result + '515'; // Stopcode
  1113. end;
  1114. function TBarcode.Code_PostNet: string;
  1115. const
  1116. tabelle_PostNet: array['0'..'9'] of string[10] =
  1117. (
  1118. ('5151A1A1A1'), // '0'
  1119. ('A1A1A15151'), // '1'
  1120. ('A1A151A151'), // '2'
  1121. ('A1A15151A1'), // '3'
  1122. ('A151A1A151'), // '4'
  1123. ('A151A151A1'), // '5'
  1124. ('A15151A1A1'), // '6'
  1125. ('51A1A1A151'), // '7'
  1126. ('51A1A151A1'), // '8'
  1127. ('51A151A1A1') // '9'
  1128. );
  1129. var
  1130. i: integer;
  1131. begin
  1132. Result := '51';
  1133. for i := 1 to Length(FText) do
  1134. begin
  1135. Result := Result + tabelle_PostNet[FText[i]];
  1136. end;
  1137. Result := Result + '5';
  1138. end;
  1139. function TBarcode.Code_Codabar: string;
  1140. type
  1141. TCodabar = record
  1142. c: char;
  1143. Data: array[0..6] of char;
  1144. end;
  1145. const
  1146. tabelle_cb: array[0..19] of TCodabar = (
  1147. (c: '1'; Data: '5050615'),
  1148. (c: '2'; Data: '5051506'),
  1149. (c: '3'; Data: '6150505'),
  1150. (c: '4'; Data: '5060515'),
  1151. (c: '5'; Data: '6050515'),
  1152. (c: '6'; Data: '5150506'),
  1153. (c: '7'; Data: '5150605'),
  1154. (c: '8'; Data: '5160505'),
  1155. (c: '9'; Data: '6051505'),
  1156. (c: '0'; Data: '5050516'),
  1157. (c: '-'; Data: '5051605'),
  1158. (c: '$'; Data: '5061505'),
  1159. (c: ':'; Data: '6050606'),
  1160. (c: '/'; Data: '6060506'),
  1161. (c: '.'; Data: '6060605'),
  1162. (c: '+'; Data: '5060606'),
  1163. (c: 'A'; Data: '5061515'),
  1164. (c: 'B'; Data: '5151506'),
  1165. (c: 'C'; Data: '5051516'),
  1166. (c: 'D'; Data: '5051615')
  1167. );
  1168. // find Codabar
  1169. function Find_Codabar(c: char): integer;
  1170. var
  1171. i: integer;
  1172. begin
  1173. for i := 0 to High(tabelle_cb) do
  1174. begin
  1175. if c = tabelle_cb[i].c then
  1176. begin
  1177. Result := i;
  1178. exit;
  1179. end;
  1180. end;
  1181. Result := -1;
  1182. end;
  1183. var
  1184. i, idx: integer;
  1185. begin
  1186. Result := tabelle_cb[Find_Codabar('A')].Data + '0';
  1187. for i := 1 to Length(FText) do
  1188. begin
  1189. idx := Find_Codabar(FText[i]);
  1190. Result := Result + tabelle_cb[idx].Data + '0';
  1191. end;
  1192. Result := Result + tabelle_cb[Find_Codabar('B')].Data;
  1193. end;
  1194. procedure TBarcode.MakeModules;
  1195. begin
  1196. case Typ of
  1197. bcCode_2_5_interleaved,
  1198. bcCode_2_5_industrial,
  1199. bcCode39,
  1200. bcCodeEAN8,
  1201. bcCodeEAN13,
  1202. bcCode39Extended,
  1203. bcCodeCodabar:
  1204. begin
  1205. if Ratio < 2.0 then
  1206. Ratio := 2.0;
  1207. if Ratio > 3.0 then
  1208. Ratio := 3.0;
  1209. end;
  1210. bcCode_2_5_matrix:
  1211. begin
  1212. if Ratio < 2.25 then
  1213. Ratio := 2.25;
  1214. if Ratio > 3.0 then
  1215. Ratio := 3.0;
  1216. end;
  1217. bcCode128A,
  1218. bcCode128B,
  1219. bcCode128C,
  1220. bcCode93,
  1221. bcCode93Extended,
  1222. bcCodeMSI,
  1223. bcCodePostNet: ;
  1224. end;
  1225. modules[0] := FModul;
  1226. modules[1] := Round(FModul * FRatio);
  1227. modules[2] := modules[1] * 3 div 2;
  1228. modules[3] := modules[1] * 2;
  1229. end;
  1230. {
  1231. Draw the Barcode
  1232. Parameter :
  1233. 'data' holds the pattern for a Barcode.
  1234. A barcode begins always with a black line and
  1235. ends with a black line.
  1236. The white Lines builds the space between the black Lines.
  1237. A black line must always followed by a white Line and vica versa.
  1238. Examples:
  1239. '50505' // 3 thin black Lines with 2 thin white Lines
  1240. '606' // 2 fat black Lines with 1 thin white Line
  1241. '5605015' // Error
  1242. data[] : see procedure OneBarProps
  1243. }
  1244. procedure TBarcode.DoLines(Data: string; Canvas: TCanvas);
  1245. var
  1246. i: integer;
  1247. lt: TBarLineType;
  1248. xadd: integer;
  1249. w, h: integer;
  1250. a, b, c, d, // Edges of a line (we need 4 Point because the line
  1251. // is a recangle
  1252. orgin: TPoint;
  1253. alpha: double;
  1254. begin
  1255. xadd := 0;
  1256. orgin.x := FLeft;
  1257. orgin.y := FTop;
  1258. alpha := FAngle * pi / 180.0;
  1259. with Canvas do
  1260. begin
  1261. Pen.Width := 1;
  1262. for i := 1 to Length(Data) do // examine the pattern string
  1263. begin
  1264. OneBarProps(Data[i], w, lt);
  1265. {
  1266. case data[i] of
  1267. '0': begin w := modules[0]; lt := white; end;
  1268. '1': begin w := modules[1]; lt := white; end;
  1269. '2': begin w := modules[2]; lt := white; end;
  1270. '3': begin w := modules[3]; lt := white; end;
  1271. '5': begin w := modules[0]; lt := black; end;
  1272. '6': begin w := modules[1]; lt := black; end;
  1273. '7': begin w := modules[2]; lt := black; end;
  1274. '8': begin w := modules[3]; lt := black; end;
  1275. 'A': begin w := modules[0]; lt := black_half; end;
  1276. 'B': begin w := modules[1]; lt := black_half; end;
  1277. 'C': begin w := modules[2]; lt := black_half; end;
  1278. 'D': begin w := modules[3]; lt := black_half; end;
  1279. else
  1280. begin
  1281. // something went wrong
  1282. // mistyped pattern table
  1283. raise Exception.CreateFmt('%s: internal Error', [self.ClassName]);
  1284. end;
  1285. end;
  1286. }
  1287. if (lt = black) or (lt = black_half) then
  1288. begin
  1289. Pen.Color := clBlack;
  1290. end
  1291. else
  1292. begin
  1293. Pen.Color := clWhite;
  1294. end;
  1295. Brush.Color := Pen.Color;
  1296. if lt = black_half then
  1297. H := FHeight * 2 div 5
  1298. else
  1299. H := FHeight;
  1300. a.x := xadd;
  1301. a.y := 0;
  1302. b.x := xadd;
  1303. b.y := H;
  1304. // c.x := xadd+width;
  1305. c.x := xadd + W - 1; // 23.04.1999 Line was 1 Pixel too wide
  1306. c.y := H;
  1307. // d.x := xadd+width;
  1308. d.x := xadd + W - 1; // 23.04.1999 Line was 1 Pixel too wide
  1309. d.y := 0;
  1310. // a,b,c,d builds the rectangle we want to draw
  1311. // rotate the rectangle
  1312. a := Translate2D(Rotate2D(a, alpha), orgin);
  1313. b := Translate2D(Rotate2D(b, alpha), orgin);
  1314. c := Translate2D(Rotate2D(c, alpha), orgin);
  1315. d := Translate2D(Rotate2D(d, alpha), orgin);
  1316. // draw the rectangle
  1317. Polygon([a, b, c, d]);
  1318. xadd := xadd + w;
  1319. end;
  1320. end;
  1321. end;
  1322. procedure TBarcode.DrawBarcode(Canvas: TCanvas);
  1323. var
  1324. Data: string;
  1325. SaveFont: TFont;
  1326. SavePen: TPen;
  1327. SaveBrush: TBrush;
  1328. begin
  1329. Savefont := TFont.Create;
  1330. SavePen := TPen.Create;
  1331. SaveBrush := TBrush.Create;
  1332. // get barcode pattern
  1333. Data := MakeData;
  1334. try
  1335. // store Canvas properties
  1336. Savefont.Assign(Canvas.Font);
  1337. SavePen.Assign(Canvas.Pen);
  1338. SaveBrush.Assign(Canvas.Brush);
  1339. DoLines(Data, Canvas); // draw the barcode
  1340. if FShowText then
  1341. DrawText(Canvas); // show readable Text
  1342. // restore old Canvas properties
  1343. Canvas.Font.Assign(savefont);
  1344. Canvas.Pen.Assign(SavePen);
  1345. Canvas.Brush.Assign(SaveBrush);
  1346. finally
  1347. Savefont.Free;
  1348. SavePen.Free;
  1349. SaveBrush.Free;
  1350. end;
  1351. end;
  1352. {
  1353. draw contents and type/name of barcode
  1354. as human readable text at the left
  1355. upper edge of the barcode.
  1356. main use for this procedure is testing.
  1357. note: this procedure changes Pen and Brush
  1358. of the current canvas.
  1359. }
  1360. procedure TBarcode.DrawText(Canvas: TCanvas);
  1361. begin
  1362. with Canvas do
  1363. begin
  1364. Font.Size := 4;
  1365. // the fixed font size is a problem, if you
  1366. // use very large or small barcodes
  1367. Pen.Color := clBlack;
  1368. Brush.Color := clWhite;
  1369. TextOut(FLeft, FTop, FText); // contents of Barcode
  1370. TextOut(FLeft, FTop + 14, GetTypText); // type/name of barcode
  1371. end;
  1372. end;
  1373. // this function returns true for those symbols that correct them selves
  1374. // in case invalid data is fed. For example feeding ABCD to 128C numeric
  1375. // only symbol, the generated barcode will be for 0000
  1376. function TBarcode.BarcodeTypeChecked(AType: TBarcodeType): boolean;
  1377. begin
  1378. result := aType in [ bcCode128A, bcCode128B, bcCode128C, bcCodeEAN8,
  1379. bcCodeEAN13 ];
  1380. end;
  1381. function TBarcode.CleanEANValue(const AValue:string; const ASize: Byte): string;
  1382. var
  1383. tmp: string;
  1384. n,i: Integer;
  1385. begin
  1386. tmp := AValue;
  1387. n := Length(tmp);
  1388. // check if there is any strange char in string
  1389. for i:=1 to n do
  1390. if not (tmp[i] in ['0'..'9']) then
  1391. tmp[i] := '0';
  1392. // enforce a ASize char string by adding a 0
  1393. // verifier digit if necesary or calc it if
  1394. // checksum was specified
  1395. if n<ASize then begin
  1396. tmp := stringofchar('0', ASize-n-1) + tmp + '0';
  1397. // TODO: if not FCheckSum was specified
  1398. // resulting barcode might be invalid
  1399. // as a '0' checksum digit was forced.
  1400. end;
  1401. if FCheckSum then
  1402. Result := getEAN(copy(tmp, 1, ASize-1) + '0')
  1403. else
  1404. Result := copy(tmp, 1, ASize);
  1405. end;
  1406. end.