3 * Copyright (C) 2001-2009 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 #ifdef HAVE_LIBBARCODE
25 #include "bc-gnubarcode.h"
30 #include <barcode.h> /* GNU Barcode */
35 /*========================================================*/
36 /* Private macros and constants. */
37 /*========================================================*/
38 #define SHRINK_AMOUNT 0.15 /* shrink bars to account for ink spreading */
39 #define FONT_SCALE 0.95 /* Shrink fonts just a hair */
42 /*===========================================*/
43 /* Local function prototypes */
44 /*===========================================*/
45 static lglBarcode *render_pass1 (struct Barcode_Item *bci,
48 static gboolean is_length_valid (const gchar *digits,
52 static gboolean is_length1_valid (const gchar *digits,
56 static gboolean is_length2_valid (const gchar *digits,
61 /*****************************************************************************/
62 /* Generate intermediate representation of barcode. */
63 /*****************************************************************************/
65 gl_barcode_gnubarcode_new (const gchar *id,
67 gboolean checksum_flag,
73 struct Barcode_Item *bci;
76 /* Assign type flag. Pre-filter by length for subtypes. */
77 if (g_ascii_strcasecmp (id, "EAN") == 0)
81 else if (g_ascii_strcasecmp (id, "EAN-8") == 0)
83 if (!is_length_valid (digits, 7, 8))
89 else if (g_ascii_strcasecmp (id, "EAN-8+2") == 0)
91 if (!is_length1_valid (digits, 7, 8) || !is_length2_valid (digits, 2, 2))
97 else if (g_ascii_strcasecmp (id, "EAN-8+5") == 0)
99 if (!is_length1_valid (digits, 7, 8) || !is_length2_valid (digits, 5, 5))
105 else if (g_ascii_strcasecmp (id, "EAN-13") == 0)
107 if (!is_length_valid (digits, 12, 13))
113 else if (g_ascii_strcasecmp (id, "EAN-13+2") == 0)
115 if (!is_length1_valid (digits, 12,13) || !is_length2_valid (digits, 2,2))
121 else if (g_ascii_strcasecmp (id, "EAN-13+5") == 0)
123 if (!is_length1_valid (digits, 12,13) || !is_length2_valid (digits, 5,5))
129 else if (g_ascii_strcasecmp (id, "UPC") == 0)
133 else if (g_ascii_strcasecmp (id, "UPC-A") == 0)
135 if (!is_length_valid (digits, 11, 12))
141 else if (g_ascii_strcasecmp (id, "UPC-A+2") == 0)
143 if (!is_length1_valid (digits, 11,12) || !is_length2_valid (digits, 2,2))
149 else if (g_ascii_strcasecmp (id, "UPC-A+5") == 0)
151 if (!is_length1_valid (digits, 11,12) || !is_length2_valid (digits, 5,5))
157 else if (g_ascii_strcasecmp (id, "UPC-E") == 0)
159 if (!is_length_valid (digits, 6, 8))
165 else if (g_ascii_strcasecmp (id, "UPC-E+2") == 0)
167 if (!is_length1_valid (digits, 6, 8) || !is_length2_valid (digits, 2,2))
173 else if (g_ascii_strcasecmp (id, "UPC-E+5") == 0)
175 if (!is_length1_valid (digits, 6, 8) || !is_length2_valid (digits, 5,5))
181 else if (g_ascii_strcasecmp (id, "ISBN") == 0)
183 if (!is_length_valid (digits, 9, 10))
187 flags = BARCODE_ISBN;
189 else if (g_ascii_strcasecmp (id, "ISBN+5") == 0)
191 if (!is_length1_valid (digits, 9, 10) || !is_length2_valid (digits, 5,5))
195 flags = BARCODE_ISBN;
197 else if (g_ascii_strcasecmp (id, "Code39") == 0)
201 else if (g_ascii_strcasecmp (id, "Code128") == 0)
205 else if (g_ascii_strcasecmp (id, "Code128C") == 0)
207 flags = BARCODE_128C;
209 else if (g_ascii_strcasecmp (id, "Code128B") == 0)
211 flags = BARCODE_128B;
213 else if (g_ascii_strcasecmp (id, "I25") == 0)
217 else if (g_ascii_strcasecmp (id, "CBR") == 0)
221 else if (g_ascii_strcasecmp (id, "MSI") == 0)
225 else if (g_ascii_strcasecmp (id, "PLS") == 0)
229 else if (g_ascii_strcasecmp (id, "Code93") == 0)
235 g_message( "Illegal barcode id %s", id );
240 bci = Barcode_Create ((char *)digits);
242 /* First encode using GNU Barcode library */
245 flags |= BARCODE_NO_ASCII;
249 flags |= BARCODE_NO_CHECKSUM;
256 Barcode_Encode (bci, flags);
257 if (!bci->partial || !bci->textinfo)
259 Barcode_Delete (bci);
263 /* now render with our custom back-end,
264 to create appropriate intermdediate format */
265 gbc = render_pass1 (bci, flags);
267 Barcode_Delete (bci);
272 /*--------------------------------------------------------------------------
273 * PRIVATE. Render to lglBarcode intermediate representation of barcode.
275 * Some of this code is borrowed from the postscript renderer (ps.c)
276 * from the GNU barcode library:
278 * Copyright (C) 1999 Alessaandro Rubini (rubini@gnu.org)
279 * Copyright (C) 1999 Prosa Srl. (prosa@prosa.it)
281 *--------------------------------------------------------------------------*/
283 render_pass1 (struct Barcode_Item *bci,
286 gint validbits = BARCODE_NO_ASCII;
288 gdouble scalef = 1.0;
292 gint mode = '-'; /* text below bars */
296 if (bci->width > (2*bci->margin))
298 bci->width -= 2*bci->margin;
300 if (bci->height > (2*bci->margin))
302 bci->height -= 2*bci->margin;
305 /* If any flag is clear in "flags", inherit it from "bci->flags" */
306 if (!(flags & BARCODE_NO_ASCII))
308 flags |= bci->flags & BARCODE_NO_ASCII;
310 flags = bci->flags = (flags & validbits) | (bci->flags & ~validbits);
312 /* First calculate barlen */
313 barlen = bci->partial[0] - '0';
314 for (p = bci->partial + 1; *p != 0; p++)
322 if ((*p != '+') && (*p != '-'))
324 barlen += *p - 'a' + 1;
329 /* The scale factor depends on bar length */
334 bci->width = barlen; /* default */
336 scalef = bci->scalef = (double)bci->width / (double)barlen;
343 /* The width defaults to "just enough" */
344 bci->width = barlen * scalef + 1;
346 /* But it can be too small, in this case enlarge and center the area */
347 if (bci->width < barlen * scalef)
349 int wid = barlen * scalef + 1;
350 bci->xoff -= (wid - bci->width)/2 ;
352 /* Can't extend too far on the left */
355 bci->width += -bci->xoff;
360 /* The height defaults to 80 points (rescaled) */
363 bci->height = 80 * scalef;
366 /* If too small (5 + text), reduce the scale factor and center */
367 i = 5 + 10 * ((bci->flags & BARCODE_NO_ASCII)==0);
368 if (bci->height < i * scalef )
370 bci->height = i * scalef;
373 gbc = lgl_barcode_new ();
375 /* Now traverse the code string and create a list of lines */
376 x = bci->margin + (bci->partial[0] - '0') * scalef;
377 for (p = bci->partial + 1, i = 1; *p != 0; p++, i++)
379 /* special cases: '+' and '-' */
380 if (*p == '+' || *p == '-')
382 mode = *p; /* don't count it */
386 /* j is the width of this bar/space */
398 x0 = x + (j * scalef) / 2;
401 if (!(bci->flags & BARCODE_NO_ASCII))
403 /* leave space for text */
406 /* text below bars: 10 or 5 points */
407 yr -= (isdigit (*p) ? 10 : 5) * scalef;
412 /* above bars: 10 or 0 from bottom,
415 yr -= (isdigit (*p) ? 20 : 10) * scalef;
418 lgl_barcode_add_line (gbc, x0, y0, yr, (j * scalef) - SHRINK_AMOUNT);
425 mode = '-'; /* reinstantiate default */
426 if (!(bci->flags & BARCODE_NO_ASCII))
428 for (p = bci->textinfo; p; p = strchr (p, ' '))
438 if (*p == '+' || *p == '-')
443 if (sscanf (p, "%lf:%lf:%c", &f1, &f2, &c) != 3)
445 g_message ("impossible data: %s", p);
448 x0 = f1 * scalef + bci->margin;
451 y0 = bci->margin + bci->height - 8 * scalef;
457 lgl_barcode_add_char (gbc, x0, y0, (f2 * FONT_SCALE * scalef), c);
461 /* Fill in other info */
462 gbc->height = bci->height + 2.0 * bci->margin;
463 gbc->width = bci->width + 2.0 * bci->margin;
469 /*--------------------------------------------------------------------------*/
470 /* Validate specific length of string (for subtypes). */
471 /*--------------------------------------------------------------------------*/
473 is_length_valid (const gchar *digits,
485 for (p = (gchar *)digits, i=0; *p != 0; p++)
487 if (g_ascii_isdigit (*p))
493 return (i >= n1) && (i <= n2);
497 /*--------------------------------------------------------------------------*/
498 /* Validate specific length of string (for subtypes). */
499 /*--------------------------------------------------------------------------*/
501 is_length1_valid (const gchar *digits,
513 for (p = (gchar *)digits, i=0; !g_ascii_isspace (*p) && *p != 0; p++)
515 if (g_ascii_isdigit (*p))
521 return (i >= n1) && (i <= n2);
525 /*--------------------------------------------------------------------------*/
526 /* Validate specific length of second string (for subtypes). */
527 /*--------------------------------------------------------------------------*/
529 is_length2_valid (const gchar *digits,
541 for (p = (gchar *)digits; !g_ascii_isspace (*p) && (*p != 0); p++)
543 /* Skip over 1st string */
546 for (i=0; *p != 0; p++)
548 if (g_ascii_isdigit (*p))
554 return (i >= n1) && (i <= n2);
557 #endif /* HAVE_LIBBARCODE */
562 * Local Variables: -- emacs
564 * c-basic-offset: 8 -- emacs
565 * tab-width: 8 -- emacs
566 * indent-tabs-mode: nil -- emacs