X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=blobdiff_plain;f=pdf2swf%2Fswfoutput.cc;h=8a129bc719e8cd815f108e23c13170c006d43e81;hp=8636bba44eec9f8e50b312165d8210e9cb915526;hb=e38efb466240e266a9c0491c4be56b66af2429ee;hpb=fc554a43712b76d16b41ec77dd311b4a78b1ef6b diff --git a/pdf2swf/swfoutput.cc b/pdf2swf/swfoutput.cc index 8636bba..8a129bc 100644 --- a/pdf2swf/swfoutput.cc +++ b/pdf2swf/swfoutput.cc @@ -27,38 +27,62 @@ extern "C" { #include "../lib/log.h" #include "../lib/rfxswf.h" } +#define standardEncodingSize 335 +extern char *standardEncodingNames[standardEncodingSize]; + +int opennewwindow=0; +int ignoredraworder=0; +int drawonlyshapes=0; +int jpegquality=85; +int storeallcharacters=0; +int enablezlib=0; +int insertstoptag=0; +int flashversion=4; +static int flag_protected = 0; typedef unsigned char u8; typedef unsigned short int u16; typedef unsigned long int u32; static int fi; -static int flag_protected; +static char* filename = 0; static SWF swf; static TAG *tag; -static int shapeid = -1; -static int shapecount = 0; +static int currentswfid = 0; +static int depth = 1; +static int startdepth = 1; + static SHAPE* shape; +static int shapeid = -1; +static int textid = -1; + +static int drawmode = -1; +static char storefont = 0; static int fillstyleid; static int linestyleid; static int swflastx=0; static int swflasty=0; static int lastwasfill = 0; -static char* filename = 0; +static char fill = 0; static int sizex; static int sizey; -static char fill = 0; -static int depth = 1; -static int startdepth = 1; TAG* cliptags[128]; int clipshapes[128]; u32 clipdepths[128]; int clippos = 0; -void startshape(struct swfoutput* obj); +int CHARMIDX = 0; +int CHARMIDY = 0; + +char fillstylechanged = 0; + +static void startshape(struct swfoutput* obj); +static void starttext(struct swfoutput* obj); +static void endshape(); +static void endtext(); // matrix multiplication. changes p0 -void transform (plotxy*p0,struct swfmatrix*m) +static void transform (plotxy*p0,struct swfmatrix*m) { double x,y; x = m->m11*p0->x+m->m12*p0->y; @@ -68,31 +92,34 @@ void transform (plotxy*p0,struct swfmatrix*m) } // write a move-to command into the swf -void moveto(plotxy p0) +static int moveto(TAG*tag, plotxy p0) { int rx = (int)(p0.x*20); int ry = (int)(p0.y*20); - if(rx!=swflastx || ry!=swflasty) { - ShapeSetMove (tag, shape, rx,ry); + if(rx!=swflastx || ry!=swflasty || fillstylechanged) { + swf_ShapeSetMove (tag, shape, rx,ry); + fillstylechanged = 0; + swflastx=rx; + swflasty=ry; + return 1; } - swflastx=rx; - swflasty=ry; + return 0; } // write a line-to command into the swf -void lineto(plotxy p0) +static void lineto(TAG*tag, plotxy p0) { int rx = ((int)(p0.x*20)-swflastx); int ry = ((int)(p0.y*20)-swflasty); /* we can't skip this for rx=0,ry=0, those are plots */ - ShapeSetLine (tag, shape, rx,ry); + swf_ShapeSetLine (tag, shape, rx,ry); swflastx+=rx; swflasty+=ry; } // write a spline-to command into the swf -void splineto(plotxy control,plotxy end) +static void splineto(TAG*tag, plotxy control,plotxy end) { int cx = ((int)(control.x*20)-swflastx); int cy = ((int)(control.y*20)-swflasty); @@ -102,168 +129,722 @@ void splineto(plotxy control,plotxy end) int ey = ((int)(end.y*20)-swflasty); swflastx += ex; swflasty += ey; - ShapeSetCurve(tag, shape, cx,cy,ex,ey); + if(cx || cy || ex || ey) + swf_ShapeSetCurve(tag, shape, cx,cy,ex,ey); } /* write a line, given two points and the transformation matrix. */ -void line(plotxy p0, plotxy p1, struct swfmatrix*m) +static void line(TAG*tag, plotxy p0, plotxy p1, struct swfmatrix*m) { transform(&p0,m); transform(&p1,m); - moveto(p0); - lineto(p1); + moveto(tag, p0); + lineto(tag, p1); } /* write a cubic (!) spline. This involves calling the approximate() function out of spline.cc to convert it to a quadratic spline. */ -void spline(plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m) +static void spline(TAG*tag,plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m) { double d; - struct qspline q[16]; + struct qspline q[128]; int num; int t; transform(&p0,m); transform(&p1,m); transform(&p2,m); transform(&p3,m); - - num = approximate(p0,p1,p2,p3,q); + cspline c; + c.start = p3; + c.control1 = p2; + c.control2 = p1; + c.end = p0; + + if(storefont) { + /* fonts use a different approximation than shapes */ + num = cspline_approximate(&c, q, 10.0, APPROXIMATE_RECURSIVE_BINARY); + //num = cspline_approximate(&c, q, 10.0, APPROXIMATE_INFLECTION); + } else { + num = cspline_approximate(&c, q, 1.0, APPROXIMATE_RECURSIVE_BINARY); + } for(t=0;tid != ST_DEFINEFONT && + tag->id != ST_DEFINESHAPE && + tag->id != ST_DEFINESHAPE2 && + tag->id != ST_DEFINESHAPE3) + { + logf(" internal error: drawpath needs a shape tag, not %d\n",tag->id); + exit(1); + } double x=0,y=0; double lastx=0,lasty=0; + double firstx=0,firsty=0; + int init=1; while (outline) { - logf(" Pathtype:%s",outline->type == T1_PATHTYPE_MOVE?"MOVE": - (outline->type == T1_PATHTYPE_LINE?"LINE" - :"BEZIER")); - logf(" relative coordinates: %08x,%08x", outline->dest.x, outline->dest.y); - x += (outline->dest.x/(float)0xffff); - y += (outline->dest.y/(float)0xffff); - logf(" coordinates: %f,%f", x, y); - if(outline->type == T1_PATHTYPE_MOVE) - { - } - else if(outline->type == T1_PATHTYPE_LINE) - { - plotxy p0; - plotxy p1; - p0.x=lastx; - p0.y=lasty; - p1.x=x; - p1.y=y; - line(p0,p1,m); - } - else if(outline->type == T1_PATHTYPE_BEZIER) - { - plotxy p0; - plotxy p1; - plotxy p2; - plotxy p3; - T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline; - p0.x=x; - p0.y=y; - p1.x=o2->C.x/(float)0xffff+lastx; - p1.y=o2->C.y/(float)0xffff+lasty; - p2.x=o2->B.x/(float)0xffff+lastx; - p2.y=o2->B.y/(float)0xffff+lasty; - p3.x=lastx; - p3.y=lasty; - spline(p0,p1,p2,p3,m); - } - else { - logf(" drawpath: unknown outline type:%d\n", outline->type); - } - lastx=x; - lasty=y; - outline = outline->link; + x += (outline->dest.x/(float)0xffff); + y += (outline->dest.y/(float)0xffff); + if(outline->type == T1_PATHTYPE_MOVE) + { + if(((int)(lastx*20) != (int)(firstx*20) || + (int)(lasty*20) != (int)(firsty*20)) && + fill && !init) + { + plotxy p0; + plotxy p1; + p0.x=lastx; + p0.y=lasty; + p1.x=firstx; + p1.y=firsty; + if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y); + line(tag, p0, p1, m); + } + firstx=x; + firsty=y; + init = 0; + } + else if(outline->type == T1_PATHTYPE_LINE) + { + plotxy p0; + plotxy p1; + p0.x=lastx; + p0.y=lasty; + p1.x=x; + p1.y=y; + if(log) printf("line: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y); + line(tag, p0,p1,m); + } + else if(outline->type == T1_PATHTYPE_BEZIER) + { + plotxy p0; + plotxy p1; + plotxy p2; + plotxy p3; + T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline; + p0.x=x; + p0.y=y; + p1.x=o2->C.x/(float)0xffff+lastx; + p1.y=o2->C.y/(float)0xffff+lasty; + p2.x=o2->B.x/(float)0xffff+lastx; + p2.y=o2->B.y/(float)0xffff+lasty; + p3.x=lastx; + p3.y=lasty; + if(log) printf("spline: %f,%f -> %f,%f\n",p3.x,p3.y,p0.x,p0.y); + spline(tag,p0,p1,p2,p3,m); + } + else { + logf(" drawpath: unknown outline type:%d\n", outline->type); + } + lastx=x; + lasty=y; + outline = outline->link; + } + if(((int)(lastx*20) != (int)(firstx*20) || + (int)(lasty*20) != (int)(firsty*20)) && + fill) + { + plotxy p0; + plotxy p1; + p0.x=lastx; + p0.y=lasty; + p1.x=firstx; + p1.y=firsty; + if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y); + line(tag, p0, p1, m); } } -/* process a character. */ -void drawchar(struct swfoutput*obj, int t1fontindex, char character, swfmatrix*m) -{ - - /* */ - T1_OUTLINE*outline; - int width = T1_GetCharWidth(t1fontindex, character); - BBox bbox = T1_GetCharBBox(t1fontindex, character); - char*charname= T1_GetCharName(t1fontindex, character); - logf(" Font name is %s", T1_GetFontFileName(t1fontindex)); - logf(" char 0x%02x is named %s\n",character,charname); - logf(" bbox: %d %d %d %d\n",bbox.llx,bbox.lly,bbox.urx,bbox.ury); - if(!charname || charname[0] == '.') +static inline int colorcompare(RGBA*a,RGBA*b) +{ + + if(a->r!=b->r || + a->g!=b->g || + a->b!=b->b || + a->a!=b->a) { + return 0; + } + return 1; +} + +static const int CHARDATAMAX = 1024; +struct chardata { + int charid; + int fontid; + int x; + int y; + int size; + RGBA color; +} chardata[CHARDATAMAX]; +int chardatapos = 0; + +static void putcharacters(TAG*tag) +{ + int t; + SWFFONT font; + RGBA color; + color.r = chardata[0].color.r^255; + color.g = 0; + color.b = 0; + color.a = 0; + int lastfontid; + int lastx; + int lasty; + int lastsize; + int charids[128]; + int charadvance[128]; + int charstorepos; + int pass; + int glyphbits=1; //TODO: can this be zero? + int advancebits=1; + + if(tag->id != ST_DEFINETEXT && + tag->id != ST_DEFINETEXT2) { + logf(" internal error: putcharacters needs an text tag, not %d\n",tag->id); + exit(1); + } + if(!chardatapos) { + logf(" putcharacters called with zero characters"); + } + + for(pass = 0; pass < 2; pass++) { - /* for newline, we don't print an error. FIXME: We shouldn't get newlines here - in the first place - */ - if(character != '\n') { - logf(" Char to set is not defined!"); - logf(" - font file is %s\n", T1_GetFontFileName(t1fontindex)); - logf(" - char 0x%02x is named %s\n",character,charname); - } - return; + charstorepos = 0; + lastfontid = -1; + lastx = CHARMIDX; + lasty = CHARMIDY; + lastsize = -1; + + if(pass==1) + { + advancebits++; // add sign bit + swf_SetU8(tag, glyphbits); + swf_SetU8(tag, advancebits); + } + + for(t=0;t<=chardatapos;t++) + { + if(lastfontid != chardata[t].fontid || + lastx!=chardata[t].x || + lasty!=chardata[t].y || + !colorcompare(&color, &chardata[t].color) || + charstorepos==127 || + lastsize != chardata[t].size || + t == chardatapos) + { + if(charstorepos && pass==0) + { + int s; + for(s=0;s=(1<=(1<writeBit = 0; // Q&D + swf_SetBits(tag, 0, 1); // GLYPH Record + swf_SetBits(tag, charstorepos, 7); // number of glyphs + int s; + for(s=0;swriteBit = 0; // Q&D + swf_TextSetInfoRecord(tag, newfont, chardata[t].size, newcolor, newx,newy); + } + + lastfontid = chardata[t].fontid; + lastx = chardata[t].x; + lasty = chardata[t].y; + lastsize = chardata[t].size; + } + + if(t==chardatapos) + break; + + int advance; + int nextt = t==chardatapos-1?t:t+1; + int rel = chardata[nextt].x-chardata[t].x; + if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) { + advance = rel; + lastx=chardata[nextt].x; + } + else { + advance = 0; + lastx=chardata[t].x; + } + charids[charstorepos] = chardata[t].charid; + charadvance[charstorepos] = advance; + charstorepos ++; + } + } + chardatapos = 0; +} + +static void putcharacter(struct swfoutput*obj, int fontid, int charid, + int x,int y, int size) +{ + if(chardatapos == CHARDATAMAX) + { + endtext(); + starttext(obj); } - swfmatrix m2=*m; - m2.m11/=100; - m2.m21/=100; - m2.m12/=100; - m2.m22/=100; - outline = T1_GetCharOutline( t1fontindex, character, 100.0, 0); + chardata[chardatapos].fontid = fontid; + chardata[chardatapos].charid = charid; + chardata[chardatapos].x = x; + chardata[chardatapos].y = y; + chardata[chardatapos].color = obj->fillrgb; + chardata[chardatapos].size = size; + chardatapos++; +} - /** **/ - if(shapeid<0) - startshape(obj); +/* process a character. */ +static void drawchar(struct swfoutput*obj, SWFFont*font, char*character, int charnr, swfmatrix*m) +{ + int usefonts=1; + if(m->m12!=0 || m->m21!=0) + usefonts=0; + if(m->m11 != m->m22) + usefonts=0; - if(!lastwasfill) - ShapeSetStyle(tag,shape,0x8000,fillstyleid,0); - lastwasfill = 1; + if(usefonts && ! drawonlyshapes) + { + int charid = font->getSWFCharID(character, charnr); + if(shapeid>=0) + endshape(); + if(textid<0) + starttext(obj); + putcharacter(obj, font->swfid, charid,(int)(m->m13*20),(int)(m->m23*20), + (int)(m->m11*20/2+0.5)); //where does the /2 come from? + } + else + { + T1_OUTLINE*outline = font->getOutline(character, charnr); + char* charname = character; + + if(!outline) { + logf(" Didn't find %s in current charset (%s)", + FIXNULL(character),FIXNULL(font->getName())); + return; + } + + swfmatrix m2=*m; + m2.m11/=100; + m2.m21/=100; + m2.m12/=100; + m2.m22/=100; + + if(textid>=0) + endtext(); + if(shapeid<0) + startshape(obj); + + if(!lastwasfill) { + swf_ShapeSetStyle(tag,shape,0x8000,fillstyleid,0); + fillstylechanged = 1; + } + lastwasfill = 1; - drawpath(outline, &m2, charname); + int lf = fill; + fill = 1; + drawpath(tag, outline, &m2, 0); + fill = lf; + } } /* draw a curved polygon. */ -void swfoutput_drawpath(swfoutput*output, T1_OUTLINE*outline, struct swfmatrix*m) +void swfoutput_drawpath(swfoutput*output, T1_OUTLINE*outline, + struct swfmatrix*m) { + if(textid>=0) + endtext(); + + /* Multiple polygons in one shape don't overlap correctly, + so we better start a new shape here if the polygon is filled + */ + if(shapeid>=0 && fill && !ignoredraworder) { + endshape(); + } + if(shapeid<0) - startshape(output); + startshape(output); if(lastwasfill && !fill) { - ShapeSetStyle(tag,shape,linestyleid,0x8000,0); + swf_ShapeSetStyle(tag,shape,linestyleid,0x8000,0); + fillstylechanged = 1; lastwasfill = 0; } if(!lastwasfill && fill) { - ShapeSetStyle(tag,shape,0x8000,fillstyleid,0); + swf_ShapeSetStyle(tag,shape,0x8000,fillstyleid,0); + fillstylechanged = 1; lastwasfill = 1; } - drawpath(outline,m, 0); + drawpath(tag, outline,m, 0); +} + +/* SWFFont: copy all t1 font outlines to a local + array. */ +SWFFont::SWFFont(char*name, int id, char*filename) +{ + if(!T1_GetFontName(id)) + T1_LoadFont(id); + + this->name = strdup(T1_GetFontFileName(id)); + this->fontid = strdup(name); + this->t1id = id; + + char**a= T1_GetAllCharNames(id); + int t, outlinepos=0; + char*map[256]; + + t=0; + while(a[t]) + t++; + this->charnum = t; + + if(!charnum) + return; + logf(" Font %s(%d): Storing %d outlines.\n", FIXNULL(name), id, charnum); + + this->standardtablesize = 256; + if(this->charnum < this->standardtablesize) + this->standardtablesize = this->charnum; + this->standardtable = (char**)malloc(standardtablesize*sizeof(char*)); + + for(t = 0; t < this->standardtablesize; t++) { + char*name = T1_GetCharName(id,t); + if(!name) + name = ""; + standardtable[t] = strdup(name); + } + + outline = (T1_OUTLINE**)malloc(charnum*sizeof(T1_OUTLINE*)); + charname = (char**)malloc(charnum*sizeof(char*)); + width = (int*)malloc(charnum*sizeof(int)); + memset(width, 0, charnum*sizeof(int)); + memset(charname, 0, charnum*sizeof(char*)); + used = (char*)malloc(charnum*sizeof(char)); + char2swfcharid = (U16*)malloc(charnum*2); + swfcharid2char = (U16*)malloc(charnum*2); + swfcharpos = 0; + + memset(used,0,charnum*sizeof(char)); + + this->swfid = ++currentswfid; + + t=0; + while(*a) + { + map[t] = *a; + a++; + t++; + if(t==256 || !*a) { + int s; + for(s=t;s<256;s++) + map[s] = ".notdef"; + + int ret = T1_ReencodeFont(id, map); + if(ret) { + T1_DeleteFont(id); + T1_LoadFont(id); + int ret = T1_ReencodeFont(id, map); + if(ret) + fprintf(stderr,"Can't reencode font: (%s) ret:%d\n",filename, ret); + } + + // parsecharacters + for(s=0;soutline[outlinepos] = T1_CopyOutline(T1_GetCharOutline(id, s, 100.0, 0)); + this->width[outlinepos] = T1_GetCharWidth(id, s); + this->charname[outlinepos] = strdup(name); + outlinepos++; + } + t=0; + } + } +} + +/* free all tables, write out definefont tags */ +SWFFont::~SWFFont() +{ + int t,usednum=0; + int*ptr; + + if(storeallcharacters) + { + int t; + for(t=0;tcharnum;t++) + { + if(this->charname[t]) + getSWFCharID(this->charname[t], -1); + } + } + + ptr = (int*)malloc(swfcharpos*sizeof(int)); + + for(t=0;t Font %s has %d used characters",FIXNULL(fontid), usednum); + TAG*ftag = swf_InsertTag(swf.firstTag,ST_DEFINEFONT); + swf_SetU16(ftag, this->swfid); + int initpos = swf_GetTagLen(ftag); + swfmatrix m; + m.m11 = m.m22 = 1; + m.m21 = m.m12 = 0; + m.m13 = CHARMIDX; + m.m23 = CHARMIDY; + + for(t=0;tdata[ptr[t]] = + SWAP16(swf_GetTagLen(ftag)-initpos); + + swflastx=0; + swflasty=0; + swf_SetU8(ftag,0x10); //1 fill bits, 0 linestyle bits + SHAPE s; + s.bits.fill = 1; + s.bits.line = 0; + swf_ShapeSetStyle(ftag,&s,0,1,0); + fillstylechanged = 1; + int lastfill = fill; + fill = 1; + storefont = 1; + drawpath(ftag, outline[swfcharid2char[t]],&m, 0); + storefont = 0; + fill = lastfill; + swf_ShapeSetEnd(ftag); + } + ftag = swf_InsertTag(ftag,ST_DEFINEFONTINFO); + swf_SetU16(ftag, this->swfid); + if(this->fontid) { + swf_SetU8(ftag, strlen(this->fontid)); + swf_SetBlock(ftag, (U8*)this->fontid, strlen(this->fontid)); + } else { + swf_SetU8(ftag, 0); + } + swf_SetU8(ftag, 0); //flags + for(t=0;tcharname[this->swfcharid2char[t]]; + for(s=0;s<256;s++) { + if(standardEncodingNames[s] && + !strcmp(name,standardEncodingNames[s])) + break; + } + swf_SetU8(ftag, (U8)s); + } + } + + free(ptr); + free(outline); + for(t=0;tcharnum;t++) { + if(!strcmp(this->charname[t],name)) { + return outline[t]; + } + } + + /* if we didn't find the character, maybe + we can find the capitalized version */ + for(t=0;tcharnum;t++) { + if(!strcasecmp(this->charname[t],name)) + return outline[t]; + } + + /* if we didn't find it by name, use the names of the first 256 characters + of the font to try a new name based on charnr */ + if(this->standardtable && charnr>=0 && charnr < this->standardtablesize) { + return getOutline(this->standardtable[charnr], -1); + } + + logf(" Didn't find character '%s' in font '%s'", FIXNULL(name), this->name); + return 0; } +int SWFFont::getSWFCharID(char*name, int charnr) +{ + int t; + for(t=0;tcharnum;t++) { + if(!strcmp(this->charname[t],name)) { + if(!used[t]) + { + swfcharid2char[swfcharpos] = t; + char2swfcharid[t] = swfcharpos++; + used[t] = 1; + } + return char2swfcharid[t]; + } + } + + /* if we didn't find the character, maybe + we can find the capitalized version */ + for(t=0;tcharnum;t++) { + if(!strcasecmp(this->charname[t],name)) { + if(!used[t]) + { + swfcharid2char[swfcharpos] = t; + char2swfcharid[t] = swfcharpos++; + used[t] = 1; + } + return char2swfcharid[t]; + } + } + + /* if we didn't find it by name, use the names of the first 256 (or so) characters + of the font to try a new name based on charnr */ + if(this->standardtable && charnr>=0 && charnr < this->standardtablesize) { + return getSWFCharID(this->standardtable[charnr], -1); + } + logf(" Didn't find character '%s' in font '%s'", FIXNULL(name), this->name); + return 0; +} + +int SWFFont::getWidth(char*name) +{ + int t; + for(t=0;tcharnum;t++) { + if(!strcmp(this->charname[t],name)) { + return this->width[t]; + } + } + return 0; +} + +char*SWFFont::getName() +{ + return this->name; +} + +struct fontlist_t +{ + SWFFont * font; + fontlist_t*next; +} *fontlist = 0; /* set's the t1 font index of the font to use for swfoutput_drawchar(). */ -int swfoutput_setfont(struct swfoutput*obj, int t1id) +void swfoutput_setfont(struct swfoutput*obj, char*fontid, int t1id, char*filename) +{ + fontlist_t*last=0,*iterator; + if(obj->font && !strcmp(obj->font->fontid,fontid)) + return; + + iterator = fontlist; + while(iterator) { + if(!strcmp(iterator->font->fontid,fontid)) + break; + last = iterator; + iterator = iterator->next; + } + if(iterator) + { + obj->font = iterator->font; + return ; + } + + if(t1id<0) { + logf(" internal error: t1id:%d, fontid:%s\n", t1id,FIXNULL(fontid)); + } + + SWFFont*font = new SWFFont(fontid, t1id, filename); + iterator = new fontlist_t; + iterator->font = font; + iterator->next = 0; + + if(last) + last->next = iterator; + else + fontlist = iterator; + obj->font = font; +} + +int swfoutput_queryfont(struct swfoutput*obj, char*fontid) { - obj->t1font = t1id; + fontlist_t *iterator = fontlist; + while(iterator) { + if(!strcmp(iterator->font->fontid,fontid)) + return 1; + iterator = iterator->next; + } + return 0; } /* set's the matrix which is to be applied to characters drawn by @@ -271,6 +852,13 @@ int swfoutput_setfont(struct swfoutput*obj, int t1id) void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12, double m21,double m22) { + if(obj->fontm11 == m11 && + obj->fontm12 == m12 && + obj->fontm21 == m21 && + obj->fontm22 == m22) + return; +// if(textid>=0) +// endtext(); obj->fontm11 = m11; obj->fontm12 = m12; obj->fontm21 = m21; @@ -278,7 +866,7 @@ void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12, } /* draws a character at x,y. */ -void swfoutput_drawchar(struct swfoutput* obj,double x,double y,char character) +void swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr) { swfmatrix m; m.m11 = obj->fontm11; @@ -287,7 +875,7 @@ void swfoutput_drawchar(struct swfoutput* obj,double x,double y,char character) m.m22 = obj->fontm22; m.m13 = x; m.m23 = y; - drawchar(obj, obj->t1font, character, &m); + drawchar(obj, obj->font, character, charnr, &m); } /* initialize the swf writer */ @@ -303,24 +891,23 @@ void swfoutput_init(struct swfoutput* obj, char*_filename, int _sizex, int _size logf(" initializing swf output for size %d*%d\n", sizex,sizey); - obj->t1font = 0; + obj->font = 0; memset(&swf,0x00,sizeof(SWF)); - swf.FileVersion = 4; -// swf.FrameRate = 0x1900; - swf.FrameRate = 0x0040; // 1 frame per 4 seconds - swf.MovieSize.xmax = 20*sizex; - swf.MovieSize.ymax = 20*sizey; + swf.fileVersion = flashversion; + swf.frameRate = 0x0040; // 1 frame per 4 seconds + swf.movieSize.xmax = 20*sizex; + swf.movieSize.ymax = 20*sizey; - swf.FirstTag = InsertTag(NULL,ST_SETBACKGROUNDCOLOR); - tag = swf.FirstTag; + swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR); + tag = swf.firstTag; rgb.r = 0xff; rgb.g = 0xff; rgb.b = 0xff; - SetRGB(tag,&rgb); - if(flag_protected) - tag = InsertTag(tag, ST_PROTECT); + swf_SetRGB(tag,&rgb); + if(flag_protected) // good practice! /r + tag = swf_InsertTag(tag, ST_PROTECT); depth = 1; startdepth = depth; } @@ -330,55 +917,108 @@ void swfoutput_setprotected() //write PROTECT tag flag_protected = 1; } -void startshape(struct swfoutput*obj) +static void startshape(struct swfoutput*obj) { RGBA rgb; SRECT r; - tag = InsertTag(tag,ST_DEFINESHAPE); - NewShape(&shape); - linestyleid = ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb); + if(textid>=0) + endtext(); + + tag = swf_InsertTag(tag,ST_DEFINESHAPE); + + swf_ShapeNew(&shape); + linestyleid = swf_ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb); rgb.r = obj->fillrgb.r; rgb.g = obj->fillrgb.g; rgb.b = obj->fillrgb.b; - fillstyleid = ShapeAddSolidFillStyle(shape,&obj->fillrgb); + fillstyleid = swf_ShapeAddSolidFillStyle(shape,&obj->fillrgb); - shapeid = ++shapecount; - SetU16(tag,shapeid); // ID + shapeid = ++currentswfid; + swf_SetU16(tag,shapeid); // ID r.xmin = 0; r.ymin = 0; r.xmax = 20*sizex; r.ymax = 20*sizey; - SetRect(tag,&r); + swf_SetRect(tag,&r); - SetShapeStyles(tag,shape); - ShapeCountBits(shape,NULL,NULL); - SetShapeBits(tag,shape); + swf_SetShapeStyles(tag,shape); + swf_ShapeCountBits(shape,NULL,NULL); + swf_SetShapeBits(tag,shape); - ShapeSetAll(tag,shape,/*x*/0,/*y*/0,linestyleid,0,0); + swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,linestyleid,0,0); swflastx=swflasty=0; lastwasfill = 0; } -void endshape() +static void starttext(struct swfoutput*obj) +{ + SRECT r; + MATRIX m; + if(shapeid>=0) + endshape(); + tag = swf_InsertTag(tag,ST_DEFINETEXT); + textid = ++currentswfid; + swf_SetU16(tag, textid); + + r.xmin = 0; + r.ymin = 0; + r.xmax = 20*sizex; + r.ymax = 20*sizey; + + swf_SetRect(tag,&r); + + m.sx = 65536; + m.sy = 65536; + m.r0 = 0; + m.r1 = 0; + m.tx = 0; + m.ty = 0; + + swf_SetMatrix(tag,&m); + swflastx=swflasty=0; +} + +static void endshape() { if(shapeid<0) - return; - ShapeSetEnd(tag); - tag = InsertTag(tag,ST_PLACEOBJECT2); - ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL); + return; + swf_ShapeSetEnd(tag); + tag = swf_InsertTag(tag,ST_PLACEOBJECT2); + swf_ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL); shapeid = -1; } -void endpage(struct swfoutput*obj) +static void endtext() +{ + if(textid<0) + return; + putcharacters(tag); + swf_SetU8(tag,0); + tag = swf_InsertTag(tag,ST_PLACEOBJECT2); + swf_ObjectPlace(tag,textid,/*depth*/depth++,NULL,NULL,NULL); + textid = -1; +} + +static void endpage(struct swfoutput*obj) { if(shapeid>=0) endshape(); + if(textid>=0) + endtext(); while(clippos) - swfoutput_endclip(obj); - tag = InsertTag(tag,ST_SHOWFRAME); + swfoutput_endclip(obj); + + if(insertstoptag) { + ActionTAG*atag=0; + atag = action_Stop(atag); + atag = action_End(atag); + tag = swf_InsertTag(tag,ST_DOACTION); + swf_ActionSet(tag,atag); + } + tag = swf_InsertTag(tag,ST_SHOWFRAME); } void swfoutput_newpage(struct swfoutput*obj) @@ -386,8 +1026,8 @@ void swfoutput_newpage(struct swfoutput*obj) endpage(obj); for(depth--;depth>=startdepth;depth--) { - tag = InsertTag(tag,ST_REMOVEOBJECT2); - SetU16(tag,depth); + tag = swf_InsertTag(tag,ST_REMOVEOBJECT2); + swf_SetU16(tag,depth); } depth = 1; @@ -399,31 +1039,46 @@ void swfoutput_newpage(struct swfoutput*obj) void swfoutput_destroy(struct swfoutput* obj) { endpage(obj); + fontlist_t *tmp,*iterator = fontlist; + while(iterator) { + delete iterator->font; + iterator->font = 0; + tmp = iterator; + iterator = iterator->next; + delete tmp; + } T1_CloseLib(); if(!filename) - return; + return; if(filename) - fi = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0777); + fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777); else fi = 1; // stdout if(fi<=0) { - logf(" Could not create \"%s\". ", filename); + logf(" Could not create \"%s\". ", FIXNULL(filename)); exit(1); } - tag = InsertTag(tag,ST_END); + tag = swf_InsertTag(tag,ST_END); + + if(enablezlib) { + if FAILED(swf_WriteSWC(fi,&swf)) + logf(" WriteSWC() failed.\n"); + } else { + if FAILED(swf_WriteSWF(fi,&swf)) + logf(" WriteSWF() failed.\n"); + } - if FAILED(WriteSWF(fi,&swf)) - logf(" WriteSWF() failed.\n"); if(filename) close(fi); - printf("SWF written\n"); + logf(" SWF written\n"); } void swfoutput_setdrawmode(swfoutput* obj, int mode) { + drawmode = mode; if(mode == DRAWMODE_FILL) fill = 1; else if(mode == DRAWMODE_EOFILL) @@ -438,8 +1093,13 @@ void swfoutput_setdrawmode(swfoutput* obj, int mode) void swfoutput_setfillcolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a) { - if(shape>=0) + if(obj->fillrgb.r == r && + obj->fillrgb.g == g && + obj->fillrgb.b == b && + obj->fillrgb.a == a) return; + if(shapeid>=0) endshape(); + obj->fillrgb.r = r; obj->fillrgb.g = g; obj->fillrgb.b = b; @@ -448,7 +1108,12 @@ void swfoutput_setfillcolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a) void swfoutput_setstrokecolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a) { - if(shape>=0) + if(obj->strokergb.r == r && + obj->strokergb.g == g && + obj->strokergb.b == b && + obj->strokergb.a == a) return; + + if(shapeid>=0) endshape(); obj->strokergb.r = r; obj->strokergb.g = g; @@ -458,7 +1123,10 @@ void swfoutput_setstrokecolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a) void swfoutput_setlinewidth(struct swfoutput*obj, double linewidth) { - if(shape>=0) + if(obj->linewidth == (u16)(linewidth*20)) + return; + + if(shapeid>=0) endshape(); obj->linewidth = (u16)(linewidth*20); } @@ -466,22 +1134,25 @@ void swfoutput_setlinewidth(struct swfoutput*obj, double linewidth) void swfoutput_startclip(swfoutput*obj, T1_OUTLINE*outline, struct swfmatrix*m) { - if(shape>=0) + if(textid>=0) + endtext(); + if(shapeid>=0) endshape(); if(clippos >= 127) { - logf(" Too many clip levels."); - clippos --; + logf(" Too many clip levels."); + clippos --; } - + startshape(obj); - + int olddrawmode = drawmode; swfoutput_setdrawmode(obj, DRAWMODE_CLIP); swfoutput_drawpath(obj, outline, m); + swf_ShapeSetEnd(tag); + swfoutput_setdrawmode(obj, olddrawmode); - ShapeSetEnd(tag); - tag = InsertTag(tag,ST_PLACEOBJECT2); + tag = swf_InsertTag(tag,ST_PLACEOBJECT2); cliptags[clippos] = tag; clipshapes[clippos] = shapeid; clipdepths[clippos] = depth++; @@ -491,28 +1162,257 @@ void swfoutput_startclip(swfoutput*obj, T1_OUTLINE*outline, struct swfmatrix*m) void swfoutput_endclip(swfoutput*obj) { - if(shape>=0) + if(textid>=0) + endtext(); + if(shapeid>=0) endshape(); if(!clippos) { - logf(" Invalid end of clipping region"); - return; + logf(" Invalid end of clipping region"); + return; } clippos--; - PlaceObject(cliptags[clippos],clipshapes[clippos],clipdepths[clippos],NULL,NULL,NULL,depth++); + swf_ObjectPlaceClip(cliptags[clippos],clipshapes[clippos],clipdepths[clippos],NULL,NULL,NULL,depth++); +} + +static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover); + +void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points) +{ + ActionTAG* actions; + if(!strncmp("http://pdf2swf:", url, 15)) { + char*tmp = strdup(url); + int l = strlen(tmp); + if(tmp[l-1] == '/') + tmp[l-1] = 0; + swfoutput_namedlink(obj, tmp+15, points); + free(tmp); + return; + } + + if(shapeid>=0) + endshape(); + if(textid>=0) + endtext(); + + if(opennewwindow) + actions = action_GetUrl(0, url, "_parent"); + else + actions = action_GetUrl(0, url, "_this"); + actions = action_End(actions); + + drawlink(obj, actions, 0, points,0); +} +void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points) +{ + ActionTAG* actions; + + if(shapeid>=0) + endshape(); + if(textid>=0) + endtext(); + + actions = action_GotoFrame(0, page); + actions = action_End(actions); + + drawlink(obj, actions, 0, points,0); +} + +/* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets + of the viewer objects, like subtitles, index elements etc. +*/ +void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points) +{ + ActionTAG *actions1,*actions2; + char*tmp = strdup(name); + char mouseover = 1; + + if(shapeid>=0) + endshape(); + if(textid>=0) + endtext(); + + if(!strncmp(tmp, "call:", 5)) + { + char*x = strchr(&tmp[5], ':'); + if(!x) { + actions1 = action_PushInt(0, 0); //number of parameters (0) + actions1 = action_PushString(actions1, &tmp[5]); //function name + actions1 = action_CallFunction(actions1); + } else { + *x = 0; + actions1 = action_PushString(0, x+1); //parameter + actions1 = action_PushInt(actions1, 1); //number of parameters (1) + actions1 = action_PushString(actions1, &tmp[5]); //function name + actions1 = action_CallFunction(actions1); + } + actions2 = action_End(0); + mouseover = 0; + } + else + { + actions1 = action_PushString(0, "/:subtitle"); + actions1 = action_PushString(actions1, name); + actions1 = action_SetVariable(actions1); + actions1 = action_End(actions1); + + actions2 = action_PushString(0, "/:subtitle"); + actions2 = action_PushString(actions2, ""); + actions2 = action_SetVariable(actions2); + actions2 = action_End(actions2); + } + + drawlink(obj, actions1, actions2, points,mouseover); + + swf_ActionFree(actions1); + swf_ActionFree(actions2); + free(tmp); +} + +static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover) +{ + RGBA rgb; + SRECT r; + int lsid=0; + int fsid; + struct plotxy p1,p2,p3,p4; + int myshapeid; + int myshapeid2; + double xmin,ymin; + double xmax=xmin=points[0].x,ymax=ymin=points[0].y; + double posx = 0; + double posy = 0; + int t; + int buttonid = ++currentswfid; + for(t=1;t<4;t++) + { + if(points[t].x>xmax) xmax=points[t].x; + if(points[t].y>ymax) ymax=points[t].y; + if(points[t].xymax) ymax=y4; if(x4=0) - endshape(); + m.sx = (int)(65536*20*(p4.x-p1.x)/sizex); + m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex); + m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey); + m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey); - bitid = ++shapecount; + m.tx = (int)(p1.x*20); + m.ty = (int)(p1.y*20); - /* bitmap */ - tag = InsertTag(tag,ST_DEFINEBITSJPEG2); - SetU16(tag, bitid); - SetJPEGBits(tag, filename, 85); - /* shape */ - myshapeid = ++shapecount; - tag = InsertTag(tag,ST_DEFINESHAPE); - NewShape(&shape); + myshapeid = ++currentswfid; + tag = swf_InsertTag(tag,ST_DEFINESHAPE); + swf_ShapeNew(&shape); //lsid = ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb); //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb); - fsid = ShapeAddBitmapFillStyle(shape,&m,bitid,0); - SetU16(tag, myshapeid); + fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1); + swf_SetU16(tag, myshapeid); r.xmin = (int)(xmin*20); r.ymin = (int)(ymin*20); r.xmax = (int)(xmax*20); r.ymax = (int)(ymax*20); - SetRect(tag,&r); - SetShapeStyles(tag,shape); - ShapeCountBits(shape,NULL,NULL); - SetShapeBits(tag,shape); - ShapeSetAll(tag,shape,/*x*/0,/*y*/0,lsid,fsid,0); + swf_SetRect(tag,&r); + swf_SetShapeStyles(tag,shape); + swf_ShapeCountBits(shape,NULL,NULL); + swf_SetShapeBits(tag,shape); + swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,lsid,fsid,0); swflastx = swflasty = 0; - moveto(p1); - lineto(p2); - lineto(p3); - lineto(p4); - lineto(p1); + moveto(tag, p1); + lineto(tag, p2); + lineto(tag, p3); + lineto(tag, p4); + lineto(tag, p1); /* ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20)); ShapeSetLine (tag, shape, (int)(x1*20); ShapeSetLine (tag, shape, x*20,0); ShapeSetLine (tag, shape, 0,-y*20); ShapeSetLine (tag, shape, -x*20,0);*/ - ShapeSetEnd(tag); + swf_ShapeSetEnd(tag); /* instance */ - tag = InsertTag(tag,ST_PLACEOBJECT2); - ObjectPlace(tag,myshapeid,/*depth*/depth++,NULL,NULL,NULL); + tag = swf_InsertTag(tag,ST_PLACEOBJECT2); + swf_ObjectPlace(tag,myshapeid,/*depth*/depth++,NULL,NULL,NULL); +} + +int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey, + double x1,double y1, + double x2,double y2, + double x3,double y3, + double x4,double y4) +{ + TAG*oldtag; + if(shapeid>=0) + endshape(); + if(textid>=0) + endtext(); + + int bitid = ++currentswfid; + oldtag = tag; + tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2); + swf_SetU16(tag, bitid); + if(swf_SetJPEGBits(tag, filename, jpegquality)<0) { + swf_DeleteTag(tag); + tag = oldtag; + return -1; + } + + drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4); + return bitid; +} + +int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey, + double x1,double y1, + double x2,double y2, + double x3,double y3, + double x4,double y4) +{ + TAG*oldtag; + JPEGBITS*jpeg; + + if(shapeid>=0) + endshape(); + if(textid>=0) + endtext(); + + int bitid = ++currentswfid; + oldtag = tag; + tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2); + swf_SetU16(tag, bitid); + swf_SetJPEGBits2(tag,sizex,sizey,mem,jpegquality); + drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4); + return bitid; +} + +int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey, + double x1,double y1, + double x2,double y2, + double x3,double y3, + double x4,double y4) +{ + TAG*oldtag; + if(shapeid>=0) + endshape(); + if(textid>=0) + endtext(); + + int bitid = ++currentswfid; + oldtag = tag; + tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS); + swf_SetU16(tag, bitid); + if(swf_SetLosslessBits(tag,sizex,sizey,mem, BMF_32BIT)<0) { + swf_DeleteTag(tag); + tag = oldtag; + return -1; + } + + drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4); + return bitid; +} + +int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey, + double x1,double y1, + double x2,double y2, + double x3,double y3, + double x4,double y4, int n) +{ + TAG*oldtag; + U8*mem2 = 0; + if(shapeid>=0) + endshape(); + if(textid>=0) + endtext(); + + if(sizex&3) + { + /* SWF expects scanlines to be 4 byte aligned */ + int x,y; + U8*ptr; + mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey); + ptr = mem2; + for(y=0;y=0) + endshape(); + if(textid>=0) + endtext(); + + drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4); }