1 /*
2 libdmtx - Data Matrix Encoding/Decoding Library
3
4 Copyright (C) 2008, 2009 Mike Laughton
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
20 Contact: mike@dragonflylogic.com
21 */
22
23 #include "dmtxwrite.h"
24
25 char *programName;
26
27 /**
28 * @brief Main function for the dmtxwrite Data Matrix scanning utility.
29 * @param argc count of arguments passed from command line
30 * @param argv list of argument passed strings from command line
31 * @return Numeric exit code
32 */
33 int
main(int argc,char * argv[])34 main(int argc, char *argv[])
35 {
36 int err;
37 char *format;
38 UserOptions opt;
39 DmtxEncode *enc;
40 unsigned char codeBuffer[DMTXWRITE_BUFFER_SIZE];
41 int codeBufferSize;
42
43 opt = GetDefaultOptions();
44
45 /* Override defaults with requested options */
46 err = HandleArgs(&opt, &argc, &argv);
47 if(err != DmtxPass)
48 ShowUsage(EX_USAGE);
49
50 /* Create and initialize libdmtx encoding struct */
51 enc = dmtxEncodeCreate();
52 if(enc == NULL)
53 FatalError(EX_SOFTWARE, "create error");
54
55 /* Set output image properties */
56 dmtxEncodeSetProp(enc, DmtxPropPixelPacking, DmtxPack24bppRGB);
57 dmtxEncodeSetProp(enc, DmtxPropImageFlip, DmtxFlipNone);
58 dmtxEncodeSetProp(enc, DmtxPropRowPadBytes, 0);
59
60 /* Set encoding options */
61 dmtxEncodeSetProp(enc, DmtxPropMarginSize, opt.marginSize);
62 dmtxEncodeSetProp(enc, DmtxPropModuleSize, opt.moduleSize);
63 dmtxEncodeSetProp(enc, DmtxPropScheme, opt.scheme);
64 dmtxEncodeSetProp(enc, DmtxPropSizeRequest, opt.sizeIdx);
65
66 if(opt.gs1 != DmtxUndefined) {
67 dmtxEncodeSetProp(enc, DmtxPropFnc1, opt.gs1);
68 }
69
70 /* Read input data into buffer */
71 codeBufferSize = ReadInputData(codeBuffer, &opt);
72
73 /* Create barcode image */
74 if(opt.mosaic == DmtxTrue)
75 err = dmtxEncodeDataMosaic(enc, codeBufferSize, codeBuffer);
76 else
77 err = dmtxEncodeDataMatrix(enc, codeBufferSize, codeBuffer);
78
79 if(err == DmtxFail)
80 FatalError(EX_SOFTWARE,
81 _("Unable to encode message (possibly too large for requested size)"));
82
83 /* Write image file, but only if preview and codewords are not used */
84 if(opt.preview == DmtxTrue || opt.codewords == DmtxTrue) {
85 if(opt.preview == DmtxTrue)
86 WriteAsciiPreview(enc);
87 if(opt.codewords == DmtxTrue)
88 WriteCodewordList(enc);
89 }
90 else {
91 format = GetImageFormat(&opt);
92 if(format == NULL)
93 format = "png";
94
95 if(StrNCmpI(format, "svg", 3) == DmtxTrue)
96 WriteSvgFile(&opt, enc, format);
97 else
98 WriteImageFile(&opt, enc, format);
99 }
100
101 /* Clean up */
102 dmtxEncodeDestroy(&enc);
103
104 exit(0);
105 }
106
107 /**
108 *
109 *
110 */
111 static UserOptions
GetDefaultOptions(void)112 GetDefaultOptions(void)
113 {
114 UserOptions opt;
115 int white[3] = { 255, 255, 255 };
116 int black[3] = { 0, 0, 0 };
117
118 memset(&opt, 0x00, sizeof(UserOptions));
119
120 opt.inputPath = NULL; /* default stdin */
121 opt.outputPath = NULL; /* default stdout */
122 opt.format = NULL;
123 opt.codewords = DmtxFalse;
124 opt.marginSize = 10;
125 opt.moduleSize = 5;
126 opt.scheme = DmtxSchemeAutoBest;
127 opt.preview = DmtxFalse;
128 opt.rotate = 0;
129 opt.sizeIdx = DmtxSymbolSquareAuto;
130 memcpy(opt.color, black, sizeof(int) * 3);
131 memcpy(opt.bgColor, white, sizeof(int) * 3);
132 opt.mosaic = DmtxFalse;
133 opt.dpi = DmtxUndefined;
134 opt.verbose = DmtxFalse;
135 opt.gs1 = DmtxUndefined;
136
137 return opt;
138 }
139
140 /**
141 * @brief Set and validate user-requested options from command line arguments.
142 * @param opt runtime options from defaults or command line
143 * @param argcp pointer to argument count
144 * @param argvp pointer to argument list
145 * @return DmtxPass | DmtxFail
146 */
147 static DmtxPassFail
HandleArgs(UserOptions * opt,int * argcp,char ** argvp[])148 HandleArgs(UserOptions *opt, int *argcp, char **argvp[])
149 {
150 int err;
151 int i;
152 int optchr;
153 int longIndex;
154 char *ptr;
155
156 struct option longOptions[] = {
157 {"codewords", no_argument, NULL, 'c'},
158 {"module", required_argument, NULL, 'd'},
159 {"margin", required_argument, NULL, 'm'},
160 {"encoding", required_argument, NULL, 'e'},
161 {"format", required_argument, NULL, 'f'},
162 {"list-formats", no_argument, NULL, 'l'},
163 {"output", required_argument, NULL, 'o'},
164 {"preview", no_argument, NULL, 'p'},
165 {"resolution", required_argument, NULL, 'r'},
166 {"symbol-size", required_argument, NULL, 's'},
167 {"color", required_argument, NULL, 'C'},
168 {"bg-color", required_argument, NULL, 'B'},
169 {"mosaic", no_argument, NULL, 'M'},
170 {"rotate", required_argument, NULL, 'R'},
171 {"gs1", required_argument, NULL, 'G'},
172 {"verbose", no_argument, NULL, 'v'},
173 {"version", no_argument, NULL, 'V'},
174 {"help", no_argument, NULL, 0 },
175 {0, 0, 0, 0}
176 };
177
178 programName = Basename((*argvp)[0]);
179
180 for(;;) {
181 optchr = getopt_long(*argcp, *argvp, "cd:m:e:f:lo:pr:s:C:B:MR:G:vV", longOptions, &longIndex);
182 if(optchr == -1)
183 break;
184
185 switch(optchr) {
186 case 0: /* --help */
187 ShowUsage(EX_OK);
188 break;
189 case 'c':
190 opt->codewords = DmtxTrue;
191 break;
192 case 'd':
193 err = StringToInt(&opt->moduleSize, optarg, &ptr);
194 if(err != DmtxPass || opt->moduleSize <= 0 || *ptr != '\0')
195 FatalError(EX_USAGE, _("Invalid module size specified \"%s\""), optarg);
196 break;
197 case 'm':
198 err = StringToInt(&opt->marginSize, optarg, &ptr);
199 if(err != DmtxPass || opt->marginSize <= 0 || *ptr != '\0')
200 FatalError(EX_USAGE, _("Invalid margin size specified \"%s\""), optarg);
201 break;
202 case 'e':
203 if(strlen(optarg) != 1) {
204 fprintf(stderr, "Invalid encodation scheme \"%s\"\n", optarg);
205 return DmtxFail;
206 }
207 switch(*optarg) {
208 case 'b':
209 opt->scheme = DmtxSchemeAutoBest;
210 break;
211 case 'f':
212 opt->scheme = DmtxSchemeAutoFast;
213 fprintf(stderr, "\"Fast optimized\" not implemented\n");
214 return DmtxFail;
215 case 'a':
216 opt->scheme = DmtxSchemeAscii;
217 break;
218 case 'c':
219 opt->scheme = DmtxSchemeC40;
220 break;
221 case 't':
222 opt->scheme = DmtxSchemeText;
223 break;
224 case 'x':
225 opt->scheme = DmtxSchemeX12;
226 break;
227 case 'e':
228 opt->scheme = DmtxSchemeEdifact;
229 break;
230 case '8':
231 opt->scheme = DmtxSchemeBase256;
232 break;
233 default:
234 fprintf(stderr, "Invalid encodation scheme \"%s\"\n", optarg);
235 return DmtxFail;
236 }
237 break;
238 case 'f':
239 opt->format = optarg;
240 break;
241 case 'l':
242 ListImageFormats();
243 exit(EX_OK);
244 break;
245 case 'o':
246 if(strncmp(optarg, "-", 2) == 0)
247 opt->outputPath = NULL;
248 else
249 opt->outputPath = optarg;
250 break;
251 case 'p':
252 opt->preview = DmtxTrue;
253 break;
254 case 'r':
255 err = StringToInt(&(opt->dpi), optarg, &ptr);
256 if(err != DmtxPass || opt->dpi <= 0 || *ptr != '\0')
257 FatalError(EX_USAGE, _("Invalid dpi specified \"%s\""), optarg);
258 break;
259 case 's':
260 /* Determine correct barcode size and/or shape */
261 if(*optarg == 's') {
262 opt->sizeIdx = DmtxSymbolSquareAuto;
263 }
264 else if(*optarg == 'r') {
265 opt->sizeIdx = DmtxSymbolRectAuto;
266 }
267 else {
268 for(i = 0; i < DmtxSymbolSquareCount + DmtxSymbolRectCount; i++) {
269 if(strncmp(optarg, symbolSizes[i], 8) == 0) {
270 opt->sizeIdx = i;
271 break;
272 }
273 }
274 if(i == DmtxSymbolSquareCount + DmtxSymbolRectCount)
275 return DmtxFail;
276 }
277 break;
278 case 'C':
279 opt->color[0] = 0;
280 opt->color[1] = 0;
281 opt->color[2] = 0;
282 fprintf(stderr, "Option \"%c\" not implemented\n", optchr);
283 break;
284 case 'B':
285 opt->bgColor[0] = 255;
286 opt->bgColor[1] = 255;
287 opt->bgColor[2] = 255;
288 fprintf(stderr, "Option \"%c\" not implemented\n", optchr);
289 break;
290 case 'M':
291 opt->mosaic = DmtxTrue;
292 break;
293 case 'R':
294 err = StringToInt(&(opt->rotate), optarg, &ptr);
295 if(err != DmtxPass || *ptr != '\0')
296 FatalError(EX_USAGE, _("Invalid rotation angle specified \"%s\""), optarg);
297 break;
298 case 'v':
299 opt->verbose = DmtxTrue;
300 break;
301 case 'G':
302 err = StringToInt(&(opt->gs1), optarg, &ptr);
303 if(err != DmtxPass || opt->gs1 <= 0 || opt->gs1 > 255 || *ptr != '\0')
304 FatalError(EX_USAGE, _("Invalid gs1 character specified \"%s\""), optarg);
305 break;
306 case 'V':
307 fprintf(stderr, "%s version %s\n", programName, DmtxVersion);
308 fprintf(stderr, "libdmtx version %s\n", dmtxVersion());
309 exit(0);
310 break;
311 default:
312 return DmtxFail;
313 break;
314 }
315 }
316
317 opt->inputPath = (*argvp)[optind];
318
319 /* XXX here test for incompatibility between options. For example you
320 cannot specify dpi if PNM output is requested */
321
322 return DmtxPass;
323 }
324
325 /**
326 *
327 *
328 */
329 static size_t
ReadInputData(unsigned char * codeBuffer,UserOptions * opt)330 ReadInputData(unsigned char *codeBuffer, UserOptions *opt)
331 {
332 int fd;
333 ssize_t bytesRead;
334 size_t bytesReadTotal;
335
336 /* Open file or stdin for reading */
337 fd = (opt->inputPath == NULL) ? 0 : open(opt->inputPath, O_RDONLY);
338 if(fd == -1)
339 FatalError(EX_IOERR, _("Error while opening file \"%s\""), opt->inputPath);
340
341 /* Read input contents into buffer */
342 for(bytesReadTotal = 0;; bytesReadTotal += bytesRead) {
343 bytesRead = read(fd, codeBuffer + bytesReadTotal, DMTXWRITE_BUFFER_SIZE);
344 if(bytesRead == 0)
345 break;
346
347 if(bytesRead == -1)
348 FatalError(EX_IOERR, _("Message read error"));
349 else if(bytesReadTotal == DMTXWRITE_BUFFER_SIZE)
350 FatalError(EX_DATAERR, _("Message to be encoded is too large"));
351 }
352
353 /* Close file only if not stdin */
354 if(fd != 0 && close(fd) != 0)
355 FatalError(EX_IOERR, _("Error while closing file"));
356
357 return bytesReadTotal;
358 }
359
360 /**
361 * @brief Display program usage and exit with received status.
362 * @param status error code returned to OS
363 * @return void
364 */
365 static void
ShowUsage(int status)366 ShowUsage(int status)
367 {
368 if(status != 0) {
369 fprintf(stderr, _("Usage: %s [OPTION]... [FILE]\n"), programName);
370 fprintf(stderr, _("Try `%s --help' for more information.\n"), programName);
371 }
372 else {
373 fprintf(stderr, _("Usage: %s [OPTION]... [FILE]\n"), programName);
374 fprintf(stderr, _("\
375 Encode FILE or standard input and write Data Matrix image\n\
376 \n\
377 Example: %s message.txt -o message.png\n\
378 Example: echo -n 123456 | %s -o message.png\n\
379 \n\
380 OPTIONS:\n"), programName, programName);
381 fprintf(stderr, _("\
382 -c, --codewords print codeword listing\n\
383 -d, --module=N module size (in pixels)\n\
384 -m, --margin=N margin size (in pixels)\n"));
385 fprintf(stderr, _("\
386 -e, --encoding=[abcet8x] primary encodation scheme\n\
387 a = ASCII [default] b = Best optimized [beta]\n\
388 c = C40 e = EDIFACT\n\
389 t = Text 8 = Base 256\n\
390 x = X12\n"));
391 fprintf(stderr, _("\
392 -f, --format=FORMAT PNG [default], TIF, GIF, PDF, etc...\n\
393 -l, --list-formats list supported image formats\n\
394 -o, --output=FILE output filename\n\
395 -p, --preview print ASCII art preview\n\
396 -r, --resolution=N set image print resolution (dpi)\n"));
397 fprintf(stderr, _("\
398 -s, --symbol-size=[sr|RxC] symbol size (default \"s\")\n\
399 Automatic size options:\n\
400 s = Auto square r = Auto rectangle\n"));
401 fprintf(stderr, _("\
402 Manual size options for square symbols:\n\
403 10x10 12x12 14x14 16x16 18x18 20x20\n\
404 22x22 24x24 26x26 32x32 36x36 40x40\n\
405 44x44 48x48 52x52 64x64 72x72 80x80\n\
406 88x88 96x96 104x104 120x120 132x132 144x144\n"));
407 fprintf(stderr, _("\
408 Manual size options for rectangle symbols:\n\
409 8x18 8x32 12x26 12x36 16x36 16x48\n"));
410 fprintf(stderr, _("\
411 -C, --color=COLOR barcode color (not implemented)\n\
412 -B, --bg-color=COLOR background color (not implemented)\n\
413 -M, --mosaic create Data Mosaic (non-standard)\n"));
414 fprintf(stderr, _("\
415 -R, --rotate=DEGREES rotation angle (degrees)\n\
416 -G, --gs1=N enable GS1 mode and define character to represent FNC1\n\
417 -v, --verbose use verbose messages\n\
418 -V, --version print version information\n\
419 --help display this help and exit\n"));
420 fprintf(stderr, _("\nReport bugs to <mike@dragonflylogic.com>.\n"));
421 }
422
423 exit(status);
424 }
425
426 /**
427 *
428 *
429 */
430 static void
CleanupMagick(MagickWand ** wand,int magickError)431 CleanupMagick(MagickWand **wand, int magickError)
432 {
433 char *excMessage;
434 ExceptionType excSeverity;
435
436 if(magickError == DmtxTrue) {
437 excMessage = MagickGetException(*wand, &excSeverity);
438 fprintf(stderr, "%s %s %lu %s\n", GetMagickModule(), excMessage);
439 MagickRelinquishMemory(excMessage);
440 }
441
442 if(*wand != NULL) {
443 DestroyMagickWand(*wand);
444 *wand = NULL;
445 }
446 }
447
448 /**
449 * @brief List supported input image formats on stdout
450 * @return void
451 */
452 static void
ListImageFormats(void)453 ListImageFormats(void)
454 {
455 int i, idx;
456 int row, rowCount;
457 int col, colCount;
458 unsigned long totalCount;
459 char **list;
460
461 list = MagickQueryFormats("*", &totalCount);
462
463 if(list == NULL)
464 return;
465
466 fprintf(stderr, "\n");
467
468 colCount = 7;
469 rowCount = totalCount / colCount;
470 if(totalCount % colCount)
471 rowCount++;
472
473 for(i = 0; i < colCount * rowCount; i++) {
474 col = i % colCount;
475 row = i / colCount;
476 idx = col * rowCount + row;
477 fprintf(stderr, "%10s", (idx < totalCount) ? list[col * rowCount + row] : " ");
478 fprintf(stderr, "%s", (col + 1 < colCount) ? " " : "\n");
479 }
480 fprintf(stderr, "\n");
481
482 MagickRelinquishMemory(list);
483 }
484
485 /**
486 *
487 *
488 *
489 */
490 static char *
GetImageFormat(UserOptions * opt)491 GetImageFormat(UserOptions *opt)
492 {
493 char *ptr = NULL;
494
495 /* Derive format from filename extension */
496 if(opt->outputPath != NULL) {
497 ptr = strrchr(opt->outputPath, '.');
498 if(ptr != NULL)
499 ptr++;
500 }
501
502 /* Found filename extension but format was also provided */
503 if(ptr != NULL && strlen(ptr) > 0 && opt->format != NULL)
504 fprintf(stderr, "WARNING: --format (-f) argument ignored; Format taken from filename\n");
505
506 /* If still undefined then use format argument */
507 if(ptr == NULL || strlen(ptr) == 0)
508 ptr = opt->format;
509
510 return ptr;
511 }
512
513 /**
514 *
515 *
516 */
517 static DmtxPassFail
WriteImageFile(UserOptions * opt,DmtxEncode * enc,char * format)518 WriteImageFile(UserOptions *opt, DmtxEncode *enc, char *format)
519 {
520 MagickBooleanType successA, successB;
521 MagickWand *wand;
522 char *outputPath;
523
524 MagickWandGenesis();
525
526 wand = NewMagickWand();
527 if(wand == NULL)
528 FatalError(EX_OSERR, "Undefined error");
529
530 successA = MagickConstituteImage(wand, enc->image->width, enc->image->height,
531 "RGB", CharPixel, enc->image->pxl);
532 if(successA == MagickFalse) {
533 CleanupMagick(&wand, DmtxTrue);
534 FatalError(EX_OSERR, "Undefined error");
535 }
536
537 if(opt->dpi != DmtxUndefined) {
538 successA = MagickSetImageResolution(wand, (double)opt->dpi, (double)opt->dpi);
539 successB = MagickSetImageUnits(wand, PixelsPerInchResolution);
540 if(successA == MagickFalse || successB == MagickFalse) {
541 CleanupMagick(&wand, DmtxFalse);
542 FatalError(EX_OSERR, "Illegal resolution \"%d\"", opt->dpi);
543 }
544 }
545
546 successA = MagickSetImageFormat(wand, format);
547 if(successA == MagickFalse) {
548 CleanupMagick(&wand, DmtxFalse);
549 FatalError(EX_OSERR, "Illegal format \"%s\"", format);
550 }
551
552 outputPath = (opt->outputPath == NULL) ? "-" : opt->outputPath;
553
554 successA = MagickWriteImage(wand, outputPath);
555 if(successA == MagickFalse) {
556 CleanupMagick(&wand, DmtxTrue);
557 FatalError(EX_OSERR, "Undefined error");
558 }
559
560 CleanupMagick(&wand, DmtxFalse);
561
562 MagickWandTerminus();
563
564 return DmtxPass;
565 }
566
567 /**
568 *
569 *
570 */
571 static DmtxPassFail
WriteSvgFile(UserOptions * opt,DmtxEncode * enc,char * format)572 WriteSvgFile(UserOptions *opt, DmtxEncode *enc, char *format)
573 {
574 int col, row, rowInv;
575 int symbolCols, symbolRows;
576 int width, height, module;
577 int defineOnly = DmtxFalse;
578 unsigned char mosaicRed, mosaicGrn, mosaicBlu;
579 char *idString = NULL;
580 char style[100];
581 FILE *fp;
582
583 if(StrNCmpI(format, "svg:", 4) == DmtxTrue) {
584 defineOnly = DmtxTrue;
585 idString = &format[4];
586 }
587
588 if(idString == NULL || strlen(idString) == 0)
589 idString = "dmtx_0001";
590
591 if(opt->outputPath == NULL) {
592 fp = stdout;
593 }
594 else {
595 fp = fopen(opt->outputPath, "wb");
596 if(fp == NULL)
597 FatalError(EX_CANTCREAT, "Unable to create output file \"%s\"", opt->outputPath);
598 }
599
600 width = 2 * enc->marginSize + (enc->region.symbolCols * enc->moduleSize);
601 height = 2 * enc->marginSize + (enc->region.symbolRows * enc->moduleSize);
602
603 symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, enc->region.sizeIdx);
604 symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, enc->region.sizeIdx);
605
606 /* Print SVG Header */
607 if(defineOnly == DmtxFalse) {
608 fprintf(fp, "\
609 <?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n\
610 <!-- Created with dmtxwrite (http://www.libdmtx.org/) -->\n\
611 <svg\n\
612 xmlns:svg=\"http://www.w3.org/2000/svg\"\n\
613 xmlns=\"http://www.w3.org/2000/svg\"\n\
614 xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n\
615 version=\"1.0\"\n\
616 width=\"%d\"\n\
617 height=\"%d\"\n\
618 id=\"svg2\">\n\
619 <defs>\n", width, height);
620 }
621
622 fprintf(fp, " <symbol id=\"%s\">\n", idString);
623 fprintf(fp, " <desc>Layout:%dx%d Symbol:%dx%d Data Matrix</desc>\n",
624 width, height, symbolCols, symbolRows);
625
626 /* Write Data Matrix ON modules */
627 for(row = 0; row < enc->region.symbolRows; row++) {
628 rowInv = enc->region.symbolRows - row - 1;
629 for(col = 0; col < enc->region.symbolCols; col++) {
630 module = dmtxSymbolModuleStatus(enc->message, enc->region.sizeIdx, row, col);
631 if(opt->mosaic == DmtxTrue) {
632 mosaicRed = (module & DmtxModuleOnRed) ? 0x00 : 0xff;
633 mosaicGrn = (module & DmtxModuleOnGreen) ? 0x00 : 0xff;
634 mosaicBlu = (module & DmtxModuleOnBlue) ? 0x00 : 0xff;
635 snprintf(style, 100, "style=\"fill:#%02x%02x%02x;fill-opacity:1;stroke:none\" ",
636 mosaicRed, mosaicGrn, mosaicBlu);
637 }
638 else {
639 style[0] = '\0';
640 }
641
642 if(module & DmtxModuleOn) {
643 fprintf(fp, " <rect width=\"%d\" height=\"%d\" x=\"%d\" y=\"%d\" %s/>\n",
644 opt->moduleSize, opt->moduleSize,
645 col * opt->moduleSize + opt->marginSize,
646 rowInv * opt->moduleSize + opt->marginSize, style);
647 }
648 }
649 }
650
651 fprintf(fp, " </symbol>\n");
652
653 /* Close SVG document */
654 if(defineOnly == DmtxFalse) {
655 fprintf(fp, "\
656 </defs>\n\
657 \n\
658 <use xlink:href=\"#%s\" x='0' y='0' style=\"fill:#000000;fill-opacity:1;stroke:none\" />\n\
659 \n\
660 </svg>\n", idString);
661 }
662
663 return DmtxPass;
664 }
665
666 /**
667 *
668 *
669 */
670 static DmtxPassFail
WriteAsciiPreview(DmtxEncode * enc)671 WriteAsciiPreview(DmtxEncode *enc)
672 {
673 int symbolRow, symbolCol;
674
675 fputc('\n', stdout);
676
677 /* ASCII prints from top to bottom */
678 for(symbolRow = enc->region.symbolRows - 1; symbolRow >= 0; symbolRow--) {
679
680 fputs(" ", stdout);
681 for(symbolCol = 0; symbolCol < enc->region.symbolCols; symbolCol++) {
682 fputs((dmtxSymbolModuleStatus(enc->message, enc->region.sizeIdx,
683 symbolRow, symbolCol) & DmtxModuleOnRGB) ? "XX" : " ", stdout);
684 }
685 fputs("\n", stdout);
686 }
687
688 fputc('\n', stdout);
689
690 return DmtxPass;
691 }
692
693 /**
694 *
695 *
696 */
697 static DmtxPassFail
WriteCodewordList(DmtxEncode * enc)698 WriteCodewordList(DmtxEncode *enc)
699 {
700 int i;
701 int dataWordLength;
702 int remainingDataWords;
703
704 dataWordLength = dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, enc->region.sizeIdx);
705
706 for(i = 0; i < enc->message->codeSize; i++) {
707 remainingDataWords = dataWordLength - i;
708 if(remainingDataWords > enc->message->padCount)
709 fprintf(stdout, "%c:%03d\n", 'd', enc->message->code[i]);
710 else if(remainingDataWords > 0)
711 fprintf(stdout, "%c:%03d\n", 'p', enc->message->code[i]);
712 else
713 fprintf(stdout, "%c:%03d\n", 'e', enc->message->code[i]);
714 }
715
716 return DmtxPass;
717 }
718
719 /**
720 *
721 *
722 */
723 static DmtxBoolean
StrNCmpI(const char * s1,const char * s2,size_t n)724 StrNCmpI(const char *s1, const char *s2, size_t n)
725 {
726 size_t i;
727
728 if(s1 == NULL || s2 == NULL || n == 0)
729 return DmtxFalse;
730
731 for(i = 0; i < n; i++) {
732 if(tolower(s1[i]) != tolower(s2[i]))
733 return DmtxFalse;
734 if(s1[i] == '\0' || s2[i] == '\0')
735 break;
736 }
737
738 return DmtxTrue;
739 }
740