X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fpdf%2FBitmapOutputDev.cc;h=4b2a33432f8d667cc03de63c91f866ac9188a142;hb=7ff0a634c656a09f58162ddc57795e30400cdde9;hp=fc0a158a37215407cf1d7aad4b46a4c1a8d0239f;hpb=cbcb36e38ef35e0a1b950fa8cfa3d90e5aeaa19b;p=swftools.git diff --git a/lib/pdf/BitmapOutputDev.cc b/lib/pdf/BitmapOutputDev.cc index fc0a158..4b2a334 100644 --- a/lib/pdf/BitmapOutputDev.cc +++ b/lib/pdf/BitmapOutputDev.cc @@ -19,51 +19,144 @@ #include #include #include +#include +#include "config.h" #include "BitmapOutputDev.h" #include "GFXOutputDev.h" #include "SplashBitmap.h" +#include "SplashPattern.h" +#include "Splash.h" #include "../log.h" +#include "../png.h" +#include "../devices/record.h" + +#define UNKNOWN_BOUNDING_BOX 0,0,0,0 static SplashColor splash_white = {255,255,255}; -static SplashColor splash_black = {255,255,255}; +static SplashColor splash_black = {0,0,0}; + +ClipState::ClipState() +{ + this->next = 0; + this->clipbitmap = 0; + this->written = 0; +} BitmapOutputDev::BitmapOutputDev(InfoOutputDev*info, PDFDoc*doc) { this->info = info; this->doc = doc; this->xref = doc->getXRef(); + + /* color graphic output device, for creating bitmaps */ this->rgbdev = new SplashOutputDev(splashModeRGB8, 1, gFalse, splash_white, gTrue, gTrue); - this->alphadev = new SplashOutputDev(splashModeMono1, 1, gFalse, splash_black, gTrue, gTrue); + + /* color mode for binary bitmaps */ + SplashColorMode colorMode = splashModeMono8; + + /* two devices for testing things against clipping: one clips, the other doesn't */ + this->clip0dev = new SplashOutputDev(colorMode, 1, gFalse, splash_black, gTrue, gFalse); + this->clip1dev = new SplashOutputDev(colorMode, 1, gFalse, splash_black, gTrue, gFalse); + + /* device indicating where polygonal pixels were drawn */ + this->boolpolydev = new SplashOutputDev(colorMode, 1, gFalse, splash_black, gTrue, gFalse); + /* device indicating where text pixels were drawn */ + this->booltextdev = new SplashOutputDev(colorMode, 1, gFalse, splash_black, gTrue, gFalse); + + /* device for handling texts and links */ this->gfxdev = new GFXOutputDev(info, this->doc); + this->rgbdev->startDoc(this->xref); - this->alphadev->startDoc(this->xref); - memset(rgbdev->getBitmap()->getAlphaPtr(), 0, rgbdev->getBitmap()->getWidth()*rgbdev->getBitmap()->getHeight()); + this->boolpolydev->startDoc(this->xref); + this->booltextdev->startDoc(this->xref); + this->clip0dev->startDoc(this->xref); + this->clip1dev->startDoc(this->xref); - this->config_bitmapfonts = 0; + this->gfxoutput = (gfxdevice_t*)malloc(sizeof(gfxdevice_t)); + gfxdevice_record_init(this->gfxoutput); + + this->gfxdev->setDevice(this->gfxoutput); + + this->config_extrafontdata = 0; + this->bboxpath = 0; + //this->clipdev = 0; + //this->clipstates = 0; } BitmapOutputDev::~BitmapOutputDev() { + if(this->gfxoutput) { + gfxresult_t*r = this->gfxoutput->finish(this->gfxoutput); + r->destroy(r); + free(this->gfxoutput);this->gfxoutput = 0; + } + if(this->bboxpath) { + delete this->bboxpath;this->bboxpath = 0; + } + if(this->rgbdev) { + delete this->rgbdev;this->rgbdev = 0; + } + if(this->gfxdev) { + delete this->gfxdev;this->gfxdev= 0; + } + if(this->boolpolydev) { + delete this->boolpolydev;this->boolpolydev = 0; + } + if(this->booltextdev) { + delete this->booltextdev;this->booltextdev = 0; + } + if(this->clip0dev) { + delete this->clip0dev;this->clip0dev = 0; + } + if(this->clip1dev) { + delete this->clip1dev;this->clip1dev = 0; + } + //if(this->clipbitmap) { + // delete this->clipbitmap;this->clipbitmap = 0; + //} + //if(this->clipdev) { + // delete this->clipdev;this->clipdev = 0; + //} + } +GBool BitmapOutputDev::getVectorAntialias() +{ + return this->rgbdev->getVectorAntialias(); +} +void BitmapOutputDev::setVectorAntialias(GBool vaa) +{ + this->rgbdev->setVectorAntialias(vaa); +} void BitmapOutputDev::setDevice(gfxdevice_t*dev) { this->dev = dev; - this->gfxdev->setDevice(dev); } void BitmapOutputDev::setMove(int x,int y) { + this->gfxdev->setMove(x,y); + this->user_movex = x; + this->user_movey = y; } void BitmapOutputDev::setClip(int x1,int y1,int x2,int y2) { + this->gfxdev->setClip(x1,y1,x2,y2); + this->user_clipx1 = x1; + this->user_clipy1 = y1; + this->user_clipx2 = x2; + this->user_clipy2 = y2; } void BitmapOutputDev::setParameter(const char*key, const char*value) { + if(!strcmp(key, "extrafontdata")) { + this->config_extrafontdata = atoi(value); + } + this->gfxdev->setParameter(key, value); } void BitmapOutputDev::preparePage(int pdfpage, int outputpage) { } -void getBitmapBBox(Guchar*alpha, int width, int height, int*xmin, int*ymin, int*xmax, int*ymax) +static void getBitmapBBox(Guchar*alpha, int width, int height, int*xmin, int*ymin, int*xmax, int*ymax) { *ymin = -1; *xmin = width; @@ -96,17 +189,25 @@ void getBitmapBBox(Guchar*alpha, int width, int height, int*xmin, int*ymin, int* } } -void BitmapOutputDev::flush() +void BitmapOutputDev::flushBitmap() { int width = rgbdev->getBitmapWidth(); int height = rgbdev->getBitmapHeight(); - SplashColorPtr rgb = rgbdev->getBitmap()->getDataPtr(); - Guchar*alpha = rgbdev->getBitmap()->getAlphaPtr(); + + 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); - msg(" Flushing graphics (bbox: %d,%d,%d,%d)", xmin,ymin,xmax,ymax); + /* 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(" Flushing bitmap (bbox: %d,%d,%d,%d)", xmin,ymin,xmax,ymax); if((xmax-xmin)<=0 || (ymax-ymin)<=0) // no bitmap, nothing to do return; @@ -118,7 +219,7 @@ void BitmapOutputDev::flush() //xmin = ymin = 0; //xmax = width; //ymax = height; - + int rangex = xmax-xmin; int rangey = ymax-ymin; gfximage_t*img = (gfximage_t*)malloc(sizeof(gfximage_t)); @@ -129,95 +230,560 @@ void BitmapOutputDev::flush() for(y=0;ydata[y*rangex]; - Guchar*ain = &alpha[(y+ymin)*width+xmax]; - for(x=0;xemptypage) { + for(x=0;xfillbitmap(dev, line, img, &m, 0); gfxline_free(line); - memset(rgbdev->getBitmap()->getAlphaPtr(), 0, rgbdev->getBitmap()->getWidth()*rgbdev->getBitmap()->getHeight()); - memset(rgbdev->getBitmap()->getDataPtr(), 0, rgbdev->getBitmap()->getWidth()*rgbdev->getBitmap()->getHeight()*sizeof(SplashColor)); + memset(rgbbitmap->getAlphaPtr(), 0, rgbbitmap->getWidth()*rgbbitmap->getHeight()); + memset(rgbbitmap->getDataPtr(), 0, rgbbitmap->getRowSize()*rgbbitmap->getHeight()); free(img->data);img->data=0;free(img);img=0; + + this->emptypage = 0; +} + +void BitmapOutputDev::flushText() +{ + msg(" Flushing text/polygons"); + gfxdevice_record_flush(this->gfxoutput, this->dev); + + 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; + + int width = bitmap->getWidth(); + int height = bitmap->getHeight(); + + gfxcolor_t*data = (gfxcolor_t*)malloc(sizeof(gfxcolor_t)*width*height); + + for(y=0;ygetAlpha(x,y); + line[x].r = a; + line[x].g = a; + line[x].b = a; + line[x].a = 255; + } + } + writePNG(filename, (unsigned char*)data, width, height); + free(data); +} +static int dbg_btm_counter=1; + +static const char*STATE_NAME[] = {"parallel", "textabovebitmap", "bitmapabovetext"}; + +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 */ + + msg(" Testing new text data against current bitmap data, state=%s, counter=%d\n", STATE_NAME[layerstate], dbg_btm_counter); + + char filename1[80]; + char filename2[80]; + 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, + and also clear the bitmap buffer, so we can check for + new intersections */ + msg(" Text is above current bitmap/polygon data"); + layerstate=STATE_TEXT_IS_ABOVE; + 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* + text is now *above* the bitmap + */ + msg(" Text is above current bitmap/polygon data (which is above some other text)"); + flushText(); + layerstate=STATE_TEXT_IS_ABOVE; + /* 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(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 + bitmap data *and* new text data was drawn, and + *again* it's above the current bitmap- so clear + the polygon bitmap again, so we can check for + new intersections */ + msg(" Text is still above current bitmap/polygon data"); + clearBoolPolyDev(x1,y1,x2,y2); + } + } + return ret; +} + +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]; + 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++; + + 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(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(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(x1,y1,x2,y2); + } + } + return ret; +} + +//void checkNewText() { +// Guchar*alpha = rgbbitmap->getAlphaPtr(); +// Guchar*charpixels = clip1bitmap->getDataPtr(); +// int xx,yy; +// for(yy=0;yy>3; +// /* TODO: is the bit order correct? */ +// if(aline[xx] && (cline[bytepos]&(1<getMode()==splashModeMono1) { + if(x2<=x1) + return gFalse; + if(x2<0) + return gFalse; + if(x1<0) + x1 = 0; + if(x1>=clip0bitmap->getWidth()) + return gFalse; + if(x2>clip0bitmap->getWidth()) + x2=clip0bitmap->getWidth(); + + if(y2<=y1) + return gFalse; + if(y2<0) + return gFalse; + if(y1<0) + y1 = 0; + if(y1>=clip0bitmap->getHeight()) + return gFalse; + if(y2>clip0bitmap->getHeight()) + y2=clip0bitmap->getHeight(); + + SplashBitmap*clip0 = clip0bitmap; + SplashBitmap*clip1 = clip1bitmap; + int width8 = (clip0bitmap->getWidth()+7)/8; + int height = clip0bitmap->getHeight(); + int x18 = x1/8; + int x28 = (x2+7)/8; + int y; + + for(y=y1;ygetDataPtr()[width8*y+x18]; + unsigned char*row2 = &clip1bitmap->getDataPtr()[width8*y+x28]; + if(memcmp(row1, row2, x28-x18)) + return gTrue; + } + return gFalse; + } else { + SplashBitmap*clip0 = clip0bitmap; + SplashBitmap*clip1 = clip1bitmap; + int width = clip0->getAlphaRowSize(); + int height = clip0->getHeight(); + return memcmp(clip0->getAlphaPtr(), clip1->getAlphaPtr(), width*height); + } +} + +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(); + int height = btm->getHeight(); + memset(btm->getDataPtr(), 0, width8*height); + } else { + int width = btm->getAlphaRowSize(); + int height = btm->getHeight(); + memset(btm->getAlphaPtr(), 0, width*height); + } +} + +long long unsigned int compare64(long long unsigned int*data1, long long unsigned int*data2, int len) +{ + long long unsigned int c; + int t; + for(t=0;tgetMode()==splashModeMono1) { + /* alternative implementation, using one bit per pixel- + would work if xpdf wouldn't try to dither everything */ + + Guchar*polypixels = boolpoly->getDataPtr(); + Guchar*textpixels = booltext->getDataPtr(); + + int width8 = (width+7)/8; + int height = boolpoly->getHeight(); + + if(x1|y1|x2|y2) { + if(y1>=0 && y1<=y2 && y2<=height) { + polypixels+=y1*width8; + textpixels+=y1*width8; + height=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"); + } + int l2 = len; + len /= sizeof(unsigned long long int); + c = compare64((unsigned long long int*)polypixels, (unsigned long long int*)textpixels, len); + int l1 = len*sizeof(unsigned long long int); + for(t=l1;tgetAlphaPtr(); + 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;t startPage"); - this->width = (int)x2 - (int)x1; //not used yet - this->height = (int)y2 - (int)y1; - rgbdev->startPage(pageNum, state, x1, y1, x2, y2); - alphadev->startPage(pageNum, state, x1, y1, x2, y2); + double x1,y1,x2,y2; + state->transform(crop_x1,crop_y1,&x1,&y1); + state->transform(crop_x2,crop_y2,&x2,&y2); + if(x2movex = -(int)x1 - user_movex; + this->movey = -(int)y1 - user_movey; + + if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) { + x1 = user_clipx1; + x2 = user_clipx2; + y1 = user_clipy1; + y2 = user_clipy2; + } + this->width = (int)(x2-x1); + this->height = (int)(y2-y1); + + msg(" 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); + + boolpolybitmap = boolpolydev->getBitmap(); + booltextbitmap = booltextdev->getBitmap(); + clip0bitmap = clip0dev->getBitmap(); + clip1bitmap = clip1dev->getBitmap(); + rgbbitmap = rgbdev->getBitmap(); + + flushText(); // write out the initial clipping rectangle + + /* just in case any device did draw a white background rectangle + into the device */ + clearBoolTextDev(UNKNOWN_BOUNDING_BOX); + clearBoolPolyDev(UNKNOWN_BOUNDING_BOX); + + this->layerstate = STATE_PARALLEL; + this->emptypage = 1; + msg(" startPage done"); } void BitmapOutputDev::endPage() { - msg(" endPage"); - this->flush(); + msg(" endPage (BitmapOutputDev)"); + + /* notice: we're not fully done yet with this page- there might still be + a few calls to drawLink() yet to come */ +} +void BitmapOutputDev::finishPage() +{ + msg(" finishPage (BitmapOutputDev)"); + gfxdev->endPage(); + + if(layerstate == STATE_BITMAP_IS_ABOVE) { + this->flushText(); + this->flushBitmap(); + } else { + this->flushBitmap(); + this->flushText(); + } /* splash will now destroy alpha, and paint the background color into the "holes" in the bitmap */ + boolpolydev->endPage(); + booltextdev->endPage(); rgbdev->endPage(); - alphadev->endPage(); + clip0dev->endPage(); + clip1dev->endPage(); } GBool BitmapOutputDev::upsideDown() { - rgbdev->upsideDown(); - return alphadev->upsideDown(); + boolpolydev->upsideDown(); + booltextdev->upsideDown(); + clip0dev->upsideDown(); + clip1dev->upsideDown(); + return rgbdev->upsideDown(); } GBool BitmapOutputDev::useDrawChar() { - rgbdev->useDrawChar(); - return alphadev->useDrawChar(); + boolpolydev->useDrawChar(); + booltextdev->useDrawChar(); + clip0dev->useDrawChar(); + clip1dev->useDrawChar(); + return rgbdev->useDrawChar(); } GBool BitmapOutputDev::useTilingPatternFill() { - rgbdev->useTilingPatternFill(); - return alphadev->useTilingPatternFill(); + boolpolydev->useTilingPatternFill(); + booltextdev->useTilingPatternFill(); + clip0dev->useTilingPatternFill(); + clip1dev->useTilingPatternFill(); + return rgbdev->useTilingPatternFill(); } GBool BitmapOutputDev::useShadedFills() { - rgbdev->useTilingPatternFill(); - return alphadev->useTilingPatternFill(); + boolpolydev->useShadedFills(); + booltextdev->useShadedFills(); + clip0dev->useShadedFills(); + clip1dev->useShadedFills(); + return rgbdev->useShadedFills(); } GBool BitmapOutputDev::useDrawForm() { - rgbdev->useDrawForm(); - return alphadev->useDrawForm(); + boolpolydev->useDrawForm(); + booltextdev->useDrawForm(); + clip0dev->useDrawForm(); + clip1dev->useDrawForm(); + return rgbdev->useDrawForm(); } GBool BitmapOutputDev::interpretType3Chars() { - if(config_bitmapfonts) { - rgbdev->interpretType3Chars(); - return alphadev->interpretType3Chars(); - } else { - return gfxdev->interpretType3Chars(); - } + boolpolydev->interpretType3Chars(); + booltextdev->interpretType3Chars(); + clip0dev->interpretType3Chars(); + clip1dev->interpretType3Chars(); + return rgbdev->interpretType3Chars(); } GBool BitmapOutputDev::needNonText() { - rgbdev->needNonText(); - return alphadev->needNonText(); + boolpolydev->needNonText(); + booltextdev->needNonText(); + clip0dev->needNonText(); + clip1dev->needNonText(); + return rgbdev->needNonText(); } /*GBool BitmapOutputDev::checkPageSlice(Page *page, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool crop, @@ -230,365 +796,619 @@ GBool BitmapOutputDev::needNonText() }*/ void BitmapOutputDev::setDefaultCTM(double *ctm) { + boolpolydev->setDefaultCTM(ctm); + booltextdev->setDefaultCTM(ctm); rgbdev->setDefaultCTM(ctm); - alphadev->setDefaultCTM(ctm); + clip0dev->setDefaultCTM(ctm); + clip1dev->setDefaultCTM(ctm); + gfxdev->setDefaultCTM(ctm); } void BitmapOutputDev::saveState(GfxState *state) { + boolpolydev->saveState(state); + booltextdev->saveState(state); rgbdev->saveState(state); - alphadev->saveState(state); + clip0dev->saveState(state); + clip1dev->saveState(state); + + /*ClipState*cstate = new ClipState(); + cstate->next = this->clipstates; + this->clipstates = cstate;*/ } void BitmapOutputDev::restoreState(GfxState *state) { + boolpolydev->restoreState(state); + booltextdev->restoreState(state); rgbdev->restoreState(state); - alphadev->restoreState(state); + clip0dev->restoreState(state); + clip1dev->restoreState(state); + + /*if(this->clipstates) { + ClipState*old = this->clipstates; + if(old->written) { + gfxdev->restoreState(state); + } + this->clipstates = this->clipstates->next; + delete(old); + } else { + msg(" invalid restoreState()"); + }*/ } void BitmapOutputDev::updateAll(GfxState *state) { + boolpolydev->updateAll(state); + booltextdev->updateAll(state); rgbdev->updateAll(state); - alphadev->updateAll(state); + clip0dev->updateAll(state); + clip1dev->updateAll(state); + gfxdev->updateAll(state); } void BitmapOutputDev::updateCTM(GfxState *state, double m11, double m12, double m21, double m22, double m31, double m32) { + boolpolydev->updateCTM(state,m11,m12,m21,m22,m31,m32); + booltextdev->updateCTM(state,m11,m12,m21,m22,m31,m32); rgbdev->updateCTM(state,m11,m12,m21,m22,m31,m32); - alphadev->updateCTM(state,m11,m12,m21,m22,m31,m32); + clip0dev->updateCTM(state,m11,m12,m21,m22,m31,m32); + clip1dev->updateCTM(state,m11,m12,m21,m22,m31,m32); + gfxdev->updateCTM(state,m11,m12,m21,m22,m31,m32); } void BitmapOutputDev::updateLineDash(GfxState *state) { + boolpolydev->updateLineDash(state); + booltextdev->updateLineDash(state); rgbdev->updateLineDash(state); - alphadev->updateLineDash(state); + clip0dev->updateLineDash(state); + clip1dev->updateLineDash(state); + gfxdev->updateLineDash(state); } void BitmapOutputDev::updateFlatness(GfxState *state) { + boolpolydev->updateFlatness(state); + booltextdev->updateFlatness(state); rgbdev->updateFlatness(state); - alphadev->updateFlatness(state); + clip0dev->updateFlatness(state); + clip1dev->updateFlatness(state); + gfxdev->updateFlatness(state); } void BitmapOutputDev::updateLineJoin(GfxState *state) { + boolpolydev->updateLineJoin(state); + booltextdev->updateLineJoin(state); rgbdev->updateLineJoin(state); - alphadev->updateLineJoin(state); + clip0dev->updateLineJoin(state); + clip1dev->updateLineJoin(state); + gfxdev->updateLineJoin(state); } void BitmapOutputDev::updateLineCap(GfxState *state) { + boolpolydev->updateLineCap(state); + booltextdev->updateLineCap(state); rgbdev->updateLineCap(state); - alphadev->updateLineCap(state); + clip0dev->updateLineCap(state); + clip1dev->updateLineCap(state); + gfxdev->updateLineCap(state); } void BitmapOutputDev::updateMiterLimit(GfxState *state) { + boolpolydev->updateMiterLimit(state); + booltextdev->updateMiterLimit(state); rgbdev->updateMiterLimit(state); - alphadev->updateMiterLimit(state); + clip0dev->updateMiterLimit(state); + clip1dev->updateMiterLimit(state); + gfxdev->updateMiterLimit(state); } void BitmapOutputDev::updateLineWidth(GfxState *state) { + boolpolydev->updateLineWidth(state); + booltextdev->updateLineWidth(state); rgbdev->updateLineWidth(state); - alphadev->updateLineWidth(state); + clip0dev->updateLineWidth(state); + clip1dev->updateLineWidth(state); + gfxdev->updateLineWidth(state); } void BitmapOutputDev::updateStrokeAdjust(GfxState *state) { + boolpolydev->updateStrokeAdjust(state); + booltextdev->updateStrokeAdjust(state); rgbdev->updateStrokeAdjust(state); - alphadev->updateStrokeAdjust(state); + clip0dev->updateStrokeAdjust(state); + clip1dev->updateStrokeAdjust(state); + gfxdev->updateStrokeAdjust(state); } void BitmapOutputDev::updateFillColorSpace(GfxState *state) { + boolpolydev->updateFillColorSpace(state); + booltextdev->updateFillColorSpace(state); rgbdev->updateFillColorSpace(state); - alphadev->updateFillColorSpace(state); + clip0dev->updateFillColorSpace(state); + clip1dev->updateFillColorSpace(state); + gfxdev->updateFillColorSpace(state); } void BitmapOutputDev::updateStrokeColorSpace(GfxState *state) { + boolpolydev->updateStrokeColorSpace(state); + booltextdev->updateStrokeColorSpace(state); rgbdev->updateStrokeColorSpace(state); - alphadev->updateStrokeColorSpace(state); + clip0dev->updateStrokeColorSpace(state); + clip1dev->updateStrokeColorSpace(state); + gfxdev->updateStrokeColorSpace(state); } void BitmapOutputDev::updateFillColor(GfxState *state) { + boolpolydev->updateFillColor(state); + booltextdev->updateFillColor(state); rgbdev->updateFillColor(state); - alphadev->updateFillColor(state); + clip0dev->updateFillColor(state); + clip1dev->updateFillColor(state); + gfxdev->updateFillColor(state); } void BitmapOutputDev::updateStrokeColor(GfxState *state) { + boolpolydev->updateStrokeColor(state); + booltextdev->updateStrokeColor(state); rgbdev->updateStrokeColor(state); - alphadev->updateStrokeColor(state); + clip0dev->updateStrokeColor(state); + clip1dev->updateStrokeColor(state); + gfxdev->updateStrokeColor(state); } void BitmapOutputDev::updateBlendMode(GfxState *state) { + boolpolydev->updateBlendMode(state); + booltextdev->updateBlendMode(state); rgbdev->updateBlendMode(state); - alphadev->updateBlendMode(state); + clip0dev->updateBlendMode(state); + clip1dev->updateBlendMode(state); + gfxdev->updateBlendMode(state); } void BitmapOutputDev::updateFillOpacity(GfxState *state) { + boolpolydev->updateFillOpacity(state); + booltextdev->updateFillOpacity(state); rgbdev->updateFillOpacity(state); - alphadev->updateFillOpacity(state); + clip0dev->updateFillOpacity(state); + clip1dev->updateFillOpacity(state); + gfxdev->updateFillOpacity(state); } void BitmapOutputDev::updateStrokeOpacity(GfxState *state) { + boolpolydev->updateStrokeOpacity(state); + booltextdev->updateStrokeOpacity(state); rgbdev->updateStrokeOpacity(state); - alphadev->updateStrokeOpacity(state); + clip0dev->updateStrokeOpacity(state); + clip1dev->updateStrokeOpacity(state); + gfxdev->updateStrokeOpacity(state); } void BitmapOutputDev::updateFillOverprint(GfxState *state) { + boolpolydev->updateFillOverprint(state); + booltextdev->updateFillOverprint(state); rgbdev->updateFillOverprint(state); - alphadev->updateFillOverprint(state); + clip0dev->updateFillOverprint(state); + clip1dev->updateFillOverprint(state); + gfxdev->updateFillOverprint(state); } void BitmapOutputDev::updateStrokeOverprint(GfxState *state) { + boolpolydev->updateStrokeOverprint(state); + booltextdev->updateStrokeOverprint(state); rgbdev->updateStrokeOverprint(state); - alphadev->updateStrokeOverprint(state); + clip0dev->updateStrokeOverprint(state); + clip1dev->updateStrokeOverprint(state); + gfxdev->updateStrokeOverprint(state); } void BitmapOutputDev::updateTransfer(GfxState *state) { + boolpolydev->updateTransfer(state); + booltextdev->updateTransfer(state); rgbdev->updateTransfer(state); - alphadev->updateTransfer(state); + clip0dev->updateTransfer(state); + clip1dev->updateTransfer(state); + gfxdev->updateTransfer(state); } + void BitmapOutputDev::updateFont(GfxState *state) { + boolpolydev->updateFont(state); + booltextdev->updateFont(state); rgbdev->updateFont(state); - alphadev->updateFont(state); + clip0dev->updateFont(state); + clip1dev->updateFont(state); gfxdev->updateFont(state); } void BitmapOutputDev::updateTextMat(GfxState *state) { + boolpolydev->updateTextMat(state); + booltextdev->updateTextMat(state); rgbdev->updateTextMat(state); - alphadev->updateTextMat(state); + clip0dev->updateTextMat(state); + clip1dev->updateTextMat(state); gfxdev->updateTextMat(state); } void BitmapOutputDev::updateCharSpace(GfxState *state) { + boolpolydev->updateCharSpace(state); + booltextdev->updateCharSpace(state); rgbdev->updateCharSpace(state); - alphadev->updateCharSpace(state); - gfxdev->updateTextMat(state); + clip0dev->updateCharSpace(state); + clip1dev->updateCharSpace(state); + gfxdev->updateCharSpace(state); } void BitmapOutputDev::updateRender(GfxState *state) { + boolpolydev->updateRender(state); + booltextdev->updateRender(state); rgbdev->updateRender(state); - alphadev->updateRender(state); - gfxdev->updateTextMat(state); + clip0dev->updateRender(state); + clip1dev->updateRender(state); + gfxdev->updateRender(state); } void BitmapOutputDev::updateRise(GfxState *state) { + boolpolydev->updateRise(state); + booltextdev->updateRise(state); rgbdev->updateRise(state); - alphadev->updateRise(state); - gfxdev->updateTextMat(state); + clip0dev->updateRise(state); + clip1dev->updateRise(state); + gfxdev->updateRise(state); } void BitmapOutputDev::updateWordSpace(GfxState *state) { + boolpolydev->updateWordSpace(state); + booltextdev->updateWordSpace(state); rgbdev->updateWordSpace(state); - alphadev->updateWordSpace(state); - gfxdev->updateTextMat(state); + clip0dev->updateWordSpace(state); + clip1dev->updateWordSpace(state); + gfxdev->updateWordSpace(state); } void BitmapOutputDev::updateHorizScaling(GfxState *state) { + boolpolydev->updateHorizScaling(state); + booltextdev->updateHorizScaling(state); rgbdev->updateHorizScaling(state); - alphadev->updateHorizScaling(state); - gfxdev->updateTextMat(state); + clip0dev->updateHorizScaling(state); + clip1dev->updateHorizScaling(state); + gfxdev->updateHorizScaling(state); } void BitmapOutputDev::updateTextPos(GfxState *state) { + boolpolydev->updateTextPos(state); + booltextdev->updateTextPos(state); rgbdev->updateTextPos(state); - alphadev->updateTextPos(state); - gfxdev->updateTextMat(state); + clip0dev->updateTextPos(state); + clip1dev->updateTextPos(state); + gfxdev->updateTextPos(state); } void BitmapOutputDev::updateTextShift(GfxState *state, double shift) { + boolpolydev->updateTextShift(state, shift); + booltextdev->updateTextShift(state, shift); rgbdev->updateTextShift(state, shift); - alphadev->updateTextShift(state, shift); - gfxdev->updateTextMat(state); + clip0dev->updateTextShift(state, shift); + clip1dev->updateTextShift(state, shift); + gfxdev->updateTextShift(state, shift); } void BitmapOutputDev::stroke(GfxState *state) { - msg(" stroke"); + msg(" stroke"); + boolpolydev->stroke(state); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); rgbdev->stroke(state); - alphadev->stroke(state); } void BitmapOutputDev::fill(GfxState *state) { - msg(" fill"); + msg(" fill"); + boolpolydev->fill(state); + if(checkNewBitmap(UNKNOWN_BOUNDING_BOX)) { + boolpolydev->fill(state); + } rgbdev->fill(state); - alphadev->fill(state); } void BitmapOutputDev::eoFill(GfxState *state) { - msg(" eoFill"); + msg(" eoFill"); + boolpolydev->eoFill(state); + if(checkNewBitmap(UNKNOWN_BOUNDING_BOX)) { + boolpolydev->eoFill(state); + } rgbdev->eoFill(state); - alphadev->eoFill(state); } +#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(" tilingPatternFill"); + msg(" 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); - alphadev->tilingPatternFill(state, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep); } +#else +void BitmapOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Object *str, + int paintType, Dict *resDict, + double *mat, double *bbox, + int x0, int y0, int x1, int y1, + double xStep, double yStep) +{ + msg(" tilingPatternFill"); + boolpolydev->tilingPatternFill(state, gfx, 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); +} +#endif + GBool BitmapOutputDev::functionShadedFill(GfxState *state, GfxFunctionShading *shading) { - msg(" functionShadedFill"); - rgbdev->functionShadedFill(state, shading); - return alphadev->functionShadedFill(state, shading); + msg(" functionShadedFill"); + boolpolydev->functionShadedFill(state, shading); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); + return rgbdev->functionShadedFill(state, shading); } GBool BitmapOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading) { - msg(" axialShadedFill"); - rgbdev->axialShadedFill(state, shading); - return alphadev->axialShadedFill(state, shading); + msg(" axialShadedFill"); + boolpolydev->axialShadedFill(state, shading); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); + return rgbdev->axialShadedFill(state, shading); } GBool BitmapOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading) { - msg(" radialShadedFill"); - rgbdev->radialShadedFill(state, shading); - return alphadev->radialShadedFill(state, shading); + msg(" radialShadedFill"); + boolpolydev->radialShadedFill(state, shading); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); + return rgbdev->radialShadedFill(state, shading); } + +SplashColor black = {0,0,0}; +SplashColor white = {255,255,255}; + void BitmapOutputDev::clip(GfxState *state) { - msg(" clip"); + msg(" clip"); + boolpolydev->clip(state); + booltextdev->clip(state); rgbdev->clip(state); - alphadev->clip(state); + clip1dev->clip(state); } void BitmapOutputDev::eoClip(GfxState *state) { - msg(" eoClip"); + msg(" eoClip"); + boolpolydev->eoClip(state); + booltextdev->eoClip(state); rgbdev->eoClip(state); - alphadev->eoClip(state); + clip1dev->eoClip(state); } void BitmapOutputDev::clipToStrokePath(GfxState *state) { - msg(" clipToStrokePath"); + msg(" clipToStrokePath"); + boolpolydev->clipToStrokePath(state); + booltextdev->clipToStrokePath(state); rgbdev->clipToStrokePath(state); - alphadev->clipToStrokePath(state); + clip1dev->clipToStrokePath(state); } void BitmapOutputDev::beginStringOp(GfxState *state) { - msg(" beginStringOp"); - if(this->config_bitmapfonts) { - rgbdev->beginStringOp(state); - alphadev->beginStringOp(state); - } else { - gfxdev->beginStringOp(state); - } + msg(" beginStringOp"); + clip0dev->beginStringOp(state); + clip1dev->beginStringOp(state); + booltextdev->beginStringOp(state); + gfxdev->beginStringOp(state); } void BitmapOutputDev::endStringOp(GfxState *state) { - msg(" endStringOp"); - if(this->config_bitmapfonts) { - rgbdev->endStringOp(state); - alphadev->endStringOp(state); - } else { - gfxdev->endStringOp(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"); - if(this->config_bitmapfonts) { - rgbdev->beginString(state, s); - alphadev->beginString(state, s); - } else { - gfxdev->beginString(state, s); - } + msg(" beginString"); + clip0dev->beginString(state, s); + clip1dev->beginString(state, s); + booltextdev->beginString(state, s); + gfxdev->beginString(state, s); } void BitmapOutputDev::endString(GfxState *state) { - msg(" endString"); - if(this->config_bitmapfonts) { - rgbdev->endString(state); - alphadev->endString(state); - } else { - gfxdev->endString(state); - } + msg(" endString"); + clip0dev->endString(state); + clip1dev->endString(state); + booltextdev->endString(state); + checkNewText(UNKNOWN_BOUNDING_BOX); + gfxdev->endString(state); +} + +void BitmapOutputDev::clearClips() +{ + clearBooleanBitmap(clip0bitmap, 0, 0, 0, 0); + clearBooleanBitmap(clip1bitmap, 0, 0, 0, 0); +} +void BitmapOutputDev::clearBoolPolyDev(int x1, int y1, int x2, int y2) +{ + clearBooleanBitmap(boolpolybitmap, x1, y1, x2, y2); +} +void BitmapOutputDev::clearBoolTextDev(int x1, int y1, int x2, int y2) +{ + 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"); - flush(); - if(this->config_bitmapfonts) { + 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); - alphadev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen); } else { - gfxdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen); + // 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); + + /* 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); + int t; + for(t=0;tgetLength();t++) { + double xx,yy; + Guchar f; + path->getPoint(t,&xx,&yy,&f); + xx+=x; + yy+=y; + if(xxx2) 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 + different on a device without clipping), then draw it on the bitmap, not as + text */ + 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); + rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen); + if(config_extrafontdata) { + int oldrender = state->getRender(); + state->setRender(3); //invisible + gfxdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen); + state->setRender(oldrender); + } + } else { + /* this char is not at all affected by clipping. + Now just dump out the bitmap we're currently working on, if necessary. */ + booltextdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen); + checkNewText(x1,y1,x2,y2); + /* use polygonal output device to do the actual text handling */ + gfxdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen); + } } } void BitmapOutputDev::drawString(GfxState *state, GString *s) { - msg(" drawString"); - if(this->config_bitmapfonts) { - rgbdev->drawString(state, s); - alphadev->drawString(state, s); - } else { - gfxdev->drawString(state, s); - } + msg(" internal error: drawString not implemented"); + return; + clip0dev->drawString(state, s); + clip1dev->drawString(state, s); + booltextdev->drawString(state, s); + gfxdev->drawString(state, s); } void BitmapOutputDev::endTextObject(GfxState *state) { - msg(" endTextObject"); - if(this->config_bitmapfonts) { - rgbdev->endTextObject(state); - alphadev->endTextObject(state); - } else { - gfxdev->endType3Char(state); - } + msg(" endTextObject"); + rgbdev->endTextObject(state); + clip0dev->endTextObject(state); + clip1dev->endTextObject(state); + booltextdev->endTextObject(state); + /* TODO: do this only if rendermode!=0 */ + checkNewText(UNKNOWN_BOUNDING_BOX); + gfxdev->endTextObject(state); } + +/* TODO: these four operations below *should* do nothing, as type3 + chars are drawn using operations like fill() */ GBool BitmapOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen) { - msg(" beginType3Char"); - if(this->config_bitmapfonts) { - rgbdev->beginType3Char(state, x, y, dx, dy, code, u, uLen); - return alphadev->beginType3Char(state, x, y, dx, dy, code, u, uLen); - } else { - return gfxdev->beginType3Char(state, x, y, dx, dy, code, u, uLen); - } + msg(" beginType3Char"); + /* call gfxdev so that it can generate "invisible" characters + on top of the actual graphic content, for text extraction */ + return gfxdev->beginType3Char(state, x, y, dx, dy, code, u, uLen); } void BitmapOutputDev::type3D0(GfxState *state, double wx, double wy) { - msg(" type3D0"); - if(this->config_bitmapfonts) { - rgbdev->type3D0(state, wx, wy); - alphadev->type3D0(state, wx, wy); - } else { - return gfxdev->type3D0(state, wx, wy); - } + msg(" type3D0"); + return gfxdev->type3D0(state, wx, wy); } void BitmapOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) { - msg(" type3D1"); - if(this->config_bitmapfonts) { - rgbdev->type3D1(state, wx, wy, llx, lly, urx, ury); - alphadev->type3D1(state, wx, wy, llx, lly, urx, ury); - } else { - return gfxdev->type3D1(state, wx, wy, llx, lly, urx, ury); - } + msg(" type3D1"); + return gfxdev->type3D1(state, wx, wy, llx, lly, urx, ury); } void BitmapOutputDev::endType3Char(GfxState *state) { - msg(" endType3Char"); - if(this->config_bitmapfonts) { - rgbdev->endType3Char(state); - alphadev->endType3Char(state); - } else { - gfxdev->endType3Char(state); - } + msg(" endType3Char"); + gfxdev->endType3Char(state); } + +class CopyStream: public Object +{ + Dict*dict; + char*buf; + MemStream*memstream; + public: + CopyStream(Stream*str, int len) + { + buf = 0; + str->reset(); + if(len) { + buf = (char*)malloc(len); + int t; + for (t=0; tgetChar(); + } + str->close(); + this->dict = str->getDict(); + this->memstream = new MemStream(buf, 0, len, this); + } + ~CopyStream() + { + ::free(this->buf);this->buf = 0; + delete this->memstream; + } + Dict* getDict() {return dict;} + Stream* getStream() {return this->memstream;}; +}; + void BitmapOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) { - msg(" drawImageMask"); + msg(" drawImageMask streamkind=%d", str->getKind()); + CopyStream*cpystr = 0; + if(inlineImg) { + cpystr = new CopyStream(str, height * ((width + 7) / 8)); + str = cpystr->getStream(); + } + boolpolydev->drawImageMask(state, ref, str, width, height, invert, inlineImg); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); rgbdev->drawImageMask(state, ref, str, width, height, invert, inlineImg); - alphadev->drawImageMask(state, ref, str, width, height, invert, inlineImg); + if(cpystr) + delete cpystr; } void BitmapOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg) { - msg(" drawImage"); + msg(" drawImage streamkind=%d", str->getKind()); + CopyStream*cpystr = 0; + if(inlineImg) { + 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); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); rgbdev->drawImage(state, ref, str, width, height, colorMap, maskColors, inlineImg); - alphadev->drawImage(state, ref, str, width, height, colorMap, maskColors, inlineImg); + if(cpystr) + delete cpystr; } void BitmapOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, @@ -596,9 +1416,10 @@ void BitmapOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert) { - msg(" drawMaskedImage"); + msg(" drawMaskedImage streamkind=%d", str->getKind()); + boolpolydev->drawMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); rgbdev->drawMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert); - alphadev->drawMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert); } void BitmapOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, @@ -607,46 +1428,90 @@ void BitmapOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream * int maskWidth, int maskHeight, GfxImageColorMap *maskColorMap) { - msg(" drawSoftMaskedImage"); + 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); rgbdev->drawSoftMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap); - alphadev->drawSoftMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap); } void BitmapOutputDev::drawForm(Ref id) { - msg(" drawForm"); + msg(" drawForm"); + boolpolydev->drawForm(id); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); rgbdev->drawForm(id); - alphadev->drawForm(id); } + +void BitmapOutputDev::processLink(Link *link, Catalog *catalog) +{ + msg(" processLink"); + gfxdev->processLink(link, catalog); +} + void BitmapOutputDev::beginTransparencyGroup(GfxState *state, double *bbox, GfxColorSpace *blendingColorSpace, GBool isolated, GBool knockout, GBool forSoftMask) { - msg(" beginTransparencyGroup"); - rgbdev->beginTransparencyGroup(state, bbox, blendingColorSpace, isolated, knockout, forSoftMask); - alphadev->beginTransparencyGroup(state, bbox, blendingColorSpace, isolated, knockout, forSoftMask); + msg(" beginTransparencyGroup"); +#if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207 + GfxState*state1 = state->copy(); + GfxState*state2 = state->copy(); + state1->setPath(0); + state1->setPath(state->getPath()->copy()); + state2->setPath(0); + state2->setPath(state->getPath()->copy()); +#else + GfxState*state1 = state->copy(gTrue); + GfxState*state2 = state->copy(gTrue); +#endif + boolpolydev->beginTransparencyGroup(state1, bbox, blendingColorSpace, isolated, knockout, forSoftMask); + rgbdev->beginTransparencyGroup(state2, bbox, blendingColorSpace, isolated, knockout, forSoftMask); + clip1dev->beginTransparencyGroup(state, bbox, blendingColorSpace, isolated, knockout, forSoftMask); + delete state1; + delete state2; } void BitmapOutputDev::endTransparencyGroup(GfxState *state) { - msg(" endTransparencyGroup"); - rgbdev->endTransparencyGroup(state); - alphadev->endTransparencyGroup(state); + msg(" endTransparencyGroup"); +#if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207 + GfxState*state1 = state->copy(); + GfxState*state2 = state->copy(); + state1->setPath(0); + state1->setPath(state->getPath()->copy()); + state2->setPath(0); + state2->setPath(state->getPath()->copy()); +#else + GfxState*state1 = state->copy(gTrue); + GfxState*state2 = state->copy(gTrue); +#endif + boolpolydev->endTransparencyGroup(state1); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); + rgbdev->endTransparencyGroup(state2); + delete state1; + delete state2; + clip1dev->endTransparencyGroup(state); } void BitmapOutputDev::paintTransparencyGroup(GfxState *state, double *bbox) { - msg(" paintTransparencyGroup"); + msg(" paintTransparencyGroup"); + boolpolydev->paintTransparencyGroup(state,bbox); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); rgbdev->paintTransparencyGroup(state,bbox); - alphadev->paintTransparencyGroup(state,bbox); + clip1dev->paintTransparencyGroup(state,bbox); } void BitmapOutputDev::setSoftMask(GfxState *state, double *bbox, GBool alpha, Function *transferFunc, GfxColor *backdropColor) { - msg(" setSoftMask"); + msg(" setSoftMask"); + boolpolydev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); rgbdev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor); - alphadev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor); + clip1dev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor); } void BitmapOutputDev::clearSoftMask(GfxState *state) { - msg(" clearSoftMask"); + msg(" clearSoftMask"); + boolpolydev->clearSoftMask(state); + checkNewBitmap(UNKNOWN_BOUNDING_BOX); rgbdev->clearSoftMask(state); - alphadev->clearSoftMask(state); + clip1dev->clearSoftMask(state); }