set dpi to 72.
[swftools.git] / pdf2swf / SWFOutputDev.cc
index 55b6028..6af4102 100644 (file)
@@ -23,6 +23,7 @@
 #include <string.h>
 #include <unistd.h>
 //xpdf header files
+#include "gfile.h"
 #include "GString.h"
 #include "gmem.h"
 #include "Object.h"
 #include "swfoutput.h"
 extern "C" {
 #include "../lib/log.h"
+#include "ttf2pt1.h"
 }
 
+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",             
@@ -99,48 +109,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;
 
@@ -220,13 +188,19 @@ public:
   void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
                                   int width, int height, GfxImageColorMap*colorMap, GBool invert,
                                   GBool inlineImg, int mask);
-  int clipping[32];
+  int clipping[64];
   int clippos;
 
-  int setT1Font(char*name,FontEncoding*enc);
+  int searchT1Font(char*name);
+  char* substituteFont(GfxFont*gfxFont, char*oldname);
+  char* writeEmbeddedFontToFile(GfxFont*font);
   int t1id;
-  int jpeginfo; // did we write "Page contains jpegs" yet?
-  int pbminfo; // did we write "Page contains jpegs" yet?
+  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?
+
+  GfxState *laststate;
 };
 
 char mybuf[1024];
@@ -360,7 +334,6 @@ void showFontError(GfxFont*font, int nr)
       logf("<warning> The following font caused problems (substituting):");
     else if(nr == 2)
       logf("<warning> This document contains Type 3 Fonts: (some text may be incorrectly displayed)");
-
     dumpFontInfo("<warning>", font);
 }
 
@@ -423,6 +396,8 @@ void dumpFontInfo(char*loglevel, GfxFont*font)
 SWFOutputDev::SWFOutputDev() 
 {
     jpeginfo = 0;
+    ttfinfo = 0;
+    linkinfo = 0;
     pbminfo = 0;
     clippos = 0;
     clipping[clippos] = 0;
@@ -434,7 +409,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;
@@ -536,7 +511,7 @@ void SWFOutputDev::clip(GfxState *state)
     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) 
 {
@@ -547,7 +522,7 @@ void SWFOutputDev::eoClip(GfxState *state)
     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() 
@@ -569,11 +544,11 @@ GBool SWFOutputDev::useDrawChar()
 void SWFOutputDev::beginString(GfxState *state, GString *s) 
 { 
     double m11,m21,m12,m22;
-    logf("<debug> beginstring \"%s\"\n", 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;
@@ -590,7 +565,10 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y, double dx, doub
        y1 = y;
        state->transform(x, y, &x1, &y1);
 
-       swfoutput_drawchar(&output, x1, y1, enc->getCharName(c));
+       if(enc->getCharName(c))
+         swfoutput_drawchar(&output, x1, y1, enc->getCharName(c), c);
+       else
+         logf("<warning> couldn't get name for character %02x from Encoding", c);
     }
 }
 
@@ -608,6 +586,7 @@ void SWFOutputDev::endString(GfxState *state)
 void SWFOutputDev::startPage(int pageNum, GfxState *state) 
 {
   double x1,y1,x2,y2;
+  laststate = state;
   logf("<debug> startPage %d\n", pageNum);
   logf("<notice> processing page %d", pageNum);
 
@@ -623,45 +602,93 @@ void SWFOutputDev::startPage(int pageNum, GfxState *state)
 
 void SWFOutputDev::drawLink(Link *link, Catalog *catalog) 
 {
-  logf("<debug> drawlink\n");
   double x1, y1, x2, y2, w;
   GfxRGB rgb;
   swfcoord points[5];
   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());
@@ -669,43 +696,75 @@ 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, s, page);
   }
 }
 
 void SWFOutputDev::saveState(GfxState *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> 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;
     
@@ -730,15 +789,12 @@ int SWFOutputDev::setT1Font(char*name, FontEncoding*encoding)
                pdf2t1map[i].id = mapid;
        }
     }
-    if(id<0)
-     return 0;
-
-    this->t1id = id;
+    return id;
 }
 
 void SWFOutputDev::updateLineWidth(GfxState *state)
 {
-    double width = state->getLineWidth();
+    double width = state->getTransformedLineWidth();
     swfoutput_setlinewidth(&output, width);
 }
 
@@ -762,10 +818,9 @@ void SWFOutputDev::updateStrokeColor(GfxState *state)
                                      (char)(rgb.b*255), (char)(opaq*255));
 }
 
-char*writeEmbeddedFontToFile(GfxFont*font)
+char*SWFOutputDev::writeEmbeddedFontToFile(GfxFont*font)
 {
       char*tmpFileName = NULL;
-      char*fileName = NULL;
       FILE *f;
       int c;
       char *fontBuf;
@@ -804,12 +859,26 @@ char*writeEmbeddedFontToFile(GfxFont*font)
        strObj.free();
       }
       fclose(f);
-      fileName = tmpFileName;
-      if(!fileName) {
-         logf("<error> Embedded font writer didn't create a file");
-         return 0;
+
+      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 fileName;
+
+      return tmpFileName;
 }
 
 char* gfxFontName(GfxFont* gfxFont)
@@ -827,72 +896,42 @@ char* gfxFontName(GfxFont* gfxFont)
       }
 }
 
-void SWFOutputDev::updateFont(GfxState *state) 
-{
-  double m11, m12, m21, m22;
-  char * fontname = 0;
-  GfxFont*gfxFont = state->getFont();
-  char * fileName = 0;
-
-  if (!gfxFont) {
-    return;
-  }  
-
-  if(swfoutput_queryfont(&output, gfxFontName(gfxFont)))
-  {
-      swfoutput_setfont(&output, gfxFontName(gfxFont), -1, 0);
-      return;
-  }
-
-  // look for Type 3 font
-  if (!type3Warning && gfxFont->getType() == fontType3) {
-    type3Warning = gTrue;
-    showFontError(gfxFont, 2);
-  }
-  //dumpFontInfo ("<notice>", gfxFont);
+char* substitutetarget[256];
+char* substitutesource[256];
+int substitutepos = 0;
 
-  Ref embRef;
-  GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
-  if(embedded) {
-    if (!gfxFont->is16Bit() &&
-       (gfxFont->getType() == fontType1 ||
-        gfxFont->getType() == fontType1C)) {
-       
-       fileName = writeEmbeddedFontToFile(gfxFont);
-       if(!fileName)
-         return ;
-    }
-    else {
-       showFontError(gfxFont,0);
-       return ;
-    }
-    
-    t1id = T1_AddFont(fileName);
-  } else {
-    fontname = NULL;
-    if(gfxFont->getName()) {
-      fontname = gfxFont->getName()->getCString();
-      //logf("<notice> Processing font %s", fontname);
-    }
-    if(!fontname || !setT1Font(state->getFont()->getName()->getCString(), gfxFont->getEncoding()))
-    { //substitute font
+char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
+{
+      //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(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
@@ -934,14 +973,137 @@ 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", oldname, 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;
+    }
+}
+
+void SWFOutputDev::updateFont(GfxState *state) 
+{
+  GfxFont*gfxFont = state->getFont();
+  char * fileName = 0;
+    
+  if (!gfxFont) {
+    return;
+  }  
+  char * fontname = gfxFontName(gfxFont);
+  int t;
+  for(t=0;t<substitutepos;t++) {
+      if(!strcmp(fontname, substitutesource[t])) {
+         fontname = substitutetarget[t];
+         break;
+      }
+  }
+
+  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);
+  }
+  //dumpFontInfo ("<notice>", gfxFont);
+
+  Ref embRef;
+  GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
+  if(embedded) {
+    if (!gfxFont->is16Bit() &&
+       (gfxFont->getType() == fontType1 ||
+        gfxFont->getType() == fontType1C ||
+        gfxFont->getType() == fontTrueType)) {
+       
+       fileName = writeEmbeddedFontToFile(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 {
+       showFontError(gfxFont,0);
+       fontname = substituteFont(gfxFont, fontname);
+    }
+  } else {
+    if(fontname) {
+       int newt1id = searchT1Font(fontname);
+       if(newt1id<0) {
+           fontname = substituteFont(gfxFont, fontname);
+       } else
+           this->t1id = newt1id;
     }
+    else
+       fontname = substituteFont(gfxFont, fontname);
   }
 
-  swfoutput_setfont(&output,gfxFontName(gfxFont),t1id, 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("<verbose> Creating new SWF font: t1id: %d, filename: %s name:%s", this->t1id, fileName, fontname);
+  swfoutput_setfont(&output, fontname, this->t1id, fileName);
   if(fileName)
-      unlink(fileName);
+      unlinkfont(fileName);
 }
 
 int pic_xids[1024];
@@ -961,8 +1123,19 @@ void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
   ImageStream *imgStr;
   Guchar pixBuf[4];
   GfxRGB rgb;
-  if(!width || !height)
+  if(!width || !height || (height<=1 && width<=1))
+  {
+      logf("<verbose> Ignoring %d by %d image", width, height);
+      int i,j;
+      if (inlineImg) {
+       j = height * ((width + 7) / 8);
+       str->reset();
+       for (i = 0; i < j; ++i) {
+         str->getChar();
+       }
+      }
       return;
+  }
   
   state->transform(0, 1, &x1, &y1);
   state->transform(0, 0, &x2, &y2);
@@ -972,7 +1145,7 @@ void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
   if (str->getKind() == strDCT &&
       (colorMap->getNumPixelComps() == 3 || !mask) )
   {
-    sprintf(fileName, "/tmp/tmp%08x.jpg",lrand48());
+    sprintf(fileName, "%s.jpg",mktmpname(0));
     logf("<verbose> Found jpeg. Temporary storage is %s", fileName);
     if(!jpeginfo)
     {
@@ -1022,25 +1195,62 @@ void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
     if(!pbminfo) {
        logf("<notice> file contains pbm pictures %s",mask?"(masked)":"");
        if(mask)
-       logf("<verbose> ignoring %d by %d masked picture\n", width, height);
+       logf("<verbose> drawing %d by %d masked picture\n", width, height);
        pbminfo = 1;
     }
 
     if(mask) {
-       str->reset();
-       int yes=0;
-       while ((c = str->getChar()) != EOF)
+       imgStr = new ImageStream(str, width, 1, 1);
+       imgStr->reset();
+       //return;
+       int yes=0,i,j;
+       unsigned char buf[8];
+       int xid = 0;
+       int yid = 0;
+       int x,y;
+       int width2 = (width+3)&(~3);
+       unsigned char*pic = new unsigned char[width2*height];
+       RGBA pal[256];
+       GfxRGB rgb;
+       state->getFillRGB(&rgb);
+       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;
+       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;
+       for (y = 0; y < height; ++y)
+        for (x = 0; x < width; ++x)
        {
-           if((c<32 || c>'z') && yes && (c!=13) && (c!=10)) {
-               printf("no ascii: %02x\n", c);
-               yes = 1;
-          }
+             imgStr->getPixel(buf);
+              pic[width*y+x] = buf[0];
+             xid+=x*buf[0]+1;
+             yid+=y*buf[0]+1;
+       }
+       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) {
+           pic_ids[picpos] = swfoutput_drawimagelossless256(&output, pic, pal, width, height, 
+                   x1,y1,x2,y2,x3,y3,x4,y4);
+           pic_xids[picpos] = xid;
+           pic_yids[picpos] = yid;
+           if(picpos<1024)
+               picpos++;
+       } else {
+           swfoutput_drawimageagain(&output, pic_ids[found], width, height,
+                   x1,y1,x2,y2,x3,y3,x4,y4);
+       }
+       free(pic);
     } else {
        int x,y;
        int width2 = (width+3)&(~3);
        imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
-                                colorMap->getBits());
+                                  colorMap->getBits());
        imgStr->reset();
 
        if(colorMap->getNumPixelComps()!=1)
@@ -1149,9 +1359,50 @@ void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
   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);
@@ -1194,6 +1445,7 @@ void pdfswf_init(char*filename, char*userPassword)
 
   // print page count
   printf("Pages:        %d\n", doc->getNumPages());
+  numpages = doc->getNumPages();
   
   // print linearization info
   printf("Linearized:   %s\n", doc->isLinearized() ? "yes" : "no");
@@ -1237,6 +1489,16 @@ void pdfswf_ignoredraworder()
     ignoredraworder = 1;
 }
 
+void pdfswf_linksopennewwindow()
+{
+    opennewwindow = 1;
+}
+
+void pdfswf_storeallcharacters()
+{
+    storeallcharacters = 1;
+}
+
 void pdfswf_jpegquality(int val)
 {
     if(val<0) val=0;
@@ -1249,9 +1511,31 @@ void pdfswf_setoutputfilename(char*_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()