3 * Copyright (C) 2001-2010 Jim Evins <evins@snaught.com>.
5 * This file is part of gLabels.
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.
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.
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/>.
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);
223 /* Now vectorize code string */
224 bc = code39_vectorize (code, w, h, text_flag, checksum_flag, canon_data, display_data);
227 g_free (display_data);
234 /*--------------------------------------------------------------------------*/
235 /* PRIVATE. Generate string of symbols, representing barcode. */
236 /*--------------------------------------------------------------------------*/
238 code39_encode (const gchar *data,
239 gboolean checksum_flag)
246 /* Left frame symbol */
247 code = g_string_new( frame_symbol );
248 code = g_string_append( code, "i" );
251 for ( p=(gchar *)data; *p != 0; p++ )
254 for ( i = 0; symbols[i].c != 0; i++ )
256 if ( c == symbols[i].c )
259 code = g_string_append (code, symbols[i].sym);
263 code = g_string_append (code, "i");
268 code = g_string_append (code, symbols[sum % 43].sym);
269 code = g_string_append (code, "i");
272 /* Right frame bar */
273 code = g_string_append (code, frame_symbol);
275 return g_string_free (code, FALSE);
279 /*--------------------------------------------------------------------------*/
280 /* Generate list of rectangles that form the barcode for the given digits. */
281 /*--------------------------------------------------------------------------*/
283 code39_vectorize (const gchar *code,
287 gboolean checksum_flag,
294 gdouble width, height;
299 gchar *string_plus_stars;
301 /* determine width and establish horizontal scale */
302 n_chars = strlen (data);
305 min_l = (n_chars + 2)*(3*N + 6)*MIN_X + (n_chars + 1)*MIN_I;
309 min_l = (n_chars + 3)*(3*N + 6)*MIN_X + (n_chars + 2)*MIN_I;
318 scale = w / (min_l + 2*MIN_QUIET);
325 width = min_l * scale;
327 /* determine height of barcode */
328 height = text_flag ? h - TEXT_AREA_HEIGHT : h;
329 height = MAX (height, MAX(0.15*width, MIN_HEIGHT));
331 /* determine horizontal quiet zone */
332 x_quiet = MAX ((10 * scale * MIN_X), MIN_QUIET);
335 bc = lgl_barcode_new ();
337 /* Now traverse the code string and create a list of rectangles */
339 for ( p = (gchar *)code; *p != 0; p++ )
346 /* Inter-character gap */
352 lgl_barcode_add_box (bc, x1, 0.0, (scale * MIN_X - INK_BLEED), height);
358 lgl_barcode_add_box (bc, x1, 0.0, (scale * N * MIN_X - INK_BLEED), height);
359 x1 += scale * N * MIN_X;
369 x1 += scale * N * MIN_X;
373 g_message( "Invalid Code39 symbol, should not happen" );
380 string_plus_stars = g_strdup_printf ("*%s*", string);
381 lgl_barcode_add_string (bc,
382 x_quiet + width/2, height + (TEXT_AREA_HEIGHT-TEXT_SIZE)/2,
383 TEXT_SIZE, string_plus_stars, strlen (string_plus_stars));
384 g_free (string_plus_stars);
387 bc->width = width + 2*x_quiet;
388 bc->height = text_flag ? height + TEXT_AREA_HEIGHT : height;
397 * Local Variables: -- emacs
399 * c-basic-offset: 8 -- emacs
400 * tab-width: 8 -- emacs
401 * indent-tabs-mode: nil -- emacs