Printer.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. Bool GetPrinters(MemPtr<PrinterInfo> printers)
  6. {
  7. Bool ok=false;
  8. printers.clear();
  9. #if WINDOWS_OLD
  10. const DWORD level=2; // this is matched with PRINTER_INFO_2 used below
  11. DWORD num=0, size=0;
  12. EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, null, level, null, 0, &size, &num);
  13. Memt<Byte> temp;
  14. again:
  15. temp.setNum(size);
  16. PRINTER_INFO_2 *list=(PRINTER_INFO_2*)temp.data();
  17. if(EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, null, level, (LPBYTE)list, temp.elms(), &size, &num))
  18. {
  19. ok=true;
  20. printers.setNum(num); FREPA(printers)
  21. {
  22. C PRINTER_INFO_2 &src=list[i];
  23. PrinterInfo &pi =printers[i];
  24. pi.name = src.pPrinterName;
  25. pi.model = src.pDriverName;
  26. pi.color = (src.pDevMode->dmColor==DMCOLOR_COLOR);
  27. pi.local =FlagTest(src.Attributes, PRINTER_ATTRIBUTE_LOCAL);
  28. pi.width = src.pDevMode->dmPaperWidth;
  29. pi.height= src.pDevMode->dmPaperLength;
  30. pi.dpi = src.pDevMode->dmPrintQuality;
  31. pi.res.set(pi.width, pi.height)*=pi.dpi; pi.res/=254; // 1 inch = 25.4 mm
  32. }
  33. }else
  34. if(Int(size)>temp.elms())goto again;
  35. #endif
  36. return ok;
  37. }
  38. /******************************************************************************/
  39. // RAW PRINTER
  40. /******************************************************************************/
  41. RawPrinter::RawPrinter()
  42. {
  43. #if WINDOWS_OLD
  44. printer=null;
  45. #endif
  46. }
  47. void RawPrinter::disconnect()
  48. {
  49. #if WINDOWS_OLD
  50. if(printer){ClosePrinter(printer); printer=null;}
  51. printer_name.del();
  52. #endif
  53. }
  54. Bool RawPrinter::connect(C Str &printer_name)
  55. {
  56. disconnect();
  57. #if WINDOWS_OLD
  58. if(OpenPrinterW(ConstCast(WChar(printer_name())), &printer, null))
  59. #else
  60. if(0)
  61. #endif
  62. {
  63. T.printer_name=printer_name; return true;
  64. }
  65. return false;
  66. }
  67. /******************************************************************************/
  68. Bool RawPrinter::send(C Str8 &data, C Str &document_name)
  69. {
  70. Bool ok=false;
  71. #if WINDOWS_OLD
  72. if(printer)
  73. {
  74. DOC_INFO_1W doc_info;
  75. doc_info.pDocName =ConstCast(WChar(document_name.is() ? document_name() : App.name().is() ? App.name()() : u"Doc")); // some printers may fail if no name is specified
  76. doc_info.pOutputFile=null;
  77. doc_info.pDatatype =L"RAW";
  78. if(DWORD job_id=StartDocPrinterW(printer, 1, (LPBYTE)&doc_info))
  79. {
  80. if(StartPagePrinter(printer))
  81. {
  82. DWORD written;
  83. if(WritePrinter(printer, (Ptr)data(), data.length(), &written))
  84. ok=(written==data.length());
  85. EndPagePrinter(printer);
  86. }
  87. EndDocPrinter(printer);
  88. /*HANDLE printer_job=null; if(OpenPrinterW(ConstCast(WChar((printer_name+", Job "+(UInt)job_id)())), &printer_job, null))
  89. {
  90. Byte buffer[65536]; DWORD dwBytesRead=0;
  91. if(ReadPrinter(printer_job, buffer, SIZE(buffer), &dwBytesRead) && dwBytesRead)
  92. {
  93. int z=0;
  94. }
  95. ClosePrinter(printer_job);
  96. }*/
  97. }
  98. }
  99. #endif
  100. return ok;
  101. }
  102. /******************************************************************************/
  103. // RECEIPT PRINTER
  104. /******************************************************************************/
  105. void ReceiptPrinter::disconnect() {super::disconnect();}
  106. Bool ReceiptPrinter:: connect(C Str &printer_name)
  107. {
  108. if(super::connect(printer_name))
  109. {
  110. init(); return true;
  111. }
  112. return false;
  113. }
  114. void ReceiptPrinter::init()
  115. {
  116. code_page=0;
  117. data="\x1B@"; // reset state
  118. barcodeHeight(40); // set default bar-code height (without this, printing bar-codes will fail)
  119. }
  120. Bool ReceiptPrinter::end(C Str &document_name)
  121. {
  122. data+="\x1DVA\x03";
  123. Bool ok=send(data, document_name);
  124. init();
  125. return ok;
  126. }
  127. /******************************************************************************/
  128. void ReceiptPrinter::lineHeight(Byte height)
  129. {
  130. data+="\x1B"; data+='3'; data.alwaysAppend(height);
  131. }
  132. void ReceiptPrinter::lineHeight()
  133. {
  134. data+="\x1B"; data+='2'; // default
  135. }
  136. /******************************************************************************/
  137. void ReceiptPrinter::codePage(Byte cp)
  138. {
  139. if(code_page!=cp)
  140. {
  141. code_page=cp;
  142. #if 1
  143. data+="\x1Bt";
  144. data.alwaysAppend(cp);
  145. #else
  146. data+="\x1C\x7D\x26";
  147. data.alwaysAppend(cp&0xFF);
  148. data.alwaysAppend(cp>>8);
  149. #endif
  150. }
  151. }
  152. /******************************************************************************/
  153. void ReceiptPrinter::operator++()
  154. {
  155. data+='\n';
  156. }
  157. void ReceiptPrinter::operator+=(C Str8 &text)
  158. {
  159. if(text.is())
  160. {
  161. #if 1
  162. data+=text;
  163. #else // writing unicode requires setting code pages, however there's no universal standard, as it depends on printer model
  164. FREPA(text)
  165. {
  166. Char c=text[i];
  167. if(!HasUnicode(c))
  168. {
  169. codePage(0);
  170. data+=c;
  171. }else
  172. {
  173. codePage(27);
  174. data+=MultiByte(874, c);
  175. }
  176. }
  177. #endif
  178. data+='\n';
  179. }
  180. }
  181. /******************************************************************************/
  182. void ReceiptPrinter::justify(Int j)
  183. {
  184. data+="\x1B\x61"; data.alwaysAppend(Sign(j)+1); // -1..1 -> 0..2
  185. }
  186. /******************************************************************************/
  187. // BAR CODE
  188. /******************************************************************************/
  189. void ReceiptPrinter::barcodeWidth(Byte width)
  190. {
  191. data+="\x1D\x77"; data.alwaysAppend(width);
  192. }
  193. void ReceiptPrinter::barcodeHeight(Byte height)
  194. {
  195. data+="\x1D\x68"; data.alwaysAppend(height);
  196. }
  197. void ReceiptPrinter::barcode39(C Str8 &code)
  198. {
  199. if(code.is())
  200. {
  201. data+="\x1D\x6B\x04";
  202. data+=code;
  203. data.alwaysAppend('\0');
  204. //data+='\n'; this shouldn't be done as barcodes automatically end line
  205. }
  206. }
  207. void ReceiptPrinter::barcode93(C Str8 &code)
  208. {
  209. if(code.is())
  210. {
  211. data+="\x1D\x6B\x07";
  212. data+=code;
  213. data.alwaysAppend('\0');
  214. //data+='\n'; this shouldn't be done as barcodes automatically end line
  215. }
  216. }
  217. void ReceiptPrinter::barcode128(C Str8 &code)
  218. {
  219. if(code.is())
  220. {
  221. data+="\x1D\x6B\x08";
  222. data+=code;
  223. data.alwaysAppend('\0');
  224. //data+='\n'; this shouldn't be done as barcodes automatically end line
  225. }
  226. }
  227. /******************************************************************************/
  228. // IMAGE
  229. /******************************************************************************/
  230. static inline Bool ColToBit(C Vec4 &c)
  231. {
  232. return (1-SRGBLumOfSRGBColor(c.xyz))*c.w>=0.5f;
  233. }
  234. Bool ReceiptPrinter::operator+=(C Image &img)
  235. {
  236. Image tmp; C Image *src=&img; if(img.compressed())if(img.copyTry(tmp, -1, -1, -1, IMAGE_R8G8B8A8, IMAGE_SOFT, 1))src=&tmp;else return false;
  237. if(src->lockRead())
  238. {
  239. #if 1
  240. Int w=DivCeil8(src->lw()), h=src->lh();
  241. data+="\x1D\x76\x30"; data.alwaysAppend(0);
  242. data.alwaysAppend(w&0xFF);
  243. data.alwaysAppend(w>>8 );
  244. data.alwaysAppend(h&0xFF);
  245. data.alwaysAppend(h>>8 );
  246. FREPD(y, h)
  247. for(Int x=0; x<src->lw(); )
  248. {
  249. Byte b=0; REP(8)
  250. {
  251. if(ColToBit(src->colorF(x, y)))b|=(1<<i);
  252. x++;
  253. }
  254. data.alwaysAppend(b);
  255. }
  256. #else // this mode needs high DPI with 24 lines to achieve highest possible DPI output matching method above, however it results in padding to 24 lines, so don't use it
  257. lineHeight(0); // have to set zero line height to avoid any padding between line chunks
  258. for(Int y=0; y<src->lh(); y+=24)
  259. {
  260. data+="\x1B\x2A"; data.alwaysAppend(33);
  261. data.alwaysAppend(src->lw()&0xFF);
  262. data.alwaysAppend(src->lw()>>8 );
  263. FREPD(x, src->lw())
  264. FREPD(sy, 3)
  265. {
  266. Byte b=0; FREP(8)if(ColToBit(src->colorF(x, y+7-i + sy*8)))b|=(1<<i);
  267. data.alwaysAppend(b);
  268. }
  269. data+='\n';
  270. }
  271. lineHeight();
  272. #endif
  273. src->unlock();
  274. return true;
  275. }
  276. return false;
  277. }
  278. /******************************************************************************/
  279. Bool ReceiptPrinter::openCashDrawer()
  280. {
  281. const Int pin=0, on_ms=120, off_ms=240;
  282. Str8 data="\x1Bp";
  283. data.alwaysAppend(48+pin);
  284. data.alwaysAppend( on_ms/2);
  285. data.alwaysAppend(off_ms/2);
  286. return send(data);
  287. }
  288. /******************************************************************************
  289. void ReceiptPrinter::test()
  290. {
  291. if(printer)
  292. {
  293. FREP(256)
  294. {
  295. //Str8 data="\x1D\x49";
  296. //Str8 data="\x1D\x72";
  297. Str8 data="\x10\x04";
  298. data.alwaysAppend(i);
  299. send(data);
  300. }
  301. int z=0;
  302. }
  303. }
  304. /******************************************************************************/
  305. // LABEL PRINTER
  306. /******************************************************************************/
  307. static Str8 ZebraText(C Str8 &text)
  308. {
  309. Str8 out; out.reserve(4+3+text.length()+3); // 4="^FH`" 3="^FD" 3="^FS"
  310. out="^FH`^FD";
  311. FREPA(text)
  312. {
  313. Char8 c=text[i]; Byte b=c; if(b<32 || b>=128 || c=='`' || c=='^')
  314. {
  315. out+='`';
  316. out+=Digits16[b>>4];
  317. out+=Digits16[b&15];
  318. }else
  319. {
  320. out+=c;
  321. }
  322. }
  323. out+="^FS";
  324. return out;
  325. }
  326. void LabelPrinter::disconnect() {super::disconnect();}
  327. Bool LabelPrinter:: connect(C Str &printer_name)
  328. {
  329. Memc<PrinterInfo> pis; GetPrinters(pis); REPA(pis)
  330. {
  331. C PrinterInfo &pi=pis[i]; if(pi.name==printer_name)
  332. {
  333. res=pi.res; goto connect;
  334. }
  335. }
  336. disconnect(); return false;
  337. connect:
  338. if(super::connect(printer_name))
  339. {
  340. init(); return true;
  341. }
  342. res.zero(); return false;
  343. }
  344. void LabelPrinter::init()
  345. {
  346. data ="^XA"; // start
  347. data+="^CI28"; // code page UTF-8
  348. data+="^MUD"; // set units to Dots
  349. data+="^LH0,0"; // label home position (origin point)
  350. data+="^JMA"; // set full DPI print resolution
  351. data+="~SD15"; // set medium darkness 0..30
  352. data+="^PW"; data+=res.x; // set print width (in dots)
  353. data+="^LL"; data+=res.y; // label length (in dots)
  354. //data+="^MNN"; // continuous media
  355. //data+="^MNM"; // non-continuous media
  356. /* media type
  357. data+="^MTT"; // Thermal Transfer Media - Ribbon
  358. data+="^MTD"; // Direct Thermal Media - No Ribbon*/
  359. //data+="^CC`"; // replace ` to be command character instead of ^, this is not working, instead 'ZebraText' is used
  360. }
  361. Bool LabelPrinter::end(C Str &document_name)
  362. {
  363. data+="^XZ"; // finish
  364. Bool ok=send(data, document_name);
  365. init();
  366. return ok;
  367. }
  368. /******************************************************************************/
  369. void LabelPrinter::pos(C VecI2 &pos)
  370. {
  371. data+="^FO";
  372. data+=pos.x;
  373. data+=',';
  374. data+=pos.y;
  375. }
  376. void LabelPrinter::text(C VecI2 &pos, C Str &text)
  377. {
  378. if(text.is())
  379. {
  380. T.pos(pos);
  381. data+="^ADN,18,10";
  382. data+=ZebraText(UTF8(text));
  383. }
  384. }
  385. Bool LabelPrinter::image(C VecI2 &pos, C Image &img)
  386. {
  387. Image tmp; C Image *src=&img; if(img.compressed())if(img.copyTry(tmp, -1, -1, -1, IMAGE_R8G8B8A8, IMAGE_SOFT, 1))src=&tmp;else return false;
  388. if(src->lockRead())
  389. {
  390. T.pos(pos);
  391. Int w=DivCeil8(src->lw()), h=src->lh();
  392. data+="^GFB,"; // binary
  393. data+=w*h; data+=',';
  394. data+=w*h; data+=',';
  395. data+=w ; data+=','; // width
  396. FREPD(y, h)
  397. for(Int x=0; x<src->lw(); )
  398. {
  399. Byte b=0; REP(8)
  400. {
  401. if(ColToBit(src->colorF(x, y)))b|=(1<<i);
  402. x++;
  403. }
  404. data.alwaysAppend(b);
  405. }
  406. src->unlock();
  407. return true;
  408. }
  409. return false;
  410. }
  411. void LabelPrinter::barcodeHeight(Byte height)
  412. {
  413. data+=S8+"^BY2,3.0,"+height;
  414. }
  415. void LabelPrinter::barcode39(C VecI2 &pos, C Str8 &code)
  416. {
  417. if(code.is())
  418. {
  419. T.pos(pos);
  420. data+="^B3";
  421. data+=ZebraText(code);
  422. }
  423. }
  424. void LabelPrinter::barcode93(C VecI2 &pos, C Str8 &code)
  425. {
  426. if(code.is())
  427. {
  428. T.pos(pos);
  429. data+="^BA";
  430. data+=ZebraText(code);
  431. }
  432. }
  433. void LabelPrinter::barcode128(C VecI2 &pos, C Str8 &code)
  434. {
  435. if(code.is())
  436. {
  437. T.pos(pos);
  438. data+="^BC";
  439. data+=ZebraText(code);
  440. }
  441. }
  442. /******************************************************************************/
  443. void LabelPrinter::speed(Int speed)
  444. {
  445. data+="^PR";
  446. data+=Mid(speed, 2, 12); // print speed (inch per second)
  447. }
  448. /******************************************************************************/
  449. namespace Code128
  450. {
  451. static const U16 Pattern[]=
  452. {
  453. // index: pattern , widths
  454. 1740, // 0: 11011001100, 212222
  455. 1644, // 1: 11001101100, 222122
  456. 1638, // 2: 11001100110, 222221
  457. 1176, // 3: 10010011000, 121223
  458. 1164, // 4: 10010001100, 121322
  459. 1100, // 5: 10001001100, 131222
  460. 1224, // 6: 10011001000, 122213
  461. 1220, // 7: 10011000100, 122312
  462. 1124, // 8: 10001100100, 132212
  463. 1608, // 9: 11001001000, 221213
  464. 1604, // 10: 11001000100, 221312
  465. 1572, // 11: 11000100100, 231212
  466. 1436, // 12: 10110011100, 112232
  467. 1244, // 13: 10011011100, 122132
  468. 1230, // 14: 10011001110, 122231
  469. 1484, // 15: 10111001100, 113222
  470. 1260, // 16: 10011101100, 123122
  471. 1254, // 17: 10011100110, 123221
  472. 1650, // 18: 11001110010, 223211
  473. 1628, // 19: 11001011100, 221132
  474. 1614, // 20: 11001001110, 221231
  475. 1764, // 21: 11011100100, 213212
  476. 1652, // 22: 11001110100, 223112
  477. 1902, // 23: 11101101110, 312131
  478. 1868, // 24: 11101001100, 311222
  479. 1836, // 25: 11100101100, 321122
  480. 1830, // 26: 11100100110, 321221
  481. 1892, // 27: 11101100100, 312212
  482. 1844, // 28: 11100110100, 322112
  483. 1842, // 29: 11100110010, 322211
  484. 1752, // 30: 11011011000, 212123
  485. 1734, // 31: 11011000110, 212321
  486. 1590, // 32: 11000110110, 232121
  487. 1304, // 33: 10100011000, 111323
  488. 1112, // 34: 10001011000, 131123
  489. 1094, // 35: 10001000110, 131321
  490. 1416, // 36: 10110001000, 112313
  491. 1128, // 37: 10001101000, 132113
  492. 1122, // 38: 10001100010, 132311
  493. 1672, // 39: 11010001000, 211313
  494. 1576, // 40: 11000101000, 231113
  495. 1570, // 41: 11000100010, 231311
  496. 1464, // 42: 10110111000, 112133
  497. 1422, // 43: 10110001110, 112331
  498. 1134, // 44: 10001101110, 132131
  499. 1496, // 45: 10111011000, 113123
  500. 1478, // 46: 10111000110, 113321
  501. 1142, // 47: 10001110110, 133121
  502. 1910, // 48: 11101110110, 313121
  503. 1678, // 49: 11010001110, 211331
  504. 1582, // 50: 11000101110, 231131
  505. 1768, // 51: 11011101000, 213113
  506. 1762, // 52: 11011100010, 213311
  507. 1774, // 53: 11011101110, 213131
  508. 1880, // 54: 11101011000, 311123
  509. 1862, // 55: 11101000110, 311321
  510. 1814, // 56: 11100010110, 331121
  511. 1896, // 57: 11101101000, 312113
  512. 1890, // 58: 11101100010, 312311
  513. 1818, // 59: 11100011010, 332111
  514. 1914, // 60: 11101111010, 314111
  515. 1602, // 61: 11001000010, 221411
  516. 1930, // 62: 11110001010, 431111
  517. 1328, // 63: 10100110000, 111224
  518. 1292, // 64: 10100001100, 111422
  519. 1200, // 65: 10010110000, 121124
  520. 1158, // 66: 10010000110, 121421
  521. 1068, // 67: 10000101100, 141122
  522. 1062, // 68: 10000100110, 141221
  523. 1424, // 69: 10110010000, 112214
  524. 1412, // 70: 10110000100, 112412
  525. 1232, // 71: 10011010000, 122114
  526. 1218, // 72: 10011000010, 122411
  527. 1076, // 73: 10000110100, 142112
  528. 1074, // 74: 10000110010, 142211
  529. 1554, // 75: 11000010010, 241211
  530. 1616, // 76: 11001010000, 221114
  531. 1978, // 77: 11110111010, 413111
  532. 1556, // 78: 11000010100, 241112
  533. 1146, // 79: 10001111010, 134111
  534. 1340, // 80: 10100111100, 111242
  535. 1212, // 81: 10010111100, 121142
  536. 1182, // 82: 10010011110, 121241
  537. 1508, // 83: 10111100100, 114212
  538. 1268, // 84: 10011110100, 124112
  539. 1266, // 85: 10011110010, 124211
  540. 1956, // 86: 11110100100, 411212
  541. 1940, // 87: 11110010100, 421112
  542. 1938, // 88: 11110010010, 421211
  543. 1758, // 89: 11011011110, 212141
  544. 1782, // 90: 11011110110, 214121
  545. 1974, // 91: 11110110110, 412121
  546. 1400, // 92: 10101111000, 111143
  547. 1310, // 93: 10100011110, 111341
  548. 1118, // 94: 10001011110, 131141
  549. 1512, // 95: 10111101000, 114113
  550. 1506, // 96: 10111100010, 114311
  551. 1960, // 97: 11110101000, 411113
  552. 1954, // 98: 11110100010, 411311
  553. 1502, // 99: 10111011110, 113141
  554. 1518, // 100: 10111101110, 114131
  555. 1886, // 101: 11101011110, 311141
  556. 1966, // 102: 11110101110, 411131
  557. 1668, // 103: 11010000100, 211412
  558. 1680, // 104: 11010010000, 211214
  559. 1692, // 105: 11010011100, 211232
  560. },
  561. StopPattern=6379; // 1100011101011, 2331112
  562. enum
  563. {
  564. QUIET_ZONE_LEN=10,
  565. CHAR_LEN =11,
  566. STOP_LEN =13,
  567. };
  568. enum MODE : Byte
  569. {
  570. MODE_A,
  571. MODE_B,
  572. MODE_C,
  573. };
  574. static Byte SwitchCode(Int from, MODE to)
  575. {
  576. switch(from)
  577. {
  578. default: switch(to) // start
  579. {
  580. case MODE_A: return 103;
  581. case MODE_B: return 104;
  582. case MODE_C: return 105;
  583. }break;
  584. case MODE_A: switch(to)
  585. {
  586. case MODE_B: return 100;
  587. case MODE_C: return 99;
  588. }break;
  589. case MODE_B: switch(to)
  590. {
  591. case MODE_A: return 101;
  592. case MODE_C: return 99;
  593. }break;
  594. case MODE_C: switch(to)
  595. {
  596. case MODE_B: return 100;
  597. case MODE_A: return 101;
  598. }break;
  599. }
  600. return -1;
  601. }
  602. static Int CharToCodeA(Char8 value)
  603. {
  604. if(value>=' ' && value<='_')return value-' ';
  605. if(value>=0 && value< ' ')return value+64;
  606. /*if(value==FNC1)return 102;
  607. if(value==FNC2)return 97;
  608. if(value==FNC3)return 96;
  609. if(value==FNC4)return 101;*/
  610. return -1;
  611. }
  612. static Int CharToCodeB(Char8 value)
  613. {
  614. if(value>=32)return value-32;
  615. /*if(value==FNC1)return 102;
  616. if(value==FNC2)return 97;
  617. if(value==FNC3)return 96;
  618. if(value==FNC4)return 100;*/
  619. return -1;
  620. }
  621. static Int CharToCodeC(Char8 a, Char8 b)
  622. {
  623. if(a>='0' && a<='9'
  624. && b>='0' && b<='9')return (a-'0')*10+(b-'0');
  625. return -1;
  626. }
  627. static void SetBit(Memt<Byte, 65536/3> &bits, Int bit, Bool value)
  628. {
  629. FlagSet(bits[bit>>3], 1<<(bit&7), value);
  630. }
  631. static Bool GetBit(Memt<Byte, 65536/3> &bits, Int bit)
  632. {
  633. return FlagTest(bits[bit>>3], 1<<(bit&7));
  634. }
  635. struct Best
  636. {
  637. Int index, length, best_length;
  638. C Str8 &barcode;
  639. Memt<Byte, 65536/3> cur_c, best_c;
  640. void find() // for simplicity this checks only MODE_B and MODE_C (ignoring MODE_A)
  641. {
  642. if(!InRange(index, barcode))
  643. {
  644. //if(length<best_length) already checked before calling 'find'
  645. {
  646. best_length=length;
  647. best_c =cur_c; // copy best MODE map
  648. }
  649. }else
  650. {
  651. Char8 c=barcode[index];
  652. Int last_mode_c=((index>=1) ? GetBit(cur_c, index-1) : -1); // if at the start, then set -1 mode (none) to force mode change
  653. REPD(mode_c, 2)
  654. {
  655. Int code=(mode_c ? CharToCodeC(c, barcode[index+1]) : CharToCodeB(c)); if(code>=0) // if character can be encoded in this mode
  656. {
  657. Byte d_length=(last_mode_c!=mode_c)+1; // changing modes requires 1 extra character
  658. length+=d_length;
  659. if(length<best_length)
  660. {
  661. SetBit(cur_c, index , mode_c);
  662. if(mode_c)SetBit(cur_c, index+1, mode_c); // for mode C we're going to advance 2 characters, so set mode for 2nd too
  663. Byte d_index=(mode_c ? 2 : 1); // MODE_C consumes 2 characters
  664. index+=d_index;
  665. find();
  666. index-=d_index;
  667. }
  668. length-=d_length;
  669. }
  670. }
  671. }
  672. }
  673. Best(C Str8 &barcode) : barcode(barcode)
  674. {
  675. index=length=0; best_length=INT_MAX;
  676. Int bytes=DivCeil8(barcode.length());
  677. cur_c.setNum(bytes);
  678. best_c.setNum(bytes);
  679. find();
  680. }
  681. };
  682. static void Append(MemPtr<Bool> &data, Int &pos, UInt value, Int length)
  683. {
  684. REP(length)data[pos++]=FlagTest(value, 1<<i);
  685. }
  686. } // namespace Code128
  687. void Barcode128(C Str8 &barcode, MemPtr<Bool> data)
  688. {
  689. using namespace Code128;
  690. Best best(barcode);
  691. if(barcode.is() && best.best_length<INT_MAX)
  692. {
  693. data.setNum(best.best_length*CHAR_LEN + CHAR_LEN + STOP_LEN); // data+hash+stop
  694. Int last_mode_c=-1, pos=0, hash_pos=0;
  695. UInt hash=0;
  696. for(Int i=0; i<barcode.length(); i++)
  697. {
  698. MODE mode=(GetBit(best.best_c, i) ? MODE_C : MODE_B);
  699. if(last_mode_c!=mode)
  700. {
  701. Byte code=SwitchCode(last_mode_c, mode);
  702. Append(data, pos, Pattern[code], CHAR_LEN);
  703. hash+=Max(1, hash_pos++)*code;
  704. last_mode_c=mode;
  705. }
  706. Byte code;
  707. Char8 c=barcode[i];
  708. switch(mode)
  709. {
  710. case MODE_A: code=CharToCodeA(c); break;
  711. case MODE_B: code=CharToCodeB(c); break;
  712. default : code=CharToCodeC(c, barcode[++i]); break; // MODE_C
  713. }
  714. Append(data, pos, Pattern[code], CHAR_LEN);
  715. hash+=(hash_pos++)*code;
  716. }
  717. // hash
  718. Append(data, pos, Pattern[hash%103], CHAR_LEN);
  719. // stop
  720. Append(data, pos, StopPattern, STOP_LEN);
  721. }else data.clear();
  722. }
  723. /******************************************************************************/
  724. } // namespace EE
  725. /******************************************************************************/