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 drawmode = -1;
71 static int fillstyleid;
72 static int linestyleid;
73 static int swflastx=0;
74 static int swflasty=0;
75 static int lastwasfill = 0;
76 static int shapeisempty = 1;
88 char fillstylechanged = 0;
90 static void startshape(struct swfoutput* obj);
91 static void starttext(struct swfoutput* obj);
92 static void endshape();
93 static void endtext();
95 // matrix multiplication. changes p0
96 static void transform (plotxy*p0,struct swfmatrix*m)
99 x = m->m11*p0->x+m->m12*p0->y;
100 y = m->m21*p0->x+m->m22*p0->y;
105 // write a move-to command into the swf
106 static int moveto(TAG*tag, plotxy p0)
108 int rx = (int)(p0.x*20);
109 int ry = (int)(p0.y*20);
110 if(rx!=swflastx || ry!=swflasty || fillstylechanged) {
111 swf_ShapeSetMove (tag, shape, rx,ry);
112 fillstylechanged = 0;
120 // write a line-to command into the swf
121 static void lineto(TAG*tag, plotxy p0)
123 int rx = ((int)(p0.x*20)-swflastx);
124 int ry = ((int)(p0.y*20)-swflasty);
125 /* we can't skip this for rx=0,ry=0, those
127 swf_ShapeSetLine (tag, shape, rx,ry);
133 // write a spline-to command into the swf
134 static void splineto(TAG*tag, plotxy control,plotxy end)
136 int cx = ((int)(control.x*20)-swflastx);
137 int cy = ((int)(control.y*20)-swflasty);
140 int ex = ((int)(end.x*20)-swflastx);
141 int ey = ((int)(end.y*20)-swflasty);
144 if(cx || cy || ex || ey)
145 swf_ShapeSetCurve(tag, shape, cx,cy,ex,ey);
149 /* write a line, given two points and the transformation
151 static void line(TAG*tag, plotxy p0, plotxy p1, struct swfmatrix*m)
159 /* write a cubic (!) spline. This involves calling the approximate()
160 function out of spline.cc to convert it to a quadratic spline. */
161 static void spline(TAG*tag,plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m)
164 struct qspline q[128];
178 /* fonts use a different approximation than shapes */
179 num = cspline_approximate(&c, q, fontsplinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
180 //num = cspline_approximate(&c, q, 10.0, APPROXIMATE_INFLECTION);
182 num = cspline_approximate(&c, q, splinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
186 moveto(tag,q[t].start);
187 splineto(tag,q[t].control, q[t].end);
197 static void stopFill()
201 swf_ShapeSetStyle(tag,shape,linestyleid,0x8000,0);
202 fillstylechanged = 1;
206 static void startFill()
210 swf_ShapeSetStyle(tag,shape,0x8000,fillstyleid,0);
211 fillstylechanged = 1;
216 /* draw an outline. These are generated by pdf2swf and by t1lib
217 (representing characters). */
218 void drawpath(TAG*tag, SWF_OUTLINE*outline, struct swfmatrix*m, int log)
220 if(tag->id != ST_DEFINEFONT &&
221 tag->id != ST_DEFINESHAPE &&
222 tag->id != ST_DEFINESHAPE2 &&
223 tag->id != ST_DEFINESHAPE3)
225 msg("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
229 double lastx=0,lasty=0;
230 double firstx=0,firsty=0;
235 x += (outline->dest.x/(float)0xffff);
236 y += (outline->dest.y/(float)0xffff);
237 if(outline->type == SWF_PATHTYPE_MOVE)
239 if(((int)(lastx*20) != (int)(firstx*20) ||
240 (int)(lasty*20) != (int)(firsty*20)) &&
249 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
250 line(tag, p0, p1, m);
256 else if(outline->type == SWF_PATHTYPE_LINE)
264 if(log) printf("line: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
267 else if(outline->type == SWF_PATHTYPE_BEZIER)
273 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
276 p1.x=o2->C.x/(float)0xffff+lastx;
277 p1.y=o2->C.y/(float)0xffff+lasty;
278 p2.x=o2->B.x/(float)0xffff+lastx;
279 p2.y=o2->B.y/(float)0xffff+lasty;
282 if(log) printf("spline: %f,%f -> %f,%f\n",p3.x,p3.y,p0.x,p0.y);
283 spline(tag,p0,p1,p2,p3,m);
286 msg("<error> drawpath: unknown outline type:%d\n", outline->type);
290 outline = outline->link;
292 if(((int)(lastx*20) != (int)(firstx*20) ||
293 (int)(lasty*20) != (int)(firsty*20)) &&
302 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
303 line(tag, p0, p1, m);
307 plotxy getPivot(SWF_OUTLINE*outline, int dir, double line_width, int end, int trytwo)
309 SWF_PATHPOINT next, next2;
310 double xv=0,yv=0, xv2=0, yv2=0;
315 if(outline->type == SWF_PATHTYPE_LINE) {
316 next = outline->dest;
318 next = ((SWF_BEZIERSEGMENT*)outline)->B;
319 if(next.x==0 && next.y==0) {
320 next = ((SWF_BEZIERSEGMENT*)outline)->C;
322 if(next.x==0 && next.y==0) {
323 next = ((SWF_BEZIERSEGMENT*)outline)->dest;
327 if(trytwo && outline->last && outline->last->type != SWF_PATHTYPE_MOVE) {
328 if(outline->type == SWF_PATHTYPE_LINE) {
329 next2 = outline->last->dest;
331 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)(outline->last))->C;
332 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)(outline->last))->B;
333 next2.x = outline->last->dest.x - c.x;
334 next2.y = outline->last->dest.y - c.y;
335 if(next2.x==0 && next2.y==0) {
336 next2.x = outline->last->dest.x - b.x;
337 next2.y = outline->last->dest.y - b.y;
339 if(next2.x==0 && next2.y==0) {
340 next2.x = outline->last->dest.x;
341 next2.y = outline->last->dest.y;
347 if(outline->type == SWF_PATHTYPE_LINE) {
348 next = outline->dest;
350 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)outline)->C;
351 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)outline)->B;
352 next.x = outline->dest.x - c.x;
353 next.y = outline->dest.y - c.y;
354 if(next.x==0 && next.y==0) {
355 next.x = outline->dest.x - b.x;
356 next.y = outline->dest.y - b.y;
358 if(next.x==0 && next.y==0) {
359 next.x = outline->dest.x;
360 next.y = outline->dest.y;
364 if(trytwo && outline->link && outline->link->type != SWF_PATHTYPE_MOVE) {
365 if(outline->type == SWF_PATHTYPE_LINE) {
366 next2 = outline->link->dest;
368 next2 = ((SWF_BEZIERSEGMENT*)(outline->link))->B;
369 if(next2.x==0 && next2.y==0) {
370 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->C;
372 if(next2.x==0 && next2.y==0) {
373 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->dest;
381 xv = next.y/(float)0xffff;
382 yv = -next.x/(float)0xffff;
384 xv = -next.y/(float)0xffff;
385 yv = next.x/(float)0xffff;
388 double r = (line_width/2)/sqrt(xv*xv+yv*yv);
394 xv2 = next2.y/(float)0xffff;
395 yv2 = -next2.x/(float)0xffff;
397 xv2 = -next2.y/(float)0xffff;
398 yv2 = next2.x/(float)0xffff;
401 double r2 = (line_width/2)/sqrt(xv2*xv2+yv2*yv2);
406 double r3 = (line_width/2)/sqrt(xv*xv+yv*yv);
416 void drawShortPath(struct swfoutput*output, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline)
418 double lastx=x, lasty=y;
419 while (outline && outline->type != SWF_PATHTYPE_MOVE)
421 x += (outline->dest.x/(float)0xffff);
422 y += (outline->dest.y/(float)0xffff);
424 if(outline->type == SWF_PATHTYPE_LINE)
431 line(tag, p0, p1, m);
433 else if(outline->type == SWF_PATHTYPE_BEZIER)
436 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
439 p1.x=o2->C.x/(float)0xffff+lastx;
440 p1.y=o2->C.y/(float)0xffff+lasty;
441 p2.x=o2->B.x/(float)0xffff+lastx;
442 p2.y=o2->B.y/(float)0xffff+lasty;
445 spline(tag,p0,p1,p2,p3,m);
449 outline = outline->link;
453 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)
458 if(line_cap == LINE_CAP_BUTT || line_cap == LINE_CAP_SQUARE) {
461 SWF_OUTLINE *last, *tmp=outline;
462 plotxy s,e,p0,p1,p2,p3,m0,m1,m2,m3;
468 while(tmp && tmp->type != SWF_PATHTYPE_MOVE) {
470 lx += (tmp->dest.x/(float)0xffff);
471 ly += (tmp->dest.y/(float)0xffff);
474 s = getPivot(outline, 0, line_width, 0, 0);
475 e = getPivot(last, 0, line_width, 1, 0);
477 if(line_cap == LINE_CAP_BUTT) {
478 /* make the clipping rectangle slighly bigger
479 than the line ending, so that it get's clipped
489 p2.x = x2 - s.y - s.x*ee;
490 p2.y = y2 + s.x - s.y*ee;
491 p3.x = x2 - s.y + s.x*ee;
492 p3.y = y2 + s.x + s.y*ee;
497 m2.x = lx + e.y - e.x*ee;
498 m2.y = ly - e.x - e.y*ee;
499 m3.x = lx + e.y + e.x*ee;
500 m3.y = ly - e.x + e.y*ee;
502 for(nr=0;nr<2;nr++) {
504 struct plotxy q0,q1,q2,q3,q4,q5;
506 if(line_cap == LINE_CAP_BUTT) {
509 q1.x = sizex; q1.y = 0;
510 q2.x = sizex; q2.y = sizey;
511 q3.x = 0; q3.y = sizey;
513 q0.x = sizex; q0.y = sizey;
514 q1.x = 0; q1.y = sizey;
516 q3.x = sizex; q3.y = 0;
530 line(tag, p0, p1, m);
531 line(tag, p1, p2, m);
532 line(tag, p2, p3, m);
533 line(tag, p3, p0, m);
535 if(line_cap == LINE_CAP_BUTT) {
537 swf_ShapeSetEnd(tag);
538 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
539 swf_ObjectPlaceClip(tag,shapeid,depth,NULL,NULL,NULL,depth+2-nr);
553 drawShortPath(output,x,y,m,outline);
555 if(line_cap == LINE_CAP_BUTT) {
561 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)
563 plotxy d1,d2,p1,p2,p3,p4;
565 d1.x = (outline->dest.x/(float)0xffff);
566 d1.y = (outline->dest.y/(float)0xffff);
567 d2 = getPivot(outline, 0, line_width, 0, 0);
569 assert(line_cap != LINE_CAP_ROUND);
570 if(line_cap == LINE_CAP_SQUARE) {
579 p2.x = x + d2.x + d1.x;
580 p2.y = y + d2.y + d1.y;
581 p3.x = x - d2.x + d1.x;
582 p3.y = y - d2.y + d1.y;
592 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)
594 SWF_OUTLINE*tmp=outline;
600 drawT1toRect(output, x, y, m,outline, num, line_cap, line_join, line_width);
602 while(tmp->link && tmp->link->type!=SWF_PATHTYPE_MOVE) {
603 xx += (tmp->dest.x/(float)0xffff);
604 yy += (tmp->dest.y/(float)0xffff);
608 assert(tmp->type == SWF_PATHTYPE_LINE);
609 assert(outline->type == SWF_PATHTYPE_LINE);
613 if(outline->link == tmp) {
614 /* the two straight line segments (which are everything we
615 need to draw) are very likely to overlap. To avoid that
616 they cancel each other out at the end points, start a new
617 shape for the second one */
618 endshape();startshape(output);
622 drawT1toRect(output, xx, yy, m, tmp, num, line_cap, line_join, line_width);
624 if(outline->link != tmp)
628 tmp->type = SWF_PATHTYPE_MOVE;
629 x += (outline->dest.x/(float)0xffff);
630 y += (outline->dest.y/(float)0xffff);
631 outline = outline->link;
632 drawShortPath(output, x, y, m, outline);
640 static int t1len(SWF_OUTLINE*line)
643 while(line && line->type != SWF_PATHTYPE_MOVE) {
650 static float t1linelen(SWF_OUTLINE*line)
653 x = (line->dest.x/(float)0xffff);
654 y = (line->dest.y/(float)0xffff);
655 return sqrt(x*x+y*y);
658 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)
660 if(tag->id != ST_DEFINEFONT &&
661 tag->id != ST_DEFINESHAPE &&
662 tag->id != ST_DEFINESHAPE2 &&
663 tag->id != ST_DEFINESHAPE3) {
664 msg("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
669 double lastx=0,lasty=0;
672 SWF_OUTLINE*tmp = outline, *last = 0;
677 x += (tmp->dest.x/(float)0xffff);
678 y += (tmp->dest.y/(float)0xffff);
680 if(!tmp || tmp->type == SWF_PATHTYPE_MOVE) {
682 if(last->type == SWF_PATHTYPE_LINE && t1linelen(last)>line_width*2 &&
683 lastwasline && line_cap != LINE_CAP_ROUND)
684 drawShortPathWithStraightEnds(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
686 drawShortPathWithEnds(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
700 if(tmp && tmp->type == SWF_PATHTYPE_LINE && t1linelen(tmp)>line_width*2)
706 tmp->link->last = tmp; // make sure list is properly linked in both directions
711 static inline int colorcompare(RGBA*a,RGBA*b)
723 static const int CHARDATAMAX = 8192;
731 } chardata[CHARDATAMAX];
734 static void putcharacters(TAG*tag)
739 color.r = chardata[0].color.r^255;
748 int charadvance[128];
751 int glyphbits=1; //TODO: can this be zero?
754 if(tag->id != ST_DEFINETEXT &&
755 tag->id != ST_DEFINETEXT2) {
756 msg("<error> internal error: putcharacters needs an text tag, not %d\n",tag->id);
760 msg("<warning> putcharacters called with zero characters");
763 for(pass = 0; pass < 2; pass++)
773 advancebits++; // add sign bit
774 swf_SetU8(tag, glyphbits);
775 swf_SetU8(tag, advancebits);
778 for(t=0;t<=chardatapos;t++)
780 if(lastfontid != chardata[t].fontid ||
781 lastx!=chardata[t].x ||
782 lasty!=chardata[t].y ||
783 !colorcompare(&color, &chardata[t].color) ||
785 lastsize != chardata[t].size ||
788 if(charstorepos && pass==0)
791 for(s=0;s<charstorepos;s++)
793 while(charids[s]>=(1<<glyphbits))
795 while(charadvance[s]>=(1<<advancebits))
799 if(charstorepos && pass==1)
801 tag->writeBit = 0; // Q&D
802 swf_SetBits(tag, 0, 1); // GLYPH Record
803 swf_SetBits(tag, charstorepos, 7); // number of glyphs
805 for(s=0;s<charstorepos;s++)
807 swf_SetBits(tag, charids[s], glyphbits);
808 swf_SetBits(tag, charadvance[s], advancebits);
813 if(pass == 1 && t<chardatapos)
819 if(lastx != chardata[t].x ||
820 lasty != chardata[t].y)
822 newx = chardata[t].x;
823 newy = chardata[t].y;
829 if(!colorcompare(&color, &chardata[t].color))
831 color = chardata[t].color;
834 font.id = chardata[t].fontid;
835 if(lastfontid != chardata[t].fontid || lastsize != chardata[t].size)
838 tag->writeBit = 0; // Q&D
839 swf_TextSetInfoRecord(tag, newfont, chardata[t].size, newcolor, newx,newy);
842 lastfontid = chardata[t].fontid;
843 lastx = chardata[t].x;
844 lasty = chardata[t].y;
845 lastsize = chardata[t].size;
852 int nextt = t==chardatapos-1?t:t+1;
853 int rel = chardata[nextt].x-chardata[t].x;
854 if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) {
856 lastx=chardata[nextt].x;
862 charids[charstorepos] = chardata[t].charid;
863 charadvance[charstorepos] = advance;
870 static void putcharacter(struct swfoutput*obj, int fontid, int charid,
871 int x,int y, int size)
873 if(chardatapos == CHARDATAMAX)
875 msg("<warning> Character buffer too small. SWF will be slightly bigger");
879 chardata[chardatapos].fontid = fontid;
880 chardata[chardatapos].charid = charid;
881 chardata[chardatapos].x = x;
882 chardata[chardatapos].y = y;
883 chardata[chardatapos].color = obj->fillrgb;
884 chardata[chardatapos].size = size;
889 /* process a character. */
890 static int drawchar(struct swfoutput*obj, SWFFONT *swffont, char*character, int charnr, int u, swfmatrix*m)
893 if(m->m12!=0 || m->m21!=0)
899 msg("<warning> Font is NULL");
902 //if(usefonts && ! drawonlyshapes)
905 int charid = getCharID(swffont, charnr, character, u);
908 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
909 FIXNULL(character),charnr, u, FIXNULL((char*)swffont->name), swffont->numchars);
917 putcharacter(obj, swffont->id, charid,(int)(m->m13*20),(int)(m->m23*20),
923 SWF_OUTLINE*outline = font->getOutline(character, charnr);
924 char* charname = character;
927 msg("<warning> Didn't find character '%s' (%d) in current charset (%s)",
928 FIXNULL(character),charnr,FIXNULL(font->getName()));
947 drawpath(tag, outline, &m2, 0);
952 /* draw a curved polygon. */
953 void swfoutput_drawpath(swfoutput*output, SWF_OUTLINE*outline,
959 /* Multiple polygons in one shape don't overlap correctly,
960 so we better start a new shape here if the polygon is filled
962 if(shapeid>=0 && fill && !ignoredraworder) {
974 drawpath(tag, outline,m, 0);
977 void swfoutput_drawpath2poly(struct swfoutput*output, SWF_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
987 drawpath2poly(output, outline, m, 0, line_join, line_cap, line_width, miter_limit);
990 int getCharID(SWFFONT *font, int charnr, char *charname, int u)
994 for(t=0;t<font->numchars;t++) {
995 if(font->glyphnames[t] && !strcmp(font->glyphnames[t],charname)) {
999 /* if we didn't find the character, maybe
1000 we can find the capitalized version */
1001 for(t=0;t<font->numchars;t++) {
1002 if(font->glyphnames[t] && !strcasecmp(font->glyphnames[t],charname)) {
1009 if(u>=font->maxascii)
1010 msg("<debug> u=%d, font->maxascii=%d",u,font->maxascii);
1012 msg("<debug> u=%d, font->maxascii=%d ascci2glyph[%d]=%d",u,font->maxascii,u,font->ascii2glyph[u]);
1014 /* try to use the unicode id */
1015 if(u>=0 && u<font->maxascii && font->ascii2glyph[u]>=0)
1016 return font->ascii2glyph[u];
1019 if(charnr>=0 && charnr<font->numchars)
1030 /* set's the t1 font index of the font to use for swfoutput_drawchar(). */
1031 void swfoutput_setfont(struct swfoutput*obj, char*fontid, char*filename)
1033 fontlist_t*last=0,*iterator;
1035 msg("<error> No fontid");
1039 if(obj->swffont && obj->swffont->name && !strcmp((char*)obj->swffont->name,fontid))
1042 iterator = fontlist;
1044 if(!strcmp((char*)iterator->swffont->name,fontid)) {
1045 obj->swffont = iterator->swffont;
1049 iterator = iterator->next;
1053 msg("<error> No filename given for font- internal error?");
1057 /* TODO: sometimes, scale has to be 64, and sometimes 32.
1058 It's probably font format related */
1059 swf_SetLoadFontParameters(32, 0);
1061 SWFFONT *swffont = swf_LoadFont(filename);
1062 swf_FontSetID(swffont, ++currentswfid);
1064 if(screenloglevel >= LOGLEVEL_DEBUG) {
1065 // print font information
1066 msg("<debug> Font %s (%s)",swffont->name, filename);
1067 msg("<debug> | ID: %d", swffont->id);
1068 msg("<debug> | Version: %d", swffont->version);
1069 msg("<debug> | Name: %s", fontid);
1070 msg("<debug> | Numchars: %d", swffont->numchars);
1071 msg("<debug> | Maxascii: %d", swffont->maxascii);
1072 msg("<debug> | Style: %d", swffont->style);
1073 msg("<debug> | Encoding: %d", swffont->encoding);
1074 for(int iii=0; iii<swffont->numchars;iii++) {
1075 msg("<debug> | Glyph %d) name=%s, unicode=%d\n", iii, swffont->glyphnames[iii], swffont->glyph2ascii[iii]);
1079 /* set the font name to the ID we use here */
1080 if(swffont->name) free(swffont->name);
1081 swffont->name = (U8*)strdup(fontid);
1083 iterator = new fontlist_t;
1084 iterator->swffont = swffont;
1088 last->next = iterator;
1090 fontlist = iterator;
1092 obj->swffont = swffont;
1095 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1097 fontlist_t *iterator = fontlist;
1099 if(!strcmp((char*)iterator->swffont->name,fontid))
1101 iterator = iterator->next;
1106 /* set's the matrix which is to be applied to characters drawn by
1107 swfoutput_drawchar() */
1108 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1109 double m21,double m22)
1111 if(obj->fontm11 == m11 &&
1112 obj->fontm12 == m12 &&
1113 obj->fontm21 == m21 &&
1114 obj->fontm22 == m22)
1124 /* draws a character at x,y. */
1125 int swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr, int u)
1128 m.m11 = obj->fontm11;
1129 m.m12 = obj->fontm12;
1130 m.m21 = obj->fontm21;
1131 m.m22 = obj->fontm22;
1134 return drawchar(obj, obj->swffont, character, charnr, u, &m);
1137 /* initialize the swf writer */
1138 void swfoutput_init(struct swfoutput* obj, char*_filename, int x1, int y1, int x2, int y2)
1142 memset(obj, 0, sizeof(struct swfoutput));
1143 filename = _filename;
1147 msg("<verbose> initializing swf output for size %d*%d\n", sizex,sizey);
1151 memset(&swf,0x00,sizeof(SWF));
1153 swf.fileVersion = flashversion;
1154 swf.frameRate = 0x0040; // 1 frame per 4 seconds
1155 swf.movieSize.xmin = 20*x1;
1156 swf.movieSize.ymin = 20*y1;
1157 swf.movieSize.xmax = 20*x2;
1158 swf.movieSize.ymax = 20*y2;
1162 swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1164 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1165 swf_SetRGB(tag,&rgb);
1167 if(1)/* add white rectangle */
1172 int shapeid = ++currentswfid;
1177 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
1179 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1180 swf_SetU16(tag,shapeid);
1181 swf_SetRect(tag,&r);
1182 swf_SetShapeHeader(tag,s);
1183 swf_ShapeSetAll(tag,s,x1*20,y1*20,ls1,fs1,0);
1184 swf_ShapeSetLine(tag,s,20*(x2-x1),0);
1185 swf_ShapeSetLine(tag,s,0,20*(y2-y1));
1186 swf_ShapeSetLine(tag,s,20*(x1-x2),0);
1187 swf_ShapeSetLine(tag,s,0,20*(y1-y2));
1188 swf_ShapeSetEnd(tag);
1190 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1191 swf_ObjectPlace(tag,shapeid,depth++,0,0,0);
1192 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1193 swf_ObjectPlaceClip(tag,shapeid,depth++,0,0,0,65535);
1197 tag = swf_InsertTag(tag, ST_PROTECT);
1202 void swfoutput_setprotected() //write PROTECT tag
1207 static void startshape(struct swfoutput*obj)
1215 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1217 swf_ShapeNew(&shape);
1218 linestyleid = swf_ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1219 rgb.r = obj->fillrgb.r;
1220 rgb.g = obj->fillrgb.g;
1221 rgb.b = obj->fillrgb.b;
1222 fillstyleid = swf_ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1224 shapeid = ++currentswfid;
1225 swf_SetU16(tag,shapeid); // ID
1232 swf_SetRect(tag,&r);
1234 swf_SetShapeStyles(tag,shape);
1235 swf_ShapeCountBits(shape,NULL,NULL);
1236 swf_SetShapeBits(tag,shape);
1238 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,linestyleid,0,0);
1239 swflastx=swflasty=0;
1244 static void starttext(struct swfoutput*obj)
1250 tag = swf_InsertTag(tag,ST_DEFINETEXT);
1251 textid = ++currentswfid;
1252 swf_SetU16(tag, textid);
1259 swf_SetRect(tag,&r);
1268 swf_SetMatrix(tag,&m);
1269 swflastx=swflasty=0;
1272 static void endshape()
1276 swf_ShapeSetEnd(tag);
1279 msg("<warning> empty shape");
1283 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1284 swf_ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL);
1288 static void endtext()
1294 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1295 swf_ObjectPlace(tag,textid,/*depth*/depth++,NULL,NULL,NULL);
1299 static void endpage(struct swfoutput*obj)
1306 swfoutput_endclip(obj);
1310 atag = action_Stop(atag);
1311 atag = action_End(atag);
1312 tag = swf_InsertTag(tag,ST_DOACTION);
1313 swf_ActionSet(tag,atag);
1315 tag = swf_InsertTag(tag,ST_SHOWFRAME);
1318 void swfoutput_newpage(struct swfoutput*obj)
1322 for(depth--;depth>=startdepth;depth--) {
1323 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1324 swf_SetU16(tag,depth);
1330 /* "destroy" like in (oo-terminology) "destructor". Perform cleaning
1331 up, complete the swf, and write it out. */
1332 void swfoutput_destroy(struct swfoutput* obj)
1335 fontlist_t *tmp,*iterator = fontlist;
1337 TAG*mtag = swf.firstTag;
1338 if(iterator->swffont) {
1339 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1340 swf_FontSetDefine2(mtag, iterator->swffont);
1341 swf_FontFree(iterator->swffont);
1345 iterator = iterator->next;
1352 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1357 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1361 tag = swf_InsertTag(tag,ST_END);
1364 if FAILED(swf_WriteSWC(fi,&swf))
1365 msg("<error> WriteSWC() failed.\n");
1367 if FAILED(swf_WriteSWF(fi,&swf))
1368 msg("<error> WriteSWF() failed.\n");
1373 msg("<notice> SWF written\n");
1376 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1379 if(mode == DRAWMODE_FILL)
1381 else if(mode == DRAWMODE_EOFILL)
1383 else if(mode == DRAWMODE_STROKE)
1385 else if(mode == DRAWMODE_CLIP)
1387 else if(mode == DRAWMODE_EOCLIP)
1391 void swfoutput_setfillcolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1393 if(obj->fillrgb.r == r &&
1394 obj->fillrgb.g == g &&
1395 obj->fillrgb.b == b &&
1396 obj->fillrgb.a == a) return;
1406 void swfoutput_setstrokecolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1408 if(obj->strokergb.r == r &&
1409 obj->strokergb.g == g &&
1410 obj->strokergb.b == b &&
1411 obj->strokergb.a == a) return;
1415 obj->strokergb.r = r;
1416 obj->strokergb.g = g;
1417 obj->strokergb.b = b;
1418 obj->strokergb.a = a;
1421 void swfoutput_setlinewidth(struct swfoutput*obj, double linewidth)
1423 if(obj->linewidth == (u16)(linewidth*20))
1428 obj->linewidth = (u16)(linewidth*20);
1432 void swfoutput_startclip(swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m)
1441 msg("<warning> Too many clip levels.");
1446 int olddrawmode = drawmode;
1447 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1448 swfoutput_drawpath(obj, outline, m);
1449 swf_ShapeSetEnd(tag);
1450 swfoutput_setdrawmode(obj, olddrawmode);
1452 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1453 cliptags[clippos] = tag;
1454 clipshapes[clippos] = shapeid;
1455 clipdepths[clippos] = depth++;
1460 void swfoutput_endclip(swfoutput*obj)
1468 msg("<error> Invalid end of clipping region");
1472 swf_ObjectPlaceClip(cliptags[clippos],clipshapes[clippos],clipdepths[clippos],NULL,NULL,NULL,depth++);
1475 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1477 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1480 if(!strncmp("http://pdf2swf:", url, 15)) {
1481 char*tmp = strdup(url);
1482 int l = strlen(tmp);
1485 swfoutput_namedlink(obj, tmp+15, points);
1496 actions = action_GetUrl(0, url, "_parent");
1498 actions = action_GetUrl(0, url, "_this");
1499 actions = action_End(actions);
1501 drawlink(obj, actions, 0, points,0);
1503 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1512 actions = action_GotoFrame(0, page);
1513 actions = action_End(actions);
1515 drawlink(obj, actions, 0, points,0);
1518 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
1519 of the viewer objects, like subtitles, index elements etc.
1521 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
1523 ActionTAG *actions1,*actions2;
1524 char*tmp = strdup(name);
1532 if(!strncmp(tmp, "call:", 5))
1534 char*x = strchr(&tmp[5], ':');
1536 actions1 = action_PushInt(0, 0); //number of parameters (0)
1537 actions1 = action_PushString(actions1, &tmp[5]); //function name
1538 actions1 = action_CallFunction(actions1);
1541 actions1 = action_PushString(0, x+1); //parameter
1542 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
1543 actions1 = action_PushString(actions1, &tmp[5]); //function name
1544 actions1 = action_CallFunction(actions1);
1546 actions2 = action_End(0);
1551 actions1 = action_PushString(0, "/:subtitle");
1552 actions1 = action_PushString(actions1, name);
1553 actions1 = action_SetVariable(actions1);
1554 actions1 = action_End(actions1);
1556 actions2 = action_PushString(0, "/:subtitle");
1557 actions2 = action_PushString(actions2, "");
1558 actions2 = action_SetVariable(actions2);
1559 actions2 = action_End(actions2);
1562 drawlink(obj, actions1, actions2, points,mouseover);
1564 swf_ActionFree(actions1);
1565 swf_ActionFree(actions2);
1569 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
1575 struct plotxy p1,p2,p3,p4;
1579 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
1583 int buttonid = ++currentswfid;
1586 if(points[t].x>xmax) xmax=points[t].x;
1587 if(points[t].y>ymax) ymax=points[t].y;
1588 if(points[t].x<xmin) xmin=points[t].x;
1589 if(points[t].y<ymin) ymin=points[t].y;
1592 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
1593 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
1595 /* the following code subtracts the upper left edge from all coordinates,
1596 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
1597 Necessary for preprocessing with swfcombine. */
1598 posx = xmin; posy = ymin;
1599 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
1600 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
1601 xmin -= posx; ymin -= posy;
1602 xmax -= posx; ymax -= posy;
1605 myshapeid = ++currentswfid;
1606 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1607 swf_ShapeNew(&shape);
1608 rgb.r = rgb.b = rgb.a = rgb.g = 0;
1609 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1610 swf_SetU16(tag, myshapeid);
1611 r.xmin = (int)(xmin*20);
1612 r.ymin = (int)(ymin*20);
1613 r.xmax = (int)(xmax*20);
1614 r.ymax = (int)(ymax*20);
1615 swf_SetRect(tag,&r);
1616 swf_SetShapeStyles(tag,shape);
1617 swf_ShapeCountBits(shape,NULL,NULL);
1618 swf_SetShapeBits(tag,shape);
1619 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1620 swflastx = swflasty = 0;
1626 swf_ShapeSetEnd(tag);
1629 myshapeid2 = ++currentswfid;
1630 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1631 swf_ShapeNew(&shape);
1632 rgb.r = rgb.b = rgb.a = rgb.g = 255;
1634 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1635 swf_SetU16(tag, myshapeid2);
1636 r.xmin = (int)(xmin*20);
1637 r.ymin = (int)(ymin*20);
1638 r.xmax = (int)(xmax*20);
1639 r.ymax = (int)(ymax*20);
1640 swf_SetRect(tag,&r);
1641 swf_SetShapeStyles(tag,shape);
1642 swf_ShapeCountBits(shape,NULL,NULL);
1643 swf_SetShapeBits(tag,shape);
1644 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1645 swflastx = swflasty = 0;
1651 swf_ShapeSetEnd(tag);
1655 tag = swf_InsertTag(tag,ST_DEFINEBUTTON);
1656 swf_SetU16(tag,buttonid); //id
1657 swf_ButtonSetFlags(tag, 0); //menu=no
1658 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1659 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1660 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1661 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1663 swf_ActionSet(tag,actions1);
1668 tag = swf_InsertTag(tag,ST_DEFINEBUTTON2);
1669 swf_SetU16(tag,buttonid); //id
1670 swf_ButtonSetFlags(tag, 0); //menu=no
1671 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1672 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1673 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1674 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1675 swf_SetU8(tag,0); // end of button records
1676 swf_ButtonSetCondition(tag, BC_IDLE_OVERUP);
1677 swf_ActionSet(tag,actions1);
1679 swf_ButtonSetCondition(tag, BC_OVERUP_IDLE);
1680 swf_ActionSet(tag,actions2);
1682 swf_ButtonPostProcess(tag, 2);
1685 swf_ButtonPostProcess(tag, 1);
1689 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1691 if(posx!=0 || posy!=0) {
1693 swf_GetMatrix(0,&m);
1694 m.tx = (int)(posx*20);
1695 m.ty = (int)(posy*20);
1696 swf_ObjectPlace(tag, buttonid, depth++,&m,0,0);
1699 swf_ObjectPlace(tag, buttonid, depth++,0,0,0);
1703 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
1704 double x1,double y1,
1705 double x2,double y2,
1706 double x3,double y3,
1707 double x4,double y4)
1713 struct plotxy p1,p2,p3,p4;
1715 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
1716 if(x2>xmax) xmax=x2;
1717 if(y2>ymax) ymax=y2;
1718 if(x2<xmin) xmin=x2;
1719 if(y2<ymin) ymin=y2;
1720 if(x3>xmax) xmax=x3;
1721 if(y3>ymax) ymax=y3;
1722 if(x3<xmin) xmin=x3;
1723 if(y3<ymin) ymin=y3;
1724 if(x4>xmax) xmax=x4;
1725 if(y4>ymax) ymax=y4;
1726 if(x4<xmin) xmin=x4;
1727 if(y4<ymin) ymin=y4;
1733 {p1.x = (int)(p1.x*20)/20.0;
1734 p1.y = (int)(p1.y*20)/20.0;
1735 p2.x = (int)(p2.x*20)/20.0;
1736 p2.y = (int)(p2.y*20)/20.0;
1737 p3.x = (int)(p3.x*20)/20.0;
1738 p3.y = (int)(p3.y*20)/20.0;
1739 p4.x = (int)(p4.x*20)/20.0;
1740 p4.y = (int)(p4.y*20)/20.0;}
1743 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
1744 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
1745 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
1746 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
1748 m.tx = (int)(p1.x*20);
1749 m.ty = (int)(p1.y*20);
1752 myshapeid = ++currentswfid;
1753 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1754 swf_ShapeNew(&shape);
1755 //lsid = ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1756 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1757 fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
1758 swf_SetU16(tag, myshapeid);
1759 r.xmin = (int)(xmin*20);
1760 r.ymin = (int)(ymin*20);
1761 r.xmax = (int)(xmax*20);
1762 r.ymax = (int)(ymax*20);
1763 swf_SetRect(tag,&r);
1764 swf_SetShapeStyles(tag,shape);
1765 swf_ShapeCountBits(shape,NULL,NULL);
1766 swf_SetShapeBits(tag,shape);
1767 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,lsid,fsid,0);
1768 swflastx = swflasty = 0;
1775 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
1776 ShapeSetLine (tag, shape, (int)(x1*20);
1777 ShapeSetLine (tag, shape, x*20,0);
1778 ShapeSetLine (tag, shape, 0,-y*20);
1779 ShapeSetLine (tag, shape, -x*20,0);*/
1780 swf_ShapeSetEnd(tag);
1783 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1784 swf_ObjectPlace(tag,myshapeid,/*depth*/depth++,NULL,NULL,NULL);
1787 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
1788 double x1,double y1,
1789 double x2,double y2,
1790 double x3,double y3,
1791 double x4,double y4)
1799 int bitid = ++currentswfid;
1801 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
1802 swf_SetU16(tag, bitid);
1803 if(swf_SetJPEGBits(tag, filename, jpegquality)<0) {
1809 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1813 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
1814 double x1,double y1,
1815 double x2,double y2,
1816 double x3,double y3,
1817 double x4,double y4)
1827 int bitid = ++currentswfid;
1829 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
1830 swf_SetU16(tag, bitid);
1831 swf_SetJPEGBits2(tag,sizex,sizey,mem,jpegquality);
1832 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1836 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
1837 double x1,double y1,
1838 double x2,double y2,
1839 double x3,double y3,
1840 double x4,double y4)
1848 int bitid = ++currentswfid;
1850 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS);
1851 swf_SetU16(tag, bitid);
1852 if(swf_SetLosslessBits(tag,sizex,sizey,mem, BMF_32BIT)<0) {
1858 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1862 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
1863 double x1,double y1,
1864 double x2,double y2,
1865 double x3,double y3,
1866 double x4,double y4, int n)
1877 /* SWF expects scanlines to be 4 byte aligned */
1880 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
1882 for(y=0;y<sizey;y++)
1884 for(x=0;x<sizex;x++)
1885 *ptr++ = mem[y*sizex+x];
1886 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
1891 int bitid = ++currentswfid;
1893 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS2);
1894 swf_SetU16(tag, bitid);
1895 if(swf_SetLosslessBitsIndexed(tag,sizex,sizey,mem, pal, n)<0) {
1903 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1907 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
1908 double x1,double y1,
1909 double x2,double y2,
1910 double x3,double y3,
1911 double x4,double y4)
1919 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);