added xpdf-3.00 support.
[swftools.git] / pdf2swf / SWFOutputDev.cc
index 5ae25d4..8e93f5d 100644 (file)
@@ -23,6 +23,9 @@
 #include <string.h>
 #include <unistd.h>
 #include "../config.h"
+#ifdef HAVE_FONTCONFIG_H
+#include <fontconfig.h>
+#endif
 //xpdf header files
 #include "config.h"
 #include "gfile.h"
 #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"
 #include "../lib/log.h"
@@ -70,6 +81,7 @@ static int pagebuflen = 0;
 static int pagepos = 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);
@@ -645,6 +657,9 @@ void SWFOutputDev::beginString(GfxState *state, GString *s)
     m11 *= state->getHorizScaling();
     m21 *= state->getHorizScaling();
     swfoutput_setfontmatrix(&output, m11, -m21, m12, -m22);
+    
+    msg("<debug> fontmatrix %7.3f %7.3f\n", m11,-m21);
+    msg("<debug> fontmatrix %7.3f %7.3f\n", m12,-m22);
 }
 
 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
@@ -666,7 +681,7 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y,
     x1 = x;
     y1 = y;
     state->transform(x, y, &x1, &y1);
-       
+    
     Unicode u=0;
     if(_u) 
        u = *_u;
@@ -693,6 +708,9 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y,
     
     msg("<debug> 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);
 }
 
@@ -759,7 +777,11 @@ void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
   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;
@@ -990,6 +1012,11 @@ 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;
@@ -1030,8 +1057,13 @@ char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
        msg("<error> 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;
@@ -1043,8 +1075,13 @@ char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
        msg("<error> Couldn't read embedded font file");
        return 0;
       }
+#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 {
@@ -1091,11 +1128,106 @@ 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)
 {
-    char*fontname = "Times-Roman";
-    msg("<verbose> substituteFont(,%s)", FIXNULL(oldname));
-    char*filename = searchFont(fontname);
+    char*fontname = 0, *filename = 0;
+    msg("<notice> subsituteFont(%s)", oldname);
+
+    if(!(fontname = searchForSuitableFont(gfxFont))) {
+       fontname = "Times-Roman";
+    }
+    filename = searchFont(fontname);
+
     if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
        msg("<fatal> Too many fonts in file.");
        exit(1);
@@ -1175,9 +1307,12 @@ void SWFOutputDev::updateFont(GfxState *state)
     }
 
     // look for Type 3 font
-    if (!type3Warning && gfxFont->getType() == fontType3) {
-       type3Warning = gTrue;
-       showFontError(gfxFont, 2);
+    if (gfxFont->getType() == fontType3) {
+       if(!type3Warning) {
+           type3Warning = gTrue;
+           showFontError(gfxFont, 2);
+       }
+       return;
     }
 
     /* now either load the font, or find a substitution */
@@ -1205,9 +1340,11 @@ void SWFOutputDev::updateFont(GfxState *state)
     }
     if(!fileName) {
        char * fontname = getFontName(gfxFont);
-       msg("<warning> Font %s could not be loaded.", fontname);
+       msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
        msg("<warning> 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("<notice> Font is now %s (%s)", fontid, fileName);
     }
 
     if(!fileName) {
@@ -1665,41 +1802,14 @@ 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);
     }
 }
 
@@ -1711,53 +1821,7 @@ void pdfswf_addfont(char*filename)
     fonts[fontnum++] = f;
 }
 
-void pdfswf_drawonlyshapes()
-{
-    drawonlyshapes = 1;
-}
-
-void pdfswf_ignoredraworder()
-{
-    ignoredraworder = 1;
-}
-
-void pdfswf_linksopennewwindow()
-{
-    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;
-}
-
+void pdfswf_setoutputfilename(char*_filename) { swffilename = _filename; }
 
 void pdfswf_convertpage(int page)
 {
@@ -1781,10 +1845,13 @@ void pdfswf_performconversion()
     for(t=0;t<pagepos;t++)
     {
        currentpage = pages[t];
-       doc->displayPage((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();