X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=blobdiff_plain;f=lib%2Fpdf%2FBitmapOutputDev.cc;h=6eaea6bcb461ff4c9b68c82464c85a37a25f7113;hp=2851f09642f43c71e61f36462c874d377b26dcea;hb=b43d07ef45012438211d2ed4b588e77b73a1994c;hpb=5150420d30de70031c50b95e52bec8c5fe74651d diff --git a/lib/pdf/BitmapOutputDev.cc b/lib/pdf/BitmapOutputDev.cc index 2851f09..6eaea6b 100644 --- a/lib/pdf/BitmapOutputDev.cc +++ b/lib/pdf/BitmapOutputDev.cc @@ -30,6 +30,7 @@ #include "../png.h" #include "../devices/record.h" #include "../types.h" +#include "bbox.h" #define UNKNOWN_BOUNDING_BOX 0,0,0,0 @@ -53,7 +54,7 @@ BitmapOutputDev::BitmapOutputDev(InfoOutputDev*info, PDFDoc*doc) this->rgbdev = new SplashOutputDev(splashModeRGB8, 1, gFalse, splash_white, gTrue, gTrue); /* color mode for binary bitmaps */ - SplashColorMode colorMode = splashModeMono8; + SplashColorMode colorMode = splashModeMono1; /* two devices for testing things against clipping: one clips, the other doesn't */ this->clip0dev = new SplashOutputDev(colorMode, 1, gFalse, splash_black, gTrue, gFalse); @@ -153,135 +154,121 @@ void BitmapOutputDev::setParameter(const char*key, const char*value) } this->gfxdev->setParameter(key, value); } -void BitmapOutputDev::preparePage(int pdfpage, int outputpage) +void BitmapOutputDev::setPageMap(int*page2page, int num_pages) { + this->gfxdev->setPageMap(page2page, num_pages); } -static void getBitmapBBox(Guchar*alpha, int width, int height, int*xmin, int*ymin, int*xmax, int*ymax) -{ - *ymin = -1; - *xmin = width; - *xmax = 0; - int x,y; - for(y=0;y*xmax) *xmax = right; - } - } - if(*xmin>=*xmax || *ymin>=*ymax) { - *xmin = 0; - *ymin = 0; - *xmax = 0; - *ymax = 0; - } -} +void writeBitmap(SplashBitmap*bitmap, char*filename); void BitmapOutputDev::flushBitmap() { int width = rgbdev->getBitmapWidth(); int height = rgbdev->getBitmapHeight(); + + if(sizeof(SplashColor)!=3) { + msg(" sizeof(SplashColor)!=3"); + return; + } + + /*static int counter=0; + if(!counter) { + writeBitmap(rgbdev->getBitmap(), "test.png"); + } counter++;*/ SplashColorPtr rgb = rgbbitmap->getDataPtr(); Guchar*alpha = rgbbitmap->getAlphaPtr(); - Guchar*alpha2 = boolpolybitmap->getAlphaPtr(); + + Guchar*alpha2 = boolpolybitmap->getDataPtr(); + int width8 = (boolpolybitmap->getWidth()+7)/8; - int xmin,ymin,xmax,ymax; - getBitmapBBox(alpha, width, height, &xmin,&ymin,&xmax,&ymax); + ibbox_t* boxes = get_bitmap_bboxes((unsigned char*)alpha, width, height); + ibbox_t*b; - /* 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; + for(b=boxes;b;b=b->next) { + int xmin = b->xmin; + int ymin = b->ymin; + int xmax = b->xmax; + int ymax = b->ymax; - if(sizeof(SplashColor)!=3) { - msg(" sizeof(SplashColor)!=3"); - return; - } - //xmin = ymin = 0; - //xmax = width; - //ymax = height; - - int rangex = xmax-xmin; - int rangey = ymax-ymin; - gfximage_t*img = (gfximage_t*)malloc(sizeof(gfximage_t)); - img->data = (gfxcolor_t*)malloc(rangex * rangey * 4); - img->width = rangex; - img->height = rangey; - int x,y; - for(y=0;ydata[y*rangex]; - Guchar*ain = &alpha[(y+ymin)*width+xmin]; - Guchar*ain2 = &alpha2[(y+ymin)*width+xmin]; - if(this->emptypage) { - for(x=0;xmovex) 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 + continue; + + int rangex = xmax-xmin; + int rangey = ymax-ymin; + gfximage_t*img = (gfximage_t*)malloc(sizeof(gfximage_t)); + img->data = (gfxcolor_t*)malloc(rangex * rangey * 4); + img->width = rangex; + img->height = rangey; + int x,y; + for(y=0;ydata[y*rangex]; + Guchar*ain = &alpha[(y+ymin)*width+xmin]; + Guchar*ain2 = &alpha2[(y+ymin)*width8]; + if(this->emptypage) { + for(x=0;x>(x&7)))) { + /* cut away pixels that we don't remember drawing (i.e., that are + not in the monochrome bitmap. Prevents some "hairlines" showing + up to the left and right of bitmaps */ + out[x].r = 0;out[x].g = 0;out[x].b = 0;out[x].a = 0; + } else { + /* according to endPage()/compositeBackground() in xpdf/SplashOutputDev.cc, we + have to premultiply alpha (mix background and pixel according to the alpha channel). + */ + out[x].r = (in[x*3+0]*ain[x])/255; + out[x].g = (in[x*3+1]*ain[x])/255; + out[x].b = (in[x*3+2]*ain[x])/255; + out[x].a = ain[x]; + } + } } } + + /* transform bitmap rectangle to "device space" */ + xmin += movex; + ymin += movey; + xmax += movex; + ymax += movey; + + gfxmatrix_t m; + m.tx = xmin; + 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); + gfxline_free(line); + + free(img->data);img->data=0;free(img);img=0; } - /* transform bitmap rectangle to "device space" */ - xmin += movex; - ymin += movey; - xmax += movex; - ymax += movey; - - gfxmatrix_t m; - m.tx = xmin; - 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); - gfxline_free(line); + ibbox_destroy(boxes); 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; } @@ -293,6 +280,30 @@ void BitmapOutputDev::flushText() this->emptypage = 0; } +void writeMonoBitmap(SplashBitmap*btm, char*filename) +{ + int width8 = (btm->getWidth()+7)/8; + int width = btm->getWidth(); + int height = btm->getHeight(); + gfxcolor_t*b = (gfxcolor_t*)malloc(sizeof(gfxcolor_t)*width*height); + unsigned char*data = btm->getDataPtr(); + int x,y; + for(y=0;y>3]&(128>>(x&7))) { + d[x].r = d[x].g = d[x].b = 255; + } else { + d[x].r = d[x].g = d[x].b = 0; + } + d[x].a = 255; + } + } + writePNG(filename, (unsigned char*)b, width, height); + free(b); +} + void writeBitmap(SplashBitmap*bitmap, char*filename) { int y,x; @@ -302,16 +313,20 @@ void writeBitmap(SplashBitmap*bitmap, char*filename) gfxcolor_t*data = (gfxcolor_t*)malloc(sizeof(gfxcolor_t)*width*height); + if(bitmap->getMode()==splashModeMono1) { + writeMonoBitmap(bitmap, filename); + return; + } + 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; + line[x].a = bitmap->getAlpha(x,y); } } writePNG(filename, (unsigned char*)data, width, height); @@ -324,6 +339,11 @@ void writeAlpha(SplashBitmap*bitmap, char*filename) int width = bitmap->getWidth(); int height = bitmap->getHeight(); + + if(bitmap->getMode()==splashModeMono1) { + writeMonoBitmap(bitmap, filename); + return; + } gfxcolor_t*data = (gfxcolor_t*)malloc(sizeof(gfxcolor_t)*width*height); @@ -383,13 +403,13 @@ GBool BitmapOutputDev::checkNewText(int x1, int y1, int x2, int y2) 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) { + 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); msg(" %s %s %s", filename1, filename2, filename3); writeAlpha(boolpolybitmap, filename1); writeAlpha(booltextbitmap, filename2); @@ -442,14 +462,13 @@ 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) { + 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); msg(" %s %s %s", filename1, filename2, filename3); writeAlpha(boolpolybitmap, filename1); writeAlpha(booltextbitmap, filename2); @@ -499,62 +518,65 @@ GBool BitmapOutputDev::checkNewBitmap(int x1, int y1, int x2, int y2) // break; //} +static inline GBool fixBBox(int*x1, int*y1, int*x2, int*y2, int width, int height) +{ + if(!(*x1|*y1|*x2|*y2)) { + // undefined bbox + *x1 = *y1 = 0; + *x2 = width; + *y2 = height; + return gTrue; + } + if(*x2<=*x1) return gFalse; + if(*x2<0) return gFalse; + if(*x1<0) *x1 = 0; + if(*x1>=width) return gFalse; + if(*x2>width) *x2=width; + + if(*y2<=*y1) return gFalse; + if(*y2<0) return gFalse; + if(*y1<0) *y1 = 0; + if(*y1>=height) return gFalse; + if(*y2>height) *y2=height; + return gTrue; +} + GBool BitmapOutputDev::clip0and1differ(int x1,int y1,int x2,int y2) { if(clip0bitmap->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(); + int width = clip0bitmap->getWidth(); + int width8 = (width+7)/8; + int height = clip0bitmap->getHeight(); + + if(!fixBBox(&x1,&y1,&x2,&y2,width,height)) { + /* area is outside or null */ + return gFalse; + } 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)) + unsigned char*row2 = &clip1bitmap->getDataPtr()[width8*y+x18]; + if(memcmp(row1, row2, x28-x18)) { return gTrue; + } } 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(); + + if(!fixBBox(&x1, &y1, &x2, &y2, width, height)) { + x1=y1=0;x2=y2=1; + } + Guchar*a0 = clip0->getAlphaPtr(); Guchar*a1 = clip1->getAlphaPtr(); int x,y; @@ -599,14 +621,42 @@ static void clearBooleanBitmap(SplashBitmap*btm, int x1, int y1, int x2, int y2) } } -long long unsigned int compare64(long long unsigned int*data1, long long unsigned int*data2, int len) +GBool compare8(unsigned char*data1, unsigned char*data2, int len) { - long long unsigned int c; + if(!len) + return 0; + if(((ptroff_t)data1&7)==((ptroff_t)data2&7)) { + // oh good, we can do aligning + while((ptroff_t)data1&7) { + if(*data1&*data2) + return 1; + data1++; + data2++; + if(!--len) + return 0; + } + } + /* use 64 bit for the (hopefully aligned) middle section */ + int l8 = len/8; + long long unsigned int*d1 = (long long unsigned int*)data1; + long long unsigned int*d2 = (long long unsigned int*)data2; + long long unsigned int x = 0; int t; + for(t=0;tgetMode()==splashModeMono1) { /* alternative implementation, using one bit per pixel- needs the no-dither patch in xpdf */ + + int width = boolpoly->getWidth(); + int height = boolpoly->getHeight(); - 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; + if(!fixBBox(&x1,&y1,&x2,&y2, width, height)) { + return gFalse; + } Guchar*polypixels = boolpoly->getDataPtr(); Guchar*textpixels = booltext->getDataPtr(); - int width = boolpoly->getWidth(); - int height = boolpoly->getHeight(); int width8 = (width+7)/8; int runx = width8; int runy = height; @@ -650,32 +698,26 @@ GBool BitmapOutputDev::intersection(int x1, int y1, int x2, int y2) }*/ int x,y; + unsigned char*data1 = (unsigned char*)polypixels; + unsigned char*data2 = (unsigned char*)textpixels; + msg(" Testing area (%d,%d,%d,%d), runx=%d,runy=%d", x1,y1,x2,y2, runx, runy); 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(); + if(!fixBBox(&x1, &y1, &x2, &y2, width, height)) { + x1=y1=0;x2=y2=1; + } + Guchar*polypixels = boolpoly->getAlphaPtr(); + Guchar*textpixels = booltext->getAlphaPtr(); + int x,y; char overlap1 = 0; char overlap2 = 0; @@ -708,7 +750,7 @@ GBool BitmapOutputDev::intersection(int x1, int y1, int x2, int y2) 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"); + //writeAlpha(booltextbitmap, "alpha.png"); } return overlap2; } @@ -1356,7 +1398,9 @@ 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); + SplashFont*font = clip0dev->getCurrentFont(); + SplashPath*path = font?font->getGlyphPath(code):NULL; + if(!path) { if(code) msg(" couldn't create outline for char %d", code); @@ -1392,6 +1436,7 @@ void BitmapOutputDev::drawChar(GfxState *state, double x, double y, 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);