3 Output Device which creates a bitmap.
5 Swftools is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 Swftools is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with swftools; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
24 #include "BitmapOutputDev.h"
25 #include "GFXOutputDev.h"
26 #include "SplashBitmap.h"
27 #include "SplashPattern.h"
31 #include "../devices/record.h"
32 #include "../gfxtools.h"
36 #define UNKNOWN_BOUNDING_BOX 0,0,0,0
38 static SplashColor splash_white
= {255,255,255};
39 static SplashColor splash_black
= {0,0,0};
41 ClipState::ClipState()
48 BitmapOutputDev::BitmapOutputDev(InfoOutputDev
*info
, PDFDoc
*doc
)
52 this->xref
= doc
->getXRef();
54 /* color graphic output device, for creating bitmaps */
55 this->rgbdev
= new SplashOutputDev(splashModeRGB8
, 1, gFalse
, splash_white
, gTrue
, gTrue
);
57 /* color mode for binary bitmaps */
58 SplashColorMode colorMode
= splashModeMono1
;
60 /* two devices for testing things against clipping: one clips, the other doesn't */
61 this->clip0dev
= new SplashOutputDev(colorMode
, 1, gFalse
, splash_black
, gTrue
, gFalse
);
62 this->clip1dev
= new SplashOutputDev(colorMode
, 1, gFalse
, splash_black
, gTrue
, gFalse
);
64 /* device indicating where polygonal pixels were drawn */
65 this->boolpolydev
= new SplashOutputDev(colorMode
, 1, gFalse
, splash_black
, gTrue
, gFalse
);
66 /* device indicating where text pixels were drawn */
67 this->booltextdev
= new SplashOutputDev(colorMode
, 1, gFalse
, splash_black
, gTrue
, gFalse
);
69 /* device for handling texts and links */
70 this->gfxdev
= new GFXOutputDev(info
, this->doc
);
72 this->rgbdev
->startDoc(this->xref
);
73 this->boolpolydev
->startDoc(this->xref
);
74 this->booltextdev
->startDoc(this->xref
);
75 this->clip0dev
->startDoc(this->xref
);
76 this->clip1dev
->startDoc(this->xref
);
78 this->gfxoutput
= (gfxdevice_t
*)malloc(sizeof(gfxdevice_t
));
79 gfxdevice_record_init(this->gfxoutput
, 0);
81 this->gfxdev
->setDevice(this->gfxoutput
);
83 this->config_extrafontdata
= 0;
84 this->config_optimizeplaincolorfills
= 0;
87 //this->clipstates = 0;
89 BitmapOutputDev::~BitmapOutputDev()
92 gfxresult_t
*r
= this->gfxoutput
->finish(this->gfxoutput
);
94 free(this->gfxoutput
);this->gfxoutput
= 0;
97 delete this->bboxpath
;this->bboxpath
= 0;
100 delete this->rgbdev
;this->rgbdev
= 0;
103 delete this->gfxdev
;this->gfxdev
= 0;
105 if(this->boolpolydev
) {
106 delete this->boolpolydev
;this->boolpolydev
= 0;
108 if(this->stalepolybitmap
) {
109 delete this->stalepolybitmap
;this->stalepolybitmap
= 0;
111 if(this->staletextbitmap
) {
112 delete this->staletextbitmap
;this->staletextbitmap
= 0;
114 if(this->booltextdev
) {
115 delete this->booltextdev
;this->booltextdev
= 0;
118 delete this->clip0dev
;this->clip0dev
= 0;
121 delete this->clip1dev
;this->clip1dev
= 0;
123 //if(this->clipbitmap) {
124 // delete this->clipbitmap;this->clipbitmap = 0;
126 //if(this->clipdev) {
127 // delete this->clipdev;this->clipdev = 0;
132 GBool
BitmapOutputDev::getVectorAntialias()
134 return this->rgbdev
->getVectorAntialias();
136 void BitmapOutputDev::setVectorAntialias(GBool vaa
)
138 this->rgbdev
->setVectorAntialias(vaa
);
140 void BitmapOutputDev::setDevice(gfxdevice_t
*dev
)
144 void BitmapOutputDev::setMove(int x
,int y
)
146 this->gfxdev
->setMove(x
,y
);
147 this->user_movex
= x
;
148 this->user_movey
= y
;
150 void BitmapOutputDev::setClip(int x1
,int y1
,int x2
,int y2
)
152 this->gfxdev
->setClip(x1
,y1
,x2
,y2
);
153 this->user_clipx1
= x1
;
154 this->user_clipy1
= y1
;
155 this->user_clipx2
= x2
;
156 this->user_clipy2
= y2
;
158 void BitmapOutputDev::setParameter(const char*key
, const char*value
)
160 if(!strcmp(key
, "extrafontdata")) {
161 this->config_extrafontdata
= atoi(value
);
163 this->gfxdev
->setParameter(key
, value
);
165 void BitmapOutputDev::setPageMap(int*page2page
, int num_pages
)
167 this->gfxdev
->setPageMap(page2page
, num_pages
);
170 void writeBitmap(SplashBitmap
*bitmap
, char*filename
);
171 void writeAlpha(SplashBitmap
*bitmap
, char*filename
);
173 static int dbg_btm_counter
=1;
175 void BitmapOutputDev::flushBitmap()
177 int width
= rgbdev
->getBitmapWidth();
178 int height
= rgbdev
->getBitmapHeight();
180 if(sizeof(SplashColor
)!=3) {
181 msg("<error> sizeof(SplashColor)!=3");
185 /*static int counter=0;
187 writeBitmap(rgbdev->getBitmap(), "test.png");
190 /*static int counter=0;
192 sprintf(filename, "test%d.png", counter++);
193 writeBitmap(rgbbitmap, filename);*/
195 SplashColorPtr rgb
= rgbbitmap
->getDataPtr();
196 Guchar
*alpha
= rgbbitmap
->getAlphaPtr();
198 Guchar
*alpha2
= stalepolybitmap
->getDataPtr();
199 int width8
= (stalepolybitmap
->getWidth()+7)/8;
202 sprintf(filename, "flush%d_mask.png", dbg_btm_counter);
203 writeAlpha(stalepolybitmap, filename);
204 sprintf(filename, "flush%d_alpha.png", dbg_btm_counter);
205 writeAlpha(rgbbitmap, filename);
206 sprintf(filename, "flush%d_bitmap.png", dbg_btm_counter);
207 writeBitmap(rgbbitmap, filename);*/
209 ibbox_t
* boxes
= get_bitmap_bboxes((unsigned char*)alpha
, width
, height
);
212 for(b
=boxes
;b
;b
=b
->next
) {
218 /* clip against (-movex, -movey, -movex+width, -movey+height) */
220 msg("<verbose> Flushing bitmap (bbox: %d,%d,%d,%d %dx%d) (clipped against %d,%d,%d,%d)", xmin
,ymin
,xmax
,ymax
, xmax
-xmin
, ymax
-ymin
,
221 -this->movex
, -this->movey
, -this->movex
+this->width
, -this->movey
+this->height
);
223 if(xmin
< -this->movex
) {
225 if(xmax
< -this->movex
) continue;
227 if(ymin
< -this->movey
) {
229 if(ymax
< -this->movey
) continue;
231 if(xmax
>= -this->movex
+ this->width
) {
232 xmax
= -this->movex
+this->width
;
233 if(xmin
>= -this->movex
+ this->width
) continue;
235 if(ymax
>= -this->movey
+ this->height
) {
236 ymax
= -this->movey
+this->height
;
237 if(ymin
>= -this->movey
+ this->height
) continue;
240 if((xmax
-xmin
)<=0 || (ymax
-ymin
)<=0) // no bitmap, nothing to do
243 int rangex
= xmax
-xmin
;
244 int rangey
= ymax
-ymin
;
245 gfximage_t
*img
= (gfximage_t
*)malloc(sizeof(gfximage_t
));
246 img
->data
= (gfxcolor_t
*)malloc(rangex
* rangey
* 4);
248 img
->height
= rangey
;
250 for(y
=0;y
<rangey
;y
++) {
251 SplashColorPtr in
=&rgb
[((y
+ymin
)*width
+xmin
)*sizeof(SplashColor
)];
252 gfxcolor_t
*out
= &img
->data
[y
*rangex
];
253 Guchar
*ain
= &alpha
[(y
+ymin
)*width
+xmin
];
254 Guchar
*ain2
= &alpha2
[(y
+ymin
)*width8
];
255 if(this->emptypage
) {
256 for(x
=0;x
<rangex
;x
++) {
257 /* the first bitmap on the page doesn't need to have an alpha channel-
258 blend against a white background*/
259 out
[x
].r
= (in
[x
*3+0]*ain
[x
])/255 + 255-ain
[x
];
260 out
[x
].g
= (in
[x
*3+1]*ain
[x
])/255 + 255-ain
[x
];
261 out
[x
].b
= (in
[x
*3+2]*ain
[x
])/255 + 255-ain
[x
];
265 for(x
=0;x
<rangex
;x
++) {
266 if(!(ain2
[(x
+xmin
)/8]&(0x80>>((x
+xmin
)&7)))) {
267 /* cut away pixels that we don't remember drawing (i.e., that are
268 not in the monochrome bitmap). Prevents some "hairlines" showing
269 up to the left and right of bitmaps. */
270 out
[x
].r
= 0;out
[x
].g
= 0;out
[x
].b
= 0;out
[x
].a
= 0;
272 /* according to endPage()/compositeBackground() in xpdf/SplashOutputDev.cc, this
273 data has non-premultiplied alpha, which is exactly what the output device
274 expects, so don't premultiply it here, either.
276 out
[x
].r
= in
[x
*3+0];
277 out
[x
].g
= in
[x
*3+1];
278 out
[x
].b
= in
[x
*3+2];
285 /* transform bitmap rectangle to "device space" */
299 gfxline_t
* line
= gfxline_makerectangle(xmin
, ymin
, xmax
, ymax
);
300 dev
->fillbitmap(dev
, line
, img
, &m
, 0);
303 free(img
->data
);img
->data
=0;free(img
);img
=0;
305 ibbox_destroy(boxes
);
307 memset(rgbbitmap
->getAlphaPtr(), 0, rgbbitmap
->getWidth()*rgbbitmap
->getHeight());
308 memset(rgbbitmap
->getDataPtr(), 0, rgbbitmap
->getRowSize()*rgbbitmap
->getHeight());
313 void BitmapOutputDev::flushText()
315 msg("<verbose> Flushing text");
317 static gfxfontlist_t
*output_font_list
= 0;
318 static gfxdevice_t
*last
= 0;
319 if(last
!= this->dev
) {
321 gfxfontlist_free(output_font_list
, 0);
322 output_font_list
= gfxfontlist_create();
324 gfxdevice_record_flush(this->gfxoutput
, this->dev
, &output_font_list
);
330 void writeMonoBitmap(SplashBitmap
*btm
, char*filename
)
332 int width8
= (btm
->getWidth()+7)/8;
333 int width
= btm
->getWidth();
334 int height
= btm
->getHeight();
335 gfxcolor_t
*b
= (gfxcolor_t
*)malloc(sizeof(gfxcolor_t
)*width
*height
);
336 unsigned char*data
= btm
->getDataPtr();
338 for(y
=0;y
<height
;y
++) {
339 unsigned char*l
= &data
[width8
*y
];
340 gfxcolor_t
*d
= &b
[width
*y
];
341 for(x
=0;x
<width
;x
++) {
342 if(l
[x
>>3]&(128>>(x
&7))) {
343 d
[x
].r
= d
[x
].b
= d
[x
].a
= 255;
346 d
[x
].r
= d
[x
].g
= d
[x
].b
= d
[x
].a
= 0;
350 writePNG(filename
, (unsigned char*)b
, width
, height
);
354 void writeBitmap(SplashBitmap
*bitmap
, char*filename
)
358 int width
= bitmap
->getWidth();
359 int height
= bitmap
->getHeight();
361 gfxcolor_t
*data
= (gfxcolor_t
*)malloc(sizeof(gfxcolor_t
)*width
*height
);
363 if(bitmap
->getMode()==splashModeMono1
) {
364 writeMonoBitmap(bitmap
, filename
);
368 for(y
=0;y
<height
;y
++) {
369 gfxcolor_t
*line
= &data
[y
*width
];
370 for(x
=0;x
<width
;x
++) {
371 Guchar c
[4] = {0,0,0,0};
372 bitmap
->getPixel(x
,y
,c
);
376 line
[x
].a
= bitmap
->getAlpha(x
,y
);
379 writePNG(filename
, (unsigned char*)data
, width
, height
);
383 void writeAlpha(SplashBitmap
*bitmap
, char*filename
)
387 int width
= bitmap
->getWidth();
388 int height
= bitmap
->getHeight();
390 if(bitmap
->getMode()==splashModeMono1
) {
391 writeMonoBitmap(bitmap
, filename
);
395 gfxcolor_t
*data
= (gfxcolor_t
*)malloc(sizeof(gfxcolor_t
)*width
*height
);
397 for(y
=0;y
<height
;y
++) {
398 gfxcolor_t
*line
= &data
[y
*width
];
399 for(x
=0;x
<width
;x
++) {
400 int a
= bitmap
->getAlpha(x
,y
);
407 writePNG(filename
, (unsigned char*)data
, width
, height
);
411 static const char*STATE_NAME
[] = {"parallel", "textabovebitmap", "bitmapabovetext"};
413 int checkAlphaSanity(SplashBitmap
*boolbtm
, SplashBitmap
*alphabtm
)
415 assert(boolbtm
->getWidth() == alphabtm
->getWidth());
416 assert(boolbtm
->getHeight() == alphabtm
->getHeight());
417 if(boolbtm
->getMode()==splashModeMono1
) {
421 int width
= boolbtm
->getWidth();
422 int height
= boolbtm
->getHeight();
426 for(y
=0;y
<height
;y
++) {
427 for(x
=0;x
<width
;x
++) {
428 int a1
= alphabtm
->getAlpha(x
,y
);
429 int a2
= boolbtm
->getAlpha(x
,y
);
435 double badness
= bad
/(double)(width
*height
);
437 msg("<error> Bitmaps don't correspond: %d out of %d pixels wrong (%.2f%%)", bad
, width
*height
,
441 msg("<notice> %f", badness
);
445 static inline GBool
fixBBox(int*x1
, int*y1
, int*x2
, int*y2
, int width
, int height
)
447 if(!(*x1
|*y1
|*x2
|*y2
)) {
454 if(*x2
<=*x1
) return gFalse
;
455 if(*x2
<0) return gFalse
;
457 if(*x1
>=width
) return gFalse
;
458 if(*x2
>width
) *x2
=width
;
460 if(*y2
<=*y1
) return gFalse
;
461 if(*y2
<0) return gFalse
;
463 if(*y1
>=height
) return gFalse
;
464 if(*y2
>height
) *y2
=height
;
468 static void update_bitmap(SplashBitmap
*bitmap
, SplashBitmap
*update
, int x1
, int y1
, int x2
, int y2
, char overwrite
)
470 assert(bitmap
->getMode()==splashModeMono1
);
471 assert(update
->getMode()==splashModeMono1
);
473 int width8
= (bitmap
->getWidth()+7)/8;
474 assert(width8
== bitmap
->getRowSize());
475 assert(width8
== update
->getRowSize());
476 int height
= bitmap
->getHeight();
477 assert(height
== update
->getHeight());
479 if(!fixBBox(&x1
, &y1
, &x2
, &y2
, bitmap
->getWidth(), bitmap
->getHeight()))
482 Guchar
*b
= bitmap
->getDataPtr() + y1
*width8
+ x1
/8;
483 Guchar
*u
= update
->getDataPtr() + y1
*width8
+ x1
/8;
485 int xspan
= (x2
+7)/8 - x1
/8;
486 int size
= (y2
-y1
)*width8
;
490 for(y
=0;y
<yspan
;y
++) {
496 if(((ptroff_t
)b
&7)==((ptroff_t
)u
&7)) {
498 for(y
=0;y
<yspan
;y
++) {
499 Guchar
*e1
= b
+xspan
-8;
501 while(((ptroff_t
)b
&7) && b
<e1
) {
506 *(long long*)b
|= *(long long*)u
;
518 for(y
=0;y
<yspan
;y
++) {
519 for(x
=0;x
<xspan
;x
++) {
529 static void clearBooleanBitmap(SplashBitmap
*btm
, int x1
, int y1
, int x2
, int y2
)
531 if(!fixBBox(&x1
, &y1
, &x2
, &y2
, btm
->getWidth(), btm
->getHeight()))
534 if(btm
->getMode()==splashModeMono1
) {
535 int width8
= (btm
->getWidth()+7)/8;
536 assert(width8
== btm
->getRowSize());
537 int width
= btm
->getWidth();
538 int height
= btm
->getHeight();
539 Guchar
*data
= btm
->getDataPtr();
540 memset(data
+y1
*width8
, 0, width8
*(y2
-y1
));
542 int width
= btm
->getAlphaRowSize();
543 int height
= btm
->getHeight();
544 memset(btm
->getAlphaPtr(), 0, width
*height
);
548 void BitmapOutputDev::dbg_newdata(char*newdata
)
554 sprintf(filename1
, "state%03dboolbitmap_after%s.png", dbg_btm_counter
, newdata
);
555 sprintf(filename2
, "state%03dbooltext_after%s.png", dbg_btm_counter
, newdata
);
556 sprintf(filename3
, "state%03dbitmap_after%s.png", dbg_btm_counter
, newdata
);
557 msg("<verbose> %s %s %s", filename1
, filename2
, filename3
);
558 writeAlpha(stalepolybitmap
, filename1
);
559 writeAlpha(booltextbitmap
, filename2
);
560 writeBitmap(rgbdev
->getBitmap(), filename3
);
565 GBool
BitmapOutputDev::checkNewText(int x1
, int y1
, int x2
, int y2
)
567 /* called once some new text was drawn on booltextdev, and
568 before the same thing is drawn on gfxdev */
570 msg("<trace> Testing new text data against current bitmap data, state=%s, counter=%d\n", STATE_NAME
[layerstate
], dbg_btm_counter
);
573 if(intersection(booltextbitmap
, stalepolybitmap
, x1
,y1
,x2
,y2
)) {
574 if(layerstate
==STATE_PARALLEL
) {
575 /* the new text is above the bitmap. So record that fact. */
576 msg("<verbose> Text is above current bitmap/polygon data");
577 layerstate
=STATE_TEXT_IS_ABOVE
;
578 update_bitmap(staletextbitmap
, booltextbitmap
, x1
, y1
, x2
, y2
, 0);
579 } else if(layerstate
==STATE_BITMAP_IS_ABOVE
) {
580 /* there's a bitmap above the (old) text. So we need
581 to flush out that text, and record that the *new*
582 text is now *above* the bitmap
584 msg("<verbose> Text is above current bitmap/polygon data (which is above some other text)");
586 layerstate
=STATE_TEXT_IS_ABOVE
;
589 /* re-apply the update (which we would otherwise lose) */
590 update_bitmap(staletextbitmap
, booltextbitmap
, x1
, y1
, x2
, y2
, 1);
593 /* we already know that the current text section is
594 above the current bitmap section- now just new
595 bitmap data *and* new text data was drawn, and
596 *again* it's above the current bitmap. */
597 msg("<verbose> Text is still above current bitmap/polygon data");
598 update_bitmap(staletextbitmap
, booltextbitmap
, x1
, y1
, x2
, y2
, 0);
601 update_bitmap(staletextbitmap
, booltextbitmap
, x1
, y1
, x2
, y2
, 0);
604 /* clear the thing we just drew from our temporary drawing bitmap */
605 clearBooleanBitmap(booltextbitmap
, x1
, y1
, x2
, y2
);
609 GBool
BitmapOutputDev::checkNewBitmap(int x1
, int y1
, int x2
, int y2
)
611 /* similar to checkNewText() above, only in reverse */
612 msg("<trace> Testing new graphics data against current text data, state=%s, counter=%d\n", STATE_NAME
[layerstate
], dbg_btm_counter
);
615 if(intersection(boolpolybitmap
, staletextbitmap
, x1
,y1
,x2
,y2
)) {
616 if(layerstate
==STATE_PARALLEL
) {
617 msg("<verbose> Bitmap is above current text data");
618 layerstate
=STATE_BITMAP_IS_ABOVE
;
619 update_bitmap(stalepolybitmap
, boolpolybitmap
, x1
, y1
, x2
, y2
, 0);
620 } else if(layerstate
==STATE_TEXT_IS_ABOVE
) {
621 msg("<verbose> Bitmap is above current text data (which is above some bitmap)");
623 layerstate
=STATE_BITMAP_IS_ABOVE
;
625 update_bitmap(stalepolybitmap
, boolpolybitmap
, x1
, y1
, x2
, y2
, 1);
628 msg("<verbose> Bitmap is still above current text data");
629 update_bitmap(stalepolybitmap
, boolpolybitmap
, x1
, y1
, x2
, y2
, 0);
632 update_bitmap(stalepolybitmap
, boolpolybitmap
, x1
, y1
, x2
, y2
, 0);
635 /* clear the thing we just drew from our temporary drawing bitmap */
636 clearBooleanBitmap(boolpolybitmap
, x1
, y1
, x2
, y2
);
641 //void checkNewText() {
642 // Guchar*alpha = rgbbitmap->getAlphaPtr();
643 // Guchar*charpixels = clip1bitmap->getDataPtr();
645 // for(yy=0;yy<height;yy++) {
646 // Guchar*aline = &alpha[yy*width];
647 // Guchar*cline = &charpixels[yy*width8];
648 // for(xx=0;xx<width;xx++) {
650 // int bytepos = xx>>3;
651 // /* TODO: is the bit order correct? */
652 // if(aline[xx] && (cline[bytepos]&(1<<bit)))
659 GBool
BitmapOutputDev::clip0and1differ(int x1
,int y1
,int x2
,int y2
)
661 if(clip0bitmap
->getMode()==splashModeMono1
) {
662 int width
= clip0bitmap
->getWidth();
663 int width8
= (width
+7)/8;
664 int height
= clip0bitmap
->getHeight();
666 if(!fixBBox(&x1
,&y1
,&x2
,&y2
,width
,height
)) {
667 /* area is outside or null */
671 SplashBitmap
*clip0
= clip0bitmap
;
672 SplashBitmap
*clip1
= clip1bitmap
;
678 unsigned char*row1
= &clip0bitmap
->getDataPtr()[width8
*y
+x18
];
679 unsigned char*row2
= &clip1bitmap
->getDataPtr()[width8
*y
+x18
];
680 if(memcmp(row1
, row2
, x28
-x18
)) {
686 SplashBitmap
*clip0
= clip0bitmap
;
687 SplashBitmap
*clip1
= clip1bitmap
;
688 int width
= clip0
->getAlphaRowSize();
689 int height
= clip0
->getHeight();
691 if(!fixBBox(&x1
, &y1
, &x2
, &y2
, width
, height
)) {
695 Guchar
*a0
= clip0
->getAlphaPtr();
696 Guchar
*a1
= clip1
->getAlphaPtr();
701 if(a0
[y
*width
+x
]!=a1
[y
*width
+x
]) {
709 char differs2
= memcmp(a0
, a1
, width
*height
);
710 if(differs
&& !differs2
)
711 msg("<warning> Strange internal error (2)");
712 else if(!differs
&& differs2
) {
713 msg("<warning> Bad Bounding Box: Difference in clip0 and clip1 outside bbox");
714 msg("<warning> %d %d %d %d", x1
, y1
, x2
, y2
);
720 GBool
compare8(unsigned char*data1
, unsigned char*data2
, int len
)
724 if(((ptroff_t
)data1
&7)==((ptroff_t
)data2
&7)) {
725 // oh good, we can align both to 8 byte
726 while((ptroff_t
)data1
&7) {
735 /* use 64 bit for the (hopefully aligned) middle section */
737 long long unsigned int*d1
= (long long unsigned int*)data1
;
738 long long unsigned int*d2
= (long long unsigned int*)data2
;
739 long long unsigned int x
= 0;
751 if(data1
[t
]&data2
[t
]) {
758 GBool
BitmapOutputDev::intersection(SplashBitmap
*boolpoly
, SplashBitmap
*booltext
, int x1
, int y1
, int x2
, int y2
)
760 if(boolpoly
->getMode()==splashModeMono1
) {
761 /* alternative implementation, using one bit per pixel-
762 needs the no-dither patch in xpdf */
764 int width
= boolpoly
->getWidth();
765 int height
= boolpoly
->getHeight();
767 if(!fixBBox(&x1
,&y1
,&x2
,&y2
, width
, height
)) {
771 Guchar
*polypixels
= boolpoly
->getDataPtr();
772 Guchar
*textpixels
= booltext
->getDataPtr();
774 int width8
= (width
+7)/8;
779 polypixels
+=y1
*width8
+x1
/8;
780 textpixels
+=y1
*width8
+x1
/8;
781 runx
=(x2
+7)/8 - x1
/8;
788 /*assert(sizeof(unsigned long long int)==8);
789 if(((ptroff_t)polypixels&7) || ((ptroff_t)textpixels&7)) {
790 //msg("<warning> Non-optimal alignment");
794 unsigned char*data1
= (unsigned char*)polypixels
;
795 unsigned char*data2
= (unsigned char*)textpixels
;
796 msg("<verbose> Testing area (%d,%d,%d,%d), runx=%d,runy=%d", x1
,y1
,x2
,y2
, runx
, runy
);
797 for(y
=0;y
<runy
;y
++) {
798 if(compare8(data1
,data2
,runx
))
805 int width
= boolpoly
->getAlphaRowSize();
806 int height
= boolpoly
->getHeight();
808 if(!fixBBox(&x1
, &y1
, &x2
, &y2
, width
, height
)) {
811 Guchar
*polypixels
= boolpoly
->getAlphaPtr();
812 Guchar
*textpixels
= booltext
->getAlphaPtr();
819 if(polypixels
[width
*y
+x
]&&textpixels
[width
*y
+x
])
823 int ax1
=0,ay1
=0,ax2
=0,ay2
=0;
824 for(y
=0;y
<height
;y
++) {
825 for(x
=0;x
<width
;x
++) {
826 if(polypixels
[width
*y
+x
]&&textpixels
[width
*y
+x
]) {
828 if(!(ax1
|ay1
|ax2
|ay2
)) {
840 if(overlap1
&& !overlap2
)
841 msg("<warning> strange internal error");
842 if(!overlap1
&& overlap2
) {
843 msg("<warning> Bad bounding box: intersection outside bbox");
844 msg("<warning> given bbox: %d %d %d %d", x1
, y1
, x2
, y2
);
845 msg("<warning> changed area: %d %d %d %d", ax1
, ay1
, ax2
, ay2
);
852 void BitmapOutputDev::startPage(int pageNum
, GfxState
*state
, double crop_x1
, double crop_y1
, double crop_x2
, double crop_y2
)
855 state
->transform(crop_x1
,crop_y1
,&x1
,&y1
);
856 state
->transform(crop_x2
,crop_y2
,&x2
,&y2
);
857 if(x2
<x1
) {double x3
=x1
;x1
=x2
;x2
=x3
;}
858 if(y2
<y1
) {double y3
=y1
;y1
=y2
;y2
=y3
;}
860 this->movex
= -(int)x1
- user_movex
;
861 this->movey
= -(int)y1
- user_movey
;
863 if(user_clipx1
|user_clipy1
|user_clipx2
|user_clipy2
) {
869 this->width
= (int)(x2
-x1
);
870 this->height
= (int)(y2
-y1
);
872 rgbdev
->startPage(pageNum
, state
, crop_x1
, crop_y1
, crop_x2
, crop_y2
);
873 boolpolydev
->startPage(pageNum
, state
, crop_x1
, crop_y1
, crop_x2
, crop_y2
);
874 booltextdev
->startPage(pageNum
, state
, crop_x1
, crop_y1
, crop_x2
, crop_y2
);
875 clip0dev
->startPage(pageNum
, state
, crop_x1
, crop_y1
, crop_x2
, crop_y2
);
876 clip1dev
->startPage(pageNum
, state
, crop_x1
, crop_y1
, crop_x2
, crop_y2
);
877 gfxdev
->startPage(pageNum
, state
, crop_x1
, crop_y1
, crop_x2
, crop_y2
);
879 boolpolybitmap
= boolpolydev
->getBitmap();
880 stalepolybitmap
= new SplashBitmap(boolpolybitmap
->getWidth(), boolpolybitmap
->getHeight(), 1, boolpolybitmap
->getMode(), 0);
881 assert(stalepolybitmap
->getRowSize() == boolpolybitmap
->getRowSize());
883 booltextbitmap
= booltextdev
->getBitmap();
884 staletextbitmap
= new SplashBitmap(booltextbitmap
->getWidth(), booltextbitmap
->getHeight(), 1, booltextbitmap
->getMode(), 0);
885 assert(staletextbitmap
->getRowSize() == booltextbitmap
->getRowSize());
887 msg("<debug> startPage %dx%d (%dx%d)", this->width
, this->height
, booltextbitmap
->getWidth(), booltextbitmap
->getHeight());
889 clip0bitmap
= clip0dev
->getBitmap();
890 clip1bitmap
= clip1dev
->getBitmap();
891 rgbbitmap
= rgbdev
->getBitmap();
893 flushText(); // write out the initial clipping rectangle
895 /* just in case any device did draw a white background rectangle
900 this->layerstate
= STATE_PARALLEL
;
902 msg("<debug> startPage done");
905 void BitmapOutputDev::endPage()
907 msg("<verbose> endPage (BitmapOutputDev)");
909 /* notice: we're not fully done yet with this page- there might still be
910 a few calls to drawLink() yet to come */
912 void BitmapOutputDev::finishPage()
914 msg("<verbose> finishPage (BitmapOutputDev)");
919 /* splash will now destroy alpha, and paint the
920 background color into the "holes" in the bitmap */
921 boolpolydev
->endPage();
922 booltextdev
->endPage();
928 GBool
BitmapOutputDev::upsideDown()
930 boolpolydev
->upsideDown();
931 booltextdev
->upsideDown();
932 clip0dev
->upsideDown();
933 clip1dev
->upsideDown();
934 return rgbdev
->upsideDown();
937 GBool
BitmapOutputDev::useDrawChar()
939 boolpolydev
->useDrawChar();
940 booltextdev
->useDrawChar();
941 clip0dev
->useDrawChar();
942 clip1dev
->useDrawChar();
943 return rgbdev
->useDrawChar();
946 GBool
BitmapOutputDev::useTilingPatternFill()
948 boolpolydev
->useTilingPatternFill();
949 booltextdev
->useTilingPatternFill();
950 clip0dev
->useTilingPatternFill();
951 clip1dev
->useTilingPatternFill();
952 return rgbdev
->useTilingPatternFill();
955 GBool
BitmapOutputDev::useShadedFills()
957 boolpolydev
->useShadedFills();
958 booltextdev
->useShadedFills();
959 clip0dev
->useShadedFills();
960 clip1dev
->useShadedFills();
961 return rgbdev
->useShadedFills();
964 GBool
BitmapOutputDev::useDrawForm()
966 boolpolydev
->useDrawForm();
967 booltextdev
->useDrawForm();
968 clip0dev
->useDrawForm();
969 clip1dev
->useDrawForm();
970 return rgbdev
->useDrawForm();
973 GBool
BitmapOutputDev::interpretType3Chars()
975 boolpolydev
->interpretType3Chars();
976 booltextdev
->interpretType3Chars();
977 clip0dev
->interpretType3Chars();
978 clip1dev
->interpretType3Chars();
979 return rgbdev
->interpretType3Chars();
982 GBool
BitmapOutputDev::needNonText()
984 boolpolydev
->needNonText();
985 booltextdev
->needNonText();
986 clip0dev
->needNonText();
987 clip1dev
->needNonText();
988 return rgbdev
->needNonText();
990 /*GBool BitmapOutputDev::checkPageSlice(Page *page, double hDPI, double vDPI,
991 int rotate, GBool useMediaBox, GBool crop,
992 int sliceX, int sliceY, int sliceW, int sliceH,
993 GBool printing, Catalog *catalog,
994 GBool (*abortCheckCbk)(void *data),
995 void *abortCheckCbkData)
999 void BitmapOutputDev::setDefaultCTM(double *ctm
)
1001 boolpolydev
->setDefaultCTM(ctm
);
1002 booltextdev
->setDefaultCTM(ctm
);
1003 rgbdev
->setDefaultCTM(ctm
);
1004 clip0dev
->setDefaultCTM(ctm
);
1005 clip1dev
->setDefaultCTM(ctm
);
1006 gfxdev
->setDefaultCTM(ctm
);
1008 void BitmapOutputDev::saveState(GfxState
*state
)
1010 boolpolydev
->saveState(state
);
1011 booltextdev
->saveState(state
);
1012 rgbdev
->saveState(state
);
1013 clip0dev
->saveState(state
);
1014 clip1dev
->saveState(state
);
1016 /*ClipState*cstate = new ClipState();
1017 cstate->next = this->clipstates;
1018 this->clipstates = cstate;*/
1020 void BitmapOutputDev::restoreState(GfxState
*state
)
1022 boolpolydev
->restoreState(state
);
1023 booltextdev
->restoreState(state
);
1024 rgbdev
->restoreState(state
);
1025 clip0dev
->restoreState(state
);
1026 clip1dev
->restoreState(state
);
1028 /*if(this->clipstates) {
1029 ClipState*old = this->clipstates;
1031 gfxdev->restoreState(state);
1033 this->clipstates = this->clipstates->next;
1036 msg("<error> invalid restoreState()");
1039 void BitmapOutputDev::updateAll(GfxState
*state
)
1041 boolpolydev
->updateAll(state
);
1042 booltextdev
->updateAll(state
);
1043 rgbdev
->updateAll(state
);
1044 clip0dev
->updateAll(state
);
1045 clip1dev
->updateAll(state
);
1046 gfxdev
->updateAll(state
);
1048 void BitmapOutputDev::updateCTM(GfxState
*state
, double m11
, double m12
, double m21
, double m22
, double m31
, double m32
)
1050 boolpolydev
->updateCTM(state
,m11
,m12
,m21
,m22
,m31
,m32
);
1051 booltextdev
->updateCTM(state
,m11
,m12
,m21
,m22
,m31
,m32
);
1052 rgbdev
->updateCTM(state
,m11
,m12
,m21
,m22
,m31
,m32
);
1053 clip0dev
->updateCTM(state
,m11
,m12
,m21
,m22
,m31
,m32
);
1054 clip1dev
->updateCTM(state
,m11
,m12
,m21
,m22
,m31
,m32
);
1055 gfxdev
->updateCTM(state
,m11
,m12
,m21
,m22
,m31
,m32
);
1057 void BitmapOutputDev::updateLineDash(GfxState
*state
)
1059 boolpolydev
->updateLineDash(state
);
1060 booltextdev
->updateLineDash(state
);
1061 rgbdev
->updateLineDash(state
);
1062 clip0dev
->updateLineDash(state
);
1063 clip1dev
->updateLineDash(state
);
1064 gfxdev
->updateLineDash(state
);
1066 void BitmapOutputDev::updateFlatness(GfxState
*state
)
1068 boolpolydev
->updateFlatness(state
);
1069 booltextdev
->updateFlatness(state
);
1070 rgbdev
->updateFlatness(state
);
1071 clip0dev
->updateFlatness(state
);
1072 clip1dev
->updateFlatness(state
);
1073 gfxdev
->updateFlatness(state
);
1075 void BitmapOutputDev::updateLineJoin(GfxState
*state
)
1077 boolpolydev
->updateLineJoin(state
);
1078 booltextdev
->updateLineJoin(state
);
1079 rgbdev
->updateLineJoin(state
);
1080 clip0dev
->updateLineJoin(state
);
1081 clip1dev
->updateLineJoin(state
);
1082 gfxdev
->updateLineJoin(state
);
1084 void BitmapOutputDev::updateLineCap(GfxState
*state
)
1086 boolpolydev
->updateLineCap(state
);
1087 booltextdev
->updateLineCap(state
);
1088 rgbdev
->updateLineCap(state
);
1089 clip0dev
->updateLineCap(state
);
1090 clip1dev
->updateLineCap(state
);
1091 gfxdev
->updateLineCap(state
);
1093 void BitmapOutputDev::updateMiterLimit(GfxState
*state
)
1095 boolpolydev
->updateMiterLimit(state
);
1096 booltextdev
->updateMiterLimit(state
);
1097 rgbdev
->updateMiterLimit(state
);
1098 clip0dev
->updateMiterLimit(state
);
1099 clip1dev
->updateMiterLimit(state
);
1100 gfxdev
->updateMiterLimit(state
);
1102 void BitmapOutputDev::updateLineWidth(GfxState
*state
)
1104 boolpolydev
->updateLineWidth(state
);
1105 booltextdev
->updateLineWidth(state
);
1106 rgbdev
->updateLineWidth(state
);
1107 clip0dev
->updateLineWidth(state
);
1108 clip1dev
->updateLineWidth(state
);
1109 gfxdev
->updateLineWidth(state
);
1111 void BitmapOutputDev::updateStrokeAdjust(GfxState
*state
)
1113 boolpolydev
->updateStrokeAdjust(state
);
1114 booltextdev
->updateStrokeAdjust(state
);
1115 rgbdev
->updateStrokeAdjust(state
);
1116 clip0dev
->updateStrokeAdjust(state
);
1117 clip1dev
->updateStrokeAdjust(state
);
1118 gfxdev
->updateStrokeAdjust(state
);
1120 void BitmapOutputDev::updateFillColorSpace(GfxState
*state
)
1122 boolpolydev
->updateFillColorSpace(state
);
1123 booltextdev
->updateFillColorSpace(state
);
1124 rgbdev
->updateFillColorSpace(state
);
1125 clip0dev
->updateFillColorSpace(state
);
1126 clip1dev
->updateFillColorSpace(state
);
1127 gfxdev
->updateFillColorSpace(state
);
1129 void BitmapOutputDev::updateStrokeColorSpace(GfxState
*state
)
1131 boolpolydev
->updateStrokeColorSpace(state
);
1132 booltextdev
->updateStrokeColorSpace(state
);
1133 rgbdev
->updateStrokeColorSpace(state
);
1134 clip0dev
->updateStrokeColorSpace(state
);
1135 clip1dev
->updateStrokeColorSpace(state
);
1136 gfxdev
->updateStrokeColorSpace(state
);
1138 void BitmapOutputDev::updateFillColor(GfxState
*state
)
1140 boolpolydev
->updateFillColor(state
);
1141 booltextdev
->updateFillColor(state
);
1142 rgbdev
->updateFillColor(state
);
1143 clip0dev
->updateFillColor(state
);
1144 clip1dev
->updateFillColor(state
);
1145 gfxdev
->updateFillColor(state
);
1147 void BitmapOutputDev::updateStrokeColor(GfxState
*state
)
1149 boolpolydev
->updateStrokeColor(state
);
1150 booltextdev
->updateStrokeColor(state
);
1151 rgbdev
->updateStrokeColor(state
);
1152 clip0dev
->updateStrokeColor(state
);
1153 clip1dev
->updateStrokeColor(state
);
1154 gfxdev
->updateStrokeColor(state
);
1156 void BitmapOutputDev::updateBlendMode(GfxState
*state
)
1158 boolpolydev
->updateBlendMode(state
);
1159 booltextdev
->updateBlendMode(state
);
1160 rgbdev
->updateBlendMode(state
);
1161 clip0dev
->updateBlendMode(state
);
1162 clip1dev
->updateBlendMode(state
);
1163 gfxdev
->updateBlendMode(state
);
1165 void BitmapOutputDev::updateFillOpacity(GfxState
*state
)
1167 boolpolydev
->updateFillOpacity(state
);
1168 booltextdev
->updateFillOpacity(state
);
1169 rgbdev
->updateFillOpacity(state
);
1170 clip0dev
->updateFillOpacity(state
);
1171 clip1dev
->updateFillOpacity(state
);
1172 gfxdev
->updateFillOpacity(state
);
1174 void BitmapOutputDev::updateStrokeOpacity(GfxState
*state
)
1176 boolpolydev
->updateStrokeOpacity(state
);
1177 booltextdev
->updateStrokeOpacity(state
);
1178 rgbdev
->updateStrokeOpacity(state
);
1179 clip0dev
->updateStrokeOpacity(state
);
1180 clip1dev
->updateStrokeOpacity(state
);
1181 gfxdev
->updateStrokeOpacity(state
);
1183 void BitmapOutputDev::updateFillOverprint(GfxState
*state
)
1185 boolpolydev
->updateFillOverprint(state
);
1186 booltextdev
->updateFillOverprint(state
);
1187 rgbdev
->updateFillOverprint(state
);
1188 clip0dev
->updateFillOverprint(state
);
1189 clip1dev
->updateFillOverprint(state
);
1190 gfxdev
->updateFillOverprint(state
);
1192 void BitmapOutputDev::updateStrokeOverprint(GfxState
*state
)
1194 boolpolydev
->updateStrokeOverprint(state
);
1195 booltextdev
->updateStrokeOverprint(state
);
1196 rgbdev
->updateStrokeOverprint(state
);
1197 clip0dev
->updateStrokeOverprint(state
);
1198 clip1dev
->updateStrokeOverprint(state
);
1199 gfxdev
->updateStrokeOverprint(state
);
1201 void BitmapOutputDev::updateTransfer(GfxState
*state
)
1203 boolpolydev
->updateTransfer(state
);
1204 booltextdev
->updateTransfer(state
);
1205 rgbdev
->updateTransfer(state
);
1206 clip0dev
->updateTransfer(state
);
1207 clip1dev
->updateTransfer(state
);
1208 gfxdev
->updateTransfer(state
);
1211 void BitmapOutputDev::updateFont(GfxState
*state
)
1213 boolpolydev
->updateFont(state
);
1214 booltextdev
->updateFont(state
);
1215 rgbdev
->updateFont(state
);
1216 clip0dev
->updateFont(state
);
1217 clip1dev
->updateFont(state
);
1218 gfxdev
->updateFont(state
);
1220 void BitmapOutputDev::updateTextMat(GfxState
*state
)
1222 boolpolydev
->updateTextMat(state
);
1223 booltextdev
->updateTextMat(state
);
1224 rgbdev
->updateTextMat(state
);
1225 clip0dev
->updateTextMat(state
);
1226 clip1dev
->updateTextMat(state
);
1227 gfxdev
->updateTextMat(state
);
1229 void BitmapOutputDev::updateCharSpace(GfxState
*state
)
1231 boolpolydev
->updateCharSpace(state
);
1232 booltextdev
->updateCharSpace(state
);
1233 rgbdev
->updateCharSpace(state
);
1234 clip0dev
->updateCharSpace(state
);
1235 clip1dev
->updateCharSpace(state
);
1236 gfxdev
->updateCharSpace(state
);
1238 void BitmapOutputDev::updateRender(GfxState
*state
)
1240 boolpolydev
->updateRender(state
);
1241 booltextdev
->updateRender(state
);
1242 rgbdev
->updateRender(state
);
1243 clip0dev
->updateRender(state
);
1244 clip1dev
->updateRender(state
);
1245 gfxdev
->updateRender(state
);
1247 void BitmapOutputDev::updateRise(GfxState
*state
)
1249 boolpolydev
->updateRise(state
);
1250 booltextdev
->updateRise(state
);
1251 rgbdev
->updateRise(state
);
1252 clip0dev
->updateRise(state
);
1253 clip1dev
->updateRise(state
);
1254 gfxdev
->updateRise(state
);
1256 void BitmapOutputDev::updateWordSpace(GfxState
*state
)
1258 boolpolydev
->updateWordSpace(state
);
1259 booltextdev
->updateWordSpace(state
);
1260 rgbdev
->updateWordSpace(state
);
1261 clip0dev
->updateWordSpace(state
);
1262 clip1dev
->updateWordSpace(state
);
1263 gfxdev
->updateWordSpace(state
);
1265 void BitmapOutputDev::updateHorizScaling(GfxState
*state
)
1267 boolpolydev
->updateHorizScaling(state
);
1268 booltextdev
->updateHorizScaling(state
);
1269 rgbdev
->updateHorizScaling(state
);
1270 clip0dev
->updateHorizScaling(state
);
1271 clip1dev
->updateHorizScaling(state
);
1272 gfxdev
->updateHorizScaling(state
);
1274 void BitmapOutputDev::updateTextPos(GfxState
*state
)
1276 boolpolydev
->updateTextPos(state
);
1277 booltextdev
->updateTextPos(state
);
1278 rgbdev
->updateTextPos(state
);
1279 clip0dev
->updateTextPos(state
);
1280 clip1dev
->updateTextPos(state
);
1281 gfxdev
->updateTextPos(state
);
1283 void BitmapOutputDev::updateTextShift(GfxState
*state
, double shift
)
1285 boolpolydev
->updateTextShift(state
, shift
);
1286 booltextdev
->updateTextShift(state
, shift
);
1287 rgbdev
->updateTextShift(state
, shift
);
1288 clip0dev
->updateTextShift(state
, shift
);
1289 clip1dev
->updateTextShift(state
, shift
);
1290 gfxdev
->updateTextShift(state
, shift
);
1293 double max(double x
, double y
)
1297 double min(double x
, double y
)
1302 gfxbbox_t
BitmapOutputDev::getBBox(GfxState
*state
)
1304 GfxPath
* path
= state
->getPath();
1305 int num
= path
->getNumSubpaths();
1306 gfxbbox_t bbox
= {0,0,1,1};
1309 for(t
= 0; t
< num
; t
++) {
1310 GfxSubpath
*subpath
= path
->getSubpath(t
);
1311 int subnum
= subpath
->getNumPoints();
1313 for(s
=0;s
<subnum
;s
++) {
1315 state
->transform(subpath
->getX(s
),subpath
->getY(s
),&x
,&y
);
1317 bbox
.xmin
= x
; bbox
.ymin
= y
;
1318 bbox
.xmax
= x
; bbox
.ymax
= y
;
1321 bbox
.xmin
= min(bbox
.xmin
, x
);
1322 bbox
.ymin
= min(bbox
.ymin
, y
);
1323 bbox
.xmax
= max(bbox
.xmax
, x
);
1324 bbox
.ymax
= max(bbox
.ymax
, y
);
1331 void BitmapOutputDev::stroke(GfxState
*state
)
1333 msg("<debug> stroke");
1334 boolpolydev
->stroke(state
);
1335 gfxbbox_t bbox
= getBBox(state
);
1336 double width
= state
->getTransformedLineWidth();
1337 bbox
.xmin
-= width
; bbox
.ymin
-= width
;
1338 bbox
.xmax
+= width
; bbox
.ymax
+= width
;
1339 checkNewBitmap(bbox
.xmin
, bbox
.ymin
, ceil(bbox
.xmax
), ceil(bbox
.ymax
));
1340 rgbdev
->stroke(state
);
1341 dbg_newdata("stroke");
1344 extern gfxcolor_t
getFillColor(GfxState
* state
);
1346 char area_is_plain_colored(GfxState
*state
, SplashBitmap
*boolpoly
, SplashBitmap
*rgbbitmap
, int x1
, int y1
, int x2
, int y2
)
1348 int width
= boolpoly
->getWidth();
1349 int height
= boolpoly
->getHeight();
1350 if(!fixBBox(&x1
, &y1
, &x2
, &y2
, width
, height
)) {
1353 gfxcolor_t color
= getFillColor(state
);
1354 SplashColorPtr rgb
= rgbbitmap
->getDataPtr()
1355 + (y1
*width
+x1
)*sizeof(SplashColor
);
1356 int width8
= (width
+7)/8;
1357 unsigned char*bits
= (unsigned char*)boolpoly
->getDataPtr()
1364 if(rgb
[x
*3+0] != color
.r
||
1365 rgb
[x
*3+1] != color
.g
||
1366 rgb
[x
*3+2] != color
.b
)
1369 rgb
+= width
*sizeof(SplashColor
);
1374 void BitmapOutputDev::fill(GfxState
*state
)
1376 msg("<debug> fill");
1377 boolpolydev
->fill(state
);
1378 gfxbbox_t bbox
= getBBox(state
);
1379 if(config_optimizeplaincolorfills
) {
1380 if(area_is_plain_colored(state
, boolpolybitmap
, rgbbitmap
, bbox
.xmin
, bbox
.ymin
, bbox
.xmax
, bbox
.ymax
)) {
1384 checkNewBitmap(bbox
.xmin
, bbox
.ymin
, ceil(bbox
.xmax
), ceil(bbox
.ymax
));
1385 rgbdev
->fill(state
);
1386 dbg_newdata("fill");
1388 void BitmapOutputDev::eoFill(GfxState
*state
)
1390 msg("<debug> eoFill");
1391 boolpolydev
->eoFill(state
);
1392 gfxbbox_t bbox
= getBBox(state
);
1393 checkNewBitmap(bbox
.xmin
, bbox
.ymin
, ceil(bbox
.xmax
), ceil(bbox
.ymax
));
1394 rgbdev
->eoFill(state
);
1395 dbg_newdata("eofill");
1397 #if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207
1398 void BitmapOutputDev::tilingPatternFill(GfxState
*state
, Object
*str
,
1399 int paintType
, Dict
*resDict
,
1400 double *mat
, double *bbox
,
1401 int x0
, int y0
, int x1
, int y1
,
1402 double xStep
, double yStep
)
1404 msg("<debug> tilingPatternFill");
1405 boolpolydev
->tilingPatternFill(state
, str
, paintType
, resDict
, mat
, bbox
, x0
, y0
, x1
, y1
, xStep
, yStep
);
1406 checkNewBitmap(UNKNOWN_BOUNDING_BOX
);
1407 rgbdev
->tilingPatternFill(state
, str
, paintType
, resDict
, mat
, bbox
, x0
, y0
, x1
, y1
, xStep
, yStep
);
1408 dbg_newdata("tilingpatternfill");
1411 void BitmapOutputDev::tilingPatternFill(GfxState
*state
, Gfx
*gfx
, Object
*str
,
1412 int paintType
, Dict
*resDict
,
1413 double *mat
, double *bbox
,
1414 int x0
, int y0
, int x1
, int y1
,
1415 double xStep
, double yStep
)
1417 msg("<debug> tilingPatternFill");
1418 boolpolydev
->tilingPatternFill(state
, gfx
, str
, paintType
, resDict
, mat
, bbox
, x0
, y0
, x1
, y1
, xStep
, yStep
);
1419 checkNewBitmap(UNKNOWN_BOUNDING_BOX
);
1420 rgbdev
->tilingPatternFill(state
, gfx
, str
, paintType
, resDict
, mat
, bbox
, x0
, y0
, x1
, y1
, xStep
, yStep
);
1421 dbg_newdata("tilingpatternfill");
1425 GBool
BitmapOutputDev::functionShadedFill(GfxState
*state
, GfxFunctionShading
*shading
)
1427 msg("<debug> functionShadedFill");
1428 boolpolydev
->functionShadedFill(state
, shading
);
1429 checkNewBitmap(UNKNOWN_BOUNDING_BOX
);
1430 return rgbdev
->functionShadedFill(state
, shading
);
1432 GBool
BitmapOutputDev::axialShadedFill(GfxState
*state
, GfxAxialShading
*shading
)
1434 msg("<debug> axialShadedFill");
1435 boolpolydev
->axialShadedFill(state
, shading
);
1436 checkNewBitmap(UNKNOWN_BOUNDING_BOX
);
1437 return rgbdev
->axialShadedFill(state
, shading
);
1439 GBool
BitmapOutputDev::radialShadedFill(GfxState
*state
, GfxRadialShading
*shading
)
1441 msg("<debug> radialShadedFill");
1442 boolpolydev
->radialShadedFill(state
, shading
);
1443 checkNewBitmap(UNKNOWN_BOUNDING_BOX
);
1444 return rgbdev
->radialShadedFill(state
, shading
);
1447 SplashColor black
= {0,0,0};
1448 SplashColor white
= {255,255,255};
1450 void BitmapOutputDev::clip(GfxState
*state
)
1452 msg("<debug> clip");
1453 boolpolydev
->clip(state
);
1454 booltextdev
->clip(state
);
1455 rgbdev
->clip(state
);
1456 clip1dev
->clip(state
);
1458 void BitmapOutputDev::eoClip(GfxState
*state
)
1460 msg("<debug> eoClip");
1461 boolpolydev
->eoClip(state
);
1462 booltextdev
->eoClip(state
);
1463 rgbdev
->eoClip(state
);
1464 clip1dev
->eoClip(state
);
1466 void BitmapOutputDev::clipToStrokePath(GfxState
*state
)
1468 msg("<debug> clipToStrokePath");
1469 boolpolydev
->clipToStrokePath(state
);
1470 booltextdev
->clipToStrokePath(state
);
1471 rgbdev
->clipToStrokePath(state
);
1472 clip1dev
->clipToStrokePath(state
);
1475 void BitmapOutputDev::beginStringOp(GfxState
*state
)
1477 msg("<debug> beginStringOp");
1478 clip0dev
->beginStringOp(state
);
1479 clip1dev
->beginStringOp(state
);
1480 booltextdev
->beginStringOp(state
);
1481 gfxdev
->beginStringOp(state
);
1483 void BitmapOutputDev::beginString(GfxState
*state
, GString
*s
)
1485 msg("<debug> beginString");
1486 clip0dev
->beginString(state
, s
);
1487 clip1dev
->beginString(state
, s
);
1488 booltextdev
->beginString(state
, s
);
1489 gfxdev
->beginString(state
, s
);
1492 void BitmapOutputDev::clearClips()
1494 clearBooleanBitmap(clip0bitmap
, 0, 0, 0, 0);
1495 clearBooleanBitmap(clip1bitmap
, 0, 0, 0, 0);
1497 void BitmapOutputDev::clearBoolPolyDev()
1499 clearBooleanBitmap(stalepolybitmap
, 0, 0, stalepolybitmap
->getWidth(), stalepolybitmap
->getHeight());
1501 void BitmapOutputDev::clearBoolTextDev()
1503 clearBooleanBitmap(staletextbitmap
, 0, 0, staletextbitmap
->getWidth(), staletextbitmap
->getHeight());
1505 void BitmapOutputDev::drawChar(GfxState
*state
, double x
, double y
,
1506 double dx
, double dy
,
1507 double originX
, double originY
,
1508 CharCode code
, int nBytes
, Unicode
*u
, int uLen
)
1510 msg("<debug> drawChar render=%d", state
->getRender());
1512 if(state
->getRender()&RENDER_CLIP
) {
1513 //char is just a clipping boundary
1514 rgbdev
->drawChar(state
, x
, y
, dx
, dy
, originX
, originY
, code
, nBytes
, u
, uLen
);
1515 boolpolydev
->drawChar(state
, x
, y
, dx
, dy
, originX
, originY
, code
, nBytes
, u
, uLen
);
1516 booltextdev
->drawChar(state
, x
, y
, dx
, dy
, originX
, originY
, code
, nBytes
, u
, uLen
);
1517 clip1dev
->drawChar(state
, x
, y
, dx
, dy
, originX
, originY
, code
, nBytes
, u
, uLen
);
1518 } else if(state
->getRender()&RENDER_STROKE
) {
1519 // we're drawing as stroke
1520 boolpolydev
->drawChar(state
, x
, y
, dx
, dy
, originX
, originY
, code
, nBytes
, u
, uLen
);
1521 rgbdev
->drawChar(state
, x
, y
, dx
, dy
, originX
, originY
, code
, nBytes
, u
, uLen
);
1522 } else if(rgbbitmap
!= rgbdev
->getBitmap()) {
1523 // we're doing softmasking or transparency grouping
1524 boolpolydev
->drawChar(state
, x
, y
, dx
, dy
, originX
, originY
, code
, nBytes
, u
, uLen
);
1525 rgbdev
->drawChar(state
, x
, y
, dx
, dy
, originX
, originY
, code
, nBytes
, u
, uLen
);
1527 // we're drawing a regular char
1529 clip0dev
->drawChar(state
, x
, y
, dx
, dy
, originX
, originY
, code
, nBytes
, u
, uLen
);
1530 clip1dev
->drawChar(state
, x
, y
, dx
, dy
, originX
, originY
, code
, nBytes
, u
, uLen
);
1532 /* calculate the bbox of this character */
1533 int x1
= (int)x
, x2
= (int)x
+1, y1
= (int)y
, y2
= (int)y
+1;
1534 SplashFont
*font
= clip0dev
->getCurrentFont();
1535 SplashPath
*path
= font
?font
->getGlyphPath(code
):NULL
;
1539 path
->offset((SplashCoord
)x
, (SplashCoord
)y
);
1541 for(t
=0;t
<path
->getLength();t
++) {
1544 path
->getPoint(t
,&xx
,&yy
,&f
);
1545 state
->transform(xx
,yy
,&xx
,&yy
);
1546 if(xx
<x1
) x1
=(int)xx
;
1547 if(yy
<y1
) y1
=(int)yy
;
1548 if(xx
>=x2
) x2
=(int)xx
+1;
1549 if(yy
>=y2
) y2
=(int)yy
+1;
1551 delete(path
);path
=0;
1554 /* if this character is affected somehow by the various clippings (i.e., it looks
1555 different on a device without clipping), then draw it on the bitmap, not as
1557 if(clip0and1differ(x1
,y1
,x2
,y2
)) {
1558 msg("<verbose> Char %d is affected by clipping", code
);
1559 boolpolydev
->drawChar(state
, x
, y
, dx
, dy
, originX
, originY
, code
, nBytes
, u
, uLen
);
1560 checkNewBitmap(x1
,y1
,x2
,y2
);
1561 rgbdev
->drawChar(state
, x
, y
, dx
, dy
, originX
, originY
, code
, nBytes
, u
, uLen
);
1562 if(config_extrafontdata
) {
1563 int oldrender
= state
->getRender();
1564 state
->setRender(3); //invisible
1565 gfxdev
->drawChar(state
, x
, y
, dx
, dy
, originX
, originY
, code
, nBytes
, u
, uLen
);
1566 state
->setRender(oldrender
);
1570 /* this char is not at all affected by clipping.
1571 Now just dump out the bitmap we're currently working on, if necessary. */
1572 booltextdev
->drawChar(state
, x
, y
, dx
, dy
, originX
, originY
, code
, nBytes
, u
, uLen
);
1573 checkNewText(x1
,y1
,x2
,y2
);
1574 /* use polygonal output device to do the actual text handling */
1575 gfxdev
->drawChar(state
, x
, y
, dx
, dy
, originX
, originY
, code
, nBytes
, u
, uLen
);
1578 dbg_newdata("text");
1580 void BitmapOutputDev::drawString(GfxState
*state
, GString
*s
)
1582 msg("<error> internal error: drawString not implemented");
1585 void BitmapOutputDev::endTextObject(GfxState
*state
)
1587 msg("<debug> endTextObject");
1588 rgbdev
->endTextObject(state
);
1589 clip0dev
->endTextObject(state
);
1590 clip1dev
->endTextObject(state
);
1591 booltextdev
->endTextObject(state
);
1592 /* the only thing "drawn" here is clipping */
1593 //checkNewText(UNKNOWN_BOUNDING_BOX);
1594 gfxdev
->endTextObject(state
);
1595 dbg_newdata("endtextobject");
1597 void BitmapOutputDev::endString(GfxState
*state
)
1599 msg("<debug> endString");
1600 clip0dev
->endString(state
);
1601 clip1dev
->endString(state
);
1602 booltextdev
->endString(state
);
1603 int render
= state
->getRender();
1604 if(render
!= RENDER_INVISIBLE
&& render
!= RENDER_FILL
) {
1605 /* xpdf draws things like stroke text or fill+stroke text in the
1606 endString() method */
1607 checkNewText(UNKNOWN_BOUNDING_BOX
);
1609 gfxdev
->endString(state
);
1610 dbg_newdata("endstring");
1612 void BitmapOutputDev::endStringOp(GfxState
*state
)
1614 msg("<debug> endStringOp");
1615 clip0dev
->endStringOp(state
);
1616 clip1dev
->endStringOp(state
);
1617 booltextdev
->endStringOp(state
);
1618 gfxdev
->endStringOp(state
);
1619 dbg_newdata("endstringop");
1622 /* TODO: these four operations below *should* do nothing, as type3
1623 chars are drawn using operations like fill() */
1624 GBool
BitmapOutputDev::beginType3Char(GfxState
*state
, double x
, double y
,
1625 double dx
, double dy
,
1626 CharCode code
, Unicode
*u
, int uLen
)
1628 msg("<debug> beginType3Char");
1629 /* call gfxdev so that it can generate "invisible" characters
1630 on top of the actual graphic content, for text extraction */
1631 return gfxdev
->beginType3Char(state
, x
, y
, dx
, dy
, code
, u
, uLen
);
1633 void BitmapOutputDev::type3D0(GfxState
*state
, double wx
, double wy
)
1635 msg("<debug> type3D0");
1636 return gfxdev
->type3D0(state
, wx
, wy
);
1638 void BitmapOutputDev::type3D1(GfxState
*state
, double wx
, double wy
, double llx
, double lly
, double urx
, double ury
)
1640 msg("<debug> type3D1");
1641 return gfxdev
->type3D1(state
, wx
, wy
, llx
, lly
, urx
, ury
);
1643 void BitmapOutputDev::endType3Char(GfxState
*state
)
1645 msg("<debug> endType3Char");
1646 gfxdev
->endType3Char(state
);
1649 class CopyStream
: public Object
1653 MemStream
*memstream
;
1655 CopyStream(Stream
*str
, int len
)
1660 buf
= (char*)malloc(len
);
1662 for (t
=0; t
<len
; t
++)
1663 buf
[t
] = str
->getChar();
1666 this->dict
= str
->getDict();
1667 this->memstream
= new MemStream(buf
, 0, len
, this);
1671 ::free(this->buf
);this->buf
= 0;
1672 delete this->memstream
;
1674 Dict
* getDict() {return dict
;}
1675 Stream
* getStream() {return this->memstream
;};
1678 gfxbbox_t
BitmapOutputDev::getImageBBox(GfxState
*state
)
1682 state
->transform(0, 1, &x
, &y
);
1683 bbox
.xmin
=bbox
.xmax
= x
;
1684 bbox
.ymin
=bbox
.ymax
= y
;
1685 state
->transform(0, 0, &x
, &y
);
1686 bbox
.xmin
=min(bbox
.xmin
,x
);
1687 bbox
.ymin
=min(bbox
.ymin
,y
);
1688 bbox
.xmax
=max(bbox
.xmax
,x
);
1689 bbox
.ymax
=max(bbox
.ymax
,y
);
1690 state
->transform(1, 0, &x
, &y
);
1691 bbox
.xmin
=min(bbox
.xmin
,x
);
1692 bbox
.ymin
=min(bbox
.ymin
,y
);
1693 bbox
.xmax
=max(bbox
.xmax
,x
);
1694 bbox
.ymax
=max(bbox
.ymax
,y
);
1695 state
->transform(1, 1, &x
, &y
);
1696 bbox
.xmin
=min(bbox
.xmin
,x
);
1697 bbox
.ymin
=min(bbox
.ymin
,y
);
1698 bbox
.xmax
=max(bbox
.xmax
,x
);
1699 bbox
.ymax
=max(bbox
.ymax
,y
);
1702 void BitmapOutputDev::drawImageMask(GfxState
*state
, Object
*ref
, Stream
*str
,
1703 int width
, int height
, GBool invert
,
1706 msg("<debug> drawImageMask streamkind=%d", str
->getKind());
1708 CopyStream
*cpystr
= new CopyStream(str
, height
* ((width
+ 7) / 8));
1709 str
= cpystr
->getStream();
1711 boolpolydev
->drawImageMask(state
, ref
, str
, width
, height
, invert
, inlineImg
);
1712 gfxbbox_t bbox
= getImageBBox(state
);
1713 checkNewBitmap(bbox
.xmin
, bbox
.ymin
, ceil(bbox
.xmax
), ceil(bbox
.ymax
));
1714 rgbdev
->drawImageMask(state
, ref
, str
, width
, height
, invert
, inlineImg
);
1716 dbg_newdata("imagemask");
1718 void BitmapOutputDev::drawImage(GfxState
*state
, Object
*ref
, Stream
*str
,
1719 int width
, int height
, GfxImageColorMap
*colorMap
,
1720 int *maskColors
, GBool inlineImg
)
1722 msg("<debug> drawImage streamkind=%d", str
->getKind());
1724 CopyStream
*cpystr
= new CopyStream(str
, height
* ((width
* colorMap
->getNumPixelComps() * colorMap
->getBits() + 7) / 8));
1725 str
= cpystr
->getStream();
1727 boolpolydev
->drawImage(state
, ref
, str
, width
, height
, colorMap
, maskColors
, inlineImg
);
1728 gfxbbox_t bbox
=getImageBBox(state
);
1729 checkNewBitmap(bbox
.xmin
, bbox
.ymin
, ceil(bbox
.xmax
), ceil(bbox
.ymax
));
1730 rgbdev
->drawImage(state
, ref
, str
, width
, height
, colorMap
, maskColors
, inlineImg
);
1732 dbg_newdata("image");
1734 void BitmapOutputDev::drawMaskedImage(GfxState
*state
, Object
*ref
, Stream
*str
,
1735 int width
, int height
,
1736 GfxImageColorMap
*colorMap
,
1737 Stream
*maskStr
, int maskWidth
, int maskHeight
,
1740 msg("<debug> drawMaskedImage streamkind=%d", str
->getKind());
1742 CopyStream
*cpystr
= new CopyStream(str
, height
* ((width
* colorMap
->getNumPixelComps() * colorMap
->getBits() + 7) / 8));
1743 str
= cpystr
->getStream();
1745 boolpolydev
->drawMaskedImage(state
, ref
, str
, width
, height
, colorMap
, maskStr
, maskWidth
, maskHeight
, maskInvert
);
1746 gfxbbox_t bbox
=getImageBBox(state
);
1747 checkNewBitmap(bbox
.xmin
, bbox
.ymin
, ceil(bbox
.xmax
), ceil(bbox
.ymax
));
1748 rgbdev
->drawMaskedImage(state
, ref
, str
, width
, height
, colorMap
, maskStr
, maskWidth
, maskHeight
, maskInvert
);
1750 dbg_newdata("maskedimage");
1752 void BitmapOutputDev::drawSoftMaskedImage(GfxState
*state
, Object
*ref
, Stream
*str
,
1753 int width
, int height
,
1754 GfxImageColorMap
*colorMap
,
1756 int maskWidth
, int maskHeight
,
1757 GfxImageColorMap
*maskColorMap
)
1759 msg("<debug> drawSoftMaskedImage %dx%d (%dx%d) streamkind=%d", width
, height
, maskWidth
, maskHeight
, str
->getKind());
1761 CopyStream
*cpystr
= new CopyStream(str
, height
* ((width
* colorMap
->getNumPixelComps() * colorMap
->getBits() + 7) / 8));
1762 str
= cpystr
->getStream();
1764 boolpolydev
->drawSoftMaskedImage(state
, ref
, str
, width
, height
, colorMap
, maskStr
, maskWidth
, maskHeight
, maskColorMap
);
1765 gfxbbox_t bbox
=getImageBBox(state
);
1766 checkNewBitmap(bbox
.xmin
, bbox
.ymin
, ceil(bbox
.xmax
), ceil(bbox
.ymax
));
1767 rgbdev
->drawSoftMaskedImage(state
, ref
, str
, width
, height
, colorMap
, maskStr
, maskWidth
, maskHeight
, maskColorMap
);
1769 dbg_newdata("softmaskimage");
1771 void BitmapOutputDev::drawForm(Ref id
)
1773 msg("<debug> drawForm");
1774 boolpolydev
->drawForm(id
);
1775 checkNewBitmap(UNKNOWN_BOUNDING_BOX
);
1776 rgbdev
->drawForm(id
);
1779 void BitmapOutputDev::processLink(Link
*link
, Catalog
*catalog
)
1781 msg("<debug> processLink");
1783 gfxdev
->processLink(link
, catalog
);
1785 void BitmapOutputDev::flushEverything()
1787 if(layerstate
== STATE_BITMAP_IS_ABOVE
) {
1789 this->flushBitmap();
1791 this->flushBitmap();
1796 void BitmapOutputDev::beginTransparencyGroup(GfxState
*state
, double *bbox
,
1797 GfxColorSpace
*blendingColorSpace
,
1798 GBool isolated
, GBool knockout
,
1801 msg("<debug> beginTransparencyGroup");
1802 #if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207
1803 GfxState
*state1
= state
->copy();
1804 GfxState
*state2
= state
->copy();
1806 state1
->setPath(state
->getPath()->copy());
1808 state2
->setPath(state
->getPath()->copy());
1810 GfxState
*state1
= state
->copy(gTrue
);
1811 GfxState
*state2
= state
->copy(gTrue
);
1813 boolpolydev
->beginTransparencyGroup(state1
, bbox
, blendingColorSpace
, isolated
, knockout
, forSoftMask
);
1814 rgbdev
->beginTransparencyGroup(state2
, bbox
, blendingColorSpace
, isolated
, knockout
, forSoftMask
);
1815 clip1dev
->beginTransparencyGroup(state
, bbox
, blendingColorSpace
, isolated
, knockout
, forSoftMask
);
1818 dbg_newdata("endtransparencygroup");
1820 void BitmapOutputDev::endTransparencyGroup(GfxState
*state
)
1822 msg("<debug> endTransparencyGroup");
1823 #if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207
1824 GfxState
*state1
= state
->copy();
1825 GfxState
*state2
= state
->copy();
1827 state1
->setPath(state
->getPath()->copy());
1829 state2
->setPath(state
->getPath()->copy());
1831 GfxState
*state1
= state
->copy(gTrue
);
1832 GfxState
*state2
= state
->copy(gTrue
);
1834 boolpolydev
->endTransparencyGroup(state1
);
1835 checkNewBitmap(UNKNOWN_BOUNDING_BOX
);
1836 rgbdev
->endTransparencyGroup(state2
);
1839 clip1dev
->endTransparencyGroup(state
);
1840 dbg_newdata("endtransparencygroup");
1842 void BitmapOutputDev::paintTransparencyGroup(GfxState
*state
, double *bbox
)
1844 msg("<debug> paintTransparencyGroup");
1845 boolpolydev
->paintTransparencyGroup(state
,bbox
);
1846 checkNewBitmap(UNKNOWN_BOUNDING_BOX
);
1847 rgbdev
->paintTransparencyGroup(state
,bbox
);
1848 clip1dev
->paintTransparencyGroup(state
,bbox
);
1849 dbg_newdata("painttransparencygroup");
1851 void BitmapOutputDev::setSoftMask(GfxState
*state
, double *bbox
, GBool alpha
, Function
*transferFunc
, GfxColor
*backdropColor
)
1853 msg("<debug> setSoftMask");
1854 boolpolydev
->setSoftMask(state
, bbox
, alpha
, transferFunc
, backdropColor
);
1855 checkNewBitmap(UNKNOWN_BOUNDING_BOX
);
1856 rgbdev
->setSoftMask(state
, bbox
, alpha
, transferFunc
, backdropColor
);
1857 clip1dev
->setSoftMask(state
, bbox
, alpha
, transferFunc
, backdropColor
);
1858 dbg_newdata("setsoftmask");
1860 void BitmapOutputDev::clearSoftMask(GfxState
*state
)
1862 msg("<debug> clearSoftMask");
1863 boolpolydev
->clearSoftMask(state
);
1864 checkNewBitmap(UNKNOWN_BOUNDING_BOX
);
1865 rgbdev
->clearSoftMask(state
);
1866 clip1dev
->clearSoftMask(state
);
1867 dbg_newdata("clearsoftmask");