lmtzint.c /size: 21 Kb    last modification: 2024-01-16 10:22
1/*
2    See license.txt in the root of this project.
3*/
4
5/*
6    For a long time the zint api was quite stable but in after 2020 it started changing: the data
7    structures got fields added in the middle So, after a few updates Michal Vlasák suggested that
8    we adapt to versions. We can always decide to drop older ones when we get too many. The next
9    variant is a mix of our attempts to deal with this issue.
10
11*/
12
13# include "luametatex.h"
14# include "lmtoptional.h"
15
16# define ZINT_UNICODE_MODE   1
17# define ZINT_OUT_BUFFER     0
18# define ZINT_DM_SQUARE    100
19
20struct zint_vector;
21
22typedef struct {
23    int                 symbology;
24    float               height;
25    int                 whitespace_width;
26    int                 whitespace_height;
27    int                 border_width;
28    int                 output_options;
29    char                fgcolour[10];
30    char                bgcolour[10];
31    char               *fgcolor;
32    char               *bgcolor;
33    char                outfile[256];
34    float               scale;
35    int                 option_1;
36    int                 option_2;
37    int                 option_3;
38    int                 show_hrt;
39    int                 fontsize;
40    int                 input_mode;
41    int                 eci;
42    unsigned char       text[128];
43    int                 rows;
44    int                 width;
45    char                primary[128];
46    unsigned char       encoded_data[200][143];
47    float               row_height[200];
48    char                errtxt[100];
49    unsigned char      *bitmap;
50    int                 bitmap_width;
51    int                 bitmap_height;
52    unsigned char      *alphamap;
53    unsigned int        bitmap_byte_length;
54    float               dot_size;
55    struct zint_vector *vector;
56    int                 debug;
57    int                 warn_level;
58} zint_symbol_210;
59
60struct zint_structapp {
61    int  index;
62    int  count;
63    char id[32];
64};
65
66typedef struct {
67    int                    symbology;
68    float                  height;
69    float                  scale;
70    int                    whitespace_width;
71    int                    whitespace_height;
72    int                    border_width;
73    int                    output_options;
74    char                   fgcolour[10];
75    char                   bgcolour[10];
76    char                  *fgcolor;
77    char                  *bgcolor;
78    char                   outfile[256];
79    char                   primary[128];
80    int                    option_1;
81    int                    option_2;
82    int                    option_3;
83    int                    show_hrt;
84    int                    fontsize;
85    int                    input_mode;
86    int                    eci;
87    float                  dot_size;
88    float                  guard_descent;
89    struct zint_structapp  structapp;
90    int                    warn_level;
91    int                    debug;
92    unsigned char          text[128];
93    int                    rows;
94    int                    width;
95    unsigned char          encoded_data[200][144];
96    float                  row_height[200];
97    char                   errtxt[100];
98    unsigned char         *bitmap;
99    int                    bitmap_width;
100    int                    bitmap_height;
101    unsigned char         *alphamap;
102    unsigned int           bitmap_byte_length;
103    struct zint_vector    *vector;
104} zint_symbol_211;
105
106typedef struct {
107    int                    symbology;
108    float                  height;
109    float                  scale;
110    int                    whitespace_width;
111    int                    whitespace_height;
112    int                    border_width;
113    int                    output_options;
114    char                   fgcolour[10];
115    char                   bgcolour[10];
116    char                  *fgcolor;
117    char                  *bgcolor;
118    char                   outfile[256];
119    char                   primary[128];
120    int                    option_1;
121    int                    option_2;
122    int                    option_3;
123    int                    show_hrt;
124    int                    fontsize;
125    int                    input_mode;
126    float                  dpmm;
127    int                    eci;
128    float                  dot_size;
129    float                  guard_descent;
130    struct zint_structapp  structapp;
131    int                    warn_level;
132    int                    debug;
133    unsigned char          text[128];
134    int                    rows;
135    int                    width;
136    unsigned char          encoded_data[200][144];
137    float                  row_height[200];
138    char                   errtxt[100];
139    unsigned char         *bitmap;
140    int                    bitmap_width;
141    int                    bitmap_height;
142    unsigned char         *alphamap;
143    unsigned int           bitmap_byte_length;
144    struct zint_vector    *vector;
145} zint_symbol_212;
146
147/* It looks like we have 2.12's with a different blob: */
148
149// typedef struct {
150//     int                    symbology;
151//     float                  height;
152//     float                  scale;
153//     int                    whitespace_width;
154//     int                    whitespace_height;
155//     int                    border_width;
156//     int                    output_options;
157//     char                   fgcolour[16];
158//     char                   bgcolour[16];
159//     char                  *fgcolor;
160//     char                  *bgcolor;
161//     char                   outfile[256];
162//     char                   primary[128];
163//     int                    option_1;
164//     int                    option_2;
165//     int                    option_3;
166//     int                    show_hrt;
167//     int                    input_mode;
168//     int                    eci;
169//     float                  dpmm;
170//     float                  dot_size;
171//     float                  text_gap;
172//     float                  guard_descent;
173//     struct zint_structapp  structapp;
174//     int                    warn_level;
175//     int                    debug;
176//     unsigned char          text[160];
177//     int                    rows;
178//     int                    width;
179//     unsigned char          encoded_data[200][144];
180//     float                  row_height[200];
181//     char                   errtxt[100];
182//     unsigned char         *bitmap;
183//     int                    bitmap_width;
184//     int                    bitmap_height;
185//     unsigned char         *alphamap;
186//     struct zint_vector    *vector;
187// } zint_symbol_212;
188
189typedef struct zint_rectangle zint_rectangle;
190
191typedef struct {
192    double          x;
193    double          y;
194    double          w;
195    double          h;
196    zint_rectangle *next;
197} lmt_zint_rectangle;
198
199static void lmt_zint_get_rect(
200    zint_rectangle     *zint_,
201    lmt_zint_rectangle *lmt
202)
203{
204    struct {
205        float           x;
206        float           y;
207        float           height;
208        float           width;
209        int             colour;
210        zint_rectangle *next;
211    } *zint = (void*) zint_;
212    lmt->x = (double) zint->x;
213    lmt->y = (double) zint->y;
214    lmt->w = (double) zint->width;
215    lmt->h = (double) zint->height;
216    lmt->next = zint->next;
217}
218
219typedef struct zint_circle zint_circle;
220
221typedef struct {
222    double       x;
223    double       y;
224    double       d;
225    zint_circle *next;
226} lmt_zint_circle;
227
228static void lmt_zint_get_circle_210
229(
230    zint_circle     *zint_,
231    lmt_zint_circle *lmt
232)
233{
234    struct {
235        float         x;
236        float         y;
237        float         diameter;
238        int           colour;
239        zint_circle  *next;
240    } *zint   = (void*) zint_;
241    lmt->x    = (double) zint->x;
242    lmt->y    = (double) zint->y;
243    lmt->d    = (double) zint->diameter;
244    lmt->next = zint->next;
245}
246
247static void lmt_zint_get_circle_211
248(
249    zint_circle     *zint_,
250    lmt_zint_circle *lmt
251)
252{
253    struct {
254        float         x;
255        float         y;
256        float         diameter;
257        float         width;
258        int           colour;
259        zint_circle  *next;
260    } *zint   = (void*) zint_;
261    lmt->x    = (double) zint->x;
262    lmt->y    = (double) zint->y;
263    lmt->d    = (double) zint->diameter;
264    lmt->next = zint->next;
265}
266
267static void lmt_zint_get_circle_212
268(
269    zint_circle     *zint_,
270    lmt_zint_circle *lmt
271)
272{
273    struct {
274        float         x;
275        float         y;
276        float         diameter;
277        float         width;
278        int           colour;
279        zint_circle  *next;
280    } *zint   = (void*) zint_;
281    lmt->x    = (double) zint->x;
282    lmt->y    = (double) zint->y;
283    lmt->d    = (double) zint->diameter;
284    lmt->next = zint->next;
285}
286
287typedef struct zint_hexagon zint_hexagon;
288
289typedef struct {
290    double        x;
291    double        y;
292    double        d;
293    zint_hexagon *next;
294} lmt_zint_hexagon;
295
296static void lmt_zint_get_hexagon
297(
298    zint_hexagon     *zint_,
299    lmt_zint_hexagon *lmt
300)
301{
302    struct {
303        float          x;
304        float          y;
305        float          diameter;
306        int            rotation;
307        zint_hexagon  *next;
308    } *zint   = (void *) zint_;
309    lmt->x    = (double) zint->x;
310    lmt->y    = (double) zint->y;
311    lmt->d    = (double) zint->diameter;
312    lmt->next = zint->next;
313}
314
315typedef struct zint_string zint_string;
316
317typedef struct {
318    double       x;
319    double       y;
320    double       s;
321    const char  *t;
322    zint_string *next;
323} lmt_zint_string;
324
325static void lmt_zint_next_string(zint_string *zint_, lmt_zint_string *lmt)
326{
327    struct {
328        float          x;
329        float          y;
330        float          fsize;
331        float          width;
332        int            length;
333        int            rotation;
334        int            halign;
335        unsigned char *text;
336        zint_string   *next;
337    } *zint   = (void *) zint_;
338    lmt->x    = (double) zint->x;
339    lmt->y    = (double) zint->y;
340    lmt->s    = (double) zint->fsize;
341    lmt->t    = (const char *) zint->text;
342    lmt->next = zint->next;
343}
344
345typedef struct zint_symbol zint_symbol;
346
347typedef struct zint_vector {
348    float           width;
349    float           height;
350    zint_rectangle *rectangles;
351    zint_hexagon   *hexagons;
352    zint_string    *strings;
353    zint_circle    *circles;
354} zint_vector;
355
356static zint_vector *lmt_zint_vector_210(zint_symbol *symbol_)
357{
358    zint_symbol_210 *symbol = (void*) symbol_;
359    return symbol->vector;
360}
361
362static zint_vector *lmt_zint_vector_211(zint_symbol *symbol_)
363{
364    zint_symbol_211 *symbol = (void*) symbol_;
365    return symbol->vector;
366}
367
368static zint_vector *lmt_zint_vector_212(zint_symbol *symbol_)
369{
370    zint_symbol_212 *symbol = (void*) symbol_;
371    return symbol->vector;
372}
373
374static void lmt_zint_symbol_set_options_210(zint_symbol *symbol_, int symbology, int input_mode, int output_options, int square)
375{
376    zint_symbol_210 *symbol = (void*) symbol_;
377    symbol->symbology = symbology;
378    symbol->input_mode = input_mode;
379    symbol->output_options = output_options;
380    if (square)
381        symbol->option_3 = ZINT_DM_SQUARE;
382}
383
384static void lmt_zint_symbol_set_options_211(zint_symbol *symbol_, int symbology, int input_mode, int output_options, int square)
385{
386    zint_symbol_211 *symbol = (void*) symbol_;
387    symbol->symbology = symbology;
388    symbol->input_mode = input_mode;
389    symbol->output_options = output_options;
390    if (square) {
391        symbol->option_3 = ZINT_DM_SQUARE;
392    }
393}
394
395static void lmt_zint_symbol_set_options_212(zint_symbol *symbol_, int symbology, int input_mode, int output_options, int square)
396{
397    zint_symbol_212 *symbol = (void*) symbol_;
398    symbol->symbology = symbology;
399    symbol->input_mode = input_mode;
400    symbol->output_options = output_options;
401    if (square) {
402        symbol->option_3 = ZINT_DM_SQUARE;
403    }
404}
405
406typedef struct zintlib_state_info {
407
408    int initialized;
409    int version;
410
411    int (*ZBarcode_Version) (
412        void
413    );
414
415    zint_symbol * (*ZBarcode_Create) (
416        void
417    );
418
419    void (*ZBarcode_Delete) (
420        zint_symbol *symbol
421    );
422
423    int (*ZBarcode_Encode_and_Buffer_Vector) (
424        zint_symbol         *symbol,
425        const unsigned char *input,
426        int                  length,
427        int                  rotate_angle
428    );
429
430} zintlib_state_info;
431
432static zintlib_state_info zintlib_state = {
433
434    .initialized                       = 0,
435    .version                           = 0,
436
437    .ZBarcode_Version                  = NULL,
438    .ZBarcode_Create                   = NULL,
439    .ZBarcode_Delete                   = NULL,
440    .ZBarcode_Encode_and_Buffer_Vector = NULL,
441
442};
443
444static void (*lmt_zint_get_circle) (
445    zint_circle     *zint_,
446	lmt_zint_circle *lmt
447);
448
449static zint_vector *(*lmt_zint_vector)(
450    zint_symbol *symbol_
451);
452static void (*lmt_zint_symbol_set_options)(
453    zint_symbol *symbol,
454    int          symbology,
455    int          input_mode,
456    int          output_options,
457    int          square
458);
459
460static int zintlib_initialize(lua_State * L)
461{
462    if (! zintlib_state.initialized) {
463        const char *filename = lua_tostring(L, 1);
464        if (filename) {
465
466            lmt_library lib = lmt_library_load(filename);
467
468            zintlib_state.ZBarcode_Version                  = lmt_library_find(lib, "ZBarcode_Version");
469            zintlib_state.ZBarcode_Create                   = lmt_library_find(lib, "ZBarcode_Create");
470            zintlib_state.ZBarcode_Delete                   = lmt_library_find(lib, "ZBarcode_Delete");
471            zintlib_state.ZBarcode_Encode_and_Buffer_Vector = lmt_library_find(lib, "ZBarcode_Encode_and_Buffer_Vector");
472
473            zintlib_state.initialized = lmt_library_okay(lib);
474
475            if (zintlib_state.ZBarcode_Version) {
476                zintlib_state.version = zintlib_state.ZBarcode_Version();
477            }
478            zintlib_state.version = zintlib_state.version / 100;
479         // printf("zint version: %i\n", zintlib_state.version);
480            if (zintlib_state.version < 210) {
481                zintlib_state.initialized = 0;
482            } else if (zintlib_state.version < 211) {
483                lmt_zint_get_circle         = lmt_zint_get_circle_210;
484                lmt_zint_vector             = lmt_zint_vector_210;
485                lmt_zint_symbol_set_options = lmt_zint_symbol_set_options_210;
486            } else if (zintlib_state.version < 212) {
487                lmt_zint_get_circle         = lmt_zint_get_circle_211;
488                lmt_zint_vector             = lmt_zint_vector_211;
489                lmt_zint_symbol_set_options = lmt_zint_symbol_set_options_211;
490            } else {
491                lmt_zint_get_circle         = lmt_zint_get_circle_212;
492                lmt_zint_vector             = lmt_zint_vector_212;
493                lmt_zint_symbol_set_options = lmt_zint_symbol_set_options_212;
494            }
495        }
496    }
497    lua_pushboolean(L, zintlib_state.initialized);
498    return 1;
499}
500
501static int zintlib_execute(lua_State * L)
502{
503    if (zintlib_state.initialized) {
504        if (lua_type(L, 1) == LUA_TTABLE) {
505            int code = -1;
506            size_t l = 0;
507            const unsigned char *s = NULL;
508            const char *o = NULL;
509            if (lua_getfield(L, 1, "code") == LUA_TNUMBER) {
510                code = lmt_tointeger(L, -1);
511            }
512            lua_pop(L, 1);
513            switch (lua_getfield(L, 1, "text")) {
514                case LUA_TSTRING:
515                case LUA_TNUMBER:
516                    s = (const unsigned char *) lua_tolstring(L, -1, &l);
517                    break;
518            }
519            lua_pop(L, 1);
520            if (lua_getfield(L, 1, "option") == LUA_TSTRING) {
521                /* for the moment one option */
522                o = lua_tostring(L, -1);
523            }
524            lua_pop(L, 1);
525            if (code >= 0 && l > 0) {
526                zint_symbol *symbol = zintlib_state.ZBarcode_Create();
527                if (symbol) {
528                    /*tex
529                        We could handle this at the \LUA\ end but as we only have a few options we
530                        do it here.
531                    */
532                    int square = (o && (strcmp(o, "square") == 0)) ? 1 : 0;
533                    lmt_zint_symbol_set_options(symbol, code, ZINT_UNICODE_MODE, ZINT_OUT_BUFFER, square);
534                    if (zintlib_state.ZBarcode_Encode_and_Buffer_Vector(symbol, s, (int) l, 0)) {
535                        zintlib_state.ZBarcode_Delete(symbol);
536                        lua_pushboolean(L, 0);
537                        lua_pushstring(L, "invalid result");
538                    } else {
539                        zint_vector *vector = lmt_zint_vector(symbol);
540                        if (vector) {
541                            /*tex
542                                It's a bit like the svg output ... first I used named fields but a
543                                list is more efficient, not so much in the \LUA\ interfacing but in
544                                generating an compact path at the \METAPOST\ end.
545                            */
546                            lua_createtable(L, 0, 4);
547                            if (vector->rectangles) {
548                                lmt_zint_rectangle rectangle;
549                                int i = 1;
550                                lua_newtable(L);
551                                for (zint_rectangle *r = vector->rectangles; r; r = rectangle.next) {
552                                    lmt_zint_get_rect(r, &rectangle);
553                                    lua_createtable(L, 4, 0);
554                                    lua_pushinteger(L, lmt_roundedfloat(rectangle.x)); lua_rawseti(L, -2, 1);
555                                    lua_pushinteger(L, lmt_roundedfloat(rectangle.y)); lua_rawseti(L, -2, 2);
556                                    lua_pushinteger(L, lmt_roundedfloat(rectangle.w)); lua_rawseti(L, -2, 3);
557                                    lua_pushinteger(L, lmt_roundedfloat(rectangle.h)); lua_rawseti(L, -2, 4);
558                                    lua_rawseti(L, -2, i++);
559                                }
560                                lua_setfield(L, -2, "rectangles");
561                            }
562                            if (vector->hexagons) {
563                                lmt_zint_hexagon hexagon;
564                                int i = 1;
565                                lua_newtable(L);
566                                for (zint_hexagon *h = vector->hexagons; h; h = hexagon.next) {
567                                    lmt_zint_get_hexagon(h, &hexagon);
568                                    lua_createtable(L, 0, 3);
569                                    lua_pushinteger(L, lmt_roundedfloat(hexagon.x)); lua_rawseti(L, -2, 1);
570                                    lua_pushinteger(L, lmt_roundedfloat(hexagon.y)); lua_rawseti(L, -2, 2);
571                                    lua_pushinteger(L, lmt_roundedfloat(hexagon.d)); lua_rawseti(L, -2, 3);
572                                    lua_rawseti(L, -2, i++);
573                                }
574                                lua_setfield(L, -2, "hexagons");
575                            }
576                            if (vector->circles) {
577                                lmt_zint_circle circle;
578                                int i = 1;
579                                lua_newtable(L);
580                                for (zint_circle *c = vector->circles; c; c = circle.next) {
581                                    lmt_zint_get_circle(c, &circle);
582                                    lua_createtable(L, 0, 3);
583                                    lua_pushinteger(L, lmt_roundedfloat(circle.x)); lua_rawseti(L, -2, 1);
584                                    lua_pushinteger(L, lmt_roundedfloat(circle.y)); lua_rawseti(L, -2, 2);
585                                    lua_pushinteger(L, lmt_roundedfloat(circle.d)); lua_rawseti(L, -2, 3);
586                                    lua_rawseti(L, -2, i++);
587                                }
588                                lua_setfield(L, -2, "circles");
589                            }
590                            if (vector->strings) {
591                                lmt_zint_string string;
592                                int i = 1;
593                                lua_newtable(L);
594                                for (zint_string *s = vector->strings; s; s = string.next) {
595                                    lmt_zint_next_string(s, &string);
596                                    lua_createtable(L, 0, 4);
597                                    lua_pushinteger(L, lmt_roundedfloat(string.x)); lua_rawseti(L, -2, 1);
598                                    lua_pushinteger(L, lmt_roundedfloat(string.y)); lua_rawseti(L, -2, 2);
599                                    lua_pushinteger(L, lmt_roundedfloat(string.s)); lua_rawseti(L, -2, 3);
600                                    lua_pushstring (L,                  string.t ); lua_rawseti(L, -2, 4);
601                                    lua_rawseti(L, -2, i++);
602                                }
603                                lua_setfield(L, -2, "strings");
604                            }
605                            zintlib_state.ZBarcode_Delete(symbol);
606                            return 1;
607                        } else {
608                            zintlib_state.ZBarcode_Delete(symbol);
609                            lua_pushboolean(L, 0);
610                            lua_pushstring(L, "invalid result vector");
611                        }
612                    }
613                } else {
614                    lua_pushboolean(L, 0);
615                    lua_pushstring(L, "invalid result symbol");
616                }
617            } else {
618                lua_pushboolean(L, 0);
619                lua_pushstring(L, "invalid code");
620            }
621        } else {
622            lua_pushboolean(L, 0);
623            lua_pushstring(L, "invalid specification");
624        }
625    } else {
626        lua_pushboolean(L, 0);
627        lua_pushstring(L, "not initialized");
628    }
629    return 2;
630}
631
632static struct luaL_Reg zintlib_function_list[] = {
633    { "initialize", zintlib_initialize },
634    { "execute",    zintlib_execute    },
635    { NULL,         NULL               },
636};
637
638int luaopen_zint(lua_State * L)
639{
640    lmt_library_register(L, "zint", zintlib_function_list);
641    return 0;
642}
643