guy 3bf951f42c Patch level : 10.0
Files correlati     : pdflib
Ricompilazione Demo : [ ]
Commento            :
Aggiornata pdflib.dll alla versione 7.0.4


git-svn-id: svn://10.65.10.50/trunk@18580 c028cbd2-c16b-5b4b-a496-9718f37d4682
2009-03-23 08:55:58 +00:00

757 lines
21 KiB
C
Executable File

/*---------------------------------------------------------------------------*
| PDFlib - A library for generating PDF on the fly |
+---------------------------------------------------------------------------+
| Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. |
+---------------------------------------------------------------------------+
| |
| This software is subject to the PDFlib license. It is NOT in the |
| public domain. Extended versions and commercial licenses are |
| available, please check http://www.pdflib.com. |
| |
*---------------------------------------------------------------------------*/
/* $Id: p_afm.c,v 1.4 2009-03-23 08:51:17 guy Exp $
*
* PDFlib AFM parsing routines
*
*/
#include "p_intern.h"
#include "p_font.h"
#define AFM_GLYPH_SUPPL 3
#define AFM_LINEBUF 4096
#define AFM_SEPARATORS "\f\n\r\t\v ,:;"
/* The values of each of these enumerated items correspond to an entry in the
* table of strings defined below. Therefore, if you add a new string as
* new keyword into the keyStrings table, you must also add a corresponding
* pdf_afmkey AND it MUST be in the same position!
*
* IMPORTANT: since the sorting algorithm is a binary search, the strings of
* keywords must be placed in lexicographical order, below. [Therefore, the
* enumerated items are not necessarily in lexicographical order, depending
* on the name chosen. BUT, they must be placed in the same position as the
* corresponding key string.] The NOPE shall remain in the last position,
* since it does not correspond to any key string.
*/
#ifndef PDFLIB_EBCDIC
typedef enum
{
ASCENDER,
CHARBBOX,
CODE,
COMPCHAR,
CODEHEX,
CAPHEIGHT,
CHARWIDTH,
CHARACTERSET,
CHARACTERS,
COMMENT,
DESCENDER,
ENCODINGSCHEME,
ENDCHARMETRICS,
ENDCOMPOSITES,
ENDDIRECTION,
ENDFONTMETRICS,
ENDKERNDATA,
ENDKERNPAIRS,
ENDKERNPAIRS0,
ENDKERNPAIRS1,
ENDMASTERFONTMETRICS,
ENDTRACKKERN,
ESCCHAR,
FAMILYNAME,
FONTBBOX,
FONTNAME,
FULLNAME,
ISBASEFONT,
ISCIDFONT,
ISFIXEDPITCH,
ISFIXEDV,
ITALICANGLE,
KERNPAIR,
KERNPAIRHAMT,
KERNPAIRXAMT,
KERNPAIRYAMT,
LIGATURE,
MAPPINGSCHEME,
METRICSSETS,
CHARNAME,
NOTICE,
COMPCHARPIECE,
STARTCHARMETRICS,
STARTCOMPFONTMETRICS,
STARTCOMPOSITES,
STARTDIRECTION,
STARTFONTMETRICS,
STARTKERNDATA,
STARTKERNPAIRS,
STARTKERNPAIRS0,
STARTKERNPAIRS1,
STARTMASTERFONTMETRICS,
STARTTRACKKERN,
STDHW,
STDVW,
TRACKKERN,
UNDERLINEPOSITION,
UNDERLINETHICKNESS,
VVECTOR,
VERSION,
XYWIDTH,
XY0WIDTH,
X0WIDTH,
Y0WIDTH,
XY1WIDTH,
X1WIDTH,
Y1WIDTH,
XWIDTH,
YWIDTH,
WEIGHT,
XHEIGHT,
NOPE
}
pdf_afmkey;
/* keywords for the system:
* This a table of all of the current strings that are vaild AFM keys.
* Each entry can be referenced by the appropriate pdf_afmkey value (an
* enumerated data type defined above). If you add a new keyword here,
* a corresponding pdf_afmkey MUST be added to the enumerated data type
* defined above, AND it MUST be added in the same position as the
* string is in this table.
*
* IMPORTANT: since the sorting algorithm is a binary search, the keywords
* must be placed in lexicographical order. And, NULL should remain at the
* end.
*/
static const char *keyStrings[] =
{
"Ascender",
"B",
"C",
"CC",
"CH",
"CapHeight",
"CharWidth",
"CharacterSet",
"Characters",
"Comment",
"Descender",
"EncodingScheme",
"EndCharMetrics",
"EndComposites",
"EndDirection",
"EndFontMetrics",
"EndKernData",
"EndKernPairs",
"EndKernPairs0",
"EndKernPairs1",
"EndMasterFontMetrics",
"EndTrackKern",
"EscChar",
"FamilyName",
"FontBBox",
"FontName",
"FullName",
"IsBaseFont",
"IsCIDFont",
"IsFixedPitch",
"IsFixedV",
"ItalicAngle",
"KP",
"KPH",
"KPX",
"KPY",
"L",
"MappingScheme",
"MetricsSets",
"N",
"Notice",
"PCC",
"StartCharMetrics",
"StartCompFontMetrics",
"StartComposites",
"StartDirection",
"StartFontMetrics",
"StartKernData",
"StartKernPairs",
"StartKernPairs0",
"StartKernPairs1",
"StartMasterFontMetrics",
"StartTrackKern",
"StdHW",
"StdVW",
"TrackKern",
"UnderlinePosition",
"UnderlineThickness",
"VVector",
"Version",
"W",
"W0",
"W0X",
"W0Y",
"W1",
"W1X",
"W1Y",
"WX",
"WY",
"Weight",
"XHeight"
};
#else /* !PDFLIB_EBCDIC */
#endif /* PDFLIB_EBCDIC */
static pdc_bool
pdf_parse_afm(
PDF *p,
pdc_file *fp,
pdf_font *font,
const char *fontname,
const char *filename)
{
static const char fn[] = "pdf_parse_afm";
fnt_font_metric *ftm = &font->ft.m;
const char *afmtype = NULL;
char **wordlist = NULL, *keyword, *arg1;
char line[AFM_LINEBUF];
int i, cmp, lo, hi, nwords, nglyphs = 0, nline = 0;
int tablen = ((sizeof keyStrings) / (sizeof (char *)));
pdc_sint32 iz;
double dz;
pdc_scalar charwidth = -1;
pdf_afmkey keynumber;
fnt_glyphwidth *glw;
pdc_bool toskip = pdc_false;
pdc_bool is_zadbfont = !strcmp(fontname, "ZapfDingbats");
/* all new glyph names of AGL 2.0 are missing */
font->missingglyphs = 0xFFFFFFFF;
/* read loop. because of Mac files we use pdc_fgetline */
while (pdc_fgetline(line, AFM_LINEBUF, fp) != NULL)
{
/* split line */
nline++;
nwords = pdc_split_stringlist(p->pdc, line, AFM_SEPARATORS, 0,
&wordlist);
if (!nwords) continue;
keyword = wordlist[0];
/* find keynumber */
lo = 0;
hi = tablen;
keynumber = NOPE;
while (lo < hi)
{
i = (lo + hi) / 2;
cmp = strcmp(keyword, keyStrings[i]);
if (cmp == 0)
{
keynumber = (pdf_afmkey) i;
break;
}
if (cmp < 0)
hi = i;
else
lo = i + 1;
}
/* unkown key */
if (keynumber == NOPE)
{
pdc_warning(p->pdc, PDF_E_T1_AFMBADKEY, keyword, filename, 0,0);
goto PDF_PARSECONTD;
}
if (keynumber == ENDDIRECTION)
toskip = pdc_false;
if (nwords == 1 || toskip == pdc_true)
goto PDF_PARSECONTD;
/* key switch */
arg1 = wordlist[1];
switch (keynumber)
{
case STARTDIRECTION:
if (pdc_str2integer(arg1, 0, &iz) != pdc_true)
goto PDF_SYNTAXERROR;
if (iz)
toskip = pdc_true;
break;
case STARTCOMPFONTMETRICS:
afmtype = "ACFM";
goto PDF_SYNTAXERROR;
case STARTMASTERFONTMETRICS:
afmtype = "AMFM";
goto PDF_SYNTAXERROR;
case ISCIDFONT:
afmtype = "CID font";
if (!strcmp(arg1, "true"))
goto PDF_SYNTAXERROR;
break;
case FONTNAME:
font->ft.name = pdc_strdup(p->pdc, arg1);
ftm->name = pdc_strdup(p->pdc, arg1);
pdc_logg_cond(p->pdc, 1, trc_font,
"\tPostScript font name: \"%s\"\n", ftm->name);
break;
/* Recognize Multiple Master fonts by last part of name */
case FAMILYNAME:
if (!strcmp(wordlist[nwords-1], "MM"))
ftm->type = fnt_MMType1;
else
ftm->type = fnt_Type1;
break;
/* Default: FontSpecific */
case ENCODINGSCHEME:
if (!pdc_stricmp(arg1, "StandardEncoding") ||
!pdc_stricmp(arg1, "AdobeStandardEncoding"))
font->ft.issymbfont = pdc_false;
break;
case STDHW:
if (pdc_str2double(arg1, &dz) != pdc_true)
goto PDF_SYNTAXERROR;
ftm->StdHW = (int) dz;
break;
case STDVW:
if (pdc_str2double(arg1, &dz) != pdc_true)
goto PDF_SYNTAXERROR;
ftm->StdVW = (int) dz;
break;
case WEIGHT:
font->ft.weight = fnt_check_weight(fnt_weightname2weight(arg1));
break;
case ISFIXEDPITCH:
if (!pdc_stricmp(arg1, "false"))
ftm->isFixedPitch = pdc_false;
else
ftm->isFixedPitch = pdc_true;
break;
/* New AFM 4.1 keyword "CharWidth" implies fixed pitch */
case CHARWIDTH:
if (pdc_str2double(arg1, &dz) != pdc_true)
goto PDF_SYNTAXERROR;
charwidth = dz;
ftm->isFixedPitch = pdc_true;
break;
case ITALICANGLE:
{
if (pdc_str2double(arg1, &dz) != pdc_true)
goto PDF_SYNTAXERROR;
ftm->italicAngle = dz;
}
break;
case UNDERLINEPOSITION:
if (pdc_str2double(arg1, &dz) != pdc_true)
goto PDF_SYNTAXERROR;
ftm->underlinePosition = (int) dz;
break;
case UNDERLINETHICKNESS:
if (pdc_str2double(arg1, &dz) != pdc_true)
goto PDF_SYNTAXERROR;
ftm->underlineThickness = (int) dz;
break;
case FONTBBOX:
{
if (nwords != 5)
goto PDF_SYNTAXERROR;
for (i = 1; i < nwords; i++)
{
if (pdc_str2double(wordlist[i], &dz) != pdc_true)
goto PDF_SYNTAXERROR;
if (i == 1)
ftm->llx = dz;
else if (i == 2)
ftm->lly = dz;
else if (i == 3)
ftm->urx = dz;
else if (i == 4)
ftm->ury = dz;
}
}
break;
case CAPHEIGHT:
if (pdc_str2double(arg1, &dz) != pdc_true)
goto PDF_SYNTAXERROR;
ftm->capHeight = (int) dz;
break;
case XHEIGHT:
if (pdc_str2double(arg1, &dz) != pdc_true)
goto PDF_SYNTAXERROR;
ftm->xHeight = (int) dz;
break;
case DESCENDER:
if (pdc_str2double(arg1, &dz) != pdc_true)
goto PDF_SYNTAXERROR;
ftm->descender = (int) dz;
break;
case ASCENDER:
if (pdc_str2double(arg1, &dz) != pdc_true)
goto PDF_SYNTAXERROR;
ftm->ascender = (int) dz;
break;
/* Character widths */
case STARTCHARMETRICS:
if (pdc_str2integer(arg1, PDC_INT_UNSIGNED, (pdc_sint32 *) &nglyphs)
!= pdc_true || nglyphs <= 0)
goto PDF_SYNTAXERROR;
ftm->glw = (fnt_glyphwidth *) pdc_calloc(p->pdc,
(size_t) nglyphs * sizeof(fnt_glyphwidth), fn);
break;
/* Character code */
case CODE:
case CODEHEX:
if (!nglyphs || !ftm->glw)
goto PDF_SYNTAXERROR;
if (font->ft.numglyphs >= nglyphs)
{
nglyphs++;
ftm->glw = (fnt_glyphwidth *) pdc_realloc(p->pdc, ftm->glw,
(size_t) nglyphs * sizeof(fnt_glyphwidth), fn);
}
glw = &ftm->glw[font->ft.numglyphs];
if (keynumber == CODE)
{
if (pdc_str2integer(arg1, 0, &iz) != pdc_true)
goto PDF_SYNTAXERROR;
}
else
{
if (pdc_str2integer(arg1, PDC_INT_HEXADEC, &iz) != pdc_true)
goto PDF_SYNTAXERROR;
}
glw->code = (pdc_short) iz;
glw->unicode = 0;
glw->width = (pdc_ushort)
(font->opt.monospace ? font->opt.monospace : charwidth);
font->ft.numglyphs++;
/* Character width and name */
for (i = 2; i < nwords; i++)
{
if (!strcmp(wordlist[i], "WX") ||
!strcmp(wordlist[i], "W0X") ||
!strcmp(wordlist[i], "W"))
{
i++;
if (i == nwords)
goto PDF_SYNTAXERROR;
if (pdc_str2double(wordlist[i], &dz) != pdc_true)
goto PDF_SYNTAXERROR;
glw->width = (pdc_ushort)
(font->opt.monospace ? font->opt.monospace : dz);
}
if (!strcmp(wordlist[i], "N"))
{
i++;
if (i == nwords)
goto PDF_SYNTAXERROR;
/* Unicode value by means of AGL,
* internal and private table
*/
glw->unicode = is_zadbfont ?
(pdc_ushort) pdc_zadb2unicode(wordlist[i]):
pdc_insert_glyphname(p->pdc, wordlist[i]);
pdc_delete_missingglyph_bit(glw->unicode,
&font->missingglyphs);
}
}
break;
default:
break;
}
PDF_PARSECONTD:
pdc_cleanup_stringlist(p->pdc, wordlist);
wordlist = NULL;
if (keynumber == ENDFONTMETRICS)
break;
}
/* necessary font struct members */
if (font->ft.name == NULL || ftm->glw == NULL)
goto PDF_SYNTAXERROR;
pdc_fclose(fp);
ftm->numglwidths = font->ft.numglyphs;
return pdc_true;
PDF_SYNTAXERROR:
pdc_fclose(fp);
pdc_cleanup_stringlist(p->pdc, wordlist);
if (afmtype)
pdc_set_errmsg(p->pdc, PDF_E_T1_UNSUPP_FORMAT, afmtype, 0, 0, 0);
else
pdc_set_errmsg(p->pdc, PDC_E_IO_ILLSYNTAX, "AFM ", filename,
pdc_errprintf(p->pdc, "%d", nline), 0);
return pdc_false;
}
pdc_bool
pdf_process_metrics_data(
PDF *p,
pdf_font *font,
const char *fontname)
{
static const char fn[] = "pdf_process_metrics_data";
fnt_font_metric *ftm = &font->ft.m;
int width = 0;
pdc_ushort uv;
pdc_encoding enc = font->ft.enc;
pdc_encodingvector *ev = NULL;
int nalloc, foundglyphs = 0, i, j = 0, k;
(void) j;
/* Unallowed encoding */
if (enc == pdc_cid || enc < pdc_builtin)
{
pdc_set_errmsg(p->pdc, PDF_E_FONT_BADENC, 0, 0, 0, 0);
return pdc_false;
}
/* Determine the default character width (width of space character) */
if (font->opt.monospace)
{
ftm->defwidth = font->opt.monospace;
}
else
{
width = fnt_get_glyphwidth((int) PDF_DEFAULT_CHAR, &font->ft);
if (width != FNT_MISSING_WIDTH)
ftm->defwidth = width;
else
ftm->defwidth = FNT_DEFAULT_WIDTH;
}
/* builtin font */
if (font->ft.issymbfont == pdc_true && enc != pdc_builtin &&
!strcmp(font->encapiname, "auto"))
{
enc = pdc_builtin;
font->ft.enc = enc;
}
/* optimizing PDF output */
if (enc == pdc_ebcdic ||
enc == pdc_ebcdic_37 ||
enc == pdc_ebcdic_winansi)
font->towinansi = pdc_winansi;
/* glyph name list for incore fonts */
nalloc = font->ft.numglyphs + AFM_GLYPH_SUPPL;
/*
* Generate character width according to the chosen encoding
*/
{
font->ft.numcodes = 256;
font->ft.code2gid = (pdc_ushort *) pdc_calloc(p->pdc,
font->ft.numcodes * sizeof (pdc_ushort), fn);
ftm->numwidths = font->ft.numcodes;
ftm->widths = (int *)pdc_calloc(p->pdc,
font->ft.numcodes * sizeof(int), fn);
/* Given 8-bit encoding */
if (enc >= 0)
{
ev = pdc_get_encoding_vector(p->pdc, enc);
for (k = 0; k < font->ft.numcodes; k++)
{
uv = ev->codes[k];
ftm->widths[k] = ftm->defwidth;
if (uv)
{
uv = pdc_get_alter_glyphname(uv, font->missingglyphs, NULL);
if (uv)
{
for (i = 0; i < ftm->numglwidths; i++)
{
if (ftm->glw[i].unicode == uv)
{
j = i + 1;
ftm->widths[k] = ftm->glw[i].width;
font->ft.code2gid[k] = j;
foundglyphs++;
}
}
}
}
}
if (ftm->ciw != NULL)
{
pdc_free(p->pdc, ftm->ciw);
ftm->ciw = NULL;
}
pdc_logg_cond(p->pdc, 2, trc_font,
"\t\t%d glyphs could be mapped to Unicode\n", foundglyphs);
/* No characters found */
if (!foundglyphs)
{
if (font->ft.issymbfont == pdc_false)
{
pdc_set_errmsg(p->pdc, PDF_E_FONT_BADENC, 0, 0, 0, 0);
return pdc_false;
}
else
{
/* We enforce builtin encoding */
pdc_warning(p->pdc, PDF_E_FONT_FORCEENC,
pdf_get_encoding_name(p, pdc_builtin, font),
0, 0, 0);
enc = pdc_builtin;
font->ft.enc = enc;
font->towinansi = pdc_invalidenc;
}
}
else if (foundglyphs < PDF_MIN_GLYPHS)
{
pdc_warning(p->pdc, PDF_E_FONT_INAPPROPENC,
pdc_errprintf(p->pdc, "%d", foundglyphs), 0, 0, 0);
}
}
/* built-in encoding */
if (enc == pdc_builtin)
{
if (ftm->glw == NULL)
{
pdc_set_errmsg(p->pdc, PDF_E_FONT_BADENC, 0, 0, 0, 0);
return pdc_false;
}
/* encoding for builtin */
ev = pdf_create_font_encoding(p, enc, font, fontname, pdc_true);
font->symenc = font->ft.enc;
/***************************/
font->ft.enc = pdc_builtin;
/***************************/
for (i = 0; i < font->ft.numcodes; i++)
{
ftm->widths[i] = ftm->defwidth;
}
for (i = 0; i < font->ft.numglyphs; i++)
{
pdc_short code = ftm->glw[i].code;
if (code >= 0 && code < font->ft.numcodes)
{
j = i + 1;
ftm->widths[code] = ftm->glw[i].width;
font->ft.code2gid[code] = j;
if (ev != NULL)
{
ev->codes[code] = ftm->glw[i].unicode;
}
}
}
}
}
if (ftm->glw != NULL)
{
pdc_free(p->pdc, ftm->glw);
ftm->glw = NULL;
}
return pdc_true;
}
pdc_bool
pdf_get_metrics_afm(
PDF *p,
pdf_font *font,
const char *fontname,
pdc_encoding enc,
const char *filename,
pdc_bool requested)
{
static const char fn[] = "pdf_get_metrics_afm";
char fullname[PDC_FILENAMELEN];
pdc_file *afmfile;
/* open AFM file */
afmfile = pdc_fsearch_fopen(p->pdc, filename, fullname, "AFM ",
PDC_FILE_TEXT);
if (afmfile == NULL)
return pdc_check_fopen_errmsg(p->pdc, requested);
pdc_logg_cond(p->pdc, 1, trc_font,
"\tLoading AFM metric fontfile \"%s\":\n", fullname);
/* parse AFM file */
if (pdf_parse_afm(p, afmfile, font, fontname, fullname) == pdc_false)
return pdc_false;
/* members not fount */
if (font->ft.m.type == fnt_unknownType)
font->ft.m.type = fnt_Type1;
if (font->ft.name == NULL)
{
font->ft.name = pdc_strdup(p->pdc, fontname);
font->ft.m.name = pdc_strdup(p->pdc, fontname);
}
/* save full filename */
font->metricfilename = pdc_strdup_ext(p->pdc, fullname, 0, fn);
/* process metric data */
font->ft.enc = enc;
if (pdf_process_metrics_data(p, font, fontname) == pdc_false)
return pdc_false;
if (!pdf_make_fontflag(p, font))
return pdc_false;
return pdc_true;
}