/*
- * "$Id: texttops.c,v 1.21 2000/02/25 19:23:30 mike Exp $"
+ * "$Id: texttops.c,v 1.22 2000/02/26 22:56:50 mike Exp $"
*
* Text to PostScript filter for the Common UNIX Printing System (CUPS).
*
* Globals...
*/
-char *Glyphs[65536]; /* PostScript glyphs for Unicode */
+char *Glyphs[65536]; /* PostScript glyphs for Unicode */
+int NumFonts; /* Number of fonts to use */
+char *Fonts[256][4]; /* Fonts to use */
+unsigned short Chars[65536]; /* 0xffcc (ff = font, cc = char) */
+unsigned short Codes[65536]; /* Unicode glyph mapping to fonts */
+int Widths[256]; /* Widths of each font */
+int Directions[256];/* Text directions for each font */
+
/*
* Local functions...
char *user, /* I - Username */
ppd_file_t *ppd) /* I - PPD file info */
{
- int line; /* Current output line */
+ int i, j, k; /* Looping vars */
char *charset; /* Character set string */
char filename[1024]; /* Glyph filenames */
FILE *fp; /* Glyph files */
+ char line[1024], /* Line from file */
+ *lineptr, /* Pointer into line */
+ *valptr; /* Pointer to value in line */
int ch, unicode; /* Character values */
+ int start, end; /* Start and end values for range */
char glyph[64]; /* Glyph name */
- int chars[256]; /* Character encoding array */
time_t curtime; /* Current time */
struct tm *curtm; /* Current date */
char curdate[255]; /* Current date (text format) */
+ int num_fonts; /* Number of unique fonts */
+ char *fonts[1024]; /* Unique fonts */
+ static char *names[] = /* Font names */
+ {
+ "cupsNormal",
+ "cupsBold",
+ "cupsItalic"
+ };
+
+
+ /*
+ * Allocate memory for the page...
+ */
+
+ SizeColumns = (PageRight - PageLeft) / 72.0 * CharsPerInch;
+ SizeLines = (PageTop - PageBottom) / 72.0 * LinesPerInch;
+
+ Page = calloc(sizeof(lchar_t *), SizeLines);
+ Page[0] = calloc(sizeof(lchar_t), SizeColumns * SizeLines);
+ for (i = 1; i < SizeLines; i ++)
+ Page[i] = Page[0] + i * SizeColumns;
+
+ if (PageColumns > 1)
+ {
+ ColumnGutter = CharsPerInch / 2;
+ ColumnWidth = (SizeColumns - ColumnGutter * (PageColumns - 1)) /
+ PageColumns;
+ }
+ else
+ ColumnWidth = SizeColumns;
+ /*
+ * Output the DSC header...
+ */
curtime = time(NULL);
curtm = localtime(&curtime);
printf("%%%%CreationDate: %s\n", curdate);
printf("%%%%Title: %s\n", title);
printf("%%%%For: %s\n", user);
- if (PrettyPrint)
- puts("%%DocumentNeededResources: font Courier Courier-Bold Courier-Oblique");
- else
- puts("%%DocumentNeededResources: font Courier Courier-Bold");
- puts("%%DocumentSuppliedResources: procset texttops 1.0 0");
+ puts("%%DocumentSuppliedResources: procset texttops 1.1 0");
puts("%%Pages: (atend)");
- puts("%%EndComments");
+ /*
+ * Initialize globals...
+ */
- SizeColumns = (PageRight - PageLeft) / 72.0 * CharsPerInch;
- SizeLines = (PageTop - PageBottom) / 72.0 * LinesPerInch;
+ NumFonts = 0;
+ memset(Fonts, 0, sizeof(Fonts));
+ memset(Glyphs, 0, sizeof(Glyphs));
+ memset(Chars, 0, sizeof(Chars));
+ memset(Codes, 0, sizeof(Codes));
- Page = calloc(sizeof(lchar_t *), SizeLines);
- Page[0] = calloc(sizeof(lchar_t), SizeColumns * SizeLines);
- for (line = 1; line < SizeLines; line ++)
- Page[line] = Page[0] + line * SizeColumns;
+ /*
+ * Load the PostScript glyph names and the corresponding character
+ * set definition...
+ */
- if (PageColumns > 1)
+ if ((fp = fopen(CUPS_DATADIR "/data/psglyphs", "r")) != NULL)
{
- ColumnGutter = CharsPerInch / 2;
- ColumnWidth = (SizeColumns - ColumnGutter * (PageColumns - 1)) /
- PageColumns;
+ while (fscanf(fp, "%x%63s", &unicode, glyph) == 2)
+ Glyphs[unicode] = strdup(glyph);
+
+ fclose(fp);
}
else
- ColumnWidth = SizeColumns;
+ {
+ perror("ERROR: Unable to open " CUPS_DATADIR "/data/psglyphs");
+ exit(1);
+ }
/*
- * Get the output character set; if it is undefined or "us-ascii", do
- * nothing because we can use the default encoding...
+ * Get the output character set...
*/
- puts("%%BeginProlog");
- puts("%%BeginResource: procset texttops 1.0 0");
-
charset = getenv("CHARSET");
if (charset != NULL && strcmp(charset, "us-ascii") != 0)
{
+ snprintf(filename, sizeof(filename), CUPS_DATADIR "/charsets/%s", charset);
+
+ if ((fp = fopen(filename, "r")) == NULL)
+ {
+ /*
+ * Can't open charset file!
+ */
+
+ fprintf(stderr, "ERROR: Unable to open %s: %s\n", filename,
+ strerror(errno));
+ exit(1);
+ }
+
/*
- * Load the PostScript glyph names and the corresponding character
- * set definition...
+ * Opened charset file; now see if this is really a charset file...
*/
- memset(Glyphs, 0, sizeof(Glyphs));
+ if (fgets(line, sizeof(line), fp) == NULL)
+ {
+ /*
+ * Bad/empty charset file!
+ */
- if ((fp = fopen(CUPS_DATADIR "/data/psglyphs", "r")) != NULL)
+ fclose(fp);
+ fprintf(stderr, "ERROR: Bad/empty charset file %s\n", filename);
+ exit(1);
+ }
+
+ if (strncmp(line, "charset", 7) != 0)
{
- while (fscanf(fp, "%x%63s", &unicode, glyph) == 2)
- Glyphs[unicode] = strdup(glyph);
+ /*
+ * Bad format/not a charset file!
+ */
fclose(fp);
+ fprintf(stderr, "ERROR: Bad charset file %s\n", filename);
+ exit(1);
}
- if (strncmp(charset, "iso-", 4) == 0)
+ /*
+ * See if this is an 8-bit or UTF-8 character set file...
+ */
+
+ line[strlen(line) - 1] = '\0'; /* Drop \n */
+ for (lineptr = line + 7; isspace(*lineptr); lineptr ++); /* Skip whitespace */
+
+ if (strcmp(lineptr, "8bit") == 0)
{
- memset(chars, 0, sizeof(chars));
+ /*
+ * 8-bit text...
+ */
+
+ UTF8 = 0;
+ NumFonts = 1;
+
+ /*
+ * Read the font description...
+ */
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ {
+ /*
+ * Skip comment and blank lines...
+ */
+
+ if (line[0] != '#' && line[0] != '\n')
+ break;
+ }
- snprintf(filename, sizeof(filename), CUPS_DATADIR "/data/%s", charset + 4);
+ /*
+ * Read the font descriptions that should look like:
+ *
+ * direction width normal [bold italic bold-italic]
+ */
- if ((fp = fopen(filename, "r")) != NULL)
+ lineptr = line;
+ while (isspace(*lineptr))
+ lineptr ++;
+
+ valptr = lineptr;
+
+ while (!isspace(*lineptr) && *lineptr)
+ lineptr ++;
+
+ if (!*lineptr)
{
- while (fscanf(fp, "%x%x", &ch, &unicode) == 2)
- chars[ch] = unicode;
+ /*
+ * Can't have a font without all required values...
+ */
- fclose(fp);
+ fprintf(stderr, "ERROR: bad font description line: %s\n", valptr);
+ fclose(fp);
+ exit(1);
}
+
+ *lineptr++ = '\0';
+
+ if (strcmp(valptr, "ltor") == 0)
+ Directions[0] = 1;
+ else if (strcmp(valptr, "rtol") == 0)
+ Directions[0] = -1;
else
+ {
+ fprintf(stderr, "ERROR: Bad text direction %s\n", valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ /*
+ * Got the direction, now get the width...
+ */
+
+ while (isspace(*lineptr))
+ lineptr ++;
+
+ valptr = lineptr;
+
+ while (!isspace(*lineptr) && *lineptr)
+ lineptr ++;
+
+ if (!*lineptr)
{
/*
- * Fall back to ISO-8859-1...
+ * Can't have a font without all required values...
*/
- for (ch = 0; ch < 256; ch ++)
- chars[ch] = ch;
+ fprintf(stderr, "ERROR: bad font description line: %s\n", valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ *lineptr++ = '\0';
+
+ if (strcmp(valptr, "single") == 0)
+ Widths[0] = 1;
+ else if (strcmp(valptr, "double") == 0)
+ Widths[0] = 2;
+ else
+ {
+ fprintf(stderr, "ERROR: Bad text width %s\n", valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ /*
+ * Get the fonts...
+ */
+
+ for (i = 0; *lineptr && i < 4; i ++)
+ {
+ while (isspace(*lineptr))
+ lineptr ++;
+
+ valptr = lineptr;
+
+ while (!isspace(*lineptr) && *lineptr)
+ lineptr ++;
+
+ if (*lineptr)
+ *lineptr++ = '\0';
+
+ if (lineptr > valptr)
+ Fonts[0][i] = strdup(valptr);
}
+
+ /*
+ * Fill in remaining fonts as needed...
+ */
+
+ for (j = i; j < 4; j ++)
+ Fonts[0][j] = strdup(Fonts[0][0]);
+
+ /*
+ * Read encoding lines...
+ */
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ {
+ /*
+ * Skip comment and blank lines...
+ */
+
+ if (line[0] == '#' || line[0] == '\n')
+ continue;
+
+ /*
+ * Grab the character and unicode glyph number.
+ */
+
+ if (sscanf(line, "%x%x", &ch, &unicode) == 2 && ch < 256)
+ {
+ Codes[ch] = unicode;
+ Chars[ch] = ch;
+ }
+ }
+
+ fclose(fp);
}
- else
+ else if (strcmp(lineptr, "utf8") == 0)
{
/*
- * UTF-8 encoding - just pass the first 256 characters for now...
+ * UTF-8 (Unicode) text...
*/
UTF8 = 1;
- for (unicode = 0; unicode < 256; unicode ++)
- chars[unicode] = unicode;
+ /*
+ * Read the font descriptions...
+ */
+
+ NumFonts = 0;
+
+ while (fgets(line, sizeof(line), fp) != NULL)
+ {
+ /*
+ * Skip comment and blank lines...
+ */
+
+ if (line[0] == '#' || line[0] == '\n')
+ continue;
+
+ /*
+ * Read the font descriptions that should look like:
+ *
+ * start end direction width normal [bold italic bold-italic]
+ */
+
+ lineptr = line;
+
+ start = strtol(lineptr, &lineptr, 16);
+ end = strtol(lineptr, &lineptr, 16);
+
+ while (isspace(*lineptr))
+ lineptr ++;
+
+ valptr = lineptr;
+
+ while (!isspace(*lineptr) && *lineptr)
+ lineptr ++;
+
+ if (!*lineptr)
+ {
+ /*
+ * Can't have a font without all required values...
+ */
+
+ fprintf(stderr, "ERROR: bad font description line: %s\n", valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ *lineptr++ = '\0';
+
+ if (strcmp(valptr, "ltor") == 0)
+ Directions[NumFonts] = 1;
+ else if (strcmp(valptr, "rtol") == 0)
+ Directions[NumFonts] = -1;
+ else
+ {
+ fprintf(stderr, "ERROR: Bad text direction %s\n", valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ /*
+ * Got the direction, now get the width...
+ */
+
+ while (isspace(*lineptr))
+ lineptr ++;
+
+ valptr = lineptr;
+
+ while (!isspace(*lineptr) && *lineptr)
+ lineptr ++;
+
+ if (!*lineptr)
+ {
+ /*
+ * Can't have a font without all required values...
+ */
+
+ fprintf(stderr, "ERROR: bad font description line: %s\n", valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ *lineptr++ = '\0';
+
+ if (strcmp(valptr, "single") == 0)
+ Widths[NumFonts] = 1;
+ else if (strcmp(valptr, "double") == 0)
+ Widths[NumFonts] = 2;
+ else
+ {
+ fprintf(stderr, "ERROR: Bad text width %s\n", valptr);
+ fclose(fp);
+ exit(1);
+ }
+
+ /*
+ * Get the fonts...
+ */
+
+ for (i = 0; *lineptr && i < 4; i ++)
+ {
+ while (isspace(*lineptr))
+ lineptr ++;
+
+ valptr = lineptr;
+
+ while (!isspace(*lineptr) && *lineptr)
+ lineptr ++;
+
+ if (*lineptr)
+ *lineptr++ = '\0';
+
+ if (lineptr > valptr)
+ Fonts[NumFonts][i] = strdup(valptr);
+ }
+
+ /*
+ * Fill in remaining fonts as needed...
+ */
+
+ for (j = i; j < 4; j ++)
+ Fonts[NumFonts][j] = strdup(Fonts[NumFonts][0]);
+
+ /*
+ * Define the character mappings...
+ */
+
+ for (i = start, j = NumFonts * 256; i <= end; i ++, j ++)
+ {
+ Chars[i] = j;
+ Codes[j] = i;
+ }
+
+ /*
+ * Move to the next font, stopping if needed...
+ */
+
+ NumFonts ++;
+ if (NumFonts >= 256)
+ break;
+ }
+
+ fclose(fp);
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: Bad charset type %s\n", lineptr);
+ fclose(fp);
+ exit(1);
}
+ }
+ else
+ {
+ /*
+ * Standard ASCII output just uses Courier, Courier-Bold, and
+ * possibly Courier-Oblique.
+ */
+
+ NumFonts = 1;
+
+ Fonts[0][ATTR_NORMAL] = strdup("Courier");
+ Fonts[0][ATTR_BOLD] = strdup("Courier-Bold");
+ Fonts[0][ATTR_ITALIC] = strdup("Courier-Oblique");
+ Fonts[0][ATTR_BOLDITALIC] = strdup("Courier-BoldOblique");
+
+ Widths[0] = 1;
+ Directions[0] = 1;
/*
- * Write the encoding array...
+ * Define US-ASCII characters...
*/
- printf("%% %s encoding\n", charset);
- puts("/textEncoding [");
+ for (i = 32; i < 127; i ++)
+ {
+ Chars[i] = i;
+ Codes[i] = i;
+ }
+ }
+
+ /*
+ * Generate a list of unique fonts to use...
+ */
+
+ for (i = 0, num_fonts = 0; i < NumFonts; i ++)
+ for (j = 1 + PrettyPrint; j >= 0; j --)
+ {
+ for (k = 0; k < num_fonts; k ++)
+ if (strcmp(Fonts[i][j], fonts[k]) == 0)
+ break;
+
+ if (k >= num_fonts)
+ {
+ /*
+ * Add new font...
+ */
+
+ fonts[num_fonts] = Fonts[i][j];
+ num_fonts ++;
+ }
+ }
+
+ /*
+ * List the fonts that will be used...
+ */
+
+ for (i = 0; i < num_fonts; i ++)
+ if (i == 0)
+ printf("%%DocumentNeededResources: font %s\n", fonts[i]);
+ else
+ printf("%%+ font %s\n", fonts[i]);
+
+ puts("%%EndComments");
+
+ puts("%%BeginProlog");
+
+ /*
+ * Write the encoding array(s)...
+ */
+
+ puts("% character encoding(s)");
+
+ for (i = 0; i < NumFonts; i ++)
+ {
+ printf("/cupsEncoding%02x [\n", i);
for (ch = 0; ch < 256; ch ++)
{
- if (Glyphs[chars[ch]])
- printf("/%s", Glyphs[chars[ch]]);
+ if (Glyphs[Codes[i * 256 + ch]])
+ printf("/%s", Glyphs[Codes[i * 256 + ch]]);
else
printf("/.notdef");
if ((ch & 7) == 7)
- putchar('\n');
+ putchar('\n');
}
puts("] def");
+ }
+
+ /*
+ * Create the fonts...
+ */
+
+ if (NumFonts == 1)
+ {
+ /*
+ * Just reencode the named fonts...
+ */
puts("% Reencode fonts");
- puts("/Courier findfont");
- puts("dup length dict begin\n"
- " { 1 index /FID ne { def } { pop pop } ifelse } forall\n"
- " /Encoding textEncoding def\n"
- " currentdict\n"
- "end");
- puts("/Courier exch definefont pop");
-
- puts("/Courier-Bold findfont");
- puts("dup length dict begin\n"
- " { 1 index /FID ne { def } { pop pop } ifelse } forall\n"
- " /Encoding textEncoding def\n"
- " currentdict\n"
- "end");
- puts("/Courier-Bold exch definefont pop");
-
- if (PrettyPrint)
+
+ for (i = 1 + PrettyPrint; i >= 0; i --)
{
- puts("/Courier-Oblique findfont");
+ printf("/%s findfont\n", Fonts[0][i]);
puts("dup length dict begin\n"
- " { 1 index /FID ne { def } { pop pop } ifelse } forall\n"
- " /Encoding textEncoding def\n"
- " currentdict\n"
- "end");
- puts("/Courier-Oblique exch definefont pop");
+ " { 1 index /FID ne { def } { pop pop } ifelse } forall\n"
+ " /Encoding cupsEncoding00 def\n"
+ " currentdict\n"
+ "end");
+ printf("/%s exch definefont pop\n", names[i]);
+ }
+ }
+ else
+ {
+ /*
+ * Construct composite fonts... Start by reencoding the base fonts...
+ */
+
+ puts("% Reencode base fonts");
+
+ for (i = 1 + PrettyPrint; i >= 0; i --)
+ for (j = 0; j < NumFonts; j ++)
+ {
+ printf("/%s findfont\n", Fonts[j][i]);
+ printf("dup length dict begin\n"
+ " { 1 index /FID ne { def } { pop pop } ifelse } forall\n"
+ " /Encoding cupsEncoding%02x def\n"
+ " currentdict\n"
+ "end\n", j);
+ printf("/%s%02x exch definefont pop\n", names[i], j);
+ }
+
+ /*
+ * Then merge them into composite fonts...
+ */
+
+ for (i = 1 + PrettyPrint; i >= 0; i --)
+ {
+ printf("/%s 6 dict begin", names[i]);
+ puts("/FMapType 3 def/Encoding[");
+ for (j = 0; j < NumFonts; j ++)
+ if (j == (NumFonts - 1))
+ printf("%d", j);
+ else if ((j & 15) == 15)
+ printf("%d\n", j);
+ else
+ printf("%d ", j);
+ puts("]def/FDepVector[");
+ for (j = 0; j < NumFonts; j ++)
+ if (j == (NumFonts - 1))
+ printf("/%s%02x", names[i], j);
+ else if ((j & 3) == 3)
+ printf("/%s%02x\n", names[i], j);
+ else
+ printf("/%s%02x ", names[i], j);
+ puts("]def end definefont pop");
}
}
+ /*
+ * Output the texttops procset...
+ */
+
+ puts("%%BeginResource: procset texttops 1.1 0");
+
puts("% Define fonts");
- printf("/FN /Courier findfont [%.1f 0 0 %.1f 0 0] makefont def\n",
+ printf("/FN /cupsNormal findfont [%.1f 0 0 %.1f 0 0] makefont def\n",
120.0 / CharsPerInch, 68.0 / LinesPerInch);
- printf("/FB /Courier-Bold findfont [%.1f 0 0 %.1f 0 0] makefont def\n",
+ printf("/FB /cupsBold findfont [%.1f 0 0 %.1f 0 0] makefont def\n",
120.0 / CharsPerInch, 68.0 / LinesPerInch);
if (PrettyPrint)
- printf("/FI /Courier-Oblique findfont [%.1f 0 0 %.1f 0 0] makefont def\n",
+ printf("/FI /cupsItalic findfont [%.1f 0 0 %.1f 0 0] makefont def\n",
120.0 / CharsPerInch, 68.0 / LinesPerInch);
puts("% Common procedures");
lchar_t *s) /* I - String to print */
{
int i; /* Looping var */
+ int ch; /* Current character */
float x, y; /* Position of text */
unsigned attr; /* Character attributes */
+ int font; /* Current font */
/*
printf(" %.1f U", (float)len * 72.0 / (float)CharsPerInch);
/*
- * See if the string contains 16-bit characters...
+ * Write a quoted string...
*/
- for (i = 0; i < len; i ++)
- if (s[i].ch > 255)
- break;
-
- if (i < len)
- {
- /*
- * Write a hex Unicode string...
- */
+ font = 0;
- fputs("<feff", stdout);
+ putchar('(');
- while (len > 0)
- {
- printf("%04x", s->ch);
- len --;
- s ++;
- }
-
- putchar('>');
- }
- else
+ while (len > 0)
{
- /*
- * Write a quoted string...
- */
+ ch = Chars[s->ch];
- putchar('(');
-
- while (len > 0)
+ if ((ch / 256) != font)
{
- if (s->ch > 126)
- {
- /*
- * Quote 8-bit characters...
- */
-
- printf("\\%03o", s->ch);
- }
+ font = ch / 256;
+ printf("\\377");
+ if (font > 126 || font < 32)
+ printf("\\%03o", font);
else
{
- /*
- * Quote the parenthesis and backslash as needed...
- */
-
- if (s->ch == '(' || s->ch == ')' || s->ch == '\\')
+ if (ch == '(' || ch == ')' || ch == '\\')
putchar('\\');
- putchar(s->ch);
+ putchar(font);
}
+ }
- len --;
- s ++;
+ if (ch < 32 || ch > 126)
+ {
+ /*
+ * Quote 8-bit and control characters...
+ */
+
+ printf("\\%03o", ch);
+ }
+ else
+ {
+ /*
+ * Quote the parenthesis and backslash as needed...
+ */
+
+ if (ch == '(' || ch == ')' || ch == '\\')
+ putchar('\\');
+
+ putchar(ch);
}
- putchar(')');
+ len --;
+ s ++;
}
+ putchar(')');
+
if (PrettyPrint)
{
if (attr & ATTR_RED)
/*
- * End of "$Id: texttops.c,v 1.21 2000/02/25 19:23:30 mike Exp $".
+ * End of "$Id: texttops.c,v 1.22 2000/02/26 22:56:50 mike Exp $".
*/