1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
4 * (GLABELS) Label and Business Card Creation program for GNOME
6 * bc-gnubarcode.c: front-end to GNU-barcode-library module
8 * Copyright (C) 2001-2003 Jim Evins <evins@snaught.com>.
10 * Some of this code is borrowed from the postscript renderer (ps.c)
11 * from the GNU barcode library:
13 * Copyright (C) 1999 Alessaandro Rubini (rubini@gnu.org)
14 * Copyright (C) 1999 Prosa Srl. (prosa@prosa.it)
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #include "bc-gnubarcode.h"
37 #include <glib/gstring.h>
38 #include <glib/gstrfuncs.h>
39 #include <glib/gmessages.h>
45 /*========================================================*/
46 /* Private macros and constants. */
47 /*========================================================*/
48 #define SHRINK_AMOUNT 0.15 /* shrink bars to account for ink spreading */
49 #define FONT_SCALE 0.95 /* Shrink fonts just a hair */
51 /*===========================================*/
52 /* Local function prototypes */
53 /*===========================================*/
54 static glBarcode *render_pass1 (struct Barcode_Item *bci,
57 static gboolean is_length_valid (const gchar *digits,
61 static gboolean is_length1_valid (const gchar *digits,
65 static gboolean is_length2_valid (const gchar *digits,
70 /*****************************************************************************/
71 /* Generate intermediate representation of barcode. */
72 /*****************************************************************************/
74 gl_barcode_gnubarcode_new (const gchar *id,
76 gboolean checksum_flag,
82 struct Barcode_Item *bci;
85 /* Assign type flag. Pre-filter by length for subtypes. */
86 if (g_strcasecmp (id, "EAN") == 0) {
88 } else if (g_strcasecmp (id, "EAN-8") == 0) {
89 if (!is_length_valid (digits, 7, 8)) {
93 } else if (g_strcasecmp (id, "EAN-8+2") == 0) {
94 if (!is_length1_valid (digits, 7, 8) || !is_length2_valid (digits, 2, 2)) {
98 } else if (g_strcasecmp (id, "EAN-8+5") == 0) {
99 if (!is_length1_valid (digits, 7, 8) || !is_length2_valid (digits, 5, 5)) {
103 } else if (g_strcasecmp (id, "EAN-13") == 0) {
104 if (!is_length_valid (digits, 12, 13)) {
108 } else if (g_strcasecmp (id, "EAN-13+2") == 0) {
109 if (!is_length1_valid (digits, 12,13) || !is_length2_valid (digits, 2,2)) {
113 } else if (g_strcasecmp (id, "EAN-13+5") == 0) {
114 if (!is_length1_valid (digits, 12,13) || !is_length2_valid (digits, 5,5)) {
118 } else if (g_strcasecmp (id, "UPC") == 0) {
120 } else if (g_strcasecmp (id, "UPC-A") == 0) {
121 if (!is_length_valid (digits, 11, 12)) {
125 } else if (g_strcasecmp (id, "UPC-A+2") == 0) {
126 if (!is_length1_valid (digits, 11,12) || !is_length2_valid (digits, 2,2)) {
130 } else if (g_strcasecmp (id, "UPC-A+5") == 0) {
131 if (!is_length1_valid (digits, 11,12) || !is_length2_valid (digits, 5,5)) {
135 } else if (g_strcasecmp (id, "UPC-E") == 0) {
136 if (!is_length_valid (digits, 6, 8)) {
140 } else if (g_strcasecmp (id, "UPC-E+2") == 0) {
141 if (!is_length1_valid (digits, 6, 8) || !is_length2_valid (digits, 2,2)) {
145 } else if (g_strcasecmp (id, "UPC-E+5") == 0) {
146 if (!is_length1_valid (digits, 6, 8) || !is_length2_valid (digits, 5,5)) {
150 } else if (g_strcasecmp (id, "ISBN") == 0) {
151 if (!is_length_valid (digits, 9, 10)) {
154 flags = BARCODE_ISBN;
155 } else if (g_strcasecmp (id, "ISBN+5") == 0) {
156 if (!is_length1_valid (digits, 9, 10) || !is_length2_valid (digits, 5,5)) {
159 flags = BARCODE_ISBN;
160 } else if (g_strcasecmp (id, "Code39") == 0) {
162 } else if (g_strcasecmp (id, "Code128") == 0) {
164 } else if (g_strcasecmp (id, "Code128C") == 0) {
165 flags = BARCODE_128C;
166 } else if (g_strcasecmp (id, "Code128B") == 0) {
167 flags = BARCODE_128B;
168 } else if (g_strcasecmp (id, "I25") == 0) {
170 } else if (g_strcasecmp (id, "CBR") == 0) {
172 } else if (g_strcasecmp (id, "MSI") == 0) {
174 } else if (g_strcasecmp (id, "PLS") == 0) {
177 g_message( "Illegal barcode id %s", id );
182 bci = Barcode_Create ((char *)digits);
184 /* First encode using GNU Barcode library */
186 flags |= BARCODE_NO_ASCII;
188 if (!checksum_flag) {
189 flags |= BARCODE_NO_CHECKSUM;
196 Barcode_Encode (bci, flags);
197 if (!bci->partial || !bci->textinfo) {
198 Barcode_Delete (bci);
202 /* now render with our custom back-end,
203 to create appropriate intermdediate format */
204 gbc = render_pass1 (bci, flags);
206 Barcode_Delete (bci);
210 /*--------------------------------------------------------------------------
211 * PRIVATE. Render to glBarcode intermediate representation of barcode.
213 * Some of this code is borrowed from the postscript renderer (ps.c)
214 * from the GNU barcode library:
216 * Copyright (C) 1999 Alessaandro Rubini (rubini@gnu.org)
217 * Copyright (C) 1999 Prosa Srl. (prosa@prosa.it)
219 *--------------------------------------------------------------------------*/
221 render_pass1 (struct Barcode_Item *bci,
224 gint validbits = BARCODE_NO_ASCII;
227 glBarcodeChar *bchar;
228 gdouble scalef = 1.0;
232 gint mode = '-'; /* text below bars */
236 if (bci->width > (2*bci->margin)) {
237 bci->width -= 2*bci->margin;
239 if (bci->height > (2*bci->margin)) {
240 bci->height -= 2*bci->margin;
243 /* If any flag is clear in "flags", inherit it from "bci->flags" */
244 if (!(flags & BARCODE_NO_ASCII)) {
245 flags |= bci->flags & BARCODE_NO_ASCII;
247 flags = bci->flags = (flags & validbits) | (bci->flags & ~validbits);
249 /* First calculate barlen */
250 barlen = bci->partial[0] - '0';
251 for (p = bci->partial + 1; *p != 0; p++) {
255 if ((*p != '+') && (*p != '-')) {
256 barlen += *p - 'a' + 1;
261 /* The scale factor depends on bar length */
263 if (!bci->width) bci->width = barlen; /* default */
264 scalef = bci->scalef = (double)bci->width / (double)barlen;
265 if (scalef < 0.5) scalef = 0.5;
268 /* The width defaults to "just enough" */
269 bci->width = barlen * scalef + 1;
271 /* But it can be too small, in this case enlarge and center the area */
272 if (bci->width < barlen * scalef) {
273 int wid = barlen * scalef + 1;
274 bci->xoff -= (wid - bci->width)/2 ;
276 /* Can't extend too far on the left */
278 bci->width += -bci->xoff;
283 /* The height defaults to 80 points (rescaled) */
285 bci->height = 80 * scalef;
287 /* If too small (5 + text), reduce the scale factor and center */
288 i = 5 + 10 * ((bci->flags & BARCODE_NO_ASCII)==0);
289 if (bci->height < i * scalef ) {
291 double scaleg = ((double)bci->height) / i;
292 int wid = bci->width * scaleg / scalef;
293 bci->xoff += (bci->width - wid)/2;
297 bci->height = i * scalef;
301 gbc = g_new0 (glBarcode, 1);
303 /* Now traverse the code string and create a list of lines */
304 x = bci->margin + (bci->partial[0] - '0') * scalef;
305 for (p = bci->partial + 1, i = 1; *p != 0; p++, i++) {
306 /* special cases: '+' and '-' */
307 if (*p == '+' || *p == '-') {
308 mode = *p; /* don't count it */
312 /* j is the width of this bar/space */
317 if (i % 2) { /* bar */
318 x0 = x + (j * scalef) / 2;
321 if (!(bci->flags & BARCODE_NO_ASCII)) { /* leave space for text */
323 /* text below bars: 10 or 5 points */
324 yr -= (isdigit (*p) ? 10 : 5) * scalef;
326 /* above bars: 10 or 0 from bottom,
329 yr -= (isdigit (*p) ? 20 : 10) * scalef;
332 line = g_new0 (glBarcodeLine, 1);
336 line->width = (j * scalef) - SHRINK_AMOUNT;
337 gbc->lines = g_list_append (gbc->lines, line);
344 mode = '-'; /* reinstantiate default */
345 if (!(bci->flags & BARCODE_NO_ASCII)) {
346 for (p = bci->textinfo; p; p = strchr (p, ' ')) {
351 if (*p == '+' || *p == '-') {
355 if (sscanf (p, "%lf:%lf:%c", &f1, &f2, &c) != 3) {
356 g_message ("impossible data: %s", p);
359 bchar = g_new0 (glBarcodeChar, 1);
360 bchar->x = f1 * scalef + bci->margin;
363 bci->margin + bci->height - 8 * scalef;
365 bchar->y = bci->margin;
367 bchar->fsize = f2 * FONT_SCALE * scalef;
369 gbc->chars = g_list_append (gbc->chars, bchar);
373 /* Fill in other info */
374 gbc->height = bci->height + 2.0 * bci->margin;
375 gbc->width = bci->width + 2.0 * bci->margin;
378 g_print ("w=%f, h=%f\n", gbc->width, gbc->height);
384 /*--------------------------------------------------------------------------*/
385 /* Validate specific length of string (for subtypes). */
386 /*--------------------------------------------------------------------------*/
388 is_length_valid (const gchar *digits,
399 for (p = (gchar *)digits, i=0; *p != 0; p++) {
400 if (g_ascii_isdigit (*p)) {
405 return (i >= n1) && (i <= n2);
408 /*--------------------------------------------------------------------------*/
409 /* Validate specific length of string (for subtypes). */
410 /*--------------------------------------------------------------------------*/
412 is_length1_valid (const gchar *digits,
423 for (p = (gchar *)digits, i=0; !g_ascii_isspace (*p) && *p != 0; p++) {
424 if (g_ascii_isdigit (*p)) {
429 return (i >= n1) && (i <= n2);
432 /*--------------------------------------------------------------------------*/
433 /* Validate specific length of second string (for subtypes). */
434 /*--------------------------------------------------------------------------*/
436 is_length2_valid (const gchar *digits,
447 for (p = (gchar *)digits; !g_ascii_isspace (*p) && (*p != 0); p++) {
448 /* Skip over 1st string */
451 for (i=0; *p != 0; p++) {
452 if (g_ascii_isdigit (*p)) {
457 return (i >= n1) && (i <= n2);