turned off checking, fixed compiler warnings.
[swftools.git] / pdf2swf / SWFOutputDev.cc
index 9486441..d70e3e5 100644 (file)
 #include <string.h>
 #include <unistd.h>
 #include "../config.h"
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
 #ifdef HAVE_FONTCONFIG_H
 #include <fontconfig.h>
 #endif
@@ -71,6 +77,8 @@ typedef struct _fontfile
 static fontfile_t fonts[2048];
 static int fontnum = 0;
 
+static int config_use_fontconfig = 1;
+
 // swf <-> pdf pages
 // TODO: move into pdf_doc_t
 static int*pages = 0;
@@ -80,6 +88,7 @@ static int pagepos = 0;
 /* config */
 static double caplinewidth = 3.0;
 static int zoom = 72; /* xpdf: 86 */
+static int forceType0Fonts = 0;
 
 static void printInfoString(Dict *infoDict, char *key, char *fmt);
 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
@@ -104,8 +113,8 @@ struct mapping {
 {"ZapfDingbats",          "d050000l"}};
 
 class SWFOutputDev:  public OutputDev {
-  struct swfoutput output;
   int outputstarted;
+  struct swfoutput output;
 public:
 
   // Constructor.
@@ -113,8 +122,15 @@ public:
 
   // Destructor.
   virtual ~SWFOutputDev() ;
+
+  void setMove(int x,int y);
+  void setClip(int x1,int y1,int x2,int y2);
   
-  void save(char*filename);
+  int save(char*filename);
+  void  pagefeed();
+  void* getSWF();
+
+  void getDimensions(int*x1,int*y1,int*x2,int*y2);
 
   //----- get info about output device
 
@@ -218,18 +234,14 @@ public:
 
   GfxState *laststate;
 
-  int pic_xids[1024];
-  int pic_yids[1024];
-  int pic_ids[1024];
-  int pic_width[1024];
-  int pic_height[1024];
-  int picpos;
-  int pic_id;
   char type3Warning;
 
   char* substitutetarget[256];
   char* substitutesource[256];
   int substitutepos;
+
+  int user_movex,user_movey;
+  int user_clipx1,user_clipx2,user_clipy1,user_clipy2;
 };
 
 static char*getFontID(GfxFont*font);
@@ -238,15 +250,19 @@ class InfoOutputDev:  public OutputDev
 {
   public:
   int x1,y1,x2,y2;
-  int has_links;
-  int has_images;
+  int num_links;
+  int num_images;
+  int num_fonts;
 
   InfoOutputDev() 
   {
-      has_links = 0;
-      has_images = 0;
+      num_links = 0;
+      num_images = 0;
+      num_fonts = 0;
+  }
+  virtual ~InfoOutputDev() 
+  {
   }
-  virtual ~InfoOutputDev() {}
   virtual GBool upsideDown() {return gTrue;}
   virtual GBool useDrawChar() {return gTrue;}
   virtual GBool useGradients() {return gTrue;}
@@ -265,23 +281,28 @@ class InfoOutputDev:  public OutputDev
   }
   virtual void drawLink(Link *link, Catalog *catalog) 
   {
-      has_links = 1;
+      num_links++;
   }
   virtual void updateFont(GfxState *state) 
   {
-      char*id = getFontID(state->getFont());
+      GfxFont*font = state->getFont();
+      if(!font)
+          return;
+      char*id = getFontID(font);
+      /* FIXME*/
+      num_fonts++;
   }
   virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
                             int width, int height, GBool invert,
                             GBool inlineImg) 
   {
-      has_images = 1;
+      num_images++;
   }
   virtual void drawImage(GfxState *state, Object *ref, Stream *str,
                         int width, int height, GfxImageColorMap *colorMap,
                         int *maskColors, GBool inlineImg)
   {
-      has_images = 1;
+      num_images++;
   }
 };
 
@@ -296,12 +317,38 @@ SWFOutputDev::SWFOutputDev()
     clipping[clippos] = 0;
     outputstarted = 0;
     xref = 0;
-    picpos = 0;
-    pic_id = 0;
     substitutepos = 0;
     type3Warning = 0;
+    user_movex = 0;
+    user_movey = 0;
+    user_clipx1 = 0;
+    user_clipy1 = 0;
+    user_clipx2 = 0;
+    user_clipy2 = 0;
+    memset(&output, 0, sizeof(output));
 //    printf("SWFOutputDev::SWFOutputDev() \n");
 };
+  
+void SWFOutputDev::setMove(int x,int y)
+{
+    this->user_movex = x;
+    this->user_movey = y;
+}
+
+void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
+{
+    if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
+    if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
+
+    this->user_clipx1 = x1;
+    this->user_clipy1 = y1;
+    this->user_clipx2 = x2;
+    this->user_clipy2 = y2;
+}
+void SWFOutputDev::getDimensions(int*x1,int*y1,int*x2,int*y2)
+{
+    return swfoutput_getdimensions(&output, x1,y1,x2,y2);
+}
 
 static char*getFontID(GfxFont*font)
 {
@@ -646,7 +693,7 @@ void SWFOutputDev::stroke(GfxState *state)
     m.m12 = 0; m.m13 = 0; m.m23 = 0;
     SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
     
-    if(screenloglevel >= LOGLEVEL_TRACE)  {
+    if(getLogLevel() >= LOGLEVEL_TRACE)  {
         msg("<trace> stroke\n");
         dump_outline(outline);
     }
@@ -682,7 +729,7 @@ void SWFOutputDev::fill(GfxState *state)
     m.m12 = 0; m.m13 = 0; m.m23 = 0;
     SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
 
-    if(screenloglevel >= LOGLEVEL_TRACE)  {
+    if(getLogLevel() >= LOGLEVEL_TRACE)  {
         msg("<trace> fill\n");
         dump_outline(outline);
     }
@@ -699,7 +746,7 @@ void SWFOutputDev::eoFill(GfxState *state)
     m.m12 = 0; m.m13 = 0; m.m23 = 0;
     SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
 
-    if(screenloglevel >= LOGLEVEL_TRACE)  {
+    if(getLogLevel() >= LOGLEVEL_TRACE)  {
         msg("<trace> eofill\n");
         dump_outline(outline);
     }
@@ -717,7 +764,7 @@ void SWFOutputDev::clip(GfxState *state)
     m.m13 = 0; m.m23 = 0;
     SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
 
-    if(screenloglevel >= LOGLEVEL_TRACE)  {
+    if(getLogLevel() >= LOGLEVEL_TRACE)  {
         msg("<trace> clip\n");
         dump_outline(outline);
     }
@@ -734,7 +781,7 @@ void SWFOutputDev::eoClip(GfxState *state)
     m.m12 = 0; m.m13 = 0; m.m23 = 0;
     SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
 
-    if(screenloglevel >= LOGLEVEL_TRACE)  {
+    if(getLogLevel() >= LOGLEVEL_TRACE)  {
         msg("<trace> eoclip\n");
         dump_outline(outline);
     }
@@ -743,9 +790,19 @@ void SWFOutputDev::eoClip(GfxState *state)
     clipping[clippos] ++;
     free_outline(outline);
 }
-void SWFOutputDev::save(char*filename)
+
+/* pass through functions for swf_output */
+int SWFOutputDev::save(char*filename)
 {
-    swfoutput_save(&output, filename);
+    return swfoutput_save(&output, filename);
+}
+void SWFOutputDev::pagefeed()
+{
+    swfoutput_pagefeed(&output);
+}
+void* SWFOutputDev::getSWF()
+{
+    return (void*)swfoutput_get(&output);
 }
 
 SWFOutputDev::~SWFOutputDev() 
@@ -790,7 +847,7 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y,
     // check for invisible text -- this is used by Acrobat Capture
     if ((state->getRender() & 3) == 3)
        return;
-
+    Gushort *CIDToGIDMap = 0;
     GfxFont*font = state->getFont();
 
     if(font->getType() == fontType3) {
@@ -803,20 +860,29 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y,
     state->transform(x, y, &x1, &y1);
     
     Unicode u=0;
-    if(_u && uLen) 
+    char*name=0;
+
+    if(_u && uLen) {
        u = *_u;
+       if (u) {
+           int t;
+           /* find out char name from unicode index 
+              TODO: should be precomputed
+            */
+           for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
+               if(nameToUnicodeTab[t].u == u) {
+                   name = nameToUnicodeTab[t].name;
+                   break;
+               }
+           }
+       }
+    }
 
-    /* find out the character name */
-    char*name=0;
-    if(font->isCIDFont() && u) {
+    if(font->isCIDFont()) {
        GfxCIDFont*cfont = (GfxCIDFont*)font;
-       int t;
-       for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
-           /* todo: should be precomputed */
-           if(nameToUnicodeTab[t].u == u) {
-               name = nameToUnicodeTab[t].name;
-               break;
-           }
+
+       if(font->getType() == fontCIDType2) {
+           CIDToGIDMap = cfont->getCIDToGID();
        }
     } else {
        Gfx8BitFont*font8;
@@ -825,13 +891,14 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y,
        if(enc && enc[c])
           name = enc[c];
     }
-    
-    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);
+    if (CIDToGIDMap) {
+       msg("<debug> drawChar(%f, %f, c='%c' (%d), GID=%d, u=%d <%d>) CID=%d name=\"%s\"\n", x, y, (c&127)>=32?c:'?', c, CIDToGIDMap[c], u, uLen, font->isCIDFont(), FIXNULL(name));
+       swfoutput_drawchar(&output, x1, y1, name, CIDToGIDMap[c], u);
+    } else {
+       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));
+       swfoutput_drawchar(&output, x1, y1, name, c, u);
+    }
 }
 
 void SWFOutputDev::endString(GfxState *state) { 
@@ -879,13 +946,21 @@ void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, doubl
     if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
     if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
 
+    /* apply user clip box */
+    if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
+        /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
+        /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
+        /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
+        /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
+    }
+
     if(!outputstarted) {
         msg("<verbose> Bounding box is (%f,%f)-(%f,%f)", x1,y1,x2,y2);
         swfoutput_init(&output);
         outputstarted = 1;
     }
       
-    swfoutput_newpage(&output, pageNum, (int)x1, (int)y1, (int)x2, (int)y2);
+    swfoutput_newpage(&output, pageNum, user_movex, user_movey, (int)x1, (int)y1, (int)x2, (int)y2);
 }
 
 void SWFOutputDev::drawLink(Link *link, Catalog *catalog) 
@@ -1177,9 +1252,11 @@ char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
       }
 #ifdef XPDF_101
       Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
+      if(!cvt) return 0;
       cvt->convertToType1(f);
 #else
       FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
+      if(!cvt) return 0;
       cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
 #endif
       //cvt->convertToCIDType0("test", f);
@@ -1246,6 +1323,9 @@ char* searchForSuitableFont(GfxFont*gfxFont)
     char*name = getFontName(gfxFont);
     char*fontname = 0;
     char*filename = 0;
+
+    if(!config_use_fontconfig)
+        return 0;
     
 #ifdef HAVE_FONTCONFIG
     FcPattern *pattern, *match;
@@ -1253,25 +1333,38 @@ char* searchForSuitableFont(GfxFont*gfxFont)
     FcChar8 *v;
 
     static int fcinitcalled = false; 
+        
+    msg("<debug> searchForSuitableFont(%s)", name);
     
     // call init ony once
     if (!fcinitcalled) {
+        msg("<debug> Initializing FontConfig...");
         fcinitcalled = true;
-       FcInit(); //leaks
+       if(FcInit()) {
+            msg("<debug> FontConfig Initialization failed. Disabling.");
+            config_use_fontconfig = 0;
+            return 0;
+        }
+        msg("<debug> ...initialized FontConfig");
     }
    
+    msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
     pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
     if (gfxFont->isItalic()) // check for italic
+        msg("<debug> FontConfig: Adding Italic Slant");
        FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
     if (gfxFont->isBold()) // check for bold
+        msg("<debug> FontConfig: Adding Bold Weight");
         FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
 
+    msg("<debug> FontConfig: Try to match...");
     // 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) {
+        msg("<debug> FontConfig: family=%s", (char*)v);
         // if we get an exact match
         if (strcmp((char *)v, name) == 0) {
            if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
@@ -1280,6 +1373,7 @@ char* searchForSuitableFont(GfxFont*gfxFont)
                if(nfn) fontname = strdup(nfn+1);
                else    fontname = filename;
             }
+            msg("<debug> FontConfig: Returning \"%s\"", fontname);
         } else {
             // initialize patterns
             FcPatternDestroy(pattern);
@@ -1287,22 +1381,28 @@ char* searchForSuitableFont(GfxFont*gfxFont)
 
             // now match against serif etc.
            if (gfxFont->isSerif()) {
+                msg("<debug> FontConfig: Create Serif Family Pattern");
                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
             } else if (gfxFont->isFixedWidth()) {
+                msg("<debug> FontConfig: Create Monospace Family Pattern");
                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
             } else {
+                msg("<debug> FontConfig: Create Sans Family Pattern");
                 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
             }
 
             // check for italic
             if (gfxFont->isItalic()) {
+                msg("<debug> FontConfig: Adding Italic Slant");
                 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
             }
             // check for bold
             if (gfxFont->isBold()) {
+                msg("<debug> FontConfig: Adding Bold Weight");
                 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
             }
 
+            msg("<debug> FontConfig: Try to match... (2)");
             // configure and match using serif etc
            FcConfigSubstitute (0, pattern, FcMatchPattern);
             FcDefaultSubstitute (pattern);
@@ -1314,6 +1414,7 @@ char* searchForSuitableFont(GfxFont*gfxFont)
                if(nfn) fontname = strdup(nfn+1);
                else    fontname = filename;
            }
+            msg("<debug> FontConfig: Returning \"%s\"", fontname);
         }        
     }
 
@@ -1341,6 +1442,10 @@ char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
        fontname = "Times-Roman";
     }
     filename = searchFont(fontname);
+    if(!filename) {
+       msg("<error> Couldn't find font %s- did you install the default fonts?");
+       return 0;
+    }
 
     if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
        msg("<fatal> Too many fonts in file.");
@@ -1440,7 +1545,7 @@ void SWFOutputDev::updateFont(GfxState *state)
     if(embedded &&
        (gfxFont->getType() == fontType1 ||
        gfxFont->getType() == fontType1C ||
-       //gfxFont->getType() == fontCIDType0C ||
+       (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
        gfxFont->getType() == fontTrueType ||
        gfxFont->getType() == fontCIDType2
        ))
@@ -1581,22 +1686,21 @@ void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
   }
 
   if(mask) {
-      int yes=0,i,j;
+      int 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;
+      pal[0].r = (int)(rgb.r*255); pal[1].r = 0;
+      pal[0].g = (int)(rgb.g*255); pal[1].g = 0;
+      pal[0].b = (int)(rgb.b*255); pal[1].b = 0;
+      pal[0].a = 255;              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)
@@ -1606,72 +1710,52 @@ void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
            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(type3active) {
+         unsigned char*pic2 = 0;
+         numpalette = 16;
+         
+         pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
+
+         if(!pic2) {
+           delete pic;
+           delete imgStr;
+           return;
          }
-      }
-      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);
-                 }
-             }
+
+         width = realwidth;
+         height = realheight;
+         free(pic);
+         pic = pic2;
+         
+         /* make a black/white palette */
+         GfxRGB rgb2;
+         rgb2.r = 1 - rgb.r;
+         rgb2.g = 1 - rgb.g;
+         rgb2.b = 1 - rgb.b;
+         float r = 255/(numpalette-1);
+         int t;
+         for(t=0;t<numpalette;t++) {
+             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);
       }
+
+      RGBA*pic2 = new RGBA[width*height];
+      for (y = 0; y < height; ++y) {
+       for (x = 0; x < width; ++x) {
+         pic2[width*y+x] = pal[pic[y*width+x]];
+       }
+      }
+      swfoutput_drawimagelossless(&output, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
+      free(pic2);
       free(pic);
       delete imgStr;
       return;
@@ -1679,100 +1763,45 @@ void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
 
   int x,y;
   
-  if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT)
-  {
+  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;
+         pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5);
+         pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5);
+         pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5);
+         pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
        }
       }
-      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);
-      }
+      if(str->getKind()==strDCT)
+         swfoutput_drawimagejpeg(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
+      else
+         swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
       delete pic;
       delete imgStr;
       return;
-  }
-  else
-  {
-      U8*pic = new U8[width*height];
+  } else {
+      RGBA*pic=new RGBA[width*height];
       RGBA pal[256];
       int t;
-      int xid=0,yid=0;
-      for(t=0;t<256;t++)
-      {
-         int r,g,b,a;
+      for(t=0;t<256;t++) {
          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;
+         pal[t].r = (U8)(rgb.r * 255 + 0.5);
+         pal[t].g = (U8)(rgb.g * 255 + 0.5);
+         pal[t].b = (U8)(rgb.b * 255 + 0.5);
+         pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
       }
       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;
+         pic[width*y+x] = pal[pixBuf[0]];
        }
       }
-      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);
-      }
+      swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
+
       delete pic;
       delete imgStr;
       return;
@@ -1845,12 +1874,39 @@ static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
   obj.free();
 }
 
+int jpeg_dpi = 0;
+int ppm_dpi = 0;
+
 void pdfswf_setparameter(char*name, char*value)
 {
+    msg("<verbose> setting parameter %s to \"%s\"", name, value);
     if(!strcmp(name, "caplinewidth")) {
        caplinewidth = atof(value);
     } else if(!strcmp(name, "zoom")) {
+       char buf[80];
        zoom = atoi(value);
+       sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
+       swfoutput_setparameter("jpegsubpixels", buf);
+       sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
+       swfoutput_setparameter("ppmsubpixels", buf);
+    } else if(!strcmp(name, "jpegdpi")) {
+       char buf[80];
+       jpeg_dpi = atoi(value);
+       sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
+       swfoutput_setparameter("jpegsubpixels", buf);
+    } else if(!strcmp(name, "ppmdpi")) {
+       char buf[80];
+       ppm_dpi = atoi(value);
+       sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
+       swfoutput_setparameter("ppmsubpixels", buf);
+    } else if(!strcmp(name, "forceType0Fonts")) {
+       forceType0Fonts = atoi(value);
+    } else if(!strcmp(name, "fontdir")) {
+        pdfswf_addfontdir(value);
+    } else if(!strcmp(name, "languagedir")) {
+        pdfswf_addlanguagedir(value);
+    } else if(!strcmp(name, "fontconfig")) {
+        config_use_fontconfig = atoi(value);
     } else {
        swfoutput_setparameter(name, value);
     }
@@ -1867,6 +1923,82 @@ void pdfswf_addfont(char*filename)
     }
 }
 
+static char* dirseparator()
+{
+#ifdef WIN32
+    return "\\";
+#else
+    return "/";
+#endif
+}
+
+void pdfswf_addlanguagedir(char*dir)
+{
+    if(!globalParams)
+        globalParams = new GlobalParams("");
+    
+    msg("<notice> Adding %s to language pack directories", dir);
+
+    int l;
+    FILE*fi = 0;
+    char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
+    strcpy(config_file, dir);
+    strcat(config_file, dirseparator());
+    strcat(config_file, "add-to-xpdfrc");
+
+    fi = fopen(config_file, "rb");
+    if(!fi) {
+        msg("<error> Could not open %s", config_file);
+        return;
+    }
+    globalParams->parseFile(new GString(config_file), fi);
+    fclose(fi);
+}
+
+void pdfswf_addfontdir(char*dirname)
+{
+#ifdef HAVE_DIRENT_H
+    msg("<notice> Adding %s to font directories", dirname);
+    DIR*dir = opendir(dirname);
+    if(!dir) {
+       msg("<warning> Couldn't open directory %s\n", dirname);
+       return;
+    }
+    struct dirent*ent;
+    while(1) {
+       ent = readdir (dir);
+       if (!ent) 
+           break;
+       int l;
+       char*name = ent->d_name;
+       char type = 0;
+       if(!name) continue;
+       l=strlen(name);
+       if(l<4)
+           continue;
+       if(!strncasecmp(&name[l-4], ".pfa", 4)) 
+           type=1;
+       if(!strncasecmp(&name[l-4], ".pfb", 4)) 
+           type=3;
+       if(!strncasecmp(&name[l-4], ".ttf", 4)) 
+           type=2;
+       if(type)
+       {
+           char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
+           strcpy(fontname, dirname);
+            strcat(fontname, dirseparator());
+           strcat(fontname, name);
+           msg("<verbose> Adding %s to fonts", fontname);
+           pdfswf_addfont(fontname);
+       }
+    }
+    closedir(dir);
+#else
+    msg("<warning> No dirent.h- unable to add font dir %s", dir);
+#endif
+}
+
+
 typedef struct _pdf_doc_internal
 {
     int protect;
@@ -1893,7 +2025,8 @@ pdf_doc_t* pdf_init(char*filename, char*userPassword)
     Object info;
 
     // read config file
-    globalParams = new GlobalParams("");
+    if(!globalParams)
+        globalParams = new GlobalParams("");
 
     // open PDF file
     if (userPassword && userPassword[0]) {
@@ -1912,7 +2045,7 @@ pdf_doc_t* pdf_init(char*filename, char*userPassword)
     // print doc info
     i->doc->getDocInfo(&info);
     if (info.isDict() &&
-      (screenloglevel>=LOGLEVEL_NOTICE)) {
+      (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
       printInfoString(info.getDict(), "Title",        "Title:        %s\n");
       printInfoString(info.getDict(), "Subject",      "Subject:      %s\n");
       printInfoString(info.getDict(), "Keywords",     "Keywords:     %s\n");
@@ -1940,8 +2073,8 @@ pdf_doc_t* pdf_init(char*filename, char*userPassword)
     i->protect = 0;
     if (i->doc->isEncrypted()) {
           if(!i->doc->okToCopy()) {
-              printf("PDF disallows copying. Terminating.\n");
-              exit(1); //bail out
+              printf("PDF disallows copying.\n");
+              return 0;
           }
           if(!i->doc->okToChange() || !i->doc->okToAddNotes())
               i->protect = 1;
@@ -1970,7 +2103,7 @@ class MemCheck
 {
     public: ~MemCheck()
     {
-        delete globalParams;
+        delete globalParams;globalParams=0;
         Object::memCheck(stderr);
         gMemReport(stderr);
     }
@@ -1992,6 +2125,9 @@ void pdf_destroy(pdf_doc_t*pdf_doc)
 pdf_page_t* pdf_getpage(pdf_doc_t*pdf_doc, int page)
 {
     pdf_doc_internal_t*di= (pdf_doc_internal_t*)pdf_doc->internal;
+
+    if(page < 1 || page > pdf_doc->num_pages)
+        return 0;
     
     pdf_page_t* pdf_page = (pdf_page_t*)malloc(sizeof(pdf_page_t));
     pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
@@ -2028,10 +2164,27 @@ void swf_output_setparameter(swf_output_t*swf_output, char*name, char*value)
     pdfswf_setparameter(name, value);
 }
 
-void swf_output_save(swf_output_t*swf, char*filename)
+void swf_output_pagefeed(swf_output_t*swf)
 {
     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
-    i->outputDev->save(filename);
+    i->outputDev->pagefeed();
+    i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
+}
+
+int swf_output_save(swf_output_t*swf, char*filename)
+{
+    swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
+    int ret = i->outputDev->save(filename);
+    i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
+    return ret;
+}
+
+void* swf_output_get(swf_output_t*swf)
+{
+    swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
+    void* ret = i->outputDev->getSWF();
+    i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
+    return ret;
 }
 
 void swf_output_destroy(swf_output_t*output)
@@ -2042,11 +2195,10 @@ void swf_output_destroy(swf_output_t*output)
     free(output);
 }
 
-
-void pdf_page_render(pdf_page_t*page, swf_output_t*output)
+void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
 {
     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
-    swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
+    swf_output_internal_t*si = (swf_output_internal_t*)swf->internal;
 
     if(pi->protect) {
         swfoutput_setparameter("protect", "1");
@@ -2057,13 +2209,61 @@ void pdf_page_render(pdf_page_t*page, swf_output_t*output)
 #else
     pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
 #endif
+    si->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2);
 }
 
+void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
+{
+    pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
+    swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
+
+    si->outputDev->setMove(x,y);
+    if((x1|y1|x2|y2)==0) x2++;
+    si->outputDev->setClip(x1,y1,x2,y2);
+
+    pdf_page_render2(page, output);
+}
+void pdf_page_render(pdf_page_t*page, swf_output_t*output)
+{
+    pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
+    swf_output_internal_t*si = (swf_output_internal_t*)output->internal;
+    
+    si->outputDev->setMove(0,0);
+    si->outputDev->setClip(0,0,0,0);
+    
+    pdf_page_render2(page, output);
+}
+
+
 pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
 {
+    pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
     pdf_page_internal_t*i= (pdf_page_internal_t*)page->internal;
     pdf_page_info_t*info = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t));
     memset(info, 0, sizeof(pdf_page_info_t));
+
+    InfoOutputDev*output = new InfoOutputDev;
+    
+#ifdef XPDF_101
+    pi->doc->displayPage((OutputDev*)output, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
+#else
+    pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
+#endif
+
+    info->xMin = output->x1;
+    info->yMin = output->y1;
+    info->xMax = output->x2;
+    info->yMax = output->y2;
+    info->number_of_images = output->num_images;
+    info->number_of_links = output->num_links;
+    info->number_of_fonts = output->num_fonts;
+
+    delete output;
+
     return info;
 }
 
+void pdf_page_info_destroy(pdf_page_info_t*info)
+{
+    free(info);
+}