barcode_view.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. #include "../barcode_app.h"
  2. #include "barcode_view.h"
  3. #include "../encodings.h"
  4. /**
  5. * @brief Draws a single bit from a barcode at a specified location
  6. * @param canvas
  7. * @param bit a 1 or a 0 to signify a bit of data
  8. * @param x the top left x coordinate
  9. * @param y the top left y coordinate
  10. * @param width the width of the bit
  11. * @param height the height of the bit
  12. */
  13. static void draw_bit(Canvas* canvas, int bit, int x, int y, int width, int height) {
  14. if(bit == 1) {
  15. canvas_set_color(canvas, ColorBlack);
  16. } else {
  17. canvas_set_color(canvas, ColorWhite);
  18. }
  19. canvas_draw_box(canvas, x, y, width, height);
  20. }
  21. /**
  22. * Draws the error name and message on the screen
  23. */
  24. static void draw_error_str(Canvas* canvas, const char* title, const char* error) {
  25. canvas_clear(canvas);
  26. elements_multiline_text_aligned(canvas, 0, 0, AlignLeft, AlignTop, title);
  27. elements_multiline_text_aligned(canvas, 0, 12, AlignLeft, AlignTop, error);
  28. }
  29. /**
  30. * @param bits a string of 1's and 0's
  31. * @returns the x coordinate after the bits have been drawn, useful for drawing the next section of bits
  32. */
  33. static int draw_bits(Canvas* canvas, const char* bits, int x, int y, int width, int height) {
  34. int bits_length = strlen(bits);
  35. for(int i = 0; i < bits_length; i++) {
  36. char c = bits[i];
  37. int num = c - '0';
  38. draw_bit(canvas, num, x, y, width, height);
  39. x += width;
  40. }
  41. return x;
  42. }
  43. /**
  44. * Draws an EAN-8 type barcode, does not check if the barcode is valid
  45. * @param canvas the canvas
  46. * @param barcode_digits the digits in the barcode, must be 8 characters long
  47. */
  48. static void draw_ean_8(Canvas* canvas, BarcodeData* barcode_data) {
  49. FuriString* barcode_digits = barcode_data->correct_data;
  50. BarcodeTypeObj* type_obj = barcode_data->type_obj;
  51. int barcode_length = furi_string_size(barcode_digits);
  52. int x = type_obj->start_pos;
  53. int y = BARCODE_Y_START;
  54. int width = 1;
  55. int height = BARCODE_HEIGHT;
  56. //the guard patterns for the beginning, center, ending
  57. const char* end_bits = "101";
  58. const char* center_bits = "01010";
  59. //draw the starting guard pattern
  60. x = draw_bits(canvas, end_bits, x, y, width, height + 5);
  61. FuriString* code_part = furi_string_alloc();
  62. //loop through each digit, find the encoding, and draw it
  63. for(int i = 0; i < barcode_length; i++) {
  64. char current_digit = furi_string_get_char(barcode_digits, i);
  65. //the actual number and the index of the bits
  66. int index = current_digit - '0';
  67. //use the L-codes for the first 4 digits and the R-Codes for the last 4 digits
  68. if(i <= 3) {
  69. furi_string_set_str(code_part, UPC_EAN_L_CODES[index]);
  70. } else {
  71. furi_string_set_str(code_part, UPC_EAN_R_CODES[index]);
  72. }
  73. //convert the current_digit char into a string so it can be printed
  74. char current_digit_string[2];
  75. snprintf(current_digit_string, 2, "%c", current_digit);
  76. //set the canvas color to black to print the digit
  77. canvas_set_color(canvas, ColorBlack);
  78. canvas_draw_str(canvas, x + 1, y + height + 8, current_digit_string);
  79. //draw the bits of the barcode
  80. x = draw_bits(canvas, furi_string_get_cstr(code_part), x, y, width, height);
  81. //if the index has reached 3, that means 4 digits have been drawn and now draw the center guard pattern
  82. if(i == 3) {
  83. x = draw_bits(canvas, center_bits, x, y, width, height + 5);
  84. }
  85. }
  86. furi_string_free(code_part);
  87. //draw the ending guard pattern
  88. x = draw_bits(canvas, end_bits, x, y, width, height + 5);
  89. }
  90. static void draw_ean_13(Canvas* canvas, BarcodeData* barcode_data) {
  91. FuriString* barcode_digits = barcode_data->correct_data;
  92. BarcodeTypeObj* type_obj = barcode_data->type_obj;
  93. int barcode_length = furi_string_size(barcode_digits);
  94. int x = type_obj->start_pos;
  95. int y = BARCODE_Y_START;
  96. int width = 1;
  97. int height = BARCODE_HEIGHT;
  98. //the guard patterns for the beginning, center, ending
  99. const char* end_bits = "101";
  100. const char* center_bits = "01010";
  101. //draw the starting guard pattern
  102. x = draw_bits(canvas, end_bits, x, y, width, height + 5);
  103. FuriString* left_structure = furi_string_alloc();
  104. FuriString* code_part = furi_string_alloc();
  105. //loop through each digit, find the encoding, and draw it
  106. for(int i = 0; i < barcode_length; i++) {
  107. char current_digit = furi_string_get_char(barcode_digits, i);
  108. int index = current_digit - '0';
  109. if(i == 0) {
  110. furi_string_set_str(left_structure, EAN_13_STRUCTURE_CODES[index]);
  111. //convert the current_digit char into a string so it can be printed
  112. char current_digit_string[2];
  113. snprintf(current_digit_string, 2, "%c", current_digit);
  114. //set the canvas color to black to print the digit
  115. canvas_set_color(canvas, ColorBlack);
  116. canvas_draw_str(canvas, x - 10, y + height + 8, current_digit_string);
  117. continue;
  118. } else {
  119. //use the L-codes for the first 6 digits and the R-Codes for the last 6 digits
  120. if(i <= 6) {
  121. //get the encoding type at the current barcode bit position
  122. char encoding_type = furi_string_get_char(left_structure, i - 1);
  123. if(encoding_type == 'L') {
  124. furi_string_set_str(code_part, UPC_EAN_L_CODES[index]);
  125. } else {
  126. furi_string_set_str(code_part, EAN_G_CODES[index]);
  127. }
  128. } else {
  129. furi_string_set_str(code_part, UPC_EAN_R_CODES[index]);
  130. }
  131. //convert the current_digit char into a string so it can be printed
  132. char current_digit_string[2];
  133. snprintf(current_digit_string, 2, "%c", current_digit);
  134. //set the canvas color to black to print the digit
  135. canvas_set_color(canvas, ColorBlack);
  136. canvas_draw_str(canvas, x + 1, y + height + 8, current_digit_string);
  137. //draw the bits of the barcode
  138. x = draw_bits(canvas, furi_string_get_cstr(code_part), x, y, width, height);
  139. //if the index has reached 6, that means 6 digits have been drawn and we now draw the center guard pattern
  140. if(i == 6) {
  141. x = draw_bits(canvas, center_bits, x, y, width, height + 5);
  142. }
  143. }
  144. }
  145. furi_string_free(left_structure);
  146. furi_string_free(code_part);
  147. //draw the ending guard pattern
  148. x = draw_bits(canvas, end_bits, x, y, width, height + 5);
  149. }
  150. /**
  151. * Draw a UPC-A barcode
  152. */
  153. static void draw_upc_a(Canvas* canvas, BarcodeData* barcode_data) {
  154. FuriString* barcode_digits = barcode_data->correct_data;
  155. BarcodeTypeObj* type_obj = barcode_data->type_obj;
  156. int barcode_length = furi_string_size(barcode_digits);
  157. int x = type_obj->start_pos;
  158. int y = BARCODE_Y_START;
  159. int width = 1;
  160. int height = BARCODE_HEIGHT;
  161. //the guard patterns for the beginning, center, ending
  162. char* end_bits = "101";
  163. char* center_bits = "01010";
  164. //draw the starting guard pattern
  165. x = draw_bits(canvas, end_bits, x, y, width, height + 5);
  166. FuriString* code_part = furi_string_alloc();
  167. //loop through each digit, find the encoding, and draw it
  168. for(int i = 0; i < barcode_length; i++) {
  169. char current_digit = furi_string_get_char(barcode_digits, i);
  170. int index = current_digit - '0'; //convert the number into an int (also the index)
  171. //use the L-codes for the first 6 digits and the R-Codes for the last 6 digits
  172. if(i <= 5) {
  173. furi_string_set_str(code_part, UPC_EAN_L_CODES[index]);
  174. } else {
  175. furi_string_set_str(code_part, UPC_EAN_R_CODES[index]);
  176. }
  177. //convert the current_digit char into a string so it can be printed
  178. char current_digit_string[2];
  179. snprintf(current_digit_string, 2, "%c", current_digit);
  180. //set the canvas color to black to print the digit
  181. canvas_set_color(canvas, ColorBlack);
  182. canvas_draw_str(canvas, x + 1, y + height + 8, current_digit_string);
  183. //draw the bits of the barcode
  184. x = draw_bits(canvas, furi_string_get_cstr(code_part), x, y, width, height);
  185. //if the index has reached 6, that means 6 digits have been drawn and we now draw the center guard pattern
  186. if(i == 5) {
  187. x = draw_bits(canvas, center_bits, x, y, width, height + 5);
  188. }
  189. }
  190. furi_string_free(code_part);
  191. //draw the ending guard pattern
  192. x = draw_bits(canvas, end_bits, x, y, width, height + 5);
  193. }
  194. static void draw_code_39(Canvas* canvas, BarcodeData* barcode_data) {
  195. FuriString* raw_data = barcode_data->raw_data;
  196. FuriString* barcode_digits = barcode_data->correct_data;
  197. //BarcodeTypeObj* type_obj = barcode_data->type_obj;
  198. int barcode_length = furi_string_size(barcode_digits);
  199. int total_pixels = 0;
  200. for(int i = 0; i < barcode_length; i++) {
  201. //1 for wide, 0 for narrow
  202. char wide_or_narrow = furi_string_get_char(barcode_digits, i);
  203. int wn_digit = wide_or_narrow - '0'; //wide(1) or narrow(0) digit
  204. if(wn_digit == 1) {
  205. total_pixels += 3;
  206. } else {
  207. total_pixels += 1;
  208. }
  209. if((i + 1) % 9 == 0) {
  210. total_pixels += 1;
  211. }
  212. }
  213. int x = (128 - total_pixels) / 2;
  214. int y = BARCODE_Y_START;
  215. int width = 1;
  216. int height = BARCODE_HEIGHT;
  217. bool filled_in = true;
  218. //set the canvas color to black to print the digit
  219. canvas_set_color(canvas, ColorBlack);
  220. // canvas_draw_str_aligned(canvas, 62, 30, AlignCenter, AlignCenter, error);
  221. canvas_draw_str_aligned(
  222. canvas, 62, y + height + 8, AlignCenter, AlignBottom, furi_string_get_cstr(raw_data));
  223. for(int i = 0; i < barcode_length; i++) {
  224. //1 for wide, 0 for narrow
  225. char wide_or_narrow = furi_string_get_char(barcode_digits, i);
  226. int wn_digit = wide_or_narrow - '0'; //wide(1) or narrow(0) digit
  227. if(filled_in) {
  228. if(wn_digit == 1) {
  229. x = draw_bits(canvas, "111", x, y, width, height);
  230. } else {
  231. x = draw_bits(canvas, "1", x, y, width, height);
  232. }
  233. filled_in = false;
  234. } else {
  235. if(wn_digit == 1) {
  236. x = draw_bits(canvas, "000", x, y, width, height);
  237. } else {
  238. x = draw_bits(canvas, "0", x, y, width, height);
  239. }
  240. filled_in = true;
  241. }
  242. if((i + 1) % 9 == 0) {
  243. x = draw_bits(canvas, "0", x, y, width, height);
  244. filled_in = true;
  245. }
  246. }
  247. }
  248. static void draw_code_128(Canvas* canvas, BarcodeData* barcode_data) {
  249. FuriString* raw_data = barcode_data->raw_data;
  250. FuriString* barcode_digits = barcode_data->correct_data;
  251. int barcode_length = furi_string_size(barcode_digits);
  252. int x = (128 - barcode_length) / 2;
  253. int y = BARCODE_Y_START;
  254. int width = 1;
  255. int height = BARCODE_HEIGHT;
  256. x = draw_bits(canvas, furi_string_get_cstr(barcode_digits), x, y, width, height);
  257. //set the canvas color to black to print the digit
  258. canvas_set_color(canvas, ColorBlack);
  259. // canvas_draw_str_aligned(canvas, 62, 30, AlignCenter, AlignCenter, error);
  260. canvas_draw_str_aligned(
  261. canvas, 62, y + height + 8, AlignCenter, AlignBottom, furi_string_get_cstr(raw_data));
  262. }
  263. static void draw_codabar(Canvas* canvas, BarcodeData* barcode_data) {
  264. FuriString* raw_data = barcode_data->raw_data;
  265. FuriString* barcode_digits = barcode_data->correct_data;
  266. //BarcodeTypeObj* type_obj = barcode_data->type_obj;
  267. int barcode_length = furi_string_size(barcode_digits);
  268. int total_pixels = 0;
  269. for(int i = 0; i < barcode_length; i++) {
  270. //1 for wide, 0 for narrow
  271. char wide_or_narrow = furi_string_get_char(barcode_digits, i);
  272. int wn_digit = wide_or_narrow - '0'; //wide(1) or narrow(0) digit
  273. if(wn_digit == 1) {
  274. total_pixels += 3;
  275. } else {
  276. total_pixels += 1;
  277. }
  278. if((i + 1) % 7 == 0) {
  279. total_pixels += 1;
  280. }
  281. }
  282. int x = (128 - total_pixels) / 2;
  283. int y = BARCODE_Y_START;
  284. int width = 1;
  285. int height = BARCODE_HEIGHT;
  286. bool filled_in = true;
  287. //set the canvas color to black to print the digit
  288. canvas_set_color(canvas, ColorBlack);
  289. // canvas_draw_str_aligned(canvas, 62, 30, AlignCenter, AlignCenter, error);
  290. canvas_draw_str_aligned(
  291. canvas, 62, y + height + 8, AlignCenter, AlignBottom, furi_string_get_cstr(raw_data));
  292. for(int i = 0; i < barcode_length; i++) {
  293. //1 for wide, 0 for narrow
  294. char wide_or_narrow = furi_string_get_char(barcode_digits, i);
  295. int wn_digit = wide_or_narrow - '0'; //wide(1) or narrow(0) digit
  296. if(filled_in) {
  297. if(wn_digit == 1) {
  298. x = draw_bits(canvas, "111", x, y, width, height);
  299. } else {
  300. x = draw_bits(canvas, "1", x, y, width, height);
  301. }
  302. filled_in = false;
  303. } else {
  304. if(wn_digit == 1) {
  305. x = draw_bits(canvas, "000", x, y, width, height);
  306. } else {
  307. x = draw_bits(canvas, "0", x, y, width, height);
  308. }
  309. filled_in = true;
  310. }
  311. if((i + 1) % 7 == 0) {
  312. x = draw_bits(canvas, "0", x, y, width, height);
  313. filled_in = true;
  314. }
  315. }
  316. }
  317. static void barcode_draw_callback(Canvas* canvas, void* ctx) {
  318. furi_assert(ctx);
  319. BarcodeModel* barcode_model = ctx;
  320. BarcodeData* data = barcode_model->data;
  321. // const char* barcode_digits =;
  322. canvas_clear(canvas);
  323. if(data->valid) {
  324. switch(data->type_obj->type) {
  325. case UPCA:
  326. draw_upc_a(canvas, data);
  327. break;
  328. case EAN8:
  329. draw_ean_8(canvas, data);
  330. break;
  331. case EAN13:
  332. draw_ean_13(canvas, data);
  333. break;
  334. case CODE39:
  335. draw_code_39(canvas, data);
  336. break;
  337. case CODE128:
  338. case CODE128C:
  339. draw_code_128(canvas, data);
  340. break;
  341. case CODABAR:
  342. draw_codabar(canvas, data);
  343. break;
  344. case UNKNOWN:
  345. default:
  346. break;
  347. }
  348. } else {
  349. draw_error_str(
  350. canvas, get_error_code_name(data->reason), get_error_code_message(data->reason));
  351. }
  352. }
  353. bool barcode_input_callback(InputEvent* input_event, void* ctx) {
  354. UNUSED(ctx);
  355. //furi_assert(ctx);
  356. //Barcode* test_view_object = ctx;
  357. if(input_event->key == InputKeyBack) {
  358. return false;
  359. } else {
  360. return true;
  361. }
  362. }
  363. Barcode* barcode_view_allocate(BarcodeApp* barcode_app) {
  364. furi_assert(barcode_app);
  365. Barcode* barcode = malloc(sizeof(Barcode));
  366. barcode->view = view_alloc();
  367. barcode->barcode_app = barcode_app;
  368. view_set_context(barcode->view, barcode);
  369. view_allocate_model(barcode->view, ViewModelTypeLocking, sizeof(BarcodeModel));
  370. view_set_draw_callback(barcode->view, barcode_draw_callback);
  371. view_set_input_callback(barcode->view, barcode_input_callback);
  372. return barcode;
  373. }
  374. void barcode_free_model(Barcode* barcode) {
  375. with_view_model(
  376. barcode->view,
  377. BarcodeModel * model,
  378. {
  379. if(model->file_path != NULL) {
  380. furi_string_free(model->file_path);
  381. }
  382. if(model->data != NULL) {
  383. if(model->data->raw_data != NULL) {
  384. furi_string_free(model->data->raw_data);
  385. }
  386. if(model->data->correct_data != NULL) {
  387. furi_string_free(model->data->correct_data);
  388. }
  389. free(model->data);
  390. }
  391. },
  392. false);
  393. }
  394. void barcode_free(Barcode* barcode) {
  395. furi_assert(barcode);
  396. barcode_free_model(barcode);
  397. view_free(barcode->view);
  398. free(barcode);
  399. }
  400. View* barcode_get_view(Barcode* barcode) {
  401. furi_assert(barcode);
  402. return barcode->view;
  403. }