]> git.sur5r.net Git - glabels/blob - iec16022-0.2.1/iec16022.c
Imported Upstream version 2.2.8
[glabels] / iec16022-0.2.1 / iec16022.c
1 /** 
2  *
3  * IEC16022 bar code generation
4  * Adrian Kennard, Andrews & Arnold Ltd
5  * with help from Cliff Hones on the RS coding
6  *
7  * (c) 2004 Adrian Kennard, Andrews & Arnold Ltd
8  * (c) 2006 Stefan Schmidt <stefan@datenfreihafen.org>
9  * 
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
23  *
24  */
25
26 #define IEC16022_VERSION "0.2"
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <ctype.h>
31 #include <string.h>
32 #include <time.h>
33 #include <popt.h>
34 #include <malloc.h>
35 #include "image.h"
36 #include "iec16022ecc200.h"
37
38  // simple checked response malloc
39 void *safemalloc(int n)
40 {
41         void *p = malloc(n);
42         if (!p) {
43                 fprintf(stderr, "Malloc(%d) failed\n", n);
44                 exit(1);
45         }
46         return p;
47 }
48
49 // hex dump - bottom left pixel first
50 void dumphex(unsigned char *grid, int W, int H, unsigned char p)
51 {
52         int c = 0, y;
53         for (y = 0; y < H; y++) {
54                 int v = 0, x, b = 128;
55                 for (x = 0; x < W; x++) {
56                         if (grid[y * W + x])
57                                 v |= b;
58                         b >>= 1;
59                         if (!b) {
60                                 printf("%02X", v ^ p);
61                                 v = 0;
62                                 b = 128;
63                                 c++;
64                         }
65                 }
66                 if (b != 128) {
67                         printf("%02X", v ^ p);
68                         c++;
69                 }
70                 printf(" ");
71                 c++;
72                 if (c >= 80) {
73                         printf("\n");
74                         c = 0;
75                 }
76         }
77         if (c)
78                 printf("\n");
79 }
80
81 int main(int argc, const char *argv[])
82 {
83         char c;
84         int W = 0, H = 0;
85         int ecc = 0;
86         int barcodelen = 0;
87         char *encoding = 0;
88         char *outfile = 0;
89         char *infile = 0;
90         char *barcode = 0;
91         char *format = "Text";
92         char *size = 0;
93         char *eccstr = 0;
94         int len = 0, maxlen = 0, ecclen = 0;
95         unsigned char *grid = 0;
96         poptContext optCon;     // context for parsing command-line options
97         const struct poptOption optionsTable[] = {
98                 {
99                  "size", 's', POPT_ARG_STRING, &size, 0, "Size", "WxH"},
100                 {
101                  "barcode", 'c', POPT_ARG_STRING, &barcode, 0, "Barcode",
102                  "text"},
103                 {
104                  "ecc", 0, POPT_ARG_STRING, &eccstr, 0, "ECC",
105                  "000/050/080/100/140/200"},
106                 {
107                  "infile", 'i', POPT_ARG_STRING, &infile, 0, "Barcode file",
108                  "filename"},
109                 {
110                  "outfile", 'o', POPT_ARG_STRING, &outfile, 0,
111                  "Output filename",
112                  "filename"},
113                 {
114                  "encoding", 'e', POPT_ARG_STRING, &encoding, 0,
115                  "Encoding template",
116                  "[CTXEAB]* for ecc200 or 11/27/41/37/128/256"},
117                 {
118                  "format", 'f', POPT_ARGFLAG_SHOW_DEFAULT | POPT_ARG_STRING,
119                  &format, 0,
120                  "Output format", "Text/EPS/PNG/Bin/Hex/Stamp"},
121                 POPT_AUTOHELP {
122                                NULL, 0, 0, NULL, 0}
123         };
124         optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
125         poptSetOtherOptionHelp(optCon, "[barcode]");
126         if ((c = poptGetNextOpt(optCon)) < -1) {
127                 /* an error occurred during option processing */
128                 fprintf(stderr, "%s: %s\n", poptBadOption(optCon,
129                                                           POPT_BADOPTION_NOALIAS),
130                         poptStrerror(c));
131                 return 1;
132         }
133
134         if (poptPeekArg(optCon) && !barcode && !infile)
135                 barcode = (char *)poptGetArg(optCon);
136         if (poptPeekArg(optCon) || !barcode && !infile || barcode && infile) {
137                 fprintf(stderr, "Version: %s\n", IEC16022_VERSION);
138                 poptPrintUsage(optCon, stderr, 0);
139                 return -1;
140         }
141         if (outfile && !freopen(outfile, "w", stdout)) {
142                 perror(outfile);
143                 return 1;
144         }
145
146         if (infile) {           // read from file
147                 FILE *f = fopen(infile, "rb");
148                 barcode = safemalloc(4001);
149                 if (!f) {
150                         perror(infile);
151                         return 1;
152                 }
153                 barcodelen = fread(barcode, 1, 4000, f);
154                 if (barcodelen < 0) {
155                         perror(infile);
156                         return 1;
157                 }
158                 barcode[barcodelen] = 0;        // null terminate anyway
159                 close(f);
160         } else
161                 barcodelen = strlen(barcode);
162         // check parameters
163         if (size) {
164                 char *x = strchr(size, 'x');
165                 W = atoi(size);
166                 if (x)
167                         H = atoi(x + 1);
168                 if (!H)
169                         W = H;
170         }
171         if (eccstr)
172                 ecc = atoi(eccstr);
173         if (W & 1) {            // odd size
174                 if (W != H || W < 9 || W > 49) {
175                         fprintf(stderr, "Invalid size %dx%d\n", W, H);
176                         return 1;
177                 }
178                 if (!eccstr) {
179                         if (W >= 17)
180                                 ecc = 140;
181                         else if (W >= 13)
182                                 ecc = 100;
183                         else if (W >= 11)
184                                 ecc = 80;
185                         else
186                                 ecc = 0;
187                 }
188                 if (ecc && ecc != 50 && ecc != 80 && ecc != 100 && ecc != 140 ||
189                     ecc == 50 && W < 11 || ecc == 80 && W < 13 || ecc == 100
190                     && W < 13 || ecc == 140 && W < 17) {
191                         fprintf(stderr, "ECC%03d invalid for %dx%d\n", ecc, W,
192                                 H);
193                         return 1;
194                 }
195
196         } else if (W) {         // even size
197                 if (W < H) {
198                         int t = W;
199                         W = H;
200                         H = t;
201                 }
202                 if (!eccstr)
203                         ecc = 200;
204                 if (ecc != 200) {
205                         fprintf(stderr, "ECC%03d invalid for %dx%d\n", ecc, W,
206                                 H);
207                         return 1;
208                 }
209         }
210
211         else {                  // auto size
212                 if (!eccstr)
213                         // default is even sizes only unless explicit ecc set to force odd
214                         // sizes
215                         ecc = 200;
216         }
217
218         if (tolower(*format) == 's') {  // special stamp format checks & defaults
219                 if (!W)
220                         W = H = 32;
221                 if (ecc != 200 || W != 32 || H != 32)
222                         fprintf(stderr, "Stamps must be 32x32\n");
223                 if (encoding)
224                         fprintf(stderr, "Stamps should use auto encoding\n");
225                 else {
226                         int n;
227                         for (n = 0; n < barcodelen && (barcode[n] == ' ' ||
228                                                        isdigit(barcode[n])
229                                                        || isupper(barcode[n]));
230                              n++) ;
231                         if (n < barcodelen)
232                                 fprintf(stderr,
233                                         "Has invalid characters for a stamp\n");
234                         else {
235                                 // Generate simplistic encoding rules as used by the windows app
236                                 // TBA - does not always match the windows app...
237                                 n = 0;
238                                 encoding = safemalloc(barcodelen + 1);
239                                 while (n < barcodelen) {
240                                         // ASCII
241                                         while (1) {
242                                                 if (n == barcodelen
243                                                     || n + 3 <= barcodelen
244                                                     && (!isdigit(barcode[n])
245                                                         ||
246                                                         !isdigit(barcode
247                                                                  [n + 1])))
248                                                         break;
249                                                 encoding[n++] = 'A';
250                                                 if (n < barcodelen
251                                                     && isdigit(barcode[n - 1])
252                                                     && isdigit(barcode[n]))
253                                                         encoding[n++] = 'A';
254                                         }
255                                         // C40
256                                         while (1) {
257                                                 int r = 0;
258                                                 while (n + r < barcodelen
259                                                        &&
260                                                        isdigit(barcode[n + r]))
261                                                         r++;
262                                                 if (n + 3 > barcodelen
263                                                     || r >= 6)
264                                                         break;
265                                                 encoding[n++] = 'C';
266                                                 encoding[n++] = 'C';
267                                                 encoding[n++] = 'C';
268                                         }
269                                 }
270                                 encoding[n] = 0;
271                                 //fprintf (stderr, "%s\n%s\n", barcode, encoding);
272                         }
273                 }
274         }
275         // processing stamps
276         if ((W & 1) || ecc < 200) {     // odd sizes
277                 fprintf(stderr, "Not done odd sizes yet, sorry\n");
278         } else {                // even sizes
279                 grid =
280                     iec16022ecc200(&W, &H, &encoding, barcodelen, barcode, &len,
281                                    &maxlen, &ecclen);
282         }
283
284         // output
285         if (!grid || !W) {
286                 fprintf(stderr, "No barcode produced\n");
287                 return 1;
288         }
289         switch (tolower(*format)) {
290         case 'i':               // info
291                 printf("Size    : %dx%d\n", W, H);
292                 printf("Encoded : %d of %d bytes with %d bytes of ecc\n", len,
293                        maxlen, ecclen);
294                 printf("Barcode : %s\n", barcode);
295                 printf("Encoding: %s\n", encoding);
296                 break;
297         case 'h':               // hex
298                 dumphex(grid, W, H, 0);
299                 break;
300         case 'b':               // bin
301                 {
302                         int y;
303                         for (y = 0; y < H; y++) {
304                                 int v = 0, x, b = 128;
305                                 for (x = 0; x < W; x++) {
306                                         if (grid[y * W + x])
307                                                 v |= b;
308                                         b >>= 1;
309                                         if (!b) {
310                                                 putchar(v);
311                                                 v = 0;
312                                                 b = 128;
313                                         }
314                                 }
315                                 if (b != 128)
316                                         putchar(v);
317                         }
318                 }
319                 break;
320         case 't':               // text
321                 {
322                         int y;
323                         for (y = H - 1; y >= 0; y--) {
324                                 int x;
325                                 for (x = 0; x < W; x++)
326                                         printf("%c",
327                                                grid[W * y + x] ? '*' : ' ');
328                                 printf("\n");
329                         }
330                 }
331                 break;
332         case 'e':               // EPS
333                 printf("%%!PS-Adobe-3.0 EPSF-3.0\n"
334                        "%%%%Creator: IEC16022 barcode/stamp generator\n"
335                        "%%%%BarcodeData: %s\n" "%%%%BarcodeSize: %dx%d\n"
336                        "%%%%BarcodeFormat: ECC200\n"
337                        "%%%%DocumentData: Clean7Bit\n" "%%%%LanguageLevel: 1\n"
338                        "%%%%Pages: 1\n" "%%%%BoundingBox: 0 0 %d %d\n"
339                        "%%%%EndComments\n" "%%%%Page: 1 1\n"
340                        "%d %d 1[1 0 0 1 -1 -1]{<\n", barcode, W, H, W + 2,
341                        H + 2, W, H);
342                 dumphex(grid, W, H, 0xFF);
343                 printf(">}image\n");
344                 break;
345         case 's':               // Stamp
346                 {
347                         char temp[74], c;
348                         time_t now;
349                         struct tm t = {
350                                 0
351                         };
352                         int v;
353                         if (barcodelen < 74) {
354                                 fprintf(stderr,
355                                         "Does not look like a stamp barcode\n");
356                                 return 1;
357                         }
358                         memcpy(temp, barcode, 74);
359                         c = temp[5];
360                         temp[56] = 0;
361                         t.tm_year = atoi(temp + 54) + 100;
362                         t.tm_mday = 1;
363                         now = mktime(&t);
364                         temp[54] = 0;
365                         now += 86400 * (atoi(temp + 51) - 1);
366                         t = *gmtime(&now);
367                         temp[46] = 0;
368                         v = atoi(temp + 36);
369                         printf("%%!PS-Adobe-3.0 EPSF-3.0\n"
370                                "%%%%Creator: IEC16022 barcode/stamp generator\n"
371                                "%%%%BarcodeData: %s\n" "%%%%BarcodeSize: %dx%d\n" "%%%%DocumentData: Clean7Bit\n" "%%%%LanguageLevel: 1\n" "%%%%Pages: 1\n" "%%%%BoundingBox: 0 0 190 80\n" "%%%%EndComments\n" "%%%%Page: 1 1\n" "10 dict begin/f{findfont exch scalefont \
372                                  setfont}bind def/rm/rmoveto load def/m/moveto load \
373                                  def/rl/rlineto load def\n" "/l/lineto load def/cp/closepath load def/c{dup stringwidth \
374                                  pop -2 div 0 rmoveto show}bind def\n" "gsave 72 25.4 div dup scale 0 0 m 67 0 rl 0 28 rl -67 0 rl \
375                                  cp clip 1 setgray fill 0 setgray 0.5 0 translate 0.3 \
376                                  setlinewidth\n" "32 32 1[2 0 0 2 0 -11]{<\n", barcode, W, H);
377                         dumphex(grid, W, H, 0xFF);
378                         printf(">}image\n"
379                                "3.25/Helvetica-Bold f 8 25.3 m(\\243%d.%02d)c\n"
380                                "2.6/Helvetica f 8 22.3 m(%.4s %.4s)c\n"
381                                "1.5/Helvetica f 8 3.3 m(POST BY)c\n"
382                                "3.3/Helvetica f 8 0.25 m(%02d.%02d.%02d)c\n",
383                                v / 100, v % 100, temp + 6, temp + 10, t.tm_mday,
384                                t.tm_mon + 1, t.tm_year % 100);
385                         if (c == '1' || c == '2' || c == 'A' || c == 'S') {
386                                 if (c == '2')
387                                         printf
388                                             ("42 0 m 10 0 rl 0 28 rl -10 0 rl cp 57 0 m 5 0 rl 0 \
389                                            28 rl -5 0 rl cp");
390                                 else
391                                         printf
392                                             ("42 0 m 5 0 rl 0 28 rl -5 0 rl cp 52 0 m 10 0 rl 0 \
393                                            28 rl -10 0 rl cp");
394                                 printf
395                                     (" 21 0 m 16 0 rl 0 28 rl -16 0 rl cp fill\n"
396                                      "21.3 0.3 m 15.4 0 rl 0 13 rl -15.4 0 rl cp 1 setgray \
397                                         fill gsave 21.3 0.3 15.4 27.4 rectclip newpath\n");
398                                 switch (c) {
399                                 case '1':
400                                         printf
401                                             ("27/Helvetica-Bold f 27 8.7 m(1)show grestore 0 setgray \
402                                    1.5/Helvetica-Bold f 22 3.3 m(POSTAGE PAID GB)show \
403                                    1.7/Helvetica f 29 1.5 m(DumbStamp.co.uk)c\n");
404                                         break;
405                                 case '2':
406                                         printf
407                                             ("21/Helvetica-Bold f 23.5 13 m(2)1.25 1 scale show grestore \
408                                    0 setgray 1.5/Helvetica-Bold f 22 3.3 \
409                                    m(POSTAGE PAID GB)show 1.7/Helvetica f 29 1.5 \
410                                    m(DumbStamp.co.uk)c\n");
411                                         break;
412                                 case 'A':
413                                         printf
414                                             ("16/Helvetica-Bold f 29 14.75 m 1.1 1 scale(A)c grestore 0 \
415                                    setgray 1.5/Helvetica-Bold f 22 3.3 m(POSTAGE PAID GB)show \
416                                    1.7/Helvetica f 22 1.5 m(Par Avion)show\n");
417                                         break;
418                                 case 'S':
419                                         printf
420                                             ("10/Helvetica-Bold f 29 17 m(SU)c grestore 0 setgray \
421                                            1.5/Helvetica-Bold f 22 1.5 m(POSTAGE PAID GB)show\n");
422                                         break;
423                                 }
424                                 printf
425                                     ("2.3/Helvetica-Bold f 29 10 m(LOYAL MAIL)c\n");
426                         } else if (c == 'P') {  // Standard Parcels
427                                 printf("21 0 m 41 0 rl 0 28 rl -41 0 rl cp fill\n" "37.7 0.3 m 24 0 rl 0 27.4 rl -24 0 rl cp 1 setgray fill \
428                                         gsave 21.3 0.3 16.4 27.4 rectclip newpath\n" "22.5/Helvetica-Bold f 37.75 -1.25 m 90 rotate(SP)show \
429                                         grestore 0 setgray\n"
430                                        "3.5/Helvetica-Bold f 49.7 21.5 m(LOYAL MAIL)c\n" "2.3/Helvetica-Bold f 49.7 7 m(POSTAGE PAID GB)c\n" "2.6/Helveica f 49.7 4.25 m(DumbStamp.co.uk)c\n");
431                         } else if (c == '3')
432                                 printf("21.15 0.15 40.7 27.7 rectstroke\n"
433                                        "21 0 m 41 0 rl 0 5 rl -41 0 rl cp fill\n"
434                                        "0 1 2{0 1 18{dup 1.525 mul 22.9 add 24 3 index 1.525 mul \
435                                         add 3 -1 roll 9 add 29 div 0 360 arc fill}for pop}for\n" "50.5 23.07 m 11.5 0 rl 0 5 rl -11.5 0 rl cp fill\n"
436                                        "5.85/Helvetica f 23.7 15.6 m(Loyal Mail)show\n" "4.75/Helvetica-Bold f 24 11 m(special)show 4.9/Helvetica \
437                                         f(delivery)show\n" "gsave 1 setgray 3.2/Helvetica-Bold f 24 1.6 \
438                                         m(next day)show 26 10.15 m 2 0 rl stroke grestore\n" "21.15 9.9 m 53.8 9.9 l stroke 53.8 9.9 0.4 0 360 \
439                                         arc fill\n");
440                         printf("end grestore\n");
441                 }
442                 break;
443         case 'p':               // png
444                 {
445                         int x, y;
446                         Image *i = ImageNew(W + 2, H + 2, 2);
447                         i->Colour[0] = 0xFFFFFF;
448                         i->Colour[1] = 0;
449                         for (y = 0; y < H; y++)
450                                 for (x = 0; x < W; x++)
451                                         if (grid[y * W + x])
452                                                 ImagePixel(i, x + 1, H - y) = 1;
453                         ImageWritePNG(i, fileno(stdout), 0, -1, barcode);
454                         ImageFree(i);
455                 }
456                 break;
457         default:
458                 fprintf(stderr, "Unknown output format %s\n", format);
459                 break;
460         }
461         return 0;
462 }