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 glBarcodeShapeLine *line;
221 glBarcodeShapeAlpha *bchar;
222 gdouble scalef = 1.0;
226 gint mode = '-'; /* text below bars */
230 if (bci->width > (2*bci->margin)) {
231 bci->width -= 2*bci->margin;
233 if (bci->height > (2*bci->margin)) {
234 bci->height -= 2*bci->margin;
237 /* If any flag is clear in "flags", inherit it from "bci->flags" */
238 if (!(flags & BARCODE_NO_ASCII)) {
239 flags |= bci->flags & BARCODE_NO_ASCII;
241 flags = bci->flags = (flags & validbits) | (bci->flags & ~validbits);
243 /* First calculate barlen */
244 barlen = bci->partial[0] - '0';
245 for (p = bci->partial + 1; *p != 0; p++) {
249 if ((*p != '+') && (*p != '-')) {
250 barlen += *p - 'a' + 1;
255 /* The scale factor depends on bar length */
257 if (!bci->width) bci->width = barlen; /* default */
258 scalef = bci->scalef = (double)bci->width / (double)barlen;
259 if (scalef < 0.5) scalef = 0.5;
262 /* The width defaults to "just enough" */
263 bci->width = barlen * scalef + 1;
265 /* But it can be too small, in this case enlarge and center the area */
266 if (bci->width < barlen * scalef) {
267 int wid = barlen * scalef + 1;
268 bci->xoff -= (wid - bci->width)/2 ;
270 /* Can't extend too far on the left */
272 bci->width += -bci->xoff;
277 /* The height defaults to 80 points (rescaled) */
279 bci->height = 80 * scalef;
281 /* If too small (5 + text), reduce the scale factor and center */
282 i = 5 + 10 * ((bci->flags & BARCODE_NO_ASCII)==0);
283 if (bci->height < i * scalef ) {
284 bci->height = i * scalef;
287 gbc = g_new0 (glBarcode, 1);
289 /* Now traverse the code string and create a list of lines */
290 x = bci->margin + (bci->partial[0] - '0') * scalef;
291 for (p = bci->partial + 1, i = 1; *p != 0; p++, i++) {
292 /* special cases: '+' and '-' */
293 if (*p == '+' || *p == '-') {
294 mode = *p; /* don't count it */
298 /* j is the width of this bar/space */
303 if (i % 2) { /* bar */
304 x0 = x + (j * scalef) / 2;
307 if (!(bci->flags & BARCODE_NO_ASCII)) { /* leave space for text */
309 /* text below bars: 10 or 5 points */
310 yr -= (isdigit (*p) ? 10 : 5) * scalef;
312 /* above bars: 10 or 0 from bottom,
315 yr -= (isdigit (*p) ? 20 : 10) * scalef;
318 line = gl_barcode_shape_line_new ();
322 line->width = (j * scalef) - SHRINK_AMOUNT;
323 gl_barcode_add_shape (gbc, (glBarcodeShape *)line);
330 mode = '-'; /* reinstantiate default */
331 if (!(bci->flags & BARCODE_NO_ASCII)) {
332 for (p = bci->textinfo; p; p = strchr (p, ' ')) {
337 if (*p == '+' || *p == '-') {
341 if (sscanf (p, "%lf:%lf:%c", &f1, &f2, &c) != 3) {
342 g_message ("impossible data: %s", p);
345 bchar = gl_barcode_shape_alpha_new ();
346 bchar->x = f1 * scalef + bci->margin;
349 bci->margin + bci->height - 8 * scalef;
351 bchar->y = bci->margin;
353 bchar->fsize = f2 * FONT_SCALE * scalef;
355 gl_barcode_add_shape (gbc, (glBarcodeShape *)bchar);
359 /* Fill in other info */
360 gbc->height = bci->height + 2.0 * bci->margin;
361 gbc->width = bci->width + 2.0 * bci->margin;
367 /*--------------------------------------------------------------------------*/
368 /* Validate specific length of string (for subtypes). */
369 /*--------------------------------------------------------------------------*/
371 is_length_valid (const gchar *digits,
382 for (p = (gchar *)digits, i=0; *p != 0; p++) {
383 if (g_ascii_isdigit (*p)) {
388 return (i >= n1) && (i <= n2);
392 /*--------------------------------------------------------------------------*/
393 /* Validate specific length of string (for subtypes). */
394 /*--------------------------------------------------------------------------*/
396 is_length1_valid (const gchar *digits,
407 for (p = (gchar *)digits, i=0; !g_ascii_isspace (*p) && *p != 0; p++) {
408 if (g_ascii_isdigit (*p)) {
413 return (i >= n1) && (i <= n2);
417 /*--------------------------------------------------------------------------*/
418 /* Validate specific length of second string (for subtypes). */
419 /*--------------------------------------------------------------------------*/
421 is_length2_valid (const gchar *digits,
432 for (p = (gchar *)digits; !g_ascii_isspace (*p) && (*p != 0); p++) {
433 /* Skip over 1st string */
436 for (i=0; *p != 0; p++) {
437 if (g_ascii_isdigit (*p)) {
442 return (i >= n1) && (i <= n2);
445 #endif /* HAVE_LIBBARCODE */
450 * Local Variables: -- emacs
452 * c-basic-offset: 8 -- emacs
453 * tab-width: 8 -- emacs
454 * indent-tabs-mode: nil -- emacs