2 Implements generation of swf files using the rfxswf lib. The routines
3 in this file are called from pdf2swf.
5 This file is part of swftools.
7 Swftools is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 Swftools is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with swftools; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
24 #include "swfoutput.h"
27 #include "../lib/log.h"
28 #include "../lib/rfxswf.h"
30 #define standardEncodingSize 335
31 extern char *standardEncodingNames[standardEncodingSize];
36 int ignoredraworder=0;
39 int storeallcharacters=0;
44 int fontsplinemaxerror=1;
45 static int flag_protected = 0;
47 typedef unsigned char u8;
48 typedef unsigned short int u16;
49 typedef unsigned long int u32;
52 static char* filename = 0;
55 static int currentswfid = 0;
57 static int startdepth = 1;
60 static int shapeid = -1;
61 static int textid = -1;
63 static int drawmode = -1;
64 static char storefont = 0;
65 static int fillstyleid;
66 static int linestyleid;
67 static int swflastx=0;
68 static int swflasty=0;
69 static int lastwasfill = 0;
81 char fillstylechanged = 0;
83 static void startshape(struct swfoutput* obj);
84 static void starttext(struct swfoutput* obj);
85 static void endshape();
86 static void endtext();
88 // matrix multiplication. changes p0
89 static void transform (plotxy*p0,struct swfmatrix*m)
92 x = m->m11*p0->x+m->m12*p0->y;
93 y = m->m21*p0->x+m->m22*p0->y;
98 // write a move-to command into the swf
99 static int moveto(TAG*tag, plotxy p0)
101 int rx = (int)(p0.x*20);
102 int ry = (int)(p0.y*20);
103 if(rx!=swflastx || ry!=swflasty || fillstylechanged) {
104 swf_ShapeSetMove (tag, shape, rx,ry);
105 fillstylechanged = 0;
113 // write a line-to command into the swf
114 static void lineto(TAG*tag, plotxy p0)
116 int rx = ((int)(p0.x*20)-swflastx);
117 int ry = ((int)(p0.y*20)-swflasty);
118 /* we can't skip this for rx=0,ry=0, those
120 swf_ShapeSetLine (tag, shape, rx,ry);
125 // write a spline-to command into the swf
126 static void splineto(TAG*tag, plotxy control,plotxy end)
128 int cx = ((int)(control.x*20)-swflastx);
129 int cy = ((int)(control.y*20)-swflasty);
132 int ex = ((int)(end.x*20)-swflastx);
133 int ey = ((int)(end.y*20)-swflasty);
136 if(cx || cy || ex || ey)
137 swf_ShapeSetCurve(tag, shape, cx,cy,ex,ey);
140 /* write a line, given two points and the transformation
142 static void line(TAG*tag, plotxy p0, plotxy p1, struct swfmatrix*m)
150 /* write a cubic (!) spline. This involves calling the approximate()
151 function out of spline.cc to convert it to a quadratic spline. */
152 static void spline(TAG*tag,plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m)
155 struct qspline q[128];
169 /* fonts use a different approximation than shapes */
170 num = cspline_approximate(&c, q, fontsplinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
171 //num = cspline_approximate(&c, q, 10.0, APPROXIMATE_INFLECTION);
173 num = cspline_approximate(&c, q, splinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
177 moveto(tag,q[t].start);
178 splineto(tag,q[t].control, q[t].end);
188 static void stopFill()
192 swf_ShapeSetStyle(tag,shape,linestyleid,0x8000,0);
193 fillstylechanged = 1;
197 static void startFill()
201 swf_ShapeSetStyle(tag,shape,0x8000,fillstyleid,0);
202 fillstylechanged = 1;
207 /* draw a T1 outline. These are generated by pdf2swf and by t1lib
208 (representing characters). */
209 void drawpath(TAG*tag, T1_OUTLINE*outline, struct swfmatrix*m, int log)
211 if(tag->id != ST_DEFINEFONT &&
212 tag->id != ST_DEFINESHAPE &&
213 tag->id != ST_DEFINESHAPE2 &&
214 tag->id != ST_DEFINESHAPE3)
216 logf("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
220 double lastx=0,lasty=0;
221 double firstx=0,firsty=0;
226 x += (outline->dest.x/(float)0xffff);
227 y += (outline->dest.y/(float)0xffff);
228 if(outline->type == T1_PATHTYPE_MOVE)
230 if(((int)(lastx*20) != (int)(firstx*20) ||
231 (int)(lasty*20) != (int)(firsty*20)) &&
240 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
241 line(tag, p0, p1, m);
247 else if(outline->type == T1_PATHTYPE_LINE)
255 if(log) printf("line: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
258 else if(outline->type == T1_PATHTYPE_BEZIER)
264 T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline;
267 p1.x=o2->C.x/(float)0xffff+lastx;
268 p1.y=o2->C.y/(float)0xffff+lasty;
269 p2.x=o2->B.x/(float)0xffff+lastx;
270 p2.y=o2->B.y/(float)0xffff+lasty;
273 if(log) printf("spline: %f,%f -> %f,%f\n",p3.x,p3.y,p0.x,p0.y);
274 spline(tag,p0,p1,p2,p3,m);
277 logf("<error> drawpath: unknown outline type:%d\n", outline->type);
281 outline = outline->link;
283 if(((int)(lastx*20) != (int)(firstx*20) ||
284 (int)(lasty*20) != (int)(firsty*20)) &&
293 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
294 line(tag, p0, p1, m);
298 plotxy getPivot(T1_OUTLINE*outline, int dir, double line_width, int end)
300 T1_PATHPOINT next, next2;
301 double xv=0,yv=0, xv2=0, yv2=0;
306 if(outline->type == T1_PATHTYPE_LINE) {
307 next = outline->dest;
309 next = ((T1_BEZIERSEGMENT*)outline)->B;
310 if(next.x==0 && next.y==0) {
311 next = ((T1_BEZIERSEGMENT*)outline)->C;
313 if(next.x==0 && next.y==0) {
314 next = ((T1_BEZIERSEGMENT*)outline)->dest;
318 if(outline->last && outline->last->type != T1_PATHTYPE_MOVE) {
319 if(outline->type == T1_PATHTYPE_LINE) {
320 next2 = outline->last->dest;
322 T1_PATHPOINT c = ((T1_BEZIERSEGMENT*)(outline->last))->C;
323 T1_PATHPOINT b = ((T1_BEZIERSEGMENT*)(outline->last))->B;
324 next2.x = outline->last->dest.x - c.x;
325 next2.y = outline->last->dest.y - c.y;
326 if(next2.x==0 && next2.y==0) {
327 next2.x = outline->last->dest.x - b.x;
328 next2.y = outline->last->dest.y - b.y;
330 if(next2.x==0 && next2.y==0) {
331 next2.x = outline->last->dest.x;
332 next2.y = outline->last->dest.y;
338 if(outline->type == T1_PATHTYPE_LINE) {
339 next = outline->dest;
341 T1_PATHPOINT c = ((T1_BEZIERSEGMENT*)outline)->C;
342 T1_PATHPOINT b = ((T1_BEZIERSEGMENT*)outline)->B;
343 next.x = outline->dest.x - c.x;
344 next.y = outline->dest.y - c.y;
345 if(next.x==0 && next.y==0) {
346 next.x = outline->dest.x - b.x;
347 next.y = outline->dest.y - b.y;
349 if(next.x==0 && next.y==0) {
350 next.x = outline->dest.x;
351 next.y = outline->dest.y;
355 if(outline->link && outline->link->type != T1_PATHTYPE_MOVE) {
356 if(outline->type == T1_PATHTYPE_LINE) {
357 next2 = outline->link->dest;
359 next2 = ((T1_BEZIERSEGMENT*)(outline->link))->B;
360 if(next2.x==0 && next2.y==0) {
361 next2 = ((T1_BEZIERSEGMENT*)outline->link)->C;
363 if(next2.x==0 && next2.y==0) {
364 next2 = ((T1_BEZIERSEGMENT*)outline->link)->dest;
372 xv = next.y/(float)0xffff;
373 yv = -next.x/(float)0xffff;
375 xv = -next.y/(float)0xffff;
376 yv = next.x/(float)0xffff;
379 double r = line_width/sqrt(xv*xv+yv*yv);
385 xv2 = next2.y/(float)0xffff;
386 yv2 = -next2.x/(float)0xffff;
388 xv2 = -next2.y/(float)0xffff;
389 yv2 = next2.x/(float)0xffff;
392 double r2 = line_width/sqrt(xv2*xv2+yv2*yv2);
397 double r3 = line_width/sqrt(xv*xv+yv*yv);
407 void drawShortPath(struct swfoutput*output, double x, double y, struct swfmatrix* m, T1_OUTLINE*outline, int num, int line_cap, int line_join, double line_width)
409 double lastx=x, lasty=y;
413 if(line_cap == LINE_CAP_BUTT || line_cap == LINE_CAP_SQUARE) {
416 T1_OUTLINE *last, *tmp=outline;
417 plotxy s,e,p0,p1,p2,p3,m0,m1,m2,m3;
422 while(tmp && tmp->type != T1_PATHTYPE_MOVE) {
424 lx += (tmp->dest.x/(float)0xffff);
425 ly += (tmp->dest.y/(float)0xffff);
428 s = getPivot(outline, 0, line_width, 0);
429 e = getPivot(last, 0, line_width, 1);
440 p2.x = x2 - s.y - s.x;
441 p2.y = y2 + s.x - s.y;
442 p3.x = x2 - s.y + s.x;
443 p3.y = y2 + s.x + s.y;
448 m2.x = lx + e.y - e.x;
449 m2.y = ly - e.x - e.y;
450 m3.x = lx + e.y + e.x;
451 m3.y = ly - e.x + e.y;
453 for(nr=0;nr<2;nr++) {
455 struct plotxy q0,q1,q2,q3,q4,q5;
457 if(line_cap == LINE_CAP_BUTT) {
460 q1.x = sizex; q1.y = 0;
461 q2.x = sizex; q2.y = sizey;
462 q3.x = 0; q3.y = sizey;
464 q0.x = sizex; q0.y = sizey;
465 q1.x = 0; q1.y = sizey;
467 q3.x = sizex; q3.y = 0;
481 line(tag, p0, p1, m);
482 line(tag, p1, p2, m);
483 line(tag, p2, p3, m);
484 line(tag, p3, p0, m);
486 if(line_cap == LINE_CAP_BUTT) {
488 swf_ShapeSetEnd(tag);
489 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
490 swf_ObjectPlaceClip(tag,shapeid,depth,NULL,NULL,NULL,depth+2-nr);
504 while (outline && outline->type != T1_PATHTYPE_MOVE)
506 x += (outline->dest.x/(float)0xffff);
507 y += (outline->dest.y/(float)0xffff);
509 if(outline->type == T1_PATHTYPE_LINE)
516 line(tag, p0, p1, m);
518 else if(outline->type == T1_PATHTYPE_BEZIER)
521 T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline;
524 p1.x=o2->C.x/(float)0xffff+lastx;
525 p1.y=o2->C.y/(float)0xffff+lasty;
526 p2.x=o2->B.x/(float)0xffff+lastx;
527 p2.y=o2->B.y/(float)0xffff+lasty;
530 spline(tag,p0,p1,p2,p3,m);
534 outline = outline->link;
536 if(line_cap == LINE_CAP_BUTT) {
541 void drawpath2poly(struct swfoutput *output, T1_OUTLINE*outline, struct swfmatrix*m, int log, int line_join, int line_cap, double line_width, double miter_limit)
543 if(tag->id != ST_DEFINEFONT &&
544 tag->id != ST_DEFINESHAPE &&
545 tag->id != ST_DEFINESHAPE2 &&
546 tag->id != ST_DEFINESHAPE3) {
547 logf("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
551 double lastx=0,lasty=0;
553 T1_OUTLINE*tmp = outline, *last = 0;
557 x += (tmp->dest.x/(float)0xffff);
558 y += (tmp->dest.y/(float)0xffff);
559 if(tmp->type == T1_PATHTYPE_MOVE) {
561 drawShortPath(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
573 tmp->link->last = tmp; // make sure list is properly linked in both directions
577 drawShortPath(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
581 static inline int colorcompare(RGBA*a,RGBA*b)
593 static const int CHARDATAMAX = 1024;
601 } chardata[CHARDATAMAX];
604 static void putcharacters(TAG*tag)
609 color.r = chardata[0].color.r^255;
618 int charadvance[128];
621 int glyphbits=1; //TODO: can this be zero?
624 if(tag->id != ST_DEFINETEXT &&
625 tag->id != ST_DEFINETEXT2) {
626 logf("<error> internal error: putcharacters needs an text tag, not %d\n",tag->id);
630 logf("<warning> putcharacters called with zero characters");
633 for(pass = 0; pass < 2; pass++)
643 advancebits++; // add sign bit
644 swf_SetU8(tag, glyphbits);
645 swf_SetU8(tag, advancebits);
648 for(t=0;t<=chardatapos;t++)
650 if(lastfontid != chardata[t].fontid ||
651 lastx!=chardata[t].x ||
652 lasty!=chardata[t].y ||
653 !colorcompare(&color, &chardata[t].color) ||
655 lastsize != chardata[t].size ||
658 if(charstorepos && pass==0)
661 for(s=0;s<charstorepos;s++)
663 while(charids[s]>=(1<<glyphbits))
665 while(charadvance[s]>=(1<<advancebits))
669 if(charstorepos && pass==1)
671 tag->writeBit = 0; // Q&D
672 swf_SetBits(tag, 0, 1); // GLYPH Record
673 swf_SetBits(tag, charstorepos, 7); // number of glyphs
675 for(s=0;s<charstorepos;s++)
677 swf_SetBits(tag, charids[s], glyphbits);
678 swf_SetBits(tag, charadvance[s], advancebits);
683 if(pass == 1 && t<chardatapos)
689 if(lastx != chardata[t].x ||
690 lasty != chardata[t].y)
695 if(!colorcompare(&color, &chardata[t].color))
697 color = chardata[t].color;
700 font.id = chardata[t].fontid;
701 if(lastfontid != chardata[t].fontid || lastsize != chardata[t].size)
704 tag->writeBit = 0; // Q&D
705 swf_TextSetInfoRecord(tag, newfont, chardata[t].size, newcolor, newx,newy);
708 lastfontid = chardata[t].fontid;
709 lastx = chardata[t].x;
710 lasty = chardata[t].y;
711 lastsize = chardata[t].size;
718 int nextt = t==chardatapos-1?t:t+1;
719 int rel = chardata[nextt].x-chardata[t].x;
720 if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) {
722 lastx=chardata[nextt].x;
728 charids[charstorepos] = chardata[t].charid;
729 charadvance[charstorepos] = advance;
736 static void putcharacter(struct swfoutput*obj, int fontid, int charid,
737 int x,int y, int size)
739 if(chardatapos == CHARDATAMAX)
744 chardata[chardatapos].fontid = fontid;
745 chardata[chardatapos].charid = charid;
746 chardata[chardatapos].x = x;
747 chardata[chardatapos].y = y;
748 chardata[chardatapos].color = obj->fillrgb;
749 chardata[chardatapos].size = size;
754 /* process a character. */
755 static void drawchar(struct swfoutput*obj, SWFFont*font, char*character, int charnr, swfmatrix*m)
758 if(m->m12!=0 || m->m21!=0)
763 if(usefonts && ! drawonlyshapes)
765 int charid = font->getSWFCharID(character, charnr);
770 putcharacter(obj, font->swfid, charid,(int)(m->m13*20),(int)(m->m23*20),
771 (int)(m->m11*20/2+0.5)); //where does the /2 come from?
775 T1_OUTLINE*outline = font->getOutline(character, charnr);
776 char* charname = character;
779 logf("<warning> Didn't find %s in current charset (%s)",
780 FIXNULL(character),FIXNULL(font->getName()));
799 drawpath(tag, outline, &m2, 0);
804 /* draw a curved polygon. */
805 void swfoutput_drawpath(swfoutput*output, T1_OUTLINE*outline,
811 /* Multiple polygons in one shape don't overlap correctly,
812 so we better start a new shape here if the polygon is filled
814 if(shapeid>=0 && fill && !ignoredraworder) {
826 drawpath(tag, outline,m, 0);
829 void swfoutput_drawpath2poly(struct swfoutput*output, T1_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
839 drawpath2poly(output, outline, m, 0, line_join, line_cap, line_width, miter_limit);
842 /* SWFFont: copy all t1 font outlines to a local
844 SWFFont::SWFFont(char*name, int id, char*filename)
846 if(!T1_GetFontName(id))
849 this->name = strdup(T1_GetFontFileName(id));
850 this->fontid = strdup(name);
853 char**a= T1_GetAllCharNames(id);
864 logf("<verbose> Font %s(%d): Storing %d outlines.\n", FIXNULL(name), id, charnum);
866 this->standardtablesize = 256;
867 if(this->charnum < this->standardtablesize)
868 this->standardtablesize = this->charnum;
869 this->standardtable = (char**)malloc(standardtablesize*sizeof(char*));
871 for(t = 0; t < this->standardtablesize; t++) {
872 char*name = T1_GetCharName(id,t);
875 standardtable[t] = strdup(name);
878 outline = (T1_OUTLINE**)malloc(charnum*sizeof(T1_OUTLINE*));
879 charname = (char**)malloc(charnum*sizeof(char*));
880 width = (int*)malloc(charnum*sizeof(int));
881 memset(width, 0, charnum*sizeof(int));
882 memset(charname, 0, charnum*sizeof(char*));
883 used = (char*)malloc(charnum*sizeof(char));
884 char2swfcharid = (U16*)malloc(charnum*2);
885 swfcharid2char = (U16*)malloc(charnum*2);
888 memset(used,0,charnum*sizeof(char));
890 this->swfid = ++currentswfid;
903 int ret = T1_ReencodeFont(id, map);
907 int ret = T1_ReencodeFont(id, map);
909 fprintf(stderr,"Can't reencode font: (%s) ret:%d\n",filename, ret);
915 char* name = T1_GetCharName(id, s);
917 this->outline[outlinepos] = T1_CopyOutline(T1_GetCharOutline(id, s, 100.0, 0));
918 this->width[outlinepos] = T1_GetCharWidth(id, s);
919 this->charname[outlinepos] = strdup(name);
927 /* free all tables, write out definefont tags */
933 if(storeallcharacters)
936 for(t=0;t<this->charnum;t++)
938 if(this->charname[t])
939 getSWFCharID(this->charname[t], -1);
943 ptr = (int*)malloc(swfcharpos*sizeof(int));
945 for(t=0;t<charnum;t++)
946 if(used[t]) usednum++;
948 if(usednum && !drawonlyshapes)
950 logf("<verbose> Font %s has %d used characters",FIXNULL(fontid), usednum);
951 TAG*ftag = swf_InsertTag(swf.firstTag,ST_DEFINEFONT);
952 swf_SetU16(ftag, this->swfid);
953 int initpos = swf_GetTagLen(ftag);
960 for(t=0;t<swfcharpos;t++)
962 ptr[t] = swf_GetTagLen(ftag);
963 swf_SetU16(ftag, 0x1234);
965 for(t=0;t<swfcharpos;t++)
967 *(U16*)&ftag->data[ptr[t]] =
968 SWAP16(swf_GetTagLen(ftag)-initpos);
972 swf_SetU8(ftag,0x10); //1 fill bits, 0 linestyle bits
976 swf_ShapeSetStyle(ftag,&s,0,1,0);
977 fillstylechanged = 1;
981 drawpath(ftag, outline[swfcharid2char[t]],&m, 0);
984 swf_ShapeSetEnd(ftag);
986 ftag = swf_InsertTag(ftag,ST_DEFINEFONTINFO);
987 swf_SetU16(ftag, this->swfid);
989 swf_SetU8(ftag, strlen(this->fontid));
990 swf_SetBlock(ftag, (U8*)this->fontid, strlen(this->fontid));
994 swf_SetU8(ftag, 0); //flags
995 for(t=0;t<swfcharpos;t++)
998 char * name = this->charname[this->swfcharid2char[t]];
1000 if(standardEncodingNames[s] &&
1001 !strcmp(name,standardEncodingNames[s]))
1004 swf_SetU8(ftag, (U8)s);
1010 for(t=0;t<charnum;t++)
1012 for(t=0;t<standardtablesize;t++)
1013 if(standardtable[t]) {
1014 free(standardtable[t]);
1016 free(standardtable);
1020 free(swfcharid2char);
1021 free(char2swfcharid);
1024 T1_OUTLINE*SWFFont::getOutline(char*name, int charnr)
1027 for(t=0;t<this->charnum;t++) {
1028 if(!strcmp(this->charname[t],name)) {
1033 /* if we didn't find the character, maybe
1034 we can find the capitalized version */
1035 for(t=0;t<this->charnum;t++) {
1036 if(!strcasecmp(this->charname[t],name))
1040 /* if we didn't find it by name, use the names of the first 256 characters
1041 of the font to try a new name based on charnr */
1042 if(this->standardtable && charnr>=0 && charnr < this->standardtablesize) {
1043 return getOutline(this->standardtable[charnr], -1);
1046 logf("<warning> Didn't find character '%s' in font '%s'", FIXNULL(name), this->name);
1050 int SWFFont::getSWFCharID(char*name, int charnr)
1053 for(t=0;t<this->charnum;t++) {
1054 if(!strcmp(this->charname[t],name)) {
1057 swfcharid2char[swfcharpos] = t;
1058 char2swfcharid[t] = swfcharpos++;
1061 return char2swfcharid[t];
1065 /* if we didn't find the character, maybe
1066 we can find the capitalized version */
1067 for(t=0;t<this->charnum;t++) {
1068 if(!strcasecmp(this->charname[t],name)) {
1071 swfcharid2char[swfcharpos] = t;
1072 char2swfcharid[t] = swfcharpos++;
1075 return char2swfcharid[t];
1079 /* if we didn't find it by name, use the names of the first 256 (or so) characters
1080 of the font to try a new name based on charnr */
1081 if(this->standardtable && charnr>=0 && charnr < this->standardtablesize) {
1082 return getSWFCharID(this->standardtable[charnr], -1);
1084 logf("<warning> Didn't find character '%s' in font '%s'", FIXNULL(name), this->name);
1088 int SWFFont::getWidth(char*name)
1091 for(t=0;t<this->charnum;t++) {
1092 if(!strcmp(this->charname[t],name)) {
1093 return this->width[t];
1099 char*SWFFont::getName()
1110 /* set's the t1 font index of the font to use for swfoutput_drawchar(). */
1111 void swfoutput_setfont(struct swfoutput*obj, char*fontid, int t1id, char*filename)
1113 fontlist_t*last=0,*iterator;
1114 if(obj->font && !strcmp(obj->font->fontid,fontid))
1117 iterator = fontlist;
1119 if(!strcmp(iterator->font->fontid,fontid))
1122 iterator = iterator->next;
1126 obj->font = iterator->font;
1131 logf("<error> internal error: t1id:%d, fontid:%s\n", t1id,FIXNULL(fontid));
1134 SWFFont*font = new SWFFont(fontid, t1id, filename);
1135 iterator = new fontlist_t;
1136 iterator->font = font;
1140 last->next = iterator;
1142 fontlist = iterator;
1146 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1148 fontlist_t *iterator = fontlist;
1150 if(!strcmp(iterator->font->fontid,fontid))
1152 iterator = iterator->next;
1157 /* set's the matrix which is to be applied to characters drawn by
1158 swfoutput_drawchar() */
1159 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1160 double m21,double m22)
1162 if(obj->fontm11 == m11 &&
1163 obj->fontm12 == m12 &&
1164 obj->fontm21 == m21 &&
1165 obj->fontm22 == m22)
1175 /* draws a character at x,y. */
1176 void swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr)
1179 m.m11 = obj->fontm11;
1180 m.m12 = obj->fontm12;
1181 m.m21 = obj->fontm21;
1182 m.m22 = obj->fontm22;
1185 drawchar(obj, obj->font, character, charnr, &m);
1188 /* initialize the swf writer */
1189 void swfoutput_init(struct swfoutput* obj, char*_filename, int _sizex, int _sizey)
1194 memset(obj, 0, sizeof(struct swfoutput));
1195 filename = _filename;
1199 logf("<verbose> initializing swf output for size %d*%d\n", sizex,sizey);
1203 memset(&swf,0x00,sizeof(SWF));
1205 swf.fileVersion = flashversion;
1206 swf.frameRate = 0x0040; // 1 frame per 4 seconds
1207 swf.movieSize.xmax = 20*sizex;
1208 swf.movieSize.ymax = 20*sizey;
1210 swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1215 swf_SetRGB(tag,&rgb);
1216 if(flag_protected) // good practice! /r
1217 tag = swf_InsertTag(tag, ST_PROTECT);
1222 void swfoutput_setprotected() //write PROTECT tag
1227 static void startshape(struct swfoutput*obj)
1235 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1237 swf_ShapeNew(&shape);
1238 linestyleid = swf_ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1239 rgb.r = obj->fillrgb.r;
1240 rgb.g = obj->fillrgb.g;
1241 rgb.b = obj->fillrgb.b;
1242 fillstyleid = swf_ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1244 shapeid = ++currentswfid;
1245 swf_SetU16(tag,shapeid); // ID
1252 swf_SetRect(tag,&r);
1254 swf_SetShapeStyles(tag,shape);
1255 swf_ShapeCountBits(shape,NULL,NULL);
1256 swf_SetShapeBits(tag,shape);
1258 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,linestyleid,0,0);
1259 swflastx=swflasty=0;
1263 static void starttext(struct swfoutput*obj)
1269 tag = swf_InsertTag(tag,ST_DEFINETEXT);
1270 textid = ++currentswfid;
1271 swf_SetU16(tag, textid);
1278 swf_SetRect(tag,&r);
1287 swf_SetMatrix(tag,&m);
1288 swflastx=swflasty=0;
1291 static void endshape()
1295 swf_ShapeSetEnd(tag);
1296 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1297 swf_ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL);
1301 static void endtext()
1307 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1308 swf_ObjectPlace(tag,textid,/*depth*/depth++,NULL,NULL,NULL);
1312 static void endpage(struct swfoutput*obj)
1319 swfoutput_endclip(obj);
1323 atag = action_Stop(atag);
1324 atag = action_End(atag);
1325 tag = swf_InsertTag(tag,ST_DOACTION);
1326 swf_ActionSet(tag,atag);
1328 tag = swf_InsertTag(tag,ST_SHOWFRAME);
1331 void swfoutput_newpage(struct swfoutput*obj)
1335 for(depth--;depth>=startdepth;depth--) {
1336 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1337 swf_SetU16(tag,depth);
1344 /* "destroy" like in (oo-terminology) "destructor". Perform cleaning
1345 up, complete the swf, and write it out. */
1346 void swfoutput_destroy(struct swfoutput* obj)
1349 fontlist_t *tmp,*iterator = fontlist;
1351 delete iterator->font;
1354 iterator = iterator->next;
1362 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1367 logf("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1371 tag = swf_InsertTag(tag,ST_END);
1374 if FAILED(swf_WriteSWC(fi,&swf))
1375 logf("<error> WriteSWC() failed.\n");
1377 if FAILED(swf_WriteSWF(fi,&swf))
1378 logf("<error> WriteSWF() failed.\n");
1383 logf("<notice> SWF written\n");
1386 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1389 if(mode == DRAWMODE_FILL)
1391 else if(mode == DRAWMODE_EOFILL)
1393 else if(mode == DRAWMODE_STROKE)
1395 else if(mode == DRAWMODE_CLIP)
1397 else if(mode == DRAWMODE_EOCLIP)
1401 void swfoutput_setfillcolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1403 if(obj->fillrgb.r == r &&
1404 obj->fillrgb.g == g &&
1405 obj->fillrgb.b == b &&
1406 obj->fillrgb.a == a) return;
1416 void swfoutput_setstrokecolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1418 if(obj->strokergb.r == r &&
1419 obj->strokergb.g == g &&
1420 obj->strokergb.b == b &&
1421 obj->strokergb.a == a) return;
1425 obj->strokergb.r = r;
1426 obj->strokergb.g = g;
1427 obj->strokergb.b = b;
1428 obj->strokergb.a = a;
1431 void swfoutput_setlinewidth(struct swfoutput*obj, double linewidth)
1433 if(obj->linewidth == (u16)(linewidth*20))
1438 obj->linewidth = (u16)(linewidth*20);
1442 void swfoutput_startclip(swfoutput*obj, T1_OUTLINE*outline, struct swfmatrix*m)
1451 logf("<warning> Too many clip levels.");
1456 int olddrawmode = drawmode;
1457 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1458 swfoutput_drawpath(obj, outline, m);
1459 swf_ShapeSetEnd(tag);
1460 swfoutput_setdrawmode(obj, olddrawmode);
1462 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1463 cliptags[clippos] = tag;
1464 clipshapes[clippos] = shapeid;
1465 clipdepths[clippos] = depth++;
1470 void swfoutput_endclip(swfoutput*obj)
1478 logf("<error> Invalid end of clipping region");
1482 swf_ObjectPlaceClip(cliptags[clippos],clipshapes[clippos],clipdepths[clippos],NULL,NULL,NULL,depth++);
1485 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1487 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1490 if(!strncmp("http://pdf2swf:", url, 15)) {
1491 char*tmp = strdup(url);
1492 int l = strlen(tmp);
1495 swfoutput_namedlink(obj, tmp+15, points);
1506 actions = action_GetUrl(0, url, "_parent");
1508 actions = action_GetUrl(0, url, "_this");
1509 actions = action_End(actions);
1511 drawlink(obj, actions, 0, points,0);
1513 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1522 actions = action_GotoFrame(0, page);
1523 actions = action_End(actions);
1525 drawlink(obj, actions, 0, points,0);
1528 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
1529 of the viewer objects, like subtitles, index elements etc.
1531 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
1533 ActionTAG *actions1,*actions2;
1534 char*tmp = strdup(name);
1542 if(!strncmp(tmp, "call:", 5))
1544 char*x = strchr(&tmp[5], ':');
1546 actions1 = action_PushInt(0, 0); //number of parameters (0)
1547 actions1 = action_PushString(actions1, &tmp[5]); //function name
1548 actions1 = action_CallFunction(actions1);
1551 actions1 = action_PushString(0, x+1); //parameter
1552 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
1553 actions1 = action_PushString(actions1, &tmp[5]); //function name
1554 actions1 = action_CallFunction(actions1);
1556 actions2 = action_End(0);
1561 actions1 = action_PushString(0, "/:subtitle");
1562 actions1 = action_PushString(actions1, name);
1563 actions1 = action_SetVariable(actions1);
1564 actions1 = action_End(actions1);
1566 actions2 = action_PushString(0, "/:subtitle");
1567 actions2 = action_PushString(actions2, "");
1568 actions2 = action_SetVariable(actions2);
1569 actions2 = action_End(actions2);
1572 drawlink(obj, actions1, actions2, points,mouseover);
1574 swf_ActionFree(actions1);
1575 swf_ActionFree(actions2);
1579 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
1585 struct plotxy p1,p2,p3,p4;
1589 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
1593 int buttonid = ++currentswfid;
1596 if(points[t].x>xmax) xmax=points[t].x;
1597 if(points[t].y>ymax) ymax=points[t].y;
1598 if(points[t].x<xmin) xmin=points[t].x;
1599 if(points[t].y<ymin) ymin=points[t].y;
1602 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
1603 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
1605 /* the following code subtracts the upper left edge from all coordinates,
1606 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
1607 Necessary for preprocessing with swfcombine. */
1608 posx = xmin; posy = ymin;
1609 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
1610 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
1611 xmin -= posx; ymin -= posy;
1612 xmax -= posx; ymax -= posy;
1615 myshapeid = ++currentswfid;
1616 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1617 swf_ShapeNew(&shape);
1618 rgb.r = rgb.b = rgb.a = rgb.g = 0;
1619 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1620 swf_SetU16(tag, myshapeid);
1621 r.xmin = (int)(xmin*20);
1622 r.ymin = (int)(ymin*20);
1623 r.xmax = (int)(xmax*20);
1624 r.ymax = (int)(ymax*20);
1625 swf_SetRect(tag,&r);
1626 swf_SetShapeStyles(tag,shape);
1627 swf_ShapeCountBits(shape,NULL,NULL);
1628 swf_SetShapeBits(tag,shape);
1629 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1630 swflastx = swflasty = 0;
1636 swf_ShapeSetEnd(tag);
1639 myshapeid2 = ++currentswfid;
1640 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1641 swf_ShapeNew(&shape);
1642 rgb.r = rgb.b = rgb.a = rgb.g = 255;
1644 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1645 swf_SetU16(tag, myshapeid2);
1646 r.xmin = (int)(xmin*20);
1647 r.ymin = (int)(ymin*20);
1648 r.xmax = (int)(xmax*20);
1649 r.ymax = (int)(ymax*20);
1650 swf_SetRect(tag,&r);
1651 swf_SetShapeStyles(tag,shape);
1652 swf_ShapeCountBits(shape,NULL,NULL);
1653 swf_SetShapeBits(tag,shape);
1654 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1655 swflastx = swflasty = 0;
1661 swf_ShapeSetEnd(tag);
1665 tag = swf_InsertTag(tag,ST_DEFINEBUTTON);
1666 swf_SetU16(tag,buttonid); //id
1667 swf_ButtonSetFlags(tag, 0); //menu=no
1668 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1669 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1670 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1671 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1673 swf_ActionSet(tag,actions1);
1678 tag = swf_InsertTag(tag,ST_DEFINEBUTTON2);
1679 swf_SetU16(tag,buttonid); //id
1680 swf_ButtonSetFlags(tag, 0); //menu=no
1681 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1682 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1683 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1684 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1685 swf_SetU8(tag,0); // end of button records
1686 swf_ButtonSetCondition(tag, BC_IDLE_OVERUP);
1687 swf_ActionSet(tag,actions1);
1689 swf_ButtonSetCondition(tag, BC_OVERUP_IDLE);
1690 swf_ActionSet(tag,actions2);
1692 swf_ButtonPostProcess(tag, 2);
1695 swf_ButtonPostProcess(tag, 1);
1699 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1701 if(posx!=0 || posy!=0) {
1703 swf_GetMatrix(0,&m);
1704 m.tx = (int)(posx*20);
1705 m.ty = (int)(posy*20);
1706 swf_ObjectPlace(tag, buttonid, depth++,&m,0,0);
1709 swf_ObjectPlace(tag, buttonid, depth++,0,0,0);
1713 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
1714 double x1,double y1,
1715 double x2,double y2,
1716 double x3,double y3,
1717 double x4,double y4)
1723 struct plotxy p1,p2,p3,p4;
1725 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
1726 if(x2>xmax) xmax=x2;
1727 if(y2>ymax) ymax=y2;
1728 if(x2<xmin) xmin=x2;
1729 if(y2<ymin) ymin=y2;
1730 if(x3>xmax) xmax=x3;
1731 if(y3>ymax) ymax=y3;
1732 if(x3<xmin) xmin=x3;
1733 if(y3<ymin) ymin=y3;
1734 if(x4>xmax) xmax=x4;
1735 if(y4>ymax) ymax=y4;
1736 if(x4<xmin) xmin=x4;
1737 if(y4<ymin) ymin=y4;
1743 {p1.x = (int)(p1.x*20)/20.0;
1744 p1.y = (int)(p1.y*20)/20.0;
1745 p2.x = (int)(p2.x*20)/20.0;
1746 p2.y = (int)(p2.y*20)/20.0;
1747 p3.x = (int)(p3.x*20)/20.0;
1748 p3.y = (int)(p3.y*20)/20.0;
1749 p4.x = (int)(p4.x*20)/20.0;
1750 p4.y = (int)(p4.y*20)/20.0;}
1753 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
1754 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
1755 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
1756 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
1758 m.tx = (int)(p1.x*20);
1759 m.ty = (int)(p1.y*20);
1762 myshapeid = ++currentswfid;
1763 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1764 swf_ShapeNew(&shape);
1765 //lsid = ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1766 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1767 fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
1768 swf_SetU16(tag, myshapeid);
1769 r.xmin = (int)(xmin*20);
1770 r.ymin = (int)(ymin*20);
1771 r.xmax = (int)(xmax*20);
1772 r.ymax = (int)(ymax*20);
1773 swf_SetRect(tag,&r);
1774 swf_SetShapeStyles(tag,shape);
1775 swf_ShapeCountBits(shape,NULL,NULL);
1776 swf_SetShapeBits(tag,shape);
1777 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,lsid,fsid,0);
1778 swflastx = swflasty = 0;
1785 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
1786 ShapeSetLine (tag, shape, (int)(x1*20);
1787 ShapeSetLine (tag, shape, x*20,0);
1788 ShapeSetLine (tag, shape, 0,-y*20);
1789 ShapeSetLine (tag, shape, -x*20,0);*/
1790 swf_ShapeSetEnd(tag);
1793 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1794 swf_ObjectPlace(tag,myshapeid,/*depth*/depth++,NULL,NULL,NULL);
1797 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
1798 double x1,double y1,
1799 double x2,double y2,
1800 double x3,double y3,
1801 double x4,double y4)
1809 int bitid = ++currentswfid;
1811 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
1812 swf_SetU16(tag, bitid);
1813 if(swf_SetJPEGBits(tag, filename, jpegquality)<0) {
1819 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1823 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
1824 double x1,double y1,
1825 double x2,double y2,
1826 double x3,double y3,
1827 double x4,double y4)
1837 int bitid = ++currentswfid;
1839 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
1840 swf_SetU16(tag, bitid);
1841 swf_SetJPEGBits2(tag,sizex,sizey,mem,jpegquality);
1842 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1846 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
1847 double x1,double y1,
1848 double x2,double y2,
1849 double x3,double y3,
1850 double x4,double y4)
1858 int bitid = ++currentswfid;
1860 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS);
1861 swf_SetU16(tag, bitid);
1862 if(swf_SetLosslessBits(tag,sizex,sizey,mem, BMF_32BIT)<0) {
1868 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1872 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
1873 double x1,double y1,
1874 double x2,double y2,
1875 double x3,double y3,
1876 double x4,double y4, int n)
1887 /* SWF expects scanlines to be 4 byte aligned */
1890 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
1892 for(y=0;y<sizey;y++)
1894 for(x=0;x<sizex;x++)
1895 *ptr++ = mem[y*sizex+x];
1896 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
1901 int bitid = ++currentswfid;
1903 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS2);
1904 swf_SetU16(tag, bitid);
1905 if(swf_SetLosslessBitsIndexed(tag,sizex,sizey,mem, pal, n)<0) {
1913 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1917 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
1918 double x1,double y1,
1919 double x2,double y2,
1920 double x3,double y3,
1921 double x4,double y4)
1929 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);