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 #include "bc-gnubarcode.h"
28 #include <barcode.h> /* GNU Barcode */
33 /*========================================================*/
34 /* Private macros and constants. */
35 /*========================================================*/
36 #define SHRINK_AMOUNT 0.15 /* shrink bars to account for ink spreading */
37 #define FONT_SCALE 0.95 /* Shrink fonts just a hair */
40 /*===========================================*/
41 /* Local function prototypes */
42 /*===========================================*/
43 static glBarcode *render_pass1 (struct Barcode_Item *bci,
46 static gboolean is_length_valid (const gchar *digits,
50 static gboolean is_length1_valid (const gchar *digits,
54 static gboolean is_length2_valid (const gchar *digits,
59 /*****************************************************************************/
60 /* Generate intermediate representation of barcode. */
61 /*****************************************************************************/
63 gl_barcode_gnubarcode_new (const gchar *id,
65 gboolean checksum_flag,
71 struct Barcode_Item *bci;
74 /* Assign type flag. Pre-filter by length for subtypes. */
75 if (g_ascii_strcasecmp (id, "EAN") == 0) {
77 } else if (g_ascii_strcasecmp (id, "EAN-8") == 0) {
78 if (!is_length_valid (digits, 7, 8)) {
82 } else if (g_ascii_strcasecmp (id, "EAN-8+2") == 0) {
83 if (!is_length1_valid (digits, 7, 8) || !is_length2_valid (digits, 2, 2)) {
87 } else if (g_ascii_strcasecmp (id, "EAN-8+5") == 0) {
88 if (!is_length1_valid (digits, 7, 8) || !is_length2_valid (digits, 5, 5)) {
92 } else if (g_ascii_strcasecmp (id, "EAN-13") == 0) {
93 if (!is_length_valid (digits, 12, 13)) {
97 } else if (g_ascii_strcasecmp (id, "EAN-13+2") == 0) {
98 if (!is_length1_valid (digits, 12,13) || !is_length2_valid (digits, 2,2)) {
102 } else if (g_ascii_strcasecmp (id, "EAN-13+5") == 0) {
103 if (!is_length1_valid (digits, 12,13) || !is_length2_valid (digits, 5,5)) {
107 } else if (g_ascii_strcasecmp (id, "UPC") == 0) {
109 } else if (g_ascii_strcasecmp (id, "UPC-A") == 0) {
110 if (!is_length_valid (digits, 11, 12)) {
114 } else if (g_ascii_strcasecmp (id, "UPC-A+2") == 0) {
115 if (!is_length1_valid (digits, 11,12) || !is_length2_valid (digits, 2,2)) {
119 } else if (g_ascii_strcasecmp (id, "UPC-A+5") == 0) {
120 if (!is_length1_valid (digits, 11,12) || !is_length2_valid (digits, 5,5)) {
124 } else if (g_ascii_strcasecmp (id, "UPC-E") == 0) {
125 if (!is_length_valid (digits, 6, 8)) {
129 } else if (g_ascii_strcasecmp (id, "UPC-E+2") == 0) {
130 if (!is_length1_valid (digits, 6, 8) || !is_length2_valid (digits, 2,2)) {
134 } else if (g_ascii_strcasecmp (id, "UPC-E+5") == 0) {
135 if (!is_length1_valid (digits, 6, 8) || !is_length2_valid (digits, 5,5)) {
139 } else if (g_ascii_strcasecmp (id, "ISBN") == 0) {
140 if (!is_length_valid (digits, 9, 10)) {
143 flags = BARCODE_ISBN;
144 } else if (g_ascii_strcasecmp (id, "ISBN+5") == 0) {
145 if (!is_length1_valid (digits, 9, 10) || !is_length2_valid (digits, 5,5)) {
148 flags = BARCODE_ISBN;
149 } else if (g_ascii_strcasecmp (id, "Code39") == 0) {
151 } else if (g_ascii_strcasecmp (id, "Code128") == 0) {
153 } else if (g_ascii_strcasecmp (id, "Code128C") == 0) {
154 flags = BARCODE_128C;
155 } else if (g_ascii_strcasecmp (id, "Code128B") == 0) {
156 flags = BARCODE_128B;
157 } else if (g_ascii_strcasecmp (id, "I25") == 0) {
159 } else if (g_ascii_strcasecmp (id, "CBR") == 0) {
161 } else if (g_ascii_strcasecmp (id, "MSI") == 0) {
163 } else if (g_ascii_strcasecmp (id, "PLS") == 0) {
166 g_message( "Illegal barcode id %s", id );
171 bci = Barcode_Create ((char *)digits);
173 /* First encode using GNU Barcode library */
175 flags |= BARCODE_NO_ASCII;
177 if (!checksum_flag) {
178 flags |= BARCODE_NO_CHECKSUM;
185 Barcode_Encode (bci, flags);
186 if (!bci->partial || !bci->textinfo) {
187 Barcode_Delete (bci);
191 /* now render with our custom back-end,
192 to create appropriate intermdediate format */
193 gbc = render_pass1 (bci, flags);
195 Barcode_Delete (bci);
200 /*--------------------------------------------------------------------------
201 * PRIVATE. Render to glBarcode intermediate representation of barcode.
203 * Some of this code is borrowed from the postscript renderer (ps.c)
204 * from the GNU barcode library:
206 * Copyright (C) 1999 Alessaandro Rubini (rubini@gnu.org)
207 * Copyright (C) 1999 Prosa Srl. (prosa@prosa.it)
209 *--------------------------------------------------------------------------*/
211 render_pass1 (struct Barcode_Item *bci,
214 gint validbits = BARCODE_NO_ASCII;
217 glBarcodeChar *bchar;
218 gdouble scalef = 1.0;
222 gint mode = '-'; /* text below bars */
226 if (bci->width > (2*bci->margin)) {
227 bci->width -= 2*bci->margin;
229 if (bci->height > (2*bci->margin)) {
230 bci->height -= 2*bci->margin;
233 /* If any flag is clear in "flags", inherit it from "bci->flags" */
234 if (!(flags & BARCODE_NO_ASCII)) {
235 flags |= bci->flags & BARCODE_NO_ASCII;
237 flags = bci->flags = (flags & validbits) | (bci->flags & ~validbits);
239 /* First calculate barlen */
240 barlen = bci->partial[0] - '0';
241 for (p = bci->partial + 1; *p != 0; p++) {
245 if ((*p != '+') && (*p != '-')) {
246 barlen += *p - 'a' + 1;
251 /* The scale factor depends on bar length */
253 if (!bci->width) bci->width = barlen; /* default */
254 scalef = bci->scalef = (double)bci->width / (double)barlen;
255 if (scalef < 0.5) scalef = 0.5;
258 /* The width defaults to "just enough" */
259 bci->width = barlen * scalef + 1;
261 /* But it can be too small, in this case enlarge and center the area */
262 if (bci->width < barlen * scalef) {
263 int wid = barlen * scalef + 1;
264 bci->xoff -= (wid - bci->width)/2 ;
266 /* Can't extend too far on the left */
268 bci->width += -bci->xoff;
273 /* The height defaults to 80 points (rescaled) */
275 bci->height = 80 * scalef;
277 /* If too small (5 + text), reduce the scale factor and center */
278 i = 5 + 10 * ((bci->flags & BARCODE_NO_ASCII)==0);
279 if (bci->height < i * scalef ) {
280 bci->height = i * scalef;
283 gbc = g_new0 (glBarcode, 1);
285 /* Now traverse the code string and create a list of lines */
286 x = bci->margin + (bci->partial[0] - '0') * scalef;
287 for (p = bci->partial + 1, i = 1; *p != 0; p++, i++) {
288 /* special cases: '+' and '-' */
289 if (*p == '+' || *p == '-') {
290 mode = *p; /* don't count it */
294 /* j is the width of this bar/space */
299 if (i % 2) { /* bar */
300 x0 = x + (j * scalef) / 2;
303 if (!(bci->flags & BARCODE_NO_ASCII)) { /* leave space for text */
305 /* text below bars: 10 or 5 points */
306 yr -= (isdigit (*p) ? 10 : 5) * scalef;
308 /* above bars: 10 or 0 from bottom,
311 yr -= (isdigit (*p) ? 20 : 10) * scalef;
314 line = g_new0 (glBarcodeLine, 1);
318 line->width = (j * scalef) - SHRINK_AMOUNT;
319 gbc->lines = g_list_append (gbc->lines, line);
326 mode = '-'; /* reinstantiate default */
327 if (!(bci->flags & BARCODE_NO_ASCII)) {
328 for (p = bci->textinfo; p; p = strchr (p, ' ')) {
333 if (*p == '+' || *p == '-') {
337 if (sscanf (p, "%lf:%lf:%c", &f1, &f2, &c) != 3) {
338 g_message ("impossible data: %s", p);
341 bchar = g_new0 (glBarcodeChar, 1);
342 bchar->x = f1 * scalef + bci->margin;
345 bci->margin + bci->height - 8 * scalef;
347 bchar->y = bci->margin;
349 bchar->fsize = f2 * FONT_SCALE * scalef;
351 gbc->chars = g_list_append (gbc->chars, bchar);
355 /* Fill in other info */
356 gbc->height = bci->height + 2.0 * bci->margin;
357 gbc->width = bci->width + 2.0 * bci->margin;
363 /*--------------------------------------------------------------------------*/
364 /* Validate specific length of string (for subtypes). */
365 /*--------------------------------------------------------------------------*/
367 is_length_valid (const gchar *digits,
378 for (p = (gchar *)digits, i=0; *p != 0; p++) {
379 if (g_ascii_isdigit (*p)) {
384 return (i >= n1) && (i <= n2);
388 /*--------------------------------------------------------------------------*/
389 /* Validate specific length of string (for subtypes). */
390 /*--------------------------------------------------------------------------*/
392 is_length1_valid (const gchar *digits,
403 for (p = (gchar *)digits, i=0; !g_ascii_isspace (*p) && *p != 0; p++) {
404 if (g_ascii_isdigit (*p)) {
409 return (i >= n1) && (i <= n2);
413 /*--------------------------------------------------------------------------*/
414 /* Validate specific length of second string (for subtypes). */
415 /*--------------------------------------------------------------------------*/
417 is_length2_valid (const gchar *digits,
428 for (p = (gchar *)digits; !g_ascii_isspace (*p) && (*p != 0); p++) {
429 /* Skip over 1st string */
432 for (i=0; *p != 0; p++) {
433 if (g_ascii_isdigit (*p)) {
438 return (i >= n1) && (i <= n2);
444 * Local Variables: -- emacs
446 * c-basic-offset: 8 -- emacs
447 * tab-width: 8 -- emacs
448 * indent-tabs-mode: nil -- emacs