1 /* zint_tcl.c TCL binding for zint */
2 /*
3     zint - the open source tcl binding to the zint barcode library
4     Copyright (C) 2014 Harald Oehlmann <oehhar@users.sourceforge.net>
5 
6     Redistribution and use in source and binary forms, with or without
7     modification, are permitted provided that the following conditions
8     are met:
9 
10     1. Redistributions of source code must retain the above copyright
11        notice, this list of conditions and the following disclaimer.
12     2. Redistributions in binary form must reproduce the above copyright
13        notice, this list of conditions and the following disclaimer in the
14        documentation and/or other materials provided with the distribution.
15     3. Neither the name of the project nor the names of its contributors
16        may be used to endorse or promote products derived from this software
17        without specific prior written permission.
18 
19     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22     ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
23     FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25     OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28     OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29     SUCH DAMAGE.
30 */
31 /* vim: set ts=4 sw=4 et : */
32 /*
33  History
34 
35   2014-06-16 2.5.0 HaO
36     First implementation
37  2016-09-14 2.5.1 HaO
38 -   Added Codablock F options "-rows".
39 -   Adopted to new image format of zint
40  2016-10-14 2.5.2 HaO
41 -   Include the upstream reverted image format
42  2016-12-12 2.5.3 HaO
43 -   No changes here, take 2.5.1 framework files
44  2017-05-12 2.6.0 HaO
45 -   No changes here, take 2.6 framework files
46  2017-08-29 2.6.1 HaO
47 -   Framework 2.6.1 extensions
48 -   EAN/UPC Codes with included check digit
49 -   UPNQR Code
50 -   Misspelled symbology: AztecRunes
51  2017-10-23 2.6.2 HaO
52 -   Framework 2.6.2 bugfixes
53 -   Allow dll unload
54  2018-02-13 2.6.3 HaO
55  -  Framework trunk update
56  -  Added VIN and MailMark symbologies.
57  2018-11-02 2.6.4 HaO
58  -  Framework trunk update
59  -  Add options -bold, -dotted, -dotsize, -dmre, -eci
60  -  Implemented ECI logic
61  2019-09-01 2.6.5 HaO
62  -  Framework 2.6.5 update
63  -  Add option -gssep
64  2019-09-18 2.6.6 HaO
65  -  Framework 2.6.6 update
66  2019-10-07 2.6.7 HaO
67  -  Framework 2.6.7 update
68  2019-12-05 2.7.0 HaO
69  -  Framework 2.7.0 update
70  -  Add symbology rmqr
71  2020-02-01 2.7.1 HaO
72  -  Framework 2.7.1 update
73  2020-04-06 HaO
74  -  Added option -fullmultibyte
75  2020-04-07 2.8.0 HaO
76  - Added symbology "UltraCode".
77  2020-05-19 HaO
78  - Added option -separator to specify stacked symbology separator width
79  - -cols maximum changed from 66 to 67
80  2020-07-27 2.9.0 HaO
81  - added option "-addongap"
82  - Renamed symbology names:
83     - Matrix2of5 -> Standard2of5
84     - PDF417Trunc -> PDF417Compact
85     - RSS14Stacked -> GS1DataBarStacked
86     - RSS14Stacked -> GS1DataBarStacked
87     - RSS14StackedOmni -> GS1DataBarSstackedOmni
88     - RSS14ExpandedStacked -> GS1DataBarExpandedStacked
89     - OneCode -> USPSIntelligentMail
90     - EAN128-CC -> GS1-128-CC
91     - RSS14-CC -> GS1DataBarOmni-CC
92     - RSSLimited-CC -> GS1DataBarLimited-CC
93     - RSSExpandedStacked-CC -> GS1DataBarExpanded-CC
94     - RSSEXPanded-CC -> GS1DataBarExpanded-CC
95     - RSS14Stacked-CC -> GS1DataBarStacked-CC
96     - RSS14Omni-CC -> GS1DataBarStackedOmni-CC
97     - RSSExpandedStacked-CC -> GS1DataBarExpandedStacked-CC
98     *** Potential incompatibility ***
99 2020-08-04 2.10.0 HaO
100 - added symbology "DPDCode"
101 - Alpha channel support added:
102     - added option -nobackground
103     - also allow RRGGBBAA for -fg and -bg options
104 2021-01-05 2.9.1 HaO
105 - Added options -reverse, -werror, -wzpl
106 - Use version number from zint.h (first 3 digits). Do not use an own one.
107 2021-01-14 GL
108 - Removed TCL native encoding of ECI's and replace by zint buildin mechanism.
109   The input is now UTF-8 for any ECI and zint cares about the encoding.
110 2021-01-14 HaO
111 - Added detection of presence of the Tk package and late initialization.
112   This is a preparation to add a TCL only mode to the DLL.
113 2021-01-22 GL
114 - -cols maximum changed from 67 to 108 (DotCode)
115 2021-05-10 GL
116 - Added -gs1parens option
117 2021-05-22 GL
118 - Added -vwhitesp option
119 2021-05-28 GL
120 - -cols maximum changed from 108 to 200 (DotCode)
121 2021-07-09 GL
122 - Removed -wzpl, added -gs1nocheck
123 - Made -format position independent
124 - Tabs -> spaces
125 */
126 
127 #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
128 #pragma warning(disable : 4201 4214 4514)
129 #define STRICT
130 #define WIN32_LEAN_AND_MEAN
131 /* TCL Defines */
132 #define DLL_BUILD
133 
134 #include <windows.h>
135 
136 /* Define ERROR_INVALID_DATA is also used by zint... */
137 #ifdef ERROR_INVALID_DATA
138 #undef ERROR_INVALID_DATA
139 #endif
140 #endif
141 
142 #include <zint.h>
143 /* Load version defines */
144 #include <zintconfig.h>
145 #include <string.h>
146 
147 #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
148 #define USE_TCL_STUBS
149 #define USE_TK_STUBS
150 #endif
151 
152 #include <tcl.h>
153 #include <tk.h>
154 
155 #undef EXPORT
156 #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
157 #define EXPORT __declspec(dllexport)
158 #else
159 #define EXPORT
160 #endif
161 
162 
163 /*----------------------------------------------------------------------------*/
164 /* >>>>> Hepler defines */
165 
166 /* Two macros are necessary to not include the define name, but the value */
167 #define STRING(x) #x
168 #define TOSTRING(x) STRING(x)
169 
170 /* Define VERSION as the first 3 digits of the zint library version number */
171 #define VERSION TOSTRING( ZINT_VERSION_MAJOR ) \
172         "." TOSTRING( ZINT_VERSION_MINOR ) \
173         "." TOSTRING( ZINT_VERSION_RELEASE )
174 
175 /*----------------------------------------------------------------------------*/
176 /* >>>> External Prototypes (exports) */
177 EXPORT int Zint_Init (Tcl_Interp *interp);
178 EXPORT int Zint_Unload (Tcl_Interp *Interp, int Flags);
179 /*----------------------------------------------------------------------------*/
180 /* >>>> local prototypes */
181 static void InterpCleanupProc(ClientData clientData, Tcl_Interp *interp);
182 static int CheckForTk(Tcl_Interp *interp, int *tkFlagPtr);
183 static int Zint(ClientData unused, Tcl_Interp *interp, int objc,
184     Tcl_Obj *CONST objv[]);
185 static int Encode(Tcl_Interp *interp, int objc,
186     Tcl_Obj *CONST objv[]);
187 /*----------------------------------------------------------------------------*/
188 /* >>>> File Global Variables */
189 
190 /* >> List of Codes */
191 
192 static char *s_code_list[] = {
193     "Code11",
194     "Standard2of5",
195     "Interleaved2of5",
196     "IATAC2of5",
197     "Logic2of5",
198     "Ind2of5",
199     "Code39",
200     "Code39Extended",
201     "EAN",
202     "EAN+Check",
203     "GS1-128",
204     "Codabar",
205     "Code128",
206     "DPLeit",
207     "DPIdent",
208     "Code16K",
209     "Code49",
210     "Code93",
211     "Flat",
212     "GS1DataBar",
213     "GS1DataBarLimited",
214     "GS1DataBarExpanded",
215     "Telepen",
216     "UPC-A",
217     "UPC-A+Check",
218     "UPC-E",
219     "UPC-E+Check",
220     "POSTNET",
221     "MSIPlessey",
222     "FIM",
223     "Logmars",
224     "Pharma",
225     "PZN",
226     "PharmaTwo",
227     "PDF417",
228     "PDF417Compact",
229     "MaxiCode",
230     "QR",
231     "Code128B",
232     "AusPost",
233     "AusReply",
234     "AusRoute",
235     "AusRedirect",
236     "ISBN",
237     "RM4SCC",
238     "Datamatrix",
239     "EAN14",
240     "VIN",
241     "CodablockF",
242     "NVE18",
243     "JapanPost",
244     "KoreaPost",
245     "GS1DataBarStacked",
246     "GS1DataBarSstackedOmni",
247     "GS1DataBarExpandedStacked",
248     "PLANET",
249     "DPDCode",
250     "MicroPDF417",
251     "USPSIntelligentMail",
252     "Plessey",
253     "TelepenNum",
254     "ITF14",
255     "KIX",
256     "Aztec",
257     "DAFT",
258     "MicroQR",
259     "HIBC-128",
260     "HIBC-39",
261     "HIBC-DM",
262     "HIBC-QR",
263     "HIBC-PDF",
264     "HIBC-MicroPDF",
265     "HIBC-CodablockF",
266     "HIBCAztec",
267     "DotCode",
268     "HanXin",
269     "MailMark",
270     "AztecRunes",
271     "Code32",
272     "EAN-CC",
273     "GS1-128-CC",
274     "GS1DataBarOmni-CC",
275     "GS1DataBarLimited-CC",
276     "GS1DataBarExpanded-CC",
277     "UPCA-CC",
278     "UPCE-CC",
279     "GS1DataBarStacked-CC",
280     "GS1DataBarStackedOmni-CC",
281     "GS1DataBarExpandedStacked-CC",
282     "Channel",
283     "CodeOne",
284     "GridMatrix",
285     "UPNQR",
286     "UltraCode",
287     "rMQR",
288     NULL};
289 
290 static int s_code_number[] = {
291     BARCODE_CODE11,
292     BARCODE_C25STANDARD,
293     BARCODE_C25INTER,
294     BARCODE_C25IATA,
295     BARCODE_C25LOGIC,
296     BARCODE_C25IND,
297     BARCODE_CODE39,
298     BARCODE_EXCODE39,
299     BARCODE_EANX,
300     BARCODE_EANX_CHK,
301     BARCODE_GS1_128,
302     BARCODE_CODABAR,
303     BARCODE_CODE128,
304     BARCODE_DPLEIT,
305     BARCODE_DPIDENT,
306     BARCODE_CODE16K,
307     BARCODE_CODE49,
308     BARCODE_CODE93,
309     BARCODE_FLAT,
310     BARCODE_DBAR_OMN,
311     BARCODE_DBAR_LTD,
312     BARCODE_DBAR_EXP,
313     BARCODE_TELEPEN,
314     BARCODE_UPCA,
315     BARCODE_UPCA_CHK,
316     BARCODE_UPCE,
317     BARCODE_UPCE_CHK,
318     BARCODE_POSTNET,
319     BARCODE_MSI_PLESSEY,
320     BARCODE_FIM,
321     BARCODE_LOGMARS,
322     BARCODE_PHARMA,
323     BARCODE_PZN,
324     BARCODE_PHARMA_TWO,
325     BARCODE_PDF417,
326     BARCODE_PDF417COMP,
327     BARCODE_MAXICODE,
328     BARCODE_QRCODE,
329     BARCODE_CODE128B,
330     BARCODE_AUSPOST,
331     BARCODE_AUSREPLY,
332     BARCODE_AUSROUTE,
333     BARCODE_AUSREDIRECT,
334     BARCODE_ISBNX,
335     BARCODE_RM4SCC,
336     BARCODE_DATAMATRIX,
337     BARCODE_EAN14,
338     BARCODE_VIN,
339     BARCODE_CODABLOCKF,
340     BARCODE_NVE18,
341     BARCODE_JAPANPOST,
342     BARCODE_KOREAPOST,
343     BARCODE_DBAR_STK,
344     BARCODE_DBAR_OMNSTK,
345     BARCODE_DBAR_EXPSTK,
346     BARCODE_PLANET,
347     BARCODE_DPD,
348     BARCODE_MICROPDF417,
349     BARCODE_USPS_IMAIL,
350     BARCODE_PLESSEY,
351     BARCODE_TELEPEN_NUM,
352     BARCODE_ITF14,
353     BARCODE_KIX,
354     BARCODE_AZTEC,
355     BARCODE_DAFT,
356     BARCODE_MICROQR,
357     BARCODE_HIBC_128,
358     BARCODE_HIBC_39,
359     BARCODE_HIBC_DM,
360     BARCODE_HIBC_QR,
361     BARCODE_HIBC_PDF,
362     BARCODE_HIBC_MICPDF,
363     BARCODE_HIBC_BLOCKF,
364     BARCODE_HIBC_AZTEC,
365     BARCODE_DOTCODE,
366     BARCODE_HANXIN,
367     BARCODE_MAILMARK,
368     BARCODE_AZRUNE,
369     BARCODE_CODE32,
370     BARCODE_EANX_CC,
371     BARCODE_GS1_128_CC,
372     BARCODE_DBAR_OMN_CC,
373     BARCODE_DBAR_LTD_CC,
374     BARCODE_DBAR_EXP_CC,
375     BARCODE_UPCA_CC,
376     BARCODE_UPCE_CC,
377     BARCODE_DBAR_STK_CC,
378     BARCODE_DBAR_OMNSTK_CC,
379     BARCODE_DBAR_EXPSTK_CC,
380     BARCODE_CHANNEL,
381     BARCODE_CODEONE,
382     BARCODE_GRIDMATRIX,
383     BARCODE_UPNQR,
384     BARCODE_ULTRA,
385     BARCODE_RMQR,
386     0};
387 
388 /* ECI TCL encoding names.
389  * The ECI comments are given after the name.
390  * A ** indicates encodings where native data must be delivered and not utf-8
391  */
392 static char *s_eci_list[] = {
393     "iso8859-1",    /* 3: ISO-8859-1 - Latin alphabet No. 1 (default)*/
394     "iso8859-2",    /* 4: ISO-8859-2 - Latin alphabet No. 2*/
395     "iso8859-3",    /* 5: ISO-8859-3 - Latin alphabet No. 3*/
396     "iso8859-4",    /* 6: ISO-8859-4 - Latin alphabet No. 4*/
397     "iso8859-5",    /* 7: ISO-8859-5 - Latin/Cyrillic alphabet*/
398     "iso8859-6",    /* 8: ISO-8859-6 - Latin/Arabic alphabet*/
399     "iso8859-7",    /* 9: ISO-8859-7 - Latin/Greek alphabet*/
400     "iso8859-9",    /*10: ISO-8859-8 - Latin/Hebrew alphabet*/
401     "iso8859-9",    /*11: ISO-8859-9 - Latin alphabet No. 5*/
402     "iso8859-10",   /*12: ISO-8859-10 - Latin alphabet No. 6*/
403     "iso8859-11",   /*13: ISO-8859-11 - Latin/Thai alphabet*/
404     "iso8859-13",   /*15: ISO-8859-13 - Latin alphabet No. 7*/
405     "iso8859-14",   /*16: ISO-8859-14 - Latin alphabet No. 8 (Celtic)*/
406     "iso8859-15",   /*17: ISO-8859-15 - Latin alphabet No. 9*/
407     "iso8859-16",   /*18: ISO-8859-16 - Latin alphabet No. 10*/
408     "jis0208",      /*20: Shift JIS (JIS X 0208 and JIS X 0201)*/
409     "cp1250",       /*21: Windows-1250*/
410     "cp1251",       /*22: Windows-1251*/
411     "cp1252",       /*23: Windows-1252*/
412     "cp1256",       /*24: Windows-1256*/
413     "unicode",      /*25: UCS-2BE (High order byte first) Unicode BMP*/
414     "utf-8",        /*26: Unicode (UTF-8)*/
415     "ascii",        /*27: ISO-646:1991 7-bit character set*/
416     "big5",         /*28: Big5 (Taiwan) Chinese Character Set*/
417     "euc-cn",       /*29: GB (PRC) Chinese Character Set*/
418     "iso2022-kr",   /*30: Korean Character Set EUC-KR (KS X 1001:2002)*/
419     NULL
420 };
421 
422 /* The ECI numerical number to pass to ZINT */
423 static int s_eci_number[] = {
424     3,4,5,6,7,8,9,10,11,12,13,15,16,17,18,20,21,22,23,24,25,26,27,28,29,30
425 };
426 
427 
428 /* Version information */
429 static char version_string[] = VERSION;
430 /* Help text */
431 static char help_message[] = "zint tcl(stub,obj) dll\n"
432     " Generate barcode in tk images\n"
433     "Usage:\n"
434     " zint encode data photo ?option value? ...\n"
435     "  data: data to encode in the symbol\n"
436     "  photo: a tcl photo image handle ('p' after 'image create photo p')\n"
437     "  Available options:\n"
438     "   -barcode choice: symbology, use 'zint symbology' to get a list\n"
439     "   -addongap number: (7..12, default: 9) set add-on gap in multiple of module size (UPC/EAN-CC)\n"
440     "   -bg color: set background color as 6 or 8 hex rrggbbaa\n"
441     /* cli option --binary internally handled */
442     "   -bind bool: bars above/below the code, size set by -border\n"
443     "   -bold bool: use bold text\n"
444     "   -border integer: width of a border around the symbol. Use with -bind/-box 1\n"
445     "   -box bool: box around bar code, size set be -border\n"
446     /* cli option --cmyk not supported as no corresponding output */
447     "   -cols integer: PDF417, Codablock F, DotCode: number of columns\n"
448     /* cli option --data is standard parameter */
449     "   -dmre bool: Allow Data Matrix Rectangular Extended\n"
450     "   -dotsize number: radius ratio of dots from 0.01 to 1.0\n"
451     "   -dotty bool: use dots instead of boxes for matrix codes\n"
452     /* cli option --dump not supported */
453     /* cli option --ecinos not supported */
454     "   -eci number: ECI to use\n"
455     /* cli option --esc not supported */
456     "   -fg color: set foreground color as 6 or 8 hex rrggbbaa\n"
457     /* replaces cli options --binary and --gs1 */
458     "   -format binary|unicode|gs1: input data format. Default:unicode\n"
459     "   -fullmultibyte bool: allow multibyte compaction for xQR, HanXin, Gridmatrix\n"
460     /* cli option --gs1 replaced by -format */
461     "   -gs1nocheck bool: for gs1, do not check validity of data (allows non-standard symbols)\n"
462     "   -gs1parens bool: for gs1, AIs enclosed in parentheses instead of square brackets\n"
463     "   -gssep bool: for gs1, use gs as separator instead fnc1 (Datamatrix only)\n"
464     "   -height double: Symbol height in modules\n"
465     /* cli option --input not supported */
466     "   -init bool: Create reader initialisation symbol (Code 128, Data Matrix)\n"
467     "   -mask number: set masking pattern to use (QR/MicroQR/HanXin/DotCode)\n"
468     /* cli option --mirror not supported */
469     "   -mode number: set encoding mode (MaxiCode, Composite)\n"
470     "   -nobackground bool: set background transparent\n"
471     "   -notext bool: no interpretation line\n"
472     /* cli option --output not supported */
473     "   -primary text: Structured primary data (MaxiCode, Composite)\n"
474     "   -reverse bool: Reverse colours (white on black)\n"
475     "   -rotate angle: Image rotation by 0,90 or 270 degrees\n"
476     "   -rows integer: Codablock F: number of rows\n"
477     "   -scale double: Scale the image to this factor\n"
478     "   -scmvv number: Prefix SCM with [)>\\R01\\Gvv (vv is NUMBER) (MaxiCode)\n"
479     "   -secure integer: EC Level (PDF417, QR)\n"
480     "   -separator 0..4 (default: 1) : Stacked symbologies: separator width\n"
481     /* cli option --small replaced by -smalltext */
482     "   -smalltext bool: tiny interpretation line font\n"
483     "   -square bool: force Data Matrix symbols to be square\n"
484     /* cli option --types not supported */
485     "   -vers integer: Symbology option\n"
486     "   -vwhitesp integer: vertical quiet zone in modules\n"
487     "   -whitesp integer: horizontal quiet zone in modules\n"
488     "   -werror bool: Convert all warnings into errors\n"
489     "   -to {x0 y0 ?width? ?height?}: place to put in photo image\n"
490     "\n"
491     "zint symbologies: List available symbologies\n"
492     "zint eci: List available eci tables\n"
493     "zint help\n"
494     "zint version\n"
495     ;
496 
497 /*----------------------------------------------------------------------------*/
498 /* Exported symbols */
499 #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
DllEntryPoint(HINSTANCE hInstance,DWORD seginfo,LPVOID lpCmdLine)500 EXPORT BOOL WINAPI DllEntryPoint (HINSTANCE hInstance,
501     DWORD seginfo, LPVOID lpCmdLine)
502 {
503   /* Don't do anything, so just return true */
504   return TRUE;
505 }
506 #endif
507 /*----------------------------------------------------------------------------*/
508 /* Initialisation Procedures */
Zint_Init(Tcl_Interp * interp)509 EXPORT int Zint_Init (Tcl_Interp *interp)
510 {
511     int * tkFlagPtr;
512     /*------------------------------------------------------------------------*/
513 #ifdef USE_TCL_STUBS
514     if (Tcl_InitStubs(interp, "8.5", 0) == NULL)
515 #else
516     if (Tcl_PkgRequire(interp, "Tcl", "8.5", 0) == NULL)
517 #endif
518     {
519         return TCL_ERROR;
520     }
521     /*------------------------------------------------------------------------*/
522     /* This procedure is called once per thread and any thread local data     */
523     /* should be allocated and initialized here (and not in static variables) */
524 
525     /* Create a flag if Tk is loaded */
526     tkFlagPtr = (int *)ckalloc(sizeof(int));
527     *tkFlagPtr = 0;
528     Tcl_CallWhenDeleted(interp, InterpCleanupProc, (ClientData)tkFlagPtr);
529     /*------------------------------------------------------------------------*/
530     Tcl_CreateObjCommand(interp, "zint", Zint, (ClientData)tkFlagPtr,
531             (Tcl_CmdDeleteProc *)NULL);
532     Tcl_PkgProvide (interp, "zint", version_string);
533     /*------------------------------------------------------------------------*/
534     return TCL_OK;
535 }
536 /*----------------------------------------------------------------------------*/
537 /* >>>> Cleanup procedure */
538 /*----------------------------------------------------------------------------*/
539 /* This routine is called, if a thread is terminated */
InterpCleanupProc(ClientData clientData,Tcl_Interp * interp)540 static void InterpCleanupProc(ClientData clientData, Tcl_Interp *interp)
541 {
542     ckfree( (char *)clientData );
543 }
544 /*----------------------------------------------------------------------------*/
545 /* >>>> Unload Procedures */
546 /*----------------------------------------------------------------------------*/
Zint_Unload(Tcl_Interp * Interp,int Flags)547 EXPORT int Zint_Unload (Tcl_Interp *Interp, int Flags)
548 {
549     // Allow unload
550     return TCL_OK;
551 }
552 /*----------------------------------------------------------------------------*/
553 /* >>>>> Called routine */
554 /*----------------------------------------------------------------------------*/
555 /* Decode tcl commands */
Zint(ClientData tkFlagPtr,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])556 static int Zint(ClientData tkFlagPtr, Tcl_Interp *interp, int objc,
557     Tcl_Obj *CONST objv[])
558 {
559     /* Option list and indexes */
560     enum iCommand {iEncode, iSymbologies, iECI, iVersion, iHelp};
561     /* choice of option */
562     int Index;
563     /*------------------------------------------------------------------------*/
564     /* > Check if option argument is given and decode it */
565     if (objc > 1)
566     {
567         char *subCmds[] = {"encode", "symbologies", "eci", "version", "help", NULL};
568         if(Tcl_GetIndexFromObj(interp, objv[1], (const char **) subCmds,
569             "option", 0, &Index)
570             == TCL_ERROR)
571         {
572             return TCL_ERROR;
573         }
574     } else {
575         Tcl_WrongNumArgs(interp, 1, objv, "option");
576         return TCL_ERROR;
577     }
578     /*------------------------------------------------------------------------*/
579     /* > Call functions in dependency of Index */
580     /*------------------------------------------------------------------------*/
581     switch (Index)
582     {
583     case iEncode:
584         if (CheckForTk(interp, (int *)tkFlagPtr) != TCL_OK) {
585             return TCL_ERROR;
586         }
587         return Encode(interp, objc, objv);
588     case iSymbologies:
589         {
590             Tcl_Obj *oRes;
591             int posCur;
592             oRes = Tcl_NewObj();
593             for (posCur = 0 ; s_code_list[posCur] != NULL; posCur++) {
594                 if( ZBarcode_ValidID(s_code_number[posCur]) != 0) {
595                     if (TCL_OK != Tcl_ListObjAppendElement(interp,
596                         oRes, Tcl_NewStringObj(s_code_list[posCur],-1)))
597                     {
598                         return TCL_ERROR;
599                     }
600                 }
601             }
602             Tcl_SetObjResult(interp,oRes);
603             return TCL_OK;
604         }
605     case iECI:
606         {
607             Tcl_Obj *oRes;
608             int posCur;
609             oRes = Tcl_NewObj();
610             for (posCur = 0 ; s_eci_list[posCur] != NULL; posCur++) {
611                 if (TCL_OK != Tcl_ListObjAppendElement(interp,
612                     oRes, Tcl_NewStringObj(s_eci_list[posCur],-1)))
613                 {
614                     return TCL_ERROR;
615                 }
616             }
617             Tcl_SetObjResult(interp,oRes);
618             return TCL_OK;
619         }
620     case iVersion:
621         Tcl_SetObjResult(interp,
622             Tcl_NewStringObj(version_string, -1));
623         return TCL_OK;
624     case iHelp:
625     default:
626         Tcl_SetObjResult(interp,
627             Tcl_NewStringObj(help_message, -1));
628         return TCL_OK;
629     }
630 }
631 /*----------------------------------------------------------------------
632  * Check availability of Tk.
633  *----------------------------------------------------------------------
634  */
CheckForTk(Tcl_Interp * interp,int * tkFlagPtr)635 static int CheckForTk(Tcl_Interp *interp, int *tkFlagPtr)
636 {
637     if (*tkFlagPtr > 0) {
638         return TCL_OK;
639     }
640     if (*tkFlagPtr == 0) {
641         if ( ! Tcl_PkgPresent(interp, "Tk", "8.5", 0) ) {
642             Tcl_SetResult(interp, "package Tk not loaded", TCL_STATIC);
643             return TCL_ERROR;
644         }
645     }
646 #ifdef USE_TK_STUBS
647     if (*tkFlagPtr < 0 || Tk_InitStubs(interp, "8.5", 0) == NULL) {
648         *tkFlagPtr = -1;
649         Tcl_SetResult(interp, "error initializing Tk", TCL_STATIC);
650         return TCL_ERROR;
651     }
652 #endif
653     *tkFlagPtr = 1;
654     return TCL_OK;
655 }/*----------------------------------------------------------------------------*/
656 /* >>>>> Encode */
657 /*----------------------------------------------------------------------------*/
658 /* Encode image */
Encode(Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])659 static int Encode(Tcl_Interp *interp, int objc,
660     Tcl_Obj *CONST objv[])
661 {
662     struct zint_symbol *my_symbol;
663     Tcl_DString dsInput;
664     char *pStr = NULL;
665     int lStr;
666     Tcl_Encoding hZINTEncoding;
667     int rotate_angle=0;
668     int fError = 0;
669     Tcl_DString dString;
670     int optionPos;
671     int destX0 = 0;
672     int destY0 = 0;
673     int destWidth = 0;
674     int destHeight = 0;
675     int ECIIndex = 0;
676     int fFullMultiByte = 0;
677     int addon_gap = 0;
678     int Separator = 1;
679     int Mask = 0;
680     unsigned int cap;
681     /*------------------------------------------------------------------------*/
682     /* >> Check if at least data and object is given and a pair number of */
683     /* >> options */
684     if ( objc < 4 || (objc % 2) != 0 )
685     {
686         Tcl_WrongNumArgs(interp, 2, objv, "data photo ?-switch value?...");
687         return TCL_ERROR;
688     }
689     /*------------------------------------------------------------------------*/
690     /* >>> Prepare encoding */
691     hZINTEncoding = Tcl_GetEncoding(interp, "utf-8");
692     if (NULL == hZINTEncoding) {
693         return TCL_ERROR;
694     }
695     /*------------------------------------------------------------------------*/
696     /* >>> Prepare zint object */
697     my_symbol = ZBarcode_Create();
698     my_symbol->input_mode = UNICODE_MODE;
699     my_symbol->option_3 = 0;
700     /*------------------------------------------------------------------------*/
701     /* >> Decode options */
702     for (optionPos = 4; optionPos < objc; optionPos+=2) {
703         /*--------------------------------------------------------------------*/
704         /* Option list and indexes */
705         char *optionList[] = {
706             "-addongap", "-barcode", "-bg", "-bind", "-bold", "-border", "-box",
707             "-cols", "-dmre", "-dotsize", "-dotty", "-eci", "-fg", "-format",
708             "-fullmultibyte", "-gs1nocheck", "-gs1parens", "-gssep", "-height",
709             "-init", "-mask", "-mode",
710             "-nobackground", "-notext", "-primary", "-reverse", "-rotate",
711             "-rows", "-scale", "-scmvv", "-secure", "-separator", "-smalltext",
712             "-square", "-to", "-vers", "-vwhitesp", "-werror", "-whitesp",
713             NULL};
714         enum iOption {
715             iAddonGap, iBarcode, iBG, iBind, iBold, iBorder, iBox,
716             iCols, iDMRE, iDotSize, iDotty, iECI, iFG, iFormat,
717             iFullMultiByte, iGS1NoCheck, iGS1Parens, iGSSep, iHeight,
718             iInit, iMask, iMode,
719             iNoBackground, iNoText, iPrimary, iReverse, iRotate,
720             iRows, iScale, iSCMvv, iSecure, iSeparator, iSmallText,
721             iSquare, iTo, iVers, iVWhiteSp, iWError, iWhiteSp
722             };
723         int optionIndex;
724         int intValue;
725         double doubleValue;
726         /*--------------------------------------------------------------------*/
727         if(Tcl_GetIndexFromObj(interp, objv[optionPos],
728             (const char **) optionList,
729             "zint option", optionPos-1, &optionIndex)
730             == TCL_ERROR)
731         {
732             fError = 1;
733             break;
734         }
735         /*--------------------------------------------------------------------*/
736         /* >> Decode object */
737         switch (optionIndex) {
738         case iBind:
739         case iBold:
740         case iBox:
741         case iDMRE:
742         case iDotty:
743         case iGS1NoCheck:
744         case iGS1Parens:
745         case iGSSep:
746         case iInit:
747         case iNoBackground:
748         case iNoText:
749         case iSmallText:
750         case iSquare:
751         case iFullMultiByte:
752         case iReverse:
753         case iWError:
754             /* >> Binary options */
755             if (TCL_OK != Tcl_GetBooleanFromObj(interp, objv[optionPos+1],
756                     &intValue))
757             {
758                 fError = 1;
759             }
760             break;
761         case iFG:
762         case iBG:
763             /* >> Colors */
764             pStr = Tcl_GetStringFromObj(objv[optionPos+1],&lStr);
765             if (lStr != 6 && lStr != 8) {
766                 Tcl_SetObjResult(interp,
767                     Tcl_NewStringObj("Color is not 6 or 8 hex",-1));
768                 fError = 1;
769             }
770             break;
771         case iDotSize:
772         case iScale:
773             /* >> Float */
774             if (TCL_OK != Tcl_GetDoubleFromObj(interp, objv[optionPos+1],
775                 &doubleValue))
776             {
777                 fError = 1;
778             }
779             break;
780         case iAddonGap:
781         case iBorder:
782         case iCols:
783         case iHeight:
784         case iMask:
785         case iMode:
786         case iRotate:
787         case iRows:
788         case iSecure:
789         case iSeparator:
790         case iSCMvv:
791         case iVers:
792         case iVWhiteSp:
793         case iWhiteSp:
794             /* >> Int */
795             if (TCL_OK != Tcl_GetIntFromObj(interp, objv[optionPos+1],
796                     &intValue))
797             {
798                 fError = 1;
799             }
800             break;
801         case iPrimary:
802             /* > Primary String up to 90 characters */
803             /* > Output filename up to 250 characters */
804             Tcl_DStringInit(& dString);
805             pStr = Tcl_GetStringFromObj(objv[optionPos+1], &lStr);
806             Tcl_UtfToExternalDString( hZINTEncoding, pStr, lStr, &dString);
807             if (Tcl_DStringLength(&dString) > (optionIndex==iPrimary?90:250)) {
808                 Tcl_DStringFree(&dString);
809                 Tcl_SetObjResult(interp,Tcl_NewStringObj("String to long", -1));
810                 fError = 1;
811             }
812             break;
813         }
814         if (fError) {
815             break;
816         }
817         /*--------------------------------------------------------------------*/
818         switch (optionIndex) {
819         case iAddonGap:
820             if (intValue < 7 || intValue > 12) {
821                 Tcl_SetObjResult(interp,
822                     Tcl_NewStringObj("Invalid add-on gap value not within 7 to 12", -1));
823                 fError = 1;
824             } else {
825                 addon_gap = intValue;
826             }
827             break;
828         case iBind:
829             if (intValue) {
830                 my_symbol->output_options |= BARCODE_BIND;
831             } else {
832                 my_symbol->output_options &= ~BARCODE_BIND;
833             }
834             break;
835         case iBold:
836             if (intValue) {
837                 my_symbol->output_options |= BOLD_TEXT;
838             } else {
839                 my_symbol->output_options &= ~BOLD_TEXT;
840             }
841             break;
842         case iBox:
843             if (intValue) {
844                 my_symbol->output_options |= BARCODE_BOX;
845             } else {
846                 my_symbol->output_options &= ~BARCODE_BOX;
847             }
848             break;
849         case iDotSize:
850             if (doubleValue < 0.01) {
851                 Tcl_SetObjResult(interp,
852                     Tcl_NewStringObj("Dot size below 0.01", -1));
853                 fError = 1;
854             } else {
855                 my_symbol->dot_size = (float)doubleValue;
856             }
857             break;
858         case iDotty:
859             if (intValue) {
860                 my_symbol->output_options |= BARCODE_DOTTY_MODE;
861             } else {
862                 my_symbol->output_options &= ~BARCODE_DOTTY_MODE;
863             }
864             break;
865         case iGS1NoCheck:
866             if (intValue) {
867                 my_symbol->input_mode |= GS1NOCHECK_MODE;
868             } else {
869                 my_symbol->input_mode &= ~GS1NOCHECK_MODE;
870             }
871             break;
872         case iGS1Parens:
873             if (intValue) {
874                 my_symbol->input_mode |= GS1PARENS_MODE;
875             } else {
876                 my_symbol->input_mode &= ~GS1PARENS_MODE;
877             }
878             break;
879         case iGSSep:
880             if (intValue) {
881                 my_symbol->output_options |= GS1_GS_SEPARATOR;
882             } else {
883                 my_symbol->output_options &= ~GS1_GS_SEPARATOR;
884             }
885             break;
886         case iFullMultiByte:
887             fFullMultiByte = intValue;
888             break;
889         case iECI:
890             if(Tcl_GetIndexFromObj(interp, objv[optionPos+1],
891                 (const char **) s_eci_list,"-eci", optionPos, &ECIIndex)
892                 == TCL_ERROR)
893             {
894                 fError = 1;
895             } else {
896                 my_symbol->eci = s_eci_number[ECIIndex];
897             }
898             break;
899         case iInit:
900             if (intValue) {
901                 my_symbol->output_options |= READER_INIT;
902             } else {
903                 my_symbol->output_options &= ~READER_INIT;
904             }
905             break;
906         case iSmallText:
907             if (intValue) {
908                 my_symbol->output_options |= SMALL_TEXT;
909             } else {
910                 my_symbol->output_options &= ~SMALL_TEXT;
911             }
912             break;
913         case iReverse:
914             if (intValue) {
915                 strcpy(my_symbol->fgcolour, "ffffff");
916                 strcpy(my_symbol->bgcolour, "000000");
917             }
918             break;
919         case iWError:
920             if (intValue) {
921                 my_symbol->warn_level = WARN_FAIL_ALL;
922             }
923             break;
924         case iFG:
925             strncpy(my_symbol->fgcolour, pStr, lStr);
926             my_symbol->fgcolour[lStr]='\0';
927             break;
928         case iBG:
929             strncpy(my_symbol->bgcolour, pStr, lStr);
930             my_symbol->bgcolour[lStr]='\0';
931             break;
932         case iNoBackground:
933             if (intValue) {
934                 strcpy(my_symbol->bgcolour, "ffffff00");
935             }
936             break;
937         case iNoText:
938             my_symbol->show_hrt = (intValue?0:1);
939             break;
940         case iSquare:
941             /* DM_SQUARE overwrites DM_DMRE */
942             if (intValue)
943                 my_symbol->option_3 = DM_SQUARE;
944             break;
945         case iDMRE:
946             /* DM_DMRE overwrites DM_SQUARE */
947             if (intValue)
948                 my_symbol->option_3 = DM_DMRE;
949             break;
950         case iScale:
951             if (doubleValue < 0.01) {
952                 Tcl_SetObjResult(interp,
953                     Tcl_NewStringObj("Scale below 0.01", -1));
954                 fError = 1;
955             } else {
956                 my_symbol->scale = (float)doubleValue;
957             }
958             break;
959         case iBorder:
960             if (intValue < 0 || intValue > 1000) {
961                 Tcl_SetObjResult(interp,
962                     Tcl_NewStringObj("Border out of range", -1));
963                 fError = 1;
964             } else {
965                 my_symbol->border_width = intValue;
966             }
967             break;
968         case iHeight:
969             if ((float)doubleValue < 0.5f || (float)doubleValue > 1000.0f) {
970                 Tcl_SetObjResult(interp,
971                     Tcl_NewStringObj("Height out of range", -1));
972                 fError = 1;
973             } else {
974                 my_symbol->height = (float)doubleValue;
975             }
976             break;
977         case iSeparator:
978             if (intValue < 0 || intValue > 4) {
979                 Tcl_SetObjResult(interp,
980                     Tcl_NewStringObj("Separator out of range", -1));
981                 fError = 1;
982             } else {
983                 Separator = intValue;
984             }
985             break;
986         case iMask:
987             if (intValue < 0 || intValue > 7) {
988                 Tcl_SetObjResult(interp,
989                     Tcl_NewStringObj("Mask out of range", -1));
990                 fError = 1;
991             } else {
992                 Mask = intValue + 1;
993             }
994             break;
995         case iSCMvv:
996             if (intValue < 0 || intValue > 99) {
997                 Tcl_SetObjResult(interp,
998                     Tcl_NewStringObj("SCM version out of range", -1));
999                 fError = 1;
1000             } else {
1001                 my_symbol->option_2 = intValue + 1;
1002             }
1003             break;
1004         case iCols:
1005         case iVers:
1006             /* >> Int in Option 2 */
1007             if (intValue < 1
1008                 || (optionIndex==iCols && intValue > 200)
1009                 || (optionIndex==iVers && intValue > 47))
1010             {
1011                 Tcl_SetObjResult(interp,
1012                     Tcl_NewStringObj("cols/vers out of range", -1));
1013                 fError = 1;
1014             } else {
1015                 my_symbol->option_2 = intValue;
1016             }
1017             break;
1018         case iSecure:
1019         case iMode:
1020         case iRows:
1021             /* >> Int in Option 1 */
1022             if ( (optionIndex==iSecure && (intValue < 1 || intValue > 8))
1023                 || (optionIndex==iMode && (intValue < 0 || intValue > 6))
1024                 || (optionIndex==iRows && (intValue < 0 || intValue > 44)))
1025             {
1026                 Tcl_SetObjResult(interp,
1027                     Tcl_NewStringObj("secure/mode/rows out of range", -1));
1028                 fError = 1;
1029             } else {
1030                 my_symbol->option_1 = intValue;
1031             }
1032             break;
1033         case iPrimary:
1034             strcpy(my_symbol->primary, Tcl_DStringValue( &dString ) );
1035             Tcl_DStringFree(&dString);
1036             break;
1037         case iRotate:
1038             /* >> Rotate angle */
1039             /*----------------------------------------------------------------*/
1040             {
1041                 char *rotateList[] = {"0", "90", "180", "270", NULL};
1042                 enum iRotate { iRotate0, iRotate90, iRotate180, iRotate270 };
1043                 /*------------------------------------------------------------*/
1044                 if(Tcl_GetIndexFromObj(interp, objv[optionPos+1],
1045                     (const char **) rotateList,
1046                     "rotate", optionPos, &intValue)
1047                     == TCL_ERROR)
1048                 {
1049                     fError = 1;
1050                     break;
1051                 }
1052                 switch (intValue) {
1053                     case iRotate90: rotate_angle = 90; break;
1054                     case iRotate180: rotate_angle = 180; break;
1055                     case iRotate270: rotate_angle = 270; break;
1056                     default: rotate_angle = 0; break;
1057                 }
1058             }
1059             break;
1060         case iBarcode:
1061             if(Tcl_GetIndexFromObj(interp, objv[optionPos+1],
1062                 (const char **) s_code_list,"-barcode", optionPos, &intValue)
1063                 == TCL_ERROR)
1064             {
1065                 fError = 1;
1066             } else {
1067                 my_symbol->symbology = s_code_number[intValue];
1068             }
1069             break;
1070         case iVWhiteSp:
1071             my_symbol->whitespace_height = intValue;
1072             break;
1073         case iWhiteSp:
1074             my_symbol->whitespace_width = intValue;
1075             break;
1076         case iTo:
1077             /* >> Decode the -to parameter as list of X0 Y0 ?Width Height? */
1078             {
1079                 Tcl_Obj *poParam;
1080                 if (TCL_OK != Tcl_ListObjLength(interp,
1081                     objv[optionPos+1], &lStr))
1082                 {
1083                     fError = 1;
1084                 } else if ( ! ( lStr == 2 || lStr == 4 ) ) {
1085                     Tcl_SetObjResult(interp,
1086                         Tcl_NewStringObj(
1087                         "option -to not a list of 2 or 4", -1));
1088                     fError = 1;
1089                 } else if ((
1090                     TCL_OK != Tcl_ListObjIndex(interp, objv[optionPos+1],
1091                         0, &poParam)
1092                     || TCL_OK != Tcl_GetIntFromObj(interp,poParam,&destX0)
1093                     || TCL_OK != Tcl_ListObjIndex(interp, objv[optionPos+1],
1094                         1, &poParam)
1095                     || TCL_OK != Tcl_GetIntFromObj(interp,poParam,&destY0)
1096                     || lStr == 4) && (
1097                     TCL_OK != Tcl_ListObjIndex(interp, objv[optionPos+1],
1098                         2, &poParam)
1099                     || TCL_OK != Tcl_GetIntFromObj(interp,poParam,
1100                         &destWidth)
1101                     || TCL_OK != Tcl_ListObjIndex(interp, objv[optionPos+1],
1102                         3, &poParam)
1103                     || TCL_OK != Tcl_GetIntFromObj(interp,poParam,
1104                         &destHeight)
1105                     ))
1106                 {
1107                     fError = 1;
1108                 }
1109             }
1110             break;
1111         case iFormat:
1112             /* >> Format of the input data */
1113             /*----------------------------------------------------------------*/
1114             {
1115                 char *formatList[] = {"binary", "gs1", "unicode",NULL};
1116                 enum iFormat { iBinary, iGS1, iUnicode };
1117                 /*------------------------------------------------------------*/
1118                 if(Tcl_GetIndexFromObj(interp, objv[optionPos+1],
1119                     (const char **) formatList,
1120                     "format", optionPos, &intValue)
1121                     == TCL_ERROR)
1122                 {
1123                     fError = 1;
1124                     break;
1125                 }
1126                 switch (intValue) {
1127                     case iBinary: my_symbol->input_mode = (my_symbol->input_mode & ~0x07) | DATA_MODE; break;
1128                     case iGS1: my_symbol->input_mode = (my_symbol->input_mode & ~0x07) | GS1_MODE; break;
1129                     default: my_symbol->input_mode = (my_symbol->input_mode & ~0x07) | UNICODE_MODE; break;
1130                 }
1131             }
1132         }
1133     }
1134     /*------------------------------------------------------------------------*/
1135     /* >>> Get symbology capability mask */
1136     cap = ZBarcode_Cap(my_symbol->symbology,
1137             ZINT_CAP_STACKABLE | ZINT_CAP_EXTENDABLE | ZINT_CAP_FULL_MULTIBYTE
1138             | ZINT_CAP_MASK);
1139     /*------------------------------------------------------------------------*/
1140     /* >>> option_3 is set by three values depending on the symbology */
1141     /* On wrong symbology, the option is ignored(as does the zint program)*/
1142     if (fFullMultiByte && (cap & ZINT_CAP_FULL_MULTIBYTE)) {
1143         my_symbol->option_3 = ZINT_FULL_MULTIBYTE;
1144     }
1145     if (Mask && (cap & ZINT_CAP_MASK)) {
1146         my_symbol->option_3 |= Mask << 8;
1147     }
1148     if (Separator && (cap & ZINT_CAP_STACKABLE)) {
1149         my_symbol->option_3 = Separator;
1150     }
1151     /*------------------------------------------------------------------------*/
1152     /* >>> option_2 is set by two values depending on the symbology */
1153     /* On wrong symbology, the option is ignored(as does the zint program)*/
1154     if (addon_gap && (cap & ZINT_CAP_EXTENDABLE)) {
1155         my_symbol->option_2 = addon_gap;
1156     }
1157     /*------------------------------------------------------------------------*/
1158     /* >>> Prepare input dstring and encode it to ECI encoding*/
1159     Tcl_DStringInit(& dsInput);
1160     /*------------------------------------------------------------------------*/
1161     if (!fError) {
1162         /*--------------------------------------------------------------------*/
1163         /* >>> Get input mode */
1164         if ((my_symbol->input_mode & 0x07) == DATA_MODE) {
1165             /* Binary data */
1166             pStr = (char *) Tcl_GetByteArrayFromObj(objv[2], &lStr);
1167         } else {
1168             /* UTF8 Data */
1169             pStr = Tcl_GetStringFromObj(objv[2], &lStr);
1170             Tcl_UtfToExternalDString( hZINTEncoding, pStr, lStr, &dsInput);
1171             pStr = Tcl_DStringValue( &dsInput );
1172             lStr = Tcl_DStringLength( &dsInput );
1173         }
1174     }
1175     /*------------------------------------------------------------------------*/
1176     /* >>> Build symbol graphic */
1177     if (! fError ) {
1178         int ErrorNumber;
1179         Tk_PhotoHandle hPhoto;
1180         /*--------------------------------------------------------------------*/
1181         /* call zint graphic creation to buffer */
1182         ErrorNumber = ZBarcode_Encode_and_Buffer(my_symbol,
1183             (unsigned char *) pStr, lStr, rotate_angle);
1184         /*--------------------------------------------------------------------*/
1185         /* >> Show a message */
1186         if( 0 != ErrorNumber )
1187         {
1188             Tcl_SetObjResult(interp, Tcl_NewStringObj(my_symbol->errtxt, -1));
1189         }
1190         if( ZINT_ERROR <= ErrorNumber )
1191         {
1192             /* >> Encode error */
1193             fError = 1;
1194         } else if (
1195             NULL == (hPhoto = Tk_FindPhoto(interp, Tcl_GetString(objv[3]))))
1196         {
1197             Tcl_SetObjResult(interp,
1198                 Tcl_NewStringObj("Unknown photo image", -1));
1199             fError = 1;
1200         } else {
1201             Tk_PhotoImageBlock sImageBlock;
1202             char * pImageRGBA = NULL;
1203             if (my_symbol->alphamap == NULL) {
1204                 sImageBlock.pixelPtr = (unsigned char *) my_symbol->bitmap;
1205                 sImageBlock.width = my_symbol->bitmap_width;
1206                 sImageBlock.height = my_symbol->bitmap_height;
1207                 sImageBlock.pitch = 3*my_symbol->bitmap_width;
1208                 sImageBlock.pixelSize = 3;
1209                 sImageBlock.offset[0] = 0;
1210                 sImageBlock.offset[1] = 1;
1211                 sImageBlock.offset[2] = 2;
1212                 sImageBlock.offset[3] = 0;
1213             } else {
1214                 int index;
1215                 /* Alpha channel present - prepare the image data in rgba order */
1216                 pImageRGBA = ckalloc(my_symbol->bitmap_width*my_symbol->bitmap_height*4);
1217                 for (index = 0; index < my_symbol->bitmap_width*my_symbol->bitmap_height; index++) {
1218                     pImageRGBA[index*4] = my_symbol->bitmap[index*3];
1219                     pImageRGBA[index*4+1] = my_symbol->bitmap[index*3+1];
1220                     pImageRGBA[index*4+2] = my_symbol->bitmap[index*3+2];
1221                     pImageRGBA[index*4+3] = my_symbol->alphamap[index];
1222                 }
1223                 sImageBlock.pixelPtr = (unsigned char *) pImageRGBA;
1224                 sImageBlock.width = my_symbol->bitmap_width;
1225                 sImageBlock.height = my_symbol->bitmap_height;
1226                 sImageBlock.pitch = 4*my_symbol->bitmap_width;
1227                 sImageBlock.pixelSize = 4;
1228                 sImageBlock.offset[0] = 0;
1229                 sImageBlock.offset[1] = 1;
1230                 sImageBlock.offset[2] = 2;
1231                 sImageBlock.offset[3] = 3;
1232             }
1233             if (0 == destWidth) {
1234                 destWidth = my_symbol->bitmap_width;
1235             }
1236             if (0 == destHeight) {
1237                 destHeight = my_symbol->bitmap_height;
1238             }
1239             if (TCL_OK != Tk_PhotoPutBlock(interp, hPhoto, &sImageBlock,
1240                 destX0, destY0, destWidth, destHeight,
1241                 TK_PHOTO_COMPOSITE_OVERLAY))
1242             {
1243                 fError = 1;
1244             }
1245             if (pImageRGBA != NULL) {
1246                 ckfree(pImageRGBA);
1247             }
1248         }
1249     }
1250     /*------------------------------------------------------------------------*/
1251     Tcl_FreeEncoding(hZINTEncoding);
1252     Tcl_DStringFree(& dsInput);
1253     ZBarcode_Delete(my_symbol);
1254     /*------------------------------------------------------------------------*/
1255     if (fError) {
1256         return TCL_ERROR;
1257     }
1258     return TCL_OK;
1259 }
1260