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 /*========================================================*/
53 /*===========================================*/
55 /*===========================================*/
57 /* Code 39 alphabet. Position indicates value. */
58 static gchar *alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%";
60 /* Code 39 symbols. Position must match position in alphabet. */
61 static gchar* symbols[43] = {
108 static gchar *frame_symbol = "NwNnWnWnN";
110 static gchar *ascii_map[128] =
112 /* NUL */ "%U", /* SOH */ "$A", /* STX */ "$B", /* ETX */ "$C",
113 /* EOT */ "$D", /* ENQ */ "$E", /* ACK */ "$F", /* BEL */ "$G",
114 /* BS */ "$H", /* HT */ "$I", /* LF */ "$J", /* VT */ "$K",
115 /* FF */ "$L", /* CR */ "$M", /* SO */ "$N", /* SI */ "$O",
116 /* DLE */ "$P", /* DC1 */ "$Q", /* DC2 */ "$R", /* DC3 */ "$S",
117 /* DC4 */ "$T", /* NAK */ "$U", /* SYN */ "$V", /* ETB */ "$W",
118 /* CAN */ "$X", /* EM */ "$Y", /* SUB */ "$Z", /* ESC */ "%A",
119 /* FS */ "%B", /* GS */ "%C", /* RS */ "%D", /* US */ "%E",
120 /* " " */ " ", /* ! */ "/A", /* " */ "/B", /* # */ "/C",
121 /* $ */ "/D", /* % */ "/E", /* & */ "/F", /* ' */ "/G",
122 /* ( */ "/H", /* ) */ "/I", /* * */ "/J", /* + */ "/K",
123 /* , */ "/L", /* - */ "-", /* . */ ".", /* / */ "/O",
124 /* 0 */ "0", /* 1 */ "1", /* 2 */ "2", /* 3 */ "3",
125 /* 4 */ "4", /* 5 */ "5", /* 6 */ "6", /* 7 */ "7",
126 /* 8 */ "8", /* 9 */ "9", /* : */ "/Z", /* ; */ "%F",
127 /* < */ "%G", /* = */ "%H", /* > */ "%I", /* ? */ "%J",
128 /* @ */ "%V", /* A */ "A", /* B */ "B", /* C */ "C",
129 /* D */ "D", /* E */ "E", /* F */ "F", /* G */ "G",
130 /* H */ "H", /* I */ "I", /* J */ "J", /* K */ "K",
131 /* L */ "L", /* M */ "M", /* N */ "N", /* O */ "O",
132 /* P */ "P", /* Q */ "Q", /* R */ "R", /* S */ "S",
133 /* T */ "T", /* U */ "U", /* V */ "V", /* W */ "W",
134 /* X */ "X", /* Y */ "Y", /* Z */ "Z", /* [ */ "%K",
135 /* \ */ "%L", /* ] */ "%M", /* ^ */ "%N", /* _ */ "%O",
136 /* ` */ "%W", /* a */ "+A", /* b */ "+B", /* c */ "+C",
137 /* d */ "+D", /* e */ "+E", /* f */ "+F", /* g */ "+G",
138 /* h */ "+H", /* i */ "+I", /* j */ "+J", /* k */ "+K",
139 /* l */ "+L", /* m */ "+M", /* n */ "+N", /* o */ "+O",
140 /* p */ "+P", /* q */ "+Q", /* r */ "+R", /* s */ "+S",
141 /* t */ "+T", /* u */ "+U", /* v */ "+V", /* w */ "+W",
142 /* x */ "+X", /* y */ "+Y", /* z */ "+Z", /* { */ "%P",
143 /* | */ "%Q", /* } */ "%R", /* ~ */ "%S", /* DEL */ "%T"
147 /*===========================================*/
148 /* Local function prototypes */
149 /*===========================================*/
151 static gboolean code39_is_data_valid (const gchar *data);
152 static gboolean code39_ext_is_data_valid (const gchar *data);
154 static gchar *code39_encode (const gchar *data,
155 gboolean checksum_flag);
157 static lglBarcode *code39_vectorize (const gchar *code,
161 gboolean checksum_flag,
163 const gchar *string);
166 /****************************************************************************/
167 /* Generate new Code 39 barcode structure from data. */
168 /****************************************************************************/
170 lgl_barcode_code39_new (lglBarcodeType type,
172 gboolean checksum_flag,
182 if ( (type != LGL_BARCODE_TYPE_CODE39) &&
183 (type != LGL_BARCODE_TYPE_CODE39_EXT) )
185 g_message ("Invalid barcode type for CODE39 backend.");
191 if (type == LGL_BARCODE_TYPE_CODE39)
193 if ( !code39_is_data_valid (data) )
197 canon_data = g_ascii_strup (data, -1);
198 display_data = g_strdup (canon_data);
202 GString *canon_data_str;
204 if ( !code39_ext_is_data_valid (data) )
209 canon_data_str = g_string_new ("");
210 for ( p = (gchar *)data; *p != '\0'; p++ )
212 canon_data_str = g_string_append (canon_data_str, ascii_map[(int)*p]);
214 canon_data = g_string_free (canon_data_str, FALSE);
216 display_data = g_strdup (data);
219 /* First get code string */
220 code = code39_encode (canon_data, checksum_flag);
224 g_free (display_data);
228 /* Now vectorize code string */
229 bc = code39_vectorize (code, w, h, text_flag, checksum_flag, canon_data, display_data);
232 g_free (display_data);
239 /*--------------------------------------------------------------------------*/
240 /* PRIVATE. Validate data for Code 39. */
241 /*--------------------------------------------------------------------------*/
243 code39_is_data_valid (const gchar *data)
248 if (!data || (*data == '\0'))
253 for ( p = (gchar *)data; *p != 0; p++ )
255 c = g_ascii_toupper (*p);
257 if ( strchr(alphabet, c) == NULL )
267 /*--------------------------------------------------------------------------*/
268 /* PRIVATE. Validate data for Extended Code 39. */
269 /*--------------------------------------------------------------------------*/
271 code39_ext_is_data_valid (const gchar *data)
275 if (!data || (*data == '\0'))
280 for ( p = (gchar *)data; *p != 0; p++ )
282 if ( (*p < 0) || (*p > 0x7f) )
292 /*--------------------------------------------------------------------------*/
293 /* PRIVATE. Generate string of symbols, representing barcode. */
294 /*--------------------------------------------------------------------------*/
296 code39_encode (const gchar *data,
297 gboolean checksum_flag)
304 /* Left frame symbol */
305 code = g_string_new( frame_symbol );
306 code = g_string_append( code, "i" );
309 for ( p=(gchar *)data; *p != 0; p++ )
311 c = g_ascii_toupper( *p );
312 c_value = strchr(alphabet, c) - alphabet;
313 code = g_string_append (code, symbols[c_value]);
314 code = g_string_append (code, "i");
321 code = g_string_append (code, symbols[sum % 43]);
322 code = g_string_append (code, "i");
325 /* Right frame bar */
326 code = g_string_append (code, frame_symbol);
328 return g_string_free (code, FALSE);
332 /*--------------------------------------------------------------------------*/
333 /* PRIVATE. Vectorize encoded barcode. */
334 /*--------------------------------------------------------------------------*/
336 code39_vectorize (const gchar *code,
340 gboolean checksum_flag,
347 gdouble width, height;
352 gchar *string_plus_stars;
354 /* determine width and establish horizontal scale */
355 n_chars = strlen (data);
358 min_l = (n_chars + 2)*(3*N + 6)*MIN_X + (n_chars + 1)*MIN_I;
362 min_l = (n_chars + 3)*(3*N + 6)*MIN_X + (n_chars + 2)*MIN_I;
371 scale = w / (min_l + 2*MIN_QUIET);
378 width = min_l * scale;
380 /* determine height of barcode */
381 height = text_flag ? h - TEXT_AREA_HEIGHT : h;
382 height = MAX (height, MAX(0.15*width, MIN_HEIGHT));
384 /* determine horizontal quiet zone */
385 x_quiet = MAX ((10 * scale * MIN_X), MIN_QUIET);
388 bc = lgl_barcode_new ();
390 /* Now traverse the code string and create a list of rectangles */
392 for ( p = (gchar *)code; *p != 0; p++ )
399 /* Inter-character gap */
405 lgl_barcode_add_box (bc, x1, 0.0, (scale * MIN_X - INK_BLEED), height);
411 lgl_barcode_add_box (bc, x1, 0.0, (scale * N * MIN_X - INK_BLEED), height);
412 x1 += scale * N * MIN_X;
422 x1 += scale * N * MIN_X;
426 g_message( "Invalid Code39 symbol, should not happen" );
433 string_plus_stars = g_strdup_printf ("*%s*", string);
434 lgl_barcode_add_string (bc,
435 x_quiet + width/2, height + (TEXT_AREA_HEIGHT-TEXT_SIZE)/2,
436 TEXT_SIZE, string_plus_stars, strlen (string_plus_stars));
437 g_free (string_plus_stars);
440 bc->width = width + 2*x_quiet;
441 bc->height = text_flag ? height + TEXT_AREA_HEIGHT : height;
450 * Local Variables: -- emacs
452 * c-basic-offset: 8 -- emacs
453 * tab-width: 8 -- emacs
454 * indent-tabs-mode: nil -- emacs