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 void 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' (%d) in current charset (%s, %d characters)",
909 FIXNULL(character),charnr, FIXNULL((char*)swffont->name), swffont->numchars);
917 putcharacter(obj, swffont->id, charid,(int)(m->m13*20),(int)(m->m23*20),
922 SWF_OUTLINE*outline = font->getOutline(character, charnr);
923 char* charname = character;
926 msg("<warning> Didn't find character '%s' (%d) in current charset (%s)",
927 FIXNULL(character),charnr,FIXNULL(font->getName()));
946 drawpath(tag, outline, &m2, 0);
951 /* draw a curved polygon. */
952 void swfoutput_drawpath(swfoutput*output, SWF_OUTLINE*outline,
958 /* Multiple polygons in one shape don't overlap correctly,
959 so we better start a new shape here if the polygon is filled
961 if(shapeid>=0 && fill && !ignoredraworder) {
973 drawpath(tag, outline,m, 0);
976 void swfoutput_drawpath2poly(struct swfoutput*output, SWF_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
986 drawpath2poly(output, outline, m, 0, line_join, line_cap, line_width, miter_limit);
989 int getCharID(SWFFONT *font, int charnr, char *charname, int u)
993 for(t=0;t<font->numchars;t++) {
994 if(font->glyphnames[t] && !strcmp(font->glyphnames[t],charname)) {
998 /* if we didn't find the character, maybe
999 we can find the capitalized version */
1000 for(t=0;t<font->numchars;t++) {
1001 if(font->glyphnames[t] && !strcasecmp(font->glyphnames[t],charname)) {
1008 if(u>=font->maxascii)
1009 msg("<debug> u=%d, font->maxascii=%d",u,font->maxascii);
1011 msg("<debug> u=%d, font->maxascii=%d ascci2glyph[%d]=%d",u,font->maxascii,u,font->ascii2glyph[u]);
1013 /* try to use the unicode id */
1014 if(u>=0 && u<font->maxascii && font->ascii2glyph[u]>=0)
1015 return font->ascii2glyph[u];
1018 if(charnr>=0 && charnr<font->numchars)
1029 /* set's the t1 font index of the font to use for swfoutput_drawchar(). */
1030 void swfoutput_setfont(struct swfoutput*obj, char*fontid, char*filename)
1032 fontlist_t*last=0,*iterator;
1034 msg("<error> No fontid");
1038 if(obj->swffont && obj->swffont->name && !strcmp((char*)obj->swffont->name,fontid))
1041 iterator = fontlist;
1043 if(!strcmp((char*)iterator->swffont->name,fontid)) {
1044 obj->swffont = iterator->swffont;
1048 iterator = iterator->next;
1052 msg("<error> No filename given for font- internal error?");
1056 /* TODO: sometimes, scale has to be 64, and sometimes 32.
1057 It's probably font format related */
1058 swf_SetLoadFontParameters(32, 0);
1060 SWFFONT *swffont = swf_LoadFont(filename);
1061 swf_FontSetID(swffont, ++currentswfid);
1063 if(screenloglevel >= LOGLEVEL_DEBUG) {
1064 // print font information
1065 msg("<debug> Font %s (%s)",swffont->name, filename);
1066 msg("<debug> | ID: %d", swffont->id);
1067 msg("<debug> | Version: %d", swffont->version);
1068 msg("<debug> | Name: %s", fontid);
1069 msg("<debug> | Numchars: %d", swffont->numchars);
1070 msg("<debug> | Maxascii: %d", swffont->maxascii);
1071 msg("<debug> | Style: %d", swffont->style);
1072 msg("<debug> | Encoding: %d", swffont->encoding);
1073 for(int iii=0; iii<swffont->numchars;iii++) {
1074 msg("<debug> | Glyph %d) name=%s, unicode=%d\n", iii, swffont->glyphnames[iii], swffont->glyph2ascii[iii]);
1078 /* set the font name to the ID we use here */
1079 if(swffont->name) free(swffont->name);
1080 swffont->name = (U8*)strdup(fontid);
1082 iterator = new fontlist_t;
1083 iterator->swffont = swffont;
1087 last->next = iterator;
1089 fontlist = iterator;
1091 obj->swffont = swffont;
1094 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1096 fontlist_t *iterator = fontlist;
1098 if(!strcmp((char*)iterator->swffont->name,fontid))
1100 iterator = iterator->next;
1105 /* set's the matrix which is to be applied to characters drawn by
1106 swfoutput_drawchar() */
1107 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1108 double m21,double m22)
1110 if(obj->fontm11 == m11 &&
1111 obj->fontm12 == m12 &&
1112 obj->fontm21 == m21 &&
1113 obj->fontm22 == m22)
1123 /* draws a character at x,y. */
1124 void swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr, int u)
1127 m.m11 = obj->fontm11;
1128 m.m12 = obj->fontm12;
1129 m.m21 = obj->fontm21;
1130 m.m22 = obj->fontm22;
1133 drawchar(obj, obj->swffont, character, charnr, u, &m);
1136 /* initialize the swf writer */
1137 void swfoutput_init(struct swfoutput* obj, char*_filename, int x1, int y1, int x2, int y2)
1141 memset(obj, 0, sizeof(struct swfoutput));
1142 filename = _filename;
1146 msg("<verbose> initializing swf output for size %d*%d\n", sizex,sizey);
1150 memset(&swf,0x00,sizeof(SWF));
1152 swf.fileVersion = flashversion;
1153 swf.frameRate = 0x0040; // 1 frame per 4 seconds
1154 swf.movieSize.xmin = 20*x1;
1155 swf.movieSize.ymin = 20*y1;
1156 swf.movieSize.xmax = 20*x2;
1157 swf.movieSize.ymax = 20*y2;
1161 swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1163 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1164 swf_SetRGB(tag,&rgb);
1166 if(1)/* add white rectangle */
1171 int shapeid = ++currentswfid;
1176 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
1178 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1179 swf_SetU16(tag,shapeid);
1180 swf_SetRect(tag,&r);
1181 swf_SetShapeHeader(tag,s);
1182 swf_ShapeSetAll(tag,s,x1*20,y1*20,ls1,fs1,0);
1183 swf_ShapeSetLine(tag,s,20*(x2-x1),0);
1184 swf_ShapeSetLine(tag,s,0,20*(y2-y1));
1185 swf_ShapeSetLine(tag,s,20*(x1-x2),0);
1186 swf_ShapeSetLine(tag,s,0,20*(y1-y2));
1187 swf_ShapeSetEnd(tag);
1189 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1190 swf_ObjectPlace(tag,shapeid,depth++,0,0,0);
1191 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1192 swf_ObjectPlaceClip(tag,shapeid,depth++,0,0,0,65535);
1196 tag = swf_InsertTag(tag, ST_PROTECT);
1201 void swfoutput_setprotected() //write PROTECT tag
1206 static void startshape(struct swfoutput*obj)
1214 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1216 swf_ShapeNew(&shape);
1217 linestyleid = swf_ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1218 rgb.r = obj->fillrgb.r;
1219 rgb.g = obj->fillrgb.g;
1220 rgb.b = obj->fillrgb.b;
1221 fillstyleid = swf_ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1223 shapeid = ++currentswfid;
1224 swf_SetU16(tag,shapeid); // ID
1231 swf_SetRect(tag,&r);
1233 swf_SetShapeStyles(tag,shape);
1234 swf_ShapeCountBits(shape,NULL,NULL);
1235 swf_SetShapeBits(tag,shape);
1237 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,linestyleid,0,0);
1238 swflastx=swflasty=0;
1243 static void starttext(struct swfoutput*obj)
1249 tag = swf_InsertTag(tag,ST_DEFINETEXT);
1250 textid = ++currentswfid;
1251 swf_SetU16(tag, textid);
1258 swf_SetRect(tag,&r);
1267 swf_SetMatrix(tag,&m);
1268 swflastx=swflasty=0;
1271 static void endshape()
1275 swf_ShapeSetEnd(tag);
1278 msg("<warning> empty shape");
1282 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1283 swf_ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL);
1287 static void endtext()
1293 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1294 swf_ObjectPlace(tag,textid,/*depth*/depth++,NULL,NULL,NULL);
1298 static void endpage(struct swfoutput*obj)
1305 swfoutput_endclip(obj);
1309 atag = action_Stop(atag);
1310 atag = action_End(atag);
1311 tag = swf_InsertTag(tag,ST_DOACTION);
1312 swf_ActionSet(tag,atag);
1314 tag = swf_InsertTag(tag,ST_SHOWFRAME);
1317 void swfoutput_newpage(struct swfoutput*obj)
1321 for(depth--;depth>=startdepth;depth--) {
1322 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1323 swf_SetU16(tag,depth);
1329 /* "destroy" like in (oo-terminology) "destructor". Perform cleaning
1330 up, complete the swf, and write it out. */
1331 void swfoutput_destroy(struct swfoutput* obj)
1334 fontlist_t *tmp,*iterator = fontlist;
1336 TAG*mtag = swf.firstTag;
1337 if(iterator->swffont) {
1338 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1339 swf_FontSetDefine2(mtag, iterator->swffont);
1340 swf_FontFree(iterator->swffont);
1344 iterator = iterator->next;
1351 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1356 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1360 tag = swf_InsertTag(tag,ST_END);
1363 if FAILED(swf_WriteSWC(fi,&swf))
1364 msg("<error> WriteSWC() failed.\n");
1366 if FAILED(swf_WriteSWF(fi,&swf))
1367 msg("<error> WriteSWF() failed.\n");
1372 msg("<notice> SWF written\n");
1375 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1378 if(mode == DRAWMODE_FILL)
1380 else if(mode == DRAWMODE_EOFILL)
1382 else if(mode == DRAWMODE_STROKE)
1384 else if(mode == DRAWMODE_CLIP)
1386 else if(mode == DRAWMODE_EOCLIP)
1390 void swfoutput_setfillcolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1392 if(obj->fillrgb.r == r &&
1393 obj->fillrgb.g == g &&
1394 obj->fillrgb.b == b &&
1395 obj->fillrgb.a == a) return;
1405 void swfoutput_setstrokecolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1407 if(obj->strokergb.r == r &&
1408 obj->strokergb.g == g &&
1409 obj->strokergb.b == b &&
1410 obj->strokergb.a == a) return;
1414 obj->strokergb.r = r;
1415 obj->strokergb.g = g;
1416 obj->strokergb.b = b;
1417 obj->strokergb.a = a;
1420 void swfoutput_setlinewidth(struct swfoutput*obj, double linewidth)
1422 if(obj->linewidth == (u16)(linewidth*20))
1427 obj->linewidth = (u16)(linewidth*20);
1431 void swfoutput_startclip(swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m)
1440 msg("<warning> Too many clip levels.");
1445 int olddrawmode = drawmode;
1446 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1447 swfoutput_drawpath(obj, outline, m);
1448 swf_ShapeSetEnd(tag);
1449 swfoutput_setdrawmode(obj, olddrawmode);
1451 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1452 cliptags[clippos] = tag;
1453 clipshapes[clippos] = shapeid;
1454 clipdepths[clippos] = depth++;
1459 void swfoutput_endclip(swfoutput*obj)
1467 msg("<error> Invalid end of clipping region");
1471 swf_ObjectPlaceClip(cliptags[clippos],clipshapes[clippos],clipdepths[clippos],NULL,NULL,NULL,depth++);
1474 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1476 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1479 if(!strncmp("http://pdf2swf:", url, 15)) {
1480 char*tmp = strdup(url);
1481 int l = strlen(tmp);
1484 swfoutput_namedlink(obj, tmp+15, points);
1495 actions = action_GetUrl(0, url, "_parent");
1497 actions = action_GetUrl(0, url, "_this");
1498 actions = action_End(actions);
1500 drawlink(obj, actions, 0, points,0);
1502 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1511 actions = action_GotoFrame(0, page);
1512 actions = action_End(actions);
1514 drawlink(obj, actions, 0, points,0);
1517 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
1518 of the viewer objects, like subtitles, index elements etc.
1520 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
1522 ActionTAG *actions1,*actions2;
1523 char*tmp = strdup(name);
1531 if(!strncmp(tmp, "call:", 5))
1533 char*x = strchr(&tmp[5], ':');
1535 actions1 = action_PushInt(0, 0); //number of parameters (0)
1536 actions1 = action_PushString(actions1, &tmp[5]); //function name
1537 actions1 = action_CallFunction(actions1);
1540 actions1 = action_PushString(0, x+1); //parameter
1541 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
1542 actions1 = action_PushString(actions1, &tmp[5]); //function name
1543 actions1 = action_CallFunction(actions1);
1545 actions2 = action_End(0);
1550 actions1 = action_PushString(0, "/:subtitle");
1551 actions1 = action_PushString(actions1, name);
1552 actions1 = action_SetVariable(actions1);
1553 actions1 = action_End(actions1);
1555 actions2 = action_PushString(0, "/:subtitle");
1556 actions2 = action_PushString(actions2, "");
1557 actions2 = action_SetVariable(actions2);
1558 actions2 = action_End(actions2);
1561 drawlink(obj, actions1, actions2, points,mouseover);
1563 swf_ActionFree(actions1);
1564 swf_ActionFree(actions2);
1568 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
1574 struct plotxy p1,p2,p3,p4;
1578 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
1582 int buttonid = ++currentswfid;
1585 if(points[t].x>xmax) xmax=points[t].x;
1586 if(points[t].y>ymax) ymax=points[t].y;
1587 if(points[t].x<xmin) xmin=points[t].x;
1588 if(points[t].y<ymin) ymin=points[t].y;
1591 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
1592 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
1594 /* the following code subtracts the upper left edge from all coordinates,
1595 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
1596 Necessary for preprocessing with swfcombine. */
1597 posx = xmin; posy = ymin;
1598 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
1599 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
1600 xmin -= posx; ymin -= posy;
1601 xmax -= posx; ymax -= posy;
1604 myshapeid = ++currentswfid;
1605 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1606 swf_ShapeNew(&shape);
1607 rgb.r = rgb.b = rgb.a = rgb.g = 0;
1608 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1609 swf_SetU16(tag, myshapeid);
1610 r.xmin = (int)(xmin*20);
1611 r.ymin = (int)(ymin*20);
1612 r.xmax = (int)(xmax*20);
1613 r.ymax = (int)(ymax*20);
1614 swf_SetRect(tag,&r);
1615 swf_SetShapeStyles(tag,shape);
1616 swf_ShapeCountBits(shape,NULL,NULL);
1617 swf_SetShapeBits(tag,shape);
1618 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1619 swflastx = swflasty = 0;
1625 swf_ShapeSetEnd(tag);
1628 myshapeid2 = ++currentswfid;
1629 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1630 swf_ShapeNew(&shape);
1631 rgb.r = rgb.b = rgb.a = rgb.g = 255;
1633 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1634 swf_SetU16(tag, myshapeid2);
1635 r.xmin = (int)(xmin*20);
1636 r.ymin = (int)(ymin*20);
1637 r.xmax = (int)(xmax*20);
1638 r.ymax = (int)(ymax*20);
1639 swf_SetRect(tag,&r);
1640 swf_SetShapeStyles(tag,shape);
1641 swf_ShapeCountBits(shape,NULL,NULL);
1642 swf_SetShapeBits(tag,shape);
1643 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1644 swflastx = swflasty = 0;
1650 swf_ShapeSetEnd(tag);
1654 tag = swf_InsertTag(tag,ST_DEFINEBUTTON);
1655 swf_SetU16(tag,buttonid); //id
1656 swf_ButtonSetFlags(tag, 0); //menu=no
1657 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1658 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1659 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1660 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1662 swf_ActionSet(tag,actions1);
1667 tag = swf_InsertTag(tag,ST_DEFINEBUTTON2);
1668 swf_SetU16(tag,buttonid); //id
1669 swf_ButtonSetFlags(tag, 0); //menu=no
1670 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1671 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1672 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1673 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1674 swf_SetU8(tag,0); // end of button records
1675 swf_ButtonSetCondition(tag, BC_IDLE_OVERUP);
1676 swf_ActionSet(tag,actions1);
1678 swf_ButtonSetCondition(tag, BC_OVERUP_IDLE);
1679 swf_ActionSet(tag,actions2);
1681 swf_ButtonPostProcess(tag, 2);
1684 swf_ButtonPostProcess(tag, 1);
1688 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1690 if(posx!=0 || posy!=0) {
1692 swf_GetMatrix(0,&m);
1693 m.tx = (int)(posx*20);
1694 m.ty = (int)(posy*20);
1695 swf_ObjectPlace(tag, buttonid, depth++,&m,0,0);
1698 swf_ObjectPlace(tag, buttonid, depth++,0,0,0);
1702 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
1703 double x1,double y1,
1704 double x2,double y2,
1705 double x3,double y3,
1706 double x4,double y4)
1712 struct plotxy p1,p2,p3,p4;
1714 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
1715 if(x2>xmax) xmax=x2;
1716 if(y2>ymax) ymax=y2;
1717 if(x2<xmin) xmin=x2;
1718 if(y2<ymin) ymin=y2;
1719 if(x3>xmax) xmax=x3;
1720 if(y3>ymax) ymax=y3;
1721 if(x3<xmin) xmin=x3;
1722 if(y3<ymin) ymin=y3;
1723 if(x4>xmax) xmax=x4;
1724 if(y4>ymax) ymax=y4;
1725 if(x4<xmin) xmin=x4;
1726 if(y4<ymin) ymin=y4;
1732 {p1.x = (int)(p1.x*20)/20.0;
1733 p1.y = (int)(p1.y*20)/20.0;
1734 p2.x = (int)(p2.x*20)/20.0;
1735 p2.y = (int)(p2.y*20)/20.0;
1736 p3.x = (int)(p3.x*20)/20.0;
1737 p3.y = (int)(p3.y*20)/20.0;
1738 p4.x = (int)(p4.x*20)/20.0;
1739 p4.y = (int)(p4.y*20)/20.0;}
1742 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
1743 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
1744 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
1745 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
1747 m.tx = (int)(p1.x*20);
1748 m.ty = (int)(p1.y*20);
1751 myshapeid = ++currentswfid;
1752 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1753 swf_ShapeNew(&shape);
1754 //lsid = ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1755 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1756 fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
1757 swf_SetU16(tag, myshapeid);
1758 r.xmin = (int)(xmin*20);
1759 r.ymin = (int)(ymin*20);
1760 r.xmax = (int)(xmax*20);
1761 r.ymax = (int)(ymax*20);
1762 swf_SetRect(tag,&r);
1763 swf_SetShapeStyles(tag,shape);
1764 swf_ShapeCountBits(shape,NULL,NULL);
1765 swf_SetShapeBits(tag,shape);
1766 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,lsid,fsid,0);
1767 swflastx = swflasty = 0;
1774 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
1775 ShapeSetLine (tag, shape, (int)(x1*20);
1776 ShapeSetLine (tag, shape, x*20,0);
1777 ShapeSetLine (tag, shape, 0,-y*20);
1778 ShapeSetLine (tag, shape, -x*20,0);*/
1779 swf_ShapeSetEnd(tag);
1782 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1783 swf_ObjectPlace(tag,myshapeid,/*depth*/depth++,NULL,NULL,NULL);
1786 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
1787 double x1,double y1,
1788 double x2,double y2,
1789 double x3,double y3,
1790 double x4,double y4)
1798 int bitid = ++currentswfid;
1800 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
1801 swf_SetU16(tag, bitid);
1802 if(swf_SetJPEGBits(tag, filename, jpegquality)<0) {
1808 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1812 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
1813 double x1,double y1,
1814 double x2,double y2,
1815 double x3,double y3,
1816 double x4,double y4)
1826 int bitid = ++currentswfid;
1828 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
1829 swf_SetU16(tag, bitid);
1830 swf_SetJPEGBits2(tag,sizex,sizey,mem,jpegquality);
1831 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1835 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
1836 double x1,double y1,
1837 double x2,double y2,
1838 double x3,double y3,
1839 double x4,double y4)
1847 int bitid = ++currentswfid;
1849 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS);
1850 swf_SetU16(tag, bitid);
1851 if(swf_SetLosslessBits(tag,sizex,sizey,mem, BMF_32BIT)<0) {
1857 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1861 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
1862 double x1,double y1,
1863 double x2,double y2,
1864 double x3,double y3,
1865 double x4,double y4, int n)
1876 /* SWF expects scanlines to be 4 byte aligned */
1879 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
1881 for(y=0;y<sizey;y++)
1883 for(x=0;x<sizex;x++)
1884 *ptr++ = mem[y*sizex+x];
1885 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
1890 int bitid = ++currentswfid;
1892 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS2);
1893 swf_SetU16(tag, bitid);
1894 if(swf_SetLosslessBitsIndexed(tag,sizex,sizey,mem, pal, n)<0) {
1902 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1906 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
1907 double x1,double y1,
1908 double x2,double y2,
1909 double x3,double y3,
1910 double x4,double y4)
1918 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);