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);
1064 msg("<error> Coudln't load font %s (%s)", fontid, filename);
1065 swffont = swf_LoadFont(0);
1068 swf_FontSetID(swffont, ++currentswfid);
1070 if(screenloglevel >= LOGLEVEL_DEBUG) {
1071 // print font information
1072 msg("<debug> Font %s (%s)",swffont->name, filename);
1073 msg("<debug> | ID: %d", swffont->id);
1074 msg("<debug> | Version: %d", swffont->version);
1075 msg("<debug> | Name: %s", fontid);
1076 msg("<debug> | Numchars: %d", swffont->numchars);
1077 msg("<debug> | Maxascii: %d", swffont->maxascii);
1078 msg("<debug> | Style: %d", swffont->style);
1079 msg("<debug> | Encoding: %d", swffont->encoding);
1080 for(int iii=0; iii<swffont->numchars;iii++) {
1081 msg("<debug> | Glyph %d) name=%s, unicode=%d\n", iii, swffont->glyphnames[iii], swffont->glyph2ascii[iii]);
1085 /* set the font name to the ID we use here */
1086 if(swffont->name) free(swffont->name);
1087 swffont->name = (U8*)strdup(fontid);
1089 iterator = new fontlist_t;
1090 iterator->swffont = swffont;
1094 last->next = iterator;
1096 fontlist = iterator;
1098 obj->swffont = swffont;
1101 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1103 fontlist_t *iterator = fontlist;
1105 if(!strcmp((char*)iterator->swffont->name,fontid))
1107 iterator = iterator->next;
1112 /* set's the matrix which is to be applied to characters drawn by
1113 swfoutput_drawchar() */
1114 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1115 double m21,double m22)
1117 if(obj->fontm11 == m11 &&
1118 obj->fontm12 == m12 &&
1119 obj->fontm21 == m21 &&
1120 obj->fontm22 == m22)
1130 /* draws a character at x,y. */
1131 int swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr, int u)
1134 m.m11 = obj->fontm11;
1135 m.m12 = obj->fontm12;
1136 m.m21 = obj->fontm21;
1137 m.m22 = obj->fontm22;
1140 return drawchar(obj, obj->swffont, character, charnr, u, &m);
1143 /* initialize the swf writer */
1144 void swfoutput_init(struct swfoutput* obj, char*_filename, int x1, int y1, int x2, int y2)
1148 memset(obj, 0, sizeof(struct swfoutput));
1149 filename = _filename;
1153 msg("<verbose> initializing swf output for size %d*%d\n", sizex,sizey);
1157 memset(&swf,0x00,sizeof(SWF));
1159 swf.fileVersion = flashversion;
1160 swf.frameRate = 0x0040; // 1 frame per 4 seconds
1161 swf.movieSize.xmin = 20*x1;
1162 swf.movieSize.ymin = 20*y1;
1163 swf.movieSize.xmax = 20*x2;
1164 swf.movieSize.ymax = 20*y2;
1168 swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1170 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1171 swf_SetRGB(tag,&rgb);
1173 if(1)/* add white rectangle */
1178 int shapeid = ++currentswfid;
1183 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
1185 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1186 swf_SetU16(tag,shapeid);
1187 swf_SetRect(tag,&r);
1188 swf_SetShapeHeader(tag,s);
1189 swf_ShapeSetAll(tag,s,x1*20,y1*20,ls1,fs1,0);
1190 swf_ShapeSetLine(tag,s,20*(x2-x1),0);
1191 swf_ShapeSetLine(tag,s,0,20*(y2-y1));
1192 swf_ShapeSetLine(tag,s,20*(x1-x2),0);
1193 swf_ShapeSetLine(tag,s,0,20*(y1-y2));
1194 swf_ShapeSetEnd(tag);
1196 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1197 swf_ObjectPlace(tag,shapeid,depth++,0,0,0);
1198 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1199 swf_ObjectPlaceClip(tag,shapeid,depth++,0,0,0,65535);
1203 tag = swf_InsertTag(tag, ST_PROTECT);
1208 void swfoutput_setprotected() //write PROTECT tag
1213 static void startshape(struct swfoutput*obj)
1221 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1223 swf_ShapeNew(&shape);
1224 linestyleid = swf_ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1225 rgb.r = obj->fillrgb.r;
1226 rgb.g = obj->fillrgb.g;
1227 rgb.b = obj->fillrgb.b;
1228 fillstyleid = swf_ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1230 shapeid = ++currentswfid;
1231 swf_SetU16(tag,shapeid); // ID
1238 swf_SetRect(tag,&r);
1240 swf_SetShapeStyles(tag,shape);
1241 swf_ShapeCountBits(shape,NULL,NULL);
1242 swf_SetShapeBits(tag,shape);
1244 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,linestyleid,0,0);
1245 swflastx=swflasty=0;
1250 static void starttext(struct swfoutput*obj)
1256 tag = swf_InsertTag(tag,ST_DEFINETEXT);
1257 textid = ++currentswfid;
1258 swf_SetU16(tag, textid);
1265 swf_SetRect(tag,&r);
1274 swf_SetMatrix(tag,&m);
1275 swflastx=swflasty=0;
1278 static void endshape()
1282 swf_ShapeSetEnd(tag);
1285 msg("<warning> empty shape");
1289 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1290 swf_ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL);
1294 static void endtext()
1300 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1301 swf_ObjectPlace(tag,textid,/*depth*/depth++,NULL,NULL,NULL);
1305 static void endpage(struct swfoutput*obj)
1312 swfoutput_endclip(obj);
1316 atag = action_Stop(atag);
1317 atag = action_End(atag);
1318 tag = swf_InsertTag(tag,ST_DOACTION);
1319 swf_ActionSet(tag,atag);
1321 tag = swf_InsertTag(tag,ST_SHOWFRAME);
1324 void swfoutput_newpage(struct swfoutput*obj)
1328 for(depth--;depth>=startdepth;depth--) {
1329 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1330 swf_SetU16(tag,depth);
1336 /* "destroy" like in (oo-terminology) "destructor". Perform cleaning
1337 up, complete the swf, and write it out. */
1338 void swfoutput_destroy(struct swfoutput* obj)
1341 fontlist_t *tmp,*iterator = fontlist;
1343 TAG*mtag = swf.firstTag;
1344 if(iterator->swffont) {
1345 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1346 swf_FontSetDefine2(mtag, iterator->swffont);
1347 swf_FontFree(iterator->swffont);
1351 iterator = iterator->next;
1358 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1363 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1367 tag = swf_InsertTag(tag,ST_END);
1370 if FAILED(swf_WriteSWC(fi,&swf))
1371 msg("<error> WriteSWC() failed.\n");
1373 if FAILED(swf_WriteSWF(fi,&swf))
1374 msg("<error> WriteSWF() failed.\n");
1379 msg("<notice> SWF written\n");
1382 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1385 if(mode == DRAWMODE_FILL)
1387 else if(mode == DRAWMODE_EOFILL)
1389 else if(mode == DRAWMODE_STROKE)
1391 else if(mode == DRAWMODE_CLIP)
1393 else if(mode == DRAWMODE_EOCLIP)
1397 void swfoutput_setfillcolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1399 if(obj->fillrgb.r == r &&
1400 obj->fillrgb.g == g &&
1401 obj->fillrgb.b == b &&
1402 obj->fillrgb.a == a) return;
1412 void swfoutput_setstrokecolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1414 if(obj->strokergb.r == r &&
1415 obj->strokergb.g == g &&
1416 obj->strokergb.b == b &&
1417 obj->strokergb.a == a) return;
1421 obj->strokergb.r = r;
1422 obj->strokergb.g = g;
1423 obj->strokergb.b = b;
1424 obj->strokergb.a = a;
1427 void swfoutput_setlinewidth(struct swfoutput*obj, double linewidth)
1429 if(obj->linewidth == (u16)(linewidth*20))
1434 obj->linewidth = (u16)(linewidth*20);
1438 void swfoutput_startclip(swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m)
1447 msg("<warning> Too many clip levels.");
1452 int olddrawmode = drawmode;
1453 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1454 swfoutput_drawpath(obj, outline, m);
1455 swf_ShapeSetEnd(tag);
1456 swfoutput_setdrawmode(obj, olddrawmode);
1458 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1459 cliptags[clippos] = tag;
1460 clipshapes[clippos] = shapeid;
1461 clipdepths[clippos] = depth++;
1466 void swfoutput_endclip(swfoutput*obj)
1474 msg("<error> Invalid end of clipping region");
1478 swf_ObjectPlaceClip(cliptags[clippos],clipshapes[clippos],clipdepths[clippos],NULL,NULL,NULL,depth++);
1481 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1483 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1486 if(!strncmp("http://pdf2swf:", url, 15)) {
1487 char*tmp = strdup(url);
1488 int l = strlen(tmp);
1491 swfoutput_namedlink(obj, tmp+15, points);
1502 actions = action_GetUrl(0, url, "_parent");
1504 actions = action_GetUrl(0, url, "_this");
1505 actions = action_End(actions);
1507 drawlink(obj, actions, 0, points,0);
1509 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1518 actions = action_GotoFrame(0, page);
1519 actions = action_End(actions);
1521 drawlink(obj, actions, 0, points,0);
1524 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
1525 of the viewer objects, like subtitles, index elements etc.
1527 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
1529 ActionTAG *actions1,*actions2;
1530 char*tmp = strdup(name);
1538 if(!strncmp(tmp, "call:", 5))
1540 char*x = strchr(&tmp[5], ':');
1542 actions1 = action_PushInt(0, 0); //number of parameters (0)
1543 actions1 = action_PushString(actions1, &tmp[5]); //function name
1544 actions1 = action_CallFunction(actions1);
1547 actions1 = action_PushString(0, x+1); //parameter
1548 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
1549 actions1 = action_PushString(actions1, &tmp[5]); //function name
1550 actions1 = action_CallFunction(actions1);
1552 actions2 = action_End(0);
1557 actions1 = action_PushString(0, "/:subtitle");
1558 actions1 = action_PushString(actions1, name);
1559 actions1 = action_SetVariable(actions1);
1560 actions1 = action_End(actions1);
1562 actions2 = action_PushString(0, "/:subtitle");
1563 actions2 = action_PushString(actions2, "");
1564 actions2 = action_SetVariable(actions2);
1565 actions2 = action_End(actions2);
1568 drawlink(obj, actions1, actions2, points,mouseover);
1570 swf_ActionFree(actions1);
1571 swf_ActionFree(actions2);
1575 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
1581 struct plotxy p1,p2,p3,p4;
1585 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
1589 int buttonid = ++currentswfid;
1592 if(points[t].x>xmax) xmax=points[t].x;
1593 if(points[t].y>ymax) ymax=points[t].y;
1594 if(points[t].x<xmin) xmin=points[t].x;
1595 if(points[t].y<ymin) ymin=points[t].y;
1598 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
1599 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
1601 /* the following code subtracts the upper left edge from all coordinates,
1602 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
1603 Necessary for preprocessing with swfcombine. */
1604 posx = xmin; posy = ymin;
1605 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
1606 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
1607 xmin -= posx; ymin -= posy;
1608 xmax -= posx; ymax -= posy;
1611 myshapeid = ++currentswfid;
1612 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1613 swf_ShapeNew(&shape);
1614 rgb.r = rgb.b = rgb.a = rgb.g = 0;
1615 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1616 swf_SetU16(tag, myshapeid);
1617 r.xmin = (int)(xmin*20);
1618 r.ymin = (int)(ymin*20);
1619 r.xmax = (int)(xmax*20);
1620 r.ymax = (int)(ymax*20);
1621 swf_SetRect(tag,&r);
1622 swf_SetShapeStyles(tag,shape);
1623 swf_ShapeCountBits(shape,NULL,NULL);
1624 swf_SetShapeBits(tag,shape);
1625 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1626 swflastx = swflasty = 0;
1632 swf_ShapeSetEnd(tag);
1635 myshapeid2 = ++currentswfid;
1636 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1637 swf_ShapeNew(&shape);
1638 rgb.r = rgb.b = rgb.a = rgb.g = 255;
1640 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1641 swf_SetU16(tag, myshapeid2);
1642 r.xmin = (int)(xmin*20);
1643 r.ymin = (int)(ymin*20);
1644 r.xmax = (int)(xmax*20);
1645 r.ymax = (int)(ymax*20);
1646 swf_SetRect(tag,&r);
1647 swf_SetShapeStyles(tag,shape);
1648 swf_ShapeCountBits(shape,NULL,NULL);
1649 swf_SetShapeBits(tag,shape);
1650 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1651 swflastx = swflasty = 0;
1657 swf_ShapeSetEnd(tag);
1661 tag = swf_InsertTag(tag,ST_DEFINEBUTTON);
1662 swf_SetU16(tag,buttonid); //id
1663 swf_ButtonSetFlags(tag, 0); //menu=no
1664 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1665 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1666 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1667 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1669 swf_ActionSet(tag,actions1);
1674 tag = swf_InsertTag(tag,ST_DEFINEBUTTON2);
1675 swf_SetU16(tag,buttonid); //id
1676 swf_ButtonSetFlags(tag, 0); //menu=no
1677 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1678 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1679 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1680 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1681 swf_SetU8(tag,0); // end of button records
1682 swf_ButtonSetCondition(tag, BC_IDLE_OVERUP);
1683 swf_ActionSet(tag,actions1);
1685 swf_ButtonSetCondition(tag, BC_OVERUP_IDLE);
1686 swf_ActionSet(tag,actions2);
1688 swf_ButtonPostProcess(tag, 2);
1691 swf_ButtonPostProcess(tag, 1);
1695 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1697 if(posx!=0 || posy!=0) {
1699 swf_GetMatrix(0,&m);
1700 m.tx = (int)(posx*20);
1701 m.ty = (int)(posy*20);
1702 swf_ObjectPlace(tag, buttonid, depth++,&m,0,0);
1705 swf_ObjectPlace(tag, buttonid, depth++,0,0,0);
1709 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
1710 double x1,double y1,
1711 double x2,double y2,
1712 double x3,double y3,
1713 double x4,double y4)
1719 struct plotxy p1,p2,p3,p4;
1721 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
1722 if(x2>xmax) xmax=x2;
1723 if(y2>ymax) ymax=y2;
1724 if(x2<xmin) xmin=x2;
1725 if(y2<ymin) ymin=y2;
1726 if(x3>xmax) xmax=x3;
1727 if(y3>ymax) ymax=y3;
1728 if(x3<xmin) xmin=x3;
1729 if(y3<ymin) ymin=y3;
1730 if(x4>xmax) xmax=x4;
1731 if(y4>ymax) ymax=y4;
1732 if(x4<xmin) xmin=x4;
1733 if(y4<ymin) ymin=y4;
1739 {p1.x = (int)(p1.x*20)/20.0;
1740 p1.y = (int)(p1.y*20)/20.0;
1741 p2.x = (int)(p2.x*20)/20.0;
1742 p2.y = (int)(p2.y*20)/20.0;
1743 p3.x = (int)(p3.x*20)/20.0;
1744 p3.y = (int)(p3.y*20)/20.0;
1745 p4.x = (int)(p4.x*20)/20.0;
1746 p4.y = (int)(p4.y*20)/20.0;}
1749 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
1750 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
1751 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
1752 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
1754 m.tx = (int)(p1.x*20);
1755 m.ty = (int)(p1.y*20);
1758 myshapeid = ++currentswfid;
1759 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1760 swf_ShapeNew(&shape);
1761 //lsid = ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1762 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1763 fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
1764 swf_SetU16(tag, myshapeid);
1765 r.xmin = (int)(xmin*20);
1766 r.ymin = (int)(ymin*20);
1767 r.xmax = (int)(xmax*20);
1768 r.ymax = (int)(ymax*20);
1769 swf_SetRect(tag,&r);
1770 swf_SetShapeStyles(tag,shape);
1771 swf_ShapeCountBits(shape,NULL,NULL);
1772 swf_SetShapeBits(tag,shape);
1773 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,lsid,fsid,0);
1774 swflastx = swflasty = 0;
1781 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
1782 ShapeSetLine (tag, shape, (int)(x1*20);
1783 ShapeSetLine (tag, shape, x*20,0);
1784 ShapeSetLine (tag, shape, 0,-y*20);
1785 ShapeSetLine (tag, shape, -x*20,0);*/
1786 swf_ShapeSetEnd(tag);
1789 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1790 swf_ObjectPlace(tag,myshapeid,/*depth*/depth++,NULL,NULL,NULL);
1793 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
1794 double x1,double y1,
1795 double x2,double y2,
1796 double x3,double y3,
1797 double x4,double y4)
1805 int bitid = ++currentswfid;
1807 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
1808 swf_SetU16(tag, bitid);
1809 if(swf_SetJPEGBits(tag, filename, jpegquality)<0) {
1815 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1819 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
1820 double x1,double y1,
1821 double x2,double y2,
1822 double x3,double y3,
1823 double x4,double y4)
1833 int bitid = ++currentswfid;
1835 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
1836 swf_SetU16(tag, bitid);
1837 swf_SetJPEGBits2(tag,sizex,sizey,mem,jpegquality);
1838 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1842 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
1843 double x1,double y1,
1844 double x2,double y2,
1845 double x3,double y3,
1846 double x4,double y4)
1854 int bitid = ++currentswfid;
1856 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS);
1857 swf_SetU16(tag, bitid);
1858 if(swf_SetLosslessBits(tag,sizex,sizey,mem, BMF_32BIT)<0) {
1864 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1868 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
1869 double x1,double y1,
1870 double x2,double y2,
1871 double x3,double y3,
1872 double x4,double y4, int n)
1883 /* SWF expects scanlines to be 4 byte aligned */
1886 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
1888 for(y=0;y<sizey;y++)
1890 for(x=0;x<sizex;x++)
1891 *ptr++ = mem[y*sizex+x];
1892 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
1897 int bitid = ++currentswfid;
1899 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS2);
1900 swf_SetU16(tag, bitid);
1901 if(swf_SetLosslessBitsIndexed(tag,sizex,sizey,mem, pal, n)<0) {
1909 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1913 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
1914 double x1,double y1,
1915 double x2,double y2,
1916 double x3,double y3,
1917 double x4,double y4)
1925 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);