X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=pdf2swf%2FSWFOutputDev.cc;h=ad47eac551e320a25e45dbcec1d6aa974fc87fec;hb=40f3cebdd00b39cc3977e94efc947e96870b7f54;hp=fa5b247b70469c5bd32859bb0fd8cc8d9618b3bc;hpb=e7515e00abe3e930c8bfe209022d0ef2f05c865a;p=swftools.git diff --git a/pdf2swf/SWFOutputDev.cc b/pdf2swf/SWFOutputDev.cc index fa5b247..ad47eac 100644 --- a/pdf2swf/SWFOutputDev.cc +++ b/pdf2swf/SWFOutputDev.cc @@ -23,6 +23,12 @@ #include #include #include "../config.h" +#ifdef HAVE_DIRENT_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif #ifdef HAVE_FONTCONFIG_H #include #endif @@ -58,6 +64,8 @@ //swftools header files #include "swfoutput.h" #include "../lib/log.h" +#include "../lib/gfxdevice.h" +#include "gfxtools.h" #include @@ -71,6 +79,8 @@ typedef struct _fontfile static fontfile_t fonts[2048]; static int fontnum = 0; +static int config_use_fontconfig = 1; + // swf <-> pdf pages // TODO: move into pdf_doc_t static int*pages = 0; @@ -80,6 +90,7 @@ static int pagepos = 0; /* config */ static double caplinewidth = 3.0; static int zoom = 72; /* xpdf: 86 */ +static int forceType0Fonts = 0; static void printInfoString(Dict *infoDict, char *key, char *fmt); static void printInfoDate(Dict *infoDict, char *key, char *fmt); @@ -104,8 +115,8 @@ struct mapping { {"ZapfDingbats", "d050000l"}}; class SWFOutputDev: public OutputDev { - struct swfoutput output; int outputstarted; + struct swfoutput output; public: // Constructor. @@ -118,6 +129,10 @@ public: void setClip(int x1,int y1,int x2,int y2); int save(char*filename); + void pagefeed(); + void* getSWF(); + + void getDimensions(int*x1,int*y1,int*x2,int*y2); //----- get info about output device @@ -191,14 +206,16 @@ public: int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg); - virtual GBool beginType3Char(GfxState *state, - CharCode code, Unicode *u, int uLen); + virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen); virtual void endType3Char(GfxState *state); + virtual void type3D0(GfxState *state, double wx, double wy); + virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury); + private: void drawGeneralImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap*colorMap, GBool invert, - GBool inlineImg, int mask); + GBool inlineImg, int mask, int *maskColors); int clipping[64]; int clippos; @@ -221,13 +238,6 @@ public: GfxState *laststate; - int pic_xids[1024]; - int pic_yids[1024]; - int pic_ids[1024]; - int pic_width[1024]; - int pic_height[1024]; - int picpos; - int pic_id; char type3Warning; char* substitutetarget[256]; @@ -311,8 +321,6 @@ SWFOutputDev::SWFOutputDev() clipping[clippos] = 0; outputstarted = 0; xref = 0; - picpos = 0; - pic_id = 0; substitutepos = 0; type3Warning = 0; user_movex = 0; @@ -341,6 +349,10 @@ void SWFOutputDev::setClip(int x1,int y1,int x2,int y2) this->user_clipx2 = x2; this->user_clipy2 = y2; } +void SWFOutputDev::getDimensions(int*x1,int*y1,int*x2,int*y2) +{ + return swfoutput_getdimensions(&output, x1,y1,x2,y2); +} static char*getFontID(GfxFont*font) { @@ -565,106 +577,81 @@ static void dumpFontInfo(char*loglevel, GfxFont*font) //void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) {printf("void SWFOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) \n");} //void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool inlineImg) {printf("void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool inlineImg) \n");} -static void free_outline(SWF_OUTLINE*outline) -{ - while(outline) { - SWF_OUTLINE*next = outline->link; - free(outline); - outline = next; - } -} -static void dump_outline(SWF_OUTLINE*outline) -{ - double x=0,y=0; - while(outline) { - double lastx=x,lasty=y; - x += (outline->dest.x/(float)0xffff); - y += (outline->dest.y/(float)0xffff); - if(outline->type == SWF_PATHTYPE_MOVE) { - msg(" | moveto %f,%f", x,y); - } else if(outline->type == SWF_PATHTYPE_LINE) { - msg(" | lineto: %f,%f\n",x,y); - } else if(outline->type == SWF_PATHTYPE_BEZIER) { - SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline; - float x1 = o2->C.x/(float)0xffff+lastx; - float y1 = o2->C.y/(float)0xffff+lasty; - float x2 = o2->B.x/(float)0xffff+lastx; - float y2 = o2->B.y/(float)0xffff+lasty; - msg(" | spline: %f,%f -> %f,%f -> %f,%f\n",x1,y1,x2,y2,x,y); - } - outline = outline->link; +void dump_outline(gfxline_t*line) +{ + while(line) { + if(line->type == gfx_moveTo) { + msg(" | moveTo %.2f %.2f", line->x,line->y); + } else if(line->type == gfx_lineTo) { + msg(" | lineTo %.2f %.2f", line->x,line->y); + } else if(line->type == gfx_splineTo) { + msg(" | splineTo (%.2f %.2f) %.2f %.2f", line->sx,line->sy, line->x, line->y); + } + line = line->next; } } -SWF_OUTLINE* gfxPath_to_SWF_OUTLINE(GfxState*state, GfxPath*path) +gfxline_t* gfxPath_to_gfxline(GfxState*state, GfxPath*path, int closed) { int num = path->getNumSubpaths(); int s,t; - bezierpathsegment*start,*last=0; - bezierpathsegment*outline = start = (bezierpathsegment*)malloc(sizeof(bezierpathsegment)); int cpos = 0; - double lastx=0,lasty=0; + double lastx=0,lasty=0,posx=0,posy=0; + int needsfix=0; if(!num) { msg(" empty path"); - outline->type = SWF_PATHTYPE_MOVE; - outline->dest.x = 0; - outline->dest.y = 0; - outline->link = 0; - return (SWF_OUTLINE*)outline; + return 0; } + gfxdrawer_t draw; + gfxdrawer_target_gfxline(&draw); + for(t = 0; t < num; t++) { GfxSubpath *subpath = path->getSubpath(t); int subnum = subpath->getNumPoints(); + double bx=0,by=0,cx=0,cy=0; for(s=0;stransform(subpath->getX(s),subpath->getY(s),&nx,&ny); - int x = (int)((nx-lastx)*0xffff); - int y = (int)((ny-lasty)*0xffff); - if(s==0) - { - last = outline; - outline->type = SWF_PATHTYPE_MOVE; - outline->dest.x = x; - outline->dest.y = y; - outline->link = (SWF_OUTLINE*)malloc(sizeof(bezierpathsegment)); - outline = (bezierpathsegment*)outline->link; + double x,y; + state->transform(subpath->getX(s),subpath->getY(s),&x,&y); + if(s==0) { + if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) { + draw.lineTo(&draw, lastx, lasty); + } + draw.moveTo(&draw, x,y); + posx = lastx = x; + posy = lasty = y; cpos = 0; - lastx = nx; - lasty = ny; - } - else if(subpath->getCurve(s) && !cpos) - { - outline->B.x = x; - outline->B.y = y; + needsfix = 0; + } else if(subpath->getCurve(s) && cpos==0) { + bx = x; + by = y; cpos = 1; - } - else if(subpath->getCurve(s) && cpos) - { - outline->C.x = x; - outline->C.y = y; + } else if(subpath->getCurve(s) && cpos==1) { + cx = x; + cy = y; cpos = 2; - } - else - { - last = outline; - outline->dest.x = x; - outline->dest.y = y; - outline->type = cpos?SWF_PATHTYPE_BEZIER:SWF_PATHTYPE_LINE; - outline->link = (SWF_OUTLINE*)malloc(sizeof(bezierpathsegment)); - outline = (bezierpathsegment*)outline->link; + } else { + posx = x; + posy = y; + if(cpos==0) { + draw.lineTo(&draw, x,y); + } else { + gfxdraw_cubicTo(&draw, bx,by, cx,cy, x,y); + } + needsfix = 1; cpos = 0; - lastx = nx; - lasty = ny; } } } - if(last->link) {free(last->link);} - last->link = 0; - - return (SWF_OUTLINE*)start; + /* fix non-closed lines */ + if(closed && needsfix && (fabs(posx-lastx)+fabs(posy-lasty))>0.001) { + draw.lineTo(&draw, lastx, lasty); + } + gfxline_t*result = (gfxline_t*)draw.result(&draw); + return result; } + /*---------------------------------------------------------------------------- * Primitive Graphic routines *----------------------------------------------------------------------------*/ @@ -676,116 +663,161 @@ void SWFOutputDev::stroke(GfxState *state) int lineJoin = state->getLineJoin(); // 0=miter, 1=round 2=bevel double miterLimit = state->getMiterLimit(); double width = state->getTransformedLineWidth(); - struct swfmatrix m; + GfxRGB rgb; double opaq = state->getStrokeOpacity(); - state->getStrokeRGB(&rgb); - - m.m11 = 1; m.m21 = 0; m.m22 = 1; - m.m12 = 0; m.m13 = 0; m.m23 = 0; - SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path); - - if(screenloglevel >= LOGLEVEL_TRACE) { - msg(" stroke\n"); - dump_outline(outline); - } + if(type3active) + state->getFillRGB(&rgb); + else + state->getStrokeRGB(&rgb); + gfxcolor_t col; + col.r = (unsigned char)(rgb.r*255); + col.g = (unsigned char)(rgb.g*255); + col.b = (unsigned char)(rgb.b*255); + col.a = (unsigned char)(opaq*255); + + gfx_capType capType = gfx_capRound; + if(lineCap == 0) capType = gfx_capButt; + else if(lineCap == 1) capType = gfx_capRound; + else if(lineCap == 2) capType = gfx_capSquare; - lineJoin = 1; // other line joins are not yet supported by the swf encoder - // TODO: support bevel joints + gfx_joinType joinType = gfx_joinRound; + if(lineJoin == 0) joinType = gfx_joinMiter; + else if(lineJoin == 1) joinType = gfx_joinRound; + else if(lineJoin == 2) joinType = gfx_joinBevel; - if(((lineCap==1) && (lineJoin==1)) || width<=caplinewidth) { - /* FIXME- if the path is smaller than 2 segments, we could ignore - lineJoin */ - swfoutput_setdrawmode(&output, DRAWMODE_STROKE); - swfoutput_drawpath(&output, outline, &m); - } else { - swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), - (char)(rgb.b*255), (char)(opaq*255)); + gfxline_t*line= gfxPath_to_gfxline(state, path, 0); + + int dashnum = 0; + double dashphase = 0; + double * ldash = 0; + state->getLineDash(&ldash, &dashnum, &dashphase); - //swfoutput_setlinewidth(&output, 1.0); //only for debugging - //swfoutput_setstrokecolor(&output, 0, 255, 0, 255); //likewise, see below - //swfoutput_setfillcolor(&output, 255, 0, 0, 255); //likewise, see below + if(dashnum && ldash) { + float * dash = (float*)malloc(sizeof(float)*(dashnum+1)); + int t; + double cut = 0; + int fixzero = 0; + msg(" %d dashes", dashnum); + msg(" | phase: %f", dashphase); + for(t=0;t | d%-3d: %f", t, ldash[t]); + } + dash[dashnum] = -1; + if(getLogLevel() >= LOGLEVEL_TRACE) { + dump_outline(line); + } - swfoutput_drawpath2poly(&output, outline, &m, lineJoin, lineCap, width, miterLimit); - updateLineWidth(state); //reset - updateStrokeColor(state); //reset - updateFillColor(state); //reset + gfxline_t*line2 = gfxtool_dash_line(line, dash, dashphase); + gfxline_free(line); + line = line2; + msg(" After dashing:"); } - free_outline(outline); + + if(getLogLevel() >= LOGLEVEL_TRACE) { + double gray; + state->getStrokeGray(&gray); + msg(" stroke width=%f join=%s cap=%s dashes=%d color=%02x%02x%02x%02x gray=%f\n", + width, + lineJoin==0?"miter": (lineJoin==1?"round":"bevel"), + lineCap==0?"butt": (lineJoin==1?"round":"square"), + dashnum, + col.r,col.g,col.b,col.a, + gray + ); + dump_outline(line); + } + + swfoutput_drawgfxline(&output, line, width, &col, capType, joinType, miterLimit); + gfxline_free(line); } void SWFOutputDev::fill(GfxState *state) { GfxPath * path = state->getPath(); - struct swfmatrix m; - m.m11 = 1; m.m21 = 0; m.m22 = 1; - m.m12 = 0; m.m13 = 0; m.m23 = 0; - SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path); - - if(screenloglevel >= LOGLEVEL_TRACE) { - msg(" fill\n"); - dump_outline(outline); + double opaq = state->getFillOpacity(); + GfxRGB rgb; + state->getFillRGB(&rgb); + gfxcolor_t col; + col.r = (unsigned char)(rgb.r*255); + col.g = (unsigned char)(rgb.g*255); + col.b = (unsigned char)(rgb.b*255); + col.a = (unsigned char)(opaq*255); + + gfxline_t*line= gfxPath_to_gfxline(state, path, 1); + + if(getLogLevel() >= LOGLEVEL_TRACE) { + msg(" fill %02x%02x%02x%02x\n", col.r, col.g, col.b, col.a); + dump_outline(line); } - swfoutput_setdrawmode(&output, DRAWMODE_FILL); - swfoutput_drawpath(&output, outline, &m); - free_outline(outline); + swfoutput_fillgfxline(&output, line, &col); + gfxline_free(line); } void SWFOutputDev::eoFill(GfxState *state) { GfxPath * path = state->getPath(); - struct swfmatrix m; - m.m11 = 1; m.m21 = 0; m.m22 = 1; - m.m12 = 0; m.m13 = 0; m.m23 = 0; - SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path); + double opaq = state->getFillOpacity(); + GfxRGB rgb; + state->getFillRGB(&rgb); + gfxcolor_t col; + col.r = (unsigned char)(rgb.r*255); + col.g = (unsigned char)(rgb.g*255); + col.b = (unsigned char)(rgb.b*255); + col.a = (unsigned char)(opaq*255); + + gfxline_t*line= gfxPath_to_gfxline(state, path, 1); - if(screenloglevel >= LOGLEVEL_TRACE) { + if(getLogLevel() >= LOGLEVEL_TRACE) { msg(" eofill\n"); - dump_outline(outline); + dump_outline(line); } - swfoutput_setdrawmode(&output, DRAWMODE_EOFILL); - swfoutput_drawpath(&output, outline, &m); - free_outline(outline); + swfoutput_fillgfxline(&output, line, &col); + gfxline_free(line); } void SWFOutputDev::clip(GfxState *state) { GfxPath * path = state->getPath(); - struct swfmatrix m; - m.m11 = 1; m.m22 = 1; - m.m12 = 0; m.m21 = 0; - m.m13 = 0; m.m23 = 0; - SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path); + gfxline_t*line = gfxPath_to_gfxline(state, path, 1); - if(screenloglevel >= LOGLEVEL_TRACE) { + if(getLogLevel() >= LOGLEVEL_TRACE) { msg(" clip\n"); - dump_outline(outline); + dump_outline(line); } - swfoutput_startclip(&output, outline, &m); + swfoutput_startclip(&output, line); clipping[clippos] ++; - free_outline(outline); + gfxline_free(line); } void SWFOutputDev::eoClip(GfxState *state) { GfxPath * path = state->getPath(); - struct swfmatrix m; - m.m11 = 1; m.m21 = 0; m.m22 = 1; - m.m12 = 0; m.m13 = 0; m.m23 = 0; - SWF_OUTLINE*outline = gfxPath_to_SWF_OUTLINE(state, path); + gfxline_t*line = gfxPath_to_gfxline(state, path, 1); - if(screenloglevel >= LOGLEVEL_TRACE) { + if(getLogLevel() >= LOGLEVEL_TRACE) { msg(" eoclip\n"); - dump_outline(outline); + dump_outline(line); } - swfoutput_startclip(&output, outline, &m); + swfoutput_startclip(&output, line); clipping[clippos] ++; - free_outline(outline); + gfxline_free(line); } + +/* pass through functions for swf_output */ int SWFOutputDev::save(char*filename) { return swfoutput_save(&output, filename); } +void SWFOutputDev::pagefeed() +{ + swfoutput_pagefeed(&output); +} +void* SWFOutputDev::getSWF() +{ + return (void*)swfoutput_get(&output); +} SWFOutputDev::~SWFOutputDev() { @@ -829,7 +861,16 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y, // check for invisible text -- this is used by Acrobat Capture if ((state->getRender() & 3) == 3) return; + GfxRGB rgb; + double opaq = state->getFillOpacity(); + state->getFillRGB(&rgb); + gfxcolor_t col; + col.r = (unsigned char)(rgb.r*255); + col.g = (unsigned char)(rgb.g*255); + col.b = (unsigned char)(rgb.b*255); + col.a = (unsigned char)(opaq*255); + Gushort *CIDToGIDMap = 0; GfxFont*font = state->getFont(); if(font->getType() == fontType3) { @@ -842,20 +883,29 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y, state->transform(x, y, &x1, &y1); Unicode u=0; - if(_u && uLen) + char*name=0; + + if(_u && uLen) { u = *_u; + if (u) { + int t; + /* find out char name from unicode index + TODO: should be precomputed + */ + for(t=0;tisCIDFont() && u) { + if(font->isCIDFont()) { GfxCIDFont*cfont = (GfxCIDFont*)font; - int t; - for(t=0;tgetType() == fontCIDType2) { + CIDToGIDMap = cfont->getCIDToGID(); } } else { Gfx8BitFont*font8; @@ -864,29 +914,46 @@ void SWFOutputDev::drawChar(GfxState *state, double x, double y, if(enc && enc[c]) name = enc[c]; } - - msg(" drawChar(%f,%f,c='%c' (%d),u=%d <%d>) CID=%d name=\"%s\"\n",x,y,(c&127)>=32?c:'?',c,u, uLen, font->isCIDFont(), FIXNULL(name)); - - /*x1 = (int)(x1+0.5); - y1 = (int)(y1+0.5);*/ - - int ret = swfoutput_drawchar(&output, x1, y1, name, c, u); + + if (CIDToGIDMap) { + msg(" drawChar(%f, %f, c='%c' (%d), GID=%d, u=%d <%d>) CID=%d name=\"%s\"\n", x, y, (c&127)>=32?c:'?', c, CIDToGIDMap[c], u, uLen, font->isCIDFont(), FIXNULL(name)); + swfoutput_drawchar(&output, x1, y1, name, CIDToGIDMap[c], u, &col); + } else { + msg(" drawChar(%f,%f,c='%c' (%d), u=%d <%d>) CID=%d name=\"%s\"\n",x,y,(c&127)>=32?c:'?',c,u, uLen, font->isCIDFont(), FIXNULL(name)); + swfoutput_drawchar(&output, x1, y1, name, c, u, &col); + } } void SWFOutputDev::endString(GfxState *state) { } - -GBool SWFOutputDev::beginType3Char(GfxState *state, - CharCode code, Unicode *u, int uLen) +/* the logic seems to be as following: + first, beginType3Char is called, with the charcode and the coordinates. + if this function returns true, it already knew about the char and has now drawn it. + if the function returns false, it's a new char, and type3D1 is called with some parameters- + the all draw operations until endType3Char are part of the char (which in this moment is + at the position first passed to beginType3Char). the char ends with endType3Char. + + The drawing operations between beginType3Char and endType3Char are somewhat different to + the normal ones. For example, the fillcolor equals the stroke color. +*/ + +GBool SWFOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen) { msg(" beginType3Char %d, %08x, %d", code, *u, uLen); type3active = 1; - /* the character itself is going to be passed using - drawImageMask() */ + /* the character itself is going to be passed using the draw functions */ return gFalse; /* gTrue= is_in_cache? */ } +void SWFOutputDev::type3D0(GfxState *state, double wx, double wy) { + msg(" type3D0 width=%f height=%f", wx, wy); +} +void SWFOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) { + msg(" type3D1 width=%f height=%f bbox=(%f,%f,%f,%f)", wx, wy, + llx,lly,urx,ury); +} + void SWFOutputDev::endType3Char(GfxState *state) { type3active = 0; @@ -920,10 +987,10 @@ void SWFOutputDev::startPage(int pageNum, GfxState *state, double crop_x1, doubl /* apply user clip box */ if(user_clipx1|user_clipy1|user_clipx2|user_clipy2) { - if(user_clipx1 > x1) x1 = user_clipx1; - if(user_clipx2 < x2) x2 = user_clipx2; - if(user_clipy1 > y1) y1 = user_clipy1; - if(user_clipy2 < y2) y2 = user_clipy2; + /*if(user_clipx1 > x1)*/ x1 = user_clipx1; + /*if(user_clipx2 < x2)*/ x2 = user_clipx2; + /*if(user_clipy1 > y1)*/ y1 = user_clipy1; + /*if(user_clipy2 < y2)*/ y2 = user_clipy2; } if(!outputstarted) { @@ -1144,7 +1211,7 @@ char* SWFOutputDev::searchFont(char*name) void SWFOutputDev::updateLineWidth(GfxState *state) { double width = state->getTransformedLineWidth(); - swfoutput_setlinewidth(&output, width); + //swfoutput_setlinewidth(&output, width); } void SWFOutputDev::updateLineCap(GfxState *state) @@ -1163,8 +1230,7 @@ void SWFOutputDev::updateFillColor(GfxState *state) double opaq = state->getFillOpacity(); state->getFillRGB(&rgb); - swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), - (char)(rgb.b*255), (char)(opaq*255)); + //swfoutput_setfillcolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255)); } void SWFOutputDev::updateStrokeColor(GfxState *state) @@ -1172,9 +1238,7 @@ void SWFOutputDev::updateStrokeColor(GfxState *state) GfxRGB rgb; double opaq = state->getStrokeOpacity(); state->getStrokeRGB(&rgb); - - swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), - (char)(rgb.b*255), (char)(opaq*255)); + //swfoutput_setstrokecolor(&output, (char)(rgb.r*255), (char)(rgb.g*255), (char)(rgb.b*255), (char)(opaq*255)); } void FoFiWrite(void *stream, char *data, int len) @@ -1224,9 +1288,11 @@ char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font) } #ifdef XPDF_101 Type1CFontFile *cvt = new Type1CFontFile(fontBuf, fontLen); + if(!cvt) return 0; cvt->convertToType1(f); #else FoFiType1C *cvt = FoFiType1C::make(fontBuf, fontLen); + if(!cvt) return 0; cvt->convertToType1(NULL, gTrue, FoFiWrite, f); #endif //cvt->convertToCIDType0("test", f); @@ -1293,6 +1359,9 @@ char* searchForSuitableFont(GfxFont*gfxFont) char*name = getFontName(gfxFont); char*fontname = 0; char*filename = 0; + + if(!config_use_fontconfig) + return 0; #ifdef HAVE_FONTCONFIG FcPattern *pattern, *match; @@ -1300,25 +1369,38 @@ char* searchForSuitableFont(GfxFont*gfxFont) FcChar8 *v; static int fcinitcalled = false; + + msg(" searchForSuitableFont(%s)", name); // call init ony once if (!fcinitcalled) { + msg(" Initializing FontConfig..."); fcinitcalled = true; - FcInit(); //leaks + if(FcInit()) { + msg(" FontConfig Initialization failed. Disabling."); + config_use_fontconfig = 0; + return 0; + } + msg(" ...initialized FontConfig"); } + msg(" FontConfig: Create \"%s\" Family Pattern", name); pattern = FcPatternBuild(NULL, FC_FAMILY, FcTypeString, name, NULL); if (gfxFont->isItalic()) // check for italic + msg(" FontConfig: Adding Italic Slant"); FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); if (gfxFont->isBold()) // check for bold + msg(" FontConfig: Adding Bold Weight"); FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); + msg(" FontConfig: Try to match..."); // configure and match using the original font name FcConfigSubstitute(0, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); match = FcFontMatch(0, pattern, &result); if (FcPatternGetString(match, "family", 0, &v) == FcResultMatch) { + msg(" FontConfig: family=%s", (char*)v); // if we get an exact match if (strcmp((char *)v, name) == 0) { if (FcPatternGetString(match, "file", 0, &v) == FcResultMatch) { @@ -1327,6 +1409,7 @@ char* searchForSuitableFont(GfxFont*gfxFont) if(nfn) fontname = strdup(nfn+1); else fontname = filename; } + msg(" FontConfig: Returning \"%s\"", fontname); } else { // initialize patterns FcPatternDestroy(pattern); @@ -1334,22 +1417,28 @@ char* searchForSuitableFont(GfxFont*gfxFont) // now match against serif etc. if (gfxFont->isSerif()) { + msg(" FontConfig: Create Serif Family Pattern"); pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "serif", NULL); } else if (gfxFont->isFixedWidth()) { + msg(" FontConfig: Create Monospace Family Pattern"); pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "monospace", NULL); } else { + msg(" FontConfig: Create Sans Family Pattern"); pattern = FcPatternBuild (NULL, FC_FAMILY, FcTypeString, "sans", NULL); } // check for italic if (gfxFont->isItalic()) { + msg(" FontConfig: Adding Italic Slant"); int bb = FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); } // check for bold if (gfxFont->isBold()) { + msg(" FontConfig: Adding Bold Weight"); int bb = FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); } + msg(" FontConfig: Try to match... (2)"); // configure and match using serif etc FcConfigSubstitute (0, pattern, FcMatchPattern); FcDefaultSubstitute (pattern); @@ -1361,6 +1450,7 @@ char* searchForSuitableFont(GfxFont*gfxFont) if(nfn) fontname = strdup(nfn+1); else fontname = filename; } + msg(" FontConfig: Returning \"%s\"", fontname); } } @@ -1388,6 +1478,10 @@ char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname) fontname = "Times-Roman"; } filename = searchFont(fontname); + if(!filename) { + msg(" Couldn't find font %s- did you install the default fonts?"); + return 0; + } if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) { msg(" Too many fonts in file."); @@ -1487,7 +1581,7 @@ void SWFOutputDev::updateFont(GfxState *state) if(embedded && (gfxFont->getType() == fontType1 || gfxFont->getType() == fontType1C || - //gfxFont->getType() == fontCIDType0C || + (gfxFont->getType() == fontCIDType0C && forceType0Fonts) || gfxFont->getType() == fontTrueType || gfxFont->getType() == fontCIDType2 )) @@ -1577,7 +1671,7 @@ unsigned char* antialize(unsigned char*data, int width, int height, int newwidth void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap*colorMap, GBool invert, - GBool inlineImg, int mask) + GBool inlineImg, int mask, int*maskColors) { FILE *fi; int c; @@ -1628,22 +1722,21 @@ void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str, } if(mask) { - int yes=0,i,j; + int i,j; unsigned char buf[8]; - int xid = 0; - int yid = 0; int x,y; unsigned char*pic = new unsigned char[width*height]; RGBA pal[256]; GfxRGB rgb; state->getFillRGB(&rgb); + memset(pal,255,sizeof(pal)); - pal[0].r = (int)(rgb.r*255); pal[0].g = (int)(rgb.g*255); - pal[0].b = (int)(rgb.b*255); pal[0].a = 255; - pal[1].r = 0; pal[1].g = 0; pal[1].b = 0; pal[1].a = 0; + pal[0].r = (int)(rgb.r*255); pal[1].r = 0; + pal[0].g = (int)(rgb.g*255); pal[1].g = 0; + pal[0].b = (int)(rgb.b*255); pal[1].b = 0; + pal[0].a = 255; pal[1].a = 0; + int numpalette = 2; - xid += pal[1].r*3 + pal[1].g*11 + pal[1].b*17; - yid += pal[1].r*7 + pal[1].g*5 + pal[1].b*23; int realwidth = (int)sqrt(SQR(x2-x3) + SQR(y2-y3)); int realheight = (int)sqrt(SQR(x1-x2) + SQR(y1-y2)); for (y = 0; y < height; ++y) @@ -1653,173 +1746,120 @@ void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str, if(invert) buf[0]=1-buf[0]; pic[width*y+x] = buf[0]; - xid+=x*buf[0]+1; - yid+=y*buf[0]*3+1; } /* the size of the drawn image is added to the identifier as the same image may require different bitmaps if displayed at different sizes (due to antialiasing): */ - if(type3active) { - xid += realwidth; - yid += realheight; - } int t,found = -1; - for(t=0;tgetNumPixelComps()!=1 || str->getKind()==strDCT) - { + + if(colorMap->getNumPixelComps()!=1 || str->getKind()==strDCT) { RGBA*pic=new RGBA[width*height]; - int xid = 0; - int yid = 0; for (y = 0; y < height; ++y) { for (x = 0; x < width; ++x) { - int r,g,b,a; imgStr->getPixel(pixBuf); colorMap->getRGB(pixBuf, &rgb); - pic[width*y+x].r = r = (U8)(rgb.r * 255 + 0.5); - pic[width*y+x].g = g = (U8)(rgb.g * 255 + 0.5); - pic[width*y+x].b = b = (U8)(rgb.b * 255 + 0.5); - pic[width*y+x].a = a = 255;//(U8)(rgb.a * 255 + 0.5); - xid += x*r+x*b*3+x*g*7+x*a*11; - yid += y*r*3+y*b*17+y*g*19+y*a*11; + pic[width*y+x].r = (U8)(rgb.r * 255 + 0.5); + pic[width*y+x].g = (U8)(rgb.g * 255 + 0.5); + pic[width*y+x].b = (U8)(rgb.b * 255 + 0.5); + pic[width*y+x].a = 255;//(U8)(rgb.a * 255 + 0.5); } } - int t,found = -1; - for(t=0;tgetKind()==strDCT) - pic_ids[picpos] = swfoutput_drawimagejpeg(&output, pic, width, height, - x1,y1,x2,y2,x3,y3,x4,y4); - else - pic_ids[picpos] = swfoutput_drawimagelossless(&output, pic, width, height, - x1,y1,x2,y2,x3,y3,x4,y4); - pic_xids[picpos] = xid; - pic_yids[picpos] = yid; - pic_width[picpos] = width; - pic_height[picpos] = height; - if(picpos<1024) - picpos++; - } else { - swfoutput_drawimageagain(&output, pic_ids[found], width, height, - x1,y1,x2,y2,x3,y3,x4,y4); - } + if(str->getKind()==strDCT) + swfoutput_drawimagejpeg(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4); + else + swfoutput_drawimagelossless(&output, pic, width, height, x1,y1,x2,y2,x3,y3,x4,y4); delete pic; delete imgStr; return; - } - else - { - U8*pic = new U8[width*height]; + } else { + RGBA*pic=new RGBA[width*height]; RGBA pal[256]; int t; - int xid=0,yid=0; - for(t=0;t<256;t++) - { - int r,g,b,a; + for(t=0;t<256;t++) { pixBuf[0] = t; colorMap->getRGB(pixBuf, &rgb); - pal[t].r = r = (U8)(rgb.r * 255 + 0.5); - pal[t].g = g = (U8)(rgb.g * 255 + 0.5); - pal[t].b = b = (U8)(rgb.b * 255 + 0.5); - pal[t].a = a = 255;//(U8)(rgb.b * 255 + 0.5); - xid += t*r+t*b*3+t*g*7+t*a*11; - xid += (~t)*r+t*b*3+t*g*7+t*a*11; + /*if(maskColors && *maskColors==t) { + msg(" Color %d is transparent", t); + if (imgData->maskColors) { + *alpha = 0; + for (i = 0; i < imgData->colorMap->getNumPixelComps(); ++i) { + if (pix[i] < imgData->maskColors[2*i] || + pix[i] > imgData->maskColors[2*i+1]) { + *alpha = 1; + break; + } + } + } else { + *alpha = 1; + } + if(!*alpha) { + pal[t].r = 0; + pal[t].g = 0; + pal[t].b = 0; + pal[t].a = 0; + } + } else*/ { + pal[t].r = (U8)(rgb.r * 255 + 0.5); + pal[t].g = (U8)(rgb.g * 255 + 0.5); + pal[t].b = (U8)(rgb.b * 255 + 0.5); + pal[t].a = 255;//(U8)(rgb.b * 255 + 0.5); + } } for (y = 0; y < height; ++y) { for (x = 0; x < width; ++x) { imgStr->getPixel(pixBuf); - pic[width*y+x] = pixBuf[0]; - xid += x*pixBuf[0]*7; - yid += y*pixBuf[0]*3; + pic[width*y+x] = pal[pixBuf[0]]; } } - int found = -1; - for(t=0;t drawImageMask %dx%d, invert=%d inline=%d", width, height, invert, inlineImg); - drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1); + drawGeneralImage(state,ref,str,width,height,0,invert,inlineImg,1, 0); } void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, @@ -1845,7 +1885,7 @@ void SWFOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, if(colorMap) msg(" colorMap pixcomps:%d bits:%d mode:%d\n", colorMap->getNumPixelComps(), colorMap->getBits(),colorMap->getColorSpace()->getMode()); - drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0); + drawGeneralImage(state,ref,str,width,height,colorMap,0,inlineImg,0,maskColors); } SWFOutputDev*output = 0; @@ -1892,12 +1932,39 @@ static void printInfoDate(Dict *infoDict, char *key, char *fmt) { obj.free(); } +int jpeg_dpi = 0; +int ppm_dpi = 0; + void pdfswf_setparameter(char*name, char*value) { + msg(" setting parameter %s to \"%s\"", name, value); if(!strcmp(name, "caplinewidth")) { caplinewidth = atof(value); } else if(!strcmp(name, "zoom")) { + char buf[80]; zoom = atoi(value); + sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom); + swfoutput_setparameter("jpegsubpixels", buf); + sprintf(buf, "%f", (double)ppm_dpi/(double)zoom); + swfoutput_setparameter("ppmsubpixels", buf); + } else if(!strcmp(name, "jpegdpi")) { + char buf[80]; + jpeg_dpi = atoi(value); + sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom); + swfoutput_setparameter("jpegsubpixels", buf); + } else if(!strcmp(name, "ppmdpi")) { + char buf[80]; + ppm_dpi = atoi(value); + sprintf(buf, "%f", (double)ppm_dpi/(double)zoom); + swfoutput_setparameter("ppmsubpixels", buf); + } else if(!strcmp(name, "forceType0Fonts")) { + forceType0Fonts = atoi(value); + } else if(!strcmp(name, "fontdir")) { + pdfswf_addfontdir(value); + } else if(!strcmp(name, "languagedir")) { + pdfswf_addlanguagedir(value); + } else if(!strcmp(name, "fontconfig")) { + config_use_fontconfig = atoi(value); } else { swfoutput_setparameter(name, value); } @@ -1914,6 +1981,82 @@ void pdfswf_addfont(char*filename) } } +static char* dirseparator() +{ +#ifdef WIN32 + return "\\"; +#else + return "/"; +#endif +} + +void pdfswf_addlanguagedir(char*dir) +{ + if(!globalParams) + globalParams = new GlobalParams(""); + + msg(" Adding %s to language pack directories", dir); + + int l; + FILE*fi = 0; + char* config_file = (char*)malloc(strlen(dir) + 1 + sizeof("add-to-xpdfrc")); + strcpy(config_file, dir); + strcat(config_file, dirseparator()); + strcat(config_file, "add-to-xpdfrc"); + + fi = fopen(config_file, "rb"); + if(!fi) { + msg(" Could not open %s", config_file); + return; + } + globalParams->parseFile(new GString(config_file), fi); + fclose(fi); +} + +void pdfswf_addfontdir(char*dirname) +{ +#ifdef HAVE_DIRENT_H + msg(" Adding %s to font directories", dirname); + DIR*dir = opendir(dirname); + if(!dir) { + msg(" Couldn't open directory %s\n", dirname); + return; + } + struct dirent*ent; + while(1) { + ent = readdir (dir); + if (!ent) + break; + int l; + char*name = ent->d_name; + char type = 0; + if(!name) continue; + l=strlen(name); + if(l<4) + continue; + if(!strncasecmp(&name[l-4], ".pfa", 4)) + type=1; + if(!strncasecmp(&name[l-4], ".pfb", 4)) + type=3; + if(!strncasecmp(&name[l-4], ".ttf", 4)) + type=2; + if(type) + { + char*fontname = (char*)malloc(strlen(dirname)+strlen(name)+2); + strcpy(fontname, dirname); + strcat(fontname, dirseparator()); + strcat(fontname, name); + msg(" Adding %s to fonts", fontname); + pdfswf_addfont(fontname); + } + } + closedir(dir); +#else + msg(" No dirent.h- unable to add font dir %s", dir); +#endif +} + + typedef struct _pdf_doc_internal { int protect; @@ -1940,7 +2083,8 @@ pdf_doc_t* pdf_init(char*filename, char*userPassword) Object info; // read config file - globalParams = new GlobalParams(""); + if(!globalParams) + globalParams = new GlobalParams(""); // open PDF file if (userPassword && userPassword[0]) { @@ -1959,7 +2103,7 @@ pdf_doc_t* pdf_init(char*filename, char*userPassword) // print doc info i->doc->getDocInfo(&info); if (info.isDict() && - (screenloglevel>=LOGLEVEL_NOTICE)) { + (getScreenLogLevel()>=LOGLEVEL_NOTICE)) { printInfoString(info.getDict(), "Title", "Title: %s\n"); printInfoString(info.getDict(), "Subject", "Subject: %s\n"); printInfoString(info.getDict(), "Keywords", "Keywords: %s\n"); @@ -2017,7 +2161,7 @@ class MemCheck { public: ~MemCheck() { - delete globalParams; + delete globalParams;globalParams=0; Object::memCheck(stderr); gMemReport(stderr); } @@ -2078,10 +2222,27 @@ void swf_output_setparameter(swf_output_t*swf_output, char*name, char*value) pdfswf_setparameter(name, value); } +void swf_output_pagefeed(swf_output_t*swf) +{ + swf_output_internal_t*i= (swf_output_internal_t*)swf->internal; + i->outputDev->pagefeed(); + i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2); +} + int swf_output_save(swf_output_t*swf, char*filename) { swf_output_internal_t*i= (swf_output_internal_t*)swf->internal; - return i->outputDev->save(filename); + int ret = i->outputDev->save(filename); + i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2); + return ret; +} + +void* swf_output_get(swf_output_t*swf) +{ + swf_output_internal_t*i= (swf_output_internal_t*)swf->internal; + void* ret = i->outputDev->getSWF(); + i->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2); + return ret; } void swf_output_destroy(swf_output_t*output) @@ -2092,10 +2253,10 @@ void swf_output_destroy(swf_output_t*output) free(output); } -void pdf_page_render2(pdf_page_t*page, swf_output_t*output) +void pdf_page_render2(pdf_page_t*page, swf_output_t*swf) { pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal; - swf_output_internal_t*si = (swf_output_internal_t*)output->internal; + swf_output_internal_t*si = (swf_output_internal_t*)swf->internal; if(pi->protect) { swfoutput_setparameter("protect", "1"); @@ -2106,6 +2267,7 @@ void pdf_page_render2(pdf_page_t*page, swf_output_t*output) #else pi->doc->displayPage((OutputDev*)si->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, /*doLinks*/(int)1); #endif + si->outputDev->getDimensions(&swf->x1, &swf->y1, &swf->x2, &swf->y2); } void pdf_page_rendersection(pdf_page_t*page, swf_output_t*output, int x, int y, int x1, int y1, int x2, int y2)