]> git.sur5r.net Git - glabels/blob - libglbarcode/lgl-barcode-postnet.c
Imported Upstream version 3.0.0
[glabels] / libglbarcode / lgl-barcode-postnet.c
1 /*
2  *  lgl-barcode-postnet.c
3  *  Copyright (C) 2001-2010  Jim Evins <evins@snaught.com>.
4  *
5  *  This file is part of libglbarcode.
6  *
7  *  libglbarcode is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU Lesser General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  libglbarcode is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public License
18  *  along with libglbarcode.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 /*
22  * This module implements the POSTNET barcode specified in the USPS
23  * publication 25, Mar 2001.
24  */
25
26 #include <config.h>
27
28 #include "lgl-barcode-postnet.h"
29
30 #include <glib.h>
31 #include <ctype.h>
32
33
34 /*========================================================*/
35 /* Private macros and constants.                          */
36 /*========================================================*/
37
38 #define PTS_PER_INCH 72.0
39
40 #define POSTNET_BAR_WIDTH      ( 0.02    * PTS_PER_INCH )
41 #define POSTNET_FULLBAR_HEIGHT ( 0.125   * PTS_PER_INCH )
42 #define POSTNET_HALFBAR_HEIGHT ( 0.05    * PTS_PER_INCH )
43 #define POSTNET_BAR_PITCH      ( 0.04545 * PTS_PER_INCH )
44 #define POSTNET_HORIZ_MARGIN   ( 0.125   * PTS_PER_INCH )
45 #define POSTNET_VERT_MARGIN    ( 0.04    * PTS_PER_INCH )
46
47
48 /*===========================================*/
49 /* Private globals                           */
50 /*===========================================*/
51 static gchar *symbols[] = {
52         /* 0 */ "11000",
53         /* 1 */ "00011",
54         /* 2 */ "00101",
55         /* 3 */ "00110",
56         /* 4 */ "01001",
57         /* 5 */ "01010",
58         /* 6 */ "01100",
59         /* 7 */ "10001",
60         /* 8 */ "10010",
61         /* 9 */ "10100",
62 };
63
64 static gchar *frame_symbol = "1";
65
66
67 /*===========================================*/
68 /* Local function prototypes                 */
69 /*===========================================*/
70 static gint         postnet_validate_data (const gchar *data);
71
72 static gchar       *postnet_encode        (const gchar *digits);
73
74 static lglBarcode  *postnet_vectorize     (const gchar *code);
75
76
77
78 /****************************************************************************/
79 /* Generate new Postnet barcode structure from data.                        */
80 /****************************************************************************/
81 lglBarcode *
82 lgl_barcode_postnet_new (lglBarcodeType  type,
83                          gboolean        text_flag,
84                          gboolean        checksum_flag,
85                          gdouble         w,
86                          gdouble         h,
87                          const gchar    *data)
88 {
89         gint                n_digits;
90         gchar              *code;
91         lglBarcode         *bc;
92
93         /* Validate data and length for all subtypes. */
94         n_digits = postnet_validate_data (data);
95         switch (type)
96         {
97
98         case LGL_BARCODE_TYPE_POSTNET:
99                 if ( (n_digits !=  5) &&
100                      (n_digits !=  9) &&
101                      (n_digits != 11) )
102                 {
103                         return NULL;
104                 }
105                 break;
106
107         case LGL_BARCODE_TYPE_POSTNET_5:
108                 if ( n_digits != 5 )
109                 {
110                         return NULL;
111                 }
112                 break;
113
114         case LGL_BARCODE_TYPE_POSTNET_9:
115                 if ( n_digits != 9 )
116                 {
117                         return NULL;
118                 }
119                 break;
120
121         case LGL_BARCODE_TYPE_POSTNET_11:
122                 if ( n_digits != 11 )
123                 {
124                         return NULL;
125                 }
126                 break;
127
128         case LGL_BARCODE_TYPE_CEPNET:
129                 if ( n_digits !=  8 )
130                 {
131                         return NULL;
132                 }
133                 break;
134
135         default:
136                 g_message ("Invalid barcode type for POSTNET backend.");
137                 return NULL;
138
139         }
140
141         /* First get code string */
142         code = postnet_encode (data);
143         if (code == NULL)
144         {
145                 return NULL;
146         }
147
148         /* Now vectorize encoded data */
149         bc = postnet_vectorize (code);
150
151         g_free (code);
152
153         return bc;
154 }
155
156
157 /*--------------------------------------------------------------------------*/
158 /* PRIVATE.  Validate data, returning number of digits if valid.            */
159 /*--------------------------------------------------------------------------*/
160 static gint
161 postnet_validate_data (const gchar *data)
162 {
163         gchar *p;
164         gint   i;
165
166         if (!data)
167         {
168                 return 0;
169         }
170
171         for ( p = (gchar *)data, i=0; *p != 0; p++ )
172         {
173                 if (g_ascii_isdigit (*p))
174                 {
175                         i++;
176                 }
177                 else if ( (*p != '-') && (*p != ' ') )
178                 {
179                         /* Only allow digits, dashes, and spaces. */
180                         return 0;
181                 }
182         }
183
184         return i;
185 }
186
187
188 /*--------------------------------------------------------------------------*/
189 /* PRIVATE.  Generate string of symbols, representing barcode.              */
190 /*--------------------------------------------------------------------------*/
191 static gchar *
192 postnet_encode (const gchar *data)
193 {
194         gchar   *p;
195         gint     len;
196         gint     d, sum;
197         GString *code;
198
199         /* Left frame bar */
200         code = g_string_new (frame_symbol);
201
202         sum = 0;
203         for ( p = (gchar *)data, len = 0; (*p != 0) && (len < 11); p++ )
204         {
205                 if (g_ascii_isdigit (*p))
206                 {
207                         /* Only translate the digits (0-9) */
208                         d = (*p) - '0';
209                         sum += d;
210                         code = g_string_append (code, symbols[d]);
211                         len++;
212                 }
213         }
214
215         /* Create correction character */
216         d = (10 - (sum % 10)) % 10;
217         code = g_string_append (code, symbols[d]);
218
219         /* Right frame bar */
220         code = g_string_append (code, frame_symbol);
221
222         return g_string_free (code, FALSE);
223 }
224
225
226 /*--------------------------------------------------------------------------*/
227 /* PRIVATE.  Vectorize encoded barcode.                                     */
228 /*--------------------------------------------------------------------------*/
229 static lglBarcode *
230 postnet_vectorize (const gchar *code)
231 {
232         lglBarcode         *bc;
233         gchar              *p;
234         gdouble             x, y, length, width;
235
236         bc = lgl_barcode_new ();
237
238         /* Now traverse the code string and create a list of lines */
239         x = POSTNET_HORIZ_MARGIN;
240         for ( p = (gchar *)code; *p != 0; p++ )
241         {
242                 y = POSTNET_VERT_MARGIN;
243                 switch (*p)
244                 {
245                 case '0':
246                         y += POSTNET_FULLBAR_HEIGHT - POSTNET_HALFBAR_HEIGHT;
247                         length = POSTNET_HALFBAR_HEIGHT;
248                         break;
249                 case '1':
250                         length = POSTNET_FULLBAR_HEIGHT;
251                         break;
252                 default:
253                         break;
254                 }
255                 width = POSTNET_BAR_WIDTH;
256
257                 lgl_barcode_add_box (bc, x, y, width, length);
258
259                 x += POSTNET_BAR_PITCH;
260         }
261
262         bc->width = x + POSTNET_HORIZ_MARGIN;
263         bc->height = POSTNET_FULLBAR_HEIGHT + 2 * POSTNET_VERT_MARGIN;
264
265         return bc;
266 }
267
268
269
270 /*
271  * Local Variables:       -- emacs
272  * mode: C                -- emacs
273  * c-basic-offset: 8      -- emacs
274  * tab-width: 8           -- emacs
275  * indent-tabs-mode: nil  -- emacs
276  * End:                   -- emacs
277  */