CIDFonts: look for external replacement.
[swftools.git] / pdf2swf / SWFOutputDev.cc
index 7563762..f0533fa 100644 (file)
@@ -21,7 +21,9 @@
 #include <stdlib.h>
 #include <stddef.h>
 #include <string.h>
+#include <unistd.h>
 //xpdf header files
+#include "gfile.h"
 #include "GString.h"
 #include "gmem.h"
 #include "Object.h"
 #include "Catalog.h"
 #include "Page.h"
 #include "PDFDoc.h"
-#include "Params.h"
 #include "Error.h"
 #include "config.h"
 #include "OutputDev.h"
 #include "GfxState.h"
 #include "GfxFont.h"
 #include "FontFile.h"
+#include "GlobalParams.h"
 //swftools header files
 #include "swfoutput.h"
 extern "C" {
 #include "../lib/log.h"
+#include "ttf2pt1.h"
 }
 
-static char* filename = 0;
+#define logf logarithmf // logf is also used by ../lib/log.h
+#include <math.h>
+#undef logf
+
+static PDFDoc*doc = 0;
+static char* swffilename = 0;
+int numpages;
+int currentpage;
+
+// swf <-> pdf pages
+int*pages = 0;
+int pagebuflen = 0;
+int pagepos = 0;
 
 static void printInfoString(Dict *infoDict, char *key, char *fmt);
 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
 
-static char userPassword[33] = "";
-static GBool printVersion = gFalse;
-static GBool printHelp = gFalse;
-
 double fontsizes[] = 
 {
- 0.833,0.833,0.889,0.889,0.788,0.722,0.833,0.778,0.600,0.600,0.600,0.600,0.576,0.576,0.576,0.576
+ 0.833,0.833,0.889,0.889,
+ 0.788,0.722,0.833,0.778,
+ 0.600,0.600,0.600,0.600,
+ 0.576,0.576,0.576,0.576,
+ 0.733 //?
 };
 char*fontnames[]={
 "Helvetica",             
@@ -98,48 +113,6 @@ struct mapping {
 {"Symbol",                "s050000l.pfb"},
 {"ZapfDingbats",          "d050000l.pfb"}};
 
-static void printInfoString(Dict *infoDict, char *key, char *fmt) {
-  Object obj;
-  GString *s1, *s2;
-  int i;
-
-  if (infoDict->lookup(key, &obj)->isString()) {
-    s1 = obj.getString();
-    if ((s1->getChar(0) & 0xff) == 0xfe &&
-       (s1->getChar(1) & 0xff) == 0xff) {
-      s2 = new GString();
-      for (i = 2; i < obj.getString()->getLength(); i += 2) {
-       if (s1->getChar(i) == '\0') {
-         s2->append(s1->getChar(i+1));
-       } else {
-         delete s2;
-         s2 = new GString("<unicode>");
-         break;
-       }
-      }
-      printf(fmt, s2->getCString());
-      delete s2;
-    } else {
-      printf(fmt, s1->getCString());
-    }
-  }
-  obj.free();
-}
-
-static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
-  Object obj;
-  char *s;
-
-  if (infoDict->lookup(key, &obj)->isString()) {
-    s = obj.getString()->getCString();
-    if (s[0] == 'D' && s[1] == ':') {
-      s += 2;
-    }
-    printf(fmt, s);
-  }
-  obj.free();
-}
-
 class GfxState;
 class GfxImageColorMap;
 
@@ -162,9 +135,13 @@ public:
 
   // Does this device use drawChar() or drawString()?
   virtual GBool useDrawChar();
+  
+  virtual GBool interpretType3Chars() {return gTrue;}
 
   //----- initialization and control
 
+  void startDoc(XRef *xref);
+
   // Start a page.
   virtual void startPage(int pageNum, GfxState *state) ;
 
@@ -203,9 +180,9 @@ public:
   virtual void beginString(GfxState *state, GString *s) ;
   virtual void endString(GfxState *state) ;
   virtual void drawChar(GfxState *state, double x, double y,
-                       double dx, double dy, Guchar c) ;
-  virtual void drawChar16(GfxState *state, double x, double y,
-                         double dx, double dy, int c) ;
+                       double dx, double dy,
+                       double originX, double originY,
+                       CharCode code, Unicode *u, int uLen);
 
   //----- image drawing
   virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
@@ -213,15 +190,33 @@ public:
                             GBool inlineImg);
   virtual void drawImage(GfxState *state, Object *ref, Stream *str,
                         int width, int height, GfxImageColorMap *colorMap,
-                        GBool inlineImg);
+                        int *maskColors, GBool inlineImg);
+  
+  virtual GBool beginType3Char(GfxState *state,
+                              CharCode code, Unicode *u, int uLen);
+  virtual void endType3Char(GfxState *state);
 
   private:
-  int clipping[32];
+  void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
+                                  int width, int height, GfxImageColorMap*colorMap, GBool invert,
+                                  GBool inlineImg, int mask);
+  int clipping[64];
   int clippos;
 
-  int setT1Font(char*name,FontEncoding*enc);
-  int initT1Font(int id, FontEncoding*encoding);
+  XRef*xref;
+
+  int searchT1Font(char*name);
+  char* substituteFont(GfxFont*gfxFont, char*oldname);
+  char* writeEmbeddedFontToFile(XRef*ref, GfxFont*font);
   int t1id;
+  int jpeginfo; // did we write "File contains jpegs" yet?
+  int pbminfo; // did we write "File contains jpegs" yet?
+  int linkinfo; // did we write "File contains links" yet?
+  int ttfinfo; // did we write "File contains TrueType Fonts" yet?
+
+  int type3active; // are we between beginType3()/endType3()?
+
+  GfxState *laststate;
 };
 
 char mybuf[1024];
@@ -340,46 +335,43 @@ int lastdumppos = 0;
  */
 void showFontError(GfxFont*font, int nr) 
 {  
-    Ref r=font->getID();
+    Ref*r=font->getID();
     int t;
     for(t=0;t<lastdumppos;t++)
-       if(lastdumps[t] == r.num)
+       if(lastdumps[t] == r->num)
            break;
     if(t < lastdumppos)
       return;
     if(lastdumppos<sizeof(lastdumps)/sizeof(int))
-    lastdumps[lastdumppos++] = r.num;
+    lastdumps[lastdumppos++] = r->num;
     if(nr == 0)
-      logf("<error> The following font caused problems:");
+      logf("<warning> The following font caused problems:");
     else if(nr == 1)
-      logf("<error> The following font caused problems (substituting):");
+      logf("<warning> The following font caused problems (substituting):");
     else if(nr == 2)
-      logf("<error> This document contains Type 3 Fonts: (some text may be incorrectly displayed)");
-
-    dumpFontInfo("<error>", font);
+      logf("<warning> The following Type 3 Font will be rendered as bitmap:");
+    dumpFontInfo("<warning>", font);
 }
 
 void dumpFontInfo(char*loglevel, GfxFont*font)
 {
   GString *gstr;
-  char*name;
+  char*name = 0;
   gstr = font->getName();
-  Ref r=font->getID();
-  logf("%s=========== %s (ID:%d) ==========\n", loglevel, gstr?gstr->getCString():"(unknown font)", r.num);
+  Ref* r=font->getID();
+  logf("%s=========== %s (ID:%d,%d) ==========\n", loglevel, gstr?FIXNULL(gstr->getCString()):"(unknown font)", r->num,r->gen);
 
   gstr  = font->getTag();
   if(gstr) 
-   logf("%sTag: %s\n", loglevel, gstr->getCString());
-  if(font->is16Bit()) logf("%sis 16 bit\n", loglevel);
+   logf("%sTag: %s\n", loglevel, FIXNULL(gstr->getCString()));
+  
+  if(font->isCIDFont()) logf("%sis CID font\n", loglevel);
 
   GfxFontType type=font->getType();
   switch(type) {
     case fontUnknownType:
      logf("%sType: unknown\n",loglevel);
     break;
-    case fontType0:
-     logf("%sType: 0\n",loglevel);
-    break;
     case fontType1:
      logf("%sType: 1\n",loglevel);
     break;
@@ -392,14 +384,27 @@ void dumpFontInfo(char*loglevel, GfxFont*font)
     case fontTrueType:
      logf("%sType: TrueType\n",loglevel);
     break;
+    case fontCIDType0:
+     logf("%sType: CIDType0\n",loglevel);
+    break;
+    case fontCIDType0C:
+     logf("%sType: CIDType0C\n",loglevel);
+    break;
+    case fontCIDType2:
+     logf("%sType: CIDType2\n",loglevel);
+    break;
   }
-  name = font->getEmbeddedFontName();
-  if(name)
-   logf("%sEmbedded name: %s\n",loglevel, name);
+  
+  Ref embRef;
+  GBool embedded = font->getEmbeddedFontID(&embRef);
+  if(font->getEmbeddedFontName())
+    name = font->getEmbeddedFontName()->getCString();
+  if(embedded)
+   logf("%sEmbedded name: %s id: %d\n",loglevel, FIXNULL(name), embRef.num);
 
   gstr = font->getExtFontFile();
   if(gstr)
-   logf("%sExternal Font file: %s\n", loglevel, gstr->getCString());
+   logf("%sExternal Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
 
   // Get font descriptor flags.
   if(font->isFixedWidth()) logf("%sis fixed width\n", loglevel);
@@ -414,9 +419,15 @@ void dumpFontInfo(char*loglevel, GfxFont*font)
 
 SWFOutputDev::SWFOutputDev() 
 {
+    jpeginfo = 0;
+    ttfinfo = 0;
+    linkinfo = 0;
+    pbminfo = 0;
+    type3active = 0;
     clippos = 0;
     clipping[clippos] = 0;
     outputstarted = 0;
+    xref = 0;
 //    printf("SWFOutputDev::SWFOutputDev() \n");
 };
 
@@ -424,7 +435,7 @@ T1_OUTLINE* gfxPath_to_T1_OUTLINE(GfxState*state, GfxPath*path)
 {
     int num = path->getNumSubpaths();
     int s,t;
-    bezierpathsegment*start,*last;
+    bezierpathsegment*start,*last=0;
     bezierpathsegment*outline = start = new bezierpathsegment();
     int cpos = 0;
     double lastx=0,lasty=0;
@@ -485,58 +496,59 @@ T1_OUTLINE* gfxPath_to_T1_OUTLINE(GfxState*state, GfxPath*path)
 
 void SWFOutputDev::stroke(GfxState *state) 
 {
-    logf("<debug> %s stroke\n",gfxstate2str(state));
+    logf("<debug> stroke\n");
     GfxPath * path = state->getPath();
     struct swfmatrix m;
     m.m11 = 1; m.m21 = 0; m.m22 = 1;
-    m.m21 = 0; m.m13 = 0; m.m23 = 0;
+    m.m12 = 0; m.m13 = 0; m.m23 = 0;
     T1_OUTLINE*outline = gfxPath_to_T1_OUTLINE(state, path);
     swfoutput_setdrawmode(&output, DRAWMODE_STROKE);
     swfoutput_drawpath(&output, outline, &m);
 }
 void SWFOutputDev::fill(GfxState *state) 
 {
-    logf("<debug> %s fill\n",gfxstate2str(state));
+    logf("<debug> fill\n");
     GfxPath * path = state->getPath();
     struct swfmatrix m;
     m.m11 = 1; m.m21 = 0; m.m22 = 1;
-    m.m21 = 0; m.m13 = 0; m.m23 = 0;
+    m.m12 = 0; m.m13 = 0; m.m23 = 0;
     T1_OUTLINE*outline = gfxPath_to_T1_OUTLINE(state, path);
     swfoutput_setdrawmode(&output, DRAWMODE_FILL);
     swfoutput_drawpath(&output, outline, &m);
 }
 void SWFOutputDev::eoFill(GfxState *state) 
 {
-    logf("<debug> %s eofill\n",gfxstate2str(state));
+    logf("<debug> eofill\n");
     GfxPath * path = state->getPath();
     struct swfmatrix m;
     m.m11 = 1; m.m21 = 0; m.m22 = 1;
-    m.m21 = 0; m.m13 = 0; m.m23 = 0;
+    m.m12 = 0; m.m13 = 0; m.m23 = 0;
     T1_OUTLINE*outline = gfxPath_to_T1_OUTLINE(state, path);
     swfoutput_setdrawmode(&output, DRAWMODE_EOFILL);
     swfoutput_drawpath(&output, outline, &m);
 }
 void SWFOutputDev::clip(GfxState *state) 
 {
-    logf("<debug> %s clip\n",gfxstate2str(state));
+    logf("<debug> clip\n");
     GfxPath * path = state->getPath();
     struct swfmatrix m;
-    m.m11 = 1; m.m21 = 0; m.m22 = 1;
-    m.m21 = 0; m.m13 = 0; m.m23 = 0;
+    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);
     swfoutput_startclip(&output, outline, &m);
-    clipping[clippos] = 1;
+    clipping[clippos] ++;
 }
 void SWFOutputDev::eoClip(GfxState *state) 
 {
-    logf("<debug> %s eoclip\n",gfxstate2str(state));
+    logf("<debug> eoclip\n");
     GfxPath * path = state->getPath();
     struct swfmatrix m;
     m.m11 = 1; m.m21 = 0; m.m22 = 1;
-    m.m21 = 0; m.m13 = 0; m.m23 = 0;
+    m.m12 = 0; m.m13 = 0; m.m23 = 0;
     T1_OUTLINE*outline = gfxPath_to_T1_OUTLINE(state, path);
     swfoutput_startclip(&output, outline, &m);
-    clipping[clippos] = 1;
+    clipping[clippos] ++;
 }
 
 SWFOutputDev::~SWFOutputDev() 
@@ -558,52 +570,85 @@ GBool SWFOutputDev::useDrawChar()
 void SWFOutputDev::beginString(GfxState *state, GString *s) 
 { 
     double m11,m21,m12,m22;
-    logf("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
+//    logf("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
     state->getFontTransMat(&m11, &m12, &m21, &m22);
     m11 *= state->getHorizScaling();
     m21 *= state->getHorizScaling();
-    swfoutput_setfontmatrix(&output, m11, -m12, m21, -m22);
+    swfoutput_setfontmatrix(&output, m11, -m21, m12, -m22);
 }
 
 int charcounter = 0;
-void SWFOutputDev::drawChar(GfxState *state, double x, double y, double dx, double dy, Guchar c) 
+int ciderror = 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("<debug> %s drawChar(%f,%f,%f,%f,'%c')\n",gfxstate2str(state), x,y,dx,dy,c);
+    logf("<debug> 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)
     {
-       FontEncoding*enc=state->getFont()->getEncoding();
+       GfxFont*font = state->getFont();
+       Gfx8BitFont*font8;
+       if(font->isCIDFont()) {
+          if(!ciderror)
+           logf("<error> Not drawing CID Font characters!");
+          ciderror++;
+          return;
+       }
+       if(font->getType() == fontType3) {
+          /* type 3 chars are passed primarily as graphics */
+          return;
+       }
+       font8 = (Gfx8BitFont*)font;
+
+       char**enc=font8->getEncoding();
 
        double x1,y1;
        x1 = x;
        y1 = y;
        state->transform(x, y, &x1, &y1);
 
-       swfoutput_drawchar(&output, x1, y1, c);
+       if(enc[c])
+         swfoutput_drawchar(&output, x1, y1, enc[c], c);
+       else
+         logf("<warning> couldn't get name for character %02x from Encoding", c);
     }
 }
 
-void SWFOutputDev::drawChar16(GfxState *state, double x, double y, double dx, double dy, int c) 
-{
-    printf("<error> %s drawChar16(%f,%f,%f,%f,%08x)\n",gfxstate2str(state), x,y,dx,dy,c);
-    exit(1);
-}
-
 void SWFOutputDev::endString(GfxState *state) 
 { 
-    logf("<debug> %s endstring\n", gfxstate2str(state));
+    logf("<debug> endstring\n");
 }    
 
+GBool SWFOutputDev::beginType3Char(GfxState *state,
+                              CharCode code, Unicode *u, int uLen)
+{
+    logf("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
+    type3active = 1;
+    /* the character itself is going to be passed using
+       drawImageMask() */
+    return gFalse; /* gTrue= is_in_cache? */
+}
+
+void SWFOutputDev::endType3Char(GfxState *state)
+{
+    type3active = 0;
+    logf("<debug> endType3Char");
+}
+
 void SWFOutputDev::startPage(int pageNum, GfxState *state) 
 {
   double x1,y1,x2,y2;
-  logf("<debug> %s, startPage %d\n", gfxstate2str(state), pageNum);
+  laststate = state;
+  logf("<debug> startPage %d\n", pageNum);
   logf("<notice> processing page %d", pageNum);
 
   state->transform(state->getX1(),state->getY1(),&x1,&y1);
   state->transform(state->getX2(),state->getY2(),&x2,&y2);
   if(!outputstarted) {
-    swfoutput_init(&output, filename, abs((int)(x2-x1)),abs((int)(y2-y1)));
+    swfoutput_init(&output, swffilename, abs((int)(x2-x1)),abs((int)(y2-y1)));
     outputstarted = 1;
   }
   else
@@ -619,38 +664,87 @@ void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
   int x, y;
 
   link->getBorder(&x1, &y1, &x2, &y2, &w);
-  if (w > 0) {
+//  if (w > 0) 
+  {
     rgb.r = 0;
     rgb.g = 0;
     rgb.b = 1;
     cvtUserToDev(x1, y1, &x, &y);
-    points[0].x = points[4].x = x;
-    points[0].y = points[4].y = y;
+    points[0].x = points[4].x = (int)x;
+    points[0].y = points[4].y = (int)y;
     cvtUserToDev(x2, y1, &x, &y);
-    points[1].x = x;
-    points[1].y = y;
+    points[1].x = (int)x;
+    points[1].y = (int)y;
     cvtUserToDev(x2, y2, &x, &y);
-    points[2].x = x;
-    points[2].y = y;
+    points[2].x = (int)x;
+    points[2].y = (int)y;
     cvtUserToDev(x1, y2, &x, &y);
-    points[3].x = x;
-    points[3].y = y;
-    //PDF: draw rect
+    points[3].x = (int)x;
+    points[3].y = (int)y;
+
     LinkAction*action=link->getAction();
-    char*s;
+    char buf[128];
+    char*s = "-?-";
+    char*type = "-?-";
+    char*url = 0;
+    char*named = 0;
+    int page = -1;
     switch(action->getKind())
     {
        case actionGoTo: {
-           LinkGoTo*l = (LinkGoTo*)action;
-           s = l->getNamedDest()->getCString();
+           type = "GoTo";
+           LinkGoTo *ha=(LinkGoTo *)link->getAction();
+           LinkDest *dest=NULL;
+           if (ha->getDest()==NULL) 
+               dest=catalog->findDest(ha->getNamedDest());
+           else dest=ha->getDest();
+           if (dest){ 
+             if (dest->isPageRef()){
+               Ref pageref=dest->getPageRef();
+               page=catalog->findPage(pageref.num,pageref.gen);
+             }
+             else  page=dest->getPageNum();
+             sprintf(buf, "%d", page);
+             s = buf;
+           }
        }
         break;
        case actionGoToR: {
+           type = "GoToR";
            LinkGoToR*l = (LinkGoToR*)action;
-           s = l->getNamedDest()->getCString();
+           GString*g = l->getNamedDest();
+           if(g)
+            s = g->getCString();
+       }
+        break;
+       case actionNamed: {
+           type = "Named";
+           LinkNamed*l = (LinkNamed*)action;
+           GString*name = l->getName();
+           if(name) {
+             s = name->lowerCase()->getCString();
+             named = name->getCString();
+             if(strstr(s, "next") || strstr(s, "forward"))
+             {
+                 page = currentpage + 1;
+             }
+             else if(strstr(s, "prev") || strstr(s, "back"))
+             {
+                 page = currentpage - 1;
+             }
+             else if(strstr(s, "last") || strstr(s, "end"))
+             {
+                 page = pages[pagepos-1]; //:)
+             }
+             else if(strstr(s, "first") || strstr(s, "top"))
+             {
+                 page = 1;
+             }
+           }
        }
         break;
        case actionLaunch: {
+           type = "Launch";
            LinkLaunch*l = (LinkLaunch*)action;
            GString * str = new GString(l->getFileName());
            str->append(l->getParams());
@@ -658,49 +752,84 @@ void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
        }
         break;
        case actionURI: {
+           type = "URI";
            LinkURI*l = (LinkURI*)action;
-           s = l->getURI()->getCString();
-       }
-        break;
-       case actionNamed: {
-           LinkNamed*l = (LinkNamed*)action;
-           s = l->getName()->getCString();
+           GString*g = l->getURI();
+           if(g) {
+            url = g->getCString();
+            s = url;
+           }
        }
         break;
        case actionUnknown: {
+           type = "Unknown";
            LinkUnknown*l = (LinkUnknown*)action;
            s = "";
        }
         break;
+       default: {
+           logf("<error> Unknown link type!\n");
+           break;
+       }
+    }
+    if(!linkinfo && (page || url))
+    {
+       logf("<notice> File contains links");
+       linkinfo = 1;
+    }
+    if(page>0)
+    {
+       int t;
+       for(t=0;t<pagepos;t++)
+           if(pages[t]==page)
+               break;
+       if(t!=pagepos)
+       swfoutput_linktopage(&output, t, points);
+    }
+    else if(url)
+    {
+       swfoutput_linktourl(&output, url, points);
+    }
+    else if(named)
+    {
+       swfoutput_namedlink(&output, named, points);
     }
-    logf("<verbose> link to \"%s\"\n", s);
+    logf("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
   }
 }
 
 void SWFOutputDev::saveState(GfxState *state) {
-  logf("<debug> %s saveState\n", gfxstate2str(state));
+  logf("<debug> saveState\n");
   updateAll(state);
-  clippos ++;
+  if(clippos<64)
+    clippos ++;
+  else
+    logf("<error> Too many nested states in pdf.");
   clipping[clippos] = 0;
 };
 
 void SWFOutputDev::restoreState(GfxState *state) {
-  logf("<debug> %s restoreState\n", gfxstate2str(state));
+  logf("<debug> restoreState\n");
   updateAll(state);
-  if(clipping[clippos])
+  while(clipping[clippos]) {
       swfoutput_endclip(&output);
+      clipping[clippos]--;
+  }
   clippos--;
 }
 
 char type3Warning=0;
 
-int SWFOutputDev::setT1Font(char*name, FontEncoding*encoding) 
+int SWFOutputDev::searchT1Font(char*name) 
 {      
     int i;
-    
-    int id=-1;
     int mapid=-1;
     char*filename=0;
+    
+    char*name2 = 0;
+    if(name) name2 = strchr(name,'+');
+    if(name2) name2++;
+
     for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++) 
     {
        if(!strcmp(name, pdf2t1map[i].pdffont))
@@ -709,63 +838,51 @@ int SWFOutputDev::setT1Font(char*name, FontEncoding*encoding)
            mapid = i;
        }
     }
-    if(filename)
-    for(i=0; i<T1_Get_no_fonts(); i++)
-    {
-       char*fontfilename = T1_GetFontFileName (i);
-       if(strstr(fontfilename, filename))
+    if(filename) {
+       for(i=0; i<T1_Get_no_fonts(); i++)
        {
-               id = i;
-               pdf2t1map[i].id = mapid;
+           char*fontfilename = T1_GetFontFileName (i);
+           if(strstr(fontfilename, filename))
+           {
+                   pdf2t1map[i].id = mapid;
+                   return i;
+           }
        }
-    }
-    if(id<0)
-     return 0;
-
-    initT1Font(id, encoding);
-}
+    } else {
+       for(i=0; i<T1_Get_no_fonts(); i++)
+       {
+           char*fontname = T1_GetFontName (i);
+           if(!fontname) {
+               T1_LoadFont(i);
+               fontname = T1_GetFontName (i);
+               logf("<verbose> Loading extra font %s from %s\n", FIXNULL(fontname), 
+                                                                 FIXNULL(T1_GetFontFileName(i)));
+           }
 
-int SWFOutputDev::initT1Font(int id, FontEncoding*encoding)
-{
-    int encStrSize;
-    char *encPtr;
-    int i;
-    T1_DeleteFont(id);
-    T1_LoadFont(id);
-    /* reencode the font: 
-     * This is the only way to get the unmapped characters
-     * from t1lib
-     */
-    encStrSize = 0;
-    for (i = 0; i < 256 && i < encoding->getSize(); ++i) {
-      if (encoding->getCharName(i)) {
-       encStrSize += strlen(encoding->getCharName(i)) + 1;
-      }
-    }
-    char**enc = (char **)gmalloc(257 * sizeof(char *));
-    char*encStr = (char *)gmalloc(encStrSize * sizeof(char));
-    encPtr = encStr;
-    for (i = 0; i < 256 && i < encoding->getSize(); ++i) {
-      if (encoding->getCharName(i)) {
-       strcpy(encPtr, encoding->getCharName(i));
-       enc[i] = encPtr;
-       encPtr += strlen(encPtr) + 1;
-      } else {
-       enc[i] = ".notdef";
-      }
-    }
-    for (; i < 256; ++i) {
-      enc[i] = ".notdef";
+           if(fontname) {
+               if((!strcmp(name, fontname)) || 
+                  (name2 && !strcmp(name2, fontname)))
+                  {
+                   logf("<notice> Extra font %s is being used.\n", fontname);
+                   return i;
+               }
+           }
+           fontname = T1_GetFontFileName(i);
+           if(strrchr(fontname,'/'))
+                   fontname = strrchr(fontname,'/')+1;
+           if(strstr(fontname, name) || (name2 && strstr(fontname,name2))) {
+               logf("<notice> Extra font %s is being used.\n", fontname);
+               return i;
+           }
+       }
     }
-    enc[256] = "custom";
-    int ret=T1_ReencodeFont(id, enc);
-    t1id = id;
-    return 1;
+    return -1;
 }
 
 void SWFOutputDev::updateLineWidth(GfxState *state)
 {
-    double width = state->getLineWidth();
+    double width = state->getTransformedLineWidth();
     swfoutput_setlinewidth(&output, width);
 }
 
@@ -789,60 +906,45 @@ void SWFOutputDev::updateStrokeColor(GfxState *state)
                                      (char)(rgb.b*255), (char)(opaq*255));
 }
 
-void SWFOutputDev::updateFont(GfxState *state) 
+char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
 {
-  double m11, m12, m21, m22;
-  char * fontname = 0;
-  GfxFont*gfxFont = state->getFont();
-  char * filename;
-
-  if (!gfxFont) {
-    return;
-  }  
-  // look for Type 3 font
-  if (!type3Warning && gfxFont->getType() == fontType3) {
-    type3Warning = gTrue;
-    showFontError(gfxFont, 2);
-  }
-  //dumpFontInfo (gfxFont);
-  
+      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) {
+         /* not embedded- the caller should now search the font
+            directories for this font */
+         return 0;
+      }
 
-  Ref embRef;
-  GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
-  if(embedded) {
-    char*tmpFileName = NULL;
-    char*fileName = NULL;
-    FILE *f;
-    char *fontBuf;
-    int fontLen;
-    Type1CFontConverter *cvt;
-    Ref embRef;
-    Object refObj, strObj;
-    int c;
-    if (!gfxFont->is16Bit() &&
-       (gfxFont->getType() == fontType1 ||
-        gfxFont->getType() == fontType1C) &&
-       gfxFont->getEmbeddedFontID(&embRef)) {
-      tmpFileName = "tmpfont";
       f = fopen(tmpFileName, "wb");
       if (!f) {
        logf("<error> Couldn't create temporary Type 1 font file");
-       return;
+         return 0;
       }
-      if (gfxFont->getType() == fontType1C) {
-       if (!(fontBuf = gfxFont->readEmbFontFile(&fontLen))) {
+      if (font->getType() == fontType1C) {
+       if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
          fclose(f);
          logf("<error> Couldn't read embedded font file");
-         return ;
+         return 0;
        }
-       cvt = new Type1CFontConverter(fontBuf, fontLen, f);
-       cvt->convert();
+       cvt = new Type1CFontFile(fontBuf, fontLen);
+       cvt->convertToType1(f);
        delete cvt;
        gfree(fontBuf);
       } else {
-       gfxFont->getEmbeddedFontID(&embRef);
+       font->getEmbeddedFontID(&embRef);
        refObj.initRef(embRef.num, embRef.gen);
-       refObj.fetch(&strObj);
+       refObj.fetch(ref, &strObj);
        refObj.free();
        strObj.streamReset();
        while ((c = strObj.streamGetChar()) != EOF) {
@@ -852,43 +954,97 @@ void SWFOutputDev::updateFont(GfxState *state)
        strObj.free();
       }
       fclose(f);
-      fileName = tmpFileName;
-      if(!fileName) {
-         logf("<error> Embedded font writer didn't create a file");
-         return ;
+
+      if(font->getType() == fontTrueType)
+      {
+         if(!ttfinfo) {
+             logf("<notice> File contains TrueType fonts");
+             ttfinfo = 1;
+         }
+         char name2[80];
+         char*tmp;
+         tmp = strdup(mktmpname((char*)name2));
+         sprintf(name2, "%s", tmp);
+         char*a[] = {"./ttf2pt1","-pttf","-b", tmpFileName, name2};
+         logf("<verbose> Invoking ttf2pt1...");
+         ttf2pt1_main(5,a);
+         unlink(tmpFileName);
+         sprintf(name2,"%s.pfb",tmp);
+         tmpFileName = strdup(name2);
       }
+
+    return 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* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
+{
+/* ------------------------------ V1 */
+
+    char*fontname = "Times-Roman";
+    this->t1id = searchT1Font(fontname);
+    if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
+       logf("<fatal> Too many fonts in file.");
+       exit(1);
     }
-    else {
-       showFontError(gfxFont,0);
-       return ;
-    }
-    t1id = T1_AddFont(fileName);
-    initT1Font(t1id, gfxFont->getEncoding());
-  } else {
-    fontname = NULL;
-    if(gfxFont->getName()) {
-      fontname = gfxFont->getName()->getCString();
-      //logf("<notice> Processing font %s", fontname);
+    if(oldname) {
+       substitutesource[substitutepos] = oldname;
+       substitutetarget[substitutepos] = fontname;
+       logf("<verbose> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
+       substitutepos ++;
     }
-    if(!fontname || !setT1Font(state->getFont()->getName()->getCString(), gfxFont->getEncoding()))
-    { //substitute font
+    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 (!gfxFont->is16Bit()) {
-       if (gfxFont->isFixedWidth()) {
+      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())
+       if (gfxFont->isBold() && index!=16)
          index += 2;
-       if (gfxFont->isItalic())
+       if (gfxFont->isItalic() && index!=16)
          index += 1;
        fontname = fontnames[index];
        // get width of 'm' in real font and substituted font
@@ -930,91 +1086,541 @@ void SWFOutputDev::updateFont(GfxState *state)
          }
        }
       }
-      if(fontname)
-        setT1Font(fontname, gfxFont->getEncoding());
+      if(fontname) {
+        this->t1id = searchT1Font(fontname);
+      }
+      if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
+         logf("<fatal> Too many fonts in file.");
+         exit(1);
+      }
+      if(oldname) {
+         substitutesource[substitutepos] = oldname;
+         substitutetarget[substitutepos] = fontname;
+         logf("<verbose> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
+         substitutepos ++;
+      }
+      return fontname;*/
+}
+
+void unlinkfont(char* filename)
+{
+    int l;
+    if(!filename)
+       return;
+    l=strlen(filename);
+    unlink(filename);
+    if(!strncmp(&filename[l-4],".afm",4)) {
+       memcpy(&filename[l-4],".pfb",4);
+       unlink(filename);
+       memcpy(&filename[l-4],".pfa",4);
+       unlink(filename);
+       memcpy(&filename[l-4],".afm",4);
+       return;
+    } else 
+    if(!strncmp(&filename[l-4],".pfa",4)) {
+       memcpy(&filename[l-4],".afm",4);
+       unlink(filename);
+       memcpy(&filename[l-4],".pfa",4);
+       return;
+    } else 
+    if(!strncmp(&filename[l-4],".pfb",4)) {
+       memcpy(&filename[l-4],".afm",4);
+       unlink(filename);
+       memcpy(&filename[l-4],".pfb",4);
+       return;
     }
-  }
+}
 
-  swfoutput_setfont(&output,gfxFont->getID().num,t1id);
+void SWFOutputDev::startDoc(XRef *xref) 
+{
+  this->xref = xref;
 }
 
-void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
-                                  int width, int height, GBool invert,
-                                  GBool inlineImg) {
-  FILE *fi;
-  int c;
-  char fileName[128];
-  double x1,y1,x2,y2,x3,y3,x4,y4;
-  state->transform(0, 1, &x1, &y1);
-  state->transform(0, 0, &x2, &y2);
-  state->transform(1, 0, &x3, &y3);
-  state->transform(1, 1, &x4, &y4);
 
-  if (str->getKind() == strDCT) {
-    sprintf(fileName, "/tmp/tmp%08x.jpg",lrand48());
-    logf("<notice> Found picture. Temporary storage is %s", fileName);
-    if (!(fi = fopen(fileName, "wb"))) {
-      logf("<error> Couldn't open temporary image file '%s'", fileName);
+void SWFOutputDev::updateFont(GfxState *state) 
+{
+  GfxFont*gfxFont = state->getFont();
+  char * fileName = 0;
+    
+  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<substitutepos;t++) {
+      if(!strcmp(fontname, substitutesource[t])) {
+         fontname = substitutetarget[t];
+         break;
+      }
+  }
+
+  /* second, see if swfoutput already has this font
+     cached- if so, we are done */
+
+  if(swfoutput_queryfont(&output, fontname))
+  {
+      swfoutput_setfont(&output, fontname, -1, 0);
       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 */
+
+  Ref embRef;
+  GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
+  if(embedded) {
+    if (!gfxFont->isCIDFont() &&
+       (gfxFont->getType() == fontType1 ||
+        gfxFont->getType() == fontType1C ||
+        gfxFont->getType() == fontTrueType)) {
+       
+       fileName = writeEmbeddedFontToFile(xref, gfxFont);
+       if(!fileName) {
+         logf("<error> Couldn't write font to file");
+         showFontError(gfxFont,0);
+         return ;
+       }
+       this->t1id = T1_AddFont(fileName);
+       if(this->t1id<0) {
+         logf("<error> Couldn't load font from file");
+         showFontError(gfxFont,0);
+         unlinkfont(fileName);
+         return ;
+       }
+    }
+    else {
+       int newt1id = searchT1Font(fontname);
+       if(newt1id<0) {
+           showFontError(gfxFont,0);
+           fontname = substituteFont(gfxFont, fontname);
+       } else
+           this->t1id = newt1id;
     }
-    str = ((DCTStream *)str)->getRawStream();
-    str->reset();
-    while ((c = str->getChar()) != EOF)
-      fputc(c, fi);
-    fclose(fi);
-    swfoutput_drawimagefile(&output, fileName, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
   } else {
-      logf("<notice> File contains pbm pictures.");
+    if(fontname) {
+       int newt1id = searchT1Font(fontname);
+       if(newt1id<0) {
+           fontname = substituteFont(gfxFont, fontname);
+       } else
+           this->t1id = newt1id;
+    }
+    else
+       fontname = substituteFont(gfxFont, fontname);
   }
+
+  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("<verbose> 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);
 }
 
-void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
-                              int width, int height,
-                              GfxImageColorMap *colorMap, GBool inlineImg) {
+int pic_xids[1024];
+int pic_yids[1024];
+int pic_ids[1024];
+int pic_width[1024];
+int pic_height[1024];
+int picpos = 0;
+int pic_id = 0;
+
+#define SQR(x) ((x)*(x))
+
+unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
+{
+    if((newwidth<2 || newheight<2) ||
+       (width<=newwidth || height<=newheight))
+       return 0;
+    unsigned char*newdata;
+    int x,y;
+    newdata= (unsigned char*)malloc(newwidth*newheight);
+    int t;
+    double fx = (double)(width)/newwidth;
+    double fy = (double)(height)/newheight;
+    double px = 0;
+    int blocksize = (int)(8192/(fx*fy));
+    int r = 8192*256/palettesize;
+    for(x=0;x<newwidth;x++) {
+       double ex = px + fx;
+       int fromx = (int)px;
+       int tox = (int)ex;
+       int xweight1 = (int)(((fromx+1)-px)*256);
+       int xweight2 = (int)((ex-tox)*256);
+       double py =0;
+       for(y=0;y<newheight;y++) {
+           double ey = py + fy;
+           int fromy = (int)py;
+           int toy = (int)ey;
+           int yweight1 = (int)(((fromy+1)-py)*256);
+           int yweight2 = (int)((ey-toy)*256);
+           int a = 0;
+           int xx,yy;
+           for(xx=fromx;xx<=tox;xx++)
+           for(yy=fromy;yy<=toy;yy++) {
+               int b = 1-data[width*yy+xx];
+               int weight=256;
+               if(xx==fromx) weight = (weight*xweight1)/256;
+               if(xx==tox) weight = (weight*xweight2)/256;
+               if(yy==fromy) weight = (weight*yweight1)/256;
+               if(yy==toy) weight = (weight*yweight2)/256;
+               a+=b*weight;
+           }
+           //if(a) a=(palettesize-1)*r/blocksize;
+           newdata[y*newwidth+x] = (a*blocksize)/r;
+           py = ey;
+       }
+       px = ex;
+    }
+    return newdata;
+}
+
+void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
+                                  int width, int height, GfxImageColorMap*colorMap, GBool invert,
+                                  GBool inlineImg, int mask)
+{
   FILE *fi;
   int c;
   char fileName[128];
   double x1,y1,x2,y2,x3,y3,x4,y4;
+  ImageStream *imgStr;
+  Guchar pixBuf[4];
+  GfxRGB rgb;
+  int ncomps = 1;
+  int bits = 1;
+                                
+  if(colorMap) {
+    ncomps = colorMap->getNumPixelComps();
+    bits = colorMap->getBits();
+  }
+  imgStr = new ImageStream(str, width, ncomps,bits);
+  imgStr->reset();
+
+  if(!width || !height || (height<=1 && width<=1))
+  {
+      logf("<verbose> Ignoring %d by %d image", width, height);
+      unsigned char buf[8];
+      int x,y;
+      for (y = 0; y < height; ++y)
+      for (x = 0; x < width; ++x) {
+         imgStr->getPixel(buf);
+      }
+      delete imgStr;
+      return;
+  }
+  
   state->transform(0, 1, &x1, &y1);
   state->transform(0, 0, &x2, &y2);
   state->transform(1, 0, &x3, &y3);
   state->transform(1, 1, &x4, &y4);
 
-  if (str->getKind() == strDCT &&
-      colorMap->getNumPixelComps() == 3) {
-    sprintf(fileName, "/tmp/tmp%08x.jpg", lrand48());
-    logf("<notice> Found picture. Temporary storage is %s", fileName);
-    if (!(fi = fopen(fileName, "wb"))) {
-      error(-1, "Couldn't open temporary image file '%s'", fileName);
+  if(!pbminfo && !(str->getKind()==strDCT)) {
+      if(!type3active) {
+         logf("<notice> file contains pbm pictures %s",mask?"(masked)":"");
+         pbminfo = 1;
+      }
+      if(mask)
+      logf("<verbose> drawing %d by %d masked picture\n", width, height);
+  }
+  if(!jpeginfo && (str->getKind()==strDCT)) {
+      logf("<notice> file contains jpeg pictures");
+      jpeginfo = 1;
+  }
+
+  if(mask) {
+      int yes=0,i,j;
+      unsigned char buf[8];
+      int xid = 0;
+      int yid = 0;
+      int x,y;
+      unsigned char*pic = new unsigned char[width*height];
+      RGBA pal[256];
+      GfxRGB rgb;
+      state->getFillRGB(&rgb);
+      memset(pal,255,sizeof(pal));
+      pal[0].r = (int)(rgb.r*255); pal[0].g = (int)(rgb.g*255); 
+      pal[0].b = (int)(rgb.b*255); pal[0].a = 255;
+      pal[1].r = 0; pal[1].g = 0; pal[1].b = 0; pal[1].a = 0;
+      int numpalette = 2;
+      xid += pal[1].r*3 + pal[1].g*11 + pal[1].b*17;
+      yid += pal[1].r*7 + pal[1].g*5 + pal[1].b*23;
+      int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
+      int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
+      for (y = 0; y < height; ++y)
+      for (x = 0; x < width; ++x)
+      {
+           imgStr->getPixel(buf);
+           if(invert) 
+               buf[0]=1-buf[0];
+           pic[width*y+x] = buf[0];
+           xid+=x*buf[0]+1;
+           yid+=y*buf[0]*3+1;
+      }
+      
+      /* the size of the drawn image is added to the identifier
+        as the same image may require different bitmaps if displayed
+        at different sizes (due to antialiasing): */
+      if(type3active) {
+         xid += realwidth;
+         yid += realheight;
+      }
+      int t,found = -1;
+      for(t=0;t<picpos;t++)
+      {
+         if(pic_xids[t] == xid &&
+            pic_yids[t] == yid) {
+             /* if the image was antialiased, the size has changed: */
+             width = pic_width[t];
+             height = pic_height[t];
+             found = t;break;
+         }
+      }
+      if(found<0) {
+         if(type3active) {
+             numpalette = 16;
+             unsigned char*pic2 = 0;
+             
+             pic2 = antialize(pic,width,height,realwidth,realheight, numpalette);
+
+             if(pic2) {
+                 width = realwidth;
+                 height = realheight;
+                 free(pic);
+                 pic = pic2;
+                 /* make a black/white palette */
+                 int t;
+                 GfxRGB rgb2;
+                 rgb2.r = 1 - rgb.r;
+                 rgb2.g = 1 - rgb.g;
+                 rgb2.b = 1 - rgb.b;
+
+                 float r = 255/(numpalette-1);
+                 for(t=0;t<numpalette;t++) {
+                     /*pal[t].r = (U8)(t*r*rgb.r+(numpalette-1-t)*r*rgb2.r);
+                     pal[t].g = (U8)(t*r*rgb.g+(numpalette-1-t)*r*rgb2.g);
+                     pal[t].b = (U8)(t*r*rgb.b+(numpalette-1-t)*r*rgb2.b);
+                     pal[t].a = 255; */
+                     pal[t].r = (U8)(255*rgb.r);
+                     pal[t].g = (U8)(255*rgb.g);
+                     pal[t].b = (U8)(255*rgb.b);
+                     pal[t].a = (U8)(t*r);
+                 }
+             }
+         }
+         pic_ids[picpos] = swfoutput_drawimagelosslessN(&output, pic, pal, width, height, 
+                 x1,y1,x2,y2,x3,y3,x4,y4, numpalette);
+         pic_xids[picpos] = xid;
+         pic_yids[picpos] = yid;
+         pic_width[picpos] = width;
+         pic_height[picpos] = height;
+         if(picpos<1024)
+             picpos++;
+      } else {
+         swfoutput_drawimageagain(&output, pic_ids[found], width, height,
+                 x1,y1,x2,y2,x3,y3,x4,y4);
+      }
+      free(pic);
+      delete imgStr;
+      return;
+  } 
+
+  int x,y;
+  
+  if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT)
+  {
+      RGBA*pic=new RGBA[width*height];
+      int xid = 0;
+      int yid = 0;
+      for (y = 0; y < height; ++y) {
+       for (x = 0; x < width; ++x) {
+         int r,g,b,a;
+         imgStr->getPixel(pixBuf);
+         colorMap->getRGB(pixBuf, &rgb);
+         pic[width*y+x].r = r = (U8)(rgb.r * 255 + 0.5);
+         pic[width*y+x].g = g = (U8)(rgb.g * 255 + 0.5);
+         pic[width*y+x].b = b = (U8)(rgb.b * 255 + 0.5);
+         pic[width*y+x].a = a = 255;//(U8)(rgb.a * 255 + 0.5);
+         xid += x*r+x*b*3+x*g*7+x*a*11;
+         yid += y*r*3+y*b*17+y*g*19+y*a*11;
+       }
+      }
+      int t,found = -1;
+      for(t=0;t<picpos;t++)
+      {
+         if(pic_xids[t] == xid &&
+            pic_yids[t] == yid) {
+             found = t;break;
+         }
+      }
+      if(found<0) {
+         if(str->getKind()==strDCT)
+             pic_ids[picpos] = swfoutput_drawimagejpeg(&output, pic, width, height, 
+                     x1,y1,x2,y2,x3,y3,x4,y4);
+         else
+             pic_ids[picpos] = swfoutput_drawimagelossless(&output, pic, width, height, 
+                     x1,y1,x2,y2,x3,y3,x4,y4);
+         pic_xids[picpos] = xid;
+         pic_yids[picpos] = yid;
+         pic_width[picpos] = width;
+         pic_height[picpos] = height;
+         if(picpos<1024)
+             picpos++;
+      } else {
+         swfoutput_drawimageagain(&output, pic_ids[found], width, height,
+                 x1,y1,x2,y2,x3,y3,x4,y4);
+      }
+      delete pic;
+      delete imgStr;
       return;
-    }
-    str = ((DCTStream *)str)->getRawStream();
-    str->reset();
-    while ((c = str->getChar()) != EOF)
-      fputc(c, fi);
-    fclose(fi);
-    swfoutput_drawimagefile(&output, fileName, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
-  } else {
-      logf("<notice> File contains pbm pictures.");
   }
+  else
+  {
+      U8*pic = new U8[width*height];
+      RGBA pal[256];
+      int t;
+      int xid=0,yid=0;
+      for(t=0;t<256;t++)
+      {
+         int r,g,b,a;
+         pixBuf[0] = t;
+         colorMap->getRGB(pixBuf, &rgb);
+         pal[t].r = r = (U8)(rgb.r * 255 + 0.5);
+         pal[t].g = g = (U8)(rgb.g * 255 + 0.5);
+         pal[t].b = b = (U8)(rgb.b * 255 + 0.5);
+         pal[t].a = a = 255;//(U8)(rgb.b * 255 + 0.5);
+         xid += t*r+t*b*3+t*g*7+t*a*11;
+         xid += (~t)*r+t*b*3+t*g*7+t*a*11;
+      }
+      for (y = 0; y < height; ++y) {
+       for (x = 0; x < width; ++x) {
+         imgStr->getPixel(pixBuf);
+         pic[width*y+x] = pixBuf[0];
+         xid += x*pixBuf[0]*7;
+         yid += y*pixBuf[0]*3;
+       }
+      }
+      int found = -1;
+      for(t=0;t<picpos;t++)
+      {
+         if(pic_xids[t] == xid &&
+            pic_yids[t] == yid) {
+             found = t;break;
+         }
+      }
+      if(found<0) {
+         pic_ids[picpos] = swfoutput_drawimagelosslessN(&output, pic, pal, width, height, 
+                 x1,y1,x2,y2,x3,y3,x4,y4,256);
+         pic_xids[picpos] = xid;
+         pic_yids[picpos] = yid;
+         pic_width[picpos] = width;
+         pic_height[picpos] = height;
+         if(picpos<1024)
+             picpos++;
+      } else {
+         swfoutput_drawimageagain(&output, pic_ids[found], width, height,
+                 x1,y1,x2,y2,x3,y3,x4,y4);
+      }
+      delete pic;
+      delete imgStr;
+      return;
+  }
+}
+
+void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
+                                  int width, int height, GBool invert,
+                                  GBool inlineImg) 
+{
+  logf("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
+  drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1);
+}
+
+void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
+                        int width, int height, GfxImageColorMap *colorMap,
+                        int *maskColors, GBool inlineImg)
+{
+  logf("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height, 
+         colorMap?"colorMap":"no colorMap", 
+         maskColors?"maskColors":"no maskColors",
+         inlineImg);
+  if(colorMap)
+      logf("<verbose> 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);
 }
 
-PDFDoc*doc = 0;
 SWFOutputDev*output = 0; 
 
+static void printInfoString(Dict *infoDict, char *key, char *fmt) {
+  Object obj;
+  GString *s1, *s2;
+  int i;
+
+  if (infoDict->lookup(key, &obj)->isString()) {
+    s1 = obj.getString();
+    if ((s1->getChar(0) & 0xff) == 0xfe &&
+       (s1->getChar(1) & 0xff) == 0xff) {
+      s2 = new GString();
+      for (i = 2; i < obj.getString()->getLength(); i += 2) {
+       if (s1->getChar(i) == '\0') {
+         s2->append(s1->getChar(i+1));
+       } else {
+         delete s2;
+         s2 = new GString("<unicode>");
+         break;
+       }
+      }
+      printf(fmt, s2->getCString());
+      delete s2;
+    } else {
+      printf(fmt, s1->getCString());
+    }
+  }
+  obj.free();
+}
+
+static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
+  Object obj;
+  char *s;
+
+  if (infoDict->lookup(key, &obj)->isString()) {
+    s = obj.getString()->getCString();
+    if (s[0] == 'D' && s[1] == ':') {
+      s += 2;
+    }
+    printf(fmt, s);
+  }
+  obj.free();
+}
+
 void pdfswf_init(char*filename, char*userPassword) 
 {
   GString *fileName = new GString(filename);
   GString *userPW;
   Object info;
-  // init error file
-  errorInit();
 
   // read config file
-  initParams(xpdfConfigFile);
+  globalParams = new GlobalParams("");
 
   // open PDF file
-  xref = NULL;
   if (userPassword && userPassword[0]) {
     userPW = new GString(userPassword);
   } else {
@@ -1030,7 +1636,8 @@ void pdfswf_init(char*filename, char*userPassword)
 
   // print doc info
   doc->getDocInfo(&info);
-  if (info.isDict()) {
+  if (info.isDict() &&
+    (screenloglevel>=LOGLEVEL_NOTICE)) {
     printInfoString(info.getDict(), "Title",        "Title:        %s\n");
     printInfoString(info.getDict(), "Subject",      "Subject:      %s\n");
     printInfoString(info.getDict(), "Keywords",     "Keywords:     %s\n");
@@ -1039,23 +1646,23 @@ void pdfswf_init(char*filename, char*userPassword)
     printInfoString(info.getDict(), "Producer",     "Producer:     %s\n");
     printInfoDate(info.getDict(),   "CreationDate", "CreationDate: %s\n");
     printInfoDate(info.getDict(),   "ModDate",      "ModDate:      %s\n");
+    printf("Pages:        %d\n", doc->getNumPages());
+    printf("Linearized:   %s\n", doc->isLinearized() ? "yes" : "no");
+    printf("Encrypted:    ");
+    if (doc->isEncrypted()) {
+      printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
+            doc->okToPrint() ? "yes" : "no",
+            doc->okToCopy() ? "yes" : "no",
+            doc->okToChange() ? "yes" : "no",
+            doc->okToAddNotes() ? "yes" : "no");
+    } else {
+      printf("no\n");
+    }
   }
   info.free();
 
-  // print page count
-  printf("Pages:        %d\n", doc->getNumPages());
-  
-  // print linearization info
-  printf("Linearized:   %s\n", doc->isLinearized() ? "yes" : "no");
-
-  // print encryption info
-  printf("Encrypted:    ");
+  numpages = doc->getNumPages();
   if (doc->isEncrypted()) {
-    printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
-          doc->okToPrint() ? "yes" : "no",
-          doc->okToCopy() ? "yes" : "no",
-          doc->okToChange() ? "yes" : "no",
-          doc->okToAddNotes() ? "yes" : "no");
        /*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
@@ -1068,23 +1675,74 @@ void pdfswf_init(char*filename, char*userPassword)
        }
        if(!doc->okToChange() || !doc->okToAddNotes())
            swfoutput_setprotected();
-    }
-  else {
-    printf("no\n");
   }
 
-
   output = new SWFOutputDev();
+  output->startDoc(doc->getXRef());
+}
+
+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)
 {
-    filename = _filename;
+    swffilename = _filename;
 }
 
+
 void pdfswf_convertpage(int page)
 {
-    doc->displayPage((OutputDev*)output, page, /*zoom*/100, /*rotate*/0, /*doLinks*/(int)1);
+    if(!pages)
+    {
+       pages = (int*)malloc(1024*sizeof(int));
+       pagebuflen = 1024;
+    } else {
+       if(pagepos == pagebuflen)
+       {
+           pagebuflen+=1024;
+           pages = (int*)realloc(pages, pagebuflen);
+       }
+    }
+    pages[pagepos++] = page;
+}
+
+void pdfswf_performconversion()
+{
+    int t;
+    for(t=0;t<pagepos;t++)
+    {
+       currentpage = pages[t];
+       doc->displayPage((OutputDev*)output, currentpage, /*dpi*/72, /*rotate*/0, /*doLinks*/(int)1);
+    }
 }
 
 int pdfswf_numpages()
@@ -1092,14 +1750,21 @@ int pdfswf_numpages()
   return doc->getNumPages();
 }
 
+void pdfswf_insertstop()
+{
+    insertstoptag = 1;
+}
+
+int closed=0;
 void pdfswf_close()
 {
-    delete doc;
+    logf("<debug> pdfswf.cc: pdfswf_close()");
     delete output;
-    
-    freeParams();
+    delete doc;
+    //freeParams();
     // check for memory leaks
     Object::memCheck(stderr);
     gMemReport(stderr);
 }
 
+