fixed treatment of "launch" links without params
[swftools.git] / pdf2swf / SWFOutputDev.cc
index ca34137..6bb12bb 100644 (file)
 #include "Page.h"
 #include "PDFDoc.h"
 #include "Error.h"
+#include "Link.h"
 #include "OutputDev.h"
 #include "GfxState.h"
 #include "GfxFont.h"
 #include "CharCodeToUnicode.h"
 #include "NameToUnicodeTable.h"
 #include "GlobalParams.h"
-//#define XPDF_101
-#ifdef XPDF_101
-#include "FontFile.h"
-#else
 #include "FoFiType1C.h"
 #include "FoFiTrueType.h"
 #include "GHash.h"
-#endif
 #include "SWFOutputDev.h"
 
 //swftools header files
-#include "swfoutput.h"
+#include "../lib/devices/swf.h"
 #include "../lib/log.h"
 #include "../lib/gfxdevice.h"
 #include "../lib/gfxtools.h"
@@ -101,6 +97,8 @@ static int forceType0Fonts = 1;
 static void printInfoString(Dict *infoDict, char *key, char *fmt);
 static void printInfoDate(Dict *infoDict, char *key, char *fmt);
 
+static char* lastfontdir = 0;
+
 struct mapping {
     char*pdffont;
     char*filename;
@@ -163,7 +161,7 @@ public:
   virtual void startPage(int pageNum, GfxState *state, double x1, double y1, double x2, double y2) ;
 
   void endframe();
-  void* getSWF();
+  void* get(char*name);
 
   //----- get info about output device
 
@@ -225,7 +223,7 @@ public:
   virtual void drawChar(GfxState *state, double x, double y,
                        double dx, double dy,
                        double originX, double originY,
-                       CharCode code, Unicode *u, int uLen);
+                       CharCode code, int nBytes, Unicode *u, int uLen);
 
   //----- image drawing
   virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
@@ -234,6 +232,17 @@ public:
   virtual void drawImage(GfxState *state, Object *ref, Stream *str,
                         int width, int height, GfxImageColorMap *colorMap,
                         int *maskColors, GBool inlineImg);
+  virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
+                              int width, int height,
+                              GfxImageColorMap *colorMap,
+                              Stream *maskStr, int maskWidth, int maskHeight,
+                              GBool maskInvert);
+  virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
+                                  int width, int height,
+                                  GfxImageColorMap *colorMap,
+                                  Stream *maskStr,
+                                  int maskWidth, int maskHeight,
+                                  GfxImageColorMap *maskColorMap);
   
   virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen);
   virtual void endType3Char(GfxState *state);
@@ -244,8 +253,9 @@ public:
   private:
   void drawGeneralImage(GfxState *state, Object *ref, Stream *str,
                                   int width, int height, GfxImageColorMap*colorMap, GBool invert,
-                                  GBool inlineImg, int mask, int *maskColors);
-  int SWFOutputDev::setGfxFont(char*id, char*filename, double quality);
+                                  GBool inlineImg, int mask, int *maskColors,
+                                  Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GfxImageColorMap*maskColorMap);
+  int SWFOutputDev::setGfxFont(char*id, char*name, char*filename, double quality);
   void strokeGfxline(GfxState *state, gfxline_t*line);
   void clipToGfxLine(GfxState *state, gfxline_t*line);
   void fillGfxLine(GfxState *state, gfxline_t*line);
@@ -427,10 +437,11 @@ class InfoOutputDev:  public OutputDev
       }
       currentfont = info;
   }
+  
   virtual void drawChar(GfxState *state, double x, double y,
                        double dx, double dy,
                        double originX, double originY,
-                       CharCode code, Unicode *u, int uLen)
+                       CharCode code, int nBytes, Unicode *u, int uLen)
   {
       int render = state->getRender();
       if (render == 3)
@@ -515,20 +526,31 @@ void SWFOutputDev::setClip(int x1,int y1,int x2,int y2)
 
 static char*getFontID(GfxFont*font)
 {
+    Ref*ref = font->getID();
     GString*gstr = font->getName();
-    char* fontname = gstr==0?0:gstr->getCString();
-    if(fontname==0) {
-       char buf[32];
-       Ref*r=font->getID();
-       sprintf(buf, "UFONT%d", r->num);
-       return strdup(buf);
+    char* fname = gstr==0?0:gstr->getCString();
+    char buf[128];
+    if(fname==0) {
+       sprintf(buf, "font-%d-%d", ref->num, ref->gen);
+    } else {
+       sprintf(buf, "%s-%d-%d", fname, ref->num, ref->gen);
     }
-    return strdup(fontname);
+    return strdup(buf);
 }
 
 static char*getFontName(GfxFont*font)
 {
-    char*fontid = getFontID(font);
+    char*fontid;
+    GString*gstr = font->getName();
+    char* fname = gstr==0?0:gstr->getCString();
+    if(fname==0) {
+       char buf[32];
+       Ref*r=font->getID();
+       sprintf(buf, "UFONT%d", r->num);
+       fontid = strdup(buf);
+    }
+    fontid = strdup(fname);
+
     char*fontname= 0;
     char* plus = strchr(fontid, '+');
     if(plus && plus < &fontid[strlen(fontid)-1]) {
@@ -847,9 +869,9 @@ void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
     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.r = colToByte(rgb.r);
+    col.g = colToByte(rgb.g);
+    col.b = colToByte(rgb.b);
     col.a = (unsigned char)(opaq*255);
    
     gfx_capType capType = gfx_capRound;
@@ -892,15 +914,12 @@ void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
     }
     
     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",
+        msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x\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
+               col.r,col.g,col.b,col.a
                );
         dump_outline(line);
     }
@@ -912,15 +931,19 @@ void SWFOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
        gfxline_free(line2);
 }
 
+void convertRGB()
+{
+}
+
 gfxcolor_t getFillColor(GfxState * state)
 {
     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.r = colToByte(rgb.r);
+    col.g = colToByte(rgb.g);
+    col.b = colToByte(rgb.b);
     col.a = (unsigned char)(opaq*255);
     return col;
 }
@@ -1020,10 +1043,10 @@ int SWFOutputDev::save(char*filename)
     finish();
     return result->save(result, filename);
 }
-void* SWFOutputDev::getSWF()
+void* SWFOutputDev::get(char*name)
 {
     finish();
-    return result->get(result, "swf");
+    return result->get(result, name);
 }
 
 SWFOutputDev::~SWFOutputDev() 
@@ -1107,8 +1130,22 @@ char* makeStringPrintable(char*str)
 
 int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
 {
-    int t;
+    char*uniname = 0;
+    if(u>0) {
+       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) {
+               uniname = nameToUnicodeTab[t].name;
+               break;
+           }
+       }
+    }
+
     if(charname) {
+       int t;
        for(t=0;t<font->num_glyphs;t++) {
            if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
                msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
@@ -1125,17 +1162,30 @@ int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
        }
     }
 
+    if(uniname) {
+       int t;
+       for(t=0;t<font->num_glyphs;t++) {
+           if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,uniname)) {
+               msg("<debug> Char [%d,%s,>%d(%s)<] maps to %d\n", charnr, charname, u, uniname, t);
+               return t;
+           }
+       }
+       /* if we didn't find the character, maybe
+          we can find the capitalized version */
+       for(t=0;t<font->num_glyphs;t++) {
+           if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,uniname)) {
+               msg("<debug> Char [%d,%s,>>%d(%s)<<] maps to %d\n", charnr, charname, u, uniname, t);
+               return t;
+           }
+       }
+    }
+
     /* try to use the unicode id */
     if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
        msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
        return font->unicode2glyph[u];
     }
 
-    /* we don't need to "draw" space characters, so don't overdo the search
-       for a matching glyph */
-    if(charname && !strcasecmp(charname, "space"))
-       return -1;
-
     if(charnr>=0 && charnr<font->num_glyphs) {
        msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
        return charnr;
@@ -1176,9 +1226,8 @@ void SWFOutputDev::beginString(GfxState *state, GString *s)
 void SWFOutputDev::drawChar(GfxState *state, double x, double y,
                        double dx, double dy,
                        double originX, double originY,
-                       CharCode c, Unicode *_u, int uLen)
+                       CharCode c, int nBytes, Unicode *_u, int uLen)
 {
-    msg("<debug> drawChar(%f,%f,%d)", x,y,c);
     int render = state->getRender();
     // check for invisible text -- this is used by Acrobat Capture
     if (render == 3) {
@@ -1203,22 +1252,6 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y,
     Unicode u=0;
     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;
-               }
-           }
-       }
-    }
-
     if(font->isCIDFont()) {
        GfxCIDFont*cfont = (GfxCIDFont*)font;
 
@@ -1228,8 +1261,7 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y,
        Gfx8BitFont*font8;
        font8 = (Gfx8BitFont*)font;
        char**enc=font8->getEncoding();
-       if(enc && enc[c])
-          name = enc[c];
+       name = enc[c];
     }
     if (CIDToGIDMap) {
        msg("<debug> drawChar(%f, %f, c='%c' (%d), GID=%d, u=%d <%d>) CID=%d name=\"%s\" render=%d\n", x, y, (c&127)>=32?c:'?', c, CIDToGIDMap[c], u, uLen, font->isCIDFont(), FIXNULL(name), render);
@@ -1243,7 +1275,8 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y,
     if(uLen<=1) {
        charid = getGfxCharID(current_gfxfont, c, name, u);
     } else {
-       charid = getGfxCharID(current_gfxfont, c, 0, -1);
+       charid = getGfxCharID(current_gfxfont, c, name, -1);
+
        if(charid < 0) {
            /* multiple unicodes- should usually map to a ligature.
               if the ligature doesn't exist, we need to draw
@@ -1251,17 +1284,14 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y,
            int t;
            msg("<warning> ligature %d missing in font %s\n", c, current_font_id);
            for(t=0;t<uLen;t++) {
-               drawChar(state, x, y, dx, dy, originX, originY, c, _u+t, 1);
+               drawChar(state, x, y, dx, dy, originX, originY, c, nBytes, _u+t, 1);
            }
            return;
        }
     }
-
     if(charid<0) {
-       if(strcasecmp(name, "space")) {
-           msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)", 
-                   FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
-       }
+       msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)", 
+               FIXNULL(name),c, u, FIXNULL((char*)current_font_id), current_gfxfont->num_glyphs);
        return;
     }
 
@@ -1431,20 +1461,13 @@ void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, doubl
 
 void SWFOutputDev::drawLink(Link *link, Catalog *catalog) 
 {
-    msg("<debug> drawlink\n");
     double x1, y1, x2, y2, w;
-    GfxRGB rgb;
     gfxline_t points[5];
     int x, y;
+    
+    msg("<debug> drawlink\n");
 
-#ifdef XPDF_101
-    link->getBorder(&x1, &y1, &x2, &y2, &w);
-#else
     link->getRect(&x1, &y1, &x2, &y2);
-#endif
-    rgb.r = 0;
-    rgb.g = 0;
-    rgb.b = 1;
     cvtUserToDev(x1, y1, &x, &y);
     points[0].type = gfx_moveTo;
     points[0].x = points[4].x = x + user_movex;
@@ -1540,7 +1563,9 @@ void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
             type = "Launch";
             LinkLaunch*l = (LinkLaunch*)action;
             GString * str = new GString(l->getFileName());
-            str->append(l->getParams());
+           GString * params = l->getParams();
+           if(params)
+               str->append(params);
             s = strdup(str->getCString());
             delete str;
         }
@@ -1566,6 +1591,7 @@ void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
             break;
         }
     }
+
     if(!s) s = strdup("-?-");
 
     if(!linkinfo && (page || url))
@@ -1584,13 +1610,12 @@ void SWFOutputDev::drawLink(Link *link, Catalog *catalog)
                 break;
            }
        }
-        if(lpage>=0) {
-           char buf[80];
-           sprintf(buf, "page%d", t);
-            output->drawlink(output, points, buf);
-       } else {
-           msg("<warning> Invalid link to page %d", page);
+        if(lpage<0) {
+           lpage = page;
        }
+       char buf[80];
+       sprintf(buf, "page%d", lpage);
+       output->drawlink(output, points, buf);
     }
     else if(url)
     {
@@ -1736,15 +1761,9 @@ char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
        msg("<error> Couldn't read embedded font file");
        return 0;
       }
-#ifdef XPDF_101
-      Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen);
-      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);
       //cvt->convertToType0("test", f);
       delete cvt;
@@ -1756,13 +1775,8 @@ char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
        msg("<error> Couldn't read embedded font file");
        return 0;
       }
-#ifdef XPDF_101
-      TrueTypeFontFile *cvt = new TrueTypeFontFile(fontBuf, fontLen);
-      cvt->writeTTF(f);
-#else
       FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
       cvt->writeTTF(FoFiWrite, f);
-#endif
       delete cvt;
       gfree(fontBuf);
     } else {
@@ -1922,7 +1936,7 @@ char* searchForSuitableFont(GfxFont*gfxFont)
 char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
 {
     char*fontname = 0, *filename = 0;
-    msg("<notice> subsituteFont(%s)", oldname);
+    msg("<notice> substituteFont(%s)", oldname);
 
     if(!(fontname = searchForSuitableFont(gfxFont))) {
        fontname = "Times-Roman";
@@ -1981,7 +1995,7 @@ void SWFOutputDev::setXRef(PDFDoc*doc, XRef *xref)
     this->xref = xref;
 }
 
-int SWFOutputDev::setGfxFont(char*id, char*filename, double maxSize)
+int SWFOutputDev::setGfxFont(char*id, char*name, char*filename, double maxSize)
 {
     gfxfont_t*font = 0;
     fontlist_t*last=0,*l = this->fontlist;
@@ -2005,8 +2019,11 @@ int SWFOutputDev::setGfxFont(char*id, char*filename, double maxSize)
        we have to divide 0.05 by (fontsize/1024)
      */
     double quality = (1024 * 0.05) / maxSize;
-    
+   
+    msg("<verbose> Loading %s...", filename);
     font = gfxfont_load(filename, quality);
+    msg("<verbose> Font %s loaded successfully", filename);
+
     l = new fontlist_t;
     l->font = font;
     l->filename = strdup(filename);
@@ -2030,7 +2047,10 @@ void SWFOutputDev::updateFont(GfxState *state)
     if (!gfxFont) {
        return;
     }  
+    
     char * fontid = getFontID(gfxFont);
+    char * fontname = getFontName(gfxFont);
+
     double maxSize = 1.0;
 
     if(this->info) {
@@ -2051,8 +2071,9 @@ void SWFOutputDev::updateFont(GfxState *state)
 
     /* second, see if this is a font which was used before-
        if so, we are done */
-    if(setGfxFont(fontid, 0, 0)) {
+    if(setGfxFont(fontid, fontname, 0, 0)) {
        free(fontid);
+       free(fontname);
        return;
     }
 /*    if(swfoutput_queryfont(&output, fontid))
@@ -2069,6 +2090,7 @@ void SWFOutputDev::updateFont(GfxState *state)
            showFontError(gfxFont, 2);
        }
        free(fontid);
+       free(fontname);
        return;
     }
 
@@ -2091,15 +2113,18 @@ void SWFOutputDev::updateFont(GfxState *state)
       if(!fileName) showFontError(gfxFont,0);
       else del = 1;
     } else {
-      char * fontname = getFontName(gfxFont);
       fileName = searchFont(fontname);
       if(!fileName) showFontError(gfxFont,0);
-      free(fontname);
     }
     if(!fileName) {
        char * fontname = getFontName(gfxFont);
        msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
-       msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into /swftools/fonts", fontname);
+       
+       if(lastfontdir)
+           msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into %s", fontname, lastfontdir);
+       else
+           msg("<warning> Try specifying one or more font directories");
+
        fileName = substituteFont(gfxFont, fontid);
        if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
        msg("<notice> Font is now %s (%s)", fontid, fileName);
@@ -2108,6 +2133,7 @@ void SWFOutputDev::updateFont(GfxState *state)
     if(!fileName) {
        msg("<error> Couldn't set font %s\n", fontid);
        free(fontid);
+       free(fontname);
        return;
     }
        
@@ -2116,15 +2142,19 @@ void SWFOutputDev::updateFont(GfxState *state)
 
     //swfoutput_setfont(&output, fontid, fileName);
     
-    if(!setGfxFont(fontid, 0, 0)) {
-       setGfxFont(fontid, fileName, maxSize);
+    if(!setGfxFont(fontid, fontname, 0, 0)) {
+       setGfxFont(fontid, fontname, fileName, maxSize);
     }
    
     if(fileName && del)
        unlinkfont(fileName);
+
     if(fileName)
         free(fileName);
     free(fontid);
+    free(fontname);
+
+    msg("<verbose> |");
 }
 
 #define SQR(x) ((x)*(x))
@@ -2180,13 +2210,13 @@ unsigned char* antialize(unsigned char*data, int width, int height, int newwidth
 #define IMAGE_TYPE_JPEG 0
 #define IMAGE_TYPE_LOSSLESS 1
 
-static void drawimage(gfxdevice_t*dev, RGBA* data, int sizex,int sizey, 
+static void drawimage(gfxdevice_t*dev, gfxcolor_t* data, int sizex,int sizey, 
         double x1,double y1,
         double x2,double y2,
         double x3,double y3,
         double x4,double y4, int type)
 {
-    RGBA*newpic=0;
+    gfxcolor_t*newpic=0;
     
     double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
     double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
@@ -2231,13 +2261,13 @@ static void drawimage(gfxdevice_t*dev, RGBA* data, int sizex,int sizey,
     dev->fillbitmap(dev, &p1, &img, &m, 0);
 }
 
-void drawimagejpeg(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey, 
+void drawimagejpeg(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey, 
         double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
 {
     drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
 }
 
-void drawimagelossless(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey, 
+void drawimagelossless(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey, 
         double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
 {
     drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
@@ -2246,22 +2276,59 @@ void drawimagelossless(gfxdevice_t*dev, RGBA*mem, int sizex,int sizey,
 
 void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
                                   int width, int height, GfxImageColorMap*colorMap, GBool invert,
-                                  GBool inlineImg, int mask, int*maskColors)
+                                  GBool inlineImg, int mask, int*maskColors,
+                                  Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GfxImageColorMap*maskColorMap)
 {
-  FILE *fi;
-  int c;
-  char fileName[128];
   double x1,y1,x2,y2,x3,y3,x4,y4;
   ImageStream *imgStr;
   Guchar pixBuf[4];
   GfxRGB rgb;
   int ncomps = 1;
   int bits = 1;
+  unsigned char* maskbitmap = 0;
                                 
   if(colorMap) {
     ncomps = colorMap->getNumPixelComps();
     bits = colorMap->getBits();
   }
+  
+  if(maskStr) {
+      int x,y;
+      unsigned char buf[8];
+      maskbitmap = (unsigned char*)malloc(maskHeight*maskWidth);
+      if(maskColorMap) {
+         ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, maskColorMap->getNumPixelComps(), maskColorMap->getBits());
+         imgMaskStr->reset();
+         unsigned char pal[256];
+         int n = 1 << colorMap->getBits();
+         int t;
+         for(t=0;t<n;t++) {
+             GfxGray gray;
+             pixBuf[0] = t;
+             maskColorMap->getGray(pixBuf, &gray);
+             pal[t] = colToByte(gray);
+         }
+         for (y = 0; y < maskHeight; y++) {
+             for (x = 0; x < maskWidth; x++) {
+                 imgMaskStr->getPixel(buf);
+                 maskbitmap[y*maskWidth+x] = pal[buf[0]];
+             }
+         }
+         delete imgMaskStr;
+      } else {
+         ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, 1, 1);
+         imgMaskStr->reset();
+         for (y = 0; y < maskHeight; y++) {
+             for (x = 0; x < maskWidth; x++) {
+                 imgMaskStr->getPixel(buf);
+                 buf[0]^=maskInvert;
+                 maskbitmap[y*maskWidth+x] = (buf[0]^1)*255;
+             }
+         }
+         delete imgMaskStr;
+      }
+  }
+      
   imgStr = new ImageStream(str, width, ncomps,bits);
   imgStr->reset();
 
@@ -2275,13 +2342,15 @@ void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
          imgStr->getPixel(buf);
       }
       delete imgStr;
+      if(maskbitmap)
+         free(maskbitmap);
       return;
   }
-  
-  state->transform(0, 1, &x1, &y1); x1 += user_movex; y1+= user_movey;
-  state->transform(0, 0, &x2, &y2); x2 += user_movex; y2+= user_movey;
-  state->transform(1, 0, &x3, &y3); x3 += user_movex; y3+= user_movey;
-  state->transform(1, 1, &x4, &y4); x4 += user_movex; y4+= user_movey;
+
+  state->transform(0, 1, &x1, &y1); x1 += user_movex; y1 += user_movey;
+  state->transform(0, 0, &x2, &y2); x2 += user_movex; y2 += user_movey;
+  state->transform(1, 0, &x3, &y3); x3 += user_movex; y3 += user_movey;
+  state->transform(1, 1, &x4, &y4); x4 += user_movex; y4 += user_movey;
 
   if(!pbminfo && !(str->getKind()==strDCT)) {
       if(!type3active) {
@@ -2301,16 +2370,16 @@ void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
       unsigned char buf[8];
       int x,y;
       unsigned char*pic = new unsigned char[width*height];
-      RGBA pal[256];
+      gfxcolor_t pal[256];
       GfxRGB rgb;
       state->getFillRGB(&rgb);
 
       memset(pal,255,sizeof(pal));
-      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].r = (int)(colToByte(rgb.r)); pal[1].r = 0;
+      pal[0].g = (int)(colToByte(rgb.g)); pal[1].g = 0;
+      pal[0].b = (int)(colToByte(rgb.b)); pal[1].b = 0;
       pal[0].a = 255;              pal[1].a = 0;
-
+    
       int numpalette = 2;
       int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
       int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
@@ -2345,21 +2414,18 @@ void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
          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);
+             pal[t].r = colToByte(rgb.r);
+             pal[t].g = colToByte(rgb.g);
+             pal[t].b = colToByte(rgb.b);
+             pal[t].a = (unsigned char)(t*r);
          }
       }
 
-      RGBA*pic2 = new RGBA[width*height];
+      gfxcolor_t*pic2 = new gfxcolor_t[width*height];
       for (y = 0; y < height; ++y) {
        for (x = 0; x < width; ++x) {
          pic2[width*y+x] = pal[pic[y*width+x]];
@@ -2369,21 +2435,25 @@ void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
       free(pic2);
       free(pic);
       delete imgStr;
+      if(maskbitmap) free(maskbitmap);
       return;
-  } 
+  }
 
   int x,y;
 
   if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
-      RGBA*pic=new RGBA[width*height];
+      gfxcolor_t*pic=new gfxcolor_t[width*height];
       for (y = 0; y < height; ++y) {
        for (x = 0; x < width; ++x) {
          imgStr->getPixel(pixBuf);
          colorMap->getRGB(pixBuf, &rgb);
-         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].r = (unsigned char)(colToByte(rgb.r));
+         pic[width*y+x].g = (unsigned char)(colToByte(rgb.g));
+         pic[width*y+x].b = (unsigned char)(colToByte(rgb.b));
          pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
+         if(maskbitmap) {
+             pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
+         }
        }
       }
       if(str->getKind()==strDCT)
@@ -2392,15 +2462,18 @@ void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
          drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
       delete pic;
       delete imgStr;
+      if(maskbitmap) free(maskbitmap);
       return;
   } else {
-      RGBA*pic=new RGBA[width*height];
-      RGBA pal[256];
+      gfxcolor_t*pic=new gfxcolor_t[width*height];
+      gfxcolor_t pal[256];
+      int n = 1 << colorMap->getBits();
       int t;
       for(t=0;t<256;t++) {
          pixBuf[0] = t;
          colorMap->getRGB(pixBuf, &rgb);
-         /*if(maskColors && *maskColors==t) {
+
+         {/*if(maskColors && *maskColors==t) {
              msg("<notice> Color %d is transparent", t);
              if (imgData->maskColors) {
                *alpha = 0;
@@ -2420,10 +2493,10 @@ void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
                    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);
+         } else {*/
+             pal[t].r = (unsigned char)(colToByte(rgb.r));
+             pal[t].g = (unsigned char)(colToByte(rgb.g));
+             pal[t].b = (unsigned char)(colToByte(rgb.b));
              pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
          }
       }
@@ -2431,12 +2504,16 @@ void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
        for (x = 0; x < width; ++x) {
          imgStr->getPixel(pixBuf);
          pic[width*y+x] = pal[pixBuf[0]];
+         if(maskbitmap) {
+             pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
+         }
        }
       }
       drawimagelossless(output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
 
       delete pic;
       delete imgStr;
+      if(maskbitmap) free(maskbitmap);
       return;
   }
 }
@@ -2448,7 +2525,7 @@ void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
   if(states[statepos].textRender & 4) //clipped
       return;
   msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
-  drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0);
+  drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0, 0,0,0,0, 0);
 }
 
 void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
@@ -2458,14 +2535,51 @@ void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
   if(states[statepos].textRender & 4) //clipped
       return;
 
-  msg("<verbose> drawImage %dx%d, %s %s, inline=%d", width, height, 
+  msg("<verbose> drawImage %dx%d, %s, %s, inline=%d", width, height, 
          colorMap?"colorMap":"no colorMap", 
          maskColors?"maskColors":"no maskColors",
          inlineImg);
   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,maskColors);
+  drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors, 0,0,0,0, 0);
+}
+  
+void SWFOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
+                              int width, int height,
+                              GfxImageColorMap *colorMap,
+                              Stream *maskStr, int maskWidth, int maskHeight,
+                              GBool maskInvert)
+{
+  if(states[statepos].textRender & 4) //clipped
+      return;
+
+  msg("<verbose> drawMaskedImage %dx%d, %s, %dx%d mask", width, height, 
+         colorMap?"colorMap":"no colorMap", 
+         maskWidth, maskHeight);
+  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,0,0,0, maskStr, maskWidth, maskHeight, maskInvert, 0);
+}
+
+void SWFOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
+                                  int width, int height,
+                                  GfxImageColorMap *colorMap,
+                                  Stream *maskStr,
+                                  int maskWidth, int maskHeight,
+                                  GfxImageColorMap *maskColorMap)
+{
+  if(states[statepos].textRender & 4) //clipped
+      return;
+
+  msg("<verbose> drawSoftMaskedImage %dx%d, %s, %dx%d mask", width, height, 
+         colorMap?"colorMap":"no colorMap", 
+         maskWidth, maskHeight);
+  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,0,0,0, maskStr, maskWidth, maskHeight, 0, maskColorMap);
 }
 
 //SWFOutputDev*output = 0; 
@@ -2554,9 +2668,9 @@ void pdfswf_setparameter(char*name, char*value)
        storeDeviceParameter("ppmsubpixels", buf);
     } else if(!strcmp(name, "forceType0Fonts")) {
        forceType0Fonts = atoi(value);
-    } else if(!strcmp(name, "fontdir")) {
+    } else if(!strncmp(name, "fontdir", strlen("fontdir"))) {
         pdfswf_addfontdir(value);
-    } else if(!strcmp(name, "languagedir")) {
+    } else if(!strncmp(name, "languagedir", strlen("languagedir"))) {
         pdfswf_addlanguagedir(value);
     } else if(!strcmp(name, "fontconfig")) {
         config_use_fontconfig = atoi(value);
@@ -2594,7 +2708,7 @@ void pdfswf_addlanguagedir(char*dir)
 
     int l;
     FILE*fi = 0;
-    char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc"));
+    char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc") + 1);
     strcpy(config_file, dir);
     strcat(config_file, dirseparator());
     strcat(config_file, "add-to-xpdfrc");
@@ -2612,6 +2726,7 @@ void pdfswf_addfontdir(char*dirname)
 {
 #ifdef HAVE_DIRENT_H
     msg("<notice> Adding %s to font directories", dirname);
+    lastfontdir = strdup(dirname);
     DIR*dir = opendir(dirname);
     if(!dir) {
        msg("<warning> Couldn't open directory %s\n", dirname);
@@ -2737,11 +2852,7 @@ pdf_doc_t* pdf_init(char*filename, char*userPassword)
     InfoOutputDev*io = new InfoOutputDev();
     int t;
     for(t=1;t<=pdf_doc->num_pages;t++) {
-#ifdef XPDF_101
-       i->doc->displayPage((OutputDev*)io, t, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
-#else
-       i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
-#endif
+       i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, /*usemediabox*/true, /*crop*/true, /*doLinks*/(int)1);
     }
     i->info = io;
 
@@ -2858,10 +2969,10 @@ int swf_output_save(swf_output_t*swf, char*filename)
     return ret;
 }
 
-void* swf_output_get(swf_output_t*swf)
+void* swf_output_get(swf_output_t*swf,char*name)
 {
     swf_output_internal_t*i= (swf_output_internal_t*)swf->internal;
-    void* ret = i->outputDev->getSWF();
+    void* ret = i->outputDev->get(name);
     return ret;
 }
 
@@ -2889,11 +3000,7 @@ void pdf_page_render2(pdf_page_t*page, swf_output_t*swf)
     }
     si->outputDev->setInfo(pi->info);
     si->outputDev->setXRef(pi->doc, pi->doc->getXRef());
-#ifdef XPDF_101
-    pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, /*zoom*/zoom, /*rotate*/0, /*doLinks*/(int)1);
-#else
-    pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1);
-#endif
+    pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
 }
 
 void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)
@@ -2928,11 +3035,7 @@ pdf_page_info_t* pdf_page_getinfo(pdf_page_t*page)
 
     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
+    pi->doc->displayPage((OutputDev*)output, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
 
     info->xMin = output->x1;
     info->yMin = output->y1;