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 glBarcode *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) {
79 } else if (g_ascii_strcasecmp (id, "EAN-8") == 0) {
80 if (!is_length_valid (digits, 7, 8)) {
84 } else if (g_ascii_strcasecmp (id, "EAN-8+2") == 0) {
85 if (!is_length1_valid (digits, 7, 8) || !is_length2_valid (digits, 2, 2)) {
89 } else if (g_ascii_strcasecmp (id, "EAN-8+5") == 0) {
90 if (!is_length1_valid (digits, 7, 8) || !is_length2_valid (digits, 5, 5)) {
94 } else if (g_ascii_strcasecmp (id, "EAN-13") == 0) {
95 if (!is_length_valid (digits, 12, 13)) {
99 } else if (g_ascii_strcasecmp (id, "EAN-13+2") == 0) {
100 if (!is_length1_valid (digits, 12,13) || !is_length2_valid (digits, 2,2)) {
104 } else if (g_ascii_strcasecmp (id, "EAN-13+5") == 0) {
105 if (!is_length1_valid (digits, 12,13) || !is_length2_valid (digits, 5,5)) {
109 } else if (g_ascii_strcasecmp (id, "UPC") == 0) {
111 } else if (g_ascii_strcasecmp (id, "UPC-A") == 0) {
112 if (!is_length_valid (digits, 11, 12)) {
116 } else if (g_ascii_strcasecmp (id, "UPC-A+2") == 0) {
117 if (!is_length1_valid (digits, 11,12) || !is_length2_valid (digits, 2,2)) {
121 } else if (g_ascii_strcasecmp (id, "UPC-A+5") == 0) {
122 if (!is_length1_valid (digits, 11,12) || !is_length2_valid (digits, 5,5)) {
126 } else if (g_ascii_strcasecmp (id, "UPC-E") == 0) {
127 if (!is_length_valid (digits, 6, 8)) {
131 } else if (g_ascii_strcasecmp (id, "UPC-E+2") == 0) {
132 if (!is_length1_valid (digits, 6, 8) || !is_length2_valid (digits, 2,2)) {
136 } else if (g_ascii_strcasecmp (id, "UPC-E+5") == 0) {
137 if (!is_length1_valid (digits, 6, 8) || !is_length2_valid (digits, 5,5)) {
141 } else if (g_ascii_strcasecmp (id, "ISBN") == 0) {
142 if (!is_length_valid (digits, 9, 10)) {
145 flags = BARCODE_ISBN;
146 } else if (g_ascii_strcasecmp (id, "ISBN+5") == 0) {
147 if (!is_length1_valid (digits, 9, 10) || !is_length2_valid (digits, 5,5)) {
150 flags = BARCODE_ISBN;
151 } else if (g_ascii_strcasecmp (id, "Code39") == 0) {
153 } else if (g_ascii_strcasecmp (id, "Code128") == 0) {
155 } else if (g_ascii_strcasecmp (id, "Code128C") == 0) {
156 flags = BARCODE_128C;
157 } else if (g_ascii_strcasecmp (id, "Code128B") == 0) {
158 flags = BARCODE_128B;
159 } else if (g_ascii_strcasecmp (id, "I25") == 0) {
161 } else if (g_ascii_strcasecmp (id, "CBR") == 0) {
163 } else if (g_ascii_strcasecmp (id, "MSI") == 0) {
165 } else if (g_ascii_strcasecmp (id, "PLS") == 0) {
167 } else if (g_ascii_strcasecmp (id, "Code93") == 0) {
170 g_message( "Illegal barcode id %s", id );
175 bci = Barcode_Create ((char *)digits);
177 /* First encode using GNU Barcode library */
179 flags |= BARCODE_NO_ASCII;
181 if (!checksum_flag) {
182 flags |= BARCODE_NO_CHECKSUM;
189 Barcode_Encode (bci, flags);
190 if (!bci->partial || !bci->textinfo) {
191 Barcode_Delete (bci);
195 /* now render with our custom back-end,
196 to create appropriate intermdediate format */
197 gbc = render_pass1 (bci, flags);
199 Barcode_Delete (bci);
204 /*--------------------------------------------------------------------------
205 * PRIVATE. Render to glBarcode intermediate representation of barcode.
207 * Some of this code is borrowed from the postscript renderer (ps.c)
208 * from the GNU barcode library:
210 * Copyright (C) 1999 Alessaandro Rubini (rubini@gnu.org)
211 * Copyright (C) 1999 Prosa Srl. (prosa@prosa.it)
213 *--------------------------------------------------------------------------*/
215 render_pass1 (struct Barcode_Item *bci,
218 gint validbits = BARCODE_NO_ASCII;
220 gdouble scalef = 1.0;
224 gint mode = '-'; /* text below bars */
228 if (bci->width > (2*bci->margin)) {
229 bci->width -= 2*bci->margin;
231 if (bci->height > (2*bci->margin)) {
232 bci->height -= 2*bci->margin;
235 /* If any flag is clear in "flags", inherit it from "bci->flags" */
236 if (!(flags & BARCODE_NO_ASCII)) {
237 flags |= bci->flags & BARCODE_NO_ASCII;
239 flags = bci->flags = (flags & validbits) | (bci->flags & ~validbits);
241 /* First calculate barlen */
242 barlen = bci->partial[0] - '0';
243 for (p = bci->partial + 1; *p != 0; p++) {
247 if ((*p != '+') && (*p != '-')) {
248 barlen += *p - 'a' + 1;
253 /* The scale factor depends on bar length */
255 if (!bci->width) bci->width = barlen; /* default */
256 scalef = bci->scalef = (double)bci->width / (double)barlen;
257 if (scalef < 0.5) scalef = 0.5;
260 /* The width defaults to "just enough" */
261 bci->width = barlen * scalef + 1;
263 /* But it can be too small, in this case enlarge and center the area */
264 if (bci->width < barlen * scalef) {
265 int wid = barlen * scalef + 1;
266 bci->xoff -= (wid - bci->width)/2 ;
268 /* Can't extend too far on the left */
270 bci->width += -bci->xoff;
275 /* The height defaults to 80 points (rescaled) */
277 bci->height = 80 * scalef;
279 /* If too small (5 + text), reduce the scale factor and center */
280 i = 5 + 10 * ((bci->flags & BARCODE_NO_ASCII)==0);
281 if (bci->height < i * scalef ) {
282 bci->height = i * scalef;
285 gbc = gl_barcode_new ();
287 /* Now traverse the code string and create a list of lines */
288 x = bci->margin + (bci->partial[0] - '0') * scalef;
289 for (p = bci->partial + 1, i = 1; *p != 0; p++, i++) {
290 /* special cases: '+' and '-' */
291 if (*p == '+' || *p == '-') {
292 mode = *p; /* don't count it */
296 /* j is the width of this bar/space */
301 if (i % 2) { /* bar */
302 x0 = x + (j * scalef) / 2;
305 if (!(bci->flags & BARCODE_NO_ASCII)) { /* leave space for text */
307 /* text below bars: 10 or 5 points */
308 yr -= (isdigit (*p) ? 10 : 5) * scalef;
310 /* above bars: 10 or 0 from bottom,
313 yr -= (isdigit (*p) ? 20 : 10) * scalef;
316 gl_barcode_add_line (gbc, x0, y0, yr, (j * scalef) - SHRINK_AMOUNT);
323 mode = '-'; /* reinstantiate default */
324 if (!(bci->flags & BARCODE_NO_ASCII)) {
325 for (p = bci->textinfo; p; p = strchr (p, ' ')) {
330 if (*p == '+' || *p == '-') {
334 if (sscanf (p, "%lf:%lf:%c", &f1, &f2, &c) != 3) {
335 g_message ("impossible data: %s", p);
338 x0 = f1 * scalef + bci->margin;
340 y0 = bci->margin + bci->height - 8 * scalef;
344 gl_barcode_add_char (gbc, x0, y0, (f2 * FONT_SCALE * scalef), c);
348 /* Fill in other info */
349 gbc->height = bci->height + 2.0 * bci->margin;
350 gbc->width = bci->width + 2.0 * bci->margin;
356 /*--------------------------------------------------------------------------*/
357 /* Validate specific length of string (for subtypes). */
358 /*--------------------------------------------------------------------------*/
360 is_length_valid (const gchar *digits,
371 for (p = (gchar *)digits, i=0; *p != 0; p++) {
372 if (g_ascii_isdigit (*p)) {
377 return (i >= n1) && (i <= n2);
381 /*--------------------------------------------------------------------------*/
382 /* Validate specific length of string (for subtypes). */
383 /*--------------------------------------------------------------------------*/
385 is_length1_valid (const gchar *digits,
396 for (p = (gchar *)digits, i=0; !g_ascii_isspace (*p) && *p != 0; p++) {
397 if (g_ascii_isdigit (*p)) {
402 return (i >= n1) && (i <= n2);
406 /*--------------------------------------------------------------------------*/
407 /* Validate specific length of second string (for subtypes). */
408 /*--------------------------------------------------------------------------*/
410 is_length2_valid (const gchar *digits,
421 for (p = (gchar *)digits; !g_ascii_isspace (*p) && (*p != 0); p++) {
422 /* Skip over 1st string */
425 for (i=0; *p != 0; p++) {
426 if (g_ascii_isdigit (*p)) {
431 return (i >= n1) && (i <= n2);
434 #endif /* HAVE_LIBBARCODE */
439 * Local Variables: -- emacs
441 * c-basic-offset: 8 -- emacs
442 * tab-width: 8 -- emacs
443 * indent-tabs-mode: nil -- emacs