]> git.sur5r.net Git - glabels/blob - glabels2/barcode-0.98/ps.c
2007-04-30 Jim Evins <evins@snaught.com>
[glabels] / glabels2 / barcode-0.98 / ps.c
1 /*
2  * ps.c -- printing the "partial" bar encoding
3  *
4  * Copyright (c) 1999 Alessandro Rubini (rubini@gnu.org)
5  * Copyright (c) 1999 Prosa Srl. (prosa@prosa.it)
6  *
7  *   This program 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 2 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program 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.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, write to the Free Software
19  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <errno.h>
27
28 #include "barcode.h"
29
30 #define SHRINK_AMOUNT 0.15 /* shrink the bars to account for ink spreading */
31
32
33 /*
34  * How do the "partial" and "textinfo" strings work?
35  *
36  * The first char in "partial" tells how much extra space to add to the
37  * left of the bars. For EAN-13, it is used to leave space to print the
38  * first digit, other codes may have '0' for no-extra-space-needed.
39  *
40  * The next characters are alternating bars and spaces, as multiples
41  * of the base dimension which is 1 unless the code is
42  * rescaled. Rescaling is calculated as the ratio from the requested
43  * width and the calculated width.  Digits represent bar/space
44  * dimensions. Lower-case letters represent those bars that should
45  * extend lower than the others: 'a' is equivalent to '1', 'b' is '2' and
46  * so on.
47  *
48  * The "textinfo" string is made up of fields "%lf:%lf:%c" separated by
49  * blank space. The first integer is the x position of the character,
50  * the second is the font size (before rescaling) and the char item is
51  * the charcter to be printed.
52  *
53  * Both the "partial" and "textinfo" strings may include "-" or "+" as
54  * special characters (in "textinfo" the char should be a standalone
55  * word).  They state where the text should be printed: below the bars
56  * ("-", default) or above the bars. This is used, for example, to
57  * print the add-5 and add-2 codes to the right of UPC or EAN codes
58  * (the add-5 extension is mostly used in ISBN codes.
59  */
60
61
62 int Barcode_ps_print(struct Barcode_Item *bc, FILE *f)
63 {
64     int i, j, k, barlen, printable=1;
65     double f1, f2, fsav=0;
66     int mode = '-'; /* text below bars */
67     double scalef=1, xpos, x0, y0, yr;
68     unsigned char *ptr;
69     unsigned char c;
70
71     if (!bc->partial || !bc->textinfo) {
72         bc->error = EINVAL;
73         return -1;
74     }
75
76
77     /*
78      * Maybe this first part can be made common to several printing back-ends,
79      * we'll see how that works when other ouput engines are added
80      */
81
82     /* First, calculate barlen */
83     barlen = bc->partial[0] - '0';
84     for (ptr = bc->partial+1; *ptr; ptr++)
85         if (isdigit(*ptr)) 
86             barlen += (*ptr - '0');
87         else if (islower(*ptr))
88             barlen += (*ptr - 'a'+1);
89
90     /* The scale factor depends on bar length */
91     if (!bc->scalef) {
92         if (!bc->width) bc->width = barlen; /* default */
93         scalef = bc->scalef = (double)bc->width / (double)barlen;
94     }
95
96     /* The width defaults to "just enough" */
97     if (!bc->width) bc->width = barlen * scalef +1;
98
99     /* But it can be too small, in this case enlarge and center the area */
100     if (bc->width < barlen * scalef) {
101         int wid = barlen * scalef + 1;
102         bc->xoff -= (wid - bc->width)/2 ;
103         bc->width = wid;
104         /* Can't extend too far on the left */
105         if (bc->xoff < 0) {
106             bc->width += -bc->xoff;
107             bc->xoff = 0;
108         }
109     }
110
111     /* The height defaults to 80 points (rescaled) */
112     if (!bc->height) bc->height = 80 * scalef;
113
114 #if 0
115     /* If too small (5 + text), enlarge and center */
116     i = 5 + 10 * ((bc->flags & BARCODE_NO_ASCII)==0);
117     if (bc->height < i * scalef ) {
118         int hei = i * scalef;
119         bc->yoff -= (hei-bc->height)/2;
120         bc->height = hei;
121         if (bc->yoff < 0) {
122             bc->height += -bc->yoff;
123             bc->yoff = 0;
124         }
125     }
126 #else
127     /* If too small (5 + text), reduce the scale factor and center */
128     i = 5 + 10 * ((bc->flags & BARCODE_NO_ASCII)==0);
129     if (bc->height < i * scalef ) {
130         double scaleg = ((double)bc->height) / i;
131         int wid = bc->width * scaleg / scalef;
132         bc->xoff += (bc->width - wid)/2;
133         bc->width = wid;
134         scalef = scaleg;
135     }
136 #endif
137
138     /*
139      * Ok, then deal with actual ps (eps) output
140      */
141
142     if (!(bc->flags & BARCODE_OUT_NOHEADERS)) { /* spit a header first */
143         if (bc->flags & BARCODE_OUT_EPS) 
144             fprintf(f, "%%!PS-Adobe-2.0 EPSF-1.2\n");
145         else
146             fprintf(f, "%%!PS-Adobe-2.0\n");
147         fprintf(f, "%%%%Creator: libbarcode\n");
148         if (bc->flags & BARCODE_OUT_EPS)  {
149             fprintf(f, "%%%%BoundingBox: %i %i %i %i\n",
150                     bc->xoff,
151                     bc->yoff,
152                     bc->xoff + bc->width + 2* bc->margin,
153                     bc->yoff + bc->height + 2* bc->margin);
154         }
155         fprintf(f, "%%%%EndComments\n");
156         if (bc->flags & BARCODE_OUT_PS)  {
157             fprintf(f, "%%%%EndProlog\n\n");
158             fprintf(f, "%%%%Page: 1 1\n\n");
159         }
160     }
161
162     /* Print some informative comments */
163     for (i=0; bc->ascii[i]; i++)
164         if (bc->ascii[i] < ' ')
165             printable = 0;
166
167     fprintf(f,"%% Printing barcode for \"%s\", scaled %5.2f",
168             printable ? bc->ascii : "<unprintable string>", scalef);
169     if (bc->encoding)
170         fprintf(f,", encoded using \"%s\"",bc->encoding);
171     fprintf(f, "\n");
172     fprintf(f,"%% The space/bar succession is represented "
173             "by the following widths (space first):\n"
174             "%% ");
175     for (i=0; i<strlen(bc->partial); i++) {
176         unsigned char c = bc->partial[i];
177         if (isdigit(c)) putc(c, f);
178         if (islower(c)) putc(c-'a'+'1', f);
179         if (isupper(c)) putc(c-'A'+'1', f);
180     }
181     /* open array for "forall" */
182     fprintf(f, "\n[\n%%  height  xpos   ypos  width"
183                  "       height  xpos   ypos  width\n");
184
185     xpos = bc->margin + (bc->partial[0]-'0') * scalef;
186     for (ptr = bc->partial+1, i=1; *ptr; ptr++, i++) {
187         /* special cases: '+' and '-' */
188         if (*ptr == '+' || *ptr == '-') {
189             mode = *ptr; /* don't count it */ i++; continue;
190         }
191         /* j is the width of this bar/space */
192         if (isdigit (*ptr))   j = *ptr-'0';
193         else                  j = *ptr-'a'+1;
194         if (i%2) { /* bar */
195             x0 = bc->xoff + xpos + (j*scalef)/2;
196             y0 = bc->yoff + bc->margin;
197             yr = bc->height;
198             if (!(bc->flags & BARCODE_NO_ASCII)) { /* leave space for text */
199                 if (mode == '-') {
200                     /* text below bars: 10 points or five points */
201                     y0 += (isdigit(*ptr) ? 10 : 5) * scalef;
202                     yr -= (isdigit(*ptr) ? 10 : 5) * scalef;
203                 } else { /* '+' */
204                     /* text above bars: 10 or 0 from bottom, and 10 from top */
205                     y0 += (isdigit(*ptr) ? 10 : 0) * scalef;
206                     yr -= (isdigit(*ptr) ? 20 : 10) * scalef; 
207                 }
208             }
209             /* Define an array and then use "forall" (Hans Schou) */
210             fprintf(f,"   [%5.2f %6.2f %6.2f %5.2f]%s",
211                     yr, x0, y0, (j * scalef) - SHRINK_AMOUNT,
212                     i%4 == 1 ? "   " : "\n");
213         }
214         xpos += j * scalef;
215     }
216     fprintf(f,"\n]\t{ {} forall setlinewidth moveto 0 exch rlineto stroke} "
217             "bind forall\n");
218
219     /* Then, the text */
220
221     mode = '-'; /* reinstantiate default */
222     if (!(bc->flags & BARCODE_NO_ASCII)) {
223         fprintf(f, "[\n%%   char    xpos   ypos fontsize\n");
224         k=0; /* k is the "previous font size" */
225         for (ptr = bc->textinfo; ptr; ptr = strchr(ptr, ' ')) {
226             while (*ptr == ' ') ptr++;
227             if (!*ptr) break;
228             if (*ptr == '+' || *ptr == '-') {
229                 mode = *ptr; continue;
230             }
231             if (sscanf(ptr, "%lf:%lf:%c", &f1, &f2, &c) != 3) {
232                 fprintf(stderr, "barcode: impossible data: %s\n", ptr);
233                 continue;
234             }
235
236             fprintf(f, "    [(");
237             /* Both the backslash and the two parens are special */
238             if (c=='\\' || c==')' || c=='(')
239                 fprintf(f, "\\%c) ", c);
240             else
241                 fprintf(f, "%c)  ", c);
242             fprintf(f, "%6.2f %6.2f %5.2f]\n", 
243                     bc->xoff + f1 * scalef + bc->margin,
244                     mode == '-'
245                        ? (double)bc->yoff + bc->margin
246                        : (double)bc->yoff + bc->margin+bc->height - 8*scalef,
247                     fsav == f2 ? 0.0 : f2 * scalef);
248             fsav = f2;
249         }
250         fprintf(f,"]   { {} forall dup 0.00 ne {\n\t"
251                 "/Helvetica findfont exch scalefont setfont\n"
252                 "    } {pop} ifelse\n"
253                 "    moveto show} bind forall\n");
254         
255
256     }
257
258     fprintf(f,"%% End barcode for \"%s\"\n\n",
259             printable ? bc->ascii : "<unprintable string>");
260
261     if (!(bc->flags & BARCODE_OUT_NOHEADERS)) {
262         if (bc->flags & BARCODE_OUT_PS)  {
263             fprintf(f,"showpage\n");
264             fprintf(f, "%%%%Trailer\n\n");
265         }
266     }
267     return 0;
268 }
269
270
271
272