X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fpdf%2FGFXOutputDev.cc;h=49bb6dbba021a39c4db854c1f4c165548255d7bc;hb=857174c423aafd86768d8f74eee7228208cd92fc;hp=4d565908c25b96f8cd775e630b7587bfc1c7d3f7;hpb=481be9c05a6e9b47339051dc0c02701b514ce65b;p=swftools.git diff --git a/lib/pdf/GFXOutputDev.cc b/lib/pdf/GFXOutputDev.cc index 4d56590..49bb6db 100644 --- a/lib/pdf/GFXOutputDev.cc +++ b/lib/pdf/GFXOutputDev.cc @@ -33,6 +33,9 @@ #ifdef HAVE_SYS_STAT_H #include #endif +#ifdef HAVE_FONTCONFIG +#include +#endif //xpdf header files #include "config.h" #include "gfile.h" @@ -64,13 +67,13 @@ #include "../gfxdevice.h" #include "../gfxtools.h" #include "../gfxfont.h" +#include "../gfxpoly.h" #include "../devices/record.h" #include "../devices/ops.h" -#include "../devices/arts.h" +#include "../devices/polyops.h" #include "../devices/render.h" #include "../art/libart.h" -#include "../devices/artsutils.h" #include "../png.h" #include "fonts.h" @@ -80,11 +83,16 @@ typedef struct _fontfile { const char*filename; + int len; // basename length int used; + struct _fontfile*next; } fontfile_t; // for pdfswf_addfont -static fontfile_t fonts[2048]; + +static fontfile_t* global_fonts = 0; +static fontfile_t* global_fonts_next = 0; + static int fontnum = 0; /* config */ @@ -151,7 +159,7 @@ typedef struct _feature } feature_t; feature_t*featurewarnings = 0; -void GFXOutputDev::showfeature(const char*feature,char fully, char warn) +void GFXOutputDev::showfeature(const char*feature, char fully, char warn) { feature_t*f = featurewarnings; while(f) { @@ -289,6 +297,8 @@ void unlinkfont(char* filename) } } +static int config_use_fontconfig = 1; +static int fcinitcalled = 0; GFXGlobalParams::GFXGlobalParams() : GlobalParams("") @@ -304,12 +314,179 @@ GFXGlobalParams::~GFXGlobalParams() unlinkfont(pdf2t1map[t].fullfilename); } } +#ifdef HAVE_FONTCONFIG + if(config_use_fontconfig && fcinitcalled) + FcFini(); +#endif +} +#ifdef HAVE_FONTCONFIG +static char fc_ismatch(FcPattern*match, char*family, char*style) +{ + char*fcfamily=0,*fcstyle=0,*fcfullname=0,*filename=0; + FcBool scalable=FcFalse, outline=FcFalse; + FcPatternGetString(match, "family", 0, (FcChar8**)&fcfamily); + FcPatternGetString(match, "style", 0, (FcChar8**)&fcstyle); + FcPatternGetString(match, "file", 0, (FcChar8**)&filename); + FcPatternGetBool(match, "outline", 0, &outline); + FcPatternGetBool(match, "scalable", 0, &scalable); + + if(scalable!=FcTrue || outline!=FcTrue) + return 0; + + if (!strcasecmp(fcfamily, family)) { + msg(" Font %s-%s (%s) is a match for %s%s%s", fcfamily, fcstyle, filename, family, style?"-":"", style?style:""); + return 1; + } else { + //msg(" Font %s-%s (%s) is NOT a match for %s%s%s", fcfamily, fcstyle, filename, family, style?"-":"", style?style:""); + return 0; + } } +#endif + +char* fontconfig_searchForFont(char*name) +{ +#ifdef HAVE_FONTCONFIG + if(!config_use_fontconfig) + return 0; + + // call init ony once + if (!fcinitcalled) { + fcinitcalled = 1; + + // check whether we have a config file + char* configfile = (char*)FcConfigFilename(0); + int configexists = 0; + FILE*fi = fopen(configfile, "rb"); + if(fi) { + configexists = 1;fclose(fi); + msg(" Initializing FontConfig (configfile=%s)", configfile); + } else { + msg(" Initializing FontConfig (no configfile)"); + } + + if(!configexists) { + /* A fontconfig instance which didn't find a configfile is unbelievably + cranky, so let's just write out a small xml file and make fontconfig + happy */ + FcConfig*c = FcConfigCreate(); + char namebuf[512]; + char* tmpFileName = mktmpname(namebuf); + FILE*fi = fopen(tmpFileName, "wb"); + fprintf(fi, "\n\n");// +#ifdef WIN32 + fprintf(fi, "WINDOWSFONTDIR\n"); +#endif + fprintf(fi, "~/.fonts\n"); +#ifdef WIN32 + fprintf(fi, "WINDOWSTEMPDIR_FONTCONFIG_CACHE\n"); +#endif + fprintf(fi, "~/.fontconfig\n"); + fprintf(fi, "\n"); + fclose(fi); + FcConfigParseAndLoad(c, (FcChar8*)tmpFileName, 1); + FcConfigBuildFonts(c); + FcConfigSetCurrent(c); + } + + if(!FcInit()) { + msg(" FontConfig Initialization failed. Disabling."); + config_use_fontconfig = 0; + return 0; + } + FcConfig * config = FcConfigGetCurrent(); + if(!config) { + msg(" FontConfig Config Initialization failed. Disabling."); + config_use_fontconfig = 0; + return 0; + } + FcFontSet * set = FcConfigGetFonts(config, FcSetSystem); + msg(" FontConfig initialized. Found %d fonts", set?set->nfont:0); + if(!set || !set->nfont) { + msg(" FontConfig has zero fonts. Disabling."); + config_use_fontconfig = 0; + return 0; + } + + if(getLogLevel() >= LOGLEVEL_TRACE) { + int t; + for(t=0;tnfont;t++) { + char*fcfamily=0,*fcstyle=0,*filename=0; + FcBool scalable=FcFalse, outline=FcFalse; + FcPatternGetString(set->fonts[t], "family", 0, (FcChar8**)&fcfamily); + FcPatternGetString(set->fonts[t], "style", 0, (FcChar8**)&fcstyle); + FcPatternGetString(set->fonts[t], "file", 0, (FcChar8**)&filename); + FcPatternGetBool(set->fonts[t], "outline", 0, &outline); + FcPatternGetBool(set->fonts[t], "scalable", 0, &scalable); + if(scalable && outline) { + msg(" %s-%s -> %s", fcfamily, fcstyle, filename); + } + } + } + } + + char*family = strdup(name); + char*style = 0; + char*dash = strchr(family, '-'); + FcPattern*pattern = 0; + if(dash) { + *dash = 0; + style = dash+1; + msg(" FontConfig: Looking for font %s (family=%s style=%s)", name, family, style); + pattern = FcPatternBuild(NULL, FC_OUTLINE, FcTypeBool, FcTrue, FC_SCALABLE, FcTypeBool, FcTrue, FC_FAMILY, FcTypeString, family, FC_STYLE, FcTypeString, style, NULL); + } else { + msg(" FontConfig: Looking for font %s (family=%s)", name, family); + pattern = FcPatternBuild(NULL, FC_OUTLINE, FcTypeBool, FcTrue, FC_SCALABLE, FcTypeBool, FcTrue, FC_FAMILY, FcTypeString, family, NULL); + } + + FcResult result; + FcConfigSubstitute(0, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + + FcFontSet*set = FcFontSort(0, pattern, 1, 0, &result); + if(set) { + int t; + for(t=0;tnfont;t++) { + FcPattern*match = set->fonts[t]; + //FcPattern*match = FcFontMatch(0, pattern, &result); + if(fc_ismatch(match, family, style)) { + char*filename=0; + if(FcPatternGetString(match, "file", 0, (FcChar8**)&filename) != FcResultMatch) { + msg(" FontConfig: Couldn't get fontconfig's filename for font %s", name); + filename=0; + } + //FcPatternDestroy(match); + msg(" fontconfig: returning filename %s", filename); + free(family); + FcPatternDestroy(pattern); + FcFontSetDestroy(set); + return filename?strdup(filename):0; + } + } + } + free(family); + FcPatternDestroy(pattern); + FcFontSetDestroy(set); + return 0; +#else + return 0; +#endif +} + +static DisplayFontParamKind detectFontType(const char*filename) +{ + if(strstr(filename, ".ttf") || strstr(filename, ".TTF")) + return displayFontTT; + if(strstr(filename, ".pfa") || strstr(filename, ".PFA") || strstr(filename, ".pfb")) + return displayFontT1; + return displayFontTT; +} + DisplayFontParam *GFXGlobalParams::getDisplayFont(GString *fontName) { - msg(" looking for font %s in global params\n", fontName->getCString()); + msg(" looking for font %s in global params", fontName->getCString()); char*name = fontName->getCString(); + /* see if it is a pdf standard font */ int t; for(t=0;tt1.fileName = new GString(fonts[t].filename); - return dfp; + + int bestlen = 0x7fffffff; + const char*bestfilename = 0; + + fontfile_t*f = global_fonts; + while(f) { + if(strstr(f->filename, name)) { + if(f->len < bestlen) { + bestlen = f->len; + bestfilename = f->filename; + } + } + f = f->next; + } + + /* if we didn't find anything up to now, try looking for the + font via fontconfig */ + char*filename = 0; + if(!bestfilename) { + filename = fontconfig_searchForFont(name); + } else { + filename = strdup(bestfilename); + } + + if(filename) { + DisplayFontParamKind kind = detectFontType(filename); + DisplayFontParam *dfp = new DisplayFontParam(new GString(fontName), kind); + if(kind == displayFontTT) { + dfp->tt.fileName = new GString(filename); + } else { + dfp->t1.fileName = new GString(filename); } + free(filename); + return dfp; } return GlobalParams::getDisplayFont(fontName); } @@ -366,11 +571,13 @@ GFXOutputDev::GFXOutputDev(InfoOutputDev*info, PDFDoc*doc) this->pages = 0; this->pagebuflen = 0; this->pagepos = 0; + this->config_convertgradients=0; this->config_break_on_warning=0; this->config_remapunicode=0; this->config_transparent=0; this->config_extrafontdata = 0; this->config_fontquality = 10; + this->config_optimize_polygons = 0; this->gfxfontlist = gfxfontlist_create(); @@ -387,6 +594,10 @@ void GFXOutputDev::setParameter(const char*key, const char*value) this->config_transparent = atoi(value); } else if(!strcmp(key,"extrafontdata")) { this->config_extrafontdata = atoi(value); + } else if(!strcmp(key,"convertgradients")) { + this->config_convertgradients = atoi(value); + } else if(!strcmp(key,"optimize_polygons")) { + this->config_optimize_polygons = atoi(value); } else if(!strcmp(key,"fontquality")) { this->config_fontquality = atof(value); if(this->config_fontquality<=1) @@ -481,39 +692,39 @@ static void dumpFontInfo(const char*loglevel, GfxFont*font) char* id = getFontID(font); char* name = getFontName(font); Ref* r=font->getID(); - msg("%s=========== %s (ID:%d,%d) ==========\n", loglevel, name, r->num,r->gen); + msg("%s=========== %s (ID:%d,%d) ==========", loglevel, name, r->num,r->gen); GString*gstr = font->getTag(); - msg("%s| Tag: %s\n", loglevel, id); + msg("%s| Tag: %s", loglevel, id); - if(font->isCIDFont()) msg("%s| is CID font\n", loglevel); + if(font->isCIDFont()) msg("%s| is CID font", loglevel); GfxFontType type=font->getType(); switch(type) { case fontUnknownType: - msg("%s| Type: unknown\n",loglevel); + msg("%s| Type: unknown",loglevel); break; case fontType1: - msg("%s| Type: 1\n",loglevel); + msg("%s| Type: 1",loglevel); break; case fontType1C: - msg("%s| Type: 1C\n",loglevel); + msg("%s| Type: 1C",loglevel); break; case fontType3: - msg("%s| Type: 3\n",loglevel); + msg("%s| Type: 3",loglevel); break; case fontTrueType: - msg("%s| Type: TrueType\n",loglevel); + msg("%s| Type: TrueType",loglevel); break; case fontCIDType0: - msg("%s| Type: CIDType0\n",loglevel); + msg("%s| Type: CIDType0",loglevel); break; case fontCIDType0C: - msg("%s| Type: CIDType0C\n",loglevel); + msg("%s| Type: CIDType0C",loglevel); break; case fontCIDType2: - msg("%s| Type: CIDType2\n",loglevel); + msg("%s| Type: CIDType2",loglevel); break; } @@ -524,18 +735,18 @@ static void dumpFontInfo(const char*loglevel, GfxFont*font) embeddedName = font->getEmbeddedFontName()->getCString(); } if(embedded) - msg("%s| Embedded id: %s id: %d\n",loglevel, FIXNULL(embeddedName), embRef.num); + msg("%s| Embedded id: %s id: %d",loglevel, FIXNULL(embeddedName), embRef.num); gstr = font->getExtFontFile(); if(gstr) - msg("%s| External Font file: %s\n", loglevel, FIXNULL(gstr->getCString())); + msg("%s| External Font file: %s", loglevel, FIXNULL(gstr->getCString())); // Get font descriptor flags. - if(font->isFixedWidth()) msg("%s| is fixed width\n", loglevel); - if(font->isSerif()) msg("%s| is serif\n", loglevel); - if(font->isSymbolic()) msg("%s| is symbolic\n", loglevel); - if(font->isItalic()) msg("%s| is italic\n", loglevel); - if(font->isBold()) msg("%s| is bold\n", loglevel); + if(font->isFixedWidth()) msg("%s| is fixed width", loglevel); + if(font->isSerif()) msg("%s| is serif", loglevel); + if(font->isSymbolic()) msg("%s| is symbolic", loglevel); + if(font->isItalic()) msg("%s| is italic", loglevel); + if(font->isBold()) msg("%s| is bold", loglevel); free(id); free(name); @@ -558,7 +769,7 @@ void dump_outline(gfxline_t*line) } } -gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey) +gfxline_t* GFXOutputDev::gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user_movex, int user_movey) { int num = path->getNumSubpaths(); int s,t; @@ -580,9 +791,7 @@ gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user for(s=0;stransform(subpath->getX(s),subpath->getY(s),&x,&y); - x += user_movex; - y += user_movey; + this->transformXY(state, subpath->getX(s),subpath->getY(s),&x,&y); if(s==0) { if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) { @@ -628,14 +837,180 @@ gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed, int user GBool GFXOutputDev::useTilingPatternFill() { infofeature("tiled patterns"); +// if(config_convertgradients) +// return gTrue; return gFalse; } - GBool GFXOutputDev::useShadedFills() { infofeature("shaded fills"); + if(config_convertgradients) + return gTrue; return gFalse; } + +void GFXOutputDev::transformXY(GfxState*state, double x, double y, double*nx, double*ny) +{ + state->transform(x,y,nx,ny); + *nx += user_movex + clipmovex; + *ny += user_movey + clipmovey; +} + + +#if (xpdfMajorVersion*10000 + xpdfMinorVersion*100 + xpdfUpdateVersion) < 30207 +void GFXOutputDev::tilingPatternFill(GfxState *state, Object *str, + int paintType, Dict *resDict, + double *mat, double *bbox, + int x0, int y0, int x1, int y1, + double xStep, double yStep) +#else +void GFXBitmapOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Object *str, + int paintType, Dict *resDict, + double *mat, double *bbox, + int x0, int y0, int x1, int y1, + double xStep, double yStep) +#endif +{ + msg(" tilingPatternFill"); + infofeature("tiling pattern fills"); +} + +GBool GFXOutputDev::functionShadedFill(GfxState *state, GfxFunctionShading *shading) +{ + msg(" functionShadedFill not supported yet"); + infofeature("function shaded fills"); + return gFalse; +} +static gfxcolor_t col2col(GfxColorSpace*colspace, GfxColor* col) +{ + gfxcolor_t c; + GfxRGB rgb; + colspace->getRGB(col, &rgb); + c.r = colToByte(rgb.r); + c.g = colToByte(rgb.g); + c.b = colToByte(rgb.b); + c.a = 255; + return c; +} + +GBool GFXOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading) +{ + double x0,y0,r0,x1,y1,x2,y2,x9,y9,r1; + shading->getCoords(&x0,&y0,&r0,&x9,&y9,&r1); + x1=x0+r1;y1=y0; + x2=x0; y2=y0+r1; + this->transformXY(state, x0,y0, &x0,&y0); + this->transformXY(state, x1,y1, &x1,&y1); + this->transformXY(state, x2,y2, &x2,&y2); + + GfxColor color0; + GfxColor color1; + GfxColor color2; + shading->getColor(0.0, &color0); + shading->getColor(0.5, &color1); + shading->getColor(1.0, &color2); + + GfxColorSpace* colspace = shading->getColorSpace(); + + msg(" radialShadedFill %f %f %f %f %f %f %02x%02x%02x->%02x%02x%02x", x0, y0, x1, y1, x2, y2, + colToByte(color0.c[0]), colToByte(color0.c[1]), colToByte(color0.c[2]), + colToByte(color1.c[0]), colToByte(color1.c[1]), colToByte(color1.c[2]), + colToByte(color2.c[0]), colToByte(color2.c[1]), colToByte(color2.c[2])); + infofeature("radial shaded fills"); + + gfxgradient_t*g = (gfxgradient_t*)malloc(sizeof(gfxgradient_t)*3); + g[0].next = &g[1]; + g[1].next = &g[2]; + g[2].next = 0; + g[0].color = col2col(colspace, &color0); + g[1].color = col2col(colspace, &color1); + g[2].color = col2col(colspace, &color2); + g[0].pos = 0.0; + g[1].pos = 0.5; + g[2].pos = 1.0; + + gfxbbox_t b = states[statepos].clipbbox; + gfxline_t p1,p2,p3,p4,p5; + p1.type=gfx_moveTo;p1.x=b.xmin; p1.y=b.ymin; p1.next=&p2; + p2.type=gfx_lineTo;p2.x=b.xmin; p2.y=b.ymax; p2.next=&p3; + p3.type=gfx_lineTo;p3.x=b.xmax; p3.y=b.ymax; p3.next=&p4; + p4.type=gfx_lineTo;p4.x=b.xmax; p4.y=b.ymin; p4.next=&p5; + p5.type=gfx_lineTo;p5.x=b.xmin; p5.y=b.ymin; p5.next=0; + + gfxmatrix_t m; + //m.m00 = (x3-x0); m.m10 = (x1-x0); + //m.m01 = (y3-y0); m.m11 = (y1-y0); + //x3/y3 specifies another (the ending) circle, not the second radius of an ellipse + m.m00 = (x1-x0); m.m10 = (x2-x0); + m.m01 = (y1-y0); m.m11 = (y2-y0); + m.tx = x0 - 0.5; + m.ty = y0 - 0.5; + + device->fillgradient(device, &p1, g, gfxgradient_radial, &m); + return gTrue; +} + +GBool GFXOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading) +{ + double x0,y0,x1,y1; + shading->getCoords(&x0,&y0,&x1,&y1); + this->transformXY(state, x0,y0,&x0,&y0); + this->transformXY(state, x1,y1,&x1,&y1); + + GfxColor color0; + GfxColor color1; + GfxColor color2; + shading->getColor(0.0, &color0); + shading->getColor(0.5, &color1); + shading->getColor(1.0, &color2); + + GfxColorSpace* colspace = shading->getColorSpace(); + + msg(" axialShadedFill %f %f %f %f %02x%02x%02x->%02x%02x%02x->%02x%02x%02x", x0, y0, x1, y1, + colToByte(color0.c[0]), colToByte(color0.c[1]), colToByte(color0.c[2]), + colToByte(color1.c[0]), colToByte(color1.c[1]), colToByte(color1.c[2]), + colToByte(color2.c[0]), colToByte(color2.c[1]), colToByte(color2.c[2]) + ); + infofeature("axial shaded fills"); + + gfxgradient_t*g = (gfxgradient_t*)malloc(sizeof(gfxgradient_t)*3); + g[0].next = &g[1]; + g[1].next = &g[2]; + g[2].next = 0; + g[0].color = col2col(colspace, &color0); + g[1].color = col2col(colspace, &color1); + g[2].color = col2col(colspace, &color2); + g[0].pos = 0.0; + g[1].pos = 0.5; + g[2].pos = 1.0; + + double xMin,yMin,xMax,yMax; + state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); + this->transformXY(state, xMin, yMin, &xMin, &yMin); + msg(" userClipBox %f %f %f %f", xMin, yMin, xMax, yMax); + + xMin = 0; yMin = 0; + xMin = 1024; yMin = 1024; + + gfxbbox_t b = states[statepos].clipbbox; + gfxline_t p1,p2,p3,p4,p5; + p1.type=gfx_moveTo;p1.x=b.xmin; p1.y=b.ymin; p1.next=&p2; + p2.type=gfx_lineTo;p2.x=b.xmin; p2.y=b.ymax; p2.next=&p3; + p3.type=gfx_lineTo;p3.x=b.xmax; p3.y=b.ymax; p3.next=&p4; + p4.type=gfx_lineTo;p4.x=b.xmax; p4.y=b.ymin; p4.next=&p5; + p5.type=gfx_lineTo;p5.x=b.xmin; p5.y=b.ymin; p5.next=0; + + /* the gradient starts at (-1.0,0.0), so move (0,0) to + the middle of the two control points */ + gfxmatrix_t m; + m.m00 = (x1-x0)/2; m.m10 = -(y1-y0)/2; + m.m01 = (y1-y0)/2; m.m11 = (x1-x0)/2; + m.tx = (x0 + x1)/2 - 0.5; + m.ty = (y0 + y1)/2 - 0.5; + + device->fillgradient(device, &p1, g, gfxgradient_linear, &m); + return gTrue; +} GBool GFXOutputDev::useDrawForm() { @@ -652,7 +1027,7 @@ GBool GFXOutputDev::needNonText() } void GFXOutputDev::endPage() { - msg(" endPage"); + msg(" endPage (GfxOutputDev)"); if(outer_clip_box) { device->endclip(device); outer_clip_box = 0; @@ -718,7 +1093,7 @@ void GFXOutputDev::strokeGfxline(GfxState *state, gfxline_t*line, int flags) } if(getLogLevel() >= LOGLEVEL_TRACE) { - msg(" stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x\n", + msg(" stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x", width, lineJoin==0?"miter": (lineJoin==1?"round":"bevel"), lineCap==0?"butt": (lineJoin==1?"round":"square"), @@ -729,8 +1104,8 @@ void GFXOutputDev::strokeGfxline(GfxState *state, gfxline_t*line, int flags) } if(flags&STROKE_FILL) { - ArtSVP* svp = gfxstrokeToSVP(line, width, capType, joinType, miterLimit); - gfxline_t*gfxline = SVPtogfxline(svp); + gfxpoly_t* poly = gfxpoly_strokeToPoly(line, width, capType, joinType, miterLimit); + gfxline_t*gfxline = gfxpoly_to_gfxline(poly); if(getLogLevel() >= LOGLEVEL_TRACE) { dump_outline(gfxline); } @@ -744,7 +1119,7 @@ void GFXOutputDev::strokeGfxline(GfxState *state, gfxline_t*line, int flags) device->fill(device, gfxline, &col); } free(gfxline); - art_svp_free(svp); + gfxpoly_free(poly); } else { if(flags&STROKE_CLIP) msg(" Stroke&clip not supported at the same time"); @@ -773,7 +1148,7 @@ void GFXOutputDev::fillGfxLine(GfxState *state, gfxline_t*line) gfxcolor_t col = getFillColor(state); if(getLogLevel() >= LOGLEVEL_TRACE) { - msg(" fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a); + msg(" fill %02x%02x%02x%02x", col.r, col.g, col.b, col.a); dump_outline(line); } device->fill(device, line, &col); @@ -782,9 +1157,10 @@ void GFXOutputDev::fillGfxLine(GfxState *state, gfxline_t*line) void GFXOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line) { if(getLogLevel() >= LOGLEVEL_TRACE) { - msg(" clip\n"); dump_outline(line); } + gfxbbox_t bbox = gfxline_getbbox(line); + gfxbbox_intersect(&states[statepos].clipbbox, &bbox); device->startclip(device, line); states[statepos].clipping++; @@ -793,7 +1169,13 @@ void GFXOutputDev::clipToGfxLine(GfxState *state, gfxline_t*line) void GFXOutputDev::clip(GfxState *state) { GfxPath * path = state->getPath(); + msg(" clip"); gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex + clipmovex, user_movey + clipmovey); + if(config_optimize_polygons) { + gfxline_t*line2 = gfxline_circularToEvenOdd(line); + gfxline_free(line); + line = line2; + } clipToGfxLine(state, line); gfxline_free(line); } @@ -802,14 +1184,7 @@ void GFXOutputDev::eoClip(GfxState *state) { GfxPath * path = state->getPath(); gfxline_t*line = gfxPath_to_gfxline(state, path, 1, user_movex + clipmovex, user_movey + clipmovey); - - if(getLogLevel() >= LOGLEVEL_TRACE) { - msg(" eoclip\n"); - dump_outline(line); - } - - device->startclip(device, line); - states[statepos].clipping++; + clipToGfxLine(state, line); gfxline_free(line); } void GFXOutputDev::clipToStrokePath(GfxState *state) @@ -818,7 +1193,7 @@ void GFXOutputDev::clipToStrokePath(GfxState *state) gfxline_t*line= gfxPath_to_gfxline(state, path, 0, user_movex + clipmovex, user_movey + clipmovey); if(getLogLevel() >= LOGLEVEL_TRACE) { - msg(" cliptostrokepath\n"); + msg(" cliptostrokepath"); dump_outline(line); } @@ -964,12 +1339,10 @@ void GFXOutputDev::drawChar(GfxState *state, double x, double y, } Unicode u = uLen?(_u[0]):0; - msg(" drawChar(%f,%f,c='%c' (%d), u=%d <%d>) CID=%d render=%d glyphid=%d\n",x,y,(charid&127)>=32?charid:'?', charid, u, uLen, font->isCIDFont(), render, glyphid); + msg(" drawChar(%f,%f,c='%c' (%d), u=%d <%d>) CID=%d render=%d glyphid=%d font=%08x",x,y,(charid&127)>=32?charid:'?', charid, u, uLen, font->isCIDFont(), render, glyphid, current_gfxfont); gfxmatrix_t m = this->current_font_matrix; - state->transform(x, y, &m.tx, &m.ty); - m.tx += user_movex + clipmovex; - m.ty += user_movey + clipmovey; + this->transformXY(state, x, y, &m.tx, &m.ty); if(render == RENDER_FILL || render == RENDER_INVISIBLE) { device->drawchar(device, current_gfxfont, glyphid, &col, &m); @@ -1061,13 +1434,11 @@ GBool GFXOutputDev::beginType3Char(GfxState *state, double x, double y, double d if(config_extrafontdata && current_fontinfo) { gfxmatrix_t m = this->current_font_matrix; - state->transform(0, 0, &m.tx, &m.ty); + this->transformXY(state, 0, 0, &m.tx, &m.ty); m.m00*=INTERNAL_FONT_SIZE; m.m01*=INTERNAL_FONT_SIZE; m.m10*=INTERNAL_FONT_SIZE; m.m11*=INTERNAL_FONT_SIZE; - m.tx += user_movex + clipmovex; - m.ty += user_movey + clipmovey; if(!current_fontinfo || (unsigned)charid >= current_fontinfo->num_glyphs || !current_fontinfo->glyphs[charid]) { msg(" Invalid charid %d for font", charid); @@ -1135,7 +1506,7 @@ void GFXOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, doubl msg(" 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); if(rot!=0) - msg(" page is rotated %d degrees\n", rot); + msg(" page is rotated %d degrees", rot); clippath[0].type = gfx_moveTo;clippath[0].x = x1; clippath[0].y = y1; clippath[0].next = &clippath[1]; clippath[1].type = gfx_lineTo;clippath[1].x = x2; clippath[1].y = y1; clippath[1].next = &clippath[2]; @@ -1146,6 +1517,10 @@ void GFXOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, doubl if(!config_transparent) { device->fill(device, clippath, &white); } + states[statepos].clipbbox.xmin = x1; + states[statepos].clipbbox.ymin = x1; + states[statepos].clipbbox.xmax = x2; + states[statepos].clipbbox.ymax = y2; } @@ -1155,7 +1530,7 @@ void GFXOutputDev::processLink(Link *link, Catalog *catalog) gfxline_t points[5]; int x, y; - msg(" drawlink\n"); + msg(" drawlink"); link->getRect(&x1, &y1, &x2, &y2); cvtUserToDev(x1, y1, &x, &y); @@ -1184,11 +1559,15 @@ void GFXOutputDev::processLink(Link *link, Catalog *catalog) points[4].y = y + user_movey + clipmovey; points[4].next = 0; - msg(" drawlink %.2f/%.2f %.2f/%.2f %.2f/%.2f %.2f/%.2f\n", + msg(" drawlink %.2f/%.2f %.2f/%.2f %.2f/%.2f %.2f/%.2f", points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y, points[3].x, points[3].y); + + if(getLogLevel() >= LOGLEVEL_TRACE) { + dump_outline(points); + } LinkAction*action=link->getAction(); char buf[128]; @@ -1196,7 +1575,7 @@ void GFXOutputDev::processLink(Link *link, Catalog *catalog) const char*type = "-?-"; char*named = 0; int page = -1; - msg(" drawlink action=%d\n", action->getKind()); + msg(" drawlink action=%d", action->getKind()); switch(action->getKind()) { case actionGoTo: { @@ -1292,14 +1671,14 @@ void GFXOutputDev::processLink(Link *link, Catalog *catalog) } break; default: { - msg(" Unknown link type!\n"); + msg(" Unknown link type!"); break; } } if(!s) s = strdup("-?-"); - msg(" drawlink s=%s\n", s); + msg(" drawlink s=%s", s); if(!linkinfo && (page || s)) { @@ -1329,14 +1708,14 @@ void GFXOutputDev::processLink(Link *link, Catalog *catalog) device->drawlink(device, points, s); } - msg(" \"%s\" link to \"%s\" (%d)\n", type, FIXNULL(s), page); + msg(" \"%s\" link to \"%s\" (%d)", type, FIXNULL(s), page); free(s);s=0; } void GFXOutputDev::saveState(GfxState *state) { dbg("saveState");dbgindent+=2; - msg(" saveState\n"); + msg(" saveState"); updateAll(state); if(statepos>=64) { msg(" Too many nested states in pdf."); @@ -1346,6 +1725,7 @@ void GFXOutputDev::saveState(GfxState *state) { states[statepos].createsoftmask = states[statepos-1].createsoftmask; states[statepos].transparencygroup = states[statepos-1].transparencygroup; states[statepos].clipping = 0; + states[statepos].clipbbox = states[statepos-1].clipbbox; }; void GFXOutputDev::restoreState(GfxState *state) { @@ -1519,7 +1899,7 @@ void GFXOutputDev::updateFont(GfxState *state) this->current_fontinfo = this->info->getFont(id); if(!this->current_fontinfo) { - msg(" Internal Error: no fontinfo for font %s\n", id); + msg(" Internal Error: no fontinfo for font %s", id); return; } if(!this->current_fontinfo->seen) { @@ -1531,8 +1911,9 @@ void GFXOutputDev::updateFont(GfxState *state) font = createGfxFont(gfxFont, current_fontinfo, this->config_fontquality); font->id = strdup(id); this->gfxfontlist = gfxfontlist_addfont(this->gfxfontlist, font); - device->addfont(device, font); } + device->addfont(device, font); + current_gfxfont = font; free(id); @@ -1711,7 +2092,7 @@ void GFXOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str, imgStr = new ImageStream(str, width, ncomps,bits); imgStr->reset(); - if(!width || !height || (height<=1 && width<=1)) + if(!width || !height || (height<=1 && width<=1 && maskWidth<=1 && maskHeight<=1)) { msg(" Ignoring %d by %d image", width, height); unsigned char buf[8]; @@ -1726,10 +2107,10 @@ void GFXOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str, return; } - state->transform(0, 1, &x1, &y1); x1 += user_movex + clipmovex; y1 += user_movey + clipmovey; - state->transform(0, 0, &x2, &y2); x2 += user_movex + clipmovex; y2 += user_movey + clipmovey; - state->transform(1, 0, &x3, &y3); x3 += user_movex + clipmovex; y3 += user_movey + clipmovey; - state->transform(1, 1, &x4, &y4); x4 += user_movex + clipmovex; y4 += user_movey + clipmovey; + this->transformXY(state, 0, 1, &x1, &y1); + this->transformXY(state, 0, 0, &x2, &y2); + this->transformXY(state, 1, 0, &x3, &y3); + this->transformXY(state, 1, 1, &x4, &y4); if(!pbminfo && !(str->getKind()==strDCT)) { if(!type3active) { @@ -1737,7 +2118,7 @@ void GFXOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str, pbminfo = 1; } if(mask) - msg(" drawing %d by %d masked picture\n", width, height); + msg(" drawing %d by %d masked picture", width, height); } if(!jpeginfo && (str->getKind()==strDCT)) { msg(" file contains jpeg pictures"); @@ -1781,7 +2162,7 @@ void GFXOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str, pic2 = antialize(pic,width,height,realwidth,realheight,numpalette); if(!pic2) { - delete pic; + delete[] pic; delete imgStr; return; } @@ -1838,7 +2219,7 @@ void GFXOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str, drawimagejpeg(device, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4); else drawimagelossless(device, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4); - delete pic; + delete[] pic; delete imgStr; if(maskbitmap) free(maskbitmap); return; @@ -1882,14 +2263,39 @@ void GFXOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str, for (x = 0; x < width; ++x) { imgStr->getPixel(pixBuf); pic[width*y+x] = pal[pixBuf[0]]; - if(maskbitmap) { - pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)]; - } } } + if(maskbitmap) { + if(maskWidth < width && maskHeight < height) { + for(y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + pic[width*y+x].a = maskbitmap[(y*maskHeight/height)*maskWidth+(x*maskWidth/width)]; + } + } + } else { + msg(" resampling %dx%d to mask size (%dx%d)", width, height, maskWidth, maskHeight); + gfxcolor_t*newpic=new gfxcolor_t[maskWidth*maskHeight]; + double dx = width / maskWidth; + double dy = height / maskHeight; + double yy = 0; + for(y = 0; y < maskHeight; y++) { + double xx = 0; + for (x = 0; x < maskWidth; x++) { + newpic[maskWidth*y+x] = pic[int(yy)*width+int(xx)]; + newpic[maskWidth*y+x].a = maskbitmap[maskWidth*y+x]; + xx += dx; + } + yy += dy; + } + delete[] pic; + pic = newpic; + width = maskWidth; + height = maskHeight; + } + } drawimagelossless(device, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4); - delete pic; + delete[] pic; delete imgStr; if(maskbitmap) free(maskbitmap); return; @@ -1918,7 +2324,7 @@ void GFXOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, maskColors?"maskColors":"no maskColors", inlineImg); if(colorMap) - msg(" colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(), + msg(" colorMap pixcomps:%d bits:%d mode:%d", colorMap->getNumPixelComps(), colorMap->getBits(),colorMap->getColorSpace()->getMode()); drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors, 0,0,0,0, 0); } @@ -1936,7 +2342,7 @@ void GFXOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, colorMap?"colorMap":"no colorMap", maskWidth, maskHeight); if(colorMap) - msg(" colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(), + msg(" colorMap pixcomps:%d bits:%d mode:%d", colorMap->getNumPixelComps(), colorMap->getBits(),colorMap->getColorSpace()->getMode()); drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, maskInvert, 0); } @@ -1955,7 +2361,7 @@ void GFXOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str colorMap?"colorMap":"no colorMap", maskWidth, maskHeight); if(colorMap) - msg(" colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(), + msg(" colorMap pixcomps:%d bits:%d mode:%d", colorMap->getNumPixelComps(), colorMap->getBits(),colorMap->getColorSpace()->getMode()); drawGeneralImage(state,ref,str,width,height,colorMap,0,0,0,0, maskStr, maskWidth, maskHeight, 0, maskColorMap); } @@ -1977,6 +2383,11 @@ void GFXOutputDev::fill(GfxState *state) GfxPath * path = state->getPath(); gfxline_t*line= gfxPath_to_gfxline(state, path, 1, user_movex + clipmovex, user_movey + clipmovey); + if(config_optimize_polygons) { + gfxline_t*line2 = gfxline_circularToEvenOdd(line); + gfxline_free(line); + line = line2; + } fillGfxLine(state, line); gfxline_free(line); } @@ -2004,14 +2415,25 @@ static const char* dirseparator() void addGlobalFont(const char*filename) { - fontfile_t f; - memset(&f, 0, sizeof(fontfile_t)); - f.filename = filename; - if(fontnum < sizeof(fonts)/sizeof(fonts[0])) { - msg(" Adding font \"%s\".", filename); - fonts[fontnum++] = f; + fontfile_t* f = (fontfile_t*)malloc(sizeof(fontfile_t)); + memset(f, 0, sizeof(fontfile_t)); + f->filename = filename; + int len = strlen(filename); + char*r1 = strrchr(filename, '/'); + char*r2 = strrchr(filename, '\\'); + if(r2>r1) + r1 = r2; + if(r1) { + len = strlen(r1+1); + } + f->len = len; + + msg(" Adding font \"%s\".", filename); + if(global_fonts_next) { + global_fonts_next->next = f; + global_fonts_next = global_fonts_next->next; } else { - msg(" Too many external fonts. Not adding font file \"%s\".", filename); + global_fonts_next = global_fonts = f; } } @@ -2041,7 +2463,7 @@ void addGlobalFontDir(const char*dirname) lastfontdir = strdup(dirname); DIR*dir = opendir(dirname); if(!dir) { - msg(" Couldn't open directory %s\n", dirname); + msg(" Couldn't open directory %s", dirname); return; } struct dirent*ent; @@ -2099,87 +2521,6 @@ void GFXOutputDev::preparePage(int pdfpage, int outputpage) this->pagepos = pdfpage; } -struct BBox -{ - double posx,posy; - double width,height; -}; - -BBox mkBBox(GfxState*state, double*bbox, double width, double height) -{ - double xMin, yMin, xMax, yMax, x, y; - double tx, ty, w, h; - // transform the bbox - state->transform(bbox[0], bbox[1], &x, &y); - xMin = xMax = x; - yMin = yMax = y; - state->transform(bbox[0], bbox[3], &x, &y); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - state->transform(bbox[2], bbox[1], &x, &y); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - state->transform(bbox[2], bbox[3], &x, &y); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - tx = (int)floor(xMin); - if (tx < 0) { - tx = 0; - } else if (tx > width) { - tx = width; - } - ty = (int)floor(yMin); - if (ty < 0) { - ty = 0; - } else if (ty > height) { - ty = height; - } - w = (int)ceil(xMax) - tx + 1; - if (tx + w > width) { - w = width - tx; - } - if (w < 1) { - w = 1; - } - h = (int)ceil(yMax) - ty + 1; - if (ty + h > height) { - h = height - ty; - } - if (h < 1) { - h = 1; - } - BBox nbbox; - nbbox.posx = xMin; - nbbox.posx = yMin; - nbbox.width = w; - nbbox.height = h; - return nbbox; -} - void GFXOutputDev::beginTransparencyGroup(GfxState *state, double *bbox, GfxColorSpace *blendingColorSpace, GBool isolated, GBool knockout, @@ -2193,7 +2534,8 @@ void GFXOutputDev::beginTransparencyGroup(GfxState *state, double *bbox, dbg("beginTransparencyGroup %.1f/%.1f/%.1f/%.1f %s isolated=%d knockout=%d forsoftmask=%d", bbox[0],bbox[1],bbox[2],bbox[3], colormodename, isolated, knockout, forSoftMask); msg(" beginTransparencyGroup %.1f/%.1f/%.1f/%.1f %s isolated=%d knockout=%d forsoftmask=%d", bbox[0],bbox[1],bbox[2],bbox[3], colormodename, isolated, knockout, forSoftMask); - states[statepos].createsoftmask |= forSoftMask; + //states[statepos].createsoftmask |= forSoftMask; + states[statepos].createsoftmask = forSoftMask; states[statepos].transparencygroup = !forSoftMask; states[statepos].isolated = isolated; @@ -2218,10 +2560,11 @@ void GFXOutputDev::endTransparencyGroup(GfxState *state) this->device = states[statepos].olddevice; + gfxresult_t*recording = r->finish(r); if(states[statepos].createsoftmask) { - states[statepos-1].softmaskrecording = r->finish(r); + states[statepos-1].softmaskrecording = recording; } else { - states[statepos-1].grouprecording = r->finish(r); + states[statepos-1].grouprecording = recording; } states[statepos].createsoftmask = 0; @@ -2247,10 +2590,14 @@ void GFXOutputDev::paintTransparencyGroup(GfxState *state, double *bbox) } gfxresult_t*grouprecording = states[statepos].grouprecording; - - if(state->getBlendMode() == gfxBlendNormal) { + + int blendmode = state->getBlendMode(); + if(blendmode == gfxBlendNormal || blendmode == gfxBlendMultiply) { + int alpha = (int)(state->getFillOpacity()*255); + if(blendmode == gfxBlendMultiply && alpha>200) + alpha = 128; gfxdevice_t ops; - gfxdevice_ops_init(&ops, this->device, (unsigned char)(state->getFillOpacity()*255)); + gfxdevice_ops_init(&ops, this->device, alpha); gfxresult_record_replay(grouprecording, &ops); ops.finish(&ops); }