]> git.sur5r.net Git - iec16022/commitdiff
Imported Upstream version 0.1 upstream/0.1
authorJan Luebbe <jluebbe@debian.org>
Wed, 18 Feb 2009 12:17:48 +0000 (13:17 +0100)
committerJan Luebbe <jluebbe@debian.org>
Wed, 18 Feb 2009 12:17:48 +0000 (13:17 +0100)
15 files changed:
CHANGELOG [new file with mode: 0644]
CREDITS [new file with mode: 0644]
INSTALL [new file with mode: 0644]
LICENSE [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
TODO [new file with mode: 0644]
iec16022.1 [new file with mode: 0644]
iec16022.c [new file with mode: 0644]
iec16022ecc200.c [new file with mode: 0644]
iec16022ecc200.h [new file with mode: 0644]
image.c [new file with mode: 0644]
image.h [new file with mode: 0644]
reedsol.c [new file with mode: 0644]
reedsol.h [new file with mode: 0644]

diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644 (file)
index 0000000..7f1e6b4
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,8 @@
+0.1
+       - Initial release.
+       - INSTALL, README, TODO, CREDITS, Makefile, LICENSE and CHANGELOG files
+         added.
+       - Fix some include issues.
+       - Fix some signed/unsigned issues.
+
+2006-01-08  Stefan Schmidt <stefan@datenfreihafen.org>
diff --git a/CREDITS b/CREDITS
new file mode 100644 (file)
index 0000000..c37d23d
--- /dev/null
+++ b/CREDITS
@@ -0,0 +1,6 @@
+Adrian Kennard, Andrews & Arnold Ltd for the original source code. You can 
+find it at http://aa.gg/free/
+
+Cliff Hones for the RS coding.
+
+Jan Luebbe for writing the manual page.
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..69cadcb
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,3 @@
+Installing iec16022 is really simple. Just do a 'make' and 'make install'.
+In standard configuration the binary will be installed in /usr/local/bin. You
+can change this behavior in the Makefile via DESTDIR.
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..3912109
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..c8fb665
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,22 @@
+CC=/usr/bin/cc
+INSTALL=/usr/bin/install
+GZIP=/bin/gzip
+
+DESTDIR=/usr/local
+
+prefix=$(DESTDIR)
+bindir=$(prefix)/bin
+mandir=$(prefix)/share/man
+
+all:
+       $(CC) -o iec16022 iec16022.c -DLIB image.c reedsol.c iec16022ecc200.c -lz -lpopt
+       $(GZIP) -f --best < iec16022.1 > iec16022.1.gz
+
+install: all
+       $(INSTALL) -m 755 iec16022 $(bindir)
+       $(INSTALL) -m 644 iec16022.1.gz $(mandir)/man1
+
+
+clean:
+       rm -f iec16022
+       rm -f iec16022.1.gz
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..cf4aef8
--- /dev/null
+++ b/README
@@ -0,0 +1,13 @@
+With iec16022 you can produce 2d barcodes. Also known as Data Matrix. These
+barcodes are defined in ISO IEC16022.
+
+The code was originally written by Andrews & Arnold Ltd. You can download this
+code from http://aa.gg/free/.
+The current maintainer of the code is Stefan Schmidt.
+
+Website:               http://www.datenfreihafen.org/projects/iec16022.html
+Maillinglist:  https://sirius.lasnet.de/mailman/listinfo/iec16022
+SVN repository:        https://svn.datenfreihafen.org/iec16022/
+
+
+Stefan Schmidt <stefan@datenfreihafen.org>
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..41c0ea9
--- /dev/null
+++ b/TODO
@@ -0,0 +1,9 @@
+- Set textwidth to 80.
+- Fix compiler warnings.
+
+- Get ISO standard to verify code.
+
+Some things to think about:
+---------------------------
+- Use libpng?
+- Merge iec16022 in barcode?
diff --git a/iec16022.1 b/iec16022.1
new file mode 100644 (file)
index 0000000..e725482
--- /dev/null
@@ -0,0 +1,63 @@
+.\"                                      Hey, EMACS: -*- nroff -*-
+.\" First parameter, NAME, should be all caps
+.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
+.\" other parameters are allowed: see man(7), man(1)
+.TH IEC16022 1 "December 28, 2005"
+.\" Please adjust this date whenever revising the manpage.
+.\"
+.\" Some roff macros, for reference:
+.\" .nh        disable hyphenation
+.\" .hy        enable hyphenation
+.\" .ad l      left justify
+.\" .ad b      justify to both left and right margins
+.\" .nf        disable filling
+.\" .fi        enable filling
+.\" .br        insert line break
+.\" .sp <n>    insert n+1 empty lines
+.\" for manpage-specific macros, see man(7)
+.SH NAME
+iec16022 \- program to generate 2d barcodes
+.SH SYNOPSIS
+.B iec16022
+.RI [ options ]
+.SH DESCRIPTION
+This manual page documents briefly the
+.B iec16022
+command.
+.PP
+.B iec16022
+generates 2d barcodes conforming to the ISO/IEC 16022 standard (which is
+also known as Data Matrix and Semacode).
+.SH OPTIONS
+These programs follow the usual GNU command line syntax, with long
+options starting with two dashes (`-').
+A summary of options is included below.
+.TP
+.B \-s, \-\-size WxH
+Sets the size of the generated barcode.
+.TP
+.B \-c, \-\-barcode text
+Specifies the text to be encoded.
+.TP
+.B \-\-ecc 000|050|080|100|140|200
+Sets the type of ecc to be used.
+.TP
+.B \-i, \-\-infile filename
+Read input data from file.
+.TP
+.B \-o, \-\-outfile filenmae
+Save output to file (instead of standard output).
+.TP
+.B \-f, \-\-format Text|EPS|Bin|Hex|Stamp|PNG
+Set the output type.
+.TP
+.B \-?, \-\-help
+Show summary of options.
+.TP
+.B \-\-usage
+Show short overview of options.
+.SH AUTHOR
+iec16022 was written by Adrian Kennard, Andrews & Arnold Ltd.
+.PP
+This manual page was written by Jan Luebbe <jluebbe@lasnet.de>,
+for the Debian project (but may be used by others).
diff --git a/iec16022.c b/iec16022.c
new file mode 100644 (file)
index 0000000..3c73935
--- /dev/null
@@ -0,0 +1,454 @@
+/** 
+ *
+ * IEC16022 bar code generation
+ * Adrian Kennard, Andrews & Arnold Ltd
+ * with help from Cliff Hones on the RS coding
+ *
+ * (c) 2004 Adrian Kennard, Andrews & Arnold Ltd
+ * (c) 2006 Stefan Schmidt <stefan@datenfreihafen.org>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ */ 
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <popt.h>
+#include <malloc.h>
+#include "image.h"
+#include "iec16022ecc200.h"
+
+ // simple checked response malloc
+void *
+safemalloc (int n)
+{
+   void *p = malloc (n);
+   if (!p)
+   {
+      fprintf (stderr, "Malloc(%d) failed\n", n);
+      exit (1);
+   }
+   return p;
+}
+
+// hex dump - bottom left pixel first
+void
+dumphex (unsigned char *grid, int W, int H, unsigned char p)
+{
+   int c = 0,
+      y;
+   for (y = 0; y < H; y++)
+   {
+      int v = 0,
+         x,
+         b = 128;
+      for (x = 0; x < W; x++)
+      {
+         if (grid[y * W + x])
+            v |= b;
+         b >>= 1;
+         if (!b)
+         {
+            printf ("%02X", v ^ p);
+            v = 0;
+            b = 128;
+            c++;
+         }
+      }
+      if (b != 128)
+      {
+         printf ("%02X", v ^ p);
+         c++;
+      }
+      printf (" ");
+      c++;
+      if (c >= 80)
+      {
+         printf ("\n");
+         c = 0;
+      }
+   }
+   if (c)
+      printf ("\n");
+}
+
+int
+main (int argc, const char *argv[])
+{
+   char c;
+   int W = 0,
+      H = 0;
+   int ecc = 0;
+   int barcodelen = 0;
+   char *encoding = 0;
+   char *outfile = 0;
+   char *infile = 0;
+   char *barcode = 0;
+   char *format = "Text";
+   char *size = 0;
+   char *eccstr = 0;
+   int len = 0,
+      maxlen = 0,
+      ecclen = 0;
+   unsigned char *grid = 0;
+   poptContext optCon;          // context for parsing command-line options
+   const struct poptOption optionsTable[] = {
+      {
+       "size", 's', POPT_ARG_STRING, &size, 0, "Size", "WxH"},
+      {
+       "barcode", 'c', POPT_ARG_STRING, &barcode, 0, "Barcode", "text"},
+      {
+       "ecc", 0, POPT_ARG_STRING, &eccstr, 0, "ECC", "000/050/080/100/140/200"},
+      {
+       "infile", 'i', POPT_ARG_STRING, &infile, 0, "Barcode file", "filename"},
+      {
+       "outfile", 'o', POPT_ARG_STRING, &outfile, 0, "Output filename", "filename"},
+      {
+       "encoding", 'e', POPT_ARG_STRING, &encoding, 0, "Encoding template", "[CTXEAB]* for ecc200 or 11/27/41/37/128/256"},
+      {
+       "format", 'f', POPT_ARGFLAG_SHOW_DEFAULT | POPT_ARG_STRING, &format, 0, "Output format", "Text/EPS/PNG/Bin/Hex/Stamp"},
+      POPT_AUTOHELP {
+                     NULL, 0, 0, NULL, 0}
+   };
+   optCon = poptGetContext (NULL, argc, argv, optionsTable, 0);
+   poptSetOtherOptionHelp (optCon, "[barcode]");
+   if ((c = poptGetNextOpt (optCon)) < -1)
+   {
+      /* an error occurred during option processing */
+      fprintf (stderr, "%s: %s\n", poptBadOption (optCon, POPT_BADOPTION_NOALIAS), poptStrerror (c));
+      return 1;
+   }
+
+   if (poptPeekArg (optCon) && !barcode && !infile)
+      barcode = (char *) poptGetArg (optCon);
+   if (poptPeekArg (optCon) || !barcode && !infile || barcode && infile)
+   {
+      poptPrintUsage (optCon, stderr, 0);
+      return -1;
+   }
+   if (outfile && !freopen (outfile, "w", stdout))
+   {
+      perror (outfile);
+      return 1;
+   }
+
+   if (infile)
+   {                            // read from file
+      FILE *f = fopen (infile, "rb");
+      barcode = safemalloc (4001);
+      if (!f)
+      {
+         perror (infile);
+         return 1;
+      }
+      barcodelen = fread (barcode, 1, 4000, f);
+      if (barcodelen < 0)
+      {
+         perror (infile);
+         return 1;
+      }
+      barcode[barcodelen] = 0;  // null terminate anyway
+      close (f);
+   } else
+      barcodelen = strlen (barcode);
+   // check parameters
+   if (size)
+   {
+      char *x = strchr (size, 'x');
+      W = atoi (size);
+      if (x)
+         H = atoi (x + 1);
+      if (!H)
+         W = H;
+   }
+   if (eccstr)
+      ecc = atoi (eccstr);
+   if (W & 1)
+   {                            // odd size
+      if (W != H || W < 9 || W > 49)
+      {
+         fprintf (stderr, "Invalid size %dx%d\n", W, H);
+         return 1;
+      }
+      if (!eccstr)
+      {
+         if (W >= 17)
+            ecc = 140;
+         else if (W >= 13)
+            ecc = 100;
+         else if (W >= 11)
+            ecc = 80;
+         else
+            ecc = 0;
+      }
+      if (ecc && ecc != 50 && ecc != 80 && ecc != 100 && ecc != 140 || ecc == 50 && W < 11 || ecc == 80 && W < 13
+          || ecc == 100 && W < 13 || ecc == 140 && W < 17)
+      {
+         fprintf (stderr, "ECC%03d invalid for %dx%d\n", ecc, W, H);
+         return 1;
+      }
+
+   } else if (W)
+   {                            // even size
+      if (W < H)
+      {
+         int t = W;
+         W = H;
+         H = t;
+      }
+      if (!eccstr)
+         ecc = 200;
+      if (ecc != 200)
+      {
+         fprintf (stderr, "ECC%03d invalid for %dx%d\n", ecc, W, H);
+         return 1;
+      }
+   }
+
+   else
+   {                            // auto size
+      if (!eccstr)
+         ecc = 200;             // default is even sizes only unless explicit ecc set to force odd sizes
+   }
+
+   if (tolower (*format) == 's')
+   {                            // special stamp format checks & defaults
+      if (!W)
+         W = H = 32;
+      if (ecc != 200 || W != 32 || H != 32)
+         fprintf (stderr, "Stamps must be 32x32\n");
+      if (encoding)
+         fprintf (stderr, "Stamps should use auto encoding\n");
+      else
+      {
+         int n;
+         for (n = 0; n < barcodelen && (barcode[n] == ' ' || isdigit (barcode[n]) || isupper (barcode[n])); n++);
+         if (n < barcodelen)
+            fprintf (stderr, "Has invalid characters for a stamp\n");
+         else
+         {                      // Generate simplistic encoding rules as used by the windows app
+            // TBA - does not always match the windows app...
+            n = 0;
+            encoding = safemalloc (barcodelen + 1);
+            while (n < barcodelen)
+            {
+               // ASCII
+               while (1)
+               {
+                  if (n == barcodelen || n + 3 <= barcodelen && (!isdigit (barcode[n]) || !isdigit (barcode[n + 1])))
+                     break;
+                  encoding[n++] = 'A';
+                  if (n < barcodelen && isdigit (barcode[n - 1]) && isdigit (barcode[n]))
+                     encoding[n++] = 'A';
+               }
+               // C40
+               while (1)
+               {
+                  int r = 0;
+                  while (n + r < barcodelen && isdigit (barcode[n + r]))
+                     r++;
+                  if (n + 3 > barcodelen || r >= 6)
+                     break;
+                  encoding[n++] = 'C';
+                  encoding[n++] = 'C';
+                  encoding[n++] = 'C';
+               }
+            }
+            encoding[n] = 0;
+            //fprintf (stderr, "%s\n%s\n", barcode, encoding);
+         }
+      }
+   }
+   // processing stamps
+   if ((W & 1) || ecc < 200)
+   {                            // odd sizes
+      fprintf (stderr, "Not done odd sizes yet, sorry\n");
+   } else
+   {                            // even sizes
+      grid = iec16022ecc200 (&W, &H, &encoding, barcodelen, barcode, &len, &maxlen, &ecclen);
+   }
+
+   // output
+   if (!grid || !W)
+   {
+      fprintf (stderr, "No barcode produced\n");
+      return 1;
+   }
+   switch (tolower (*format))
+   {
+   case 'i':                   // info
+      printf ("Size    : %dx%d\n", W, H);
+      printf ("Encoded : %d of %d bytes with %d bytes of ecc\n", len, maxlen, ecclen);
+      printf ("Barcode : %s\n", barcode);
+      printf ("Encoding: %s\n", encoding);
+      break;
+   case 'h':                   // hex
+      dumphex (grid, W, H, 0);
+      break;
+   case 'b':                   // bin
+      {
+         int y;
+         for (y = 0; y < H; y++)
+         {
+            int v = 0,
+               x,
+               b = 128;
+            for (x = 0; x < W; x++)
+            {
+               if (grid[y * W + x])
+                  v |= b;
+               b >>= 1;
+               if (!b)
+               {
+                  putchar (v);
+                  v = 0;
+                  b = 128;
+               }
+            }
+            if (b != 128)
+               putchar (v);
+         }
+      }
+      break;
+   case 't':                   // text
+      {
+         int y;
+         for (y = H - 1; y >= 0; y--)
+         {
+            int x;
+            for (x = 0; x < W; x++)
+               printf ("%c", grid[W * y + x] ? '*' : ' ');
+            printf ("\n");
+         }
+      }
+      break;
+   case 'e':                   // EPS
+      printf ("%%!PS-Adobe-3.0 EPSF-3.0\n" "%%%%Creator: IEC16022 barcode/stamp generator\n" "%%%%BarcodeData: %s\n"
+              "%%%%BarcodeSize: %dx%d\n" "%%%%BarcodeFormat: ECC200\n" "%%%%DocumentData: Clean7Bit\n" "%%%%LanguageLevel: 1\n"
+              "%%%%Pages: 1\n" "%%%%BoundingBox: 0 0 %d %d\n" "%%%%EndComments\n" "%%%%Page: 1 1\n" "%d %d 1[1 0 0 1 -1 -1]{<\n",
+              barcode, W, H, W + 2, H + 2, W, H);
+      dumphex (grid, W, H, 0xFF);
+      printf (">}image\n");
+      break;
+   case 's':                   // Stamp
+      {
+         char temp[74],
+           c;
+         time_t now;
+         struct tm t = {
+            0
+         };
+         int v;
+         if (barcodelen < 74)
+         {
+            fprintf (stderr, "Does not look like a stamp barcode\n");
+            return 1;
+         }
+         memcpy (temp, barcode, 74);
+         c = temp[5];
+         temp[56] = 0;
+         t.tm_year = atoi (temp + 54) + 100;
+         t.tm_mday = 1;
+         now = mktime (&t);
+         temp[54] = 0;
+         now += 86400 * (atoi (temp + 51) - 1);
+         t = *gmtime (&now);
+         temp[46] = 0;
+         v = atoi (temp + 36);
+         printf ("%%!PS-Adobe-3.0 EPSF-3.0\n" "%%%%Creator: IEC16022 barcode/stamp generator\n" "%%%%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 setfont}bind def/rm/rmoveto load def/m/moveto load def/rl/rlineto load def\n"
+                 "/l/lineto load def/cp/closepath load def/c{dup stringwidth 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 cp clip 1 setgray fill 0 setgray 0.5 0 translate 0.3 setlinewidth\n"
+                 "32 32 1[2 0 0 2 0 -11]{<\n", barcode, W, H);
+         dumphex (grid, W, H, 0xFF);
+         printf (">}image\n"
+                 "3.25/Helvetica-Bold f 8 25.3 m(\\243%d.%02d)c\n"
+                 "2.6/Helvetica f 8 22.3 m(%.4s %.4s)c\n"
+                 "1.5/Helvetica f 8 3.3 m(POST BY)c\n"
+                 "3.3/Helvetica f 8 0.25 m(%02d.%02d.%02d)c\n",
+                 v / 100, v % 100, temp + 6, temp + 10, t.tm_mday, t.tm_mon + 1, t.tm_year % 100);
+         if (c == '1' || c == '2' || c == 'A' || c == 'S')
+         {
+            if (c == '2')
+               printf ("42 0 m 10 0 rl 0 28 rl -10 0 rl cp 57 0 m 5 0 rl 0 28 rl -5 0 rl cp");
+            else
+               printf ("42 0 m 5 0 rl 0 28 rl -5 0 rl cp 52 0 m 10 0 rl 0 28 rl -10 0 rl cp");
+            printf (" 21 0 m 16 0 rl 0 28 rl -16 0 rl cp fill\n"
+                    "21.3 0.3 m 15.4 0 rl 0 13 rl -15.4 0 rl cp 1 setgray fill gsave 21.3 0.3 15.4 27.4 rectclip newpath\n");
+            switch (c)
+            {
+            case '1':
+               printf
+                  ("27/Helvetica-Bold f 27 8.7 m(1)show grestore 0 setgray 1.5/Helvetica-Bold f 22 3.3 m(POSTAGE PAID GB)show 1.7/Helvetica f 29 1.5 m(DumbStamp.co.uk)c\n");
+               break;
+            case '2':
+               printf
+                  ("21/Helvetica-Bold f 23.5 13 m(2)1.25 1 scale show grestore 0 setgray 1.5/Helvetica-Bold f 22 3.3 m(POSTAGE PAID GB)show 1.7/Helvetica f 29 1.5 m(DumbStamp.co.uk)c\n");
+               break;
+            case 'A':
+               printf
+                  ("16/Helvetica-Bold f 29 14.75 m 1.1 1 scale(A)c grestore 0 setgray 1.5/Helvetica-Bold f 22 3.3 m(POSTAGE PAID GB)show 1.7/Helvetica f 22 1.5 m(Par Avion)show\n");
+               break;
+            case 'S':
+               printf ("10/Helvetica-Bold f 29 17 m(SU)c grestore 0 setgray 1.5/Helvetica-Bold f 22 1.5 m(POSTAGE PAID GB)show\n");
+               break;
+            }
+            printf ("2.3/Helvetica-Bold f 29 10 m(LOYAL MAIL)c\n");
+         } else if (c == 'P')
+         {                      // Standard Parcels
+            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 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 grestore 0 setgray\n"
+                    "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");
+         } else if (c == '3')
+            printf ("21.15 0.15 40.7 27.7 rectstroke\n"
+                    "21 0 m 41 0 rl 0 5 rl -41 0 rl cp fill\n"
+                    "0 1 2{0 1 18{dup 1.525 mul 22.9 add 24 3 index 1.525 mul 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"
+                    "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 f(delivery)show\n"
+                    "gsave 1 setgray 3.2/Helvetica-Bold f 24 1.6 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 arc fill\n");
+         printf ("end grestore\n");
+      }
+      break;
+   case 'p':                   // png
+      {
+         int x,
+           y;
+         Image *i = ImageNew (W + 2, H + 2, 2);
+         i->Colour[0] = 0xFFFFFF;
+         i->Colour[1] = 0;
+         for (y = 0; y < H; y++)
+            for (x = 0; x < W; x++)
+               if (grid[y * W + x])
+                  ImagePixel (i, x + 1, H - y) = 1;
+         ImageWritePNG (i, fileno (stdout), 0, -1, barcode);
+         ImageFree (i);
+      }
+      break;
+   default:
+      fprintf (stderr, "Unknown output format %s\n", format);
+      break;
+   }
+   return 0;
+}
diff --git a/iec16022ecc200.c b/iec16022ecc200.c
new file mode 100644 (file)
index 0000000..c5bc79e
--- /dev/null
@@ -0,0 +1,936 @@
+/** 
+ *
+ * IEC16022 bar code generation
+ * Adrian Kennard, Andrews & Arnold Ltd
+ * with help from Cliff Hones on the RS coding
+ * 
+ * (c) 2004 Adrian Kennard, Andrews & Arnold Ltd
+ * (c) 2006 Stefan Schmidt <stefan@datenfreihafen.org>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <popt.h>
+#include <malloc.h>
+#include "reedsol.h"
+#include "iec16022ecc200.h"
+
+static struct ecc200matrix_s
+{
+   int H,
+     W;
+   int FH,
+     FW;
+   int bytes;
+   int datablock,
+     rsblock;
+}
+ecc200matrix[] =
+{
+   10, 10, 10, 10, 3, 3, 5,     //
+      12, 12, 12, 12, 5, 5, 7,  //
+      8, 18, 8, 18, 5, 5, 7,    //
+      14, 14, 14, 14, 8, 8, 10, //
+      8, 32, 8, 16, 10, 10, 11, //
+      16, 16, 16, 16, 12, 12, 12,       //
+      12, 26, 12, 26, 16, 16, 14,       //
+      18, 18, 18, 18, 18, 18, 14,       //
+      20, 20, 20, 20, 22, 22, 18,       //
+      12, 36, 12, 18, 22, 22, 18,       //
+      22, 22, 22, 22, 30, 30, 20,       //
+      16, 36, 16, 18, 32, 32, 24,       //
+      24, 24, 24, 24, 36, 36, 24,       //
+      26, 26, 26, 26, 44, 44, 28,       //
+      16, 48, 16, 24, 49, 49, 28,       //
+      32, 32, 16, 16, 62, 62, 36,       //
+      36, 36, 18, 18, 86, 86, 42,       //
+      40, 40, 20, 20, 114, 114, 48,     //
+      44, 44, 22, 22, 144, 144, 56,     //
+      48, 48, 24, 24, 174, 174, 68,     //
+      52, 52, 26, 26, 204, 102, 42,     //
+      64, 64, 16, 16, 280, 140, 56,     //
+      72, 72, 18, 18, 368, 92, 36,      //
+      80, 80, 20, 20, 456, 114, 48,     //
+      88, 88, 22, 22, 576, 144, 56,     //
+      96, 96, 24, 24, 696, 174, 68,     //
+      104, 104, 26, 26, 816, 136, 56,   //
+      120, 120, 20, 20, 1050, 175, 68,  //
+      132, 132, 22, 22, 1304, 163, 62,  //
+      144, 144, 24, 24, 1558, 156, 62,  // 156*4+155*2
+      0                         // terminate
+};
+
+ // simple checked response malloc
+static void *
+safemalloc (int n)
+{
+   void *p = malloc (n);
+   if (!p)
+   {
+      fprintf (stderr, "Malloc(%d) failed\n", n);
+      exit (1);
+   }
+   return p;
+}
+
+// Annex M placement alorithm low level
+static void
+ecc200placementbit (int *array, int NR, int NC, int r, int c, int p, char b)
+{
+   if (r < 0)
+   {
+      r += NR;
+      c += 4 - ((NR + 4) % 8);
+   }
+   if (c < 0)
+   {
+      c += NC;
+      r += 4 - ((NC + 4) % 8);
+   }
+   array[r * NC + c] = (p << 3) + b;
+}
+
+static void
+ecc200placementblock (int *array, int NR, int NC, int r, int c, int p)
+{
+   ecc200placementbit (array, NR, NC, r - 2, c - 2, p, 7);
+   ecc200placementbit (array, NR, NC, r - 2, c - 1, p, 6);
+   ecc200placementbit (array, NR, NC, r - 1, c - 2, p, 5);
+   ecc200placementbit (array, NR, NC, r - 1, c - 1, p, 4);
+   ecc200placementbit (array, NR, NC, r - 1, c - 0, p, 3);
+   ecc200placementbit (array, NR, NC, r - 0, c - 2, p, 2);
+   ecc200placementbit (array, NR, NC, r - 0, c - 1, p, 1);
+   ecc200placementbit (array, NR, NC, r - 0, c - 0, p, 0);
+}
+
+static void
+ecc200placementcornerA (int *array, int NR, int NC, int p)
+{
+   ecc200placementbit (array, NR, NC, NR - 1, 0, p, 7);
+   ecc200placementbit (array, NR, NC, NR - 1, 1, p, 6);
+   ecc200placementbit (array, NR, NC, NR - 1, 2, p, 5);
+   ecc200placementbit (array, NR, NC, 0, NC - 2, p, 4);
+   ecc200placementbit (array, NR, NC, 0, NC - 1, p, 3);
+   ecc200placementbit (array, NR, NC, 1, NC - 1, p, 2);
+   ecc200placementbit (array, NR, NC, 2, NC - 1, p, 1);
+   ecc200placementbit (array, NR, NC, 3, NC - 1, p, 0);
+}
+
+static void
+ecc200placementcornerB (int *array, int NR, int NC, int p)
+{
+   ecc200placementbit (array, NR, NC, NR - 3, 0, p, 7);
+   ecc200placementbit (array, NR, NC, NR - 2, 0, p, 6);
+   ecc200placementbit (array, NR, NC, NR - 1, 0, p, 5);
+   ecc200placementbit (array, NR, NC, 0, NC - 4, p, 4);
+   ecc200placementbit (array, NR, NC, 0, NC - 3, p, 3);
+   ecc200placementbit (array, NR, NC, 0, NC - 2, p, 2);
+   ecc200placementbit (array, NR, NC, 0, NC - 1, p, 1);
+   ecc200placementbit (array, NR, NC, 1, NC - 1, p, 0);
+}
+
+static void
+ecc200placementcornerC (int *array, int NR, int NC, int p)
+{
+   ecc200placementbit (array, NR, NC, NR - 3, 0, p, 7);
+   ecc200placementbit (array, NR, NC, NR - 2, 0, p, 6);
+   ecc200placementbit (array, NR, NC, NR - 1, 0, p, 5);
+   ecc200placementbit (array, NR, NC, 0, NC - 2, p, 4);
+   ecc200placementbit (array, NR, NC, 0, NC - 1, p, 3);
+   ecc200placementbit (array, NR, NC, 1, NC - 1, p, 2);
+   ecc200placementbit (array, NR, NC, 2, NC - 1, p, 1);
+   ecc200placementbit (array, NR, NC, 3, NC - 1, p, 0);
+}
+
+static void
+ecc200placementcornerD (int *array, int NR, int NC, int p)
+{
+   ecc200placementbit (array, NR, NC, NR - 1, 0, p, 7);
+   ecc200placementbit (array, NR, NC, NR - 1, NC - 1, p, 6);
+   ecc200placementbit (array, NR, NC, 0, NC - 3, p, 5);
+   ecc200placementbit (array, NR, NC, 0, NC - 2, p, 4);
+   ecc200placementbit (array, NR, NC, 0, NC - 1, p, 3);
+   ecc200placementbit (array, NR, NC, 1, NC - 3, p, 2);
+   ecc200placementbit (array, NR, NC, 1, NC - 2, p, 1);
+   ecc200placementbit (array, NR, NC, 1, NC - 1, p, 0);
+}
+
+// Annex M placement alorithm main function
+static void
+ecc200placement (int *array, int NR, int NC)
+{
+   int r,
+     c,
+     p;
+   // invalidate
+   for (r = 0; r < NR; r++)
+      for (c = 0; c < NC; c++)
+         array[r * NC + c] = 0;
+   // start
+   p = 1;
+   r = 4;
+   c = 0;
+   do
+   {
+      // check corner
+      if (r == NR && !c)
+         ecc200placementcornerA (array, NR, NC, p++);
+      if (r == NR - 2 && !c && NC % 4)
+         ecc200placementcornerB (array, NR, NC, p++);
+      if (r == NR - 2 && !c && (NC % 8) == 4)
+         ecc200placementcornerC (array, NR, NC, p++);
+      if (r == NR + 4 && c == 2 && !(NC % 8))
+         ecc200placementcornerD (array, NR, NC, p++);
+      // up/right
+      do
+      {
+         if (r < NR && c >= 0 && !array[r * NC + c])
+            ecc200placementblock (array, NR, NC, r, c, p++);
+         r -= 2;
+         c += 2;
+      }
+      while (r >= 0 && c < NC);
+      r++;
+      c += 3;
+      // down/left
+      do
+      {
+         if (r >= 0 && c < NC && !array[r * NC + c])
+            ecc200placementblock (array, NR, NC, r, c, p++);
+         r += 2;
+         c -= 2;
+      }
+      while (r < NR && c >= 0);
+      r += 3;
+      c++;
+   }
+   while (r < NR || c < NC);
+   // unfilled corner
+   if (!array[NR * NC - 1])
+      array[NR * NC - 1] = array[NR * NC - NC - 2] = 1;
+}
+
+// calculate and append ecc code, and if necessary interleave
+static void
+ecc200 (unsigned char *binary, int bytes, int datablock, int rsblock)
+{
+   int blocks = (bytes + 2) / datablock,
+      b;
+   rs_init_gf (0x12d);
+   rs_init_code (rsblock, 1);
+   for (b = 0; b < blocks; b++)
+   {
+      unsigned char buf[256],
+        ecc[256];
+      int n,
+        p = 0;
+      for (n = b; n < bytes; n += blocks)
+         buf[p++] = binary[n];
+      rs_encode (p, buf, ecc);
+      p = rsblock - 1;          // comes back reversed
+      for (n = b; n < rsblock * blocks; n += blocks)
+         binary[bytes + n] = ecc[p--];
+   }
+}
+
+// perform encoding for ecc200, source s len sl, to target t len tl, using optional encoding control string e
+// return 1 if OK, 0 if failed. Does all necessary padding to tl
+char
+ecc200encode (unsigned char *t, int tl, unsigned char *s, int sl, char *encoding, int *lenp)
+{
+   char enc = 'a';              // start in ASCII encoding mode
+   int tp = 0,
+      sp = 0;
+   if (strlen (encoding) < sl)
+   {
+      fprintf (stderr, "Encoding string too short\n");
+      return 0;
+   }
+   // do the encoding
+   while (sp < sl && tp < tl)
+   {
+      char newenc = enc;        // suggest new encoding
+      if (tl - tp <= 1 && (enc == 'c' || enc == 't') || tl - tp <= 2 && enc == 'x')
+         enc = 'a';             // auto revert to ASCII
+      newenc = tolower (encoding[sp]);
+      switch (newenc)
+      {                         // encode character
+      case 'c':                // C40
+      case 't':                // Text
+      case 'x':                // X12
+         {
+            char out[6],
+              p = 0;
+            const char *e,
+             *s2 = "!\"#$%&'()*+,-./:;<=>?@[\\]_",
+               *s3 = 0;
+            if (newenc == 'c')
+            {
+               e = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+               s3 = "`abcdefghijklmnopqrstuvwxyz{|}~\177";
+            }
+            if (newenc == 't')
+            {
+               e = " 0123456789abcdefghijklmnopqrstuvwxyz";
+               s3 = "`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~\177";
+            }
+            if (newenc == 'x')
+               e = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\r*>";
+            do
+            {
+               unsigned char c = s[sp++];
+               char *w;
+               if (c & 0x80)
+               {
+                  if (newenc == 'x')
+                  {
+                     fprintf (stderr, "Cannot encode char 0x%02X in X12\n", c);
+                     return 0;
+                  }
+                  c &= 0x7f;
+                  out[p++] = 1;
+                  out[p++] = 30;
+               }
+               w = strchr (e, c);
+               if (w)
+                  out[p++] = ((w - e) + 3) % 40;
+               else
+               {
+                  if (newenc == 'x')
+                  {
+                     fprintf (stderr, "Cannot encode char 0x%02X in X12\n", c);
+                     return 0;
+                  }
+                  if (c < 32)
+                  {             // shift 1
+                     out[p++] = 0;
+                     out[p++] = c;
+                  } else
+                  {
+                     w = strchr (s2, c);
+                     if (w)
+                     {          // shift 2
+                        out[p++] = 1;
+                        out[p++] = (w - s2);
+                     } else
+                     {
+                        w = strchr (s3, c);
+                        if (w)
+                        {
+                           out[p++] = 2;
+                           out[p++] = (w - s3);
+                        } else
+                        {
+                           fprintf (stderr, "Could not encode 0x%02X, should not happen\n", c);
+                           return 0;
+                        }
+                     }
+                  }
+               }
+               if (p == 2 && tp + 2 == tl && sp == sl)
+                  out[p++] = 0; // shift 1 pad at end
+               while (p >= 3)
+               {
+                  int v = out[0] * 1600 + out[1] * 40 + out[2] + 1;
+                  if (enc != newenc)
+                  {
+                     if (enc == 'c' || enc == 't' || enc == 'x')
+                        t[tp++] = 254;  // escape C40/text/X12
+                     else if (enc == 'x')
+                        t[tp++] = 0x7C; // escape EDIFACT
+                     if (newenc == 'c')
+                        t[tp++] = 230;
+                     if (newenc == 't')
+                        t[tp++] = 239;
+                     if (newenc == 'x')
+                        t[tp++] = 238;
+                     enc = newenc;
+                  }
+                  t[tp++] = (v >> 8);
+                  t[tp++] = (v & 0xFF);
+                  p -= 3;
+                  out[0] = out[3];
+                  out[1] = out[4];
+                  out[2] = out[5];
+               }
+            }
+            while (p && sp < sl);
+         }
+         break;
+      case 'e':                // EDIFACT
+         {
+            unsigned char out[4],
+              p = 0;
+            if (enc != newenc)
+            {                   // can only be from C40/Text/X12
+               t[tp++] = 254;
+               enc = 'a';
+            }
+            while (sp < sl && tolower (encoding[sp]) == 'e' && p < 4)
+               out[p++] = s[sp++];
+            if (p < 4)
+            {
+               out[p++] = 0x1F;
+               enc = 'a';
+            }                   // termination
+            t[tp] = ((s[0] & 0x3F) << 2);
+            t[tp++] |= ((s[1] & 0x30) >> 4);
+            t[tp] = ((s[1] & 0x0F) << 4);
+            if (p == 2)
+               tp++;
+            else
+            {
+               t[tp++] |= ((s[2] & 0x3C) >> 2);
+               t[tp] = ((s[2] & 0x03) << 6);
+               t[tp++] |= (s[3] & 0x3F);
+            }
+         }
+         break;
+      case 'a':                // ASCII
+         if (enc != newenc)
+         {
+            if (enc == 'c' || enc == 't' || enc == 'x')
+               t[tp++] = 254;   // escape C40/text/X12
+            else
+               t[tp++] = 0x7C;  // escape EDIFACT
+         }
+         enc = 'a';
+         if (sl - sp >= 2 && isdigit (s[sp]) && isdigit (s[sp + 1]))
+         {
+            t[tp++] = (s[sp] - '0') * 10 + s[sp + 1] - '0' + 130;
+            sp += 2;
+         } else if (s[sp] > 127)
+         {
+            t[tp++] = 235;
+            t[tp++] = s[sp++] - 127;
+         } else
+            t[tp++] = s[sp++] + 1;
+         break;
+      case 'b':                // Binary
+         {
+            int l = 0;          // how much to encode
+            if (encoding)
+            {
+               int p;
+               for (p = sp; p < sl && tolower (encoding[p]) == 'b'; p++)
+                  l++;
+            }
+            t[tp++] = 231;      // base256
+            if (l < 250)
+               t[tp++] = l;
+            else
+            {
+               t[tp++] = 249 + (l / 250);
+               t[tp++] = (l % 250);
+            }
+            while (l-- && tp < tl)
+            {
+               t[tp] = s[sp++] + (((tp + 1) * 149) % 255) + 1;  // see annex H
+               tp++;
+            }
+            enc = 'a';          // reverse to ASCII at end
+         }
+         break;
+      default:
+         fprintf (stderr, "Unknown encoding %c\n", newenc);
+         return 0;              // failed
+      }
+   }
+   if (lenp)
+      *lenp = tp;
+   if (tp < tl && enc != 'a')
+   {
+      if (enc == 'c' || enc == 'x' || enc == 't')
+         t[tp++] = 254;         // escape X12/C40/Text
+      else
+         t[tp++] = 0x7C;        // escape EDIFACT
+   }
+   if (tp < tl)
+      t[tp++] = 129;            // pad
+   while (tp < tl)
+   {                            // more padding
+      int v = 129 + (((tp + 1) * 149) % 253) + 1;       // see Annex H
+      if (v > 254)
+         v -= 254;
+      t[tp++] = v;
+   }
+   if (tp > tl || sp < sl)
+      return 0;                 // did not fit
+   //for (tp = 0; tp < tl; tp++) fprintf (stderr, "%02X ", t[tp]); fprintf (stderr, "\n");
+   return 1;                    // OK 
+}
+
+// Auto encoding format functions
+static char encchr[] = "ACTXEB";
+
+enum
+{
+   E_ASCII,
+   E_C40,
+   E_TEXT,
+   E_X12,
+   E_EDIFACT,
+   E_BINARY,
+   E_MAX
+};
+
+unsigned char switchcost[E_MAX][E_MAX] = {
+   0, 1, 1, 1, 1, 2,            // From E_ASCII
+   1, 0, 2, 2, 2, 3,            // From E_C40
+   1, 2, 0, 2, 2, 3,            // From E_TEXT
+   1, 2, 2, 0, 2, 3,            // From E_X12
+   1, 2, 2, 2, 0, 3,            // From E_EDIFACT
+   0, 1, 1, 1, 1, 0,            // From E_BINARY
+};
+
+// Creates a encoding list (malloc)
+// returns encoding string
+// if lenp not null, target len stored
+// if error, null returned
+// if exact specified, then assumes shortcuts applicable for exact fit in target
+// 1. No unlatch to return to ASCII for last encoded byte after C40 or Text or X12
+// 2. No unlatch to return to ASCII for last 1 or 2 encoded bytes after EDIFACT
+// 3. Final C40 or text encoding exactly in last 2 bytes can have a shift 0 to pad to make a tripple
+// Only use the encoding from an exact request if the len matches the target, otherwise free the result and try again with exact=0
+static char *
+encmake (int l, unsigned char *s, int *lenp, char exact)
+{
+   char *encoding = 0;
+   int p = l;
+   char e;
+   struct
+   {
+      short s;                  // number of bytes of source that can be encoded in a row at this point using this encoding mode
+      short t;                  // number of bytes of target generated encoding from this point to end if already in this encoding mode
+   } enc[MAXBARCODE][E_MAX];
+   memset (&enc, 0, sizeof (enc));
+   if (!l)
+      return "";                // no length
+   if (l > MAXBARCODE)
+      return 0;                 // not valid
+   while (p--)
+   {
+      char b = 0,
+         sub;
+      int sl,
+        tl,
+        bl,
+        t;
+      // consider each encoding from this point
+      // ASCII
+      sl = tl = 1;
+      if (isdigit (s[p]) && p + 1 < l && isdigit (s[p + 1]))
+         sl = 2;                // double digit
+      else if (s[p] & 0x80)
+         tl = 2;                // high shifted
+      bl = 0;
+      if (p + sl < l)
+         for (e = 0; e < E_MAX; e++)
+            if (enc[p + sl][e].t && ((t = enc[p + sl][e].t + switchcost[E_ASCII][e]) < bl || !bl))
+            {
+               bl = t;
+               b = e;
+            }
+      enc[p][E_ASCII].t = tl + bl;
+      enc[p][E_ASCII].s = sl;
+      if (bl && b == E_ASCII)
+         enc[p][b].s += enc[p + sl][b].s;
+      // C40
+      sub = tl = sl = 0;
+      do
+      {
+         unsigned char c = s[p + sl++];
+         if (c & 0x80)
+         {                      // shift + upper
+            sub += 2;
+            c &= 0x7F;
+         }
+         if (c != ' ' && !isdigit (c) && !isupper (c))
+            sub++;              // shift
+         sub++;
+         while (sub >= 3)
+         {
+            sub -= 3;
+            tl += 2;
+         }
+      } while (sub && p + sl < l);
+      if (exact && sub == 2 && p + sl == l)
+      {                         // special case, can encode last block with shift 0 at end (Is this valid when not end of target buffer?)
+         sub = 0;
+         tl += 2;
+      }
+      if (!sub)
+      {                         // can encode C40
+         bl = 0;
+         if (p + sl < l)
+            for (e = 0; e < E_MAX; e++)
+               if (enc[p + sl][e].t && ((t = enc[p + sl][e].t + switchcost[E_C40][e]) < bl || !bl))
+               {
+                  bl = t;
+                  b = e;
+               }
+         if (exact && enc[p + sl][E_ASCII].t == 1 && 1 < bl)
+         {                      // special case, switch to ASCII for last bytes
+            bl = 1;
+            b = E_ASCII;
+         }
+         enc[p][E_C40].t = tl + bl;
+         enc[p][E_C40].s = sl;
+         if (bl && b == E_C40)
+            enc[p][b].s += enc[p + sl][b].s;
+      }
+      // Text
+      sub = tl = sl = 0;
+      do
+      {
+         unsigned char c = s[p + sl++];
+         if (c & 0x80)
+         {                      // shift + upper
+            sub += 2;
+            c &= 0x7F;
+         }
+         if (c != ' ' && !isdigit (c) && !islower (c))
+            sub++;              // shift
+         sub++;
+         while (sub >= 3)
+         {
+            sub -= 3;
+            tl += 2;
+         }
+      } while (sub && p + sl < l);
+      if (exact && sub == 2 && p + sl == l)
+      {                         // special case, can encode last block with shift 0 at end (Is this valid when not end of target buffer?)
+         sub = 0;
+         tl += 2;
+      }
+      if (!sub && sl)
+      {                         // can encode Text
+         bl = 0;
+         if (p + sl < l)
+            for (e = 0; e < E_MAX; e++)
+               if (enc[p + sl][e].t && ((t = enc[p + sl][e].t + switchcost[E_TEXT][e]) < bl || !bl))
+               {
+                  bl = t;
+                  b = e;
+               }
+         if (exact && enc[p + sl][E_ASCII].t == 1 && 1 < bl)
+         {                      // special case, switch to ASCII for last bytes
+            bl = 1;
+            b = E_ASCII;
+         }
+         enc[p][E_TEXT].t = tl + bl;
+         enc[p][E_TEXT].s = sl;
+         if (bl && b == E_TEXT)
+            enc[p][b].s += enc[p + sl][b].s;
+      }
+      // X12
+      sub = tl = sl = 0;
+      do
+      {
+         unsigned char c = s[p + sl++];
+         if (c != 13 && c != '*' && c != '>' && c != ' ' && !isdigit (c) && !isupper (c))
+         {
+            sl = 0;
+            break;
+         }
+         sub++;
+         while (sub >= 3)
+         {
+            sub -= 3;
+            tl += 2;
+         }
+      } while (sub && p + sl < l);
+      if (!sub && sl)
+      {                         // can encode X12
+         bl = 0;
+         if (p + sl < l)
+            for (e = 0; e < E_MAX; e++)
+               if (enc[p + sl][e].t && ((t = enc[p + sl][e].t + switchcost[E_X12][e]) < bl || !bl))
+               {
+                  bl = t;
+                  b = e;
+               }
+         if (exact && enc[p + sl][E_ASCII].t == 1 && 1 < bl)
+         {                      // special case, switch to ASCII for last bytes
+            bl = 1;
+            b = E_ASCII;
+         }
+         enc[p][E_X12].t = tl + bl;
+         enc[p][E_X12].s = sl;
+         if (bl && b == E_X12)
+            enc[p][b].s += enc[p + sl][b].s;
+      }
+      // EDIFACT
+      sl = bl = 0;
+      if (s[p + 0] >= 32 && s[p + 0] <= 94)
+      {                         // can encode 1
+         char bs = 0;
+         if (p + 1 == l && (!bl || bl < 2))
+         {
+            bl = 2;
+            bs = 1;
+         } else
+            for (e = 0; e < E_MAX; e++)
+               if (e != E_EDIFACT && enc[p + 1][e].t && ((t = 2 + enc[p + 1][e].t + switchcost[E_ASCII][e]) < bl || !bl))       // E_ASCII as allowed for unlatch
+               {
+                  bs = 1;
+                  bl = t;
+                  b = e;
+               }
+         if (p + 1 < l && s[p + 1] >= 32 && s[p + 1] <= 94)
+         {                      // can encode 2
+            if (p + 2 == l && (!bl || bl < 2))
+            {
+               bl = 3;
+               bs = 2;
+            } else
+               for (e = 0; e < E_MAX; e++)
+                  if (e != E_EDIFACT && enc[p + 2][e].t && ((t = 3 + enc[p + 2][e].t + switchcost[E_ASCII][e]) < bl || !bl))    // E_ASCII as allowed for unlatch
+                  {
+                     bs = 2;
+                     bl = t;
+                     b = e;
+                  }
+            if (p + 2 < l && s[p + 2] >= 32 && s[p + 2] <= 94)
+            {                   // can encode 3
+               if (p + 3 == l && (!bl || bl < 3))
+               {
+                  bl = 3;
+                  bs = 3;
+               } else
+                  for (e = 0; e < E_MAX; e++)
+                     if (e != E_EDIFACT && enc[p + 3][e].t && ((t = 3 + enc[p + 3][e].t + switchcost[E_ASCII][e]) < bl || !bl)) // E_ASCII as allowed for unlatch
+                     {
+                        bs = 3;
+                        bl = t;
+                        b = e;
+                     }
+               if (p + 4 < l && s[p + 3] >= 32 && s[p + 3] <= 94)
+               {                // can encode 4
+                  if (p + 4 == l && (!bl || bl < 3))
+                  {
+                     bl = 3;
+                     bs = 4;
+                  } else
+                  {
+                     for (e = 0; e < E_MAX; e++)
+                        if (enc[p + 4][e].t && ((t = 3 + enc[p + 4][e].t + switchcost[E_EDIFACT][e]) < bl || !bl))
+                        {
+                           bs = 4;
+                           bl = t;
+                           b = e;
+                        }
+                     if (exact && enc[p + 4][E_ASCII].t && enc[p + 4][E_ASCII].t <= 2 && (t = 3 + enc[p + 4][E_ASCII].t) < bl)
+                     {          // special case, switch to ASCII for last 1 ot two bytes
+                        bs = 4;
+                        bl = t;
+                        b = E_ASCII;
+                     }
+                  }
+               }
+            }
+         }
+         enc[p][E_EDIFACT].t = bl;
+         enc[p][E_EDIFACT].s = bs;
+         if (bl && b == E_EDIFACT)
+            enc[p][b].s += enc[p + bs][b].s;
+      }
+      // Binary
+      bl = 0;
+      for (e = 0; e < E_MAX; e++)
+         if (enc[p + 1][e].t
+             && ((t = enc[p + 1][e].t + switchcost[E_BINARY][e] + ((e == E_BINARY && enc[p + 1][e].t == 249) ? 1 : 0)) < bl || !bl))
+         {
+            bl = t;
+            b = e;
+         }
+      enc[p][E_BINARY].t = 1 + bl;
+      enc[p][E_BINARY].s = 1;
+      if (bl && b == E_BINARY)
+         enc[p][b].s += enc[p + 1][b].s;
+      //fprintf (stderr, "%d:", p); for (e = 0; e < E_MAX; e++) fprintf (stderr, " %c*%d/%d", encchr[e], enc[p][e].s, enc[p][e].t); fprintf (stderr, "\n");
+   }
+   encoding = safemalloc (l + 1);
+   p = 0;
+   {
+      char cur = E_ASCII;       // starts ASCII
+      while (p < l)
+      {
+         int t,
+           m = 0;
+         char b = 0;
+         for (e = 0; e < E_MAX; e++)
+            if (enc[p][e].t && ((t = enc[p][e].t + switchcost[cur][e]) < m || t == m && e == cur || !m))
+            {
+               b = e;
+               m = t;
+            }
+         cur = b;
+         m = enc[p][b].s;
+         if (!p && lenp)
+            *lenp = enc[p][b].t;
+         while (p < l && m--)
+            encoding[p++] = encchr[b];
+      }
+   }
+   encoding[p] = 0;
+   return encoding;
+}
+
+// Main encoding function
+// Returns the grid (malloced) containing the matrix. L corner at 0,0.
+// Takes suggested size in *Wptr, *Hptr, or 0,0. Fills in actual size.
+// Takes barcodelen and barcode to be encoded
+// Note, if *encodingptr is null, then fills with auto picked (malloced) encoding
+// If lenp not null, then the length of encoded data before any final unlatch or pad is stored
+// If maxp not null, then the max storage of this size code is stored
+// If eccp not null, then the number of ecc bytes used in this size is stored
+// Returns 0 on error (writes to stderr with details).
+unsigned char *
+iec16022ecc200 (int *Wptr, int *Hptr, char **encodingptr, int barcodelen, unsigned char *barcode, int *lenp, int *maxp, int *eccp)
+{
+   unsigned char binary[3000];  // encoded raw data and ecc to place in barcode
+   int W = 0,
+      H = 0;
+   char *encoding = 0;
+   unsigned char *grid = 0;
+   struct ecc200matrix_s *matrix;
+   memset (binary, 0, sizeof (binary));
+   if (encodingptr)
+      encoding = *encodingptr;
+   if (Wptr)
+      W = *Wptr;
+   if (Hptr)
+      H = *Hptr;
+
+   // encoding
+   if (W)
+   {                            // known size
+      for (matrix = ecc200matrix; matrix->W && (matrix->W != W || matrix->H != H); matrix++);
+      if (!matrix->W)
+      {
+         fprintf (stderr, "Invalid size %dx%d\n", W, H);
+         return 0;
+      }
+      if (!encoding)
+      {
+         int len;
+         char *e = encmake (barcodelen, barcode, &len, 1);
+         if (e && len != matrix->bytes)
+         {                      // try not an exact fit
+            free (e);
+            e = encmake (barcodelen, barcode, &len, 0);
+            if (len > matrix->bytes)
+            {
+               fprintf (stderr, "Cannot make barcode fit %dx%d\n", W, H);
+               return 0;
+            }
+         }
+         encoding = e;
+      }
+   } else
+   {                            // find size
+      if (encoding)
+      {                         // find one that fits chosen encoding
+         for (matrix = ecc200matrix; matrix->W; matrix++)
+            if (ecc200encode (binary, matrix->bytes, barcode, barcodelen, encoding, 0))
+               break;
+      } else
+      {
+         int len;
+         char *e;
+         e = encmake (barcodelen, barcode, &len, 1);
+         for (matrix = ecc200matrix; matrix->W && matrix->bytes != len; matrix++);
+         if (e && !matrix->W)
+         {                      // try for non exact fit
+            free (e);
+            e = encmake (barcodelen, barcode, &len, 0);
+            for (matrix = ecc200matrix; matrix->W && matrix->bytes < len; matrix++);
+         }
+         encoding = e;
+      }
+      if (!matrix->W)
+      {
+         fprintf (stderr, "Cannot find suitable size, barcode too long\n");
+         return 0;
+      }
+      W = matrix->W;
+      H = matrix->H;
+   }
+   if (!ecc200encode (binary, matrix->bytes, barcode, barcodelen, encoding, lenp))
+   {
+      fprintf (stderr, "Barcode too long for %dx%d\n", W, H);
+      return 0;
+   }
+   // ecc code
+   ecc200 (binary, matrix->bytes, matrix->datablock, matrix->rsblock);
+   {                            // placement
+      int x,
+        y,
+        NC,
+        NR,
+       *places;
+      NC = W - 2 * (W / matrix->FW);
+      NR = H - 2 * (H / matrix->FH);
+      places = safemalloc (NC * NR * sizeof (int));
+      ecc200placement (places, NR, NC);
+      grid = safemalloc (W * H);
+      memset (grid, 0, W * H);
+      for (y = 0; y < H; y += matrix->FH)
+      {
+         for (x = 0; x < W; x++)
+            grid[y * W + x] = 1;
+         for (x = 0; x < W; x += 2)
+            grid[(y + matrix->FH - 1) * W + x] = 1;
+      }
+      for (x = 0; x < W; x += matrix->FW)
+      {
+         for (y = 0; y < H; y++)
+            grid[y * W + x] = 1;
+         for (y = 0; y < H; y += 2)
+            grid[y * W + x + matrix->FW - 1] = 1;
+      }
+      for (y = 0; y < NR; y++)
+      {
+         for (x = 0; x < NC; x++)
+         {
+            int v = places[(NR - y - 1) * NC + x];
+            //fprintf (stderr, "%4d", v);
+            if (v == 1 || v > 7 && (binary[(v >> 3) - 1] & (1 << (v & 7))))
+               grid[(1 + y + 2 * (y / (matrix->FH - 2))) * W + 1 + x + 2 * (x / (matrix->FW - 2))] = 1;
+         }
+         //fprintf (stderr, "\n");
+      }
+      free (places);
+   }
+   if (Wptr)
+      *Wptr = W;
+   if (Hptr)
+      *Hptr = H;
+   if (encodingptr)
+      *encodingptr = encoding;
+   if (maxp)
+      *maxp = matrix->bytes;
+   if (eccp)
+      *eccp = (matrix->bytes + 2) / matrix->datablock * matrix->rsblock;
+   return grid;
+}
diff --git a/iec16022ecc200.h b/iec16022ecc200.h
new file mode 100644 (file)
index 0000000..265dd31
--- /dev/null
@@ -0,0 +1,44 @@
+/** 
+ *
+ * IEC16022 bar code generation
+ * Adrian Kennard, Andrews & Arnold Ltd
+ * with help from Cliff Hones on the RS coding
+ *
+ * (c) 2004 Adrian Kennard, Andrews & Arnold Ltd
+ * (c) 2006 Stefan Schmidt <stefan@datenfreihafen.org>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ *
+ * Main encoding function
+ * Returns the grid (malloced) containing the matrix. L corner at 0,0.
+ * Takes suggested size in *Wptr, *Hptr, or 0,0. Fills in actual size.
+ * Takes barcodelen and barcode to be encoded
+ * Note, if *encodingptr is null, then fills with auto picked (malloced) 
+ * encoding.
+ * If lenp not null, then the length of encoded data before any final unlatch 
+ * or pad is stored.
+ * If maxp not null, then the max storage of this size code is stored
+ * If eccp not null, then the number of ecc bytes used in this size is stored
+ * Returns 0 on error (writes to stderr with details).
+ *
+ */
+
+
+unsigned char *
+iec16022ecc200 (int *Wptr, int *Hptr, char **encodingptr, int barcodelen, \
+                                               unsigned char *barcode, int *lenp,int *maxp,int *eccp);
+#define MAXBARCODE 3116
+
diff --git a/image.c b/image.c
new file mode 100644 (file)
index 0000000..46a828d
--- /dev/null
+++ b/image.c
@@ -0,0 +1,726 @@
+/** 
+ *
+ * Image handling tools, (c) AJK 2001-2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ */ 
+
+
+#include <stdio.h>
+#include <malloc.h>
+#include <string.h>
+#include <ctype.h>
+#include "image.h"
+
+#define        INTERLACE
+#define CLEAR
+#define USEZLIB
+
+#ifdef USEZLIB
+#include <zlib.h>
+#endif
+
+unsigned char const bbc[] = {
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,      //  
+   0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x00,      // !
+   0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,      // "
+   0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00,      // #
+   0x0C, 0x3F, 0x68, 0x3E, 0x0B, 0x7E, 0x18, 0x00,      // $
+   0x60, 0x66, 0x0C, 0x18, 0x30, 0x66, 0x06, 0x00,      // %
+   0x38, 0x6C, 0x6C, 0x38, 0x6D, 0x66, 0x3B, 0x00,      // &
+   0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,      // '
+   0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00,      // (
+   0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00,      // )
+   0x00, 0x18, 0x7E, 0x3C, 0x7E, 0x18, 0x00, 0x00,      // *
+   0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00,      // +
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30,      // ,
+   0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00,      // -
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,      // .
+   0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00,      // /
+   0x18, 0x24, 0x66, 0x66, 0x66, 0x24, 0x18, 0x00,      // 0 (non crossed)
+   0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00,      // 1
+   0x3C, 0x66, 0x06, 0x0C, 0x18, 0x30, 0x7E, 0x00,      // 2
+   0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00,      // 3
+   0x0C, 0x1C, 0x3C, 0x6C, 0x7E, 0x0C, 0x0C, 0x00,      // 4
+   0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0x00,      // 5
+   0x1C, 0x30, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00,      // 6
+   0x7E, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,      // 7
+   0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00,      // 8
+   0x3C, 0x66, 0x66, 0x3E, 0x06, 0x0C, 0x38, 0x00,      // 9
+   0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00,      // :
+   0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x30,      // ;
+   0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00,      // <
+   0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00,      // =
+   0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00,      // >
+   0x3C, 0x66, 0x0C, 0x18, 0x18, 0x00, 0x18, 0x00,      // ?
+   0x3C, 0x66, 0x6E, 0x6A, 0x6E, 0x60, 0x3C, 0x00,      // @
+   0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00,      // A
+   0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00,      // B
+   0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00,      // C
+   0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00,      // D
+   0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00,      // E
+   0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x00,      // F
+   0x3C, 0x66, 0x60, 0x6E, 0x66, 0x66, 0x3C, 0x00,      // G
+   0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00,      // H
+   0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00,      // I
+   0x3E, 0x0C, 0x0C, 0x0C, 0x0C, 0x6C, 0x38, 0x00,      // J
+   0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00,      // K
+   0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00,      // L
+   0x63, 0x77, 0x7F, 0x6B, 0x6B, 0x63, 0x63, 0x00,      // M
+   0x66, 0x66, 0x76, 0x7E, 0x6E, 0x66, 0x66, 0x00,      // N
+   0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,      // O
+   0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x00,      // P
+   0x3C, 0x66, 0x66, 0x66, 0x6A, 0x6C, 0x36, 0x00,      // Q
+   0x7C, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x00,      // R
+   0x3C, 0x66, 0x60, 0x3C, 0x06, 0x66, 0x3C, 0x00,      // S
+   0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,      // T
+   0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,      // U
+   0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00,      // V
+   0x63, 0x63, 0x6B, 0x6B, 0x7F, 0x77, 0x63, 0x00,      // W
+   0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00,      // X
+   0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00,      // Y
+   0x7E, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x7E, 0x00,      // Z
+   0x7C, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7C, 0x00,      // [
+   0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00,      // 
+   0x3E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x3E, 0x00,      // ]
+   0x18, 0x3C, 0x66, 0x42, 0x00, 0x00, 0x00, 0x00,      // ^
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,      // _
+   0x1C, 0x36, 0x30, 0x7C, 0x30, 0x30, 0x7E, 0x00,      // `
+   0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00,      // a
+   0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x00,      // b
+   0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00,      // c
+   0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00,      // d
+   0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,      // e
+   0x1C, 0x30, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x00,      // f
+   0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x3C,      // g
+   0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00,      // h
+   0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00,      // i
+   0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x70,      // j
+   0x60, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00,      // k
+   0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00,      // l
+   0x00, 0x00, 0x36, 0x7F, 0x6B, 0x6B, 0x63, 0x00,      // m
+   0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00,      // n
+   0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,      // o
+   0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60,      // p
+   0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x07,      // q
+   0x00, 0x00, 0x6C, 0x76, 0x60, 0x60, 0x60, 0x00,      // r
+   0x00, 0x00, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x00,      // s
+   0x30, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x1C, 0x00,      // t
+   0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00,      // u
+   0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00,      // v
+   0x00, 0x00, 0x63, 0x6B, 0x6B, 0x7F, 0x36, 0x00,      // w
+   0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00,      // x
+   0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x3C,      // y
+   0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00,      // z
+   0x0C, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0C, 0x00,      // {
+   0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,      // |
+   0x30, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x30, 0x00,      // }
+   0x31, 0x6B, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00,      // ~
+   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,      //
+};
+
+const char smallc[] = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-+&()/[];%";
+unsigned char const small[] = {
+   0x00, 0x00, 0x00,            //
+   0x1F, 0x11, 0x1F,            //0
+   0x11, 0x1F, 0x10,            //1
+   0x1D, 0x15, 0x17,            //2
+   0x11, 0x15, 0x1F,            //3
+   0x07, 0x04, 0x1F,            //4
+   0x17, 0x15, 0x1D,            //5
+   0x1F, 0x15, 0x1D,            //6
+   0x01, 0x01, 0x1F,            //7
+   0x1F, 0x15, 0x1F,            //8
+   0x17, 0x15, 0x1F,            //9
+   0x1E, 0x05, 0x1E,            //A
+   0x1F, 0x15, 0x0A,            //B
+   0x0E, 0x11, 0x11,            //C
+   0x1F, 0x11, 0x0E,            //D
+   0x1F, 0x15, 0x11,            //E
+   0x1F, 0x05, 0x01,            //F
+   0x0E, 0x11, 0x19,            //G
+   0x1F, 0x04, 0x1F,            //H
+   0x11, 0x1F, 0x11,            //I
+   0x11, 0x0F, 0x01,            //J
+   0x1F, 0x04, 0x1B,            //K
+   0x1F, 0x10, 0x10,            //L
+   0x1F, 0x03, 0x1F,            //M
+   0x1F, 0x01, 0x1F,            //N
+   0x0E, 0x11, 0x0E,            //O
+   0x1F, 0x05, 0x02,            //P
+   0x0E, 0x19, 0x1E,            //Q
+   0x1F, 0x05, 0x1A,            //R
+   0x12, 0x15, 0x09,            //S
+   0x01, 0x1F, 0x01,            //T
+   0x1F, 0x10, 0x1F,            //U
+   0x0F, 0x10, 0x0F,            //V
+   0x1F, 0x18, 0x1F,            //W
+   0x1B, 0x04, 0x1B,            //X
+   0x03, 0x1C, 0x03,            //Y
+   0x19, 0x15, 0x13,            //Z
+   0x04, 0x04, 0x04,            //-
+   0x04, 0x0E, 0x04,            //+
+   0x04, 0x0E, 0x04,            //& (+)
+   0x00, 0x0E, 0x11,            //(
+   0x11, 0x0E, 0x00,            //)
+   0x08, 0x04, 0x02,            ///
+   0x00, 0x1F, 0x11,            //[
+   0x11, 0x1F, 0x00,            //]
+   0x10, 0x0A, 0x00,            //;
+   0x09, 0x04, 0x12,            //%
+};
+
+Image *
+ImageNew (int w, int h, int c)
+{                               // create a new blank image
+   Image *i;
+   if (!w || !h)
+      return 0;
+   i = malloc (sizeof (*i));
+   if (!i)
+      return 0;
+   memset (i, 0, sizeof (*i));
+   i->W = w;
+   i->L = w + 1;
+   i->H = h;
+   i->C = c;
+   i->Image = malloc ((w + 1) * h);
+   if (!i->Image)
+   {
+      free (i);
+      return 0;
+   }
+   memset (i->Image, 0, (w + 1) * h);
+   if (c)
+   {
+      i->Colour = malloc (sizeof (Colour) * c);
+      if (!i->Colour)
+      {
+         free (i->Image);
+         free (i);
+         return 0;
+      }
+      memset (i->Colour, 0, sizeof (Colour) * c);
+   }
+   return i;
+}
+
+void
+ImageFree (Image * i)
+{                               // free an image
+   if (i)
+   {
+      if (i->Image)
+         free (i->Image);
+      if (i->Colour)
+         free (i->Colour);
+      free (i);
+   }
+}
+
+#define        MAXLZW  4096
+typedef short LZW[256];
+typedef LZW LZWTree[MAXLZW];
+typedef struct strPrivate
+{
+   int cols;                    // number of colours, power of 2
+   unsigned char colbits;       // number of bits for colours
+   int fh;                      // file handle
+   int lzwnext;                 // next code
+   int lzwlast;                 // last code in current bit size
+   int lzwbits;                 // current bit size
+   LZWTree lzw;                 // encode tree
+   unsigned char block[256];    // block so far, with count at start
+   int blockv;                  // pending value
+   int blockb;                  // bits used in pending value
+   short lzwcode;               // which code we are on now
+}
+Private;
+
+static
+LZWFlush (Private * p)
+{                               // flush this block
+   write (p->fh, p->block, *p->block + 1);
+   *p->block = 0;
+}
+
+static
+LZWOut (Private * p, short v)
+{                               // output a value
+   p->blockv |= (v << p->blockb);
+   p->blockb += p->lzwbits;
+   while (p->blockb >= 8)
+   {
+      p->block[++*p->block] = p->blockv;        // last partial byte
+      p->blockv >>= 8;
+      p->blockb -= 8;
+      if (*p->block == 255)
+         LZWFlush (p);
+   }
+}
+
+static
+LZWClear (Private * p)
+{
+   int c;
+   p->lzwbits = p->colbits + 1;
+   p->lzwnext = p->cols + 2;
+   p->lzwlast = (1 << p->lzwbits) - 1;
+   p->lzwcode = p->cols;        // starting point
+   for (c = 0; c < p->cols; c++)
+   {
+      p->lzw[p->cols][c] = c;   // links to literal entries
+      memset (&p->lzw[c], -1, p->cols * 2);     // links from literals, dead ends initially
+   }
+}
+
+static
+ImageStart (Private * p)
+{
+   unsigned char b = p->colbits;
+   write (p->fh, &b, 1);
+   *p->block = 0;
+   p->blockb = 0;
+   p->blockv = 0;
+   LZWClear (p);
+   LZWOut (p, p->cols);         // clear code
+}
+
+static
+ImageEnd (Private * p)
+{
+   LZWOut (p, p->lzwcode);      // last prefix
+   LZWOut (p, p->cols + 1);     // end code
+   if (p->blockb)
+      p->block[++*p->block] = p->blockv;        // last partial byte
+   LZWFlush (p);
+}
+
+static
+ImageOut (Private * p, unsigned char c)
+{
+   short next = p->lzw[p->lzwcode][c];
+   if (next == -1)
+   {                            // dead end
+      LZWOut (p, p->lzwcode);   // prefix
+#ifdef CLEAR
+      if (p->lzwnext + 1 == MAXLZW)
+      {
+         LZWOut (p, p->cols);   // clear code
+         LZWClear (p);
+      } else
+#endif
+      if (p->lzwnext < MAXLZW)
+      {
+         memset (p->lzw[p->lzwnext], -1, p->cols * 2);  // init dead ends
+         p->lzw[p->lzwcode][c] = p->lzwnext;
+         if (p->lzwnext > p->lzwlast)
+         {                      // bigger code
+            p->lzwbits++;
+            p->lzwlast = (1 << p->lzwbits) - 1;
+         }
+         p->lzwnext++;
+      }
+      p->lzwcode = c;
+   } else
+      p->lzwcode = next;        // not a dead end
+}
+
+// write GIF image
+void
+ImageWriteGif (Image * i, int fh, int back, int trans, char *comment)
+{
+   struct strPrivate p;
+   p.fh = fh;
+   for (p.colbits = 2, p.cols = 4; p.cols < i->C; p.cols *= 2, p.colbits++);    // count colours, min 4
+   {                            // headers
+      char buf[1500];
+      int n = 0;
+      strcpy (buf, "GIF87a");
+#ifndef INTERLACE
+      if (comment || trans >= 0)
+#endif
+         buf[4] = '9';          // needs gif89 format
+      n = 6;
+      buf[n++] = (i->W & 255);
+      buf[n++] = (i->W >> 8);
+      buf[n++] = (i->H & 255);
+      buf[n++] = (i->H >> 8);
+      buf[n++] = (i->Colour ? 0x80 : 0) + 0x70 + (p.colbits - 1);
+      buf[n++] = back;          // background
+      buf[n++] = 0;             // aspect
+      if (i->Colour)
+      {
+         int c;
+         for (c = 0; c < p.cols; c++)
+         {
+            if (c < i->C)
+            {
+               buf[n++] = (i->Colour[c] >> 16 & 255);
+               buf[n++] = (i->Colour[c] >> 8 & 255);
+               buf[n++] = (i->Colour[c] & 255);
+            } else
+            {                   // extra, unused, colour
+               buf[n++] = 0;
+               buf[n++] = 0;
+               buf[n++] = 0;
+            }
+         }
+      }
+      // comment
+      if (comment && strlen (comment) < 256)
+      {                         // comment
+         buf[n++] = 0x21;       //extension
+         buf[n++] = 0xFE;       //comment
+         buf[n++] = strlen (comment);
+         strcpy (buf + n, comment);
+         n += buf[n - 1];
+         buf[n++] = 0;          // end of block
+      }
+      if (trans >= 0)
+      {                         // transparrent
+         buf[n++] = 0x21;       // extension
+         buf[n++] = 0xF9;       // graphic control
+         buf[n++] = 4;          // len
+         buf[n++] = 1;          // transparrent
+         buf[n++] = 0;          // delay
+         buf[n++] = 0;
+         buf[n++] = trans;
+         buf[n++] = 0;          // terminator
+      }
+      // image
+      buf[n++] = 0x2C;
+      buf[n++] = 0;             // offset X
+      buf[n++] = 0;
+      buf[n++] = 0;             // offset Y
+      buf[n++] = 0;
+      buf[n++] = (i->W & 255);
+      buf[n++] = (i->W >> 8);
+      buf[n++] = (i->H & 255);
+      buf[n++] = (i->H >> 8);
+#ifdef INTERLACE
+      buf[n++] = 0x40;          // interlaced, no local colour table
+#else
+      buf[n++] = 0x00;          // non interlaced, no local colour table
+#endif
+      write (fh, buf, n);
+   }
+   // image data
+   {
+      unsigned char *b;
+      int x,
+        y;
+      ImageStart (&p);
+#ifdef INTERLACE
+      for (y = 0; y < i->H; y += 8)
+         for (b = &ImagePixel (i, 0, y), x = 0; x < i->W; x++)
+            ImageOut (&p, *b++);
+      for (y = 4; y < i->H; y += 8)
+         for (b = &ImagePixel (i, 0, y), x = 0; x < i->W; x++)
+            ImageOut (&p, *b++);
+      for (y = 2; y < i->H; y += 4)
+         for (b = &ImagePixel (i, 0, y), x = 0; x < i->W; x++)
+            ImageOut (&p, *b++);
+      for (y = 1; y < i->H; y += 2)
+         for (b = &ImagePixel (i, 0, y), x = 0; x < i->W; x++)
+            ImageOut (&p, *b++);
+#else
+      for (y = 0; y < i->H; y++)
+         for (b = &ImagePixel (i, 0, y), x = 0; x < i->W; x++)
+            ImageOut (&p, *b++);
+#endif
+      ImageEnd (&p);
+   }
+   write (fh, "\0", 1);         // end of image data
+   write (fh, "\x3B", 1);       // trailer
+}
+
+void
+ImageText (Image * i, int x, int y, int col, char *text)
+{                               // writes 8x8 text
+   if (i && text)
+      while (*text)
+      {
+         if (*text >= ' ' && *text)
+         {
+            int r;
+            unsigned const char *b = bbc + (*text - ' ') * 8;
+            for (r = 0; r < 8; r++)
+            {
+               unsigned char v = *b++;
+               unsigned char *p = &ImagePixel (i, x, y + r);
+               unsigned char m;
+               for (m = 0x80; m; m >>= 1, p++)
+                  if (v & m)
+                     *p = col;
+            }
+         }
+         x += 8;
+         text++;
+      }
+}
+
+void
+ImageSmall (Image * i, int x, int y, int col, char *text)
+{                               // writes 4x6 digits
+   if (i && text)
+      while (*text)
+      {
+         char *p = strchr (smallc, toupper (*text));
+         if (p)
+         {
+            int r;
+            char m = 1;
+            unsigned const char *b = small + (p - smallc) * 3;
+            for (r = 0; r < 5; r++)
+            {
+               int c;
+               for (c = 0; c < 3; c++)
+                  if (b[c] & m)
+                     ImagePixel (i, x + c, y + r) = col;
+               m <<= 1;
+            }
+            x += 4;
+         } else if (*text == '.')
+         {
+            ImagePixel (i, x, y + 4) = col;
+            x += 2;
+         } else if (*text == ':')
+         {
+            ImagePixel (i, x, y + 1) = col;
+            ImagePixel (i, x, y + 3) = col;
+            x += 2;
+         }
+         text++;
+      }
+}
+
+void
+ImageRect (Image * i, int x, int y, int w, int h, int c)
+{                               // fill a box
+   if (i && w && h)
+   {
+      while (h--)
+      {
+         unsigned char *p = &ImagePixel (i, x, y);
+         int n = w;
+         while (n--)
+            *p++ = c;
+         y++;
+      }
+   }
+}
+
+// PNG code
+
+      /* Table of CRCs of all 8-bit messages. */
+static unsigned int crc_table[256];
+
+      /* Make the table for a fast CRC. */
+void
+make_crc_table (void)
+{
+   unsigned int c;
+   int n,
+     k;
+   for (n = 0; n < 256; n++)
+   {
+      c = (unsigned int) n;
+      for (k = 0; k < 8; k++)
+      {
+         if (c & 1)
+            c = 0xedb88320L ^ (c >> 1);
+         else
+            c = c >> 1;
+      }
+      crc_table[n] = c;
+   }
+}
+
+      /* Update a running CRC with the bytes buf[0..len-1]--the CRC
+         should be initialized to all 1's, and the transmitted value
+         is the 1's complement of the final running CRC (see the
+         crc() routine below)). */
+
+unsigned int
+update_crc (unsigned int crc, unsigned char *buf, int len)
+{
+   unsigned int c = crc;
+   int n;
+
+   for (n = 0; n < len; n++)
+      c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
+
+   return c;
+}
+
+      /* Return the CRC of the bytes buf[0..len-1]. */
+unsigned int
+crc (unsigned char *buf, int len)
+{
+   return update_crc (0xffffffffL, buf, len) ^ 0xffffffffL;
+}
+
+unsigned int
+writecrc (int fh, char *ptr, int len, unsigned int c)
+{
+   write (fh, ptr, len);
+   while (len--)
+      c = crc_table[(c ^ *ptr++) & 0xff] ^ (c >> 8);
+   return c;
+}
+
+void
+writechunk (int fh, char *typ, void *ptr, int len)
+{
+   unsigned int v = htonl (len),
+      crc;
+   write (fh, &v, 4);
+   crc = writecrc (fh, typ, 4, ~0);
+   if (len)
+      crc = writecrc (fh, ptr, len, crc);
+   v = htonl (~crc);
+   write (fh, &v, 4);
+}
+
+#ifndef USEZLIB
+unsigned int
+adlersum (unsigned char *p, int l, unsigned int adler)
+{
+   unsigned int s1 = (adler & 65535),
+      s2 = (adler >> 16);
+   while (l--)
+   {
+      s1 += *p++;
+      s2 += s1;
+   }
+   s1 %= 65521;                 // can be delayed due to sensible "l" values...
+   s2 %= 65521;
+   return (s2 << 16) + s1;
+}
+#endif
+
+// write PNG image
+void
+ImageWritePNG (Image * i, int fh, int back, int trans, char *comment)
+{
+   make_crc_table ();
+   write (fh, "\211PNG\r\n\032\n", 8);  // PNG header
+   {                            // IHDR
+      struct
+      {
+         unsigned int width;
+         unsigned int height;
+         unsigned char depth;
+         unsigned char colour;
+         unsigned char compress;
+         unsigned char filter;
+         unsigned char interlace;
+      }
+      ihdr =
+      {
+      0, 0, 8, 3, 0, 0};
+      ihdr.width = htonl (i->W);
+      ihdr.height = htonl (i->H);
+      writechunk (fh, "IHDR", &ihdr, 13);
+   }
+   {                            // PLTE
+      unsigned int v = htonl (i->C * 3),
+         crc,
+         n;
+      write (fh, &v, 4);
+      crc = writecrc (fh, "PLTE", 4, ~0);
+      for (n = 0; n < i->C; n++)
+      {
+         v = htonl (i->Colour[n] << 8);
+         crc = writecrc (fh, (void *) &v, 3, crc);
+      }
+      v = htonl (~crc);
+      write (fh, &v, 4);
+   }
+   if (back >= 0)
+   {                            // bKGD
+      unsigned char b = back;
+      writechunk (fh, "bKGD", &b, 1);
+   }
+   if (*comment)
+   {                            // tEXt
+      char c[] = "Comment";
+      unsigned int v = htonl (strlen (c) + strlen (comment) + 1),
+         crc;
+      write (fh, &v, 4);
+      crc = writecrc (fh, "tEXt", 4, ~0);
+      crc = writecrc (fh, c, strlen (c) + 1, crc);
+      crc = writecrc (fh, comment, strlen (comment), crc);
+      v = htonl (~crc);
+      write (fh, &v, 4);
+   }
+   {                            // tRNS
+      unsigned char alpha[256];
+      int n;
+      for (n = 0; n < i->C; n++)
+         alpha[n] = 255 - (i->Colour[n] >> 24); // 4th palette byte treated as 0=opaque, 255-transparrent
+      if (trans >= 0 && trans < i->C)
+         alpha[trans] = 0;      // manual set of specific transparrent colour
+      writechunk (fh, "tRNS", alpha, i->C);
+   }
+#ifndef USEZLIB
+   {                            // IDAT
+      unsigned int v = htonl (i->H * (i->L + 5) + 6),
+         crc,
+         adler = 1,
+         n;
+      unsigned char *p = i->Image;
+      write (fh, &v, 4);
+      crc = writecrc (fh, "IDAT", 4, ~0);
+      crc = writecrc (fh, "\170\001", 2, crc);  // zlib header for deflate
+      n = i->H;
+      while (n--)
+      {
+         unsigned char h[5];
+         h[0] = (n ? 0 : 1);    // last chunk in deflate, un compressed
+         h[1] = (i->L & 255);   // Len, LSB first as per deflate spec
+         h[2] = (i->L / 256);
+         h[3] = ~(i->L & 255);  // Inverse of Len
+         h[4] = ~(i->L / 256);
+         *p = 0;                // filter 0 (NONE)
+         crc = writecrc (fh, h, 5, crc);
+         crc = writecrc (fh, p, i->L, crc);
+         adler = adlersum (p, i->L, adler);
+         p += i->L;
+      }
+      v = htonl (adler);
+      crc = writecrc (fh, (void *) &v, 4, crc);
+      v = htonl (~crc);
+      write (fh, &v, 4);
+   }
+#else
+   {                            // IDAT
+      unsigned char *temp;
+      unsigned long n;
+      for (n = 0; n < i->H; n++)
+         i->Image[n * i->L] = 0;        // filter 0
+      n = i->H * i->L * 1001 / 1000 + 12;
+      temp = malloc (n);
+      if (compress2 (temp, &n, i->Image, i->L * i->H, 9) != Z_OK)
+         fprintf (stderr, "Deflate error\n");
+      else
+         writechunk (fh, "IDAT", temp, n);
+      free (temp);
+   }
+#endif
+   writechunk (fh, "IEND", 0, 0);       // IEND
+}
diff --git a/image.h b/image.h
new file mode 100644 (file)
index 0000000..b742bf4
--- /dev/null
+++ b/image.h
@@ -0,0 +1,46 @@
+/** 
+ *
+ * Image handling tools, (c) AJK 2001-2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ */ 
+
+typedef unsigned int Colour;   // RGB value
+
+// Image object
+typedef struct
+{
+   int      W,                  // width
+           L,                  // Line length in Image (W+1)
+            H;                  // height
+   unsigned char *Image;        // image array, one byte per pixel
+   int      C;                  // colours (can be non power of 2, max 256)
+   Colour  *Colour;             // colour map (must have entry for each colour)
+}
+Image;
+
+// macros and functions
+
+#define ImagePixel(i,x,y)      ((i)->Image[1+(i)->L*(y)+(x)])
+
+Image *ImageNew(int w,int h,int c);            // create a new blank image
+void ImageFree(Image* i);                      // free an image
+void ImageWriteGif(Image *i,int fh,int back,int trans,char *comment);
+void ImageWritePNG(Image *i,int fh,int back,int trans,char *comment);
+void ImageText(Image *i,int x,int y,int c,char *text); // write 8x8 text
+void ImageSmall(Image *i,int x,int y,int c,char *text);        // write 4x6 text
+void ImageRect(Image *i,int x,int y,int w,int h,int c);        // fill a box
+#define ImageWrite ImageWritePNG       // default
diff --git a/reedsol.c b/reedsol.c
new file mode 100644 (file)
index 0000000..fee1dc5
--- /dev/null
+++ b/reedsol.c
@@ -0,0 +1,187 @@
+/** 
+ *
+ * This is a simple Reed-Solomon encoder
+ * (C) Cliff Hones 2004
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ */ 
+
+
+// It is not written with high efficiency in mind, so is probably
+// not suitable for real-time encoding.  The aim was to keep it
+// simple, general and clear.
+//
+// <Some notes on the theory and implementation need to be added here>
+
+// Usage:
+// First call rs_init_gf(poly) to set up the Galois Field parameters.
+// Then  call rs_init_code(size, index) to set the encoding size
+// Then  call rs_encode(datasize, data, out) to encode the data.
+//
+// These can be called repeatedly as required - but note that
+// rs_init_code must be called following any rs_init_gf call.
+//
+// If the parameters are fixed, some of the statics below can be
+// replaced with constants in the obvious way, and additionally
+// malloc/free can be avoided by using static arrays of a suitable
+// size.
+
+#include <stdio.h>              // only needed for debug (main)
+#include <stdlib.h>             // only needed for malloc/free
+
+static int gfpoly;
+static int symsize;             // in bits
+static int logmod;              // 2**symsize - 1
+static int rlen;
+
+static int *log = NULL,
+   *alog = NULL,
+   *rspoly = NULL;
+
+// rs_init_gf(poly) initialises the parameters for the Galois Field.
+// The symbol size is determined from the highest bit set in poly
+// This implementation will support sizes up to 30 bits (though that
+// will result in very large log/antilog tables) - bit sizes of
+// 8 or 4 are typical
+//
+// The poly is the bit pattern representing the GF characteristic
+// polynomial.  e.g. for ECC200 (8-bit symbols) the polynomial is
+// a**8 + a**5 + a**3 + a**2 + 1, which translates to 0x12d.
+
+void
+rs_init_gf (int poly)
+{
+   int m,
+     b,
+     p,
+     v;
+
+   // Return storage from previous setup
+   if (log)
+   {
+      free (log);
+      free (alog);
+      free (rspoly);
+      rspoly = NULL;
+   }
+   // Find the top bit, and hence the symbol size
+   for (b = 1, m = 0; b <= poly; b <<= 1)
+      m++;
+   b >>= 1;
+   m--;
+   gfpoly = poly;
+   symsize = m;
+
+   // Calculate the log/alog tables
+   logmod = (1 << m) - 1;
+   log = (int *) malloc (sizeof (int) * (logmod + 1));
+   alog = (int *) malloc (sizeof (int) * logmod);
+
+   for (p = 1, v = 0; v < logmod; v++)
+   {
+      alog[v] = p;
+      log[p] = v;
+      p <<= 1;
+      if (p & b)
+         p ^= poly;
+   }
+}
+
+// rs_init_code(nsym, index) initialises the Reed-Solomon encoder
+// nsym is the number of symbols to be generated (to be appended
+// to the input data).  index is usually 1 - it is the index of
+// the constant in the first term (i) of the RS generator polynomial:
+// (x + 2**i)*(x + 2**(i+1))*...   [nsym terms]
+// For ECC200, index is 1.
+
+void
+rs_init_code (int nsym, int index)
+{
+   int i,
+     k;
+
+   if (rspoly)
+      free (rspoly);
+   rspoly = (int *) malloc (sizeof (int) * (nsym + 1));
+
+   rlen = nsym;
+
+   rspoly[0] = 1;
+   for (i = 1; i <= nsym; i++)
+   {
+      rspoly[i] = 1;
+      for (k = i - 1; k > 0; k--)
+      {
+         if (rspoly[k])
+            rspoly[k] = alog[(log[rspoly[k]] + index) % logmod];
+         rspoly[k] ^= rspoly[k - 1];
+      }
+      rspoly[0] = alog[(log[rspoly[0]] + index) % logmod];
+      index++;
+   }
+}
+
+// Note that the following uses byte arrays, so is only suitable for
+// symbol sizes up to 8 bits.  Just change the data type of data and res
+// to unsigned int * for larger symbols.
+
+void
+rs_encode (int len, unsigned char *data, unsigned char *res)
+{
+   int i,
+     k,
+     m;
+   for (i = 0; i < rlen; i++)
+      res[i] = 0;
+   for (i = 0; i < len; i++)
+   {
+      m = res[rlen - 1] ^ data[i];
+      for (k = rlen - 1; k > 0; k--)
+      {
+         if (m && rspoly[k])
+            res[k] = res[k - 1] ^ alog[(log[m] + log[rspoly[k]]) % logmod];
+         else
+            res[k] = res[k - 1];
+      }
+      if (m && rspoly[0])
+         res[0] = alog[(log[m] + log[rspoly[0]]) % logmod];
+      else
+         res[0] = 0;
+   }
+}
+
+#ifndef LIB
+// The following tests the routines with the ISO/IEC 16022 Annexe R data
+int
+main (void)
+{
+   register int i;
+
+   unsigned char data[9] = { 142, 164, 186 };
+   unsigned char out[5];
+
+   rs_init_gf (0x12d);
+   rs_init_code (5, 1);
+
+   rs_encode (3, data, out);
+
+   printf ("Result of Annexe R encoding:\n");
+   for (i = 4; i >= 0; i--)
+      printf ("  %d\n", out[i]);
+
+   return 0;
+}
+#endif
diff --git a/reedsol.h b/reedsol.h
new file mode 100644 (file)
index 0000000..487b18f
--- /dev/null
+++ b/reedsol.h
@@ -0,0 +1,25 @@
+/** 
+ *
+ * This is a simple Reed-Solomon encoder
+ * (C) Cliff Hones 2004
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ */ 
+
+void rs_init_gf(int poly);
+void rs_init_code(int nsym, int index);
+void rs_encode(int len, unsigned char *data, unsigned char *res);
+