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 "../config.h"
33 #include "swfoutput.h"
36 #include "../lib/log.h"
37 #include "../lib/rfxswf.h"
41 int ignoredraworder=0;
44 int storeallcharacters=0;
49 int fontsplinemaxerror=1;
51 static char storefont = 0;
52 static int flag_protected = 0;
54 typedef unsigned char u8;
55 typedef unsigned short int u16;
56 typedef unsigned long int u32;
59 static char* filename = 0;
62 static int currentswfid = 0;
64 static int startdepth = 1;
67 static int shapeid = -1;
68 static int textid = -1;
70 static int fillstyleid;
71 static int linestyleid;
72 static int swflastx=0;
73 static int swflasty=0;
74 static int lastwasfill = 0;
75 static int shapeisempty = 1;
87 char fillstylechanged = 0;
89 static void startshape(struct swfoutput* obj);
90 static void starttext(struct swfoutput* obj);
91 static void endshape();
92 static void endtext();
94 // matrix multiplication. changes p0
95 static void transform (plotxy*p0,struct swfmatrix*m)
98 x = m->m11*p0->x+m->m12*p0->y;
99 y = m->m21*p0->x+m->m22*p0->y;
104 // write a move-to command into the swf
105 static int moveto(TAG*tag, plotxy p0)
107 int rx = (int)(p0.x*20);
108 int ry = (int)(p0.y*20);
109 if(rx!=swflastx || ry!=swflasty || fillstylechanged) {
110 swf_ShapeSetMove (tag, shape, rx,ry);
111 fillstylechanged = 0;
119 // write a line-to command into the swf
120 static void lineto(TAG*tag, plotxy p0)
122 int rx = ((int)(p0.x*20)-swflastx);
123 int ry = ((int)(p0.y*20)-swflasty);
124 /* we can't skip this for rx=0,ry=0, those
126 swf_ShapeSetLine (tag, shape, rx,ry);
132 // write a spline-to command into the swf
133 static void splineto(TAG*tag, plotxy control,plotxy end)
135 int cx = ((int)(control.x*20)-swflastx);
136 int cy = ((int)(control.y*20)-swflasty);
139 int ex = ((int)(end.x*20)-swflastx);
140 int ey = ((int)(end.y*20)-swflasty);
143 if(cx || cy || ex || ey)
144 swf_ShapeSetCurve(tag, shape, cx,cy,ex,ey);
148 /* write a line, given two points and the transformation
150 static void line(TAG*tag, plotxy p0, plotxy p1, struct swfmatrix*m)
158 /* write a cubic (!) spline. This involves calling the approximate()
159 function out of spline.cc to convert it to a quadratic spline. */
160 static void spline(TAG*tag,plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m)
163 struct qspline q[128];
177 /* fonts use a different approximation than shapes */
178 num = cspline_approximate(&c, q, fontsplinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
179 //num = cspline_approximate(&c, q, 10.0, APPROXIMATE_INFLECTION);
181 num = cspline_approximate(&c, q, splinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
185 moveto(tag,q[t].start);
186 splineto(tag,q[t].control, q[t].end);
196 static void stopFill()
200 swf_ShapeSetStyle(tag,shape,linestyleid,0x8000,0);
201 fillstylechanged = 1;
205 static void startFill()
209 swf_ShapeSetStyle(tag,shape,0x8000,fillstyleid,0);
210 fillstylechanged = 1;
215 /* draw an outline. These are generated by pdf2swf and by t1lib
216 (representing characters). */
217 void drawpath(struct swfoutput*output, SWF_OUTLINE*outline, struct swfmatrix*m, int log)
219 if( tag->id != ST_DEFINESHAPE &&
220 tag->id != ST_DEFINESHAPE2 &&
221 tag->id != ST_DEFINESHAPE3)
223 msg("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
227 double lastx=0,lasty=0;
228 double firstx=0,firsty=0;
233 x += (outline->dest.x/(float)0xffff);
234 y += (outline->dest.y/(float)0xffff);
235 if(outline->type == SWF_PATHTYPE_MOVE)
237 if(!init && fill && output->drawmode != DRAWMODE_EOFILL && !ignoredraworder) {
238 /* drawmode=FILL (not EOFILL) means that
239 seperate shapes do not cancel each other out.
240 On SWF side, we need to start a new shape for each
241 closed polygon, because SWF only knows EOFILL.
248 if(((int)(lastx*20) != (int)(firstx*20) ||
249 (int)(lasty*20) != (int)(firsty*20)) &&
258 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
259 line(tag, p0, p1, m);
265 else if(outline->type == SWF_PATHTYPE_LINE)
273 if(log) printf("line: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
276 else if(outline->type == SWF_PATHTYPE_BEZIER)
282 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
285 p1.x=o2->C.x/(float)0xffff+lastx;
286 p1.y=o2->C.y/(float)0xffff+lasty;
287 p2.x=o2->B.x/(float)0xffff+lastx;
288 p2.y=o2->B.y/(float)0xffff+lasty;
291 if(log) printf("spline: %f,%f -> %f,%f\n",p3.x,p3.y,p0.x,p0.y);
292 spline(tag,p0,p1,p2,p3,m);
295 msg("<error> drawpath: unknown outline type:%d\n", outline->type);
299 outline = outline->link;
301 if(((int)(lastx*20) != (int)(firstx*20) ||
302 (int)(lasty*20) != (int)(firsty*20)) &&
311 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
312 line(tag, p0, p1, m);
316 plotxy getPivot(SWF_OUTLINE*outline, int dir, double line_width, int end, int trytwo)
318 SWF_PATHPOINT next, next2;
319 double xv=0,yv=0, xv2=0, yv2=0;
324 if(outline->type == SWF_PATHTYPE_LINE) {
325 next = outline->dest;
327 next = ((SWF_BEZIERSEGMENT*)outline)->B;
328 if(next.x==0 && next.y==0) {
329 next = ((SWF_BEZIERSEGMENT*)outline)->C;
331 if(next.x==0 && next.y==0) {
332 next = ((SWF_BEZIERSEGMENT*)outline)->dest;
336 if(trytwo && outline->last && outline->last->type != SWF_PATHTYPE_MOVE) {
337 if(outline->type == SWF_PATHTYPE_LINE) {
338 next2 = outline->last->dest;
340 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)(outline->last))->C;
341 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)(outline->last))->B;
342 next2.x = outline->last->dest.x - c.x;
343 next2.y = outline->last->dest.y - c.y;
344 if(next2.x==0 && next2.y==0) {
345 next2.x = outline->last->dest.x - b.x;
346 next2.y = outline->last->dest.y - b.y;
348 if(next2.x==0 && next2.y==0) {
349 next2.x = outline->last->dest.x;
350 next2.y = outline->last->dest.y;
356 if(outline->type == SWF_PATHTYPE_LINE) {
357 next = outline->dest;
359 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)outline)->C;
360 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)outline)->B;
361 next.x = outline->dest.x - c.x;
362 next.y = outline->dest.y - c.y;
363 if(next.x==0 && next.y==0) {
364 next.x = outline->dest.x - b.x;
365 next.y = outline->dest.y - b.y;
367 if(next.x==0 && next.y==0) {
368 next.x = outline->dest.x;
369 next.y = outline->dest.y;
373 if(trytwo && outline->link && outline->link->type != SWF_PATHTYPE_MOVE) {
374 if(outline->type == SWF_PATHTYPE_LINE) {
375 next2 = outline->link->dest;
377 next2 = ((SWF_BEZIERSEGMENT*)(outline->link))->B;
378 if(next2.x==0 && next2.y==0) {
379 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->C;
381 if(next2.x==0 && next2.y==0) {
382 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->dest;
390 xv = next.y/(float)0xffff;
391 yv = -next.x/(float)0xffff;
393 xv = -next.y/(float)0xffff;
394 yv = next.x/(float)0xffff;
397 double r = (line_width/2)/sqrt(xv*xv+yv*yv);
403 xv2 = next2.y/(float)0xffff;
404 yv2 = -next2.x/(float)0xffff;
406 xv2 = -next2.y/(float)0xffff;
407 yv2 = next2.x/(float)0xffff;
410 double r2 = (line_width/2)/sqrt(xv2*xv2+yv2*yv2);
415 double r3 = (line_width/2)/sqrt(xv*xv+yv*yv);
425 void drawShortPath(struct swfoutput*output, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline)
427 double lastx=x, lasty=y;
428 while (outline && outline->type != SWF_PATHTYPE_MOVE)
430 x += (outline->dest.x/(float)0xffff);
431 y += (outline->dest.y/(float)0xffff);
433 if(outline->type == SWF_PATHTYPE_LINE)
440 line(tag, p0, p1, m);
442 else if(outline->type == SWF_PATHTYPE_BEZIER)
445 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
448 p1.x=o2->C.x/(float)0xffff+lastx;
449 p1.y=o2->C.y/(float)0xffff+lasty;
450 p2.x=o2->B.x/(float)0xffff+lastx;
451 p2.y=o2->B.y/(float)0xffff+lasty;
454 spline(tag,p0,p1,p2,p3,m);
458 outline = outline->link;
462 void drawShortPathWithEnds(struct swfoutput*output, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline, int num, int line_cap, int line_join, double line_width)
467 if(line_cap == LINE_CAP_BUTT || line_cap == LINE_CAP_SQUARE) {
470 SWF_OUTLINE *last, *tmp=outline;
471 plotxy s,e,p0,p1,p2,p3,m0,m1,m2,m3;
477 while(tmp && tmp->type != SWF_PATHTYPE_MOVE) {
479 lx += (tmp->dest.x/(float)0xffff);
480 ly += (tmp->dest.y/(float)0xffff);
483 s = getPivot(outline, 0, line_width, 0, 0);
484 e = getPivot(last, 0, line_width, 1, 0);
486 if(line_cap == LINE_CAP_BUTT) {
487 /* make the clipping rectangle slighly bigger
488 than the line ending, so that it get's clipped
498 p2.x = x2 - s.y - s.x*ee;
499 p2.y = y2 + s.x - s.y*ee;
500 p3.x = x2 - s.y + s.x*ee;
501 p3.y = y2 + s.x + s.y*ee;
506 m2.x = lx + e.y - e.x*ee;
507 m2.y = ly - e.x - e.y*ee;
508 m3.x = lx + e.y + e.x*ee;
509 m3.y = ly - e.x + e.y*ee;
511 for(nr=0;nr<2;nr++) {
513 struct plotxy q0,q1,q2,q3,q4,q5;
515 if(line_cap == LINE_CAP_BUTT) {
518 q1.x = sizex; q1.y = 0;
519 q2.x = sizex; q2.y = sizey;
520 q3.x = 0; q3.y = sizey;
522 q0.x = sizex; q0.y = sizey;
523 q1.x = 0; q1.y = sizey;
525 q3.x = sizex; q3.y = 0;
539 line(tag, p0, p1, m);
540 line(tag, p1, p2, m);
541 line(tag, p2, p3, m);
542 line(tag, p3, p0, m);
544 if(line_cap == LINE_CAP_BUTT) {
546 swf_ShapeSetEnd(tag);
547 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
548 swf_ObjectPlaceClip(tag,shapeid,depth,NULL,NULL,NULL,depth+2-nr);
562 drawShortPath(output,x,y,m,outline);
564 if(line_cap == LINE_CAP_BUTT) {
570 void drawT1toRect(struct swfoutput*output, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline, int num, int line_cap, int line_join, double line_width)
572 plotxy d1,d2,p1,p2,p3,p4;
574 d1.x = (outline->dest.x/(float)0xffff);
575 d1.y = (outline->dest.y/(float)0xffff);
576 d2 = getPivot(outline, 0, line_width, 0, 0);
578 assert(line_cap != LINE_CAP_ROUND);
579 if(line_cap == LINE_CAP_SQUARE) {
588 p2.x = x + d2.x + d1.x;
589 p2.y = y + d2.y + d1.y;
590 p3.x = x - d2.x + d1.x;
591 p3.y = y - d2.y + d1.y;
601 void drawShortPathWithStraightEnds(struct swfoutput*output, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline, int num, int line_cap, int line_join, double line_width)
603 SWF_OUTLINE*tmp=outline;
609 drawT1toRect(output, x, y, m,outline, num, line_cap, line_join, line_width);
611 while(tmp->link && tmp->link->type!=SWF_PATHTYPE_MOVE) {
612 xx += (tmp->dest.x/(float)0xffff);
613 yy += (tmp->dest.y/(float)0xffff);
617 assert(tmp->type == SWF_PATHTYPE_LINE);
618 assert(outline->type == SWF_PATHTYPE_LINE);
622 if(outline->link == tmp) {
623 /* the two straight line segments (which are everything we
624 need to draw) are very likely to overlap. To avoid that
625 they cancel each other out at the end points, start a new
626 shape for the second one */
627 endshape();startshape(output);
631 drawT1toRect(output, xx, yy, m, tmp, num, line_cap, line_join, line_width);
633 if(outline->link != tmp)
637 tmp->type = SWF_PATHTYPE_MOVE;
638 x += (outline->dest.x/(float)0xffff);
639 y += (outline->dest.y/(float)0xffff);
640 outline = outline->link;
641 drawShortPath(output, x, y, m, outline);
649 static int t1len(SWF_OUTLINE*line)
652 while(line && line->type != SWF_PATHTYPE_MOVE) {
659 static float t1linelen(SWF_OUTLINE*line)
662 x = (line->dest.x/(float)0xffff);
663 y = (line->dest.y/(float)0xffff);
664 return sqrt(x*x+y*y);
667 void drawpath2poly(struct swfoutput *output, SWF_OUTLINE*outline, struct swfmatrix*m, int log, int line_join, int line_cap, double line_width, double miter_limit)
669 if( tag->id != ST_DEFINESHAPE &&
670 tag->id != ST_DEFINESHAPE2 &&
671 tag->id != ST_DEFINESHAPE3) {
672 msg("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
677 double lastx=0,lasty=0;
680 SWF_OUTLINE*tmp = outline, *last = 0;
685 x += (tmp->dest.x/(float)0xffff);
686 y += (tmp->dest.y/(float)0xffff);
688 if(!tmp || tmp->type == SWF_PATHTYPE_MOVE) {
690 if(last->type == SWF_PATHTYPE_LINE && t1linelen(last)>line_width*2 &&
691 lastwasline && line_cap != LINE_CAP_ROUND)
692 drawShortPathWithStraightEnds(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
694 drawShortPathWithEnds(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
708 if(tmp && tmp->type == SWF_PATHTYPE_LINE && t1linelen(tmp)>line_width*2)
714 tmp->link->last = tmp; // make sure list is properly linked in both directions
719 static inline int colorcompare(RGBA*a,RGBA*b)
731 static const int CHARDATAMAX = 8192;
739 } chardata[CHARDATAMAX];
742 static void putcharacters(TAG*tag)
747 color.r = chardata[0].color.r^255;
756 int charadvance[128];
759 int glyphbits=1; //TODO: can this be zero?
762 if(tag->id != ST_DEFINETEXT &&
763 tag->id != ST_DEFINETEXT2) {
764 msg("<error> internal error: putcharacters needs an text tag, not %d\n",tag->id);
768 msg("<warning> putcharacters called with zero characters");
771 for(pass = 0; pass < 2; pass++)
781 advancebits++; // add sign bit
782 swf_SetU8(tag, glyphbits);
783 swf_SetU8(tag, advancebits);
786 for(t=0;t<=chardatapos;t++)
788 if(lastfontid != chardata[t].fontid ||
789 lastx!=chardata[t].x ||
790 lasty!=chardata[t].y ||
791 !colorcompare(&color, &chardata[t].color) ||
793 lastsize != chardata[t].size ||
796 if(charstorepos && pass==0)
799 for(s=0;s<charstorepos;s++)
801 while(charids[s]>=(1<<glyphbits))
803 while(charadvance[s]>=(1<<advancebits))
807 if(charstorepos && pass==1)
809 tag->writeBit = 0; // Q&D
810 swf_SetBits(tag, 0, 1); // GLYPH Record
811 swf_SetBits(tag, charstorepos, 7); // number of glyphs
813 for(s=0;s<charstorepos;s++)
815 swf_SetBits(tag, charids[s], glyphbits);
816 swf_SetBits(tag, charadvance[s], advancebits);
821 if(pass == 1 && t<chardatapos)
827 if(lastx != chardata[t].x ||
828 lasty != chardata[t].y)
830 newx = chardata[t].x;
831 newy = chardata[t].y;
837 if(!colorcompare(&color, &chardata[t].color))
839 color = chardata[t].color;
842 font.id = chardata[t].fontid;
843 if(lastfontid != chardata[t].fontid || lastsize != chardata[t].size)
846 tag->writeBit = 0; // Q&D
847 swf_TextSetInfoRecord(tag, newfont, chardata[t].size, newcolor, newx,newy);
850 lastfontid = chardata[t].fontid;
851 lastx = chardata[t].x;
852 lasty = chardata[t].y;
853 lastsize = chardata[t].size;
860 int nextt = t==chardatapos-1?t:t+1;
861 int rel = chardata[nextt].x-chardata[t].x;
862 if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) {
864 lastx=chardata[nextt].x;
870 charids[charstorepos] = chardata[t].charid;
871 charadvance[charstorepos] = advance;
878 static void putcharacter(struct swfoutput*obj, int fontid, int charid,
879 int x,int y, int size)
881 if(chardatapos == CHARDATAMAX)
883 msg("<warning> Character buffer too small. SWF will be slightly bigger");
887 chardata[chardatapos].fontid = fontid;
888 chardata[chardatapos].charid = charid;
889 chardata[chardatapos].x = x;
890 chardata[chardatapos].y = y;
891 chardata[chardatapos].color = obj->fillrgb;
892 chardata[chardatapos].size = size;
902 /* process a character. */
903 static int drawchar(struct swfoutput*obj, SWFFONT *swffont, char*character, int charnr, int u, swfmatrix*m)
906 if(m->m12!=0 || m->m21!=0)
912 msg("<warning> Font is NULL");
917 msg("<verbose> Non diagonal font matrix: %f %f", m->m11, m->m21);
918 msg("<verbose> | %f %f", m->m12, m->m22);
921 //if(usefonts && ! drawonlyshapes)
924 int charid = getCharID(swffont, charnr, character, u);
927 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
928 FIXNULL(character),charnr, u, FIXNULL((char*)swffont->name), swffont->numchars);
929 /*fontlist_t*it = fontlist;
931 msg("<warning> Font history: %s [%d]", it->swffont->name, getCharID(it->swffont, charnr, character, u));
942 putcharacter(obj, swffont->id, charid,(int)(m->m13*20),(int)(m->m23*20),
948 SWF_OUTLINE*outline = font->getOutline(character, charnr);
949 char* charname = character;
952 msg("<warning> Didn't find character '%s' (%d) in current charset (%s)",
953 FIXNULL(character),charnr,FIXNULL(font->getName()));
972 drawpath(tag, outline, &m2, 0);
977 /* draw a curved polygon. */
978 void swfoutput_drawpath(swfoutput*output, SWF_OUTLINE*outline,
984 /* Multiple polygons in one shape don't overlap correctly,
985 so we better start a new shape here if the polygon is filled
987 if(shapeid>=0 && fill && !ignoredraworder) {
999 drawpath(output, outline,m, 0);
1002 void swfoutput_drawpath2poly(struct swfoutput*output, SWF_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
1012 drawpath2poly(output, outline, m, 0, line_join, line_cap, line_width, miter_limit);
1015 int getCharID(SWFFONT *font, int charnr, char *charname, int u)
1019 for(t=0;t<font->numchars;t++) {
1020 if(font->glyphnames[t] && !strcmp(font->glyphnames[t],charname)) {
1024 /* if we didn't find the character, maybe
1025 we can find the capitalized version */
1026 for(t=0;t<font->numchars;t++) {
1027 if(font->glyphnames[t] && !strcasecmp(font->glyphnames[t],charname)) {
1034 if(u>=font->maxascii)
1035 msg("<debug> u=%d, font->maxascii=%d",u,font->maxascii);
1037 msg("<debug> u=%d, font->maxascii=%d ascci2glyph[%d]=%d",u,font->maxascii,u,font->ascii2glyph[u]);
1039 /* try to use the unicode id */
1040 if(u>=0 && u<font->maxascii && font->ascii2glyph[u]>=0) {
1041 return font->ascii2glyph[u];
1045 if(charnr>=0 && charnr<font->numchars) {
1049 /* the following is technically wrong, and only works if the font encoding
1050 is US-ASCII based. It's needed for fonts which return broken unicode
1052 /* if(charnr>=0 && charnr<font->maxascii && font->ascii2glyph[charnr]>=0) {
1053 return font->ascii2glyph[charnr];
1060 /* set's the t1 font index of the font to use for swfoutput_drawchar(). */
1061 void swfoutput_setfont(struct swfoutput*obj, char*fontid, char*filename)
1063 fontlist_t*last=0,*iterator;
1065 msg("<error> No fontid");
1069 if(obj->swffont && obj->swffont->name && !strcmp((char*)obj->swffont->name,fontid))
1072 iterator = fontlist;
1074 if(!strcmp((char*)iterator->swffont->name,fontid)) {
1075 obj->swffont = iterator->swffont;
1079 iterator = iterator->next;
1083 msg("<error> No filename given for font- internal error?");
1087 swf_SetLoadFontParameters(0,/*skip unused*/0,/*full unicode*/1);
1088 SWFFONT*swffont = swf_LoadFont(filename);
1091 msg("<warning> Couldn't load font %s (%s)", fontid, filename);
1092 swffont = swf_LoadFont(0);
1095 swf_FontSetID(swffont, ++currentswfid);
1097 if(screenloglevel >= LOGLEVEL_DEBUG) {
1098 // print font information
1099 msg("<debug> Font %s (%s)",swffont->name, filename);
1100 msg("<debug> | ID: %d", swffont->id);
1101 msg("<debug> | Version: %d", swffont->version);
1102 msg("<debug> | Name: %s", fontid);
1103 msg("<debug> | Numchars: %d", swffont->numchars);
1104 msg("<debug> | Maxascii: %d", swffont->maxascii);
1105 msg("<debug> | Style: %d", swffont->style);
1106 msg("<debug> | Encoding: %d", swffont->encoding);
1107 for(int iii=0; iii<swffont->numchars;iii++) {
1108 msg("<debug> | Glyph %d) name=%s, unicode=%d\n", iii, swffont->glyphnames[iii], swffont->glyph2ascii[iii]);
1112 /* set the font name to the ID we use here */
1113 if(swffont->name) free(swffont->name);
1114 swffont->name = (U8*)strdup(fontid);
1116 iterator = new fontlist_t;
1117 iterator->swffont = swffont;
1121 last->next = iterator;
1123 fontlist = iterator;
1125 obj->swffont = swffont;
1128 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1130 fontlist_t *iterator = fontlist;
1132 if(!strcmp((char*)iterator->swffont->name,fontid))
1134 iterator = iterator->next;
1139 /* set's the matrix which is to be applied to characters drawn by
1140 swfoutput_drawchar() */
1141 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1142 double m21,double m22)
1144 if(obj->fontm11 == m11 &&
1145 obj->fontm12 == m12 &&
1146 obj->fontm21 == m21 &&
1147 obj->fontm22 == m22)
1157 /* draws a character at x,y. */
1158 int swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr, int u)
1161 m.m11 = obj->fontm11;
1162 m.m12 = obj->fontm12;
1163 m.m21 = obj->fontm21;
1164 m.m22 = obj->fontm22;
1167 return drawchar(obj, obj->swffont, character, charnr, u, &m);
1170 /* initialize the swf writer */
1171 void swfoutput_init(struct swfoutput* obj, char*_filename, int x1, int y1, int x2, int y2)
1175 memset(obj, 0, sizeof(struct swfoutput));
1176 filename = _filename;
1180 msg("<verbose> initializing swf output for size %d*%d\n", sizex,sizey);
1185 memset(&swf,0x00,sizeof(SWF));
1187 swf.fileVersion = flashversion;
1188 swf.frameRate = 0x0040; // 1 frame per 4 seconds
1189 swf.movieSize.xmin = 20*x1;
1190 swf.movieSize.ymin = 20*y1;
1191 swf.movieSize.xmax = 20*x2;
1192 swf.movieSize.ymax = 20*y2;
1196 swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1198 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1199 swf_SetRGB(tag,&rgb);
1201 if(1)/* add white rectangle */
1206 int shapeid = ++currentswfid;
1211 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
1213 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1214 swf_SetU16(tag,shapeid);
1215 swf_SetRect(tag,&r);
1216 swf_SetShapeHeader(tag,s);
1217 swf_ShapeSetAll(tag,s,x1*20,y1*20,ls1,fs1,0);
1218 swf_ShapeSetLine(tag,s,20*(x2-x1),0);
1219 swf_ShapeSetLine(tag,s,0,20*(y2-y1));
1220 swf_ShapeSetLine(tag,s,20*(x1-x2),0);
1221 swf_ShapeSetLine(tag,s,0,20*(y1-y2));
1222 swf_ShapeSetEnd(tag);
1224 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1225 swf_ObjectPlace(tag,shapeid,depth++,0,0,0);
1226 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1227 swf_ObjectPlaceClip(tag,shapeid,depth++,0,0,0,65535);
1231 tag = swf_InsertTag(tag, ST_PROTECT);
1236 void swfoutput_setprotected() //write PROTECT tag
1241 static void startshape(struct swfoutput*obj)
1249 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1251 swf_ShapeNew(&shape);
1252 linestyleid = swf_ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1253 rgb.r = obj->fillrgb.r;
1254 rgb.g = obj->fillrgb.g;
1255 rgb.b = obj->fillrgb.b;
1256 fillstyleid = swf_ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1258 shapeid = ++currentswfid;
1259 swf_SetU16(tag,shapeid); // ID
1266 swf_SetRect(tag,&r);
1268 swf_SetShapeStyles(tag,shape);
1269 swf_ShapeCountBits(shape,NULL,NULL);
1270 swf_SetShapeBits(tag,shape);
1272 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,linestyleid,0,0);
1273 swflastx=swflasty=0;
1278 static void starttext(struct swfoutput*obj)
1284 tag = swf_InsertTag(tag,ST_DEFINETEXT);
1285 textid = ++currentswfid;
1286 swf_SetU16(tag, textid);
1293 swf_SetRect(tag,&r);
1302 swf_SetMatrix(tag,&m);
1303 swflastx=swflasty=0;
1306 static void endshape()
1310 swf_ShapeSetEnd(tag);
1313 // delete the tag again, we didn't do anything
1316 swf_DeleteTag(todel);
1318 /* TODO: fix bounding box */
1319 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1320 swf_ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL);
1325 static void endtext()
1331 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1332 swf_ObjectPlace(tag,textid,/*depth*/depth++,NULL,NULL,NULL);
1336 static void endpage(struct swfoutput*obj)
1343 swfoutput_endclip(obj);
1347 atag = action_Stop(atag);
1348 atag = action_End(atag);
1349 tag = swf_InsertTag(tag,ST_DOACTION);
1350 swf_ActionSet(tag,atag);
1352 tag = swf_InsertTag(tag,ST_SHOWFRAME);
1355 void swfoutput_newpage(struct swfoutput*obj)
1359 for(depth--;depth>=startdepth;depth--) {
1360 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1361 swf_SetU16(tag,depth);
1367 /* "destroy" like in (oo-terminology) "destructor". Perform cleaning
1368 up, complete the swf, and write it out. */
1369 void swfoutput_destroy(struct swfoutput* obj)
1372 fontlist_t *tmp,*iterator = fontlist;
1374 TAG*mtag = swf.firstTag;
1375 if(iterator->swffont) {
1376 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1377 swf_FontSetDefine2(mtag, iterator->swffont);
1378 swf_FontFree(iterator->swffont);
1382 iterator = iterator->next;
1389 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1394 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1398 tag = swf_InsertTag(tag,ST_END);
1401 if FAILED(swf_WriteSWC(fi,&swf))
1402 msg("<error> WriteSWC() failed.\n");
1404 if FAILED(swf_WriteSWF(fi,&swf))
1405 msg("<error> WriteSWF() failed.\n");
1410 msg("<notice> SWF written\n");
1413 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1415 obj->drawmode = mode;
1416 if(mode == DRAWMODE_FILL)
1418 else if(mode == DRAWMODE_EOFILL)
1420 else if(mode == DRAWMODE_STROKE)
1422 else if(mode == DRAWMODE_CLIP)
1424 else if(mode == DRAWMODE_EOCLIP)
1428 void swfoutput_setfillcolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1430 if(obj->fillrgb.r == r &&
1431 obj->fillrgb.g == g &&
1432 obj->fillrgb.b == b &&
1433 obj->fillrgb.a == a) return;
1443 void swfoutput_setstrokecolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1445 if(obj->strokergb.r == r &&
1446 obj->strokergb.g == g &&
1447 obj->strokergb.b == b &&
1448 obj->strokergb.a == a) return;
1452 obj->strokergb.r = r;
1453 obj->strokergb.g = g;
1454 obj->strokergb.b = b;
1455 obj->strokergb.a = a;
1458 void swfoutput_setlinewidth(struct swfoutput*obj, double linewidth)
1460 if(obj->linewidth == (u16)(linewidth*20))
1465 obj->linewidth = (u16)(linewidth*20);
1469 void swfoutput_startclip(swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m)
1478 msg("<warning> Too many clip levels.");
1483 int olddrawmode = obj->drawmode;
1484 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1485 swfoutput_drawpath(obj, outline, m);
1486 swf_ShapeSetEnd(tag);
1487 swfoutput_setdrawmode(obj, olddrawmode);
1489 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1490 cliptags[clippos] = tag;
1491 clipshapes[clippos] = shapeid;
1492 clipdepths[clippos] = depth++;
1497 void swfoutput_endclip(swfoutput*obj)
1505 msg("<error> Invalid end of clipping region");
1509 swf_ObjectPlaceClip(cliptags[clippos],clipshapes[clippos],clipdepths[clippos],NULL,NULL,NULL,depth++);
1512 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1514 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1517 if(!strncmp("http://pdf2swf:", url, 15)) {
1518 char*tmp = strdup(url);
1519 int l = strlen(tmp);
1522 swfoutput_namedlink(obj, tmp+15, points);
1533 actions = action_GetUrl(0, url, "_parent");
1535 actions = action_GetUrl(0, url, "_this");
1536 actions = action_End(actions);
1538 drawlink(obj, actions, 0, points,0);
1540 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1549 actions = action_GotoFrame(0, page);
1550 actions = action_End(actions);
1552 drawlink(obj, actions, 0, points,0);
1555 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
1556 of the viewer objects, like subtitles, index elements etc.
1558 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
1560 ActionTAG *actions1,*actions2;
1561 char*tmp = strdup(name);
1569 if(!strncmp(tmp, "call:", 5))
1571 char*x = strchr(&tmp[5], ':');
1573 actions1 = action_PushInt(0, 0); //number of parameters (0)
1574 actions1 = action_PushString(actions1, &tmp[5]); //function name
1575 actions1 = action_CallFunction(actions1);
1578 actions1 = action_PushString(0, x+1); //parameter
1579 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
1580 actions1 = action_PushString(actions1, &tmp[5]); //function name
1581 actions1 = action_CallFunction(actions1);
1583 actions2 = action_End(0);
1588 actions1 = action_PushString(0, "/:subtitle");
1589 actions1 = action_PushString(actions1, name);
1590 actions1 = action_SetVariable(actions1);
1591 actions1 = action_End(actions1);
1593 actions2 = action_PushString(0, "/:subtitle");
1594 actions2 = action_PushString(actions2, "");
1595 actions2 = action_SetVariable(actions2);
1596 actions2 = action_End(actions2);
1599 drawlink(obj, actions1, actions2, points,mouseover);
1601 swf_ActionFree(actions1);
1602 swf_ActionFree(actions2);
1606 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
1612 struct plotxy p1,p2,p3,p4;
1616 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
1620 int buttonid = ++currentswfid;
1623 if(points[t].x>xmax) xmax=points[t].x;
1624 if(points[t].y>ymax) ymax=points[t].y;
1625 if(points[t].x<xmin) xmin=points[t].x;
1626 if(points[t].y<ymin) ymin=points[t].y;
1629 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
1630 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
1632 /* the following code subtracts the upper left edge from all coordinates,
1633 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
1634 Necessary for preprocessing with swfcombine. */
1635 posx = xmin; posy = ymin;
1636 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
1637 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
1638 xmin -= posx; ymin -= posy;
1639 xmax -= posx; ymax -= posy;
1642 myshapeid = ++currentswfid;
1643 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1644 swf_ShapeNew(&shape);
1645 rgb.r = rgb.b = rgb.a = rgb.g = 0;
1646 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1647 swf_SetU16(tag, myshapeid);
1648 r.xmin = (int)(xmin*20);
1649 r.ymin = (int)(ymin*20);
1650 r.xmax = (int)(xmax*20);
1651 r.ymax = (int)(ymax*20);
1652 swf_SetRect(tag,&r);
1653 swf_SetShapeStyles(tag,shape);
1654 swf_ShapeCountBits(shape,NULL,NULL);
1655 swf_SetShapeBits(tag,shape);
1656 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1657 swflastx = swflasty = 0;
1663 swf_ShapeSetEnd(tag);
1666 myshapeid2 = ++currentswfid;
1667 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1668 swf_ShapeNew(&shape);
1669 rgb.r = rgb.b = rgb.a = rgb.g = 255;
1671 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1672 swf_SetU16(tag, myshapeid2);
1673 r.xmin = (int)(xmin*20);
1674 r.ymin = (int)(ymin*20);
1675 r.xmax = (int)(xmax*20);
1676 r.ymax = (int)(ymax*20);
1677 swf_SetRect(tag,&r);
1678 swf_SetShapeStyles(tag,shape);
1679 swf_ShapeCountBits(shape,NULL,NULL);
1680 swf_SetShapeBits(tag,shape);
1681 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1682 swflastx = swflasty = 0;
1688 swf_ShapeSetEnd(tag);
1692 tag = swf_InsertTag(tag,ST_DEFINEBUTTON);
1693 swf_SetU16(tag,buttonid); //id
1694 swf_ButtonSetFlags(tag, 0); //menu=no
1695 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1696 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1697 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1698 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1700 swf_ActionSet(tag,actions1);
1705 tag = swf_InsertTag(tag,ST_DEFINEBUTTON2);
1706 swf_SetU16(tag,buttonid); //id
1707 swf_ButtonSetFlags(tag, 0); //menu=no
1708 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1709 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1710 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1711 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1712 swf_SetU8(tag,0); // end of button records
1713 swf_ButtonSetCondition(tag, BC_IDLE_OVERUP);
1714 swf_ActionSet(tag,actions1);
1716 swf_ButtonSetCondition(tag, BC_OVERUP_IDLE);
1717 swf_ActionSet(tag,actions2);
1719 swf_ButtonPostProcess(tag, 2);
1722 swf_ButtonPostProcess(tag, 1);
1726 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1728 if(posx!=0 || posy!=0) {
1730 swf_GetMatrix(0,&m);
1731 m.tx = (int)(posx*20);
1732 m.ty = (int)(posy*20);
1733 swf_ObjectPlace(tag, buttonid, depth++,&m,0,0);
1736 swf_ObjectPlace(tag, buttonid, depth++,0,0,0);
1740 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
1741 double x1,double y1,
1742 double x2,double y2,
1743 double x3,double y3,
1744 double x4,double y4)
1750 struct plotxy p1,p2,p3,p4;
1752 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
1753 if(x2>xmax) xmax=x2;
1754 if(y2>ymax) ymax=y2;
1755 if(x2<xmin) xmin=x2;
1756 if(y2<ymin) ymin=y2;
1757 if(x3>xmax) xmax=x3;
1758 if(y3>ymax) ymax=y3;
1759 if(x3<xmin) xmin=x3;
1760 if(y3<ymin) ymin=y3;
1761 if(x4>xmax) xmax=x4;
1762 if(y4>ymax) ymax=y4;
1763 if(x4<xmin) xmin=x4;
1764 if(y4<ymin) ymin=y4;
1770 {p1.x = (int)(p1.x*20)/20.0;
1771 p1.y = (int)(p1.y*20)/20.0;
1772 p2.x = (int)(p2.x*20)/20.0;
1773 p2.y = (int)(p2.y*20)/20.0;
1774 p3.x = (int)(p3.x*20)/20.0;
1775 p3.y = (int)(p3.y*20)/20.0;
1776 p4.x = (int)(p4.x*20)/20.0;
1777 p4.y = (int)(p4.y*20)/20.0;}
1780 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
1781 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
1782 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
1783 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
1785 m.tx = (int)(p1.x*20);
1786 m.ty = (int)(p1.y*20);
1789 myshapeid = ++currentswfid;
1790 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1791 swf_ShapeNew(&shape);
1792 //lsid = ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1793 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1794 fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
1795 swf_SetU16(tag, myshapeid);
1796 r.xmin = (int)(xmin*20);
1797 r.ymin = (int)(ymin*20);
1798 r.xmax = (int)(xmax*20);
1799 r.ymax = (int)(ymax*20);
1800 swf_SetRect(tag,&r);
1801 swf_SetShapeStyles(tag,shape);
1802 swf_ShapeCountBits(shape,NULL,NULL);
1803 swf_SetShapeBits(tag,shape);
1804 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,lsid,fsid,0);
1805 swflastx = swflasty = 0;
1812 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
1813 ShapeSetLine (tag, shape, (int)(x1*20);
1814 ShapeSetLine (tag, shape, x*20,0);
1815 ShapeSetLine (tag, shape, 0,-y*20);
1816 ShapeSetLine (tag, shape, -x*20,0);*/
1817 swf_ShapeSetEnd(tag);
1820 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1821 swf_ObjectPlace(tag,myshapeid,/*depth*/depth++,NULL,NULL,NULL);
1824 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
1825 double x1,double y1,
1826 double x2,double y2,
1827 double x3,double y3,
1828 double x4,double y4)
1836 int bitid = ++currentswfid;
1838 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
1839 swf_SetU16(tag, bitid);
1840 if(swf_SetJPEGBits(tag, filename, jpegquality)<0) {
1846 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1850 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
1851 double x1,double y1,
1852 double x2,double y2,
1853 double x3,double y3,
1854 double x4,double y4)
1864 int bitid = ++currentswfid;
1866 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
1867 swf_SetU16(tag, bitid);
1868 swf_SetJPEGBits2(tag,sizex,sizey,mem,jpegquality);
1869 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1873 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
1874 double x1,double y1,
1875 double x2,double y2,
1876 double x3,double y3,
1877 double x4,double y4)
1885 int bitid = ++currentswfid;
1887 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS);
1888 swf_SetU16(tag, bitid);
1889 if(swf_SetLosslessBits(tag,sizex,sizey,mem, BMF_32BIT)<0) {
1895 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1899 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
1900 double x1,double y1,
1901 double x2,double y2,
1902 double x3,double y3,
1903 double x4,double y4, int n)
1914 /* SWF expects scanlines to be 4 byte aligned */
1917 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
1919 for(y=0;y<sizey;y++)
1921 for(x=0;x<sizex;x++)
1922 *ptr++ = mem[y*sizex+x];
1923 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
1928 int bitid = ++currentswfid;
1930 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS2);
1931 swf_SetU16(tag, bitid);
1932 if(swf_SetLosslessBitsIndexed(tag,sizex,sizey,mem, pal, n)<0) {
1940 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1944 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
1945 double x1,double y1,
1946 double x2,double y2,
1947 double x3,double y3,
1948 double x4,double y4)
1956 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);