poppler: add new axial and radialShadedFill parameters
[swftools.git] / lib / pdf / BitmapOutputDev.cc
index 49f5e3c..b94fcde 100644 (file)
 #include <stdio.h>
 #include <memory.h>
 #include <assert.h>
-#include "config.h"
 #include "BitmapOutputDev.h"
 #include "GFXOutputDev.h"
-#include "SplashBitmap.h"
-#include "SplashPattern.h"
-#include "Splash.h"
+
+#ifdef HAVE_POPPLER
+  #include "splash/SplashBitmap.h"
+  #include "splash/SplashPattern.h"
+  #include "splash/Splash.h"
+#else
+  #include "xpdf/config.h"
+  #include "SplashBitmap.h"
+  #include "SplashPattern.h"
+  #include "Splash.h"
+#endif
+
 #include "../log.h"
 #include "../png.h"
 #include "../devices/record.h"
+#include "../gfxtools.h"
 #include "../types.h"
 #include "bbox.h"
 
@@ -80,6 +89,7 @@ BitmapOutputDev::BitmapOutputDev(InfoOutputDev*info, PDFDoc*doc)
     this->gfxdev->setDevice(this->gfxoutput);
     
     this->config_extrafontdata = 0;
+    this->config_optimizeplaincolorfills = 0;
     this->bboxpath = 0;
     //this->clipdev = 0;
     //this->clipstates = 0;
@@ -172,8 +182,8 @@ static int dbg_btm_counter=1;
 
 void BitmapOutputDev::flushBitmap()
 {
-    int width = rgbdev->getBitmapWidth();
-    int height = rgbdev->getBitmapHeight();
+    int bitmap_width = rgbdev->getBitmapWidth();
+    int bitmap_height = rgbdev->getBitmapHeight();
 
     if(sizeof(SplashColor)!=3) {
        msg("<error> sizeof(SplashColor)!=3");
@@ -194,7 +204,7 @@ void BitmapOutputDev::flushBitmap()
     Guchar*alpha = rgbbitmap->getAlphaPtr();
     
     Guchar*alpha2 = stalepolybitmap->getDataPtr();
-    int width8 = (stalepolybitmap->getWidth()+7)/8;
+    int bitmap_width8 = (stalepolybitmap->getWidth()+7)/8;
 
     /*char filename[80];
     sprintf(filename, "flush%d_mask.png", dbg_btm_counter);
@@ -204,22 +214,39 @@ void BitmapOutputDev::flushBitmap()
     sprintf(filename, "flush%d_bitmap.png", dbg_btm_counter);
     writeBitmap(rgbbitmap, filename);*/
 
-    ibbox_t* boxes = get_bitmap_bboxes((unsigned char*)alpha, width, height);
-    ibbox_t*b;
+    ibbox_t pagebox = {-movex, -movey, -movex + this->width, -movey + this->height, 0};
+    ibbox_t bitmapbox = {0, 0, bitmap_width, bitmap_height, 0};
+    ibbox_t c = ibbox_clip(&bitmapbox, &pagebox);
+    ibbox_t* boxes = get_bitmap_bboxes((unsigned char*)(alpha+c.ymin*bitmap_width+c.xmin), c.xmax - c.xmin, c.ymax - c.ymin, bitmap_width);
 
+    ibbox_t*b;
     for(b=boxes;b;b=b->next) {
-       int xmin = b->xmin;
-       int ymin = b->ymin;
-       int xmax = b->xmax;
-       int ymax = b->ymax;
+       int xmin = b->xmin - this->movex;
+       int ymin = b->ymin - this->movey;
+       int xmax = b->xmax - this->movex;
+       int ymax = b->ymax - this->movey;
 
        /* clip against (-movex, -movey, -movex+width, -movey+height) */
-       if(xmin < -this->movex) xmin = -this->movex;
-       if(ymin < -this->movey) ymin = -this->movey;
-       if(xmax > -this->movex + width) xmax = -this->movex+this->width;
-       if(ymax > -this->movey + height) ymax = -this->movey+this->height;
 
-       msg("<verbose> Flushing bitmap (bbox: %d,%d,%d,%d)", xmin,ymin,xmax,ymax);
+       msg("<verbose> Flushing bitmap (bbox: %d,%d,%d,%d %dx%d) (clipped against %d,%d,%d,%d)", xmin,ymin,xmax,ymax, xmax-xmin, ymax-ymin,
+               -this->movex, -this->movey, -this->movex+this->width, -this->movey+this->height);
+
+       if(xmin < -this->movex) {
+           xmin = -this->movex;
+           if(xmax < -this->movex) continue;
+       }
+       if(ymin < -this->movey) {
+           ymin = -this->movey;
+           if(ymax < -this->movey) continue;
+       }
+       if(xmax >= -this->movex + this->width) {
+           xmax = -this->movex+this->width;
+           if(xmin >= -this->movex + this->width) continue;
+       }
+       if(ymax >= -this->movey + this->height) {
+           ymax = -this->movey+this->height;
+           if(ymin >= -this->movey + this->height) continue;
+       }
        
        if((xmax-xmin)<=0 || (ymax-ymin)<=0) // no bitmap, nothing to do
            continue;
@@ -232,10 +259,10 @@ void BitmapOutputDev::flushBitmap()
        img->height = rangey;
        int x,y;
        for(y=0;y<rangey;y++) {
-           SplashColorPtr in=&rgb[((y+ymin)*width+xmin)*sizeof(SplashColor)];
+           SplashColorPtr in=&rgb[((y+ymin)*bitmap_width+xmin)*sizeof(SplashColor)];
            gfxcolor_t*out = &img->data[y*rangex];
-           Guchar*ain = &alpha[(y+ymin)*width+xmin];
-           Guchar*ain2 = &alpha2[(y+ymin)*width8];
+           Guchar*ain = &alpha[(y+ymin)*bitmap_width+xmin];
+           Guchar*ain2 = &alpha2[(y+ymin)*bitmap_width8];
            if(this->emptypage) {
                for(x=0;x<rangex;x++) {
                    /* the first bitmap on the page doesn't need to have an alpha channel-
@@ -297,7 +324,16 @@ void BitmapOutputDev::flushBitmap()
 void BitmapOutputDev::flushText()
 {
     msg("<verbose> Flushing text");
-    gfxdevice_record_flush(this->gfxoutput, this->dev);
+
+    static gfxfontlist_t*output_font_list = 0;
+    static gfxdevice_t*last = 0;
+    if(last != this->dev) {
+       if(output_font_list)
+           gfxfontlist_free(output_font_list, 0);
+       output_font_list = gfxfontlist_create();
+    }
+    gfxdevice_record_flush(this->gfxoutput, this->dev, &output_font_list);
+    last = this->dev;
     
     this->emptypage = 0;
 }
@@ -322,7 +358,7 @@ void writeMonoBitmap(SplashBitmap*btm, char*filename)
             }
         }
     }
-    writePNG(filename, (unsigned char*)b, width, height);
+    png_write(filename, (unsigned char*)b, width, height);
     free(b);
 }
 
@@ -351,7 +387,7 @@ void writeBitmap(SplashBitmap*bitmap, char*filename)
            line[x].a =  bitmap->getAlpha(x,y);
        }
     }
-    writePNG(filename, (unsigned char*)data, width, height);
+    png_write(filename, (unsigned char*)data, width, height);
     free(data);
 }
 
@@ -379,7 +415,7 @@ void writeAlpha(SplashBitmap*bitmap, char*filename)
            line[x].a = a;
        }
     }
-    writePNG(filename, (unsigned char*)data, width, height);
+    png_write(filename, (unsigned char*)data, width, height);
     free(data);
 }
 
@@ -823,12 +859,24 @@ GBool BitmapOutputDev::intersection(SplashBitmap*boolpoly, SplashBitmap*booltext
     }
 }
 
+GBool BitmapOutputDev::checkPageSlice(Page *page, double hDPI, double vDPI,
+             int rotate, GBool useMediaBox, GBool crop,
+             int sliceX, int sliceY, int sliceW, int sliceH,
+             GBool printing, Catalog *catalog,
+             GBool (*abortCheckCbk)(void *data),
+             void *abortCheckCbkData)
+{
+    this->setPage(page);
+    gfxdev->setPage(page);
+    return gTrue;
+}
 
-void BitmapOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
+void BitmapOutputDev::startPage(int pageNum, GfxState *state)
 {
+    PDFRectangle *r = this->page->getCropBox();
     double x1,y1,x2,y2;
-    state->transform(crop_x1,crop_y1,&x1,&y1);
-    state->transform(crop_x2,crop_y2,&x2,&y2);
+    state->transform(r->x1,r->y1,&x1,&y1);
+    state->transform(r->x2,r->y2,&x2,&y2);
     if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
     if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
     
@@ -844,13 +892,12 @@ void BitmapOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, do
     this->width = (int)(x2-x1);
     this->height = (int)(y2-y1);
 
-    msg("<debug> startPage");
-    rgbdev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
-    boolpolydev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
-    booltextdev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
-    clip0dev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
-    clip1dev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
-    gfxdev->startPage(pageNum, state, crop_x1, crop_y1, crop_x2, crop_y2);
+    rgbdev->startPage(pageNum, state);
+    boolpolydev->startPage(pageNum, state);
+    booltextdev->startPage(pageNum, state);
+    clip0dev->startPage(pageNum, state);
+    clip1dev->startPage(pageNum, state);
+    gfxdev->startPage(pageNum, state);
 
     boolpolybitmap = boolpolydev->getBitmap();
     stalepolybitmap = new SplashBitmap(boolpolybitmap->getWidth(), boolpolybitmap->getHeight(), 1, boolpolybitmap->getMode(), 0);
@@ -859,6 +906,8 @@ void BitmapOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, do
     booltextbitmap = booltextdev->getBitmap();
     staletextbitmap = new SplashBitmap(booltextbitmap->getWidth(), booltextbitmap->getHeight(), 1, booltextbitmap->getMode(), 0);
     assert(staletextbitmap->getRowSize() == booltextbitmap->getRowSize());
+    
+    msg("<debug> startPage %dx%d (%dx%d)", this->width, this->height, booltextbitmap->getWidth(), booltextbitmap->getHeight());
 
     clip0bitmap = clip0dev->getBitmap();
     clip1bitmap = clip1dev->getBitmap();
@@ -888,13 +937,7 @@ void BitmapOutputDev::finishPage()
     msg("<verbose> finishPage (BitmapOutputDev)");
     gfxdev->endPage();
    
-    if(layerstate == STATE_BITMAP_IS_ABOVE) {
-       this->flushText();
-       this->flushBitmap();
-    } else {
-       this->flushBitmap();
-       this->flushText();
-    }
+    flushEverything();
 
     /* splash will now destroy alpha, and paint the 
        background color into the "holes" in the bitmap */
@@ -967,15 +1010,6 @@ GBool BitmapOutputDev::needNonText()
     clip1dev->needNonText();
     return rgbdev->needNonText();
 }
-/*GBool BitmapOutputDev::checkPageSlice(Page *page, double hDPI, double vDPI,
-                          int rotate, GBool useMediaBox, GBool crop,
-                          int sliceX, int sliceY, int sliceW, int sliceH,
-                          GBool printing, Catalog *catalog,
-                          GBool (*abortCheckCbk)(void *data),
-                          void *abortCheckCbkData)
-{
-    return gTrue;
-}*/
 void BitmapOutputDev::setDefaultCTM(double *ctm) 
 {
     boolpolydev->setDefaultCTM(ctm);
@@ -1320,11 +1354,47 @@ void BitmapOutputDev::stroke(GfxState *state)
     rgbdev->stroke(state);
     dbg_newdata("stroke");
 }
+
+extern gfxcolor_t getFillColor(GfxState * state);
+
+char area_is_plain_colored(GfxState*state, SplashBitmap*boolpoly, SplashBitmap*rgbbitmap, int x1, int y1, int x2, int y2)
+{
+    int width = boolpoly->getWidth();
+    int height = boolpoly->getHeight();
+    if(!fixBBox(&x1, &y1, &x2, &y2, width, height)) {
+       return 0;
+    }
+    gfxcolor_t color = getFillColor(state);
+    SplashColorPtr rgb = rgbbitmap->getDataPtr() 
+                      + (y1*width+x1)*sizeof(SplashColor);
+    int width8 = (width+7)/8;
+    unsigned char*bits = (unsigned char*)boolpoly->getDataPtr() 
+                        + (y1*width8+x1);
+    int x,y;
+    int w = x2-x1;
+    int h = y2-y1;
+    for(y=0;y<h;y++) {
+       for(x=0;x<w;x++) {
+           if(rgb[x*3+0] != color.r ||
+              rgb[x*3+1] != color.g ||
+              rgb[x*3+2] != color.b)
+               return 0;
+       }
+       rgb += width*sizeof(SplashColor);
+    }
+    return 1;
+}
+
 void BitmapOutputDev::fill(GfxState *state)
 {
     msg("<debug> fill");
     boolpolydev->fill(state);
     gfxbbox_t bbox = getBBox(state);
+    if(config_optimizeplaincolorfills) {
+       if(area_is_plain_colored(state, boolpolybitmap, rgbbitmap, bbox.xmin, bbox.ymin, bbox.xmax, bbox.ymax)) {
+           return;
+       }
+    }
     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
     rgbdev->fill(state);
     dbg_newdata("fill");
@@ -1338,33 +1408,24 @@ void BitmapOutputDev::eoFill(GfxState *state)
     rgbdev->eoFill(state);
     dbg_newdata("eofill");
 }
-#if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207
-void BitmapOutputDev::tilingPatternFill(GfxState *state, Object *str,
-                              int paintType, Dict *resDict,
-                              double *mat, double *bbox,
-                              int x0, int y0, int x1, int y1,
-                              double xStep, double yStep)
-{
-    msg("<debug> tilingPatternFill");
-    boolpolydev->tilingPatternFill(state, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep);
-    checkNewBitmap(UNKNOWN_BOUNDING_BOX);
-    rgbdev->tilingPatternFill(state, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep);
-    dbg_newdata("tilingpatternfill");
-}
-#else
-void BitmapOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Object *str,
+
+POPPLER_TILING_PATERN_RETURN BitmapOutputDev::tilingPatternFill(GfxState *state, POPPLER_TILING_PATERN_GFX Object *str,
                               int paintType, Dict *resDict,
                               double *mat, double *bbox,
                               int x0, int y0, int x1, int y1,
                               double xStep, double yStep) 
 {
     msg("<debug> tilingPatternFill");
-    boolpolydev->tilingPatternFill(state, gfx, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep);
+    boolpolydev->tilingPatternFill(state, POPPLER_TILING_PATERN_GFX_ARG str, paintType, resDict, mat,
+                                   bbox, x0, y0, x1, y1, xStep, yStep);
     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
-    rgbdev->tilingPatternFill(state, gfx, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep);
+    rgbdev->tilingPatternFill(state, POPPLER_TILING_PATERN_GFX_ARG str, paintType, resDict, mat,
+                              bbox, x0, y0, x1, y1, xStep, yStep);
     dbg_newdata("tilingpatternfill");
-}
+#ifdef HAVE_POPPLER
+    return gTrue;
 #endif
+}
 
 GBool BitmapOutputDev::functionShadedFill(GfxState *state, GfxFunctionShading *shading) 
 {
@@ -1373,19 +1434,21 @@ GBool BitmapOutputDev::functionShadedFill(GfxState *state, GfxFunctionShading *s
     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
     return rgbdev->functionShadedFill(state, shading);
 }
-GBool BitmapOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading)
+
+GBool BitmapOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading POPPLER_RAXIAL_MIN_MAX)
 {
     msg("<debug> axialShadedFill");
-    boolpolydev->axialShadedFill(state, shading);
+    boolpolydev->axialShadedFill(state, shading POPPLER_RAXIAL_MIN_MAX_ARG);
     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
-    return rgbdev->axialShadedFill(state, shading);
+    return rgbdev->axialShadedFill(state, shading POPPLER_RAXIAL_MIN_MAX_ARG);
 }
-GBool BitmapOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading)
+
+GBool BitmapOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading POPPLER_RAXIAL_MIN_MAX)
 {
     msg("<debug> radialShadedFill");
-    boolpolydev->radialShadedFill(state, shading);
+    boolpolydev->radialShadedFill(state, shading POPPLER_RAXIAL_MIN_MAX_ARG);
     checkNewBitmap(UNKNOWN_BOUNDING_BOX);
-    return rgbdev->radialShadedFill(state, shading);
+    return rgbdev->radialShadedFill(state, shading POPPLER_RAXIAL_MIN_MAX_ARG);
 }
 
 SplashColor black = {0,0,0};
@@ -1459,6 +1522,10 @@ void BitmapOutputDev::drawChar(GfxState *state, double x, double y,
         boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
         booltextdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
         clip1dev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
+    } else if(state->getRender()&RENDER_STROKE) {
+       // we're drawing as stroke
+       boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
+       rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
     } else if(rgbbitmap != rgbdev->getBitmap()) {
        // we're doing softmasking or transparency grouping
        boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen);
@@ -1639,72 +1706,87 @@ gfxbbox_t BitmapOutputDev::getImageBBox(GfxState*state)
     bbox.ymax=max(bbox.ymax,y);
     return bbox;
 }
+
+GBool invalid_size(int width, int height)
+{
+    if((U64)width*(U64)height > 0x7fffffffll)
+       return 1;
+    return 0;
+}
+
 void BitmapOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
-                          int width, int height, GBool invert,
+                          int width, int height, GBool invert, POPPLER_INTERPOLATE
                           GBool inlineImg)
 {
     msg("<debug> drawImageMask streamkind=%d", str->getKind());
+    if(invalid_size(width,height)) return;
 
     CopyStream*cpystr = new CopyStream(str, height * ((width + 7) / 8));
     str = cpystr->getStream();
     
-    boolpolydev->drawImageMask(state, ref, str, width, height, invert, inlineImg);
+    boolpolydev->drawImageMask(state, ref, str, width, height, invert, POPPLER_INTERPOLATE_ARG inlineImg);
     gfxbbox_t bbox = getImageBBox(state);
     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
-    rgbdev->drawImageMask(state, ref, str, width, height, invert, inlineImg);
+    rgbdev->drawImageMask(state, ref, str, width, height, invert, POPPLER_INTERPOLATE_ARG inlineImg);
     delete cpystr;
     dbg_newdata("imagemask");
 }
 void BitmapOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
                       int width, int height, GfxImageColorMap *colorMap,
+                      POPPLER_INTERPOLATE
                       int *maskColors, GBool inlineImg)
 {
     msg("<debug> drawImage streamkind=%d", str->getKind());
+    if(invalid_size(width,height)) return;
        
     CopyStream*cpystr = new CopyStream(str, height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8));
     str = cpystr->getStream();
 
-    boolpolydev->drawImage(state, ref, str, width, height, colorMap, maskColors, inlineImg);
+    boolpolydev->drawImage(state, ref, str, width, height, colorMap, POPPLER_INTERPOLATE_ARG maskColors, inlineImg);
     gfxbbox_t bbox=getImageBBox(state);
     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
-    rgbdev->drawImage(state, ref, str, width, height, colorMap, maskColors, inlineImg);
+    rgbdev->drawImage(state, ref, str, width, height, colorMap, POPPLER_INTERPOLATE_ARG maskColors, inlineImg);
     delete cpystr;
     dbg_newdata("image");
 }
 void BitmapOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
                             int width, int height,
                             GfxImageColorMap *colorMap,
+                            POPPLER_INTERPOLATE
                             Stream *maskStr, int maskWidth, int maskHeight,
-                            GBool maskInvert)
+                            GBool maskInvert POPPLER_MASK_INTERPOLATE)
 {
     msg("<debug> drawMaskedImage streamkind=%d", str->getKind());
+    if(invalid_size(width,height)) return;
     
     CopyStream*cpystr = new CopyStream(str, height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8));
     str = cpystr->getStream();
 
-    boolpolydev->drawMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert);
+    boolpolydev->drawMaskedImage(state, ref, str, width, height, colorMap, POPPLER_INTERPOLATE_ARG maskStr, maskWidth, maskHeight, maskInvert POPPLER_MASK_INTERPOLATE_ARG);
     gfxbbox_t bbox=getImageBBox(state);
     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
-    rgbdev->drawMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert);
+    rgbdev->drawMaskedImage(state, ref, str, width, height, colorMap, POPPLER_INTERPOLATE_ARG maskStr, maskWidth, maskHeight, maskInvert POPPLER_MASK_INTERPOLATE_ARG);
     delete cpystr;
     dbg_newdata("maskedimage");
 }
 void BitmapOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
                                 int width, int height,
                                 GfxImageColorMap *colorMap,
+                                POPPLER_INTERPOLATE
                                 Stream *maskStr,
                                 int maskWidth, int maskHeight,
-                                GfxImageColorMap *maskColorMap)
+                                GfxImageColorMap *maskColorMap POPPLER_MASK_INTERPOLATE)
 {
     msg("<debug> drawSoftMaskedImage %dx%d (%dx%d) streamkind=%d", width, height, maskWidth, maskHeight, str->getKind());
+    if(invalid_size(width,height)) return;
 
     CopyStream*cpystr = new CopyStream(str, height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8));
     str = cpystr->getStream();
 
-    boolpolydev->drawSoftMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap);
+    boolpolydev->drawSoftMaskedImage(state, ref, str, width, height, colorMap, POPPLER_INTERPOLATE_ARG maskStr, maskWidth, maskHeight, maskColorMap POPPLER_MASK_INTERPOLATE_ARG);
     gfxbbox_t bbox=getImageBBox(state);
     checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax));
-    rgbdev->drawSoftMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap);
+    rgbdev->drawSoftMaskedImage(state, ref, str, width, height, colorMap, POPPLER_INTERPOLATE_ARG maskStr, maskWidth, maskHeight, maskColorMap POPPLER_MASK_INTERPOLATE_ARG);
     delete cpystr;
     dbg_newdata("softmaskimage");
 }
@@ -1719,8 +1801,19 @@ void BitmapOutputDev::drawForm(Ref id)
 void BitmapOutputDev::processLink(Link *link, Catalog *catalog)
 {
     msg("<debug> processLink");
+    flushEverything();
     gfxdev->processLink(link, catalog);
 }
+void BitmapOutputDev::flushEverything()
+{
+    if(layerstate == STATE_BITMAP_IS_ABOVE) {
+       this->flushText();
+       this->flushBitmap();
+    } else {
+       this->flushBitmap();
+       this->flushText();
+    }
+}
 
 void BitmapOutputDev::beginTransparencyGroup(GfxState *state, double *bbox,
                                    GfxColorSpace *blendingColorSpace,