X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fpdf%2FBitmapOutputDev.cc;h=2851f09642f43c71e61f36462c874d377b26dcea;hb=5150420d30de70031c50b95e52bec8c5fe74651d;hp=ff6d50e1a72ec98456b71c073a68a7d01a3ceaea;hpb=d9edc98b73bbea0612f27d008866608d8baaeed1;p=swftools.git diff --git a/lib/pdf/BitmapOutputDev.cc b/lib/pdf/BitmapOutputDev.cc index ff6d50e..2851f09 100644 --- a/lib/pdf/BitmapOutputDev.cc +++ b/lib/pdf/BitmapOutputDev.cc @@ -29,6 +29,7 @@ #include "../log.h" #include "../png.h" #include "../devices/record.h" +#include "../types.h" #define UNKNOWN_BOUNDING_BOX 0,0,0,0 @@ -269,6 +270,8 @@ void BitmapOutputDev::flushBitmap() m.ty = ymin; m.m00 = m.m11 = 1; m.m10 = m.m01 = 0; + m.tx -= 0.5; + m.ty -= 0.5; gfxline_t* line = gfxline_makerectangle(xmin, ymin, xmax, ymax); dev->fillbitmap(dev, line, img, &m, 0); @@ -537,11 +540,43 @@ 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; } } @@ -578,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; } } @@ -1086,18 +1155,61 @@ 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(UNKNOWN_BOUNDING_BOX); + 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); - if(checkNewBitmap(UNKNOWN_BOUNDING_BOX)) { + gfxbbox_t bbox = getBBox(state); + if(checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax))) { boolpolydev->fill(state); } rgbdev->fill(state); @@ -1106,7 +1218,8 @@ void BitmapOutputDev::eoFill(GfxState *state) { msg(" eoFill"); boolpolydev->eoFill(state); - if(checkNewBitmap(UNKNOWN_BOUNDING_BOX)) { + gfxbbox_t bbox = getBBox(state); + if(checkNewBitmap(bbox.xmin, bbox.ymin, ceil(bbox.xmax), ceil(bbox.ymax))) { boolpolydev->eoFill(state); } rgbdev->eoFill(state); @@ -1195,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(UNKNOWN_BOUNDING_BOX); - gfxdev->endStringOp(state); -} void BitmapOutputDev::beginString(GfxState *state, GString *s) { msg(" beginString"); @@ -1212,15 +1316,6 @@ 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(UNKNOWN_BOUNDING_BOX); - gfxdev->endString(state); -} void BitmapOutputDev::clearClips() { @@ -1243,13 +1338,18 @@ void BitmapOutputDev::drawChar(GfxState *state, double x, double y, 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); - - /* FIXME: do we need these calls? */ 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); @@ -1257,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 @@ -1276,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(UNKNOWN_BOUNDING_BOX); + 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(); @@ -1310,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(UNKNOWN_BOUNDING_BOX); + /* 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() */ @@ -1371,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) @@ -1382,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(UNKNOWN_BOUNDING_BOX); + 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; @@ -1398,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(UNKNOWN_BOUNDING_BOX); + 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; @@ -1411,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(UNKNOWN_BOUNDING_BOX); + 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, @@ -1423,7 +1577,8 @@ 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(UNKNOWN_BOUNDING_BOX); + 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)