X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=pdf2swf%2FSWFOutputDev.cc;h=cef673326eca478cc0c8ea0b205090a648f50992;hb=5ede6209244433ea174111a9079fa6d0cf84d227;hp=0357f50dbbd23d05453c230db32bd164a2474caf;hpb=5fc373d518344e738a735a2d0c08fdf8273623e1;p=swftools.git diff --git a/pdf2swf/SWFOutputDev.cc b/pdf2swf/SWFOutputDev.cc index 0357f50..cef6733 100644 --- a/pdf2swf/SWFOutputDev.cc +++ b/pdf2swf/SWFOutputDev.cc @@ -22,7 +22,9 @@ #include #include #include +#include "../config.h" //xpdf header files +#include "config.h" #include "gfile.h" #include "GString.h" #include "gmem.h" @@ -35,18 +37,22 @@ #include "Page.h" #include "PDFDoc.h" #include "Error.h" -#include "config.h" #include "OutputDev.h" #include "GfxState.h" #include "GfxFont.h" +#include "CharCodeToUnicode.h" +#include "NameToUnicodeTable.h" #include "FontFile.h" #include "GlobalParams.h" //swftools header files #include "swfoutput.h" -extern "C" { #include "../lib/log.h" + #include "ttf2pt1.h" -} + +#define logf logarithmf // logf is also used by ../lib/log.h +#include +#undef logf static PDFDoc*doc = 0; static char* swffilename = 0; @@ -58,6 +64,8 @@ int*pages = 0; int pagebuflen = 0; int pagepos = 0; +double caplinewidth = 3.0; + static void printInfoString(Dict *infoDict, char *key, char *fmt); static void printInfoDate(Dict *infoDict, char *key, char *fmt); @@ -132,7 +140,7 @@ public: // Does this device use drawChar() or drawString()? virtual GBool useDrawChar(); - virtual GBool interpretType3Chars() {return gFalse;} + virtual GBool interpretType3Chars() {return gTrue;} //----- initialization and control @@ -154,6 +162,8 @@ public: virtual void updateFillColor(GfxState *state); virtual void updateStrokeColor(GfxState *state); virtual void updateLineWidth(GfxState *state); + virtual void updateLineJoin(GfxState *state); + virtual void updateLineCap(GfxState *state); virtual void updateAll(GfxState *state) { @@ -161,6 +171,8 @@ public: updateFillColor(state); updateStrokeColor(state); updateLineWidth(state); + updateLineJoin(state); + updateLineCap(state); }; //----- path painting @@ -187,6 +199,10 @@ public: virtual void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg); + + virtual GBool beginType3Char(GfxState *state, + CharCode code, Unicode *u, int uLen); + virtual void endType3Char(GfxState *state); private: void drawGeneralImage(GfxState *state, Object *ref, Stream *str, @@ -206,6 +222,8 @@ public: int linkinfo; // did we write "File contains links" yet? int ttfinfo; // did we write "File contains TrueType Fonts" yet? + int type3active; // are we between beginType3()/endType3()? + GfxState *laststate; }; @@ -339,7 +357,7 @@ void showFontError(GfxFont*font, int nr) else if(nr == 1) logf(" The following font caused problems (substituting):"); else if(nr == 2) - logf(" This document contains Type 3 Fonts: (some text may be incorrectly displayed)"); + logf(" The following Type 3 Font will be rendered as bitmap:"); dumpFontInfo("", font); } @@ -413,6 +431,7 @@ SWFOutputDev::SWFOutputDev() ttfinfo = 0; linkinfo = 0; pbminfo = 0; + type3active = 0; clippos = 0; clipping[clippos] = 0; outputstarted = 0; @@ -428,6 +447,14 @@ T1_OUTLINE* gfxPath_to_T1_OUTLINE(GfxState*state, GfxPath*path) bezierpathsegment*outline = start = new bezierpathsegment(); int cpos = 0; double lastx=0,lasty=0; + if(!num) { + logf(" empty path"); + outline->type = T1_PATHTYPE_MOVE; + outline->dest.x = 0; + outline->dest.y = 0; + outline->link = 0; + return (T1_OUTLINE*)outline; + } for(t = 0; t < num; t++) { GfxSubpath *subpath = path->getSubpath(t); int subnum = subpath->getNumPoints(); @@ -487,12 +514,40 @@ void SWFOutputDev::stroke(GfxState *state) { logf(" stroke\n"); GfxPath * path = state->getPath(); + int lineCap = state->getLineCap(); // 0=butt, 1=round 2=square + 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; T1_OUTLINE*outline = gfxPath_to_T1_OUTLINE(state, path); - swfoutput_setdrawmode(&output, DRAWMODE_STROKE); - swfoutput_drawpath(&output, outline, &m); + + lineJoin = 1; // other line joins are not yet supported by the swf encoder + // TODO: support bevel joints + + 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)); + + //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 + + swfoutput_drawpath2poly(&output, outline, &m, lineJoin, lineCap, width, miterLimit); + updateLineWidth(state); //reset + updateStrokeColor(state); //reset + updateFillColor(state); //reset + } } void SWFOutputDev::fill(GfxState *state) { @@ -570,31 +625,57 @@ int charcounter = 0; void SWFOutputDev::drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, - CharCode c, Unicode *u, int uLen) + CharCode c, Unicode *_u, int uLen) { logf(" drawChar(%f,%f,%f,%f,'%c')\n",x,y,dx,dy,c); + // check for invisible text -- this is used by Acrobat Capture - if ((state->getRender() & 3) != 3) - { - GfxFont*font = state->getFont(); - Gfx8BitFont*font8; - if(font->isCIDFont()) { - logf(" CID Font"); - return; - } - font8 = (Gfx8BitFont*)font; - - char**enc=font8->getEncoding(); - - double x1,y1; - x1 = x; - y1 = y; - state->transform(x, y, &x1, &y1); - - if(enc[c]) - swfoutput_drawchar(&output, x1, y1, enc[c], c); - else - logf(" couldn't get name for character %02x from Encoding", c); + if ((state->getRender() & 3) == 3) + return; + + GfxFont*font = state->getFont(); + + if(font->getType() == fontType3) { + /* type 3 chars are passed primarily as graphics */ + return; + } + double x1,y1; + x1 = x; + y1 = y; + state->transform(x, y, &x1, &y1); + + if(font->isCIDFont()) { + GfxCIDFont*cfont = (GfxCIDFont*)font; + Unicode u=0; + char*name=0; + if(_u) + u = *_u; + if(u) { + int t; + for(t=0;tgetName()->getCString(), + cfont->getType());*/ + + if(name) + swfoutput_drawchar(&output, x1, y1, name, c); + else + logf(" couldn't get name for CID character %02x from Encoding", c); + } else { + Gfx8BitFont*font8; + font8 = (Gfx8BitFont*)font; + char**enc=font8->getEncoding(); + + if(enc && enc[c]) + swfoutput_drawchar(&output, x1, y1, enc[c], c); + else { + logf(" couldn't get name for character %02x from Encoding", c); + } } } @@ -603,6 +684,23 @@ void SWFOutputDev::endString(GfxState *state) logf(" endstring\n"); } + +GBool SWFOutputDev::beginType3Char(GfxState *state, + CharCode code, Unicode *u, int uLen) +{ + logf(" beginType3Char %d, %08x, %d", code, *u, uLen); + type3active = 1; + /* the character itself is going to be passed using + drawImageMask() */ + return gFalse; /* gTrue= is_in_cache? */ +} + +void SWFOutputDev::endType3Char(GfxState *state) +{ + type3active = 0; + logf(" endType3Char"); +} + void SWFOutputDev::startPage(int pageNum, GfxState *state) { double x1,y1,x2,y2; @@ -687,24 +785,27 @@ void SWFOutputDev::drawLink(Link *link, Catalog *catalog) LinkNamed*l = (LinkNamed*)action; GString*name = l->getName(); if(name) { - s = name->lowerCase()->getCString(); - named = name->getCString(); - if(strstr(s, "next") || strstr(s, "forward")) - { - page = currentpage + 1; - } - else if(strstr(s, "prev") || strstr(s, "back")) - { - page = currentpage - 1; - } - else if(strstr(s, "last") || strstr(s, "end")) - { - page = pages[pagepos-1]; //:) - } - else if(strstr(s, "first") || strstr(s, "top")) - { - page = 1; - } + s = name->lowerCase()->getCString(); + named = name->getCString(); + if(!strchr(s,':')) + { + if(strstr(s, "next") || strstr(s, "forward")) + { + page = currentpage + 1; + } + else if(strstr(s, "prev") || strstr(s, "back")) + { + page = currentpage - 1; + } + else if(strstr(s, "last") || strstr(s, "end")) + { + page = pages[pagepos-1]; //:) + } + else if(strstr(s, "first") || strstr(s, "top")) + { + page = 1; + } + } } } break; @@ -790,6 +891,7 @@ int SWFOutputDev::searchT1Font(char*name) int i; int mapid=-1; char*filename=0; + for(i=0;i Loading extra font %s from %s\n", FIXNULL(fontname), FIXNULL(T1_GetFontFileName(i))); } + if(fontname && !strcmp(name, fontname)) { - logf(" Extra font %s is being used.\n", fontname); + logf(" Extra font %d, \"%s\" is being used.\n", i, fontname); return i; } fontname = T1_GetFontFileName(i); @@ -827,7 +930,7 @@ int SWFOutputDev::searchT1Font(char*name) fontname = strrchr(fontname,'/')+1; if(strstr(fontname, name)) { - logf(" Extra font %s is being used.\n", fontname); + logf(" Extra font %d, \"%s\" is being used.\n", i, fontname); return i; } } @@ -841,6 +944,16 @@ void SWFOutputDev::updateLineWidth(GfxState *state) swfoutput_setlinewidth(&output, width); } +void SWFOutputDev::updateLineCap(GfxState *state) +{ + int c = state->getLineCap(); +} + +void SWFOutputDev::updateLineJoin(GfxState *state) +{ + int j = state->getLineJoin(); +} + void SWFOutputDev::updateFillColor(GfxState *state) { GfxRGB rgb; @@ -876,6 +989,7 @@ char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font) ret = font->getEmbeddedFontID(&embRef); if(!ret) { + logf(" Didn't get embedded font id"); /* not embedded- the caller should now search the font directories for this font */ return 0; @@ -902,15 +1016,38 @@ char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font) refObj.fetch(ref, &strObj); refObj.free(); strObj.streamReset(); - while ((c = strObj.streamGetChar()) != EOF) { - fputc(c, f); + int f4[4]; + char f4c[4]; + int t; + for(t=0;t<4;t++) { + f4[t] = strObj.streamGetChar(); + f4c[t] = (char)f4[t]; + if(f4[t] == EOF) + break; + } + if(t==4) { + if(!strncmp(f4c, "true", 4)) { + /* some weird TTF fonts don't start with 0,1,0,0 but with "true". + Change this on the fly */ + f4[0] = f4[2] = f4[3] = 0; + f4[1] = 1; + } + fputc(f4[0], f); + fputc(f4[1], f); + fputc(f4[2], f); + fputc(f4[3], f); + + while ((c = strObj.streamGetChar()) != EOF) { + fputc(c, f); + } } strObj.streamClose(); strObj.free(); } fclose(f); - if(font->getType() == fontTrueType) + if(font->getType() == fontTrueType || + font->getType() == fontCIDType2) { if(!ttfinfo) { logf(" File contains TrueType fonts"); @@ -920,7 +1057,13 @@ char*SWFOutputDev::writeEmbeddedFontToFile(XRef*ref, GfxFont*font) char*tmp; tmp = strdup(mktmpname((char*)name2)); sprintf(name2, "%s", tmp); - char*a[] = {"./ttf2pt1","-pttf","-b", tmpFileName, name2}; + char*a[] = {"./ttf2pt1", +#ifndef USE_FREETYPE + "-pttf", +#else + "-pft", +#endif + "-b", tmpFileName, name2}; logf(" Invoking ttf2pt1..."); ttf2pt1_main(5,a); unlink(tmpFileName); @@ -955,6 +1098,7 @@ char* SWFOutputDev::substituteFont(GfxFont*gfxFont, char* oldname) /* ------------------------------ V1 */ char*fontname = "Times-Roman"; + logf(" substituteFont(,%s)", FIXNULL(oldname)); this->t1id = searchT1Font(fontname); if(substitutepos>=sizeof(substitutesource)/sizeof(char*)) { logf(" Too many fonts in file."); @@ -1133,11 +1277,11 @@ void SWFOutputDev::updateFont(GfxState *state) Ref embRef; GBool embedded = gfxFont->getEmbeddedFontID(&embRef); if(embedded) { - if (!gfxFont->isCIDFont() && - (gfxFont->getType() == fontType1 || - gfxFont->getType() == fontType1C || - gfxFont->getType() == fontTrueType)) { - + if (gfxFont->getType() == fontType1 || + gfxFont->getType() == fontType1C || + gfxFont->getType() == fontTrueType || + gfxFont->getType() == fontCIDType2) + { fileName = writeEmbeddedFontToFile(xref, gfxFont); if(!fileName) { logf(" Couldn't write font to file"); @@ -1153,19 +1297,29 @@ void SWFOutputDev::updateFont(GfxState *state) } } else { - showFontError(gfxFont,0); - fontname = substituteFont(gfxFont, fontname); + /* in case the font is embedded, but has an + unsupported format, we just look through the + font directories */ + int newt1id = searchT1Font(fontname); + if(newt1id<0) { + showFontError(gfxFont,0); + fontname = substituteFont(gfxFont, fontname); + } else + this->t1id = newt1id; } } else { if(fontname) { int newt1id = searchT1Font(fontname); if(newt1id<0) { + showFontError(gfxFont,1); fontname = substituteFont(gfxFont, fontname); } else this->t1id = newt1id; } - else + else { + showFontError(gfxFont,1); fontname = substituteFont(gfxFont, fontname); + } } if(t1id<0) { @@ -1190,9 +1344,61 @@ void SWFOutputDev::updateFont(GfxState *state) int pic_xids[1024]; int pic_yids[1024]; int pic_ids[1024]; +int pic_width[1024]; +int pic_height[1024]; int picpos = 0; int pic_id = 0; +#define SQR(x) ((x)*(x)) + +unsigned char* antialize(unsigned char*data, int width, int height, int newwidth, int newheight, int palettesize) +{ + if((newwidth<2 || newheight<2) || + (width<=newwidth || height<=newheight)) + return 0; + unsigned char*newdata; + int x,y; + newdata= (unsigned char*)malloc(newwidth*newheight); + int t; + double fx = (double)(width)/newwidth; + double fy = (double)(height)/newheight; + double px = 0; + int blocksize = (int)(8192/(fx*fy)); + int r = 8192*256/palettesize; + for(x=0;xtransform(1, 1, &x4, &y4); if(!pbminfo && !(str->getKind()==strDCT)) { - logf(" file contains pbm pictures %s",mask?"(masked)":""); + if(!type3active) { + logf(" file contains pbm pictures %s",mask?"(masked)":""); + pbminfo = 1; + } if(mask) logf(" drawing %d by %d masked picture\n", width, height); - pbminfo = 1; } if(!jpeginfo && (str->getKind()==strDCT)) { logf(" file contains jpeg pictures"); @@ -1249,38 +1457,86 @@ void SWFOutputDev::drawGeneralImage(GfxState *state, Object *ref, Stream *str, int xid = 0; int yid = 0; int x,y; - int width2 = (width+3)&(~3); - unsigned char*pic = new unsigned char[width2*height]; + 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; + 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) for (x = 0; x < width; ++x) { imgStr->getPixel(buf); - // if(invert) buf[0]=255-buf[0]? + if(invert) + buf[0]=1-buf[0]; pic[width*y+x] = buf[0]; xid+=x*buf[0]+1; - yid+=y*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;tgetDocInfo(&info); - if (info.isDict()) { + if (info.isDict() && + (screenloglevel>=LOGLEVEL_NOTICE)) { printInfoString(info.getDict(), "Title", "Title: %s\n"); printInfoString(info.getDict(), "Subject", "Subject: %s\n"); printInfoString(info.getDict(), "Keywords", "Keywords: %s\n"); @@ -1490,24 +1751,23 @@ void pdfswf_init(char*filename, char*userPassword) printInfoString(info.getDict(), "Producer", "Producer: %s\n"); printInfoDate(info.getDict(), "CreationDate", "CreationDate: %s\n"); printInfoDate(info.getDict(), "ModDate", "ModDate: %s\n"); + printf("Pages: %d\n", doc->getNumPages()); + printf("Linearized: %s\n", doc->isLinearized() ? "yes" : "no"); + printf("Encrypted: "); + if (doc->isEncrypted()) { + printf("yes (print:%s copy:%s change:%s addNotes:%s)\n", + doc->okToPrint() ? "yes" : "no", + doc->okToCopy() ? "yes" : "no", + doc->okToChange() ? "yes" : "no", + doc->okToAddNotes() ? "yes" : "no"); + } else { + printf("no\n"); + } } info.free(); - // print page count - printf("Pages: %d\n", doc->getNumPages()); numpages = doc->getNumPages(); - - // print linearization info - printf("Linearized: %s\n", doc->isLinearized() ? "yes" : "no"); - - // print encryption info - printf("Encrypted: "); if (doc->isEncrypted()) { - printf("yes (print:%s copy:%s change:%s addNotes:%s)\n", - doc->okToPrint() ? "yes" : "no", - doc->okToCopy() ? "yes" : "no", - doc->okToChange() ? "yes" : "no", - doc->okToAddNotes() ? "yes" : "no"); /*ERROR: This pdf is encrypted, and disallows copying. Due to the DMCA, paragraph 1201, (2) A-C, circumventing a technological measure that efficively controls access to @@ -1520,16 +1780,52 @@ void pdfswf_init(char*filename, char*userPassword) } if(!doc->okToChange() || !doc->okToAddNotes()) swfoutput_setprotected(); - } - else { - printf("no\n"); } - output = new SWFOutputDev(); output->startDoc(doc->getXRef()); } +void pdfswf_setparameter(char*name, char*value) +{ + if(!strcmp(name, "drawonlyshapes")) { + drawonlyshapes = atoi(value); + } else if(!strcmp(name, "ignoredraworder")) { + ignoredraworder = atoi(value); + } else if(!strcmp(name, "linksopennewwindow")) { + opennewwindow = atoi(value); + } else if(!strcmp(name, "storeallcharacters")) { + storeallcharacters = atoi(value); + } else if(!strcmp(name, "enablezlib")) { + enablezlib = atoi(value); + } else if(!strcmp(name, "insertstop")) { + insertstoptag = atoi(value); + } else if(!strcmp(name, "flashversion")) { + flashversion = atoi(value); + } else if(!strcmp(name, "jpegquality")) { + int val = atoi(value); + if(val<0) val=0; + if(val>100) val=100; + jpegquality = val; + } else if(!strcmp(name, "outputfilename")) { + swffilename = value; + } else if(!strcmp(name, "caplinewidth")) { + caplinewidth = atof(value); + } else if(!strcmp(name, "splinequality")) { + int v = atoi(value); + v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel + if(v<1) v = 1; + splinemaxerror = v; + } else if(!strcmp(name, "fontquality")) { + int v = atoi(value); + v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel + if(v<1) v = 1; + fontsplinemaxerror = v; + } else { + fprintf(stderr, "unknown parameter: %s (=%s)\n", name, value); + } +} + void pdfswf_drawonlyshapes() { drawonlyshapes = 1; @@ -1567,6 +1863,16 @@ void pdfswf_setoutputfilename(char*_filename) swffilename = _filename; } +void pdfswf_insertstop() +{ + insertstoptag = 1; +} + +void pdfswf_setversion(int n) +{ + flashversion = n; +} + void pdfswf_convertpage(int page) { @@ -1598,7 +1904,6 @@ int pdfswf_numpages() { return doc->getNumPages(); } - int closed=0; void pdfswf_close() { @@ -1611,3 +1916,4 @@ void pdfswf_close() gMemReport(stderr); } +