2 implements a pdf output device (OutputDev).
4 This file is part of swftools.
6 Swftools is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 Swftools is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with swftools; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
25 #include "../../config.h"
30 #ifdef HAVE_SYS_STAT_H
33 #ifdef HAVE_FONTCONFIG
34 #include <fontconfig.h>
51 #include "OutputDev.h"
54 #include "CharCodeToUnicode.h"
55 #include "NameToUnicodeTable.h"
56 #include "GlobalParams.h"
57 #include "FoFiType1C.h"
58 #include "FoFiTrueType.h"
60 #include "GFXOutputDev.h"
62 //swftools header files
64 #include "../gfxdevice.h"
65 #include "../gfxtools.h"
66 #include "../gfxfont.h"
70 typedef struct _fontfile
77 static fontfile_t fonts[2048];
78 static int fontnum = 0;
82 static char* lastfontdir = 0;
88 {"Times-Roman", "n021003l"},
89 {"Times-Italic", "n021023l"},
90 {"Times-Bold", "n021004l"},
91 {"Times-BoldItalic", "n021024l"},
92 {"Helvetica", "n019003l"},
93 {"Helvetica-Oblique", "n019023l"},
94 {"Helvetica-Bold", "n019004l"},
95 {"Helvetica-BoldOblique", "n019024l"},
96 {"Courier", "n022003l"},
97 {"Courier-Oblique", "n022023l"},
98 {"Courier-Bold", "n022004l"},
99 {"Courier-BoldOblique", "n022024l"},
100 {"Symbol", "s050000l"},
101 {"ZapfDingbats", "d050000l"}};
103 typedef struct _feature
106 struct _feature*next;
108 feature_t*featurewarnings = 0;
110 static void warnfeature(char*feature,char fully)
112 feature_t*f = featurewarnings;
114 if(!strcmp(feature, f->string))
118 f = (feature_t*)malloc(sizeof(feature_t));
119 f->string = strdup(feature);
120 f->next = featurewarnings;
122 msg("<warning> %s not yet %ssupported!",feature,fully?"fully ":"");
125 GFXOutputState::GFXOutputState() {
127 this->textRender = 0;
128 this->createsoftmask = 0;
129 this->transparencygroup = 0;
132 GBool GFXOutputDev::interpretType3Chars()
137 typedef struct _drawnchar
155 chars = (drawnchar_t*)malloc(sizeof(drawnchar_t)*buf_size);
156 memset(chars, 0, sizeof(drawnchar_t)*buf_size);
161 free(chars);chars = 0;
168 chars = (drawnchar_t*)realloc(chars, sizeof(drawnchar_t)*buf_size);
172 void addChar(int charid, gfxcoord_t x, gfxcoord_t y, gfxcolor_t color)
175 chars[num_chars].x = x;
176 chars[num_chars].y = y;
177 chars[num_chars].color = color;
178 chars[num_chars].charid = charid;
182 static char*getFontID(GfxFont*font);
184 GFXOutputDev::GFXOutputDev(parameter_t*p)
187 this->textmodeinfo = 0;
191 this->type3active = 0;
194 this->substitutepos = 0;
195 this->type3Warning = 0;
196 this->user_movex = 0;
197 this->user_movey = 0;
200 this->user_clipx1 = 0;
201 this->user_clipy1 = 0;
202 this->user_clipx2 = 0;
203 this->user_clipy2 = 0;
204 this->current_text_stroke = 0;
205 this->current_text_clip = 0;
207 this->outer_clip_box = 0;
209 this->pagebuflen = 0;
212 this->forceType0Fonts=1;
213 this->config_use_fontconfig=1;
215 this->parameters = p;
217 /* configure device */
219 if(!strcmp(p->name,"forceType0Fonts")) {
220 this->forceType0Fonts = atoi(p->value);
221 } else if(!strcmp(p->name,"fontconfig")) {
222 this->config_use_fontconfig = atoi(p->value);
228 void GFXOutputDev::setDevice(gfxdevice_t*dev)
230 parameter_t*p = this->parameters;
232 /* TODO: get rid of this */
236 this->device->setparameter(this->device, p->name, p->value);
242 void GFXOutputDev::setMove(int x,int y)
244 this->user_movex = x;
245 this->user_movey = y;
248 void GFXOutputDev::setClip(int x1,int y1,int x2,int y2)
250 if(x2<x1) {int x3=x1;x1=x2;x2=x3;}
251 if(y2<y1) {int y3=y1;y1=y2;y2=y3;}
253 this->user_clipx1 = x1;
254 this->user_clipy1 = y1;
255 this->user_clipx2 = x2;
256 this->user_clipy2 = y2;
259 static char*getFontID(GfxFont*font)
261 Ref*ref = font->getID();
262 GString*gstr = font->getName();
263 char* fname = gstr==0?0:gstr->getCString();
266 sprintf(buf, "font-%d-%d", ref->num, ref->gen);
268 sprintf(buf, "%s-%d-%d", fname, ref->num, ref->gen);
273 static char*getFontName(GfxFont*font)
276 GString*gstr = font->getName();
277 char* fname = gstr==0?0:gstr->getCString();
281 sprintf(buf, "UFONT%d", r->num);
282 fontid = strdup(buf);
284 fontid = strdup(fname);
288 char* plus = strchr(fontid, '+');
289 if(plus && plus < &fontid[strlen(fontid)-1]) {
290 fontname = strdup(plus+1);
292 fontname = strdup(fontid);
298 static char mybuf[1024];
299 static char* gfxstate2str(GfxState *state)
303 bufpos+=sprintf(bufpos,"CTM[%.3f/%.3f/%.3f/%.3f/%.3f/%.3f] ",
310 if(state->getX1()!=0.0)
311 bufpos+=sprintf(bufpos,"X1-%.1f ",state->getX1());
312 if(state->getY1()!=0.0)
313 bufpos+=sprintf(bufpos,"Y1-%.1f ",state->getY1());
314 bufpos+=sprintf(bufpos,"X2-%.1f ",state->getX2());
315 bufpos+=sprintf(bufpos,"Y2-%.1f ",state->getY2());
316 bufpos+=sprintf(bufpos,"PW%.1f ",state->getPageWidth());
317 bufpos+=sprintf(bufpos,"PH%.1f ",state->getPageHeight());
318 /*bufpos+=sprintf(bufpos,"FC[%.1f/%.1f] ",
319 state->getFillColor()->c[0], state->getFillColor()->c[1]);
320 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f] ",
321 state->getStrokeColor()->c[0], state->getFillColor()->c[1]);*/
322 /* bufpos+=sprintf(bufpos,"FC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
323 state->getFillColor()->c[0], state->getFillColor()->c[1],
324 state->getFillColor()->c[2], state->getFillColor()->c[3],
325 state->getFillColor()->c[4], state->getFillColor()->c[5],
326 state->getFillColor()->c[6], state->getFillColor()->c[7]);
327 bufpos+=sprintf(bufpos,"SC[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f/%.1f]",
328 state->getStrokeColor()->c[0], state->getFillColor()->c[1],
329 state->getStrokeColor()->c[2], state->getFillColor()->c[3],
330 state->getStrokeColor()->c[4], state->getFillColor()->c[5],
331 state->getStrokeColor()->c[6], state->getFillColor()->c[7]);*/
332 state->getFillRGB(&rgb);
333 if(rgb.r || rgb.g || rgb.b)
334 bufpos+=sprintf(bufpos,"FR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
335 state->getStrokeRGB(&rgb);
336 if(rgb.r || rgb.g || rgb.b)
337 bufpos+=sprintf(bufpos,"SR[%.1f/%.1f/%.1f] ", rgb.r,rgb.g,rgb.b);
338 if(state->getFillColorSpace()->getNComps()>1)
339 bufpos+=sprintf(bufpos,"CS[[%d]] ",state->getFillColorSpace()->getNComps());
340 if(state->getStrokeColorSpace()->getNComps()>1)
341 bufpos+=sprintf(bufpos,"SS[[%d]] ",state->getStrokeColorSpace()->getNComps());
342 if(state->getFillPattern())
343 bufpos+=sprintf(bufpos,"FP%08x ", state->getFillPattern());
344 if(state->getStrokePattern())
345 bufpos+=sprintf(bufpos,"SP%08x ", state->getStrokePattern());
347 if(state->getFillOpacity()!=1.0)
348 bufpos+=sprintf(bufpos,"FO%.1f ", state->getFillOpacity());
349 if(state->getStrokeOpacity()!=1.0)
350 bufpos+=sprintf(bufpos,"SO%.1f ", state->getStrokeOpacity());
352 bufpos+=sprintf(bufpos,"LW%.1f ", state->getLineWidth());
357 state->getLineDash(&dash, &length, &start);
361 bufpos+=sprintf(bufpos,"DASH%.1f[",start);
362 for(t=0;t<length;t++) {
363 bufpos+=sprintf(bufpos,"D%.1f",dash[t]);
365 bufpos+=sprintf(bufpos,"]");
368 if(state->getFlatness()!=1)
369 bufpos+=sprintf(bufpos,"F%d ", state->getFlatness());
370 if(state->getLineJoin()!=0)
371 bufpos+=sprintf(bufpos,"J%d ", state->getLineJoin());
372 if(state->getLineJoin()!=0)
373 bufpos+=sprintf(bufpos,"C%d ", state->getLineCap());
374 if(state->getLineJoin()!=0)
375 bufpos+=sprintf(bufpos,"ML%d ", state->getMiterLimit());
377 if(state->getFont() && getFontID(state->getFont()))
378 bufpos+=sprintf(bufpos,"F\"%s\" ",getFontID(state->getFont()));
379 bufpos+=sprintf(bufpos,"FS%.1f ", state->getFontSize());
380 bufpos+=sprintf(bufpos,"MAT[%.1f/%.1f/%.1f/%.1f/%.1f/%.1f] ", state->getTextMat()[0],state->getTextMat()[1],state->getTextMat()[2],
381 state->getTextMat()[3],state->getTextMat()[4],state->getTextMat()[5]);
382 if(state->getCharSpace())
383 bufpos+=sprintf(bufpos,"CS%.5f ", state->getCharSpace());
384 if(state->getWordSpace())
385 bufpos+=sprintf(bufpos,"WS%.5f ", state->getWordSpace());
386 if(state->getHorizScaling()!=1.0)
387 bufpos+=sprintf(bufpos,"SC%.1f ", state->getHorizScaling());
388 if(state->getLeading())
389 bufpos+=sprintf(bufpos,"L%.1f ", state->getLeading());
391 bufpos+=sprintf(bufpos,"R%.1f ", state->getRise());
392 if(state->getRender())
393 bufpos+=sprintf(bufpos,"R%d ", state->getRender());
394 bufpos+=sprintf(bufpos,"P%08x ", state->getPath());
395 bufpos+=sprintf(bufpos,"CX%.1f ", state->getCurX());
396 bufpos+=sprintf(bufpos,"CY%.1f ", state->getCurY());
397 if(state->getLineX())
398 bufpos+=sprintf(bufpos,"LX%.1f ", state->getLineX());
399 if(state->getLineY())
400 bufpos+=sprintf(bufpos,"LY%.1f ", state->getLineY());
401 bufpos+=sprintf(bufpos," ");
405 static void dumpFontInfo(char*loglevel, GfxFont*font);
406 static int lastdumps[1024];
407 static int lastdumppos = 0;
412 static void showFontError(GfxFont*font, int nr)
416 for(t=0;t<lastdumppos;t++)
417 if(lastdumps[t] == r->num)
421 if(lastdumppos<sizeof(lastdumps)/sizeof(int))
422 lastdumps[lastdumppos++] = r->num;
424 msg("<warning> The following font caused problems:");
426 msg("<warning> The following font caused problems (substituting):");
428 msg("<warning> The following Type 3 Font will be rendered as bitmap:");
429 dumpFontInfo("<warning>", font);
432 static void dumpFontInfo(char*loglevel, GfxFont*font)
434 char* id = getFontID(font);
435 char* name = getFontName(font);
436 Ref* r=font->getID();
437 msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen);
439 GString*gstr = font->getTag();
441 msg("%s| Tag: %s\n", loglevel, id);
443 if(font->isCIDFont()) msg("%s| is CID font\n", loglevel);
445 GfxFontType type=font->getType();
447 case fontUnknownType:
448 msg("%s| Type: unknown\n",loglevel);
451 msg("%s| Type: 1\n",loglevel);
454 msg("%s| Type: 1C\n",loglevel);
457 msg("%s| Type: 3\n",loglevel);
460 msg("%s| Type: TrueType\n",loglevel);
463 msg("%s| Type: CIDType0\n",loglevel);
466 msg("%s| Type: CIDType0C\n",loglevel);
469 msg("%s| Type: CIDType2\n",loglevel);
474 GBool embedded = font->getEmbeddedFontID(&embRef);
476 if(font->getEmbeddedFontName()) {
477 embeddedName = font->getEmbeddedFontName()->getCString();
480 msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num);
482 gstr = font->getExtFontFile();
484 msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString()));
486 // Get font descriptor flags.
487 if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel);
488 if(font->isSerif()) msg("%s| is serif\n", loglevel);
489 if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel);
490 if(font->isItalic()) msg("%s| is italic\n", loglevel);
491 if(font->isBold()) msg("%s| is bold\n", loglevel);
497 //void GFXOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) {printf("void GFXOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) \n");}
498 //void GFXOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool inlineImg) {printf("void GFXOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool inlineImg) \n");}
501 void dump_outline(gfxline_t*line)
504 if(line->type == gfx_moveTo) {
505 msg("<debug> | moveTo %.2f %.2f", line->x,line->y);
506 } else if(line->type == gfx_lineTo) {
507 msg("<debug> | lineTo %.2f %.2f", line->x,line->y);
508 } else if(line->type == gfx_splineTo) {
509 msg("<debug> | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y);
515 gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey)
517 int num = path->getNumSubpaths();
520 double lastx=0,lasty=0,posx=0,posy=0;
523 msg("<warning> empty path");
527 gfxdrawer_target_gfxline(&draw);
529 for(t = 0; t < num; t++) {
530 GfxSubpath *subpath = path->getSubpath(t);
531 int subnum = subpath->getNumPoints();
532 double bx=0,by=0,cx=0,cy=0;
534 for(s=0;s<subnum;s++) {
537 state->transform(subpath->getX(s),subpath->getY(s),&x,&y);
542 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
543 draw.lineTo(&draw, lastx, lasty);
545 draw.moveTo(&draw, x,y);
550 } else if(subpath->getCurve(s) && cpos==0) {
554 } else if(subpath->getCurve(s) && cpos==1) {
562 draw.lineTo(&draw, x,y);
564 gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y, 0.05);
571 /* fix non-closed lines */
572 if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) {
573 draw.lineTo(&draw, lastx, lasty);
575 gfxline_t*result = (gfxline_t*)draw.result(&draw);
579 /*----------------------------------------------------------------------------
580 * Primitive Graphic routines
581 *----------------------------------------------------------------------------*/
583 void GFXOutputDev::strokeGfxline(GfxState *state, gfxline_t*line)
585 int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square
586 int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel
587 double miterLimit = state->getMiterLimit();
588 double width = state->getTransformedLineWidth();
591 double opaq = state->getStrokeOpacity();
593 state->getFillRGB(&rgb);
595 state->getStrokeRGB(&rgb);
597 col.r = colToByte(rgb.r);
598 col.g = colToByte(rgb.g);
599 col.b = colToByte(rgb.b);
600 col.a = (unsigned char)(opaq*255);
602 gfx_capType capType = gfx_capRound;
603 if(lineCap == 0) capType = gfx_capButt;
604 else if(lineCap == 1) capType = gfx_capRound;
605 else if(lineCap == 2) capType = gfx_capSquare;
607 gfx_joinType joinType = gfx_joinRound;
608 if(lineJoin == 0) joinType = gfx_joinMiter;
609 else if(lineJoin == 1) joinType = gfx_joinRound;
610 else if(lineJoin == 2) joinType = gfx_joinBevel;
613 double dashphase = 0;
615 state->getLineDash(&ldash, &dashnum, &dashphase);
619 if(dashnum && ldash) {
620 float * dash = (float*)malloc(sizeof(float)*(dashnum+1));
624 msg("<trace> %d dashes", dashnum);
625 msg("<trace> | phase: %f", dashphase);
626 for(t=0;t<dashnum;t++) {
628 msg("<trace> | d%-3d: %f", t, ldash[t]);
631 if(getLogLevel() >= LOGLEVEL_TRACE) {
635 line2 = gfxtool_dash_line(line, dash, dashphase);
638 msg("<trace> After dashing:");
641 if(getLogLevel() >= LOGLEVEL_TRACE) {
642 msg("<trace> stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x\n",
644 lineJoin==0?"miter": (lineJoin==1?"round":"bevel"),
645 lineCap==0?"butt": (lineJoin==1?"round":"square"),
647 col.r,col.g,col.b,col.a
652 //swfoutput_drawgfxline(output, line, width, &col, capType, joinType, miterLimit);
653 device->stroke(device, line, width, &col, capType, joinType, miterLimit);
659 gfxcolor_t getFillColor(GfxState * state)
662 double opaq = state->getFillOpacity();
663 state->getFillRGB(&rgb);
665 col.r = colToByte(rgb.r);
666 col.g = colToByte(rgb.g);
667 col.b = colToByte(rgb.b);
668 col.a = (unsigned char)(opaq*255);
672 void GFXOutputDev::fillGfxLine(GfxState *state, gfxline_t*line)
674 gfxcolor_t col = getFillColor(state);
676 if(getLogLevel() >= LOGLEVEL_TRACE) {
677 msg("<trace> fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a);
680 if(states[statepos].transparencygroup && col.a != 255)
683 device->fill(device, line, &col);
686 void GFXOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line)
688 if(getLogLevel() >= LOGLEVEL_TRACE) {
689 msg("<trace> clip\n");
693 device->startclip(device, line);
694 states[statepos].clipping++;
697 void GFXOutputDev::clip(GfxState *state)
699 if(states[statepos].createsoftmask)
702 GfxPath * path = state->getPath();
703 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex + clipmovex, user_movey + clipmovey);
704 clipToGfxLine(state, line);
708 void GFXOutputDev::eoClip(GfxState *state)
710 GfxPath * path = state->getPath();
711 gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex + clipmovex, user_movey + clipmovey);
713 if(getLogLevel() >= LOGLEVEL_TRACE) {
714 msg("<trace> eoclip\n");
718 device->startclip(device, line);
719 states[statepos].clipping++;
723 void GFXOutputDev::endframe()
726 device->endclip(device);
730 device->endpage(device);
733 void GFXOutputDev::finish()
737 device->endclip(device);
743 GFXOutputDev::~GFXOutputDev()
748 free(this->pages); this->pages = 0;
751 fontlist_t*l = this->fontlist;
753 fontlist_t*next = l->next;
755 gfxfont_free(l->font);
756 free(l->filename);l->filename=0;
762 GBool GFXOutputDev::upsideDown()
766 GBool GFXOutputDev::useDrawChar()
771 char*renderModeDesc[]= {"fill", "stroke", "fill+stroke", "invisible",
772 "clip+fill", "stroke+clip", "fill+stroke+clip", "clip"};
774 #define RENDER_FILL 0
775 #define RENDER_STROKE 1
776 #define RENDER_FILLSTROKE 2
777 #define RENDER_INVISIBLE 3
778 #define RENDER_CLIP 4
780 static char tmp_printstr[4096];
781 char* makeStringPrintable(char*str)
783 int len = strlen(str);
798 tmp_printstr[len++] = '.';
799 tmp_printstr[len++] = '.';
800 tmp_printstr[len++] = '.';
802 tmp_printstr[len] = 0;
807 int getGfxCharID(gfxfont_t*font, int charnr, char *charname, int u)
812 /* find out char name from unicode index
813 TODO: should be precomputed
815 for(t=0;t<sizeof(nameToUnicodeTab)/sizeof(nameToUnicodeTab[0]);t++) {
816 if(nameToUnicodeTab[t].u == u) {
817 uniname = nameToUnicodeTab[t].name;
825 for(t=0;t<font->num_glyphs;t++) {
826 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,charname)) {
827 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
831 /* if we didn't find the character, maybe
832 we can find the capitalized version */
833 for(t=0;t<font->num_glyphs;t++) {
834 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,charname)) {
835 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
843 for(t=0;t<font->num_glyphs;t++) {
844 if(font->glyphs[t].name && !strcmp(font->glyphs[t].name,uniname)) {
845 msg("<debug> Char [%d,%s,>%d(%s)<] maps to %d\n", charnr, charname, u, uniname, t);
849 /* if we didn't find the character, maybe
850 we can find the capitalized version */
851 for(t=0;t<font->num_glyphs;t++) {
852 if(font->glyphs[t].name && !strcasecmp(font->glyphs[t].name,uniname)) {
853 msg("<debug> Char [%d,%s,>>%d(%s)<<] maps to %d\n", charnr, charname, u, uniname, t);
859 /* try to use the unicode id */
860 if(u>=0 && u<font->max_unicode && font->unicode2glyph[u]>=0) {
861 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->unicode2glyph[u]);
862 return font->unicode2glyph[u];
865 if(charnr>=0 && charnr<font->num_glyphs) {
866 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
874 void GFXOutputDev::beginString(GfxState *state, GString *s)
876 int render = state->getRender();
877 if(current_text_stroke) {
878 msg("<error> Error: Incompatible change of text rendering to %d while inside cliptext", render);
881 msg("<trace> beginString(%s) render=%d", makeStringPrintable(s->getCString()), render);
882 double m11,m21,m12,m22;
883 // msg("<debug> %s beginstring \"%s\"\n", gfxstate2str(state), s->getCString());
884 state->getFontTransMat(&m11, &m12, &m21, &m22);
885 m11 *= state->getHorizScaling();
886 m21 *= state->getHorizScaling();
888 this->current_font_matrix.m00 = m11 / 1024.0;
889 this->current_font_matrix.m01 = m12 / 1024.0;
890 this->current_font_matrix.m10 = -m21 / 1024.0;
891 this->current_font_matrix.m11 = -m22 / 1024.0;
892 this->current_font_matrix.tx = 0;
893 this->current_font_matrix.ty = 0;
895 gfxmatrix_t m = this->current_font_matrix;
897 /*if(render != 3 && render != 0)
898 msg("<warning> Text rendering mode %d (%s) not fully supported yet (for text \"%s\")", render, renderModeDesc[render&7], makeStringPrintable(s->getCString()));*/
899 states[statepos].textRender = render;
902 void GFXOutputDev::drawChar(GfxState *state, double x, double y,
903 double dx, double dy,
904 double originX, double originY,
905 CharCode c, int nBytes, Unicode *_u, int uLen)
907 if(states[statepos].createsoftmask)
910 int render = state->getRender();
911 // check for invisible text -- this is used by Acrobat Capture
913 msg("<debug> Ignoring invisible text: char %d at %f,%f", c, x, y);
917 if(states[statepos].textRender != render)
918 msg("<error> Internal error: drawChar.render!=beginString.render");
920 gfxcolor_t col = getFillColor(state);
922 Gushort *CIDToGIDMap = 0;
923 GfxFont*font = state->getFont();
925 if(font->getType() == fontType3) {
926 /* type 3 chars are passed as graphics */
927 msg("<debug> type3 char at %f/%f", x, y);
937 if(font->isCIDFont()) {
938 GfxCIDFont*cfont = (GfxCIDFont*)font;
940 if(font->getType() == fontCIDType2)
941 CIDToGIDMap = cfont->getCIDToGID();
944 font8 = (Gfx8BitFont*)font;
945 char**enc=font8->getEncoding();
949 msg("<debug> drawChar(%f, %f, c='%c' (%d), GID=%d, u=%d <%d>) CID=%d name=\"%s\" render=%d\n", x, y, (c&127)>=32?c:'?', c, CIDToGIDMap[c], u, uLen, font->isCIDFont(), FIXNULL(name), render);
952 msg("<debug> drawChar(%f,%f,c='%c' (%d), u=%d <%d>) CID=%d name=\"%s\" render=%d\n",x,y,(c&127)>=32?c:'?',c,u, uLen, font->isCIDFont(), FIXNULL(name), render);
958 charid = getGfxCharID(current_gfxfont, c, name, u);
960 charid = getGfxCharID(current_gfxfont, c, name, -1);
963 /* multiple unicodes- should usually map to a ligature.
964 if the ligature doesn't exist, we need to draw
965 the characters one-by-one. */
967 msg("<warning> ligature %d missing in font %s\n", c, current_gfxfont->id);
968 for(t=0;t<uLen;t++) {
969 drawChar(state, x, y, dx, dy, originX, originY, c, nBytes, _u+t, 1);
975 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
976 FIXNULL(name),c, u, FIXNULL((char*)current_gfxfont->id), current_gfxfont->num_glyphs);
980 gfxmatrix_t m = this->current_font_matrix;
981 state->transform(x, y, &m.tx, &m.ty);
982 m.tx += user_movex + clipmovex;
983 m.ty += user_movey + clipmovey;
985 if(render == RENDER_FILL) {
986 device->drawchar(device, current_gfxfont, charid, &col, &m);
988 msg("<debug> Drawing glyph %d as shape", charid);
990 msg("<notice> Some texts will be rendered as shape");
993 gfxline_t*glyph = current_gfxfont->glyphs[charid].line;
994 gfxline_t*tglyph = gfxline_clone(glyph);
995 gfxline_transform(tglyph, &m);
996 if((render&3) != RENDER_INVISIBLE) {
997 gfxline_t*add = gfxline_clone(tglyph);
998 current_text_stroke = gfxline_append(current_text_stroke, add);
1000 if(render&RENDER_CLIP) {
1001 gfxline_t*add = gfxline_clone(tglyph);
1002 current_text_clip = gfxline_append(current_text_clip, add);
1004 gfxline_free(tglyph);
1008 void GFXOutputDev::endString(GfxState *state)
1010 int render = state->getRender();
1011 msg("<trace> endString() render=%d textstroke=%08x", render, current_text_stroke);
1012 if(states[statepos].textRender != render)
1013 msg("<error> Internal error: drawChar.render!=beginString.render");
1015 if(current_text_stroke) {
1016 /* fillstroke and stroke text rendering objects we can process right
1017 now (as there may be texts of other rendering modes in this
1018 text object)- clipping objects have to wait until endTextObject,
1020 device->setparameter(device, "mark","TXT");
1021 if((render&3) == RENDER_FILL) {
1022 fillGfxLine(state, current_text_stroke);
1023 gfxline_free(current_text_stroke);
1024 current_text_stroke = 0;
1025 } else if((render&3) == RENDER_FILLSTROKE) {
1026 fillGfxLine(state, current_text_stroke);
1027 strokeGfxline(state, current_text_stroke);
1028 gfxline_free(current_text_stroke);
1029 current_text_stroke = 0;
1030 } else if((render&3) == RENDER_STROKE) {
1031 strokeGfxline(state, current_text_stroke);
1032 gfxline_free(current_text_stroke);
1033 current_text_stroke = 0;
1035 device->setparameter(device, "mark","");
1039 void GFXOutputDev::endTextObject(GfxState *state)
1041 int render = state->getRender();
1042 msg("<trace> endTextObject() render=%d textstroke=%08x clipstroke=%08x", render, current_text_stroke, current_text_clip);
1043 if(states[statepos].textRender != render)
1044 msg("<error> Internal error: drawChar.render!=beginString.render");
1046 if(current_text_clip) {
1047 device->setparameter(device, "mark","TXT");
1048 clipToGfxLine(state, current_text_clip);
1049 device->setparameter(device, "mark","");
1050 gfxline_free(current_text_clip);
1051 current_text_clip = 0;
1055 /* the logic seems to be as following:
1056 first, beginType3Char is called, with the charcode and the coordinates.
1057 if this function returns true, it already knew about the char and has now drawn it.
1058 if the function returns false, it's a new char, and type3D1 is called with some parameters-
1059 the all draw operations until endType3Char are part of the char (which in this moment is
1060 at the position first passed to beginType3Char). the char ends with endType3Char.
1062 The drawing operations between beginType3Char and endType3Char are somewhat different to
1063 the normal ones. For example, the fillcolor equals the stroke color.
1066 GBool GFXOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen)
1068 msg("<debug> beginType3Char %d, %08x, %d", code, *u, uLen);
1070 /* the character itself is going to be passed using the draw functions */
1071 return gFalse; /* gTrue= is_in_cache? */
1074 void GFXOutputDev::type3D0(GfxState *state, double wx, double wy) {
1075 msg("<debug> type3D0 width=%f height=%f", wx, wy);
1077 void GFXOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {
1078 msg("<debug> type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy,
1082 void GFXOutputDev::endType3Char(GfxState *state)
1085 msg("<debug> endType3Char");
1088 void GFXOutputDev::startFrame(int width, int height)
1090 if(outer_clip_box) {
1091 device->endclip(device);
1095 device->startpage(device, width, height);
1098 void GFXOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, double crop_y1, double crop_x2, double crop_y2)
1100 this->currentpage = pageNum;
1102 int rot = doc->getPageRotate(1);
1105 gfxline_t clippath[5];
1107 white.r = white.g = white.b = white.a = 255;
1109 /* state->transform(state->getX1(),state->getY1(),&x1,&y1);
1110 state->transform(state->getX2(),state->getY2(),&x2,&y2);
1111 Use CropBox, not MediaBox, as page size
1118 state->transform(crop_x1,crop_y1,&x1,&y1); //x1 += user_movex; y1 += user_movey;
1119 state->transform(crop_x2,crop_y2,&x2,&y2); //x2 += user_movex; y2 += user_movey;
1121 if(x2<x1) {double x3=x1;x1=x2;x2=x3;}
1122 if(y2<y1) {double y3=y1;y1=y2;y2=y3;}
1124 this->clipmovex = -(int)x1;
1125 this->clipmovey = -(int)y1;
1127 /* apply user clip box */
1128 if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) {
1129 /*if(user_clipx1 > x1)*/ x1 = user_clipx1;
1130 /*if(user_clipx2 < x2)*/ x2 = user_clipx2;
1131 /*if(user_clipy1 > y1)*/ y1 = user_clipy1;
1132 /*if(user_clipy2 < y2)*/ y2 = user_clipy2;
1133 msg("<verbose> Using user clip box %f/%f/%f/%f",x1,y1,x2,y2);
1136 //msg("<verbose> Bounding box is (%f,%f)-(%f,%f) [shifted by %d/%d]", x1,y1,x2,y2, user_movex, user_movey);
1138 msg("<notice> processing PDF page %d (%dx%d:%d:%d) (move:%d:%d)", pageNum, (int)x2-(int)x1,(int)y2-(int)y1, (int)x1, (int)y1, user_movex + clipmovex, user_movey + clipmovey);
1140 msg("<verbose> page is rotated %d degrees\n", rot);
1142 clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1];
1143 clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2];
1144 clippath[2].type = gfx_lineTo;clippath[2].x = x2; clippath[2].y = y2; clippath[2].next = &clippath[3];
1145 clippath[3].type = gfx_lineTo;clippath[3].x = x1; clippath[3].y = y2; clippath[3].next = &clippath[4];
1146 clippath[4].type = gfx_lineTo;clippath[4].x = x1; clippath[4].y = y1; clippath[4].next = 0;
1147 device->startclip(device, clippath); outer_clip_box = 1;
1148 device->fill(device, clippath, &white);
1151 void GFXOutputDev::drawLink(Link *link, Catalog *catalog)
1153 double x1, y1, x2, y2, w;
1154 gfxline_t points[5];
1157 msg("<debug> drawlink\n");
1159 link->getRect(&x1, &y1, &x2, &y2);
1160 cvtUserToDev(x1, y1, &x, &y);
1161 points[0].type = gfx_moveTo;
1162 points[0].x = points[4].x = x + user_movex + clipmovex;
1163 points[0].y = points[4].y = y + user_movey + clipmovey;
1164 points[0].next = &points[1];
1165 cvtUserToDev(x2, y1, &x, &y);
1166 points[1].type = gfx_lineTo;
1167 points[1].x = x + user_movex + clipmovex;
1168 points[1].y = y + user_movey + clipmovey;
1169 points[1].next = &points[2];
1170 cvtUserToDev(x2, y2, &x, &y);
1171 points[2].type = gfx_lineTo;
1172 points[2].x = x + user_movex + clipmovex;
1173 points[2].y = y + user_movey + clipmovey;
1174 points[2].next = &points[3];
1175 cvtUserToDev(x1, y2, &x, &y);
1176 points[3].type = gfx_lineTo;
1177 points[3].x = x + user_movex + clipmovex;
1178 points[3].y = y + user_movey + clipmovey;
1179 points[3].next = &points[4];
1180 cvtUserToDev(x1, y1, &x, &y);
1181 points[4].type = gfx_lineTo;
1182 points[4].x = x + user_movex + clipmovex;
1183 points[4].y = y + user_movey + clipmovey;
1186 msg("<trace> drawlink %.2f/%.2f %.2f/%.2f %.2f/%.2f %.2f/%.2f\n",
1187 points[0].x, points[0].y,
1188 points[1].x, points[1].y,
1189 points[2].x, points[2].y,
1190 points[3].x, points[3].y);
1192 LinkAction*action=link->getAction();
1198 msg("<trace> drawlink action=%d\n", action->getKind());
1199 switch(action->getKind())
1203 LinkGoTo *ha=(LinkGoTo *)link->getAction();
1204 LinkDest *dest=NULL;
1205 if (ha->getDest()==NULL)
1206 dest=catalog->findDest(ha->getNamedDest());
1207 else dest=ha->getDest();
1209 if (dest->isPageRef()){
1210 Ref pageref=dest->getPageRef();
1211 page=catalog->findPage(pageref.num,pageref.gen);
1213 else page=dest->getPageNum();
1214 sprintf(buf, "%d", page);
1221 LinkGoToR*l = (LinkGoToR*)action;
1222 GString*g = l->getFileName();
1224 s = strdup(g->getCString());
1226 /* if the GoToR link has no filename, then
1227 try to find a refernce in the *local*
1229 GString*g = l->getNamedDest();
1231 s = strdup(g->getCString());
1237 LinkNamed*l = (LinkNamed*)action;
1238 GString*name = l->getName();
1240 s = strdup(name->lowerCase()->getCString());
1241 named = name->getCString();
1244 if(strstr(s, "next") || strstr(s, "forward"))
1246 page = currentpage + 1;
1248 else if(strstr(s, "prev") || strstr(s, "back"))
1250 page = currentpage - 1;
1252 else if(strstr(s, "last") || strstr(s, "end"))
1254 if(pages && pagepos>0)
1255 page = pages[pagepos-1];
1257 else if(strstr(s, "first") || strstr(s, "top"))
1265 case actionLaunch: {
1267 LinkLaunch*l = (LinkLaunch*)action;
1268 GString * str = new GString(l->getFileName());
1269 GString * params = l->getParams();
1271 str->append(params);
1272 s = strdup(str->getCString());
1279 LinkURI*l = (LinkURI*)action;
1280 GString*g = l->getURI();
1282 url = g->getCString();
1287 case actionUnknown: {
1289 LinkUnknown*l = (LinkUnknown*)action;
1294 msg("<error> Unknown link type!\n");
1299 if(!s) s = strdup("-?-");
1301 msg("<trace> drawlink s=%s\n", s);
1303 if(!linkinfo && (page || s))
1305 msg("<notice> File contains links");
1313 for(t=1;t<=pagepos;t++) {
1314 if(pages[t]==page) {
1323 sprintf(buf, "page%d", lpage);
1324 device->drawlink(device, points, buf);
1328 device->drawlink(device, points, s);
1331 msg("<verbose> \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page);
1335 void GFXOutputDev::saveState(GfxState *state) {
1336 msg("<trace> saveState\n");
1339 msg("<error> Too many nested states in pdf.");
1343 states[statepos].textRender = states[statepos-1].textRender;
1344 states[statepos].createsoftmask = states[statepos-1].createsoftmask;
1345 states[statepos].transparencygroup = states[statepos-1].transparencygroup;
1346 states[statepos].clipping = 0;
1349 void GFXOutputDev::restoreState(GfxState *state) {
1351 msg("<error> Invalid restoreState");
1354 msg("<trace> restoreState");
1356 while(states[statepos].clipping) {
1357 device->endclip(device);
1358 states[statepos].clipping--;
1363 char* GFXOutputDev::searchFont(char*name)
1367 int is_standard_font = 0;
1369 msg("<verbose> SearchFont(%s)", name);
1371 /* see if it is a pdf standard font */
1372 for(i=0;i<sizeof(pdf2t1map)/sizeof(mapping);i++)
1374 if(!strcmp(name, pdf2t1map[i].pdffont))
1376 name = pdf2t1map[i].filename;
1377 is_standard_font = 1;
1381 /* look in all font files */
1382 for(i=0;i<fontnum;i++)
1384 if(strstr(fonts[i].filename, name))
1386 if(!fonts[i].used) {
1389 if(!is_standard_font)
1390 msg("<notice> Using %s for %s", fonts[i].filename, name);
1392 return strdup(fonts[i].filename);
1398 void GFXOutputDev::updateLineWidth(GfxState *state)
1400 double width = state->getTransformedLineWidth();
1401 //swfoutput_setlinewidth(&device, width);
1404 void GFXOutputDev::updateLineCap(GfxState *state)
1406 int c = state->getLineCap();
1409 void GFXOutputDev::updateLineJoin(GfxState *state)
1411 int j = state->getLineJoin();
1414 void GFXOutputDev::updateFillColor(GfxState *state)
1417 double opaq = state->getFillOpacity();
1418 state->getFillRGB(&rgb);
1420 void GFXOutputDev::updateFillOpacity(GfxState *state)
1423 double opaq = state->getFillOpacity();
1424 state->getFillRGB(&rgb);
1427 void GFXOutputDev::updateStrokeColor(GfxState *state)
1430 double opaq = state->getStrokeOpacity();
1431 state->getStrokeRGB(&rgb);
1434 void FoFiWrite(void *stream, char *data, int len)
1436 int ret = fwrite(data, len, 1, (FILE*)stream);
1439 char*GFXOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font)
1441 char*tmpFileName = NULL;
1447 Object refObj, strObj;
1449 tmpFileName = mktmpname(namebuf);
1452 ret = font->getEmbeddedFontID(&embRef);
1454 msg("<verbose> Didn't get embedded font id");
1455 /* not embedded- the caller should now search the font
1456 directories for this font */
1460 f = fopen(tmpFileName, "wb");
1462 msg("<error> Couldn't create temporary Type 1 font file");
1466 /*if(font->isCIDFont()) {
1467 GfxCIDFont* cidFont = (GfxCIDFont *)font;
1468 GString c = cidFont->getCollection();
1469 msg("<notice> Collection: %s", c.getCString());
1472 //if (font->getType() == fontType1C) {
1473 if (0) { //font->getType() == fontType1C) {
1474 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1476 msg("<error> Couldn't read embedded font file");
1479 FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen);
1481 cvt->convertToType1(NULL, gTrue, FoFiWrite, f);
1482 //cvt->convertToCIDType0("test", f);
1483 //cvt->convertToType0("test", f);
1486 } else if(font->getType() == fontTrueType) {
1487 msg("<verbose> writing font using TrueTypeFontFile::writeTTF");
1488 if (!(fontBuf = font->readEmbFontFile(xref, &fontLen))) {
1490 msg("<error> Couldn't read embedded font file");
1493 FoFiTrueType *cvt = FoFiTrueType::make(fontBuf, fontLen);
1494 cvt->writeTTF(FoFiWrite, f);
1498 font->getEmbeddedFontID(&embRef);
1499 refObj.initRef(embRef.num, embRef.gen);
1500 refObj.fetch(ref, &strObj);
1502 strObj.streamReset();
1507 f4[t] = strObj.streamGetChar();
1508 f4c[t] = (char)f4[t];
1513 if(!strncmp(f4c, "true", 4)) {
1514 /* some weird TTF fonts don't start with 0,1,0,0 but with "true".
1515 Change this on the fly */
1516 f4[0] = f4[2] = f4[3] = 0;
1524 while ((c = strObj.streamGetChar()) != EOF) {
1528 strObj.streamClose();
1533 return strdup(tmpFileName);
1536 char* GFXOutputDev::searchForSuitableFont(GfxFont*gfxFont)
1538 char*name = getFontName(gfxFont);
1542 if(!this->config_use_fontconfig)
1545 #ifdef HAVE_FONTCONFIG
1546 FcPattern *pattern, *match;
1550 static int fcinitcalled = false;
1552 msg("<debug> searchForSuitableFont(%s)", name);
1554 // call init ony once
1555 if (!fcinitcalled) {
1556 msg("<debug> Initializing FontConfig...");
1557 fcinitcalled = true;
1559 msg("<debug> FontConfig Initialization failed. Disabling.");
1560 config_use_fontconfig = 0;
1563 msg("<debug> ...initialized FontConfig");
1566 msg("<debug> FontConfig: Create \"%s\" Family Pattern", name);
1567 pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL);
1568 if (gfxFont->isItalic()) // check for italic
1569 msg("<debug> FontConfig: Adding Italic Slant");
1570 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1571 if (gfxFont->isBold()) // check for bold
1572 msg("<debug> FontConfig: Adding Bold Weight");
1573 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1575 msg("<debug> FontConfig: Try to match...");
1576 // configure and match using the original font name
1577 FcConfigSubstitute(0, pattern, FcMatchPattern);
1578 FcDefaultSubstitute(pattern);
1579 match = FcFontMatch(0, pattern, &result);
1581 if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) {
1582 msg("<debug> FontConfig: family=%s", (char*)v);
1583 // if we get an exact match
1584 if (strcmp((char *)v, name) == 0) {
1585 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1586 filename = strdup((char*)v); // mem leak
1587 char *nfn = strrchr(filename, '/');
1588 if(nfn) fontname = strdup(nfn+1);
1589 else fontname = filename;
1591 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1593 // initialize patterns
1594 FcPatternDestroy(pattern);
1595 FcPatternDestroy(match);
1597 // now match against serif etc.
1598 if (gfxFont->isSerif()) {
1599 msg("<debug> FontConfig: Create Serif Family Pattern");
1600 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL);
1601 } else if (gfxFont->isFixedWidth()) {
1602 msg("<debug> FontConfig: Create Monospace Family Pattern");
1603 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL);
1605 msg("<debug> FontConfig: Create Sans Family Pattern");
1606 pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL);
1610 if (gfxFont->isItalic()) {
1611 msg("<debug> FontConfig: Adding Italic Slant");
1612 int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
1615 if (gfxFont->isBold()) {
1616 msg("<debug> FontConfig: Adding Bold Weight");
1617 int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
1620 msg("<debug> FontConfig: Try to match... (2)");
1621 // configure and match using serif etc
1622 FcConfigSubstitute (0, pattern, FcMatchPattern);
1623 FcDefaultSubstitute (pattern);
1624 match = FcFontMatch (0, pattern, &result);
1626 if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) {
1627 filename = strdup((char*)v); // mem leak
1628 char *nfn = strrchr(filename, '/');
1629 if(nfn) fontname = strdup(nfn+1);
1630 else fontname = filename;
1632 msg("<debug> FontConfig: Returning \"%s\"", fontname);
1636 //printf("FONTCONFIG: pattern");
1637 //FcPatternPrint(pattern);
1638 //printf("FONTCONFIG: match");
1639 //FcPatternPrint(match);
1641 FcPatternDestroy(pattern);
1642 FcPatternDestroy(match);
1644 pdfswf_addfont(filename);
1651 char* GFXOutputDev::substituteFont(GfxFont*gfxFont, char* oldname)
1653 char*fontname = 0, *filename = 0;
1654 msg("<notice> substituteFont(%s)", oldname);
1656 if(!(fontname = searchForSuitableFont(gfxFont))) {
1657 fontname = "Times-Roman";
1659 filename = searchFont(fontname);
1661 msg("<error> Couldn't find font %s- did you install the default fonts?", fontname);
1665 if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) {
1666 msg("<fatal> Too many fonts in file.");
1670 substitutesource[substitutepos] = strdup(oldname); //mem leak
1671 substitutetarget[substitutepos] = fontname;
1672 msg("<notice> substituting %s -> %s", FIXNULL(oldname), FIXNULL(fontname));
1675 return strdup(filename); //mem leak
1678 void unlinkfont(char* filename)
1685 if(!strncmp(&filename[l-4],".afm",4)) {
1686 memcpy(&filename[l-4],".pfb",4);
1688 memcpy(&filename[l-4],".pfa",4);
1690 memcpy(&filename[l-4],".afm",4);
1693 if(!strncmp(&filename[l-4],".pfa",4)) {
1694 memcpy(&filename[l-4],".afm",4);
1696 memcpy(&filename[l-4],".pfa",4);
1699 if(!strncmp(&filename[l-4],".pfb",4)) {
1700 memcpy(&filename[l-4],".afm",4);
1702 memcpy(&filename[l-4],".pfb",4);
1707 void GFXOutputDev::setXRef(PDFDoc*doc, XRef *xref)
1713 int GFXOutputDev::setGfxFont(char*id, char*name, char*filename, double maxSize)
1716 fontlist_t*last=0,*l = this->fontlist;
1719 msg("<error> Internal Error: FontID is null");
1721 /* TODO: should this be part of the state? */
1724 if(!strcmp(l->font->id, id)) {
1725 current_gfxfont = l->font;
1727 device->addfont(device, current_gfxfont);
1732 if(!filename) return 0;
1734 /* A font size of e.g. 9 means the font will be scaled down by
1735 1024 and scaled up by 9. So to have a maximum error of 1/20px,
1736 we have to divide 0.05 by (fontsize/1024)
1738 double quality = (1024 * 0.05) / maxSize;
1740 msg("<verbose> Loading %s...", filename);
1741 font = gfxfont_load(id, filename, quality);
1743 msg("<verbose> Couldn't load Font %s (%s)", filename, id);
1746 msg("<verbose> Font %s (%s) loaded successfully", filename, id);
1750 l->filename = strdup(filename);
1752 current_gfxfont = l->font;
1758 device->addfont(device, current_gfxfont);
1762 void GFXOutputDev::updateFont(GfxState *state)
1764 GfxFont*gfxFont = state->getFont();
1770 char * fontid = getFontID(gfxFont);
1771 char * fontname = getFontName(gfxFont);
1773 double maxSize = 1.0;
1776 maxSize = this->info->getMaximumFontSize(fontid);
1780 /* first, look if we substituted this font before-
1781 this way, we don't initialize the T1 Fonts
1783 for(t=0;t<substitutepos;t++) {
1784 if(!strcmp(fontid, substitutesource[t])) {
1785 free(fontid);fontid=0;
1786 fontid = strdup(substitutetarget[t]);
1791 /* second, see if this is a font which was used before-
1792 if so, we are done */
1793 if(setGfxFont(fontid, fontname, 0, 0)) {
1798 /* if(swfoutput_queryfont(&device, fontid))
1799 swfoutput_setfont(&device, fontid, 0);
1801 msg("<debug> updateFont(%s) [cached]", fontid);
1805 // look for Type 3 font
1806 if (gfxFont->getType() == fontType3) {
1808 type3Warning = gTrue;
1809 showFontError(gfxFont, 2);
1816 /* now either load the font, or find a substitution */
1819 GBool embedded = gfxFont->getEmbeddedFontID(&embRef);
1824 (gfxFont->getType() == fontType1 ||
1825 gfxFont->getType() == fontType1C ||
1826 (gfxFont->getType() == fontCIDType0C && forceType0Fonts) ||
1827 gfxFont->getType() == fontTrueType ||
1828 gfxFont->getType() == fontCIDType2
1831 fileName = writeEmbeddedFontToFile(xref, gfxFont);
1832 if(!fileName) showFontError(gfxFont,0);
1835 fileName = searchFont(fontname);
1836 if(!fileName) showFontError(gfxFont,0);
1839 char * fontname = getFontName(gfxFont);
1840 msg("<warning> Font %s %scould not be loaded.", fontname, embedded?"":"(not embedded) ");
1843 msg("<warning> Try putting a TTF version of that font (named \"%s.ttf\") into %s", fontname, lastfontdir);
1845 msg("<warning> Try specifying one or more font directories");
1847 fileName = substituteFont(gfxFont, fontid);
1850 if(fontid) { free(fontid);fontid = strdup(substitutetarget[substitutepos-1]); /*ugly hack*/};
1851 msg("<notice> Font is now %s (%s)", fontid, fileName);
1855 msg("<error> Couldn't set font %s\n", fontid);
1861 msg("<verbose> updateFont(%s) -> %s (max size: %f)", fontid, fileName, maxSize);
1862 dumpFontInfo("<verbose>", gfxFont);
1864 //swfoutput_setfont(&device, fontid, fileName);
1866 if(!setGfxFont(fontid, fontname, 0, 0)) {
1867 setGfxFont(fontid, fontname, fileName, maxSize);
1871 unlinkfont(fileName);
1881 #define SQR(x) ((x)*(x))
1883 unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize)
1885 if((newwidth<2 || newheight<2) ||
1886 (width<=newwidth || height<=newheight))
1888 unsigned char*newdata;
1890 newdata= (unsigned char*)malloc(newwidth*newheight);
1892 double fx = (double)(width)/newwidth;
1893 double fy = (double)(height)/newheight;
1895 int blocksize = (int)(8192/(fx*fy));
1896 int r = 8192*256/palettesize;
1897 for(x=0;x<newwidth;x++) {
1898 double ex = px + fx;
1899 int fromx = (int)px;
1901 int xweight1 = (int)(((fromx+1)-px)*256);
1902 int xweight2 = (int)((ex-tox)*256);
1904 for(y=0;y<newheight;y++) {
1905 double ey = py + fy;
1906 int fromy = (int)py;
1908 int yweight1 = (int)(((fromy+1)-py)*256);
1909 int yweight2 = (int)((ey-toy)*256);
1912 for(xx=fromx;xx<=tox;xx++)
1913 for(yy=fromy;yy<=toy;yy++) {
1914 int b = 1-data[width*yy+xx];
1916 if(xx==fromx) weight = (weight*xweight1)/256;
1917 if(xx==tox) weight = (weight*xweight2)/256;
1918 if(yy==fromy) weight = (weight*yweight1)/256;
1919 if(yy==toy) weight = (weight*yweight2)/256;
1922 //if(a) a=(palettesize-1)*r/blocksize;
1923 newdata[y*newwidth+x] = (a*blocksize)/r;
1931 #define IMAGE_TYPE_JPEG 0
1932 #define IMAGE_TYPE_LOSSLESS 1
1934 static void drawimage(gfxdevice_t*dev, gfxcolor_t* data, int sizex,int sizey,
1935 double x1,double y1,
1936 double x2,double y2,
1937 double x3,double y3,
1938 double x4,double y4, int type)
1940 gfxcolor_t*newpic=0;
1942 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
1943 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
1945 gfxline_t p1,p2,p3,p4,p5;
1946 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
1947 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
1948 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
1949 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
1950 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
1952 {p1.x = (int)(p1.x*20)/20.0;
1953 p1.y = (int)(p1.y*20)/20.0;
1954 p2.x = (int)(p2.x*20)/20.0;
1955 p2.y = (int)(p2.y*20)/20.0;
1956 p3.x = (int)(p3.x*20)/20.0;
1957 p3.y = (int)(p3.y*20)/20.0;
1958 p4.x = (int)(p4.x*20)/20.0;
1959 p4.y = (int)(p4.y*20)/20.0;
1960 p5.x = (int)(p5.x*20)/20.0;
1961 p5.y = (int)(p5.y*20)/20.0;
1968 m.m00 = (p4.x-p1.x)/sizex; m.m10 = (p2.x-p1.x)/sizey;
1969 m.m01 = (p4.y-p1.y)/sizex; m.m11 = (p2.y-p1.y)/sizey;
1974 img.data = (gfxcolor_t*)data;
1978 if(type == IMAGE_TYPE_JPEG)
1979 /* TODO: pass image_dpi to device instead */
1980 dev->setparameter(dev, "next_bitmap_is_jpeg", "1");
1982 dev->fillbitmap(dev, &p1, &img, &m, 0);
1985 void drawimagejpeg(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
1986 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
1988 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
1991 void drawimagelossless(gfxdevice_t*dev, gfxcolor_t*mem, int sizex,int sizey,
1992 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
1994 drawimage(dev,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
1998 void GFXOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str,
1999 int width, int height, GfxImageColorMap*colorMap, GBool invert,
2000 GBool inlineImg, int mask, int*maskColors,
2001 Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GfxImageColorMap*maskColorMap)
2003 double x1,y1,x2,y2,x3,y3,x4,y4;
2004 ImageStream *imgStr;
2009 unsigned char* maskbitmap = 0;
2012 ncomps = colorMap->getNumPixelComps();
2013 bits = colorMap->getBits();
2018 unsigned char buf[8];
2019 maskbitmap = (unsigned char*)malloc(maskHeight*maskWidth);
2021 ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, maskColorMap->getNumPixelComps(), maskColorMap->getBits());
2022 imgMaskStr->reset();
2023 unsigned char pal[256];
2024 int n = 1 << colorMap->getBits();
2029 maskColorMap->getGray(pixBuf, &gray);
2030 pal[t] = colToByte(gray);
2032 for (y = 0; y < maskHeight; y++) {
2033 for (x = 0; x < maskWidth; x++) {
2034 imgMaskStr->getPixel(buf);
2035 maskbitmap[y*maskWidth+x] = pal[buf[0]];
2040 ImageStream*imgMaskStr = new ImageStream(maskStr, maskWidth, 1, 1);
2041 imgMaskStr->reset();
2042 for (y = 0; y < maskHeight; y++) {
2043 for (x = 0; x < maskWidth; x++) {
2044 imgMaskStr->getPixel(buf);
2046 maskbitmap[y*maskWidth+x] = (buf[0]^1)*255;
2054 imgStr = new ImageStream(str, width, ncomps,bits);
2057 if(!width || !height || (height<=1 && width<=1))
2059 msg("<verbose> Ignoring %d by %d image", width, height);
2060 unsigned char buf[8];
2062 for (y = 0; y < height; ++y)
2063 for (x = 0; x < width; ++x) {
2064 imgStr->getPixel(buf);
2072 state->transform(0, 1, &x1, &y1); x1 += user_movex + clipmovex; y1 += user_movey + clipmovey;
2073 state->transform(0, 0, &x2, &y2); x2 += user_movex + clipmovex; y2 += user_movey + clipmovey;
2074 state->transform(1, 0, &x3, &y3); x3 += user_movex + clipmovex; y3 += user_movey + clipmovey;
2075 state->transform(1, 1, &x4, &y4); x4 += user_movex + clipmovex; y4 += user_movey + clipmovey;
2078 if(!pbminfo && !(str->getKind()==strDCT)) {
2080 msg("<notice> file contains pbm pictures %s",mask?"(masked)":"");
2084 msg("<verbose> drawing %d by %d masked picture\n", width, height);
2086 if(!jpeginfo && (str->getKind()==strDCT)) {
2087 msg("<notice> file contains jpeg pictures");
2093 unsigned char buf[8];
2095 unsigned char*pic = new unsigned char[width*height];
2096 gfxcolor_t pal[256];
2098 state->getFillRGB(&rgb);
2100 memset(pal,255,sizeof(pal));
2101 pal[0].r = (int)(colToByte(rgb.r)); pal[1].r = 0;
2102 pal[0].g = (int)(colToByte(rgb.g)); pal[1].g = 0;
2103 pal[0].b = (int)(colToByte(rgb.b)); pal[1].b = 0;
2104 pal[0].a = 255; pal[1].a = 0;
2107 int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3));
2108 int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2));
2109 for (y = 0; y < height; ++y)
2110 for (x = 0; x < width; ++x)
2112 imgStr->getPixel(buf);
2115 pic[width*y+x] = buf[0];
2118 /* the size of the drawn image is added to the identifier
2119 as the same image may require different bitmaps if displayed
2120 at different sizes (due to antialiasing): */
2123 unsigned char*pic2 = 0;
2126 pic2 = antialize(pic,width,height,realwidth,realheight,numpalette);
2135 height = realheight;
2139 /* make a black/white palette */
2141 float r = 255/(numpalette-1);
2143 for(t=0;t<numpalette;t++) {
2144 pal[t].r = colToByte(rgb.r);
2145 pal[t].g = colToByte(rgb.g);
2146 pal[t].b = colToByte(rgb.b);
2147 pal[t].a = (unsigned char)(t*r);
2151 gfxcolor_t*pic2 = new gfxcolor_t[width*height];
2152 for (y = 0; y < height; ++y) {
2153 for (x = 0; x < width; ++x) {
2154 pic2[width*y+x] = pal[pic[y*width+x]];
2157 drawimagelossless(device, pic2, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2161 if(maskbitmap) free(maskbitmap);
2167 if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) {
2168 gfxcolor_t*pic=new gfxcolor_t[width*height];
2169 for (y = 0; y < height; ++y) {
2170 for (x = 0; x < width; ++x) {
2171 imgStr->getPixel(pixBuf);
2172 colorMap->getRGB(pixBuf, &rgb);
2173 pic[width*y+x].r = (unsigned char)(colToByte(rgb.r));
2174 pic[width*y+x].g = (unsigned char)(colToByte(rgb.g));
2175 pic[width*y+x].b = (unsigned char)(colToByte(rgb.b));
2176 pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5);
2178 pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2182 if(str->getKind()==strDCT)
2183 drawimagejpeg(device, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2185 drawimagelossless(device, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2188 if(maskbitmap) free(maskbitmap);
2191 gfxcolor_t*pic=new gfxcolor_t[width*height];
2192 gfxcolor_t pal[256];
2193 int n = 1 << colorMap->getBits();
2195 for(t=0;t<256;t++) {
2197 colorMap->getRGB(pixBuf, &rgb);
2199 {/*if(maskColors && *maskColors==t) {
2200 msg("<notice> Color %d is transparent", t);
2201 if (imgData->maskColors) {
2203 for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) {
2204 if (pix[i] < imgData->maskColors[2*i] ||
2205 pix[i] > imgData->maskColors[2*i+1]) {
2220 pal[t].r = (unsigned char)(colToByte(rgb.r));
2221 pal[t].g = (unsigned char)(colToByte(rgb.g));
2222 pal[t].b = (unsigned char)(colToByte(rgb.b));
2223 pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5);
2226 for (y = 0; y < height; ++y) {
2227 for (x = 0; x < width; ++x) {
2228 imgStr->getPixel(pixBuf);
2229 pic[width*y+x] = pal[pixBuf[0]];
2231 pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)];
2235 drawimagelossless(device, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4);
2239 if(maskbitmap) free(maskbitmap);
2244 void GFXOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2245 int width, int height, GBool invert,
2248 if(states[statepos].createsoftmask)
2250 msg("<verbose> drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg);
2251 drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0, 0,0,0,0, 0);
2254 void GFXOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2255 int width, int height, GfxImageColorMap *colorMap,
2256 int *maskColors, GBool inlineImg)
2258 if(states[statepos].createsoftmask)
2260 msg("<verbose> drawImage %dx%d, %s, %s, inline=%d", width, height,
2261 colorMap?"colorMap":"no colorMap",
2262 maskColors?"maskColors":"no maskColors",
2265 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2266 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2267 drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors, 0,0,0,0, 0);
2270 void GFXOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
2271 int width, int height,
2272 GfxImageColorMap *colorMap,
2273 Stream *maskStr, int maskWidth, int maskHeight,
2276 if(states[statepos].createsoftmask)
2278 msg("<verbose> drawMaskedImage %dx%d, %s, %dx%d mask", width, height,
2279 colorMap?"colorMap":"no colorMap",
2280 maskWidth, maskHeight);
2282 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2283 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2284 drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, maskInvert, 0);
2287 void GFXOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
2288 int width, int height,
2289 GfxImageColorMap *colorMap,
2291 int maskWidth, int maskHeight,
2292 GfxImageColorMap *maskColorMap)
2294 if(states[statepos].createsoftmask)
2296 msg("<verbose> drawSoftMaskedImage %dx%d, %s, %dx%d mask", width, height,
2297 colorMap?"colorMap":"no colorMap",
2298 maskWidth, maskHeight);
2300 msg("<verbose> colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(),
2301 colorMap->getBits(),colorMap->getColorSpace()->getMode());
2302 drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, 0, maskColorMap);
2305 void GFXOutputDev::stroke(GfxState *state)
2307 if(states[statepos].createsoftmask)
2310 GfxPath * path = state->getPath();
2311 gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex + clipmovex, user_movey + clipmovey);
2312 strokeGfxline(state, line);
2316 void GFXOutputDev::fill(GfxState *state)
2318 if(states[statepos].createsoftmask)
2321 GfxPath * path = state->getPath();
2322 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex + clipmovex, user_movey + clipmovey);
2323 fillGfxLine(state, line);
2327 void GFXOutputDev::eoFill(GfxState *state)
2329 if(states[statepos].createsoftmask)
2332 GfxPath * path = state->getPath();
2333 gfxcolor_t col = getFillColor(state);
2335 gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex + clipmovex, user_movey + clipmovey);
2337 if(getLogLevel() >= LOGLEVEL_TRACE) {
2338 msg("<trace> eofill\n");
2342 device->fill(device, line, &col);
2347 static char* dirseparator()
2356 void addGlobalFont(char*filename)
2359 memset(&f, 0, sizeof(fontfile_t));
2360 f.filename = filename;
2361 if(fontnum < sizeof(fonts)/sizeof(fonts[0])) {
2362 msg("<verbose> Adding font \"%s\".", filename);
2363 fonts[fontnum++] = f;
2365 msg("<error> Too many external fonts. Not adding font file \"%s\".", filename);
2369 void addGlobalLanguageDir(char*dir)
2372 globalParams = new GlobalParams("");
2374 msg("<notice> Adding %s to language pack directories", dir);
2378 char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc") + 1);
2379 strcpy(config_file, dir);
2380 strcat(config_file, dirseparator());
2381 strcat(config_file, "add-to-xpdfrc");
2383 fi = fopen(config_file, "rb");
2385 msg("<error> Could not open %s", config_file);
2388 globalParams->parseFile(new GString(config_file), fi);
2392 void addGlobalFontDir(char*dirname)
2394 #ifdef HAVE_DIRENT_H
2395 msg("<notice> Adding %s to font directories", dirname);
2396 lastfontdir = strdup(dirname);
2397 DIR*dir = opendir(dirname);
2399 msg("<warning> Couldn't open directory %s\n", dirname);
2404 ent = readdir (dir);
2408 char*name = ent->d_name;
2414 if(!strncasecmp(&name[l-4], ".pfa", 4))
2416 if(!strncasecmp(&name[l-4], ".pfb", 4))
2418 if(!strncasecmp(&name[l-4], ".ttf", 4))
2422 char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2);
2423 strcpy(fontname, dirname);
2424 strcat(fontname, dirseparator());
2425 strcat(fontname, name);
2426 addGlobalFont(fontname);
2431 msg("<warning> No dirent.h- unable to add font dir %s", dir);
2435 void GFXOutputDev::preparePage(int pdfpage, int outputpage)
2441 this->pagebuflen = 1024;
2442 this->pages = (int*)malloc(this->pagebuflen*sizeof(int));
2443 memset(this->pages, -1, this->pagebuflen*sizeof(int));
2445 while(pdfpage >= this->pagebuflen)
2447 int oldlen = this->pagebuflen;
2448 this->pagebuflen+=1024;
2449 this->pages = (int*)realloc(this->pages, this->pagebuflen*sizeof(int));
2450 memset(&this->pages[oldlen], -1, (this->pagebuflen-oldlen)*sizeof(int));
2453 this->pages[pdfpage] = outputpage;
2454 if(pdfpage>this->pagepos)
2455 this->pagepos = pdfpage;
2458 #if xpdfUpdateVersion >= 16
2459 void GFXOutputDev::beginTransparencyGroup(GfxState *state, double *bbox,
2460 GfxColorSpace *blendingColorSpace,
2461 GBool isolated, GBool knockout,
2464 char*colormodename = "";
2465 if(blendingColorSpace) {
2466 colormodename = GfxColorSpace::getColorSpaceModeName(blendingColorSpace->getMode());
2468 msg("<verbose> beginTransparencyGroup %.1f/%.1f/%.1f/%.1f %s isolated=%d knockout=%d forsoftmask=%d", bbox[0],bbox[1],bbox[2],bbox[3], colormodename, isolated, knockout, forSoftMask);
2469 states[statepos].createsoftmask = forSoftMask;
2470 states[statepos].transparencygroup = !forSoftMask;
2473 state->setFillOpacity(0.0);
2475 warnfeature("transparency groups",1);
2478 void GFXOutputDev::endTransparencyGroup(GfxState *state)
2480 msg("<verbose> endTransparencyGroup");
2481 states[statepos].createsoftmask = 0;
2482 states[statepos].transparencygroup = 0;
2485 void GFXOutputDev::paintTransparencyGroup(GfxState *state, double *bbox)
2487 msg("<verbose> paintTransparencyGroup");
2490 void GFXOutputDev::setSoftMask(GfxState *state, double *bbox, GBool alpha, Function *transferFunc, GfxColor *rgb)
2492 msg("<verbose> setSoftMask %.1f/%.1f/%.1f/%.1f alpha=%d backdrop=%02x%02x%02x",
2493 bbox[0], bbox[1], bbox[2], bbox[3], alpha, colToByte(rgb->c[0]), colToByte(rgb->c[1]), colToByte(rgb->c[2]));
2494 warnfeature("soft masks",0);
2497 void GFXOutputDev::clearSoftMask(GfxState *state)
2499 msg("<verbose> clearSoftMask");
2507 delete globalParams;globalParams=0;
2508 Object::memCheck(stderr);