2 * ps.c -- printing the "partial" bar encoding
4 * Copyright (c) 1999 Alessandro Rubini (rubini@gnu.org)
5 * Copyright (c) 1999 Prosa Srl. (prosa@prosa.it)
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.
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.
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.
30 #define SHRINK_AMOUNT 0.15 /* shrink the bars to account for ink spreading */
34 * How do the "partial" and "textinfo" strings work?
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.
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
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.
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.
62 int Barcode_ps_print(struct Barcode_Item *bc, FILE *f)
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;
71 if (!bc->partial || !bc->textinfo) {
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
82 /* First, calculate barlen */
83 barlen = bc->partial[0] - '0';
84 for (ptr = bc->partial+1; *ptr; ptr++)
86 barlen += (*ptr - '0');
87 else if (islower(*ptr))
88 barlen += (*ptr - 'a'+1);
90 /* The scale factor depends on bar length */
92 if (!bc->width) bc->width = barlen; /* default */
93 scalef = bc->scalef = (double)bc->width / (double)barlen;
96 /* The width defaults to "just enough" */
97 if (!bc->width) bc->width = barlen * scalef +1;
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 ;
104 /* Can't extend too far on the left */
106 bc->width += -bc->xoff;
111 /* The height defaults to 80 points (rescaled) */
112 if (!bc->height) bc->height = 80 * scalef;
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;
122 bc->height += -bc->yoff;
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;
139 * Ok, then deal with actual ps (eps) output
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");
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",
152 bc->xoff + bc->width + 2* bc->margin,
153 bc->yoff + bc->height + 2* bc->margin);
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");
162 /* Print some informative comments */
163 for (i=0; bc->ascii[i]; i++)
164 if (bc->ascii[i] < ' ')
167 fprintf(f,"%% Printing barcode for \"%s\", scaled %5.2f",
168 printable ? bc->ascii : "<unprintable string>", scalef);
170 fprintf(f,", encoded using \"%s\"",bc->encoding);
172 fprintf(f,"%% The space/bar succession is represented "
173 "by the following widths (space first):\n"
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);
181 /* open array for "forall" */
182 fprintf(f, "\n[\n%% height xpos ypos width"
183 " height xpos ypos width\n");
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;
191 /* j is the width of this bar/space */
192 if (isdigit (*ptr)) j = *ptr-'0';
195 x0 = bc->xoff + xpos + (j*scalef)/2;
196 y0 = bc->yoff + bc->margin;
198 if (!(bc->flags & BARCODE_NO_ASCII)) { /* leave space for text */
200 /* text below bars: 10 points or five points */
201 y0 += (isdigit(*ptr) ? 10 : 5) * scalef;
202 yr -= (isdigit(*ptr) ? 10 : 5) * scalef;
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;
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");
216 fprintf(f,"\n]\t{ {} forall setlinewidth moveto 0 exch rlineto stroke} "
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++;
228 if (*ptr == '+' || *ptr == '-') {
229 mode = *ptr; continue;
231 if (sscanf(ptr, "%lf:%lf:%c", &f1, &f2, &c) != 3) {
232 fprintf(stderr, "barcode: impossible data: %s\n", ptr);
237 /* Both the backslash and the two parens are special */
238 if (c=='\\' || c==')' || c=='(')
239 fprintf(f, "\\%c) ", c);
241 fprintf(f, "%c) ", c);
242 fprintf(f, "%6.2f %6.2f %5.2f]\n",
243 bc->xoff + f1 * scalef + bc->margin,
245 ? (double)bc->yoff + bc->margin
246 : (double)bc->yoff + bc->margin+bc->height - 8*scalef,
247 fsav == f2 ? 0.0 : f2 * scalef);
250 fprintf(f,"] { {} forall dup 0.00 ne {\n\t"
251 "/Helvetica findfont exch scalefont setfont\n"
253 " moveto show} bind forall\n");
258 fprintf(f,"%% End barcode for \"%s\"\n\n",
259 printable ? bc->ascii : "<unprintable string>");
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");