fixed type 3 stroke/fill color problem.
[swftools.git] / pdf2swf / SWFOutputDev.cc
index 23cb0c3..ad47eac 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
@@ -58,6 +64,8 @@
 //swftools header files
 #include "swfoutput.h"
 #include "../lib/log.h"
+#include "../lib/gfxdevice.h"
+#include "gfxtools.h"
 
 #include <math.h>
 
@@ -71,6 +79,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 +90,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 +115,8 @@ struct mapping {
 {"ZapfDingbats",          "d050000l"}};
 
 class SWFOutputDev:  public OutputDev {
-  struct swfoutput output;
   int outputstarted;
+  struct swfoutput output;
 public:
 
   // Constructor.
@@ -117,7 +128,11 @@ public:
   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
 
@@ -191,14 +206,16 @@ public:
                         int width, int height, GfxImageColorMap *colorMap,
                         int *maskColors, GBool inlineImg);
   
-  virtual GBool beginType3Char(GfxState *state,
-                              CharCode code, Unicode *u, int uLen);
+  virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
   virtual void endType3Char(GfxState *state);
 
+  virtual void type3D0(GfxState *state, double wx, double wy);
+  virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury);
+
   private:
   void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
                                   int width, int height, GfxImageColorMap*colorMap, GBool invert,
-                                  GBool inlineImg, int mask);
+                                  GBool inlineImg, int mask, int *maskColors);
   int clipping[64];
   int clippos;
 
@@ -221,13 +238,6 @@ 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];
@@ -311,8 +321,6 @@ SWFOutputDev::SWFOutputDev()
     clipping[clippos] = 0;
     outputstarted = 0;
     xref = 0;
-    picpos = 0;
-    pic_id = 0;
     substitutepos = 0;
     type3Warning = 0;
     user_movex = 0;
@@ -341,6 +349,10 @@ void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
     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)
 {
@@ -565,106 +577,81 @@ static void dumpFontInfo(char*loglevel, GfxFont*font)
 //void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) {printf("void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) \n");}
 //void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool inlineImg) {printf("void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool inlineImg) \n");}
 
-static void free_outline(SWF_OUTLINE*outline)
-{
-    while(outline) {
-        SWF_OUTLINE*next = outline->link;
-        free(outline);
-        outline = next;
-    }
-}
 
-static void dump_outline(SWF_OUTLINE*outline)
-{
-    double x=0,y=0;
-    while(outline) {
-        double lastx=x,lasty=y;
-        x += (outline->dest.x/(float)0xffff);
-        y += (outline->dest.y/(float)0xffff);
-        if(outline->type == SWF_PATHTYPE_MOVE) {
-            msg("<trace> | moveto %f,%f", x,y);
-        } else if(outline->type == SWF_PATHTYPE_LINE) {
-            msg("<trace> | lineto: %f,%f\n",x,y);
-        } else if(outline->type == SWF_PATHTYPE_BEZIER) {
-            SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
-            float x1 = o2->C.x/(float)0xffff+lastx;
-            float y1 = o2->C.y/(float)0xffff+lasty;
-            float x2 = o2->B.x/(float)0xffff+lastx;
-            float y2 = o2->B.y/(float)0xffff+lasty;
-            msg("<trace> | spline: %f,%f -> %f,%f -> %f,%f\n",x1,y1,x2,y2,x,y);
-        } 
-        outline = outline->link;
+void dump_outline(gfxline_t*line)
+{
+    while(line) {
+       if(line->type == gfx_moveTo) {
+           msg("<debug> |     moveTo %.2f %.2f", line->x,line->y);
+       } else if(line->type == gfx_lineTo) {
+           msg("<debug> |     lineTo %.2f %.2f", line->x,line->y);
+       } else if(line->type == gfx_splineTo) {
+           msg("<debug> |     splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
+       }
+       line = line->next;
     }
 }
 
-SWF_OUTLINE* gfxPath_to_SWF_OUTLINE(GfxState*state, GfxPath*path)
+gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed)
 {
     int num = path->getNumSubpaths();
     int s,t;
-    bezierpathsegment*start,*last=0;
-    bezierpathsegment*outline = start = (bezierpathsegment*)malloc(sizeof(bezierpathsegment));
     int cpos = 0;
-    double lastx=0,lasty=0;
+    double lastx=0,lasty=0,posx=0,posy=0;
+    int needsfix=0;
     if(!num) {
        msg("<warning> empty path");
-       outline->type = SWF_PATHTYPE_MOVE;
-       outline->dest.x = 0;
-       outline->dest.y = 0;
-       outline->link = 0;
-       return (SWF_OUTLINE*)outline;
+       return 0;
     }
+    gfxdrawer_t draw;
+    gfxdrawer_target_gfxline(&draw);
+
     for(t = 0; t < num; t++) {
        GfxSubpath *subpath = path->getSubpath(t);
        int subnum = subpath->getNumPoints();
+       double bx=0,by=0,cx=0,cy=0;
 
        for(s=0;s<subnum;s++) {
-          double nx,ny;
-          state->transform(subpath->getX(s),subpath->getY(s),&nx,&ny);
-          int x = (int)((nx-lastx)*0xffff);
-          int y = (int)((ny-lasty)*0xffff);
-          if(s==0) 
-          {
-               last = outline;
-               outline->type = SWF_PATHTYPE_MOVE;
-               outline->dest.x = x;
-               outline->dest.y = y;
-               outline->link = (SWF_OUTLINE*)malloc(sizeof(bezierpathsegment));
-               outline = (bezierpathsegment*)outline->link;
+          double x,y;
+          state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
+          if(s==0) {
+               if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
+                   draw.lineTo(&draw, lastx, lasty);
+               }
+               draw.moveTo(&draw, x,y);
+               posx = lastx = x; 
+               posy = lasty = y;
                cpos = 0;
-               lastx = nx;
-               lasty = ny;
-          }
-          else if(subpath->getCurve(s) && !cpos)
-          {
-               outline->B.x = x;
-               outline->B.y = y;
+               needsfix = 0;
+          } else if(subpath->getCurve(s) && cpos==0) {
+               bx = x;
+               by = y;
                cpos = 1;
-          } 
-          else if(subpath->getCurve(s) && cpos)
-          {
-               outline->C.x = x;
-               outline->C.y = y;
+          } else if(subpath->getCurve(s) && cpos==1) {
+               cx = x;
+               cy = y;
                cpos = 2;
-          }
-          else
-          {
-               last = outline;
-               outline->dest.x = x;
-               outline->dest.y = y;
-               outline->type = cpos?SWF_PATHTYPE_BEZIER:SWF_PATHTYPE_LINE;
-               outline->link = (SWF_OUTLINE*)malloc(sizeof(bezierpathsegment));
-               outline = (bezierpathsegment*)outline->link;
+          } else {
+               posx = x;
+               posy = y;
+               if(cpos==0) {
+                   draw.lineTo(&draw, x,y);
+               } else {
+                   gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y);
+               }
+               needsfix = 1;
                cpos = 0;
-               lastx = nx;
-               lasty = ny;
           }
        }
     }
-    if(last->link) {free(last->link);}
-    last->link = 0;
-
-    return (SWF_OUTLINE*)start;
+    /* fix non-closed lines */
+    if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
+       draw.lineTo(&draw, lastx, lasty);
+    }
+    gfxline_t*result = (gfxline_t*)draw.result(&draw);
+    return result;
 }
+
 /*----------------------------------------------------------------------------
  * Primitive Graphic routines
  *----------------------------------------------------------------------------*/
@@ -676,115 +663,160 @@ void SWFOutputDev::stroke(GfxState *state)
     int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
     double miterLimit = state->getMiterLimit();
     double width = state->getTransformedLineWidth();
-    struct swfmatrix m;
+
     GfxRGB rgb;
     double opaq = state->getStrokeOpacity();
-    state->getStrokeRGB(&rgb);
-
-    m.m11 = 1; m.m21 = 0; m.m22 = 1;
-    m.m12 = 0; m.m13 = 0; m.m23 = 0;
-    SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
-    
-    if(screenloglevel >= LOGLEVEL_TRACE)  {
-        msg("<trace> stroke\n");
-        dump_outline(outline);
-    }
+    if(type3active)
+       state->getFillRGB(&rgb);
+    else
+       state->getStrokeRGB(&rgb);
+    gfxcolor_t col;
+    col.r = (unsigned char)(rgb.r*255);
+    col.g = (unsigned char)(rgb.g*255);
+    col.b = (unsigned char)(rgb.b*255);
+    col.a = (unsigned char)(opaq*255);
+   
+    gfx_capType capType = gfx_capRound;
+    if(lineCap == 0) capType = gfx_capButt;
+    else if(lineCap == 1) capType = gfx_capRound;
+    else if(lineCap == 2) capType = gfx_capSquare;
 
-    lineJoin = 1; // other line joins are not yet supported by the swf encoder
-                  // TODO: support bevel joints
+    gfx_joinType joinType = gfx_joinRound;
+    if(lineJoin == 0) joinType = gfx_joinMiter;
+    else if(lineJoin == 1) joinType = gfx_joinRound;
+    else if(lineJoin == 2) joinType = gfx_joinBevel;
 
-    if(((lineCap==1) && (lineJoin==1)) || width<=caplinewidth) {
-       /* FIXME- if the path is smaller than 2 segments, we could ignore
-          lineJoin */
-       swfoutput_setdrawmode(&output, DRAWMODE_STROKE);
-       swfoutput_drawpath(&output, outline, &m);
-    } else {
-       swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), 
-                                       (char)(rgb.b*255), (char)(opaq*255));
+    gfxline_t*line= gfxPath_to_gfxline(state, path, 0);
+    
+    int dashnum = 0;
+    double dashphase = 0;
+    double * ldash = 0;
+    state->getLineDash(&ldash, &dashnum, &dashphase);
 
-       //swfoutput_setlinewidth(&output, 1.0); //only for debugging
-       //swfoutput_setstrokecolor(&output, 0, 255, 0, 255); //likewise, see below
-       //swfoutput_setfillcolor(&output, 255, 0, 0, 255); //likewise, see below
+    if(dashnum && ldash) {
+       float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
+       int t;
+       double cut = 0;
+       int fixzero = 0;
+       msg("<trace> %d dashes", dashnum);
+       msg("<trace> |  phase: %f", dashphase);
+       for(t=0;t<dashnum;t++) {
+           dash[t] = ldash[t];
+           msg("<trace> |  d%-3d: %f", t, ldash[t]);
+       }
+       dash[dashnum] = -1;
+       if(getLogLevel() >= LOGLEVEL_TRACE) {
+           dump_outline(line);
+       }
 
-       swfoutput_drawpath2poly(&output, outline, &m, lineJoin, lineCap, width, miterLimit);
-       updateLineWidth(state);  //reset
-       updateStrokeColor(state); //reset
-       updateFillColor(state);  //reset
+       gfxline_t*line2 = gfxtool_dash_line(line, dash, dashphase);
+       gfxline_free(line);
+       line = line2;
+       msg("<trace> After dashing:");
     }
-    free_outline(outline);
+    
+    if(getLogLevel() >= LOGLEVEL_TRACE)  {
+       double gray;
+       state->getStrokeGray(&gray);
+        msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x gray=%f\n",
+               width,
+               lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
+               lineCap==0?"butt": (lineJoin==1?"round":"square"),
+               dashnum,
+               col.r,col.g,col.b,col.a,
+               gray
+               );
+        dump_outline(line);
+    }
+   
+    swfoutput_drawgfxline(&output, line, width, &col, capType, joinType, miterLimit);
+    gfxline_free(line);
 }
 void SWFOutputDev::fill(GfxState *state) 
 {
     GfxPath * path = state->getPath();
-    struct swfmatrix m;
-    m.m11 = 1; m.m21 = 0; m.m22 = 1;
-    m.m12 = 0; m.m13 = 0; m.m23 = 0;
-    SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
-
-    if(screenloglevel >= LOGLEVEL_TRACE)  {
-        msg("<trace> fill\n");
-        dump_outline(outline);
+    double opaq = state->getFillOpacity();
+    GfxRGB rgb;
+    state->getFillRGB(&rgb);
+    gfxcolor_t col;
+    col.r = (unsigned char)(rgb.r*255);
+    col.g = (unsigned char)(rgb.g*255);
+    col.b = (unsigned char)(rgb.b*255);
+    col.a = (unsigned char)(opaq*255);
+
+    gfxline_t*line= gfxPath_to_gfxline(state, path, 1);
+
+    if(getLogLevel() >= LOGLEVEL_TRACE)  {
+        msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
+        dump_outline(line);
     }
 
-    swfoutput_setdrawmode(&output, DRAWMODE_FILL);
-    swfoutput_drawpath(&output, outline, &m);
-    free_outline(outline);
+    swfoutput_fillgfxline(&output, line, &col);
+    gfxline_free(line);
 }
 void SWFOutputDev::eoFill(GfxState *state) 
 {
     GfxPath * path = state->getPath();
-    struct swfmatrix m;
-    m.m11 = 1; m.m21 = 0; m.m22 = 1;
-    m.m12 = 0; m.m13 = 0; m.m23 = 0;
-    SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
+    double opaq = state->getFillOpacity();
+    GfxRGB rgb;
+    state->getFillRGB(&rgb);
+    gfxcolor_t col;
+    col.r = (unsigned char)(rgb.r*255);
+    col.g = (unsigned char)(rgb.g*255);
+    col.b = (unsigned char)(rgb.b*255);
+    col.a = (unsigned char)(opaq*255);
+
+    gfxline_t*line= gfxPath_to_gfxline(state, path, 1);
 
-    if(screenloglevel >= LOGLEVEL_TRACE)  {
+    if(getLogLevel() >= LOGLEVEL_TRACE)  {
         msg("<trace> eofill\n");
-        dump_outline(outline);
+        dump_outline(line);
     }
 
-    swfoutput_setdrawmode(&output, DRAWMODE_EOFILL);
-    swfoutput_drawpath(&output, outline, &m);
-    free_outline(outline);
+    swfoutput_fillgfxline(&output, line, &col);
+    gfxline_free(line);
 }
 void SWFOutputDev::clip(GfxState *state) 
 {
     GfxPath * path = state->getPath();
-    struct swfmatrix m;
-    m.m11 = 1; m.m22 = 1;
-    m.m12 = 0; m.m21 = 0; 
-    m.m13 = 0; m.m23 = 0;
-    SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
+    gfxline_t*line = gfxPath_to_gfxline(state, path, 1);
 
-    if(screenloglevel >= LOGLEVEL_TRACE)  {
+    if(getLogLevel() >= LOGLEVEL_TRACE)  {
         msg("<trace> clip\n");
-        dump_outline(outline);
+        dump_outline(line);
     }
 
-    swfoutput_startclip(&output, outline, &m);
+    swfoutput_startclip(&output, line);
     clipping[clippos] ++;
-    free_outline(outline);
+    gfxline_free(line);
 }
 void SWFOutputDev::eoClip(GfxState *state) 
 {
     GfxPath * path = state->getPath();
-    struct swfmatrix m;
-    m.m11 = 1; m.m21 = 0; m.m22 = 1;
-    m.m12 = 0; m.m13 = 0; m.m23 = 0;
-    SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path);
+    gfxline_t*line = gfxPath_to_gfxline(state, path, 1);
 
-    if(screenloglevel >= LOGLEVEL_TRACE)  {
+    if(getLogLevel() >= LOGLEVEL_TRACE)  {
         msg("<trace> eoclip\n");
-        dump_outline(outline);
+        dump_outline(line);
     }
 
-    swfoutput_startclip(&output, outline, &m);
+    swfoutput_startclip(&output, line);
     clipping[clippos] ++;
-    free_outline(outline);
+    gfxline_free(line);
+}
+
+/* pass through functions for swf_output */
+int SWFOutputDev::save(char*filename)
+{
+    return swfoutput_save(&output, filename);
+}
+void SWFOutputDev::pagefeed()
+{
+    swfoutput_pagefeed(&output);
 }
-void SWFOutputDev::save(char*filename)
+void* SWFOutputDev::getSWF()
 {
-    swfoutput_save(&output, filename);
+    return (void*)swfoutput_get(&output);
 }
 
 SWFOutputDev::~SWFOutputDev() 
@@ -829,7 +861,16 @@ 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;
+    GfxRGB rgb;
+    double opaq = state->getFillOpacity();
+    state->getFillRGB(&rgb);
+    gfxcolor_t col;
+    col.r = (unsigned char)(rgb.r*255);
+    col.g = (unsigned char)(rgb.g*255);
+    col.b = (unsigned char)(rgb.b*255);
+    col.a = (unsigned char)(opaq*255);
 
+    Gushort *CIDToGIDMap = 0;
     GfxFont*font = state->getFont();
 
     if(font->getType() == fontType3) {
@@ -842,20 +883,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;
@@ -864,29 +914,46 @@ 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, &col);
+    } 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, &col);
+    }
 }
 
 void SWFOutputDev::endString(GfxState *state) { 
 }    
 
-GBool SWFOutputDev::beginType3Char(GfxState *state,
-                              CharCode code, Unicode *u, int uLen)
+/* the logic seems to be as following:
+   first, beginType3Char is called, with the charcode and the coordinates.
+   if this function returns true, it already knew about the char and has now drawn it.
+   if the function returns false, it's a new char, and type3D1 is called with some parameters-
+   the all draw operations until endType3Char are part of the char (which in this moment is
+   at the position first passed to beginType3Char). the char ends with endType3Char.
+
+   The drawing operations between beginType3Char and endType3Char are somewhat different to
+   the normal ones. For example, the fillcolor equals the stroke color.
+*/
+
+GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
 {
     msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
     type3active = 1;
-    /* the character itself is going to be passed using
-       drawImageMask() */
+    /* the character itself is going to be passed using the draw functions */
     return gFalse; /* gTrue= is_in_cache? */
 }
 
+void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) {
+    msg("<debug> type3D0 width=%f height=%f", wx, wy);
+}
+void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
+    msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
+           llx,lly,urx,ury);
+}
+
 void SWFOutputDev::endType3Char(GfxState *state)
 {
     type3active = 0;
@@ -920,10 +987,10 @@ void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, doubl
 
     /* 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(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) {
@@ -1144,7 +1211,7 @@ char* SWFOutputDev::searchFont(char*name)
 void SWFOutputDev::updateLineWidth(GfxState *state)
 {
     double width = state->getTransformedLineWidth();
-    swfoutput_setlinewidth(&output, width);
+    //swfoutput_setlinewidth(&output, width);
 }
 
 void SWFOutputDev::updateLineCap(GfxState *state)
@@ -1163,8 +1230,7 @@ void SWFOutputDev::updateFillColor(GfxState *state)
     double opaq = state->getFillOpacity();
     state->getFillRGB(&rgb);
 
-    swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), 
-                                   (char)(rgb.b*255), (char)(opaq*255));
+    //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
 }
 
 void SWFOutputDev::updateStrokeColor(GfxState *state) 
@@ -1172,9 +1238,7 @@ void SWFOutputDev::updateStrokeColor(GfxState *state)
     GfxRGB rgb;
     double opaq = state->getStrokeOpacity();
     state->getStrokeRGB(&rgb);
-
-    swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), 
-                                     (char)(rgb.b*255), (char)(opaq*255));
+    //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255));
 }
 
 void FoFiWrite(void *stream, char *data, int len)
@@ -1224,9 +1288,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);
@@ -1293,6 +1359,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;
@@ -1300,25 +1369,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) {
@@ -1327,6 +1409,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);
@@ -1334,22 +1417,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);
@@ -1361,6 +1450,7 @@ char* searchForSuitableFont(GfxFont*gfxFont)
                if(nfn) fontname = strdup(nfn+1);
                else    fontname = filename;
            }
+            msg("<debug> FontConfig: Returning \"%s\"", fontname);
         }        
     }
 
@@ -1388,6 +1478,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.");
@@ -1487,7 +1581,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
        ))
@@ -1577,7 +1671,7 @@ unsigned char* antialize(unsigned char*data, int width, int height, int newwidth
 
 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
                                   int width, int height, GfxImageColorMap*colorMap, GBool invert,
-                                  GBool inlineImg, int mask)
+                                  GBool inlineImg, int mask, int*maskColors)
 {
   FILE *fi;
   int c;
@@ -1628,22 +1722,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)
@@ -1653,173 +1746,120 @@ 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;
   } 
 
   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;
+         /*if(maskColors && *maskColors==t) {
+             msg("<notice> Color %d is transparent", t);
+             if (imgData->maskColors) {
+               *alpha = 0;
+               for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
+                 if (pix[i] < imgData->maskColors[2*i] ||
+                     pix[i] > imgData->maskColors[2*i+1]) {
+                   *alpha = 1;
+                   break;
+                 }
+               }
+             } else {
+               *alpha = 1;
+             }
+             if(!*alpha) {
+                   pal[t].r = 0;
+                   pal[t].g = 0;
+                   pal[t].b = 0;
+                   pal[t].a = 0;
+             }
+         } else*/ {
+             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;
@@ -1831,7 +1871,7 @@ void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
                                   GBool inlineImg) 
 {
   msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
-  drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1);
+  drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
 }
 
 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
@@ -1845,7 +1885,7 @@ void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
   if(colorMap)
       msg("<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);
+  drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors);
 }
 
 SWFOutputDev*output = 0; 
@@ -1892,12 +1932,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);
     }
@@ -1914,6 +1981,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;
@@ -1940,7 +2083,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]) {
@@ -1959,7 +2103,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");
@@ -1987,8 +2131,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;
@@ -2017,7 +2161,7 @@ class MemCheck
 {
     public: ~MemCheck()
     {
-        delete globalParams;
+        delete globalParams;globalParams=0;
         Object::memCheck(stderr);
         gMemReport(stderr);
     }
@@ -2078,10 +2222,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)
@@ -2092,10 +2253,10 @@ void swf_output_destroy(swf_output_t*output)
     free(output);
 }
 
-void pdf_page_render2(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");
@@ -2106,6 +2267,7 @@ void pdf_page_render2(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)