X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=pdf2swf%2FSWFOutputDev.cc;h=8e93f5de6ae4c45789dd60ebaf43614fdf2302ea;hb=377ede4ea24974fde5de2a44bd060e6d87dd8bd5;hp=193dd44898c5e22d1bf94e51dd874571114d9e4f;hpb=89a58fa0255a580a615cb1d0e62236cb9d882fcd;p=swftools.git diff --git a/pdf2swf/SWFOutputDev.cc b/pdf2swf/SWFOutputDev.cc index 193dd44..8e93f5d 100644 --- a/pdf2swf/SWFOutputDev.cc +++ b/pdf2swf/SWFOutputDev.cc @@ -23,6 +23,9 @@ #include #include #include "../config.h" +#ifdef HAVE_FONTCONFIG_H +#include +#endif //xpdf header files #include "config.h" #include "gfile.h" @@ -42,35 +45,48 @@ #include "GfxFont.h" #include "CharCodeToUnicode.h" #include "NameToUnicodeTable.h" -#include "FontFile.h" #include "GlobalParams.h" +//#define XPDF_101 +#ifdef XPDF_101 +#include "FontFile.h" +#else +#include "FoFiType1C.h" +#include "FoFiTrueType.h" +#endif +#include "SWFOutputDev.h" + //swftools header files #include "swfoutput.h" -extern "C" { #include "../lib/log.h" -#include "ttf2pt1.h" -} -#define logf logarithmf // logf is also used by ../lib/log.h #include -#undef logf static PDFDoc*doc = 0; static char* swffilename = 0; -int numpages; -int currentpage; +static int numpages; +static int currentpage; + +typedef struct _fontfile +{ + char*filename; + int used; +} fontfile_t; + +static fontfile_t fonts[2048]; +static int fontnum = 0; // swf <-> pdf pages -int*pages = 0; -int pagebuflen = 0; -int pagepos = 0; +static int*pages = 0; +static int pagebuflen = 0; +static int pagepos = 0; -double caplinewidth = 3.0; +static double caplinewidth = 3.0; +static int zoom = 72; /* xpdf: 86 */ static void printInfoString(Dict *infoDict, char *key, char *fmt); static void printInfoDate(Dict *infoDict, char *key, char *fmt); -double fontsizes[] = +static double fontsizes[] = { 0.833,0.833,0.889,0.889, 0.788,0.722,0.833,0.778, @@ -78,7 +94,7 @@ double fontsizes[] = 0.576,0.576,0.576,0.576, 0.733 //? }; -char*fontnames[]={ +static char*fontnames[]={ "Helvetica", "Helvetica-Bold", "Helvetica-BoldOblique", @@ -103,20 +119,20 @@ struct mapping { char*filename; int id; } pdf2t1map[] ={ -{"Times-Roman", "n021003l.pfb"}, -{"Times-Italic", "n021023l.pfb"}, -{"Times-Bold", "n021004l.pfb"}, -{"Times-BoldItalic", "n021024l.pfb"}, -{"Helvetica", "n019003l.pfb"}, -{"Helvetica-Oblique", "n019023l.pfb"}, -{"Helvetica-Bold", "n019004l.pfb"}, -{"Helvetica-BoldOblique", "n019024l.pfb"}, -{"Courier", "n022003l.pfb"}, -{"Courier-Oblique", "n022023l.pfb"}, -{"Courier-Bold", "n022004l.pfb"}, -{"Courier-BoldOblique", "n022024l.pfb"}, -{"Symbol", "s050000l.pfb"}, -{"ZapfDingbats", "d050000l.pfb"}}; +{"Times-Roman", "n021003l"}, +{"Times-Italic", "n021023l"}, +{"Times-Bold", "n021004l"}, +{"Times-BoldItalic", "n021024l"}, +{"Helvetica", "n019003l"}, +{"Helvetica-Oblique", "n019023l"}, +{"Helvetica-Bold", "n019004l"}, +{"Helvetica-BoldOblique", "n019024l"}, +{"Courier", "n022003l"}, +{"Courier-Oblique", "n022023l"}, +{"Courier-Bold", "n022004l"}, +{"Courier-BoldOblique", "n022024l"}, +{"Symbol", "s050000l"}, +{"ZapfDingbats", "d050000l"}}; class GfxState; class GfxImageColorMap; @@ -148,7 +164,7 @@ public: void startDoc(XRef *xref); // Start a page. - virtual void startPage(int pageNum, GfxState *state) ; + virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ; //----- link borders virtual void drawLink(Link *link, Catalog *catalog) ; @@ -214,7 +230,7 @@ public: XRef*xref; - int searchT1Font(char*name); + char* searchFont(char*name); char* substituteFont(GfxFont*gfxFont, char*oldname); char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font); int t1id; @@ -228,6 +244,28 @@ public: GfxState *laststate; }; +static char*getFontID(GfxFont*font) +{ + GString*gstr = font->getName(); + char* fontname = gstr==0?0:gstr->getCString(); + if(fontname==0) { + char buf[32]; + Ref*r=font->getID(); + sprintf(buf, "UFONT%d", r->num); + return strdup(buf); + } + return fontname; +} + +static char*getFontName(GfxFont*font) +{ + char*fontname = getFontID(font); + char* plus = strchr(fontname, '+'); + if(plus && plus < &fontname[strlen(fontname)-1]) + fontname = plus+1; + return fontname; +} + char mybuf[1024]; char* gfxstate2str(GfxState *state) { @@ -307,8 +345,8 @@ char* gfxstate2str(GfxState *state) if(state->getLineJoin()!=0) bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit()); - if(state->getFont() && state->getFont()->getName() && state->getFont()->getName()->getCString()) - bufpos+=sprintf(bufpos,"F\"%s\" ",((state->getFont())->getName())->getCString()); + if(state->getFont() && getFontID(state->getFont())) + bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont())); bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize()); bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2], state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]); @@ -335,6 +373,8 @@ char* gfxstate2str(GfxState *state) return mybuf; } + + void dumpFontInfo(char*loglevel, GfxFont*font); int lastdumps[1024]; int lastdumppos = 0; @@ -354,53 +394,51 @@ void showFontError(GfxFont*font, int nr) if(lastdumpposnum; if(nr == 0) - logf(" The following font caused problems:"); + msg(" The following font caused problems:"); else if(nr == 1) - logf(" The following font caused problems (substituting):"); + msg(" The following font caused problems (substituting):"); else if(nr == 2) - logf(" The following Type 3 Font will be rendered as bitmap:"); + msg(" The following Type 3 Font will be rendered as bitmap:"); dumpFontInfo("", font); } void dumpFontInfo(char*loglevel, GfxFont*font) { - GString *gstr; - char*name = 0; - gstr = font->getName(); + char* name = getFontID(font); Ref* r=font->getID(); - logf("%s=========== %s (ID:%d,%d) ==========\n", loglevel, gstr?FIXNULL(gstr->getCString()):"(unknown font)", r->num,r->gen); + msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, getFontName(font), r->num,r->gen); - gstr = font->getTag(); - if(gstr) - logf("%sTag: %s\n", loglevel, FIXNULL(gstr->getCString())); + GString*gstr = font->getTag(); + + msg("%s| Tag: %s\n", loglevel, name); - if(font->isCIDFont()) logf("%sis CID font\n", loglevel); + if(font->isCIDFont()) msg("%s| is CID font\n", loglevel); GfxFontType type=font->getType(); switch(type) { case fontUnknownType: - logf("%sType: unknown\n",loglevel); + msg("%s| Type: unknown\n",loglevel); break; case fontType1: - logf("%sType: 1\n",loglevel); + msg("%s| Type: 1\n",loglevel); break; case fontType1C: - logf("%sType: 1C\n",loglevel); + msg("%s| Type: 1C\n",loglevel); break; case fontType3: - logf("%sType: 3\n",loglevel); + msg("%s| Type: 3\n",loglevel); break; case fontTrueType: - logf("%sType: TrueType\n",loglevel); + msg("%s| Type: TrueType\n",loglevel); break; case fontCIDType0: - logf("%sType: CIDType0\n",loglevel); + msg("%s| Type: CIDType0\n",loglevel); break; case fontCIDType0C: - logf("%sType: CIDType0C\n",loglevel); + msg("%s| Type: CIDType0C\n",loglevel); break; case fontCIDType2: - logf("%sType: CIDType2\n",loglevel); + msg("%s| Type: CIDType2\n",loglevel); break; } @@ -409,18 +447,18 @@ void dumpFontInfo(char*loglevel, GfxFont*font) if(font->getEmbeddedFontName()) name = font->getEmbeddedFontName()->getCString(); if(embedded) - logf("%sEmbedded name: %s id: %d\n",loglevel, FIXNULL(name), embRef.num); + msg("%s| Embedded name: %s id: %d\n",loglevel, FIXNULL(name), embRef.num); gstr = font->getExtFontFile(); if(gstr) - logf("%sExternal Font file: %s\n", loglevel, FIXNULL(gstr->getCString())); + msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString())); // Get font descriptor flags. - if(font->isFixedWidth()) logf("%sis fixed width\n", loglevel); - if(font->isSerif()) logf("%sis serif\n", loglevel); - if(font->isSymbolic()) logf("%sis symbolic\n", loglevel); - if(font->isItalic()) logf("%sis italic\n", loglevel); - if(font->isBold()) logf("%sis bold\n", loglevel); + if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel); + if(font->isSerif()) msg("%s| is serif\n", loglevel); + if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel); + if(font->isItalic()) msg("%s| is italic\n", loglevel); + if(font->isBold()) msg("%s| is bold\n", loglevel); } //void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) {printf("void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) \n");} @@ -440,7 +478,7 @@ SWFOutputDev::SWFOutputDev() // printf("SWFOutputDev::SWFOutputDev() \n"); }; -T1_OUTLINE* gfxPath_to_T1_OUTLINE(GfxState*state, GfxPath*path) +SWF_OUTLINE* gfxPath_to_SWF_OUTLINE(GfxState*state, GfxPath*path) { int num = path->getNumSubpaths(); int s,t; @@ -449,12 +487,12 @@ T1_OUTLINE* gfxPath_to_T1_OUTLINE(GfxState*state, GfxPath*path) int cpos = 0; double lastx=0,lasty=0; if(!num) { - logf(" empty path"); - outline->type = T1_PATHTYPE_MOVE; + msg(" empty path"); + outline->type = SWF_PATHTYPE_MOVE; outline->dest.x = 0; outline->dest.y = 0; outline->link = 0; - return (T1_OUTLINE*)outline; + return (SWF_OUTLINE*)outline; } for(t = 0; t < num; t++) { GfxSubpath *subpath = path->getSubpath(t); @@ -468,10 +506,10 @@ T1_OUTLINE* gfxPath_to_T1_OUTLINE(GfxState*state, GfxPath*path) if(s==0) { last = outline; - outline->type = T1_PATHTYPE_MOVE; + outline->type = SWF_PATHTYPE_MOVE; outline->dest.x = x; outline->dest.y = y; - outline->link = (T1_OUTLINE*)new bezierpathsegment(); + outline->link = (SWF_OUTLINE*)new bezierpathsegment(); outline = (bezierpathsegment*)outline->link; cpos = 0; lastx = nx; @@ -494,9 +532,9 @@ T1_OUTLINE* gfxPath_to_T1_OUTLINE(GfxState*state, GfxPath*path) last = outline; outline->dest.x = x; outline->dest.y = y; - outline->type = cpos?T1_PATHTYPE_BEZIER:T1_PATHTYPE_LINE; + outline->type = cpos?SWF_PATHTYPE_BEZIER:SWF_PATHTYPE_LINE; outline->link = 0; - outline->link = (T1_OUTLINE*)new bezierpathsegment(); + outline->link = (SWF_OUTLINE*)new bezierpathsegment(); outline = (bezierpathsegment*)outline->link; cpos = 0; lastx = nx; @@ -505,7 +543,7 @@ T1_OUTLINE* gfxPath_to_T1_OUTLINE(GfxState*state, GfxPath*path) } } last->link = 0; - return (T1_OUTLINE*)start; + return (SWF_OUTLINE*)start; } /*---------------------------------------------------------------------------- * Primitive Graphic routines @@ -513,7 +551,7 @@ T1_OUTLINE* gfxPath_to_T1_OUTLINE(GfxState*state, GfxPath*path) void SWFOutputDev::stroke(GfxState *state) { - logf(" stroke\n"); + msg(" stroke\n"); GfxPath * path = state->getPath(); int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel @@ -526,7 +564,7 @@ void SWFOutputDev::stroke(GfxState *state) m.m11 = 1; m.m21 = 0; m.m22 = 1; m.m12 = 0; m.m13 = 0; m.m23 = 0; - T1_OUTLINE*outline = gfxPath_to_T1_OUTLINE(state, path); + SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path); lineJoin = 1; // other line joins are not yet supported by the swf encoder // TODO: support bevel joints @@ -552,46 +590,46 @@ void SWFOutputDev::stroke(GfxState *state) } void SWFOutputDev::fill(GfxState *state) { - logf(" fill\n"); + msg(" fill\n"); GfxPath * path = state->getPath(); struct swfmatrix m; m.m11 = 1; m.m21 = 0; m.m22 = 1; m.m12 = 0; m.m13 = 0; m.m23 = 0; - T1_OUTLINE*outline = gfxPath_to_T1_OUTLINE(state, path); + SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path); swfoutput_setdrawmode(&output, DRAWMODE_FILL); swfoutput_drawpath(&output, outline, &m); } void SWFOutputDev::eoFill(GfxState *state) { - logf(" eofill\n"); + msg(" eofill\n"); GfxPath * path = state->getPath(); struct swfmatrix m; m.m11 = 1; m.m21 = 0; m.m22 = 1; m.m12 = 0; m.m13 = 0; m.m23 = 0; - T1_OUTLINE*outline = gfxPath_to_T1_OUTLINE(state, path); + SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path); swfoutput_setdrawmode(&output, DRAWMODE_EOFILL); swfoutput_drawpath(&output, outline, &m); } void SWFOutputDev::clip(GfxState *state) { - logf(" clip\n"); + msg(" clip\n"); GfxPath * path = state->getPath(); struct swfmatrix m; m.m11 = 1; m.m22 = 1; m.m12 = 0; m.m21 = 0; m.m13 = 0; m.m23 = 0; - T1_OUTLINE*outline = gfxPath_to_T1_OUTLINE(state, path); + SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path); swfoutput_startclip(&output, outline, &m); clipping[clippos] ++; } void SWFOutputDev::eoClip(GfxState *state) { - logf(" eoclip\n"); + msg(" eoclip\n"); GfxPath * path = state->getPath(); struct swfmatrix m; m.m11 = 1; m.m21 = 0; m.m22 = 1; m.m12 = 0; m.m13 = 0; m.m23 = 0; - T1_OUTLINE*outline = gfxPath_to_T1_OUTLINE(state, path); + SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path); swfoutput_startclip(&output, outline, &m); clipping[clippos] ++; } @@ -603,33 +641,32 @@ SWFOutputDev::~SWFOutputDev() }; GBool SWFOutputDev::upsideDown() { - logf(" upsidedown?"); + msg(" upsidedown? yes"); return gTrue; }; GBool SWFOutputDev::useDrawChar() { - logf(" usedrawchar?"); return gTrue; } void SWFOutputDev::beginString(GfxState *state, GString *s) { double m11,m21,m12,m22; -// logf(" %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString()); +// msg(" %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString()); state->getFontTransMat(&m11, &m12, &m21, &m22); m11 *= state->getHorizScaling(); m21 *= state->getHorizScaling(); swfoutput_setfontmatrix(&output, m11, -m21, m12, -m22); + + msg(" fontmatrix %7.3f %7.3f\n", m11,-m21); + msg(" fontmatrix %7.3f %7.3f\n", m12,-m22); } -int charcounter = 0; void SWFOutputDev::drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, CharCode c, Unicode *_u, int uLen) { - logf(" drawChar(%f,%f,%f,%f,'%c')\n",x,y,dx,dy,c); - // check for invisible text -- this is used by Acrobat Capture if ((state->getRender() & 3) == 3) return; @@ -637,59 +674,54 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y, GfxFont*font = state->getFont(); if(font->getType() == fontType3) { - /* type 3 chars are passed primarily as graphics */ + /* type 3 chars are passed as graphics */ return; } double x1,y1; x1 = x; y1 = y; state->transform(x, y, &x1, &y1); - - if(font->isCIDFont()) { + + Unicode u=0; + if(_u) + u = *_u; + + /* find out the character name */ + char*name=0; + if(font->isCIDFont() && u) { GfxCIDFont*cfont = (GfxCIDFont*)font; - Unicode u=0; - char*name=0; - if(_u) - u = *_u; - if(u) { - int t; - for(t=0;tgetName()->getCString(), - cfont->getType());*/ - - if(name) - swfoutput_drawchar(&output, x1, y1, name, c); - else - logf(" couldn't get name for CID character %02x from Encoding", c); } else { Gfx8BitFont*font8; font8 = (Gfx8BitFont*)font; char**enc=font8->getEncoding(); - if(enc && enc[c]) - swfoutput_drawchar(&output, x1, y1, enc[c], c); - else { - logf(" couldn't get name for character %02x from Encoding", c); - } + name = enc[c]; } + + msg(" drawChar(%f,%f,c='%c' (%d),u=%d <%d>) CID=%d name=\"%s\"\n",x,y,(c&127)>=32?c:'?',c,u, uLen, font->isCIDFont(), FIXNULL(name)); + + /*x1 = (int)(x1+0.5); + y1 = (int)(y1+0.5);*/ + + int ret = swfoutput_drawchar(&output, x1, y1, name, c, u); } -void SWFOutputDev::endString(GfxState *state) -{ - logf(" endstring\n"); +void SWFOutputDev::endString(GfxState *state) { } GBool SWFOutputDev::beginType3Char(GfxState *state, CharCode code, Unicode *u, int uLen) { - logf(" beginType3Char %d, %08x, %d", code, *u, uLen); + msg(" beginType3Char %d, %08x, %d", code, *u, uLen); type3active = 1; /* the character itself is going to be passed using drawImageMask() */ @@ -699,20 +731,38 @@ GBool SWFOutputDev::beginType3Char(GfxState *state, void SWFOutputDev::endType3Char(GfxState *state) { type3active = 0; - logf(" endType3Char"); + msg(" endType3Char"); } -void SWFOutputDev::startPage(int pageNum, GfxState *state) +void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2) { double x1,y1,x2,y2; + int rot = doc->getPageRotate(1); laststate = state; - logf(" startPage %d\n", pageNum); - logf(" processing page %d", pageNum); + msg(" startPage %d (%f,%f,%f,%f)\n", pageNum, crop_x1, crop_y1, crop_x2, crop_y2); + if(rot!=0) + msg(" page is rotated %d degrees\n", rot); + + msg(" processing page %d", pageNum); - state->transform(state->getX1(),state->getY1(),&x1,&y1); + /* state->transform(state->getX1(),state->getY1(),&x1,&y1); state->transform(state->getX2(),state->getY2(),&x2,&y2); + Use CropBox, not MediaBox, as page size + */ + + /*x1 = crop_x1; + y1 = crop_y1; + x2 = crop_x2; + y2 = crop_y2;*/ + state->transform(crop_x1,crop_y1,&x1,&y1); + state->transform(crop_x2,crop_y2,&x2,&y2); + + if(x2 Bounding box is (%f,%f)-(%f,%f)", x1,y1,x2,y2); + swfoutput_init(&output, swffilename,(int)x1,(int)y1,(int)x2,(int)y2); outputstarted = 1; } else @@ -721,13 +771,17 @@ void SWFOutputDev::startPage(int pageNum, GfxState *state) void SWFOutputDev::drawLink(Link *link, Catalog *catalog) { - logf(" drawlink\n"); + msg(" drawlink\n"); double x1, y1, x2, y2, w; GfxRGB rgb; swfcoord points[5]; int x, y; +#ifdef XPDF_101 link->getBorder(&x1, &y1, &x2, &y2, &w); +#else + link->getRect(&x1, &y1, &x2, &y2); +#endif // if (w > 0) { rgb.r = 0; @@ -835,13 +889,13 @@ void SWFOutputDev::drawLink(Link *link, Catalog *catalog) } break; default: { - logf(" Unknown link type!\n"); + msg(" Unknown link type!\n"); break; } } if(!linkinfo && (page || url)) { - logf(" File contains links"); + msg(" File contains links"); linkinfo = 1; } if(page>0) @@ -861,22 +915,22 @@ void SWFOutputDev::drawLink(Link *link, Catalog *catalog) { swfoutput_namedlink(&output, named, points); } - logf(" \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page); + msg(" \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page); } } void SWFOutputDev::saveState(GfxState *state) { - logf(" saveState\n"); + msg(" saveState\n"); updateAll(state); if(clippos<64) clippos ++; else - logf(" Too many nested states in pdf."); + msg(" Too many nested states in pdf."); clipping[clippos] = 0; }; void SWFOutputDev::restoreState(GfxState *state) { - logf(" restoreState\n"); + msg(" restoreState\n"); updateAll(state); while(clipping[clippos]) { swfoutput_endclip(&output); @@ -887,56 +941,39 @@ void SWFOutputDev::restoreState(GfxState *state) { char type3Warning=0; -int SWFOutputDev::searchT1Font(char*name) +char* SWFOutputDev::searchFont(char*name) { int i; - int mapid=-1; char*filename=0; + int is_standard_font = 0; + + msg(" SearchFont(%s)", name); + /* see if it is a pdf standard font */ for(i=0;i Loading extra font %s from %s\n", FIXNULL(fontname), - FIXNULL(T1_GetFontFileName(i))); - } + if(!fonts[i].used) { - if(fontname && !strcmp(name, fontname)) { - logf(" Extra font %d, \"%s\" is being used.\n", i, fontname); - return i; - } - fontname = T1_GetFontFileName(i); - if(strrchr(fontname,'/')) - fontname = strrchr(fontname,'/')+1; - - if(strstr(fontname, name)) { - logf(" Extra font %d, \"%s\" is being used.\n", i, fontname); - return i; + fonts[i].used = 1; + if(!is_standard_font) + msg(" Using %s for %s", fonts[i].filename, name); } + return fonts[i].filename; } } - return -1; + return 0; } void SWFOutputDev::updateLineWidth(GfxState *state) @@ -975,225 +1012,233 @@ void SWFOutputDev::updateStrokeColor(GfxState *state) (char)(rgb.b*255), (char)(opaq*255)); } +void FoFiWrite(void *stream, char *data, int len) +{ + fwrite(data, len, 1, (FILE*)stream); +} + char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font) { - char*tmpFileName = NULL; - FILE *f; - int c; - char *fontBuf; - int fontLen; - Type1CFontFile *cvt; - Ref embRef; - Object refObj, strObj; - tmpFileName = "/tmp/tmpfont"; - int ret; - - ret = font->getEmbeddedFontID(&embRef); - if(!ret) { - logf(" Didn't get embedded font id"); - /* not embedded- the caller should now search the font - directories for this font */ - return 0; - } + char*tmpFileName = NULL; + FILE *f; + int c; + char *fontBuf; + int fontLen; + Ref embRef; + Object refObj, strObj; + char namebuf[512]; + tmpFileName = mktmpname(namebuf); + int ret; + + ret = font->getEmbeddedFontID(&embRef); + if(!ret) { + msg(" Didn't get embedded font id"); + /* not embedded- the caller should now search the font + directories for this font */ + return 0; + } - f = fopen(tmpFileName, "wb"); - if (!f) { - logf(" Couldn't create temporary Type 1 font file"); - return 0; - } - if (font->getType() == fontType1C) { - if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) { - fclose(f); - logf(" Couldn't read embedded font file"); - return 0; - } - cvt = new Type1CFontFile(fontBuf, fontLen); - cvt->convertToType1(f); - delete cvt; - gfree(fontBuf); - } else { - font->getEmbeddedFontID(&embRef); - refObj.initRef(embRef.num, embRef.gen); - refObj.fetch(ref, &strObj); - refObj.free(); - strObj.streamReset(); - int f4[4]; - char f4c[4]; - int t; - for(t=0;t<4;t++) { - f4[t] = strObj.streamGetChar(); - f4c[t] = (char)f4[t]; - if(f4[t] == EOF) - break; - } - if(t==4) { - if(!strncmp(f4c, "true", 4)) { - /* some weird TTF fonts don't start with 0,1,0,0 but with "true". - Change this on the fly */ - f4[0] = f4[2] = f4[3] = 0; - f4[1] = 1; - } - fputc(f4[0], f); - fputc(f4[1], f); - fputc(f4[2], f); - fputc(f4[3], f); + f = fopen(tmpFileName, "wb"); + if (!f) { + msg(" Couldn't create temporary Type 1 font file"); + return 0; + } - while ((c = strObj.streamGetChar()) != EOF) { - fputc(c, f); - } - } - strObj.streamClose(); - strObj.free(); + /*if(font->isCIDFont()) { + GfxCIDFont* cidFont = (GfxCIDFont *)font; + GString c = cidFont->getCollection(); + msg(" Collection: %s", c.getCString()); + }*/ + + if (font->getType() == fontType1C || + font->getType() == fontCIDType0C) { + if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) { + fclose(f); + msg(" Couldn't read embedded font file"); + return 0; + } +#ifdef XPDF_101 + Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen); + cvt->convertToType1(f); +#else + FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen); + cvt->convertToType1(NULL, gTrue, FoFiWrite, f); +#endif + //cvt->convertToCIDType0("test", f); + //cvt->convertToType0("test", f); + delete cvt; + gfree(fontBuf); + } else if(font->getType() == fontTrueType) { + msg(" writing font using TrueTypeFontFile::writeTTF"); + if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) { + fclose(f); + msg(" Couldn't read embedded font file"); + return 0; } - fclose(f); +#ifdef XPDF_101 + TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen); + cvt->writeTTF(f); +#else + FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen); + cvt->writeTTF(FoFiWrite, f); +#endif + delete cvt; + gfree(fontBuf); + } else { + font->getEmbeddedFontID(&embRef); + refObj.initRef(embRef.num, embRef.gen); + refObj.fetch(ref, &strObj); + refObj.free(); + strObj.streamReset(); + int f4[4]; + char f4c[4]; + int t; + for(t=0;t<4;t++) { + f4[t] = strObj.streamGetChar(); + f4c[t] = (char)f4[t]; + if(f4[t] == EOF) + break; + } + if(t==4) { + if(!strncmp(f4c, "true", 4)) { + /* some weird TTF fonts don't start with 0,1,0,0 but with "true". + Change this on the fly */ + f4[0] = f4[2] = f4[3] = 0; + f4[1] = 1; + } + fputc(f4[0], f); + fputc(f4[1], f); + fputc(f4[2], f); + fputc(f4[3], f); - if(font->getType() == fontTrueType || - font->getType() == fontCIDType2) - { - if(!ttfinfo) { - logf(" File contains TrueType fonts"); - ttfinfo = 1; + while ((c = strObj.streamGetChar()) != EOF) { + fputc(c, f); } - char name2[80]; - char*tmp; - tmp = strdup(mktmpname((char*)name2)); - sprintf(name2, "%s", tmp); - char*a[] = {"./ttf2pt1","-pttf","-b", tmpFileName, name2}; - logf(" Invoking ttf2pt1..."); - ttf2pt1_main(5,a); - unlink(tmpFileName); - sprintf(name2,"%s.pfb",tmp); - tmpFileName = strdup(name2); } + strObj.streamClose(); + strObj.free(); + } + fclose(f); - return tmpFileName; + return strdup(tmpFileName); } -char* gfxFontName(GfxFont* gfxFont) -{ - GString *gstr; - gstr = gfxFont->getName(); - if(gstr) { - return gstr->getCString(); - } - else { - char buf[32]; - Ref*r=gfxFont->getID(); - sprintf(buf, "UFONT%d", r->num); - return strdup(buf); - } -} char* substitutetarget[256]; char* substitutesource[256]; int substitutepos = 0; +char* searchForSuitableFont(GfxFont*gfxFont) +{ + char*name = getFontName(gfxFont); + char*fontname = 0; + char*filename = 0; + +#ifdef HAVE_FONTCONFIG + FcPattern *pattern, *match; + FcResult result; + FcChar8 *v; + + // call init ony once + static int fcinitcalled = false; + if (!fcinitcalled) { + fcinitcalled = true; + FcInit(); + } + + pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL); + if (gfxFont->isItalic()) // check for italic + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); + if (gfxFont->isBold()) // check for bold + FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); + + // configure and match using the original font name + FcConfigSubstitute(0, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + match = FcFontMatch(0, pattern, &result); + + if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) { + // if we get an exact match + if (strcmp((char *)v, name) == 0) { + if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) { + filename = strdup((char*)v); + char *nfn = strrchr(filename, '/'); + if(nfn) fontname = strdup(nfn+1); + else fontname = filename; + } + } else { + // initialize patterns + FcPatternDestroy(pattern); + FcPatternDestroy(match); + + // now match against serif etc. + if (gfxFont->isSerif()) { + pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL); + } else if (gfxFont->isFixedWidth()) { + pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL); + } else { + pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL); + } + + // check for italic + if (gfxFont->isItalic()) { + int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); + } + // check for bold + if (gfxFont->isBold()) { + int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); + } + + // configure and match using serif etc + FcConfigSubstitute (0, pattern, FcMatchPattern); + FcDefaultSubstitute (pattern); + match = FcFontMatch (0, pattern, &result); + + if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) { + filename = strdup((char*)v); + char *nfn = strrchr(filename, '/'); + if(nfn) fontname = strdup(nfn+1); + else fontname = filename; + } + } + } + + //printf("FONTCONFIG: pattern"); + //FcPatternPrint(pattern); + //printf("FONTCONFIG: match"); + //FcPatternPrint(match); + + FcPatternDestroy(pattern); + FcPatternDestroy(match); + + pdfswf_addfont(filename); + return fontname; +#else + return 0; +#endif +} + char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname) { -/* ------------------------------ V1 */ + char*fontname = 0, *filename = 0; + msg(" subsituteFont(%s)", oldname); + + if(!(fontname = searchForSuitableFont(gfxFont))) { + fontname = "Times-Roman"; + } + filename = searchFont(fontname); - char*fontname = "Times-Roman"; - logf(" substituteFont(,%s)", FIXNULL(oldname)); - this->t1id = searchT1Font(fontname); if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) { - logf(" Too many fonts in file."); + msg(" Too many fonts in file."); exit(1); } if(oldname) { substitutesource[substitutepos] = oldname; substitutetarget[substitutepos] = fontname; - logf(" substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname)); + msg(" substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname)); substitutepos ++; } - return fontname; - -/* ------------------------------ V2 */ - -/* //substitute font - char* fontname = 0; - double m11, m12, m21, m22; - int index; - int code; - double w,w1,w2; - double*fm; - double v; - if(gfxFont->getName()) { - fontname = gfxFont->getName()->getCString(); - } - -// printf("%d %s\n", t, gfxFont->getCharName(t)); - showFontError(gfxFont, 1); - if(1) { //if (!gfxFont->isCIDFont()) { FIXME: xpdf 1.01 does not have is16Bit() - if(gfxFont->isSymbolic()) { - if(fontname && (strstr(fontname,"ing"))) //Dingbats, Wingdings etc. - index = 16; - else - index = 12; - } else if (gfxFont->isFixedWidth()) { - index = 8; - } else if (gfxFont->isSerif()) { - index = 4; - } else { - index = 0; - } - if (gfxFont->isBold() && index!=16) - index += 2; - if (gfxFont->isItalic() && index!=16) - index += 1; - fontname = fontnames[index]; - // get width of 'm' in real font and substituted font - if ((code = gfxFont->getCharCode("m")) >= 0) - w1 = gfxFont->getWidth(code); - else - w1 = 0; - w2 = fontsizes[index]; - if (gfxFont->getType() == fontType3) { - // This is a hack which makes it possible to substitute for some - // Type 3 fonts. The problem is that it's impossible to know what - // the base coordinate system used in the font is without actually - // rendering the font. This code tries to guess by looking at the - // width of the character 'm' (which breaks if the font is a - // subset that doesn't contain 'm'). - if (w1 > 0 && (w1 > 1.1 * w2 || w1 < 0.9 * w2)) { - w1 /= w2; - m11 *= w1; - m12 *= w1; - m21 *= w1; - m22 *= w1; - } - fm = gfxFont->getFontMatrix(); - v = (fm[0] == 0) ? 1 : (fm[3] / fm[0]); - m21 *= v; - m22 *= v; - } else if (!gfxFont->isSymbolic()) { - // if real font is substantially narrower than substituted - // font, reduce the font size accordingly - if (w1 > 0.01 && w1 < 0.9 * w2) { - w1 /= w2; - if (w1 < 0.8) { - w1 = 0.8; - } - m11 *= w1; - m12 *= w1; - m21 *= w1; - m22 *= w1; - } - } - } - if(fontname) { - this->t1id = searchT1Font(fontname); - } - if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) { - logf(" Too many fonts in file."); - exit(1); - } - if(oldname) { - substitutesource[substitutepos] = oldname; - substitutetarget[substitutepos] = fontname; - logf(" substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname)); - substitutepos ++; - } - return fontname;*/ + return filename; } void unlinkfont(char* filename) @@ -1227,113 +1272,93 @@ void unlinkfont(char* filename) void SWFOutputDev::startDoc(XRef *xref) { - this->xref = xref; + this->xref = xref; } void SWFOutputDev::updateFont(GfxState *state) { - GfxFont*gfxFont = state->getFont(); - char * fileName = 0; + GfxFont*gfxFont = state->getFont(); + + if (!gfxFont) { + return; + } + char * fontid = getFontID(gfxFont); - if (!gfxFont) { - return; - } - char * fontname = gfxFontName(gfxFont); - - int t; - /* first, look if we substituted this font before- - this way, we don't initialize the T1 Fonts - too often */ - for(t=0;t updateFont(%s) [cached]", fontid); + return; + } - if(swfoutput_queryfont(&output, fontname)) - { - swfoutput_setfont(&output, fontname, -1, 0); - return; - } + // look for Type 3 font + if (gfxFont->getType() == fontType3) { + if(!type3Warning) { + type3Warning = gTrue; + showFontError(gfxFont, 2); + } + return; + } - // look for Type 3 font - if (!type3Warning && gfxFont->getType() == fontType3) { - type3Warning = gTrue; - showFontError(gfxFont, 2); - } + /* now either load the font, or find a substitution */ - /* now either load the font, or find a substitution */ + Ref embRef; + GBool embedded = gfxFont->getEmbeddedFontID(&embRef); - Ref embRef; - GBool embedded = gfxFont->getEmbeddedFontID(&embRef); - if(embedded) { - if (gfxFont->getType() == fontType1 || + char*fileName = 0; + int del = 0; + if(embedded && + (gfxFont->getType() == fontType1 || gfxFont->getType() == fontType1C || + //gfxFont->getType() == fontCIDType0C || gfxFont->getType() == fontTrueType || - gfxFont->getType() == fontCIDType2) + gfxFont->getType() == fontCIDType2 + )) { - fileName = writeEmbeddedFontToFile(xref, gfxFont); - if(!fileName) { - logf(" Couldn't write font to file"); - showFontError(gfxFont,0); - return ; - } - this->t1id = T1_AddFont(fileName); - if(this->t1id<0) { - logf(" Couldn't load font from file"); - showFontError(gfxFont,0); - unlinkfont(fileName); - return ; - } - } - else { - /* in case the font is embedded, but has an - unsupported format, we just look through the - font directories */ - int newt1id = searchT1Font(fontname); - if(newt1id<0) { - showFontError(gfxFont,0); - fontname = substituteFont(gfxFont, fontname); - } else - this->t1id = newt1id; - } - } else { - if(fontname) { - int newt1id = searchT1Font(fontname); - if(newt1id<0) { - showFontError(gfxFont,1); - fontname = substituteFont(gfxFont, fontname); - } else - this->t1id = newt1id; + fileName = writeEmbeddedFontToFile(xref, gfxFont); + if(!fileName) showFontError(gfxFont,0); + else del = 1; + } else { + char * fontname = getFontName(gfxFont); + fileName = searchFont(fontname); + if(!fileName) showFontError(gfxFont,0); } - else { - showFontError(gfxFont,1); - fontname = substituteFont(gfxFont, fontname); + if(!fileName) { + char * fontname = getFontName(gfxFont); + msg(" Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) "); + msg(" Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname); + fileName = substituteFont(gfxFont, fontid); + if(fontid) { fontid = substitutetarget[substitutepos-1]; /*ugly hack*/}; + msg(" Font is now %s (%s)", fontid, fileName); } - } - if(t1id<0) { - showFontError(gfxFont,0); - return; - } - - /* we may have done some substitutions here, so check - again if this font is cached. */ - if(swfoutput_queryfont(&output, fontname)) - { - swfoutput_setfont(&output, fontname, -1, 0); - return; - } - - logf(" Creating new SWF font: t1id: %d, filename: %s name:%s", this->t1id, FIXNULL(fileName), FIXNULL(fontname)); - swfoutput_setfont(&output, fontname, this->t1id, fileName); - if(fileName) - unlinkfont(fileName); + if(!fileName) { + msg(" Couldn't set font %s\n", fontid); + return; + } + + msg(" updateFont(%s) -> %s", fontid, fileName); + dumpFontInfo("", gfxFont); + + swfoutput_setfont(&output, fontid, fileName); + + if(fileName && del) + unlinkfont(fileName); } int pic_xids[1024]; @@ -1417,7 +1442,7 @@ void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str, if(!width || !height || (height<=1 && width<=1)) { - logf(" Ignoring %d by %d image", width, height); + msg(" Ignoring %d by %d image", width, height); unsigned char buf[8]; int x,y; for (y = 0; y < height; ++y) @@ -1435,14 +1460,14 @@ void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str, if(!pbminfo && !(str->getKind()==strDCT)) { if(!type3active) { - logf(" file contains pbm pictures %s",mask?"(masked)":""); + msg(" file contains pbm pictures %s",mask?"(masked)":""); pbminfo = 1; } if(mask) - logf(" drawing %d by %d masked picture\n", width, height); + msg(" drawing %d by %d masked picture\n", width, height); } if(!jpeginfo && (str->getKind()==strDCT)) { - logf(" file contains jpeg pictures"); + msg(" file contains jpeg pictures"); jpeginfo = 1; } @@ -1649,7 +1674,7 @@ void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) { - logf(" drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg); + msg(" drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg); drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1); } @@ -1657,12 +1682,12 @@ void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg) { - logf(" drawImage %dx%d, %s %s, inline=%d", width, height, + msg(" drawImage %dx%d, %s %s, inline=%d", width, height, colorMap?"colorMap":"no colorMap", maskColors?"maskColors":"no maskColors", inlineImg); if(colorMap) - logf(" colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(), + msg(" colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(), colorMap->getBits(),colorMap->getColorSpace()->getMode()); drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0); } @@ -1760,15 +1785,9 @@ void pdfswf_init(char*filename, char*userPassword) } } info.free(); - + numpages = doc->getNumPages(); if (doc->isEncrypted()) { - /*ERROR: This pdf is encrypted, and disallows copying. - Due to the DMCA, paragraph 1201, (2) A-C, circumventing - a technological measure that efficively controls access to - a protected work is violating American law. - See www.eff.org for more information about DMCA issues. - */ if(!doc->okToCopy()) { printf("PDF disallows copying. Bailing out.\n"); exit(1); //bail out @@ -1783,91 +1802,26 @@ void pdfswf_init(char*filename, char*userPassword) void pdfswf_setparameter(char*name, char*value) { - if(!strcmp(name, "drawonlyshapes")) { - drawonlyshapes = atoi(value); - } else if(!strcmp(name, "ignoredraworder")) { - ignoredraworder = atoi(value); - } else if(!strcmp(name, "linksopennewwindow")) { - opennewwindow = atoi(value); - } else if(!strcmp(name, "storeallcharacters")) { - storeallcharacters = atoi(value); - } else if(!strcmp(name, "enablezlib")) { - enablezlib = atoi(value); - } else if(!strcmp(name, "insertstop")) { - insertstoptag = atoi(value); - } else if(!strcmp(name, "flashversion")) { - flashversion = atoi(value); - } else if(!strcmp(name, "jpegquality")) { - int val = atoi(value); - if(val<0) val=0; - if(val>100) val=100; - jpegquality = val; - } else if(!strcmp(name, "outputfilename")) { + if(!strcmp(name, "outputfilename")) { swffilename = value; } else if(!strcmp(name, "caplinewidth")) { caplinewidth = atof(value); - } else if(!strcmp(name, "splinequality")) { - int v = atoi(value); - v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel - if(v<1) v = 1; - splinemaxerror = v; - } else if(!strcmp(name, "fontquality")) { - int v = atoi(value); - v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel - if(v<1) v = 1; - fontsplinemaxerror = v; + } else if(!strcmp(name, "zoom")) { + zoom = atoi(value); } else { - fprintf(stderr, "unknown parameter: %s (=%s)\n", name, value); + swfoutput_setparameter(name, value); } } -void pdfswf_drawonlyshapes() -{ - drawonlyshapes = 1; -} - -void pdfswf_ignoredraworder() -{ - ignoredraworder = 1; -} - -void pdfswf_linksopennewwindow() +void pdfswf_addfont(char*filename) { - opennewwindow = 1; -} - -void pdfswf_storeallcharacters() -{ - storeallcharacters = 1; -} - -void pdfswf_enablezlib() -{ - enablezlib = 1; -} - -void pdfswf_jpegquality(int val) -{ - if(val<0) val=0; - if(val>100) val=100; - jpegquality = val; -} - -void pdfswf_setoutputfilename(char*_filename) -{ - swffilename = _filename; -} - -void pdfswf_insertstop() -{ - insertstoptag = 1; -} - -void pdfswf_setversion(int n) -{ - flashversion = n; + fontfile_t f; + memset(&f, 0, sizeof(fontfile_t)); + f.filename = filename; + fonts[fontnum++] = f; } +void pdfswf_setoutputfilename(char*_filename) { swffilename = _filename; } void pdfswf_convertpage(int page) { @@ -1891,10 +1845,13 @@ void pdfswf_performconversion() for(t=0;tdisplayPage((OutputDev*)output, currentpage, /*dpi*/72, /*rotate*/0, /*doLinks*/(int)1); +#ifdef XPDF_101 + doc->displayPage((OutputDev*)output, currentpage, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1); +#else + doc->displayPage((OutputDev*)output, currentpage, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1); +#endif } } - int pdfswf_numpages() { return doc->getNumPages(); @@ -1902,7 +1859,7 @@ int pdfswf_numpages() int closed=0; void pdfswf_close() { - logf(" pdfswf.cc: pdfswf_close()"); + msg(" pdfswf.cc: pdfswf_close()"); delete output; delete doc; //freeParams();