From 18507d7cb3535fdfd333c0e33cf5db8bd5d6e40a Mon Sep 17 00:00:00 2001 From: kramm Date: Wed, 12 Mar 2008 19:09:36 +0000 Subject: [PATCH] reworked bitmap/text overlapping texts --- lib/pdf/BitmapOutputDev.cc | 551 ++++++++++++++++++++++++++++++++++++++------ lib/pdf/BitmapOutputDev.h | 22 +- 2 files changed, 501 insertions(+), 72 deletions(-) diff --git a/lib/pdf/BitmapOutputDev.cc b/lib/pdf/BitmapOutputDev.cc index 0b49c2c..e915bed 100644 --- a/lib/pdf/BitmapOutputDev.cc +++ b/lib/pdf/BitmapOutputDev.cc @@ -26,6 +26,8 @@ #include "SplashPattern.h" #include "Splash.h" #include "../log.h" +#include "../png.h" +#include "../devices/record.h" static SplashColor splash_white = {255,255,255}; static SplashColor splash_black = {0,0,0}; @@ -42,13 +44,35 @@ 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->clip0dev = new SplashOutputDev(splashModeMono1, 1, gFalse, splash_black, gTrue, gFalse); - this->clip1dev = new SplashOutputDev(splashModeMono1, 1, gFalse, splash_black, gTrue, gFalse); + + /* 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->boolpolydev->startDoc(this->xref); + this->booltextdev->startDoc(this->xref); this->clip0dev->startDoc(this->xref); this->clip1dev->startDoc(this->xref); + + this->gfxoutput = (gfxdevice_t*)malloc(sizeof(gfxdevice_t)); + gfxdevice_record_init(this->gfxoutput); + + this->gfxdev->setDevice(this->gfxoutput); this->config_bitmapfonts = 0; this->config_extrafontdata = 0; @@ -58,17 +82,25 @@ BitmapOutputDev::BitmapOutputDev(InfoOutputDev*info, PDFDoc*doc) } 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; + delete this->rgbdev;this->rgbdev = 0; + } + if(this->boolpolydev) { + delete this->boolpolydev;this->boolpolydev = 0; } if(this->clip0dev) { - delete this->clip0dev;this->clip0dev= 0; + delete this->clip0dev;this->clip0dev = 0; } if(this->clip1dev) { - delete this->clip1dev;this->clip1dev= 0; + delete this->clip1dev;this->clip1dev = 0; } //if(this->clipbitmap) { // delete this->clipbitmap;this->clipbitmap = 0; @@ -90,7 +122,6 @@ void BitmapOutputDev::setVectorAntialias(GBool vaa) void BitmapOutputDev::setDevice(gfxdevice_t*dev) { this->dev = dev; - this->gfxdev->setDevice(dev); } void BitmapOutputDev::setMove(int x,int y) { @@ -152,7 +183,7 @@ 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(); @@ -169,7 +200,7 @@ void BitmapOutputDev::flush() if(xmax > -this->movex + width) xmax = -this->movex+this->width; if(ymax > -this->movey + height) ymax = -this->movey+this->height; - msg(" Flushing graphics (bbox: %d,%d,%d,%d)", xmin,ymin,xmax,ymax); + 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; @@ -225,6 +256,226 @@ void BitmapOutputDev::flush() free(img->data);img->data=0;free(img);img=0; } +void BitmapOutputDev::flushText() +{ + msg(" Flushing text/polygons"); + gfxdevice_record_flush(this->gfxoutput, this->dev); +} + +void writeAlpha(SplashBitmap*bitmap, char*filename) +{ + return; + 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; + +void BitmapOutputDev::checkNewText() +{ + /* 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=%d, counter=%d\n", layerstate, dbg_btm_counter); + + char filename1[80]; + char filename2[80]; + sprintf(filename1, "state%dbitmap_newtext.png", dbg_btm_counter); + sprintf(filename2, "state%dtext_newtext.png", dbg_btm_counter); + writeAlpha(boolpolydev->getBitmap(), filename1); + writeAlpha(booltextdev->getBitmap(), filename2); + dbg_btm_counter++; + + if(intersection()) { + msg(" Text is above current bitmap/polygon data"); + 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 */ + layerstate=STATE_TEXT_IS_ABOVE; + clearBoolPolyDev(); + } 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 + */ + 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(); + clearBoolTextDev(); + } 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 */ + clearBoolPolyDev(); + } + } +} + +void BitmapOutputDev::checkNewBitmap() +{ + /* similar to checkNewText() above, only in reverse */ + msg(" Testing new graphics data against current text data, state=%d, counter=%d\n", layerstate, dbg_btm_counter); + + char filename1[80]; + char filename2[80]; + sprintf(filename1, "state%dbitmap_newbitmap.png", dbg_btm_counter); + sprintf(filename2, "state%dtext_newbitmap.png", dbg_btm_counter); + writeAlpha(boolpolydev->getBitmap(), filename1); + writeAlpha(booltextdev->getBitmap(), filename2); + dbg_btm_counter++; + + if(intersection()) { + msg(" Bitmap is above current text data"); + if(layerstate==STATE_PARALLEL) { + layerstate=STATE_BITMAP_IS_ABOVE; + clearBoolTextDev(); + } else if(layerstate==STATE_TEXT_IS_ABOVE) { + flushBitmap(); + layerstate=STATE_BITMAP_IS_ABOVE; + clearBoolTextDev(); + clearBoolPolyDev(); + } else { + clearBoolTextDev(); + } + } +} + +//void checkNewText() { +// Guchar*alpha = rgbdev->getBitmap()->getAlphaPtr(); +// Guchar*charpixels = clip1dev->getBitmap()->getDataPtr(); +// int xx,yy; +// for(yy=0;yy>3; +// /* TODO: is the bit order correct? */ +// if(aline[xx] && (cline[bytepos]&(1<getBitmap()->getMode()==splashModeMono1) { + SplashBitmap*clip0 = clip0dev->getBitmap(); + SplashBitmap*clip1 = clip1dev->getBitmap(); + int width8 = (clip0->getWidth()+7)/8; + int height = clip0->getHeight(); + return memcmp(clip0->getDataPtr(), clip1->getDataPtr(), width8*height); + } else { + SplashBitmap*clip0 = clip0dev->getBitmap(); + SplashBitmap*clip1 = clip1dev->getBitmap(); + int width = clip0->getAlphaRowSize(); + int height = clip0->getHeight(); + return memcmp(clip0->getAlphaPtr(), clip1->getAlphaPtr(), width*height); + } +} + +static void clearBooleanDev(SplashOutputDev*dev) +{ + SplashBitmap*btm = dev->getBitmap(); + 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); + } +} + +GBool BitmapOutputDev::intersection() +{ + SplashBitmap*boolpoly = boolpolydev->getBitmap(); + SplashBitmap*booltext = booltextdev->getBitmap(); + + if(boolpoly->getMode()==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(); + + int t; + int len = height*width8; + unsigned int c=0; + if(len & (sizeof(unsigned int)-1)) { + Guchar c2=0; + for(t=0;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"); 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); + + flushText(); // write out the initial clipping rectangle + + /* just in case any device did draw a white background rectangle + into the device */ + clearBoolTextDev(); + clearBoolPolyDev(); + + this->layerstate = STATE_PARALLEL; } void BitmapOutputDev::endPage() { - msg(" endPage"); - this->flush(); + msg(" endPage (BitmapOutputDev)"); + + 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(); clip0dev->endPage(); clip1dev->endPage(); + gfxdev->endPage(); } GBool BitmapOutputDev::upsideDown() { + boolpolydev->upsideDown(); + booltextdev->upsideDown(); clip0dev->upsideDown(); clip1dev->upsideDown(); return rgbdev->upsideDown(); @@ -273,6 +547,8 @@ GBool BitmapOutputDev::upsideDown() GBool BitmapOutputDev::useDrawChar() { + boolpolydev->useDrawChar(); + booltextdev->useDrawChar(); clip0dev->useDrawChar(); clip1dev->useDrawChar(); return rgbdev->useDrawChar(); @@ -280,6 +556,8 @@ GBool BitmapOutputDev::useDrawChar() GBool BitmapOutputDev::useTilingPatternFill() { + boolpolydev->useTilingPatternFill(); + booltextdev->useTilingPatternFill(); clip0dev->useTilingPatternFill(); clip1dev->useTilingPatternFill(); return rgbdev->useTilingPatternFill(); @@ -287,6 +565,8 @@ GBool BitmapOutputDev::useTilingPatternFill() GBool BitmapOutputDev::useShadedFills() { + boolpolydev->useShadedFills(); + booltextdev->useShadedFills(); clip0dev->useShadedFills(); clip1dev->useShadedFills(); return rgbdev->useShadedFills(); @@ -294,6 +574,8 @@ GBool BitmapOutputDev::useShadedFills() GBool BitmapOutputDev::useDrawForm() { + boolpolydev->useDrawForm(); + booltextdev->useDrawForm(); clip0dev->useDrawForm(); clip1dev->useDrawForm(); return rgbdev->useDrawForm(); @@ -302,6 +584,8 @@ GBool BitmapOutputDev::useDrawForm() GBool BitmapOutputDev::interpretType3Chars() { if(!config_bitmapfonts) { + boolpolydev->interpretType3Chars(); + booltextdev->interpretType3Chars(); clip0dev->interpretType3Chars(); clip1dev->interpretType3Chars(); return rgbdev->interpretType3Chars(); @@ -312,6 +596,8 @@ GBool BitmapOutputDev::interpretType3Chars() GBool BitmapOutputDev::needNonText() { + boolpolydev->needNonText(); + booltextdev->needNonText(); clip0dev->needNonText(); clip1dev->needNonText(); return rgbdev->needNonText(); @@ -327,12 +613,17 @@ GBool BitmapOutputDev::needNonText() }*/ void BitmapOutputDev::setDefaultCTM(double *ctm) { + boolpolydev->setDefaultCTM(ctm); + booltextdev->setDefaultCTM(ctm); rgbdev->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); clip0dev->saveState(state); clip1dev->saveState(state); @@ -343,6 +634,8 @@ void BitmapOutputDev::saveState(GfxState *state) } void BitmapOutputDev::restoreState(GfxState *state) { + boolpolydev->restoreState(state); + booltextdev->restoreState(state); rgbdev->restoreState(state); clip0dev->restoreState(state); clip1dev->restoreState(state); @@ -360,72 +653,118 @@ void BitmapOutputDev::restoreState(GfxState *state) } void BitmapOutputDev::updateAll(GfxState *state) { + boolpolydev->updateAll(state); + booltextdev->updateAll(state); rgbdev->updateAll(state); clip0dev->updateAll(state); clip1dev->updateAll(state); + if(!config_bitmapfonts) + 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); clip0dev->updateCTM(state,m11,m12,m21,m22,m31,m32); clip1dev->updateCTM(state,m11,m12,m21,m22,m31,m32); + if(!config_bitmapfonts) + gfxdev->updateCTM(state,m11,m12,m21,m22,m31,m32); } void BitmapOutputDev::updateLineDash(GfxState *state) { + boolpolydev->updateLineDash(state); + booltextdev->updateLineDash(state); rgbdev->updateLineDash(state); clip0dev->updateLineDash(state); clip1dev->updateLineDash(state); + if(!config_bitmapfonts) + gfxdev->updateLineDash(state); } void BitmapOutputDev::updateFlatness(GfxState *state) { + boolpolydev->updateFlatness(state); + booltextdev->updateFlatness(state); rgbdev->updateFlatness(state); clip0dev->updateFlatness(state); clip1dev->updateFlatness(state); + if(!config_bitmapfonts) + gfxdev->updateFlatness(state); } void BitmapOutputDev::updateLineJoin(GfxState *state) { + boolpolydev->updateLineJoin(state); + booltextdev->updateLineJoin(state); rgbdev->updateLineJoin(state); clip0dev->updateLineJoin(state); clip1dev->updateLineJoin(state); + if(!config_bitmapfonts) + gfxdev->updateLineJoin(state); } void BitmapOutputDev::updateLineCap(GfxState *state) { + boolpolydev->updateLineCap(state); + booltextdev->updateLineCap(state); rgbdev->updateLineCap(state); clip0dev->updateLineCap(state); clip1dev->updateLineCap(state); + if(!config_bitmapfonts) + gfxdev->updateLineCap(state); } void BitmapOutputDev::updateMiterLimit(GfxState *state) { + boolpolydev->updateMiterLimit(state); + booltextdev->updateMiterLimit(state); rgbdev->updateMiterLimit(state); clip0dev->updateMiterLimit(state); clip1dev->updateMiterLimit(state); + if(!config_bitmapfonts) + gfxdev->updateMiterLimit(state); } void BitmapOutputDev::updateLineWidth(GfxState *state) { + boolpolydev->updateLineWidth(state); + booltextdev->updateLineWidth(state); rgbdev->updateLineWidth(state); clip0dev->updateLineWidth(state); clip1dev->updateLineWidth(state); + if(!config_bitmapfonts) + gfxdev->updateLineWidth(state); } void BitmapOutputDev::updateStrokeAdjust(GfxState *state) { + boolpolydev->updateStrokeAdjust(state); + booltextdev->updateStrokeAdjust(state); rgbdev->updateStrokeAdjust(state); clip0dev->updateStrokeAdjust(state); clip1dev->updateStrokeAdjust(state); + if(!config_bitmapfonts) + gfxdev->updateStrokeAdjust(state); } void BitmapOutputDev::updateFillColorSpace(GfxState *state) { + boolpolydev->updateFillColorSpace(state); + booltextdev->updateFillColorSpace(state); rgbdev->updateFillColorSpace(state); clip0dev->updateFillColorSpace(state); clip1dev->updateFillColorSpace(state); + if(!config_bitmapfonts) + gfxdev->updateFillColorSpace(state); } void BitmapOutputDev::updateStrokeColorSpace(GfxState *state) { + boolpolydev->updateStrokeColorSpace(state); + booltextdev->updateStrokeColorSpace(state); rgbdev->updateStrokeColorSpace(state); clip0dev->updateStrokeColorSpace(state); clip1dev->updateStrokeColorSpace(state); + if(!config_bitmapfonts) + gfxdev->updateStrokeColorSpace(state); } void BitmapOutputDev::updateFillColor(GfxState *state) { + boolpolydev->updateFillColor(state); + booltextdev->updateFillColor(state); rgbdev->updateFillColor(state); clip0dev->updateFillColor(state); clip1dev->updateFillColor(state); @@ -434,48 +773,78 @@ void BitmapOutputDev::updateFillColor(GfxState *state) } void BitmapOutputDev::updateStrokeColor(GfxState *state) { + boolpolydev->updateStrokeColor(state); + booltextdev->updateStrokeColor(state); rgbdev->updateStrokeColor(state); clip0dev->updateStrokeColor(state); clip1dev->updateStrokeColor(state); + if(!config_bitmapfonts) + gfxdev->updateStrokeColor(state); } void BitmapOutputDev::updateBlendMode(GfxState *state) { + boolpolydev->updateBlendMode(state); + booltextdev->updateBlendMode(state); rgbdev->updateBlendMode(state); clip0dev->updateBlendMode(state); clip1dev->updateBlendMode(state); + if(!config_bitmapfonts) + gfxdev->updateBlendMode(state); } void BitmapOutputDev::updateFillOpacity(GfxState *state) { + boolpolydev->updateFillOpacity(state); + booltextdev->updateFillOpacity(state); rgbdev->updateFillOpacity(state); clip0dev->updateFillOpacity(state); clip1dev->updateFillOpacity(state); + if(!config_bitmapfonts) + gfxdev->updateFillOpacity(state); } void BitmapOutputDev::updateStrokeOpacity(GfxState *state) { + boolpolydev->updateStrokeOpacity(state); + booltextdev->updateStrokeOpacity(state); rgbdev->updateStrokeOpacity(state); clip0dev->updateStrokeOpacity(state); clip1dev->updateStrokeOpacity(state); + if(!config_bitmapfonts) + gfxdev->updateStrokeOpacity(state); } void BitmapOutputDev::updateFillOverprint(GfxState *state) { + boolpolydev->updateFillOverprint(state); + booltextdev->updateFillOverprint(state); rgbdev->updateFillOverprint(state); clip0dev->updateFillOverprint(state); clip1dev->updateFillOverprint(state); + if(!config_bitmapfonts) + gfxdev->updateFillOverprint(state); } void BitmapOutputDev::updateStrokeOverprint(GfxState *state) { + boolpolydev->updateStrokeOverprint(state); + booltextdev->updateStrokeOverprint(state); rgbdev->updateStrokeOverprint(state); clip0dev->updateStrokeOverprint(state); clip1dev->updateStrokeOverprint(state); + if(!config_bitmapfonts) + gfxdev->updateStrokeOverprint(state); } void BitmapOutputDev::updateTransfer(GfxState *state) { + boolpolydev->updateTransfer(state); + booltextdev->updateTransfer(state); rgbdev->updateTransfer(state); clip0dev->updateTransfer(state); clip1dev->updateTransfer(state); + if(!config_bitmapfonts) + gfxdev->updateTransfer(state); } void BitmapOutputDev::updateFont(GfxState *state) { + boolpolydev->updateFont(state); + booltextdev->updateFont(state); rgbdev->updateFont(state); clip0dev->updateFont(state); clip1dev->updateFont(state); @@ -484,6 +853,8 @@ void BitmapOutputDev::updateFont(GfxState *state) } void BitmapOutputDev::updateTextMat(GfxState *state) { + boolpolydev->updateTextMat(state); + booltextdev->updateTextMat(state); rgbdev->updateTextMat(state); clip0dev->updateTextMat(state); clip1dev->updateTextMat(state); @@ -492,6 +863,8 @@ void BitmapOutputDev::updateTextMat(GfxState *state) } void BitmapOutputDev::updateCharSpace(GfxState *state) { + boolpolydev->updateCharSpace(state); + booltextdev->updateCharSpace(state); rgbdev->updateCharSpace(state); clip0dev->updateCharSpace(state); clip1dev->updateCharSpace(state); @@ -500,6 +873,8 @@ void BitmapOutputDev::updateCharSpace(GfxState *state) } void BitmapOutputDev::updateRender(GfxState *state) { + boolpolydev->updateRender(state); + booltextdev->updateRender(state); rgbdev->updateRender(state); clip0dev->updateRender(state); clip1dev->updateRender(state); @@ -508,6 +883,8 @@ void BitmapOutputDev::updateRender(GfxState *state) } void BitmapOutputDev::updateRise(GfxState *state) { + boolpolydev->updateRise(state); + booltextdev->updateRise(state); rgbdev->updateRise(state); clip0dev->updateRise(state); clip1dev->updateRise(state); @@ -516,6 +893,8 @@ void BitmapOutputDev::updateRise(GfxState *state) } void BitmapOutputDev::updateWordSpace(GfxState *state) { + boolpolydev->updateWordSpace(state); + booltextdev->updateWordSpace(state); rgbdev->updateWordSpace(state); clip0dev->updateWordSpace(state); clip1dev->updateWordSpace(state); @@ -524,6 +903,8 @@ void BitmapOutputDev::updateWordSpace(GfxState *state) } void BitmapOutputDev::updateHorizScaling(GfxState *state) { + boolpolydev->updateHorizScaling(state); + booltextdev->updateHorizScaling(state); rgbdev->updateHorizScaling(state); clip0dev->updateHorizScaling(state); clip1dev->updateHorizScaling(state); @@ -532,6 +913,8 @@ void BitmapOutputDev::updateHorizScaling(GfxState *state) } void BitmapOutputDev::updateTextPos(GfxState *state) { + boolpolydev->updateTextPos(state); + booltextdev->updateTextPos(state); rgbdev->updateTextPos(state); clip0dev->updateTextPos(state); clip1dev->updateTextPos(state); @@ -540,6 +923,8 @@ void BitmapOutputDev::updateTextPos(GfxState *state) } void BitmapOutputDev::updateTextShift(GfxState *state, double shift) { + boolpolydev->updateTextShift(state, shift); + booltextdev->updateTextShift(state, shift); rgbdev->updateTextShift(state, shift); clip0dev->updateTextShift(state, shift); clip1dev->updateTextShift(state, shift); @@ -550,19 +935,25 @@ void BitmapOutputDev::updateTextShift(GfxState *state, double shift) void BitmapOutputDev::stroke(GfxState *state) { msg(" stroke"); + boolpolydev->stroke(state); + checkNewBitmap(); rgbdev->stroke(state); } void BitmapOutputDev::fill(GfxState *state) { msg(" fill"); + boolpolydev->fill(state); + checkNewBitmap(); rgbdev->fill(state); } void BitmapOutputDev::eoFill(GfxState *state) { msg(" eoFill"); + boolpolydev->eoFill(state); + checkNewBitmap(); rgbdev->eoFill(state); } -#if (xpdfMajorVersion < 3) || (xpdfMinorVersion < 2) || (xpdfUpdateVersion < 7) +#if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207 void BitmapOutputDev::tilingPatternFill(GfxState *state, Object *str, int paintType, Dict *resDict, double *mat, double *bbox, @@ -570,6 +961,8 @@ void BitmapOutputDev::tilingPatternFill(GfxState *state, Object *str, double xStep, double yStep) { msg(" tilingPatternFill"); + boolpolydev->tilingPatternFill(state, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep); + checkNewBitmap(); rgbdev->tilingPatternFill(state, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep); } #else @@ -580,6 +973,8 @@ void BitmapOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Object *str, double xStep, double yStep) { msg(" tilingPatternFill"); + boolpolydev->tilingPatternFill(state, gfx, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep); + checkNewBitmap(); rgbdev->tilingPatternFill(state, gfx, str, paintType, resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep); } #endif @@ -587,55 +982,49 @@ void BitmapOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Object *str, GBool BitmapOutputDev::functionShadedFill(GfxState *state, GfxFunctionShading *shading) { msg(" functionShadedFill"); + boolpolydev->functionShadedFill(state, shading); + checkNewBitmap(); return rgbdev->functionShadedFill(state, shading); } GBool BitmapOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading) { msg(" axialShadedFill"); + boolpolydev->axialShadedFill(state, shading); + checkNewBitmap(); return rgbdev->axialShadedFill(state, shading); } GBool BitmapOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading) { msg(" radialShadedFill"); + boolpolydev->radialShadedFill(state, shading); + checkNewBitmap(); return rgbdev->radialShadedFill(state, shading); } SplashColor black = {0,0,0}; SplashColor white = {255,255,255}; -void BitmapOutputDev::doClip(GfxState *state, GBool eo) -{ - if(!eo) { - rgbdev->clip(state); - clip1dev->clip(state); - } else { - rgbdev->eoClip(state); - clip1dev->eoClip(state); - } - - //SplashPattern *pblack = new SplashSolidColor(black); - //SplashPattern *pwhite = new SplashSolidColor(white); - //SplashPath* path = rgbdev->convertPath(state, state->getPath()); - //clipdev->clear(black, 0); - //clipdev->clipToPath(path, eo); - //clipdev->setFillPattern(pwhite); - //clipdev->fill(bboxpath,gFalse); - //delete path; -} - void BitmapOutputDev::clip(GfxState *state) { msg(" clip"); - doClip(state, gFalse); + boolpolydev->clip(state); + booltextdev->clip(state); + rgbdev->clip(state); + clip1dev->clip(state); } void BitmapOutputDev::eoClip(GfxState *state) { msg(" eoClip"); - doClip(state, gTrue); + boolpolydev->eoClip(state); + booltextdev->eoClip(state); + rgbdev->eoClip(state); + clip1dev->eoClip(state); } void BitmapOutputDev::clipToStrokePath(GfxState *state) { msg(" clipToStrokePath"); + boolpolydev->clipToStrokePath(state); + booltextdev->clipToStrokePath(state); rgbdev->clipToStrokePath(state); clip1dev->clipToStrokePath(state); } @@ -648,6 +1037,7 @@ void BitmapOutputDev::beginStringOp(GfxState *state) clip0dev->beginStringOp(state); clip1dev->beginStringOp(state); } else { + booltextdev->beginStringOp(state); gfxdev->beginStringOp(state); } } @@ -659,6 +1049,8 @@ void BitmapOutputDev::endStringOp(GfxState *state) clip0dev->endStringOp(state); clip1dev->endStringOp(state); } else { + booltextdev->endStringOp(state); + checkNewText(); gfxdev->endStringOp(state); } } @@ -670,6 +1062,7 @@ void BitmapOutputDev::beginString(GfxState *state, GString *s) clip0dev->beginString(state, s); clip1dev->beginString(state, s); } else { + booltextdev->beginString(state, s); gfxdev->beginString(state, s); } } @@ -681,9 +1074,25 @@ void BitmapOutputDev::endString(GfxState *state) clip0dev->endString(state); clip1dev->endString(state); } else { + booltextdev->endString(state); + checkNewText(); gfxdev->endString(state); } } + +void BitmapOutputDev::clearClips() +{ + clearBooleanDev(clip0dev); + clearBooleanDev(clip1dev); +} +void BitmapOutputDev::clearBoolPolyDev() +{ + clearBooleanDev(boolpolydev); +} +void BitmapOutputDev::clearBoolTextDev() +{ + clearBooleanDev(booltextdev); +} void BitmapOutputDev::drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, @@ -693,21 +1102,17 @@ void BitmapOutputDev::drawChar(GfxState *state, double x, double y, if(this->config_bitmapfonts || (state->getRender()&4) /*clip*/ ) { rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen); } else { - SplashBitmap*clip0 = clip0dev->getBitmap(); - SplashBitmap*clip1 = clip1dev->getBitmap(); - int width8 = (clip0->getWidth()+7)/8; - int width = clip0->getWidth(); - int height = clip0->getHeight(); - memset(clip0->getDataPtr(), 0, width8*height); - memset(clip1->getDataPtr(), 0, width8*height); + 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); /* 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(memcmp(clip0->getDataPtr(), clip1->getDataPtr(), width8*height)) { + if(clip0and1differ()) { msg(" Char %d is affected by clipping", code); + boolpolydev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen); + checkNewBitmap(); rgbdev->drawChar(state, x, y, dx, dy, originX, originY, code, nBytes, u, uLen); if(config_extrafontdata) { int oldrender = state->getRender(); @@ -716,51 +1121,34 @@ void BitmapOutputDev::drawChar(GfxState *state, double x, double y, state->setRender(oldrender); } } else { - /* this char is not at all affected by clipping. Now just find out whether the - bitmap we're currently working on needs to be dumped out first, - by checking whether any of the char pixels in clip1dev is above any non-alpha - pixels in rgbdev */ - - Guchar*alpha = rgbdev->getBitmap()->getAlphaPtr(); - Guchar*charpixels = clip1dev->getBitmap()->getDataPtr(); - int xx,yy; - for(yy=0;yy>3; - /* TODO: is the bit order correct? */ - if(aline[xx] && (cline[bytepos]&(1< Char %d is above current bitmap data", code); - flush(); - } + /* 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(); + /* 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"); + msg(" internal error: drawString not implemented"); + return; if(this->config_bitmapfonts) { rgbdev->drawString(state, s); clip0dev->drawString(state, s); clip1dev->drawString(state, s); } else { + booltextdev->drawString(state, s); gfxdev->drawString(state, s); } } void BitmapOutputDev::endTextObject(GfxState *state) { + /* FIXME: the below might render things (stroke outlines etc.) to gfxdev which + might end up unflushed- should be handled similarily as + drawChar() above + */ msg(" endTextObject"); if(this->config_bitmapfonts) { rgbdev->endTextObject(state); @@ -770,6 +1158,9 @@ void BitmapOutputDev::endTextObject(GfxState *state) gfxdev->endType3Char(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) @@ -778,6 +1169,8 @@ GBool BitmapOutputDev::beginType3Char(GfxState *state, double x, double y, if(this->config_bitmapfonts) { return rgbdev->beginType3Char(state, x, y, dx, dy, code, u, uLen); } else { + /* 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); } } @@ -813,6 +1206,8 @@ void BitmapOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, GBool inlineImg) { msg(" drawImageMask"); + boolpolydev->drawImageMask(state, ref, str, width, height, invert, inlineImg); + checkNewBitmap(); rgbdev->drawImageMask(state, ref, str, width, height, invert, inlineImg); } void BitmapOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, @@ -820,6 +1215,8 @@ void BitmapOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int *maskColors, GBool inlineImg) { msg(" drawImage"); + boolpolydev->drawImage(state, ref, str, width, height, colorMap, maskColors, inlineImg); + checkNewBitmap(); rgbdev->drawImage(state, ref, str, width, height, colorMap, maskColors, inlineImg); } void BitmapOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, @@ -829,6 +1226,8 @@ void BitmapOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, GBool maskInvert) { msg(" drawMaskedImage"); + boolpolydev->drawMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert); + checkNewBitmap(); rgbdev->drawMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert); } void BitmapOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, @@ -839,11 +1238,15 @@ void BitmapOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream * GfxImageColorMap *maskColorMap) { msg(" drawSoftMaskedImage"); + boolpolydev->drawSoftMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap); + checkNewBitmap(); rgbdev->drawSoftMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap); } void BitmapOutputDev::drawForm(Ref id) { msg(" drawForm"); + boolpolydev->drawForm(id); + checkNewBitmap(); rgbdev->drawForm(id); } @@ -865,23 +1268,31 @@ void BitmapOutputDev::beginTransparencyGroup(GfxState *state, double *bbox, void BitmapOutputDev::endTransparencyGroup(GfxState *state) { msg(" endTransparencyGroup"); + boolpolydev->endTransparencyGroup(state); + checkNewBitmap(); rgbdev->endTransparencyGroup(state); clip1dev->endTransparencyGroup(state); } void BitmapOutputDev::paintTransparencyGroup(GfxState *state, double *bbox) { msg(" paintTransparencyGroup"); + boolpolydev->paintTransparencyGroup(state,bbox); + checkNewBitmap(); rgbdev->paintTransparencyGroup(state,bbox); } void BitmapOutputDev::setSoftMask(GfxState *state, double *bbox, GBool alpha, Function *transferFunc, GfxColor *backdropColor) { msg(" setSoftMask"); + boolpolydev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor); + checkNewBitmap(); rgbdev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor); clip1dev->setSoftMask(state, bbox, alpha, transferFunc, backdropColor); } void BitmapOutputDev::clearSoftMask(GfxState *state) { msg(" clearSoftMask"); + boolpolydev->clearSoftMask(state); + checkNewBitmap(); rgbdev->clearSoftMask(state); clip1dev->clearSoftMask(state); } diff --git a/lib/pdf/BitmapOutputDev.h b/lib/pdf/BitmapOutputDev.h index 23df08d..42b5071 100644 --- a/lib/pdf/BitmapOutputDev.h +++ b/lib/pdf/BitmapOutputDev.h @@ -38,6 +38,10 @@ struct ClipState ClipState(); }; +#define STATE_PARALLEL 0 +#define STATE_TEXT_IS_ABOVE 1 +#define STATE_BITMAP_IS_ABOVE 2 + class BitmapOutputDev: public CommonOutputDev { public: BitmapOutputDev(InfoOutputDev*info, PDFDoc*doc); @@ -123,7 +127,6 @@ public: virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading); virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading); - void doClip(GfxState *state, GBool eo); virtual void clip(GfxState *state); virtual void eoClip(GfxState *state); virtual void clipToStrokePath(GfxState *state); @@ -179,13 +182,24 @@ public: virtual void setVectorAntialias(GBool vaa); virtual GBool getVectorAntialias(); + private: - void flush(); + void clearClips(); + void clearBoolPolyDev(); + void clearBoolTextDev(); + void flushText(); + void flushBitmap(); + void checkNewText(); + void checkNewBitmap(); + GBool clip0and1differ(); + GBool intersection(); char config_bitmapfonts; char config_extrafontdata; + int layerstate; + SplashPath*bboxpath; PDFDoc*doc; @@ -193,6 +207,10 @@ private: SplashOutputDev*rgbdev; SplashOutputDev*clip0dev; SplashOutputDev*clip1dev; + SplashOutputDev*boolpolydev; + SplashOutputDev*booltextdev; + + gfxdevice_t* gfxoutput; GFXOutputDev*gfxdev; InfoOutputDev*info; gfxdevice_t*dev; -- 1.7.10.4