]> git.sur5r.net Git - glabels/blob - src/bc-postnet.c
Fix drawing problems with view.c
[glabels] / src / bc-postnet.c
1 /*
2  *  bc-postnet.c
3  *  Copyright (C) 2001-2009  Jim Evins <evins@snaught.com>.
4  *
5  *  This file is part of gLabels.
6  *
7  *  gLabels is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU 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  *  gLabels 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 General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with gLabels.  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 "bc-postnet.h"
29
30 #include <glib.h>
31 #include <ctype.h>
32
33 #include "debug.h"
34
35
36 /*========================================================*/
37 /* Private macros and constants.                          */
38 /*========================================================*/
39 #define POSTNET_BAR_WIDTH      1.25
40 #define POSTNET_FULLBAR_HEIGHT 9.00
41 #define POSTNET_HALFBAR_HEIGHT 3.50
42 #define POSTNET_BAR_PITCH      3.25
43 #define POSTNET_HORIZ_MARGIN   9.00
44 #define POSTNET_VERT_MARGIN    3.00
45
46
47 /*===========================================*/
48 /* Private globals                           */
49 /*===========================================*/
50 static gchar *symbols[] = {
51         /* 0 */ "11000",
52         /* 1 */ "00011",
53         /* 2 */ "00101",
54         /* 3 */ "00110",
55         /* 4 */ "01001",
56         /* 5 */ "01010",
57         /* 6 */ "01100",
58         /* 7 */ "10001",
59         /* 8 */ "10010",
60         /* 9 */ "10100",
61 };
62
63 static gchar *frame_symbol = "1";
64
65
66 /*===========================================*/
67 /* Local function prototypes                 */
68 /*===========================================*/
69 static gchar    *postnet_code    (const gchar *digits);
70
71 static gboolean  is_length_valid (const gchar *digits,
72                                   gint         n);
73
74
75 /****************************************************************************/
76 /* Generate list of lines that form the barcode for the given digits.       */
77 /****************************************************************************/
78 glBarcode *
79 gl_barcode_postnet_new (const gchar    *id,
80                         gboolean        text_flag,
81                         gboolean        checksum_flag,
82                         gdouble         w,
83                         gdouble         h,
84                         const gchar    *digits)
85 {
86         gchar              *code, *p;
87         glBarcode          *gbc;
88         gdouble             x, y, length, width;
89
90         /* Validate code length for all subtypes. */
91         if ( (g_ascii_strcasecmp (id, "POSTNET") == 0) ) {
92                 if (!is_length_valid (digits, 5) &&
93                     !is_length_valid (digits, 9) &&
94                     !is_length_valid (digits, 11)) {
95                         return NULL;
96                 }
97         }
98         if ( (g_ascii_strcasecmp (id, "POSTNET-5") == 0) ) {
99                 if (!is_length_valid (digits, 5)) {
100                         return NULL;
101                 }
102         }
103         if ( (g_ascii_strcasecmp (id, "POSTNET-9") == 0) ) {
104                 if (!is_length_valid (digits, 9)) {
105                         return NULL;
106                 }
107         }
108         if ( (g_ascii_strcasecmp (id, "POSTNET-11") == 0) ) {
109                 if (!is_length_valid (digits, 11)) {
110                         return NULL;
111                 }
112         }
113         if ( (g_ascii_strcasecmp (id, "CEPNET") == 0) ) {
114                 if (!is_length_valid (digits, 8)) {
115                         return NULL;
116                 }
117         }
118
119         /* First get code string */
120         code = postnet_code (digits);
121         if (code == NULL) {
122                 return NULL;
123         }
124
125         gbc = gl_barcode_new ();
126
127         /* Now traverse the code string and create a list of lines */
128         x = POSTNET_HORIZ_MARGIN;
129         for (p = code; *p != 0; p++) {
130                 y = POSTNET_VERT_MARGIN;
131                 if (*p == '0') {
132                         y += POSTNET_FULLBAR_HEIGHT - POSTNET_HALFBAR_HEIGHT;
133                         length = POSTNET_HALFBAR_HEIGHT;
134                 } else {
135                         length = POSTNET_FULLBAR_HEIGHT;
136                 }
137                 width = POSTNET_BAR_WIDTH;
138
139                 gl_barcode_add_line (gbc, x, y, length, width);
140
141                 x += POSTNET_BAR_PITCH;
142         }
143
144         g_free (code);
145
146         gbc->width = x + POSTNET_HORIZ_MARGIN;
147         gbc->height = POSTNET_FULLBAR_HEIGHT + 2 * POSTNET_VERT_MARGIN;
148
149         return gbc;
150 }
151
152
153 /*--------------------------------------------------------------------------*/
154 /* PRIVATE.  Generate string of symbols, representing barcode.              */
155 /*--------------------------------------------------------------------------*/
156 static gchar *
157 postnet_code (const gchar *digits)
158 {
159         gchar   *p;
160         gint     len;
161         gint     d, sum;
162         GString *code;
163         gchar   *ret;
164
165         /* Left frame bar */
166         code = g_string_new (frame_symbol);
167
168         sum = 0;
169         for (p = (gchar *)digits, len = 0; (*p != 0) && (len < 11); p++) {
170                 if (g_ascii_isdigit (*p)) {
171                         /* Only translate valid characters (0-9) */
172                         d = (*p) - '0';
173                         sum += d;
174                         code = g_string_append (code, symbols[d]);
175                         len++;
176                 }
177         }
178
179         /* Create correction character */
180         d = (10 - (sum % 10)) % 10;
181         code = g_string_append (code, symbols[d]);
182
183         /* Right frame bar */
184         code = g_string_append (code, frame_symbol);
185
186         ret = g_strdup (code->str);
187         g_string_free (code, TRUE);
188
189         return ret;
190 }
191
192
193 /*--------------------------------------------------------------------------*/
194 /* Validate specific length of string (for subtypes).                       */
195 /*--------------------------------------------------------------------------*/
196 static gboolean
197 is_length_valid (const gchar *digits,
198                  gint         n)
199 {
200         gchar *p;
201         gint   i;
202
203         if (!digits) {
204                 return FALSE;
205         }
206
207         for (p = (gchar *)digits, i=0; *p != 0; p++) {
208                 if (g_ascii_isdigit (*p)) {
209                         i++;
210                 }
211         }
212
213         return (i == n);
214 }
215
216
217
218 /*
219  * Local Variables:       -- emacs
220  * mode: C                -- emacs
221  * c-basic-offset: 8      -- emacs
222  * tab-width: 8           -- emacs
223  * indent-tabs-mode: nil  -- emacs
224  * End:                   -- emacs
225  */