X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fpdf%2FBitmapOutputDev.cc;h=2851f09642f43c71e61f36462c874d377b26dcea;hb=5150420d30de70031c50b95e52bec8c5fe74651d;hp=c27f87f4933f2dbb15c7a0978d8119e075fff25b;hpb=1f80a93dce1414db2d9b237b6af51527bd3d14bf;p=swftools.git diff --git a/lib/pdf/BitmapOutputDev.cc b/lib/pdf/BitmapOutputDev.cc index c27f87f..2851f09 100644 --- a/lib/pdf/BitmapOutputDev.cc +++ b/lib/pdf/BitmapOutputDev.cc @@ -29,6 +29,9 @@ #include "../log.h" #include "../png.h" #include "../devices/record.h" +#include "../types.h" + +#define UNKNOWN_BOUNDING_BOX 0,0,0,0 static SplashColor splash_white = {255,255,255}; static SplashColor splash_black = {0,0,0}; @@ -194,6 +197,7 @@ void BitmapOutputDev::flushBitmap() SplashColorPtr rgb = rgbbitmap->getDataPtr(); Guchar*alpha = rgbbitmap->getAlphaPtr(); + Guchar*alpha2 = boolpolybitmap->getAlphaPtr(); int xmin,ymin,xmax,ymax; getBitmapBBox(alpha, width, height, &xmin,&ymin,&xmax,&ymax); @@ -216,7 +220,7 @@ void BitmapOutputDev::flushBitmap() //xmin = ymin = 0; //xmax = width; //ymax = height; - + int rangex = xmax-xmin; int rangey = ymax-ymin; gfximage_t*img = (gfximage_t*)malloc(sizeof(gfximage_t)); @@ -228,6 +232,7 @@ void BitmapOutputDev::flushBitmap() SplashColorPtr in=&rgb[((y+ymin)*width+xmin)*sizeof(SplashColor)]; gfxcolor_t*out = &img->data[y*rangex]; Guchar*ain = &alpha[(y+ymin)*width+xmin]; + Guchar*ain2 = &alpha2[(y+ymin)*width+xmin]; if(this->emptypage) { for(x=0;xfillbitmap(dev, line, img, &m, 0); @@ -281,6 +293,31 @@ void BitmapOutputDev::flushText() this->emptypage = 0; } +void writeBitmap(SplashBitmap*bitmap, char*filename) +{ + int y,x; + + int width = bitmap->getWidth(); + int height = bitmap->getHeight(); + + gfxcolor_t*data = (gfxcolor_t*)malloc(sizeof(gfxcolor_t)*width*height); + + for(y=0;ygetPixel(x,y,c); + int a = bitmap->getAlpha(x,y); + line[x].r = c[0]; + line[x].g = c[1]; + line[x].b = c[2]; + line[x].a = a; + } + } + writePNG(filename, (unsigned char*)data, width, height); + free(data); +} + void writeAlpha(SplashBitmap*bitmap, char*filename) { int y,x; @@ -307,7 +344,39 @@ static int dbg_btm_counter=1; static const char*STATE_NAME[] = {"parallel", "textabovebitmap", "bitmapabovetext"}; -void BitmapOutputDev::checkNewText(int x1, int y1, int x2, int y2) +int checkAlphaSanity(SplashBitmap*boolbtm, SplashBitmap*alphabtm) +{ + assert(boolbtm->getWidth() == alphabtm->getWidth()); + assert(boolbtm->getHeight() == alphabtm->getHeight()); + if(boolbtm->getMode()==splashModeMono1) { + return 1; + } + + int width = boolbtm->getWidth(); + int height = boolbtm->getHeight(); + + int bad=0; + int x,y; + for(y=0;ygetAlpha(x,y); + int a2 = boolbtm->getAlpha(x,y); + if(a1!=a2) { + bad++; + } + } + } + double badness = bad/(double)(width*height); + if(badness>0.2) { + msg(" Bitmaps don't correspond: %d out of %d pixels wrong (%.2f%%)", bad, width*height, + badness*100.0); + return 0; + } + msg(" %f", badness); + return 1; +} + +GBool BitmapOutputDev::checkNewText(int x1, int y1, int x2, int y2) { /* called once some new text was drawn on booltextdev, and before the same thing is drawn on gfxdev */ @@ -316,14 +385,19 @@ void BitmapOutputDev::checkNewText(int x1, int y1, int x2, int y2) char filename1[80]; char filename2[80]; - sprintf(filename1, "state%dbitmap_afternewtext.png", dbg_btm_counter); - sprintf(filename2, "state%dtext_afternewtext.png", dbg_btm_counter); + char filename3[80]; + sprintf(filename1, "state%dboolbitmap_afternewtext.png", dbg_btm_counter); + sprintf(filename2, "state%dbooltext_afternewtext.png", dbg_btm_counter); + sprintf(filename3, "state%dbitmap_afternewtext.png", dbg_btm_counter); if(0) { + msg(" %s %s %s", filename1, filename2, filename3); writeAlpha(boolpolybitmap, filename1); writeAlpha(booltextbitmap, filename2); + writeBitmap(rgbdev->getBitmap(), filename3); } dbg_btm_counter++; + GBool ret = false; if(intersection(x1,y1,x2,y2)) { if(layerstate==STATE_PARALLEL) { /* the new text is above the bitmap. So record that fact, @@ -331,7 +405,7 @@ void BitmapOutputDev::checkNewText(int x1, int y1, int x2, int y2) new intersections */ msg(" Text is above current bitmap/polygon data"); layerstate=STATE_TEXT_IS_ABOVE; - clearBoolPolyDev(); + clearBoolPolyDev(x1,y1,x2,y2); } else if(layerstate==STATE_BITMAP_IS_ABOVE) { /* there's a bitmap above the (old) text. So we need to flush out that text, and record that the *new* @@ -343,8 +417,12 @@ void BitmapOutputDev::checkNewText(int x1, int y1, int x2, int y2) /* clear both bool devices- the text device because we just dumped out all the (old) text, and the poly dev so we can check for new intersections */ - clearBoolPolyDev(); - clearBoolTextDev(); + clearBoolPolyDev(x1,y1,x2,y2); + /* FIXME this destroys the text pixels we just + drew to test for the intersection- however we need + those to check for the *new* intersections */ + clearBoolTextDev(x1,y1,x2,y2); + ret = true; } else { /* we already know that the current text section is above the current bitmap section- now just new @@ -353,42 +431,54 @@ void BitmapOutputDev::checkNewText(int x1, int y1, int x2, int y2) the polygon bitmap again, so we can check for new intersections */ msg(" Text is still above current bitmap/polygon data"); - clearBoolPolyDev(); + clearBoolPolyDev(x1,y1,x2,y2); } } + return ret; } -void BitmapOutputDev::checkNewBitmap() +GBool BitmapOutputDev::checkNewBitmap(int x1, int y1, int x2, int y2) { /* similar to checkNewText() above, only in reverse */ msg(" Testing new graphics data against current text data, state=%s, counter=%d\n", STATE_NAME[layerstate], dbg_btm_counter); char filename1[80]; char filename2[80]; - sprintf(filename1, "state%dbitmap_afternewgfx.png", dbg_btm_counter); - sprintf(filename2, "state%dtext_afternewgfx.png", dbg_btm_counter); + char filename3[80]; + sprintf(filename1, "state%dboolbitmap_afternewgfx.png", dbg_btm_counter); + sprintf(filename2, "state%dbooltext_afternewgfx.png", dbg_btm_counter); + sprintf(filename3, "state%dbitmap_afternewgfx.png", dbg_btm_counter); + if(0) { + msg(" %s %s %s", filename1, filename2, filename3); writeAlpha(boolpolybitmap, filename1); writeAlpha(booltextbitmap, filename2); + writeBitmap(rgbdev->getBitmap(), filename3); } dbg_btm_counter++; - if(intersection(0,0,0,0)) { + GBool ret = false; + if(intersection(x1,y1,x2,y2)) { if(layerstate==STATE_PARALLEL) { msg(" Bitmap is above current text data"); layerstate=STATE_BITMAP_IS_ABOVE; - clearBoolTextDev(); + clearBoolTextDev(x1,y1,x2,y2); } else if(layerstate==STATE_TEXT_IS_ABOVE) { msg(" Bitmap is above current text data (which is above some bitmap)"); flushBitmap(); layerstate=STATE_BITMAP_IS_ABOVE; - clearBoolTextDev(); - clearBoolPolyDev(); + clearBoolTextDev(x1,y1,x2,y2); + /* FIXME this destroys the polygon pixels we just + drew to test for the intersection- however we need + those to check for the *new* intersections */ + clearBoolPolyDev(x1,y1,x2,y2); + ret = true; } else { msg(" Bitmap is still above current text data"); - clearBoolTextDev(); + clearBoolTextDev(x1,y1,x2,y2); } } + return ret; } //void checkNewText() { @@ -450,16 +540,53 @@ GBool BitmapOutputDev::clip0and1differ(int x1,int y1,int x2,int y2) } return gFalse; } else { + if(x1<0) x1=0; + if(x2<0) x2=0; + if(y1<0) y1=0; + if(y2<0) y2=0; + if(x1>clip0bitmap->getWidth()) x1=clip0bitmap->getWidth(); + if(y1>clip0bitmap->getHeight()) y1=clip0bitmap->getHeight(); + if(x2>clip0bitmap->getWidth()) x2=clip0bitmap->getWidth(); + if(y2>clip0bitmap->getHeight()) y2=clip0bitmap->getHeight(); + if(x1>x2) x1=x2; + if(y1>x2) y1=y2; + SplashBitmap*clip0 = clip0bitmap; SplashBitmap*clip1 = clip1bitmap; int width = clip0->getAlphaRowSize(); int height = clip0->getHeight(); - return memcmp(clip0->getAlphaPtr(), clip1->getAlphaPtr(), width*height); + Guchar*a0 = clip0->getAlphaPtr(); + Guchar*a1 = clip1->getAlphaPtr(); + int x,y; + char differs=0; + for(y=y1;y Strange internal error (2)"); + else if(!differs && differs2) { + msg(" Bad Bounding Box: Difference in clip0 and clip1 outside bbox"); + msg(" %d %d %d %d", x1, y1, x2, y2); + } + return differs2; } } -static void clearBooleanBitmap(SplashBitmap*btm) +static void clearBooleanBitmap(SplashBitmap*btm, int x1, int y1, int x2, int y2) { + if(!(x1|y1|x2|y2)) { + x1 = y1 = 0; + x2 = btm->getWidth(); + y2 = btm->getHeight(); + } if(btm->getMode()==splashModeMono1) { int width8 = (btm->getWidth()+7)/8; int width = btm->getWidth(); @@ -486,70 +613,104 @@ GBool BitmapOutputDev::intersection(int x1, int y1, int x2, int y2) { SplashBitmap*boolpoly = boolpolybitmap; SplashBitmap*booltext = booltextbitmap; - + if(boolpoly->getMode()==splashModeMono1) { /* alternative implementation, using one bit per pixel- - would work if xpdf wouldn't try to dither everything */ + needs the no-dither patch in xpdf */ + + if(x1>=width) return gFalse; + if(x2<=0) return gFalse; + if(y1>=height)return gFalse; + if(y2<=0) return gFalse; + if(x1>=x2) return gFalse; + if(y1>=y2) return gFalse; Guchar*polypixels = boolpoly->getDataPtr(); Guchar*textpixels = booltext->getDataPtr(); - int width8 = (width+7)/8; + int width = boolpoly->getWidth(); int height = boolpoly->getHeight(); + int width8 = (width+7)/8; + int runx = width8; + int runy = height; if(x1|y1|x2|y2) { - if(y1>=0 && y1<=y2 && y2<=height) { - polypixels+=y1*width8; - textpixels+=y1*width8; - height=y2-y1; - } + polypixels+=y1*width8+x1/8; + textpixels+=y1*width8+x1/8; + runx=(x2+7)/8 - x1/8; + runy=y2-y1; } int t; - int len = height*width8; - unsigned long long int c=0; - assert(sizeof(unsigned long long int)==8); - { - if(((int)polypixels&7) || ((int)textpixels&7)) { - //msg(" Non-optimal alignment"); + unsigned char c=0; + + /*assert(sizeof(unsigned long long int)==8); + if(((ptroff_t)polypixels&7) || ((ptroff_t)textpixels&7)) { + //msg(" Non-optimal alignment"); + }*/ + + int x,y; + for(y=0;ywidth) x1=width; + if(y1>height) y1=height; + if(x2>width) x2=width; + if(y2>height) y2=height; + if(x1>x2) x1=x2; + if(y1>y2) y1=y2; Guchar*polypixels = boolpoly->getAlphaPtr(); Guchar*textpixels = booltext->getAlphaPtr(); int width = boolpoly->getAlphaRowSize(); int height = boolpoly->getHeight(); - - int t; - int len = height*width; - unsigned int c=0; - if(len & (sizeof(unsigned int)-1)) { - Guchar c2=0; - for(t=0;tx?ax2:x; + ay2 = ay2>y?ay2:y; + } + } + } + } + if(overlap1 && !overlap2) + msg(" strange internal error"); + if(!overlap1 && overlap2) { + msg(" Bad bounding box: intersection outside bbox"); + msg(" given bbox: %d %d %d %d", x1, y1, x2, y2); + msg(" changed area: %d %d %d %d", ax1, ay1, ax2, ay2); + writeAlpha(booltextbitmap, "alpha.png"); + } + return overlap2; } } @@ -592,8 +753,8 @@ void BitmapOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, do /* just in case any device did draw a white background rectangle into the device */ - clearBoolTextDev(); - clearBoolPolyDev(); + clearBoolTextDev(UNKNOWN_BOUNDING_BOX); + clearBoolPolyDev(UNKNOWN_BOUNDING_BOX); this->layerstate = STATE_PARALLEL; this->emptypage = 1; @@ -911,6 +1072,7 @@ void BitmapOutputDev::updateTransfer(GfxState *state) clip1dev->updateTransfer(state); gfxdev->updateTransfer(state); } + void BitmapOutputDev::updateFont(GfxState *state) { boolpolydev->updateFont(state); @@ -993,25 +1155,73 @@ void BitmapOutputDev::updateTextShift(GfxState *state, double shift) gfxdev->updateTextShift(state, shift); } +double max(double x, double y) +{ + return x>y?x:y; +} +double min(double x, double y) +{ + return xgetPath(); + int num = path->getNumSubpaths(); + gfxbbox_t bbox = {0,0,1,1}; + char valid=0; + int t; + for(t = 0; t < num; t++) { + GfxSubpath *subpath = path->getSubpath(t); + int subnum = subpath->getNumPoints(); + int s; + for(s=0;stransform(subpath->getX(s),subpath->getY(s),&x,&y); + if(!valid) { + bbox.xmin = x; bbox.ymin = y; + bbox.xmax = x; bbox.ymax = y; + valid = 1; + } else { + bbox.xmin = min(bbox.xmin, x); + bbox.ymin = min(bbox.ymin, y); + bbox.xmax = max(bbox.xmax, x); + bbox.ymax = max(bbox.ymax, y); + } + } + } + return bbox; +} + void BitmapOutputDev::stroke(GfxState *state) { msg(" stroke"); boolpolydev->stroke(state); - checkNewBitmap(); + gfxbbox_t bbox = getBBox(state); + double width = state->getTransformedLineWidth(); + bbox.xmin -= width; bbox.ymin -= width; + bbox.xmax += width; bbox.ymax += width; + checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax)); rgbdev->stroke(state); } void BitmapOutputDev::fill(GfxState *state) { msg(" fill"); boolpolydev->fill(state); - checkNewBitmap(); + gfxbbox_t bbox = getBBox(state); + if(checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax))) { + boolpolydev->fill(state); + } rgbdev->fill(state); } void BitmapOutputDev::eoFill(GfxState *state) { msg(" eoFill"); boolpolydev->eoFill(state); - checkNewBitmap(); + gfxbbox_t bbox = getBBox(state); + if(checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax))) { + boolpolydev->eoFill(state); + } rgbdev->eoFill(state); } #if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207 @@ -1023,7 +1233,7 @@ void BitmapOutputDev::tilingPatternFill(GfxState *state, Object *str, { msg(" tilingPatternFill"); boolpolydev->tilingPatternFill(state, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep); - checkNewBitmap(); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); rgbdev->tilingPatternFill(state, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep); } #else @@ -1035,7 +1245,7 @@ void BitmapOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Object *str, { msg(" tilingPatternFill"); boolpolydev->tilingPatternFill(state, gfx, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep); - checkNewBitmap(); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); rgbdev->tilingPatternFill(state, gfx, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep); } #endif @@ -1044,21 +1254,21 @@ GBool BitmapOutputDev::functionShadedFill(GfxState *state, GfxFunctionShading *s { msg(" functionShadedFill"); boolpolydev->functionShadedFill(state, shading); - checkNewBitmap(); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); return rgbdev->functionShadedFill(state, shading); } GBool BitmapOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading) { msg(" axialShadedFill"); boolpolydev->axialShadedFill(state, shading); - checkNewBitmap(); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); return rgbdev->axialShadedFill(state, shading); } GBool BitmapOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading) { msg(" radialShadedFill"); boolpolydev->radialShadedFill(state, shading); - checkNewBitmap(); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); return rgbdev->radialShadedFill(state, shading); } @@ -1098,15 +1308,6 @@ void BitmapOutputDev::beginStringOp(GfxState *state) booltextdev->beginStringOp(state); gfxdev->beginStringOp(state); } -void BitmapOutputDev::endStringOp(GfxState *state) -{ - msg(" endStringOp"); - clip0dev->endStringOp(state); - clip1dev->endStringOp(state); - booltextdev->endStringOp(state); - checkNewText(0,0,0,0); - gfxdev->endStringOp(state); -} void BitmapOutputDev::beginString(GfxState *state, GString *s) { msg(" beginString"); @@ -1115,38 +1316,40 @@ void BitmapOutputDev::beginString(GfxState *state, GString *s) booltextdev->beginString(state, s); gfxdev->beginString(state, s); } -void BitmapOutputDev::endString(GfxState *state) -{ - msg(" endString"); - clip0dev->endString(state); - clip1dev->endString(state); - booltextdev->endString(state); - checkNewText(0,0,0,0); - gfxdev->endString(state); -} void BitmapOutputDev::clearClips() { - clearBooleanBitmap(clip0bitmap); - clearBooleanBitmap(clip1bitmap); + clearBooleanBitmap(clip0bitmap, 0, 0, 0, 0); + clearBooleanBitmap(clip1bitmap, 0, 0, 0, 0); } -void BitmapOutputDev::clearBoolPolyDev() +void BitmapOutputDev::clearBoolPolyDev(int x1, int y1, int x2, int y2) { - clearBooleanBitmap(boolpolybitmap); + clearBooleanBitmap(boolpolybitmap, x1, y1, x2, y2); } -void BitmapOutputDev::clearBoolTextDev() +void BitmapOutputDev::clearBoolTextDev(int x1, int y1, int x2, int y2) { - clearBooleanBitmap(booltextbitmap); + clearBooleanBitmap(booltextbitmap, x1, y1, x2, y2); } void BitmapOutputDev::drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, CharCode code, int nBytes, Unicode *u, int uLen) { - msg(" drawChar"); + msg(" drawChar render=%d", state->getRender()); + if(state->getRender()&RENDER_CLIP) { + //char is just a clipping boundary + rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen); + 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(rgbbitmap != rgbdev->getBitmap()) { + // we're doing softmasking or transparency grouping + boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen); + //checkNewBitmap(UNKNOWN_BOUNDING_BOX); rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen); } else { + // we're drawing a regular char clearClips(); clip0dev->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); @@ -1154,17 +1357,24 @@ void BitmapOutputDev::drawChar(GfxState *state, double x, double y, /* calculate the bbox of this character */ int x1 = (int)x, x2 = (int)x+1, y1 = (int)y, y2 = (int)y+1; SplashPath*path = clip0dev->getCurrentFont()->getGlyphPath(code); + if(!path) { + if(code) + msg(" couldn't create outline for char %d", code); + return; + } + x-=originX; + y-=originY; + path->offset((SplashCoord)x, (SplashCoord)y); int t; for(t=0;tgetLength();t++) { double xx,yy; Guchar f; path->getPoint(t,&xx,&yy,&f); - xx+=x; - yy+=y; + state->transform(xx,yy,&xx,&yy); if(xxx2) x2=(int)xx+1; - if(yy>y2) y2=(int)yy+1; + if(xx>=x2) x2=(int)xx+1; + if(yy>=y2) y2=(int)yy+1; } /* if this character is affected somehow by the various clippings (i.e., it looks @@ -1173,7 +1383,7 @@ void BitmapOutputDev::drawChar(GfxState *state, double x, double y, if(clip0and1differ(x1,y1,x2,y2)) { msg(" Char %d is affected by clipping", code); boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen); - checkNewBitmap(); + checkNewBitmap(x1,y1,x2,y2); rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen); if(config_extrafontdata) { int oldrender = state->getRender(); @@ -1207,10 +1417,30 @@ void BitmapOutputDev::endTextObject(GfxState *state) clip0dev->endTextObject(state); clip1dev->endTextObject(state); booltextdev->endTextObject(state); - /* TODO: do this only if rendermode!=0 */ - checkNewText(0,0,0,0); + /* the only thing "drawn" here is clipping */ + //checkNewText(UNKNOWN_BOUNDING_BOX); gfxdev->endTextObject(state); } +void BitmapOutputDev::endString(GfxState *state) +{ + msg(" endString"); + clip0dev->endString(state); + clip1dev->endString(state); + booltextdev->endString(state); + int render = state->getRender(); + if(render != RENDER_INVISIBLE && render != RENDER_FILL) { + checkNewText(UNKNOWN_BOUNDING_BOX); + } + gfxdev->endString(state); +} +void BitmapOutputDev::endStringOp(GfxState *state) +{ + msg(" endStringOp"); + clip0dev->endStringOp(state); + clip1dev->endStringOp(state); + booltextdev->endStringOp(state); + gfxdev->endStringOp(state); +} /* TODO: these four operations below *should* do nothing, as type3 chars are drawn using operations like fill() */ @@ -1268,6 +1498,30 @@ class CopyStream: public Object Stream* getStream() {return this->memstream;}; }; +gfxbbox_t BitmapOutputDev::getImageBBox(GfxState*state) +{ + gfxbbox_t bbox; + double x,y; + state->transform(0, 1, &x, &y); + bbox.xmin=bbox.xmax = x; + bbox.ymin=bbox.ymax = x; + state->transform(0, 0, &x, &y); + bbox.xmin=min(bbox.xmin,x); + bbox.ymin=min(bbox.ymin,y); + bbox.xmax=max(bbox.xmin,x); + bbox.ymax=max(bbox.ymin,y); + state->transform(1, 0, &x, &y); + bbox.xmin=min(bbox.xmin,x); + bbox.ymin=min(bbox.ymin,y); + bbox.xmax=max(bbox.xmin,x); + bbox.ymax=max(bbox.ymin,y); + state->transform(1, 1, &x, &y); + bbox.xmin=min(bbox.xmin,x); + bbox.ymin=min(bbox.ymin,y); + bbox.xmax=max(bbox.xmin,x); + bbox.ymax=max(bbox.ymin,y); + return bbox; +} void BitmapOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) @@ -1279,7 +1533,8 @@ void BitmapOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, str = cpystr->getStream(); } boolpolydev->drawImageMask(state, ref, str, width, height, invert, inlineImg); - checkNewBitmap(); + 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); if(cpystr) delete cpystr; @@ -1295,7 +1550,8 @@ void BitmapOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, str = cpystr->getStream(); } boolpolydev->drawImage(state, ref, str, width, height, colorMap, maskColors, inlineImg); - checkNewBitmap(); + 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); if(cpystr) delete cpystr; @@ -1308,7 +1564,8 @@ void BitmapOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, { msg(" drawMaskedImage streamkind=%d", str->getKind()); boolpolydev->drawMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert); - checkNewBitmap(); + 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); } void BitmapOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, @@ -1320,14 +1577,15 @@ void BitmapOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream * { msg(" drawSoftMaskedImage %dx%d (%dx%d) streamkind=%d", width, height, maskWidth, maskHeight, str->getKind()); boolpolydev->drawSoftMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap); - checkNewBitmap(); + 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); } void BitmapOutputDev::drawForm(Ref id) { msg(" drawForm"); boolpolydev->drawForm(id); - checkNewBitmap(); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); rgbdev->drawForm(id); } @@ -1375,7 +1633,7 @@ void BitmapOutputDev::endTransparencyGroup(GfxState *state) GfxState*state2 = state->copy(gTrue); #endif boolpolydev->endTransparencyGroup(state1); - checkNewBitmap(); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); rgbdev->endTransparencyGroup(state2); delete state1; delete state2; @@ -1385,7 +1643,7 @@ void BitmapOutputDev::paintTransparencyGroup(GfxState *state, double *bbox) { msg(" paintTransparencyGroup"); boolpolydev->paintTransparencyGroup(state,bbox); - checkNewBitmap(); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); rgbdev->paintTransparencyGroup(state,bbox); clip1dev->paintTransparencyGroup(state,bbox); } @@ -1393,7 +1651,7 @@ void BitmapOutputDev::setSoftMask(GfxState *state, double *bbox, GBool alpha, Fu { msg(" setSoftMask"); boolpolydev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor); - checkNewBitmap(); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); rgbdev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor); clip1dev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor); } @@ -1401,7 +1659,7 @@ void BitmapOutputDev::clearSoftMask(GfxState *state) { msg(" clearSoftMask"); boolpolydev->clearSoftMask(state); - checkNewBitmap(); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); rgbdev->clearSoftMask(state); clip1dev->clearSoftMask(state); }