3 * Copyright (C) 2001-2010 Jim Evins <evins@snaught.com>.
5 * This file is part of libglbarcode.
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.
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.
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/>.
23 #include "lgl-barcode-code39.h"
30 /*========================================================*/
31 /* Private macros and constants. */
32 /*========================================================*/
34 #define PTS_PER_INCH 72.0
36 #define MIN_X ( 0.01 * PTS_PER_INCH )
39 #define MIN_HEIGHT ( 0.25 * PTS_PER_INCH )
40 #define MIN_QUIET ( 0.10 * PTS_PER_INCH )
42 #define INK_BLEED ( 0.00325 * PTS_PER_INCH )
44 #define TEXT_AREA_HEIGHT 14.0
45 #define TEXT_SIZE 10.0
48 /*========================================================*/
50 /*========================================================*/
58 /*===========================================*/
60 /*===========================================*/
62 static Code39Symbol symbols[] = {
100 { '-', "NwNnNnWnW" },
101 { '.', "WwNnNnWnN" },
102 { ' ', "NwWnNnWnN" },
103 { '$', "NwNwNwNnN" },
104 { '/', "NwNwNnNwN" },
105 { '+', "NwNnNwNwN" },
106 { '%', "NnNwNwNwN" },
110 static gchar *frame_symbol = "NwNnWnWnN";
112 static gchar *ascii_map[128] =
114 /* NUL */ "%U", /* SOH */ "$A", /* STX */ "$B", /* ETX */ "$C",
115 /* EOT */ "$D", /* ENQ */ "$E", /* ACK */ "$F", /* BEL */ "$G",
116 /* BS */ "$H", /* HT */ "$I", /* LF */ "$J", /* VT */ "$K",
117 /* FF */ "$L", /* CR */ "$M", /* SO */ "$N", /* SI */ "$O",
118 /* DLE */ "$P", /* DC1 */ "$Q", /* DC2 */ "$R", /* DC3 */ "$S",
119 /* DC4 */ "$T", /* NAK */ "$U", /* SYN */ "$V", /* ETB */ "$W",
120 /* CAN */ "$X", /* EM */ "$Y", /* SUB */ "$Z", /* ESC */ "%A",
121 /* FS */ "%B", /* GS */ "%C", /* RS */ "%D", /* US */ "%E",
122 /* " " */ " ", /* ! */ "/A", /* " */ "/B", /* # */ "/C",
123 /* $ */ "/D", /* % */ "/E", /* & */ "/F", /* ' */ "/G",
124 /* ( */ "/H", /* ) */ "/I", /* * */ "/J", /* + */ "/K",
125 /* , */ "/L", /* - */ "-", /* . */ ".", /* / */ "/O",
126 /* 0 */ "0", /* 1 */ "1", /* 2 */ "2", /* 3 */ "3",
127 /* 4 */ "4", /* 5 */ "5", /* 6 */ "6", /* 7 */ "7",
128 /* 8 */ "8", /* 9 */ "9", /* : */ "/Z", /* ; */ "%F",
129 /* < */ "%G", /* = */ "%H", /* > */ "%I", /* ? */ "%J",
130 /* @ */ "%V", /* A */ "A", /* B */ "B", /* C */ "C",
131 /* D */ "D", /* E */ "E", /* F */ "F", /* G */ "G",
132 /* H */ "H", /* I */ "I", /* J */ "J", /* K */ "K",
133 /* L */ "L", /* M */ "M", /* N */ "N", /* O */ "O",
134 /* P */ "P", /* Q */ "Q", /* R */ "R", /* S */ "S",
135 /* T */ "T", /* U */ "U", /* V */ "V", /* W */ "W",
136 /* X */ "X", /* Y */ "Y", /* Z */ "Z", /* [ */ "%K",
137 /* \ */ "%L", /* ] */ "%M", /* ^ */ "%N", /* _ */ "%O",
138 /* ` */ "%W", /* a */ "+A", /* b */ "+B", /* c */ "+C",
139 /* d */ "+D", /* e */ "+E", /* f */ "+F", /* g */ "+G",
140 /* h */ "+H", /* i */ "+I", /* j */ "+J", /* k */ "+K",
141 /* l */ "+L", /* m */ "+M", /* n */ "+N", /* o */ "+O",
142 /* p */ "+P", /* q */ "+Q", /* r */ "+R", /* s */ "+S",
143 /* t */ "+T", /* u */ "+U", /* v */ "+V", /* w */ "+W",
144 /* x */ "+X", /* y */ "+Y", /* z */ "+Z", /* { */ "%P",
145 /* | */ "%Q", /* } */ "%R", /* ~ */ "%S", /* DEL */ "%T"
149 /*===========================================*/
150 /* Local function prototypes */
151 /*===========================================*/
153 static gchar *code39_encode (const gchar *data,
154 gboolean checksum_flag);
156 static lglBarcode *code39_vectorize (const gchar *code,
160 gboolean checksum_flag,
162 const gchar *string);
165 /****************************************************************************/
166 /* Generate list of lines that form the barcode for the given digits. */
167 /****************************************************************************/
169 lgl_barcode_code39_new (lglBarcodeType type,
171 gboolean checksum_flag,
181 if ( (type != LGL_BARCODE_TYPE_CODE39) &&
182 (type != LGL_BARCODE_TYPE_CODE39_EXT) )
184 g_message ("Invalid barcode type for CODE39 backend.");
189 /* Canonicalize data. */
190 if ( data[0] == '\0' )
194 if (type == LGL_BARCODE_TYPE_CODE39_EXT)
196 GString *canon_data_str;
197 GString *display_data_str;
199 canon_data_str = g_string_new ("");
200 display_data_str = g_string_new ("");
201 for ( p = (gchar *)data; *p != '\0'; p++ )
203 canon_data_str = g_string_append (canon_data_str, ascii_map[(*p) & 0x7F]);
204 display_data_str = g_string_append_c (display_data_str, (*p) & 0x7F);
207 canon_data = g_string_free (canon_data_str, FALSE);
208 display_data = g_string_free (display_data_str, FALSE);
212 canon_data = g_ascii_strup (data, -1);
213 g_strcanon (canon_data, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%", ' ');
214 display_data = g_strdup (canon_data);
217 /* First get code string */
218 code = code39_encode (canon_data, checksum_flag);
221 g_free (display_data);
225 /* Now vectorize code string */
226 bc = code39_vectorize (code, w, h, text_flag, checksum_flag, canon_data, display_data);
229 g_free (display_data);
236 /*--------------------------------------------------------------------------*/
237 /* PRIVATE. Generate string of symbols, representing barcode. */
238 /*--------------------------------------------------------------------------*/
240 code39_encode (const gchar *data,
241 gboolean checksum_flag)
248 /* Left frame symbol */
249 code = g_string_new( frame_symbol );
250 code = g_string_append( code, "i" );
253 for ( p=(gchar *)data; *p != 0; p++ )
256 for ( i = 0; symbols[i].c != 0; i++ )
258 if ( c == symbols[i].c )
261 code = g_string_append (code, symbols[i].sym);
265 code = g_string_append (code, "i");
270 code = g_string_append (code, symbols[sum % 43].sym);
271 code = g_string_append (code, "i");
274 /* Right frame bar */
275 code = g_string_append (code, frame_symbol);
277 return g_string_free (code, FALSE);
281 /*--------------------------------------------------------------------------*/
282 /* Generate list of rectangles that form the barcode for the given digits. */
283 /*--------------------------------------------------------------------------*/
285 code39_vectorize (const gchar *code,
289 gboolean checksum_flag,
296 gdouble width, height;
301 gchar *string_plus_stars;
303 /* determine width and establish horizontal scale */
304 n_chars = strlen (data);
307 min_l = (n_chars + 2)*(3*N + 6)*MIN_X + (n_chars + 1)*MIN_I;
311 min_l = (n_chars + 3)*(3*N + 6)*MIN_X + (n_chars + 2)*MIN_I;
320 scale = w / (min_l + 2*MIN_QUIET);
327 width = min_l * scale;
329 /* determine height of barcode */
330 height = text_flag ? h - TEXT_AREA_HEIGHT : h;
331 height = MAX (height, MAX(0.15*width, MIN_HEIGHT));
333 /* determine horizontal quiet zone */
334 x_quiet = MAX ((10 * scale * MIN_X), MIN_QUIET);
337 bc = lgl_barcode_new ();
339 /* Now traverse the code string and create a list of rectangles */
341 for ( p = (gchar *)code; *p != 0; p++ )
348 /* Inter-character gap */
354 lgl_barcode_add_box (bc, x1, 0.0, (scale * MIN_X - INK_BLEED), height);
360 lgl_barcode_add_box (bc, x1, 0.0, (scale * N * MIN_X - INK_BLEED), height);
361 x1 += scale * N * MIN_X;
371 x1 += scale * N * MIN_X;
375 g_message( "Invalid Code39 symbol, should not happen" );
382 string_plus_stars = g_strdup_printf ("*%s*", string);
383 lgl_barcode_add_string (bc,
384 x_quiet + width/2, height + (TEXT_AREA_HEIGHT-TEXT_SIZE)/2,
385 TEXT_SIZE, string_plus_stars, strlen (string_plus_stars));
386 g_free (string_plus_stars);
389 bc->width = width + 2*x_quiet;
390 bc->height = text_flag ? height + TEXT_AREA_HEIGHT : height;
399 * Local Variables: -- emacs
401 * c-basic-offset: 8 -- emacs
402 * tab-width: 8 -- emacs
403 * indent-tabs-mode: nil -- emacs