From: Jan Luebbe Date: Wed, 18 Feb 2009 12:17:48 +0000 (+0100) Subject: Imported Upstream version 0.1 X-Git-Tag: upstream/0.1^0 X-Git-Url: https://git.sur5r.net/?p=iec16022;a=commitdiff_plain;h=41a50e0be362adbf81c6dae915aa716f76e897a2 Imported Upstream version 0.1 --- 41a50e0be362adbf81c6dae915aa716f76e897a2 diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 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 diff --git a/CREDITS b/CREDITS new file mode 100644 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 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 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. + + 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.) + +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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 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 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 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 diff --git a/TODO b/TODO new file mode 100644 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 index 0000000..e725482 --- /dev/null +++ b/iec16022.1 @@ -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 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 , +for the Debian project (but may be used by others). diff --git a/iec16022.c b/iec16022.c new file mode 100644 index 0000000..3c73935 --- /dev/null +++ b/iec16022.c @@ -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 + * + * 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 +#include +#include +#include +#include +#include +#include +#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 index 0000000..c5bc79e --- /dev/null +++ b/iec16022ecc200.c @@ -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 + * + * 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 +#include +#include +#include +#include +#include +#include +#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 index 0000000..265dd31 --- /dev/null +++ b/iec16022ecc200.h @@ -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 + * + * 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 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 +#include +#include +#include +#include "image.h" + +#define INTERLACE +#define CLEAR +#define USEZLIB + +#ifdef USEZLIB +#include +#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 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 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. +// +// + +// 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 // only needed for debug (main) +#include // 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 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); +