fpbarcode.pp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453
  1. {
  2. This file is part of the Free Pascal FCL library.
  3. Copyright (c) 2017 by Michael Van Canneyt
  4. member of the Free Pascal development team
  5. Barcode encoding routines.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$IFNDEF FPC_DOTTEDUNITS}
  13. unit fpbarcode;
  14. {$ENDIF FPC_DOTTEDUNITS}
  15. {$mode objfpc}{$H+}
  16. interface
  17. {$IFDEF FPC_DOTTEDUNITS}
  18. uses
  19. System.SysUtils;
  20. {$ELSE FPC_DOTTEDUNITS}
  21. uses
  22. sysutils;
  23. {$ENDIF FPC_DOTTEDUNITS}
  24. Type
  25. // Various encodings. Sorted
  26. TBarcodeEncoding = (
  27. be128A, be128B, be128C,
  28. be2of5industrial, be2of5interleaved, be2of5matrix,
  29. be39, be39Extended,
  30. be93, be93Extended,
  31. beCodabar,
  32. beEAN13, beEAN8,
  33. beMSI,
  34. bePostNet
  35. );
  36. TBarcodeEncodings = Set of TBarcodeEncoding;
  37. {
  38. Various types of known bars in a barcode.
  39. Each type encapsulates 3 parameters.
  40. Color: black/white
  41. width: 100, (weighted) 150 or 200 % of unit width
  42. Height: full height or 2/5th (the latter is for postnet)
  43. }
  44. TBarColor = (bcWhite,bcBlack);
  45. TBarWidth = (bw100,bwWeighted,bw150,bw200);
  46. TBarheight = (bhFull,bhTwoFifth);
  47. TBarWidthArray = Array[TBarWidth] of Integer;
  48. TBarParams = record
  49. c : TBarColor;
  50. w : TBarWidth;
  51. h : TBarHeight;
  52. end;
  53. TBarType = 0..11;
  54. // auxiliary type for the constant
  55. TBarTypeParams = Array[TBarType] of TBarParams;
  56. // This
  57. TBarTypeArray = array of TBarType;
  58. TBarParamsArray = Array of TBarParams;
  59. EBarEncoding = class(exception);
  60. Const
  61. NumericalEncodings = [beEAN8,beEAN13,be2of5industrial,be2of5interleaved, be2of5matrix,bePostNet,beMSI,be128C];
  62. BarcodeEncodingNames: array[TBarcodeEncoding] of string =
  63. (
  64. '128 A', '128 B', '128 C',
  65. '2 of 5 industrial', '2 of 5 interleaved', '2 of 5 matrix',
  66. '39', '39 Extended',
  67. '93', '93 Extended',
  68. 'Codabar',
  69. 'EAN 13', 'EAN 8',
  70. 'MSI',
  71. 'PostNet'
  72. );
  73. Function StringAllowsBarEncoding(S : AnsiString; aEncoding : TBarcodeEncoding) : Boolean;
  74. Function StringToBarTypeArray(S : AnsiString; aEncoding : TBarcodeEncoding) : TBarTypeArray;
  75. Function StringToBarcodeParams(S : AnsiString; aEncoding : TBarcodeEncoding) : TBarParamsArray;
  76. Function IntToBarTypeArray(I: Int64; aEncoding : TBarcodeEncoding; aWidth : Integer = 0) : TBarTypeArray;
  77. Function IntToBarcodeParams(I : Int64; aEncoding : TBarcodeEncoding; aWidth : Integer = 0) : TBarParamsArray;
  78. Function BarTypeToBarParams(aType : TBarType) : TBarParams;
  79. Function BarTypeArrayToBarParamsArray(anArray : TBarTypeArray) : TBarParamsArray;
  80. Function CalcBarWidths(aEncoding : TBarcodeEncoding; aUnit : Integer; AWeight : Double) : TBarWidthArray;
  81. Function CalcStringWidthInBarCodeEncoding(S : AnsiString;aEncoding : TBarcodeEncoding; aUnit : Integer; AWeight : Double) : Cardinal;
  82. // Check with barcode unit
  83. implementation
  84. Const
  85. NumChars = ['0'..'9'];
  86. Procedure IllegalChar(C : AnsiChar;E : TBarcodeEncoding);
  87. Var
  88. S : AnsiString;
  89. begin
  90. Str(E,S);
  91. Raise EBarEncoding.CreateFmt('%s is an illegal character for encoding %s',[C,S]);
  92. end;
  93. Const
  94. BarTypes : TBarTypeParams = (
  95. { 0} (c: bcWhite; w: bw100; h: bhFull),
  96. { 1} (c: bcWhite; w: bwWeighted; h: bhFull),
  97. { 2} (c: bcWhite; w: bw150; h: bhFull),
  98. { 3} (c: bcWhite; w: bw200; h: bhFull),
  99. { 4} (c: bcBlack; w: bw100; h: bhFull),
  100. { 5} (c: bcBlack; w: bwWeighted; h: bhFull),
  101. { 6} (c: bcBlack; w: bw150; h: bhFull),
  102. { 7} (c: bcBlack; w: bw200; h: bhFull),
  103. { 8} (c: bcBlack; w: bw100; h: bhTwoFifth),
  104. { 9} (c: bcBlack; w: bwWeighted; h: bhTwoFifth),
  105. {10} (c: bcBlack; w: bw150; h: bhTwoFifth),
  106. {11} (c: bcBlack; w: bw200; h: bhTwoFifth)
  107. );
  108. { ---------------------------------------------------------------------
  109. EAN 8
  110. ---------------------------------------------------------------------}
  111. Type
  112. TEANChar = array[1..4] of TBarType;
  113. TEanParity = array[1..6] of TBarType;
  114. Const
  115. EANStartStop : array[1..3] of TBarType = (4,0,4);
  116. EANSep : array[1..5] of TBarType = (0,4,0,4,0);
  117. EANEncodingA : array['0'..'9'] of TEANChar = (
  118. ( 2, 5, 0, 4), // 0
  119. ( 1, 5, 1, 4), // 1
  120. ( 1, 4, 1, 5), // 2
  121. ( 0, 7, 0, 4), // 3
  122. ( 0, 4, 2, 5), // 4
  123. ( 0, 5, 2, 4), // 5
  124. ( 0, 4, 0, 7), // 6
  125. ( 0, 6, 0, 5), // 7
  126. ( 0, 5, 0, 6), // 8
  127. ( 2, 4, 0, 5) // 9
  128. );
  129. EANEncodingC : array['0'..'9'] of TEANChar = (
  130. ( 6, 1, 4, 0), // 0
  131. ( 5, 1, 5, 0), // 1
  132. ( 5, 0, 5, 1), // 2
  133. ( 4, 3, 4, 0), // 3
  134. ( 4, 0, 6, 1), // 4
  135. ( 4, 1, 6, 0), // 5
  136. ( 4, 0, 4, 3), // 6
  137. ( 4, 2, 4, 1), // 7
  138. ( 4, 1, 4, 2), // 8
  139. ( 6, 0, 4, 1) // 9
  140. );
  141. EANEncodingB : array['0'..'9'] of TEANChar = (
  142. ( 0, 4, 1, 6), // 0
  143. ( 0, 5, 1, 5), // 1
  144. ( 1, 5, 0, 5), // 2
  145. ( 0, 4, 3, 4), // 3
  146. ( 1, 6, 0, 4), // 4
  147. ( 0, 6, 1, 4), // 5
  148. ( 3, 4, 0, 4), // 6
  149. ( 1, 4, 2, 4), // 7
  150. ( 2, 4, 1, 4), // 8
  151. ( 1, 4, 0, 6) // 9
  152. );
  153. EANEncodingParity : array[0..9] of TEanParity = (
  154. ( 8, 8, 8, 8, 8, 8), // 0
  155. ( 8, 8, 9, 8, 9, 9), // 1
  156. ( 8, 8, 9, 9, 8, 9), // 2
  157. ( 8, 8, 9, 9, 9, 8), // 3
  158. ( 8, 9, 8, 8, 9, 9), // 4
  159. ( 8, 9, 9, 8, 8, 9), // 5
  160. ( 8, 9, 9, 9, 8, 8), // 6
  161. ( 8, 9, 8, 9, 8, 9), // 7
  162. ( 8, 9, 8, 9, 9, 8), // 8
  163. ( 8, 9, 9, 8, 9, 8) // 9
  164. );
  165. Procedure AddToArray(A : TBarTypeArray; var aPos : integer; Elements : Array of TBarType);
  166. Var
  167. I,L : Integer;
  168. begin
  169. L:=Length(Elements);
  170. // Safety check
  171. if ((aPos+L)>Length(A)) then
  172. Raise EBarEncoding.CreateFmt('Cannot add %d elements to array of length %d at pos %d,',[L,Length(A),aPos]);
  173. For I:=0 to L-1 do
  174. begin
  175. A[aPos]:=Elements[i];
  176. inc(aPos);
  177. end;
  178. end;
  179. function CheckEANValue(const AValue:AnsiString; const ASize: Byte): AnsiString;
  180. var
  181. L,I : Integer;
  182. begin
  183. Result:=AValue;
  184. UniqueString(Result);
  185. L:=Length(Result);
  186. for i:=1 to L do
  187. if not (Result[i] in NumChars) then
  188. Result[i]:='0';
  189. if L<ASize then
  190. Result:=StringOfChar('0', ASize-L-1)+Result+'0';
  191. end;
  192. function EncodeEAN8(S : AnsiString) : TBarTypeArray;
  193. var
  194. i, p: integer;
  195. begin
  196. S:=CheckEANValue(S,8);
  197. SetLength(Result,2*Length(EANStartStop)+Length(EANSep)+8*4);
  198. P:=0;
  199. AddToArray(Result,P,EANStartStop); // start
  200. for I:=1 to 4 do
  201. AddToArray(Result,P,EANEncodingA[S[i]]);
  202. AddToArray(Result,P,EANSep); // Separator
  203. for i := 5 to 8 do
  204. AddToArray(Result,P,EANEncodingC[S[i]]);
  205. AddToArray(Result,P,EANStartStop); // Stop
  206. end;
  207. function EnCodeEAN13(S : AnsiString) : TBarTypeArray;
  208. var
  209. i, p, cc : integer;
  210. begin
  211. S:=CheckEanValue(S, 13);
  212. SetLength(Result,2*Length(EANStartStop)+Length(EANSep)+12*4);
  213. cc:=Ord(S[1])-Ord('0');
  214. Delete(S,1,1);
  215. P:=0;
  216. AddToArray(Result,P,EANStartStop); // start
  217. for i := 1 to 6 do
  218. case EANEncodingParity[cc,i] of
  219. 8: AddToArray(Result,P,EANEncodingA[s[i]]);
  220. 9: AddToArray(Result,P,EANEncodingB[s[i]]);
  221. 10: AddToArray(Result,P,EANEncodingC[s[i]]);// will normally not happen...
  222. end;
  223. AddToArray(Result,P,EANSep); // Separator
  224. for i := 7 to 12 do
  225. AddToArray(Result,P,EANEncodingC[s[i]]);
  226. AddToArray(Result,P,EANStartStop); // stop
  227. end;
  228. { ---------------------------------------------------------------------
  229. Encoding 39 (+ extended)
  230. ---------------------------------------------------------------------}
  231. Type
  232. TCode39Char = array[0..9] of TBarType;
  233. TCode39Data = record
  234. c: AnsiChar;
  235. ck: byte;
  236. Data: TCode39Char;
  237. end;
  238. Const
  239. Encoding39 : array[0..43] of TCode39Data = (
  240. (c: '0'; ck: 0; data: ( 4, 0, 4, 1, 5, 0, 5, 0, 4, 0)),
  241. (c: '1'; ck: 1; data: ( 5, 0, 4, 1, 4, 0, 4, 0, 5, 0)),
  242. (c: '2'; ck: 2; data: ( 4, 0, 5, 1, 4, 0, 4, 0, 5, 0)),
  243. (c: '3'; ck: 3; data: ( 5, 0, 5, 1, 4, 0, 4, 0, 4, 0)),
  244. (c: '4'; ck: 4; data: ( 4, 0, 4, 1, 5, 0, 4, 0, 5, 0)),
  245. (c: '5'; ck: 5; data: ( 5, 0, 4, 1, 5, 0, 4, 0, 4, 0)),
  246. (c: '6'; ck: 6; data: ( 4, 0, 5, 1, 5, 0, 4, 0, 4, 0)),
  247. (c: '7'; ck: 7; data: ( 4, 0, 4, 1, 4, 0, 5, 0, 5, 0)),
  248. (c: '8'; ck: 8; data: ( 5, 0, 4, 1, 4, 0, 5, 0, 4, 0)),
  249. (c: '9'; ck: 9; data: ( 4, 0, 5, 1, 4, 0, 5, 0, 4, 0)),
  250. (c: 'A'; ck: 10; data: ( 5, 0, 4, 0, 4, 1, 4, 0, 5, 0)),
  251. (c: 'B'; ck: 11; data: ( 4, 0, 5, 0, 4, 1, 4, 0, 5, 0)),
  252. (c: 'C'; ck: 12; data: ( 5, 0, 5, 0, 4, 1, 4, 0, 4, 0)),
  253. (c: 'D'; ck: 13; data: ( 4, 0, 4, 0, 5, 1, 4, 0, 5, 0)),
  254. (c: 'E'; ck: 14; data: ( 5, 0, 4, 0, 5, 1, 4, 0, 4, 0)),
  255. (c: 'F'; ck: 15; data: ( 4, 0, 5, 0, 5, 1, 4, 0, 4, 0)),
  256. (c: 'G'; ck: 16; data: ( 4, 0, 4, 0, 4, 1, 5, 0, 5, 0)),
  257. (c: 'H'; ck: 17; data: ( 5, 0, 4, 0, 4, 1, 5, 0, 4, 0)),
  258. (c: 'I'; ck: 18; data: ( 4, 0, 5, 0, 4, 1, 5, 0, 0, 0)),
  259. (c: 'J'; ck: 19; data: ( 4, 0, 4, 0, 5, 1, 5, 0, 4, 0)),
  260. (c: 'K'; ck: 20; data: ( 5, 0, 4, 0, 4, 0, 4, 1, 5, 0)),
  261. (c: 'L'; ck: 21; data: ( 4, 0, 5, 0, 4, 0, 4, 1, 5, 0)),
  262. (c: 'M'; ck: 22; data: ( 5, 0, 5, 0, 4, 0, 4, 1, 4, 0)),
  263. (c: 'N'; ck: 23; data: ( 4, 0, 4, 0, 5, 0, 4, 1, 5, 0)),
  264. (c: 'O'; ck: 24; data: ( 5, 0, 4, 0, 5, 0, 4, 1, 4, 0)),
  265. (c: 'P'; ck: 25; data: ( 4, 0, 5, 0, 5, 0, 4, 1, 4, 0)),
  266. (c: 'Q'; ck: 26; data: ( 4, 0, 4, 0, 4, 0, 5, 1, 5, 0)),
  267. (c: 'R'; ck: 27; data: ( 5, 0, 4, 0, 4, 0, 5, 1, 4, 0)),
  268. (c: 'S'; ck: 28; data: ( 4, 0, 5, 0, 4, 0, 5, 1, 4, 0)),
  269. (c: 'T'; ck: 29; data: ( 4, 0, 4, 0, 5, 0, 5, 1, 4, 0)),
  270. (c: 'U'; ck: 30; data: ( 5, 1, 4, 0, 4, 0, 4, 0, 5, 0)),
  271. (c: 'V'; ck: 31; data: ( 4, 1, 5, 0, 4, 0, 4, 0, 5, 0)),
  272. (c: 'W'; ck: 32; data: ( 5, 1, 5, 0, 4, 0, 4, 0, 4, 0)),
  273. (c: 'X'; ck: 33; data: ( 4, 1, 4, 0, 5, 0, 4, 0, 5, 0)),
  274. (c: 'Y'; ck: 34; data: ( 5, 1, 4, 0, 5, 0, 4, 0, 4, 0)),
  275. (c: 'Z'; ck: 35; data: ( 4, 1, 5, 0, 5, 0, 4, 0, 4, 0)),
  276. (c: '-'; ck: 36; data: ( 4, 1, 4, 0, 4, 0, 5, 0, 5, 0)),
  277. (c: '.'; ck: 37; data: ( 5, 1, 4, 0, 4, 0, 5, 0, 4, 0)),
  278. (c: ' '; ck: 38; data: ( 4, 1, 5, 0, 4, 0, 5, 0, 4, 0)),
  279. (c: '*'; ck: 0; data: ( 4, 1, 4, 0, 5, 0, 5, 0, 4, 0)),
  280. (c: '$'; ck: 39; data: ( 4, 1, 4, 1, 4, 1, 4, 0, 4, 0)),
  281. (c: '/'; ck: 40; data: ( 4, 1, 4, 1, 4, 0, 4, 1, 4, 0)),
  282. (c: '+'; ck: 41; data: ( 4, 1, 4, 0, 4, 1, 4, 1, 4, 0)),
  283. (c: '%'; ck: 42; data: ( 4, 0, 4, 1, 4, 1, 4, 1, 4, 0))
  284. );
  285. function IndexOfCode39Char(c: AnsiChar): integer;
  286. begin
  287. Result:=High(Encoding39);
  288. While (Result>=0) and (c<>Encoding39[Result].c) do
  289. Dec(Result);
  290. end;
  291. Function AllowEncode39 (S : AnsiString) : boolean;
  292. Var
  293. I,L : integer;
  294. begin
  295. L:=Length(S);
  296. Result:=L>0;
  297. I:=1;
  298. While Result and (I<=L) do
  299. begin
  300. Result:=IndexOfCode39Char(S[i])>=0;
  301. Inc(I);
  302. end;
  303. end;
  304. Function Encode39(S : AnsiString; aCheckSum : Boolean) : TBarTypeArray;
  305. Const
  306. StartStopIndex = 39;
  307. function IndexOfCC(cs: byte): integer;
  308. Var
  309. H : integer;
  310. begin
  311. Result:=0;
  312. H:=High(Encoding39);
  313. While (Result<=H) and (cs<>Encoding39[Result].ck) do
  314. Inc(Result);
  315. if Result>=H then
  316. Result:=StartStopIndex;
  317. end;
  318. var
  319. cs, p, Idx: integer;
  320. c : AnsiChar;
  321. begin
  322. cs:=0;
  323. // Length = (length text + startstop * 2) * (length of data)
  324. SetLength(Result,(Length(S)+2)*10);
  325. P:=0;
  326. // Startcode
  327. AddToArray(Result,P,Encoding39[StartStopIndex].Data);
  328. for C in S do
  329. begin
  330. Idx:=IndexOfCode39Char(C);
  331. if Idx<0 then
  332. IllegalChar(C,be39);
  333. AddToArray(Result,P,Encoding39[Idx].Data);
  334. Inc(cs, Encoding39[Idx].ck);
  335. end;
  336. // Calculate Checksum if requested and add.
  337. if aCheckSum then
  338. begin
  339. AddToArray(Result,P,Encoding39[IndexOfCc(cs mod 43)].Data);
  340. SetLength(Result,P); // Correct result
  341. end
  342. else // No checksum: add startcode, minus last 0 !
  343. begin
  344. AddToArray(Result,P,Encoding39[StartStopIndex].Data);
  345. SetLength(Result,P-1); // Correct result
  346. end;
  347. end;
  348. function AllowEncode39Extended(S : AnsiString) : boolean;
  349. Var
  350. I,L : integer;
  351. begin
  352. L:=Length(S);
  353. Result:=L>0;
  354. I:=1;
  355. While Result and (I<=L) do
  356. begin
  357. Result:=Ord(S[i])<128;
  358. Inc(I);
  359. end;
  360. end;
  361. function Encode39Extended(S : AnsiString; aCheckSum : boolean): TBarTypeArray;
  362. // Extended uses an encoding for the first 127 characters...
  363. const
  364. CharEncoding : array[0..127] of String[2] = (
  365. '%U', '$A', '$B', '$C', '$D', '$E', '$F', '$G',
  366. '$H', '$I', '$J', '$K', '$L', '$M', '$N', '$O',
  367. '$P', '$Q', '$R', '$S', '$T', '$U', '$V', '$W',
  368. '$X', '$Y', '$Z', '%A', '%B', '%C', '%D', '%E',
  369. ' ', '/A', '/B', '/C', '/D', '/E', '/F', '/G',
  370. '/H', '/I', '/J', '/K', '/L', '/M', '/N', '/O',
  371. '0', '1', '2', '3', '4', '5', '6', '7',
  372. '8', '9', '/Z', '%F', '%G', '%H', '%I', '%J',
  373. '%V', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
  374. 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
  375. 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
  376. 'X', 'Y', 'Z', '%K', '%L', '%M', '%N', '%O',
  377. '%W', '+A', '+B', '+C', '+D', '+E', '+F', '+G',
  378. '+H', '+I', '+J', '+K', '+L', '+M', '+N', '+O',
  379. '+P', '+Q', '+R', '+S', '+T', '+U', '+V', '+W',
  380. '+X', '+Y', '+Z', '%P', '%Q', '%R', '%S', '%T'
  381. );
  382. var
  383. T : AnsiString;
  384. O,i: integer;
  385. begin
  386. T:='';
  387. for I:=1 to Length(S) do
  388. begin
  389. O:=Ord(S[i]);
  390. if (O>127) then
  391. IllegalChar(S[i],be39Extended);
  392. T:=T+CharEncoding[O];
  393. end;
  394. Result:=Encode39(T,aChecksum);
  395. end;
  396. { ---------------------------------------------------------------------
  397. Code 93
  398. ---------------------------------------------------------------------}
  399. Type
  400. TCode93Char = array[0..5] of TBarType;
  401. TCode93Data = record
  402. c: AnsiChar;
  403. Data: TCode93Char;
  404. end;
  405. Const
  406. Encoding93 : array[0..46] of TCode93Data = (
  407. (c: '0'; data: ( 4, 2, 4, 0, 4, 1)),
  408. (c: '1'; data: ( 4, 0, 4, 1, 4, 2)),
  409. (c: '2'; data: ( 4, 0, 4, 2, 4, 1)),
  410. (c: '3'; data: ( 4, 0, 4, 3, 4, 0)),
  411. (c: '4'; data: ( 4, 1, 4, 0, 4, 2)),
  412. (c: '5'; data: ( 4, 1, 4, 1, 4, 1)),
  413. (c: '6'; data: ( 4, 1, 4, 2, 4, 0)),
  414. (c: '7'; data: ( 4, 0, 4, 0, 4, 3)),
  415. (c: '8'; data: ( 4, 2, 4, 1, 4, 0)),
  416. (c: '9'; data: ( 4, 3, 4, 0, 4, 0)),
  417. (c: 'A'; data: ( 5, 0, 4, 0, 4, 2)),
  418. (c: 'B'; data: ( 5, 0, 4, 1, 4, 1)),
  419. (c: 'C'; data: ( 5, 0, 4, 2, 4, 0)),
  420. (c: 'D'; data: ( 5, 1, 4, 0, 4, 1)),
  421. (c: 'E'; data: ( 5, 1, 4, 1, 4, 0)),
  422. (c: 'F'; data: ( 5, 2, 4, 0, 4, 0)),
  423. (c: 'G'; data: ( 4, 0, 5, 0, 4, 2)),
  424. (c: 'H'; data: ( 4, 0, 5, 1, 4, 1)),
  425. (c: 'I'; data: ( 4, 0, 5, 2, 4, 0)),
  426. (c: 'J'; data: ( 4, 1, 5, 0, 4, 1)),
  427. (c: 'K'; data: ( 4, 2, 5, 0, 4, 0)),
  428. (c: 'L'; data: ( 4, 0, 4, 0, 5, 2)),
  429. (c: 'M'; data: ( 4, 0, 4, 1, 5, 1)),
  430. (c: 'N'; data: ( 4, 0, 4, 2, 5, 0)),
  431. (c: 'O'; data: ( 4, 1, 4, 0, 5, 1)),
  432. (c: 'P'; data: ( 4, 2, 4, 0, 5, 0)),
  433. (c: 'Q'; data: ( 5, 0, 5, 0, 4, 1)),
  434. (c: 'R'; data: ( 5, 0, 5, 1, 4, 0)),
  435. (c: 'S'; data: ( 5, 0, 4, 0, 5, 1)),
  436. (c: 'T'; data: ( 5, 0, 4, 1, 5, 0)),
  437. (c: 'U'; data: ( 5, 1, 4, 0, 5, 0)),
  438. (c: 'V'; data: ( 5, 1, 5, 0, 4, 0)),
  439. (c: 'W'; data: ( 4, 0, 5, 0, 5, 1)),
  440. (c: 'X'; data: ( 4, 0, 5, 1, 5, 0)),
  441. (c: 'Y'; data: ( 4, 1, 5, 0, 5, 0)),
  442. (c: 'Z'; data: ( 4, 1, 6, 0, 4, 0)),
  443. (c: '-'; data: ( 4, 1, 4, 0, 6, 0)),
  444. (c: '.'; data: ( 6, 0, 4, 0, 4, 1)),
  445. (c: ' '; data: ( 6, 0, 4, 1, 4, 0)),
  446. (c: '$'; data: ( 6, 1, 4, 0, 4, 0)),
  447. (c: '/'; data: ( 4, 0, 5, 0, 6, 0)),
  448. (c: '+'; data: ( 4, 0, 6, 0, 5, 0)),
  449. (c: '%'; data: ( 5, 0, 4, 0, 6, 0)),
  450. (c: '['; data: ( 4, 1, 4, 1, 5, 0)),
  451. (c: ']'; data: ( 6, 0, 5, 0, 4, 0)),
  452. (c: '{'; data: ( 6, 0, 4, 0, 5, 0)),
  453. (c: '}'; data: ( 4, 1, 5, 1, 4, 0))
  454. );
  455. function IndexOfCode93Char(c: AnsiChar): integer;
  456. begin
  457. Result:=High(Encoding93);
  458. While (Result>=0) and (c<>Encoding93[Result].c) do
  459. Dec(Result);
  460. end;
  461. Function AllowEncode93 (S : AnsiString) : boolean;
  462. Var
  463. I,L : integer;
  464. begin
  465. L:=Length(S);
  466. Result:=L>0;
  467. I:=1;
  468. While Result and (I<=L) do
  469. begin
  470. Result:=IndexOfCode93Char(S[i])>=0;
  471. Inc(I);
  472. end;
  473. end;
  474. Function Encode93(S : AnsiString) : TBarTypeArray;
  475. Const
  476. Code93Start : Array[1..6] of TBarType = ( 4, 0, 4, 0, 7, 0);
  477. Code93Stop : Array[1..7] of TBarType = ( 4, 0, 4, 0, 7, 0, 4);
  478. var
  479. L,i, P, Idx, CC, CK, WC, WK : integer;
  480. C : AnsiChar;
  481. begin
  482. L:=Length(S);
  483. // Length String * 6 + Start + Stop + Checksum
  484. SetLength(Result,L*6+6+7+2*6);
  485. P:=0;
  486. AddToArray(Result,P,Code93Start);
  487. for C in S do
  488. begin
  489. Idx:=IndexOfCode93Char(C);
  490. if Idx<0 then
  491. IllegalChar(C,be93);
  492. AddToArray(Result,P,Encoding93[Idx].Data);
  493. end;
  494. CC:=0;
  495. CK:=0;
  496. WC:=1;
  497. WK:=2;
  498. for i:=L downto 1 do
  499. begin
  500. Idx:=IndexOfCode93Char(S[i]);
  501. Inc(CC,Idx*WC);
  502. Inc(CK,Idx*WK);
  503. Inc(WC);
  504. if (WC>20) then
  505. WC:=1;
  506. Inc(WK);
  507. if (WK>15) then
  508. WK:=1;
  509. end;
  510. Inc(CK,CC);
  511. CC:=CC mod 47;
  512. CK:=CK mod 47;
  513. AddToArray(Result,P,Encoding93[CC].Data);
  514. AddToArray(Result,P,Encoding93[CK].Data);
  515. AddToArray(Result,P,Code93Stop);
  516. end;
  517. function AllowEncode93Extended(S : AnsiString) : boolean;
  518. Var
  519. I,L : integer;
  520. begin
  521. L:=Length(S);
  522. Result:=L>0;
  523. I:=1;
  524. While Result and (I<=L) do
  525. begin
  526. Result:=Ord(S[i])<128;
  527. Inc(I);
  528. end;
  529. end;
  530. function Encode93Extended(S: AnsiString) : TBarTypeArray;
  531. const
  532. CharEncoding: array[0..127] of string[2] = (
  533. ']U', '[A', '[B', '[C', '[D', '[E', '[F', '[G',
  534. '[H', '[I', '[J', '[K', '[L', '[M', '[N', '[O',
  535. '[P', '[Q', '[R', '[S', '[T', '[U', '[V', '[W',
  536. '[X', '[Y', '[Z', ']A', ']B', ']C', ']D', ']E',
  537. ' ', '{A', '{B', '{C', '{D', '{E', '{F', '{G',
  538. '{H', '{I', '{J', '{K', '{L', '{M', '{N', '{O',
  539. '0', '1', '2', '3', '4', '5', '6', '7',
  540. '8', '9', '{Z', ']F', ']G', ']H', ']I', ']J',
  541. ']V', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
  542. 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
  543. 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
  544. 'X', 'Y', 'Z', ']K', ']L', ']M', ']N', ']O',
  545. ']W', '}A', '}B', '}C', '}D', '}E', '}F', '}G',
  546. '}H', '}I', '}J', '}K', '}L', '}M', '}N', '}O',
  547. '}P', '}Q', '}R', '}S', '}T', '}U', '}V', '}W',
  548. '}X', '}Y', '}Z', ']P', ']Q', ']R', ']S', ']T'
  549. );
  550. var
  551. T : AnsiString;
  552. O,i: integer;
  553. begin
  554. T:='';
  555. for I:=1 to Length(S) do
  556. begin
  557. O:=Ord(S[i]);
  558. if (O>127) then
  559. IllegalChar(S[i],be93Extended);
  560. T:=T+CharEncoding[O];
  561. end;
  562. Result:=Encode93(T);
  563. end;
  564. { ---------------------------------------------------------------------
  565. MSI
  566. ---------------------------------------------------------------------}
  567. Type
  568. TMSIChar = Array[1..8] of TBarType;
  569. Const
  570. EncodingMSI : array['0'..'9'] of TMSIChar = (
  571. ( 4, 1, 4, 1, 4, 1, 4, 1), // 0
  572. ( 4, 1, 4, 1, 4, 1, 5, 0), // 1
  573. ( 4, 1, 4, 1, 5, 0, 4, 1), // 2
  574. ( 4, 1, 4, 1, 5, 0, 5, 0), // 3
  575. ( 4, 1, 5, 0, 4, 1, 4, 1), // 4
  576. ( 4, 1, 5, 0, 4, 1, 5, 0), // 5
  577. ( 4, 1, 5, 0, 5, 0, 4, 1), // 6
  578. ( 4, 1, 5, 0, 5, 0, 5, 0), // 7
  579. ( 5, 0, 4, 1, 4, 1, 4, 1), // 8
  580. ( 5, 0, 4, 1, 4, 1, 5, 0) // 9
  581. );
  582. function EncodeMSI(S : AnsiString) : TBarTypeArray;
  583. function SumDigits(D: integer): integer;
  584. begin
  585. Result:=0;
  586. while (D>0) do
  587. begin
  588. Result:=Result+(D mod 10);
  589. D:=D div 10;
  590. end;
  591. end;
  592. Const
  593. MSIPrefix : Array [1..2] of TBarType = (5,0);
  594. MSISuffix : Array [1..3] of TBarType = (4,1,4);
  595. var
  596. P,I,CSE,CSO,CS : integer;
  597. C : AnsiChar;
  598. begin
  599. // Length(Prefix)+Length(Suffix)+Length(S)+CheckSum
  600. SetLength(Result,(Length(S)+1)*8+2+3);
  601. P:=0;
  602. AddToArray(Result,P,MSIPrefix); // Prefix
  603. CSE:=0;
  604. CSO:=0;
  605. for i:=1 to Length(s) do
  606. begin
  607. C:=S[i];
  608. if Not (C in NumChars) then
  609. IllegalChar(S[i],beMSI);
  610. if odd(i-1) then
  611. CSO:=CSO*10+Ord(C)
  612. else
  613. CSE:=CSE+Ord(c);
  614. AddToArray(Result,P,EncodingMSI[C]);
  615. end;
  616. // Add checksum
  617. CS:=(SumDigits(CSO*2) + CSE) mod 10;
  618. if CS>0 then
  619. CS:=10-CS;
  620. AddToArray(Result,P,EncodingMSI[chr(Ord('0')+CS)]);
  621. AddToArray(Result,P,MSISuffix); // Suffix
  622. end;
  623. { ---------------------------------------------------------------------
  624. CodaBar
  625. ---------------------------------------------------------------------}
  626. Type
  627. TCodabarChar = array[0..6] of TBarType;
  628. TCodabarCharZero = array[0..7] of TBarType;
  629. TCodaBarData = record
  630. c: AnsiChar;
  631. Data: TCodabarChar;
  632. end;
  633. Var
  634. EncodingCodaBar : array[0..19] of TCodaBarData = (
  635. (c: '1'; data: ( 4, 0, 4, 0, 5, 1, 4)),
  636. (c: '2'; data: ( 4, 0, 4, 1, 4, 0, 5)),
  637. (c: '3'; data: ( 5, 1, 4, 0, 4, 0, 4)),
  638. (c: '4'; data: ( 4, 0, 5, 0, 4, 1, 4)),
  639. (c: '5'; data: ( 5, 0, 4, 0, 4, 1, 4)),
  640. (c: '6'; data: ( 4, 1, 4, 0, 4, 0, 5)),
  641. (c: '7'; data: ( 4, 1, 4, 0, 5, 0, 4)),
  642. (c: '8'; data: ( 4, 1, 5, 0, 4, 0, 4)),
  643. (c: '9'; data: ( 5, 0, 4, 1, 4, 0, 4)),
  644. (c: '0'; data: ( 4, 0, 4, 0, 4, 1, 5)),
  645. (c: '-'; data: ( 4, 0, 4, 1, 5, 0, 4)),
  646. (c: '$'; data: ( 4, 0, 5, 1, 4, 0, 4)),
  647. (c: ':'; data: ( 5, 0, 4, 0, 5, 0, 5)),
  648. (c: '/'; data: ( 5, 0, 5, 0, 4, 0, 5)),
  649. (c: '.'; data: ( 5, 0, 5, 0, 5, 0, 4)),
  650. (c: '+'; data: ( 4, 0, 5, 0, 5, 0, 5)),
  651. (c: 'A'; data: ( 4, 0, 5, 1, 4, 1, 4)),
  652. (c: 'B'; data: ( 4, 1, 4, 1, 4, 0, 5)),
  653. (c: 'C'; data: ( 4, 0, 4, 1, 4, 1, 5)),
  654. (c: 'D'; data: ( 4, 0, 4, 1, 5, 1, 4))
  655. );
  656. function IndexOfCodaChar(c: AnsiChar): integer;
  657. begin
  658. Result:=High(EncodingCodaBar);
  659. While (Result>=0) and (c<>EncodingCodaBar[Result].c) do
  660. Dec(Result);
  661. end;
  662. Function AllowEncodeCodaBar (S : AnsiString) : boolean;
  663. Var
  664. I,L : integer;
  665. begin
  666. L:=Length(S);
  667. Result:=L>0;
  668. I:=1;
  669. While Result and (I<=L) do
  670. begin
  671. Result:=IndexOfCodaChar(S[i])>=0;
  672. Inc(I);
  673. end;
  674. end;
  675. Function EncodeCodaBar(S : AnsiString) : TBarTypeArray;
  676. Function AddZero(C :TCodaBarChar) : TCodabarCharZero;
  677. begin
  678. Move(C,result,SizeOf(C));
  679. Result[7]:=0;
  680. end;
  681. var
  682. i, P, Idx: integer;
  683. begin
  684. // (Length(S)+1)*8+7
  685. Setlength(Result,(Length(S)+1)*8+7);
  686. P:=0;
  687. AddToArray(Result,P,AddZero(EncodingCodaBar[IndexOfCodaChar('A')].Data));
  688. for i:=1 to Length(S) do
  689. begin
  690. Idx:=IndexOfCodaChar(S[i]);
  691. if Idx<0 then
  692. IllegalChar(S[i],beCodabar);
  693. AddToArray(Result,P,AddZero(EncodingCodaBar[Idx].Data));
  694. end;
  695. AddToArray(Result,P,EncodingCodaBar[IndexOfCodaChar('B')].Data);
  696. end;
  697. { ---------------------------------------------------------------------
  698. Postnet
  699. ---------------------------------------------------------------------}
  700. Type
  701. TPostNetChar = Packed Array[1..10] of TBarType;
  702. Const
  703. EncodingPostNet : Packed array['0'..'9'] of TPostNetChar = (
  704. ( 4, 1, 4, 1, 8, 1, 8, 1, 8, 1), // 0
  705. ( 8, 1, 8, 1, 8, 1, 4, 1, 4, 1), // 1
  706. ( 8, 1, 8, 1, 4, 1, 8, 1, 4, 1), // 2
  707. ( 8, 1, 8, 1, 4, 1, 4, 1, 8, 1), // 3
  708. ( 8, 1, 4, 1, 8, 1, 8, 1, 4, 1), // 4
  709. ( 8, 1, 4, 1, 8, 1, 4, 1, 8, 1), // 5
  710. ( 8, 1, 4, 1, 4, 1, 8, 1, 8, 1), // 6
  711. ( 4, 1, 8, 1, 8, 1, 8, 1, 4, 1), // 7
  712. ( 4, 1, 8, 1, 8, 1, 4, 1, 8, 1), // 8
  713. ( 4, 1, 8, 1, 4, 1, 8, 1, 8, 1) // 9
  714. );
  715. Function EncodePostNet (S : AnsiString) : TBarTypeArray;
  716. var
  717. i,P : integer;
  718. begin
  719. SetLength(Result,Length(S)*10+2+1);
  720. P:=0;
  721. AddToArray(Result,P,[4,1]);
  722. for i := 1 to Length(S) do
  723. begin
  724. if Not (S[I] in NumChars) then
  725. IllegalChar(S[i],bePostNet);
  726. AddToArray(Result,P,EncodingPostNet[S[i]]);
  727. end;
  728. AddToArray(Result,P,[4]);
  729. end;
  730. { ---------------------------------------------------------------------
  731. Code 128
  732. ---------------------------------------------------------------------}
  733. Type
  734. TCode128Char = Packed Array[1..6] of TBarType;
  735. TCode128StopChar = Packed Array[1..7] of TBarType;
  736. Const
  737. // The order of these elements must be the same as for
  738. // the Encoding128A,Encoding128B,Encoding128C arrays below !
  739. Encoding128Data : Packed array[0..102] of TCode128Char = (
  740. ( 5, 0, 5, 1, 5, 1), // 0
  741. ( 5, 1, 5, 0, 5, 1), // 1
  742. ( 5, 1, 5, 1, 5, 0), // 2
  743. ( 4, 1, 4, 1, 5, 2), // 3
  744. ( 4, 1, 4, 2, 5, 1), // 4
  745. ( 4, 2, 4, 1, 5, 1), // 5
  746. ( 4, 1, 5, 1, 4, 2), // 6
  747. ( 4, 1, 5, 2, 4, 1), // 7
  748. ( 4, 2, 5, 1, 4, 1), // 8
  749. ( 5, 1, 4, 1, 4, 2), // 9
  750. ( 5, 1, 4, 2, 4, 1), // 10
  751. ( 5, 2, 4, 1, 4, 1), // 11
  752. ( 4, 0, 5, 1, 6, 1), // 12
  753. ( 4, 1, 5, 0, 6, 1), // 13
  754. ( 4, 1, 5, 1, 6, 0), // 14
  755. ( 4, 0, 6, 1, 5, 1), // 15
  756. ( 4, 1, 6, 0, 5, 1), // 16
  757. ( 4, 1, 6, 1, 5, 0), // 17
  758. ( 5, 1, 6, 1, 4, 0), // 18
  759. ( 5, 1, 4, 0, 6, 1), // 19
  760. ( 5, 1, 4, 1, 6, 0), // 20
  761. ( 5, 0, 6, 1, 4, 1), // 21
  762. ( 5, 1, 6, 0, 4, 1), // 22
  763. ( 6, 0, 5, 0, 6, 0), // 23
  764. ( 6, 0, 4, 1, 5, 1), // 24
  765. ( 6, 1, 4, 0, 5, 1), // 25
  766. ( 6, 1, 4, 1, 5, 0), // 26
  767. ( 6, 0, 5, 1, 4, 1), // 27
  768. ( 6, 1, 5, 0, 4, 1), // 28
  769. ( 6, 1, 5, 1, 4, 0), // 29
  770. ( 5, 0, 5, 0, 5, 2), // 30
  771. ( 5, 0, 5, 2, 5, 0), // 31
  772. ( 5, 2, 5, 0, 5, 0), // 32
  773. ( 4, 0, 4, 2, 5, 2), // 33
  774. ( 4, 2, 4, 0, 5, 2), // 34
  775. ( 4, 2, 4, 2, 5, 0), // 35
  776. ( 4, 0, 5, 2, 4, 2), // 36
  777. ( 4, 2, 5, 0, 4, 2), // 37
  778. ( 4, 2, 5, 2, 4, 0), // 38
  779. ( 5, 0, 4, 2, 4, 2), // 39
  780. ( 5, 2, 4, 0, 4, 2), // 40
  781. ( 5, 2, 4, 2, 4, 0), // 41
  782. ( 4, 0, 5, 0, 6, 2), // 42
  783. ( 4, 0, 5, 2, 6, 0), // 43
  784. ( 4, 2, 5, 0, 6, 0), // 44
  785. ( 4, 0, 6, 0, 5, 2), // 45
  786. ( 4, 0, 6, 2, 5, 0), // 46
  787. ( 4, 2, 6, 0, 5, 0), // 47
  788. ( 6, 0, 6, 0, 5, 0), // 48
  789. ( 5, 0, 4, 2, 6, 0), // 49
  790. ( 5, 2, 4, 0, 6, 0), // 50
  791. ( 5, 0, 6, 0, 4, 2), // 51
  792. ( 5, 0, 6, 2, 4, 0), // 52
  793. ( 5, 0, 6, 0, 6, 0), // 53
  794. ( 6, 0, 4, 0, 5, 2), // 54
  795. ( 6, 0, 4, 2, 5, 0), // 55
  796. ( 6, 2, 4, 0, 5, 0), // 56
  797. ( 6, 0, 5, 0, 4, 2), // 57
  798. ( 6, 0, 5, 2, 4, 0), // 58
  799. ( 6, 2, 5, 0, 4, 0), // 59
  800. ( 6, 0, 7, 0, 4, 0), // 60
  801. ( 5, 1, 4, 3, 4, 0), // 61
  802. ( 7, 2, 4, 0, 4, 0), // 62
  803. ( 4, 0, 4, 1, 5, 3), // 63
  804. ( 4, 0, 4, 3, 5, 1), // 64
  805. ( 4, 1, 4, 0, 5, 3), // 65
  806. ( 4, 1, 4, 3, 5, 0), // 66
  807. ( 4, 3, 4, 0, 5, 1), // 67
  808. ( 4, 3, 4, 1, 5, 0), // 68
  809. ( 4, 0, 5, 1, 4, 3), // 69
  810. ( 4, 0, 5, 3, 4, 1), // 70
  811. ( 4, 1, 5, 0, 4, 3), // 71
  812. ( 4, 1, 5, 3, 4, 0), // 72
  813. ( 4, 3, 5, 0, 4, 1), // 73
  814. ( 4, 3, 5, 1, 4, 0), // 74
  815. ( 5, 3, 4, 1, 4, 0), // 75
  816. ( 5, 1, 4, 0, 4, 3), // 76
  817. ( 7, 0, 6, 0, 4, 0), // 77
  818. ( 5, 3, 4, 0, 4, 1), // 78
  819. ( 4, 2, 7, 0, 4, 0), // 79
  820. ( 4, 0, 4, 1, 7, 1), // 80
  821. ( 4, 1, 4, 0, 7, 1), // 81
  822. ( 4, 1, 4, 1, 7, 0), // 82
  823. ( 4, 0, 7, 1, 4, 1), // 83
  824. ( 4, 1, 7, 0, 4, 1), // 84
  825. ( 4, 1, 7, 1, 4, 0), // 85
  826. ( 7, 0, 4, 1, 4, 1), // 86
  827. ( 7, 1, 4, 0, 4, 1), // 87
  828. ( 7, 1, 4, 1, 4, 0), // 88
  829. ( 5, 0, 5, 0, 7, 0), // 89
  830. ( 5, 0, 7, 0, 5, 0), // 90
  831. ( 7, 0, 5, 0, 5, 0), // 91
  832. ( 4, 0, 4, 0, 7, 2), // 92
  833. ( 4, 0, 4, 2, 7, 0), // 93
  834. ( 4, 2, 4, 0, 7, 0), // 94
  835. ( 4, 0, 7, 0, 4, 2), // 95
  836. ( 4, 0, 7, 2, 4, 0), // 96
  837. ( 7, 0, 4, 0, 4, 2), // 97
  838. ( 7, 0, 4, 2, 4, 0), // 98
  839. ( 4, 0, 6, 0, 7, 0), // 99
  840. ( 4, 0, 7, 0, 6, 0), // 100
  841. ( 6, 0, 4, 0, 7, 0), // 101
  842. ( 7, 0, 4, 0, 6, 0) // 102
  843. );
  844. Const
  845. Encoding128ACount = 64;
  846. Encoding128AChecksumInit = 103;
  847. Encoding128BCount = 95;
  848. Encoding128BChecksumInit = 104;
  849. Encoding128CChecksumInit = 105;
  850. Type
  851. /// 0 based, checksum relies on 0-based index
  852. TEncoding128AArray = Packed Array[0..Encoding128ACount-1] of Ansichar;
  853. TEncoding128BArray = Packed Array[0..Encoding128BCount-1] of Ansichar;
  854. Const
  855. StartEncoding128A : TCode128Char = ( 5, 0, 4, 3, 4, 1);
  856. StartEncoding128B : TCode128Char = ( 5, 0, 4, 1, 4, 3);
  857. StartEncoding128C : TCode128Char = ( 5, 0, 4, 1, 6, 1);
  858. StopEncoding128 : TCode128StopChar = ( 5, 2, 6, 0, 4, 0, 5);
  859. // The order of these elements must be the same as on Encoding128Data
  860. Encoding128A : TEncoding128AArray = (
  861. ' ','!','"','#','$','%','&','''','(',')',
  862. '*','+',',','-','.','/','0','1','2','3',
  863. '4','5','6','7','8','9',':',';','<','=',
  864. '>','?','@','A','B','C','D','E','F','G',
  865. 'H','I','J','K','L','M','N','O','P','Q',
  866. 'R','S','T','U','V','W','X','Y','Z','[',
  867. '\',']','^','_'
  868. );
  869. Encoding128B : TEncoding128BArray = (
  870. ' ','!','"','#','$','%','&','''','(',')',
  871. '*','+',',','-','.','/','0','1','2','3',
  872. '4','5','6','7','8','9',':',';','<','=',
  873. '>','?','@','A','B','C','D','E','F','G',
  874. 'H','I','J','K','L','M','N','O','P','Q',
  875. 'R','S','T','U','V','W','X','Y','Z','[',
  876. '\',']','^','_','`','a','b','c','d','e',
  877. 'f','g','h','i','j','k','l','m','n','o',
  878. 'p','q','r','s','t','u','v','w','x','y',
  879. 'z','{','|','}','~'
  880. );
  881. function IndexOf128AChar(c: AnsiChar): integer;
  882. begin
  883. Result:=0;
  884. While (Result<Encoding128ACount) and (c<>Encoding128A[Result]) do
  885. Inc(Result);
  886. if Result>=Encoding128ACount then
  887. Result:=-1;
  888. end;
  889. Function AllowEncode128A(S : AnsiString) : Boolean;
  890. Var
  891. I,L : integer;
  892. begin
  893. L:=Length(S);
  894. Result:=L>0;
  895. I:=1;
  896. While Result and (I<=L) do
  897. begin
  898. Result:=IndexOf128AChar(S[i])>=0;
  899. Inc(I);
  900. end;
  901. end;
  902. Function Encode128A(S : AnsiString) : TBarTypeArray;
  903. Var
  904. CS,I,P,Idx : integer;
  905. begin
  906. // Length(S)+StartCode+CheckSum+StopCode (stopcode has 7 bars)
  907. SetLength(Result,(Length(S)+2)*6+7);
  908. P:=0;
  909. AddToArray(Result,P,StartEncoding128A);
  910. CS:=Encoding128AChecksumInit;
  911. For I:=1 to Length(S) do
  912. begin
  913. Idx:=IndexOf128AChar(S[i]);
  914. if Idx<0 then
  915. IllegalChar(S[i],be128a);
  916. AddToArray(Result,P,Encoding128Data[Idx]);
  917. Inc(CS,Idx*I);
  918. end;
  919. // Cap CS
  920. CS:=CS mod 103;
  921. AddToArray(Result,P,Encoding128Data[CS]);
  922. AddToArray(Result,P,StopEncoding128);
  923. end;
  924. function IndexOf128BChar(c: AnsiChar): integer;
  925. begin
  926. Result:=1;
  927. While (Result<=Encoding128BCount) and (c<>Encoding128B[Result]) do
  928. Inc(Result);
  929. if Result>Encoding128BCount then
  930. Result:=-1;
  931. end;
  932. Function AllowEncode128B(S : AnsiString) : Boolean;
  933. Var
  934. I,L : integer;
  935. begin
  936. L:=Length(S);
  937. Result:=L>0;
  938. I:=1;
  939. While Result and (I<=L) do
  940. begin
  941. Result:=IndexOf128BChar(S[i])>=0;
  942. Inc(I);
  943. end;
  944. end;
  945. Function Encode128B(S : AnsiString) : TBarTypeArray;
  946. Var
  947. CS,I,P,Idx : integer;
  948. begin
  949. // Length(S)+StartCode+CheckSum+StopCode (stopcode has 7 bars)
  950. SetLength(Result,(Length(S)+2)*6+7);
  951. P:=0;
  952. AddToArray(Result,P,StartEncoding128B);
  953. CS:=Encoding128BChecksumInit;
  954. For I:=1 to Length(S) do
  955. begin
  956. Idx:=IndexOf128BChar(S[i]);
  957. if Idx<0 then
  958. IllegalChar(S[i],be128b);
  959. AddToArray(Result,P,Encoding128Data[Idx]);
  960. Inc(CS,Idx*I);
  961. end;
  962. // Cap CS
  963. CS:=CS mod 103;
  964. AddToArray(Result,P,Encoding128Data[CS]);
  965. AddToArray(Result,P,StopEncoding128);
  966. end;
  967. Function C(S : AnsiString) : TBarTypeArray;
  968. function IndexOfChar(c: AnsiChar): integer;
  969. begin
  970. Result:=1;
  971. While (Result<=Encoding128BCount) and (c<>Encoding128A[Result]) do
  972. Inc(Result);
  973. if Result>Encoding128BCount then
  974. Result:=-1;
  975. end;
  976. Var
  977. CS,I,P,Idx : integer;
  978. begin
  979. // Length(S)+StartCode+CheckSum+StopCode (stopcode has 7 bars)
  980. SetLength(Result,(Length(S)+2)*6+7);
  981. P:=0;
  982. AddToArray(Result,P,StartEncoding128B);
  983. CS:=Encoding128BChecksumInit;
  984. For I:=1 to Length(S) do
  985. begin
  986. Idx:=IndexOfChar(S[i]);
  987. if Idx<0 then
  988. IllegalChar(S[i],be128b);
  989. AddToArray(Result,P,Encoding128Data[Idx]);
  990. Inc(CS,Idx*I);
  991. end;
  992. // Cap CS
  993. CS:=CS mod 103;
  994. AddToArray(Result,P,Encoding128Data[CS]);
  995. AddToArray(Result,P,StopEncoding128);
  996. end;
  997. Function Encode128C(S : AnsiString) : TBarTypeArray;
  998. Var
  999. CS,I,CC,P,Idx : integer;
  1000. T : AnsiString;
  1001. begin
  1002. // Length(S)+StartCode+CheckSum+StopCode (stopcode has 7 bars)
  1003. if Odd(Length(S)) then
  1004. S:='0'+S;
  1005. I:=1;
  1006. T:='';
  1007. // construct a AnsiString with codes.
  1008. while i<Length(S) do
  1009. begin
  1010. CC:=StrToIntDef(Copy(S,i,2),-1);
  1011. if CC=-1 then
  1012. IllegalChar(S[i],be128C);
  1013. T:=T+Chr(CC);
  1014. Inc(I,2);
  1015. end;
  1016. // With the new AnsiString, construct barcode
  1017. SetLength(Result,(Length(T)+2)*6+7);
  1018. P:=0;
  1019. AddToArray(Result,P,StartEncoding128C);
  1020. CS:=Encoding128CChecksumInit;
  1021. For I:=1 to Length(T) do
  1022. begin
  1023. Idx:=Ord(T[i]);
  1024. AddToArray(Result,P,Encoding128Data[Idx]);
  1025. Inc(CS,Idx*I);
  1026. end;
  1027. // Cap CS
  1028. CS:=CS mod 103;
  1029. AddToArray(Result,P,Encoding128Data[CS]);
  1030. AddToArray(Result,P,StopEncoding128);
  1031. end;
  1032. { ---------------------------------------------------------------------
  1033. Barcode 2 of 5
  1034. ---------------------------------------------------------------------}
  1035. Type
  1036. TCode2of5Char = Packed array [1..5] of boolean;
  1037. Const
  1038. Encoding2of5 : array['0'..'9'] of TCode2of5Char = (
  1039. (false, false, True, True, false), // 0
  1040. (True, false, false, false, True), // 1
  1041. (false, True, false, false, True), // 2
  1042. (True, True, false, false, false), // 3
  1043. (false, false, True, false, True), // 4
  1044. (True, false, True, false, false), // 5
  1045. (false, True, True, false, false), // 6
  1046. (false, false, false, True, True), // 7
  1047. (True, false, false, True, false), // 8
  1048. (false, True, false, True, false) // 9
  1049. );
  1050. Function Encode2of5Interleaved(S : AnsiString) : TBarTypeArray;
  1051. Const
  1052. Encode2of5Start : Array [1..4] of TBarType = (4,0,4,0);
  1053. Encode2of5Stop : Array [1..3] of TBarType = (5,0,4);
  1054. COdd : Array [Boolean] of TBarType = (4,5);
  1055. CEven : Array [Boolean] of TBarType = (0,1);
  1056. var
  1057. P, i, j: integer;
  1058. CC : Array[1..2] of TBarType;
  1059. begin
  1060. SetLength(Result,(Length(S)*5)+4+3);
  1061. P:=0;
  1062. AddToArray(Result,P,Encode2of5Start);
  1063. for i := 1 to Length(S) div 2 do
  1064. for j:=1 to 5 do
  1065. begin
  1066. if not (S[i*2-1] in NumChars) then
  1067. IllegalChar(S[i*2-1],be2of5interleaved);
  1068. if not (S[i*2] in NumChars) then
  1069. IllegalChar(S[i*2],be2of5interleaved);
  1070. CC[1]:=COdd[Encoding2of5[S[i*2-1],j]];
  1071. CC[2]:=CEven[Encoding2of5[S[i*2],j]];
  1072. AddToArray(Result,P,CC);
  1073. end;
  1074. AddToArray(Result,P,Encode2of5Stop);
  1075. end;
  1076. Function Encode2of5Industrial(S : AnsiString) : TBarTypeArray;
  1077. Const
  1078. Encode2of5Start : Array [1..6] of TBarType = (5,0,5,0,4,0);
  1079. Encode2of5Stop : Array [1..6] of TBarType = (5,0,4,0,5,0);
  1080. Codes : Array [Boolean] of Array[1..2] of TBarType = ((4,0),(5,0));
  1081. var
  1082. P,I,J : integer;
  1083. C : AnsiChar;
  1084. begin
  1085. // Length of AnsiString * 2 + StartCode+StopCode
  1086. SetLength(Result,Length(S)*10+6+6);
  1087. P:=0;
  1088. AddToArray(Result,P,Encode2of5Start);
  1089. for i := 1 to Length(S) do
  1090. for j := 1 to 5 do
  1091. begin
  1092. C:=S[i];
  1093. if not (C in NumChars) then
  1094. IllegalChar(C,be2of5industrial);
  1095. AddToArray(Result,P,Codes[Encoding2of5[S[i],j]]);
  1096. end;
  1097. AddToArray(Result,P,Encode2of5Stop);
  1098. end;
  1099. Function Encode2of5Matrix(S : AnsiString) : TBarTypeArray;
  1100. Const
  1101. Encode2of5Start : Array [1..6] of TBarType = (6,0,4,0,4,0);
  1102. Encode2of5Stop : Array [1..5] of TBarType = (6,0,4,0,4);
  1103. var
  1104. P,I,J : integer;
  1105. C : AnsiChar;
  1106. BT : TBarType;
  1107. begin
  1108. // Length of AnsiString + StartCode+StopCode
  1109. SetLength(Result,Length(S)*6+6+5);
  1110. P:=0;
  1111. AddToArray(Result,P,Encode2of5Start);
  1112. for i:=1 to Length(S) do
  1113. begin
  1114. for j:=1 to 5 do
  1115. begin
  1116. C:=S[i];
  1117. if not (C in NumChars) then
  1118. IllegalChar(C,be2of5industrial);
  1119. BT:=Ord(Encoding2of5[S[i],j]); // 0 or 1
  1120. if odd(J) then
  1121. BT:=BT+4;
  1122. AddToArray(Result,P,[BT]);
  1123. end;
  1124. AddToArray(Result,P,[0]);
  1125. end;
  1126. AddToArray(Result,P,Encode2of5Stop);
  1127. end;
  1128. { ---------------------------------------------------------------------
  1129. Global routines
  1130. ---------------------------------------------------------------------}
  1131. Function AllNumerical (S : AnsiString) : boolean;
  1132. Var
  1133. I,L : integer;
  1134. begin
  1135. L:=Length(S);
  1136. Result:=L>0;
  1137. I:=1;
  1138. While Result and (I<=L) do
  1139. begin
  1140. Result:=S[i] in Numchars;
  1141. Inc(I);
  1142. end;
  1143. end;
  1144. Function StringAllowsBarEncoding(S : AnsiString; aEncoding : TBarcodeEncoding) : Boolean;
  1145. begin
  1146. if (AEncoding in NumericalEncodings) then
  1147. Result:=AllNumerical(S)
  1148. else
  1149. Case aEncoding of
  1150. be128A : Result:=AllowEncode128A(S);
  1151. be128B : Result:=AllowEncode128B(S);
  1152. be39: Result:=AllowEncode39(S);
  1153. be39Extended: Result:=AllowEncode39Extended(S);
  1154. be93: Result:=AllowEncode93(S);
  1155. be93Extended: Result:=AllowEncode93Extended(S);
  1156. beCodabar: Result:=AllowEncodeCodaBar(S);
  1157. else
  1158. Raise EBarEncoding.CreateFmt('Unknown/Unhandled encoding, ordinal value : %d',[ord(aEncoding)]);
  1159. end;
  1160. end;
  1161. Function StringToBarTypeArray(S : AnsiString; aEncoding : TBarcodeEncoding) : TBarTypeArray;
  1162. begin
  1163. SetLength(Result,0);
  1164. Case aEncoding of
  1165. beEAN8 : Result:=EncodeEan8(S);
  1166. beEAN13 : Result:=EncodeEan13(S);
  1167. be128A : Result:=Encode128A(S);
  1168. be128B : Result:=Encode128B(S);
  1169. be128C: Result:=Encode128C(S);
  1170. be2of5industrial: Result:=Encode2of5Industrial(S);
  1171. be2of5interleaved: Result:=Encode2of5Interleaved(S);
  1172. be2of5matrix: Result:=Encode2of5Matrix(S);
  1173. be39: Result:=Encode39(S,False);
  1174. be39Extended: Result:=Encode39Extended(S,False);
  1175. be93: Result:=Encode93(S);
  1176. be93Extended: Result:=Encode93Extended(S);
  1177. beCodabar: Result:=EncodeCodaBar(S);
  1178. beMSI: Result:=EncodeMSI(S);
  1179. bePostNet : Result:=EncodePostNet(S);
  1180. else
  1181. Raise EBarEncoding.CreateFmt('Unknown/Unhandled encoding, ordinal value : %d',[ord(aEncoding)]);
  1182. end;
  1183. end;
  1184. Function StringToBarcodeParams(S : AnsiString; aEncoding : TBarcodeEncoding) : TBarParamsArray;
  1185. begin
  1186. Result:=BarTypeArrayToBarParamsArray(StringToBarTypeArray(S,aEncoding));
  1187. end;
  1188. Function IntToBarTypeArray(I: Int64; aEncoding : TBarcodeEncoding; aWidth : Integer = 0) : TBarTypeArray;
  1189. Var
  1190. S : AnsiString;
  1191. L : integer;
  1192. begin
  1193. S:=IntToStr(i);
  1194. L:=Length(S);
  1195. if (AWidth>0) and (L<AWidth) then
  1196. S:=StringOfChar('0',AWidth-L)+S;
  1197. Result:=StringToBarTypeArray(S,aEncoding);
  1198. end;
  1199. Function IntToBarcodeParams(I : Int64; aEncoding : TBarcodeEncoding; aWidth : Integer = 0) : TBarParamsArray;
  1200. begin
  1201. Result:=BarTypeArrayToBarParamsArray(IntToBarTypeArray(I,aEncoding,aWidth));
  1202. end;
  1203. Function BarTypeToBarParams(aType : TBarType) : TBarParams;
  1204. begin
  1205. Result:=BarTypes[aType];
  1206. end;
  1207. Function BarTypeArrayToBarParamsArray(anArray : TBarTypeArray) : TBarParamsArray;
  1208. Var
  1209. I: Integer;
  1210. begin
  1211. Setlength(Result,Length(anArray));
  1212. For I:=0 to length(AnArray)-1 do
  1213. Result[i]:=BarTypeToBarParams(anArray[i]);
  1214. end;
  1215. function CalcBarWidths(aEncoding: TBarcodeEncoding; aUnit: Integer; AWeight: Double): TBarWidthArray;
  1216. Const
  1217. Weight2to3Encodings =
  1218. [be2of5interleaved, be2of5industrial, be39, beEAN8, beEAN13, be39Extended, beCodabar];
  1219. Weight225to3Encodings = [be2of5matrix];
  1220. begin
  1221. if aEncoding in Weight2to3Encodings then
  1222. begin
  1223. if aWeight < 2.0 then
  1224. aWeight := 2.0;
  1225. if aWeight > 3.0 then
  1226. aWeight := 3.0;
  1227. end
  1228. else if aEncoding in Weight225to3Encodings then
  1229. begin
  1230. if aWeight < 2.25 then
  1231. aWeight := 2.25;
  1232. if aWeight > 3.0 then
  1233. aWeight := 3.0;
  1234. end;
  1235. Result[bw100]:=aUnit;
  1236. Result[bwWeighted]:=Round(aUnit*aWeight);
  1237. Result[bw150]:=Result[bwWeighted]*3 div 2;
  1238. Result[bw200]:=Result[bwWeighted]*2;
  1239. end;
  1240. function CalcStringWidthInBarCodeEncoding(S : AnsiString;aEncoding: TBarcodeEncoding; aUnit: Integer; AWeight: Double): Cardinal;
  1241. Var
  1242. BP : TBarParams;
  1243. Data : TBarTypeArray;
  1244. BWT : TBarWidthArray;
  1245. I : integer;
  1246. begin
  1247. Result:=0;
  1248. BWT:=CalcBarWidths(aEncoding,aUnit,aWeight);
  1249. Data:=StringToBarTypeArray(S,aEncoding);
  1250. for i:=0 to Length(Data)-1 do // examine the pattern string
  1251. begin
  1252. BP:=BarTypeToBarParams(Data[i]);
  1253. Result:=Result+BWT[BP.w];
  1254. end;
  1255. end;
  1256. end.