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;
894 /* process a character. */
895 static int drawchar(struct swfoutput*obj, SWFFONT *swffont, char*character, int charnr, int u, swfmatrix*m)
898 if(m->m12!=0 || m->m21!=0)
904 msg("<warning> Font is NULL");
909 msg("<verbose> Non diagonal font matrix: %f %f", m->m11, m->m21);
910 msg("<verbose> | %f %f", m->m12, m->m22);
913 //if(usefonts && ! drawonlyshapes)
916 int charid = getCharID(swffont, charnr, character, u);
919 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
920 FIXNULL(character),charnr, u, FIXNULL((char*)swffont->name), swffont->numchars);
921 /*fontlist_t*it = fontlist;
923 msg("<warning> Font history: %s [%d]", it->swffont->name, getCharID(it->swffont, charnr, character, u));
934 putcharacter(obj, swffont->id, charid,(int)(m->m13*20),(int)(m->m23*20),
940 SWF_OUTLINE*outline = font->getOutline(character, charnr);
941 char* charname = character;
944 msg("<warning> Didn't find character '%s' (%d) in current charset (%s)",
945 FIXNULL(character),charnr,FIXNULL(font->getName()));
964 drawpath(tag, outline, &m2, 0);
969 /* draw a curved polygon. */
970 void swfoutput_drawpath(swfoutput*output, SWF_OUTLINE*outline,
976 /* Multiple polygons in one shape don't overlap correctly,
977 so we better start a new shape here if the polygon is filled
979 if(shapeid>=0 && fill && !ignoredraworder) {
991 drawpath(tag, outline,m, 0);
994 void swfoutput_drawpath2poly(struct swfoutput*output, SWF_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
1004 drawpath2poly(output, outline, m, 0, line_join, line_cap, line_width, miter_limit);
1007 int getCharID(SWFFONT *font, int charnr, char *charname, int u)
1011 for(t=0;t<font->numchars;t++) {
1012 if(font->glyphnames[t] && !strcmp(font->glyphnames[t],charname)) {
1016 /* if we didn't find the character, maybe
1017 we can find the capitalized version */
1018 for(t=0;t<font->numchars;t++) {
1019 if(font->glyphnames[t] && !strcasecmp(font->glyphnames[t],charname)) {
1026 if(u>=font->maxascii)
1027 msg("<debug> u=%d, font->maxascii=%d",u,font->maxascii);
1029 msg("<debug> u=%d, font->maxascii=%d ascci2glyph[%d]=%d",u,font->maxascii,u,font->ascii2glyph[u]);
1031 /* try to use the unicode id */
1032 if(u>=0 && u<font->maxascii && font->ascii2glyph[u]>=0) {
1033 return font->ascii2glyph[u];
1037 if(charnr>=0 && charnr<font->numchars) {
1045 /* set's the t1 font index of the font to use for swfoutput_drawchar(). */
1046 void swfoutput_setfont(struct swfoutput*obj, char*fontid, char*filename)
1048 fontlist_t*last=0,*iterator;
1050 msg("<error> No fontid");
1054 if(obj->swffont && obj->swffont->name && !strcmp((char*)obj->swffont->name,fontid))
1057 iterator = fontlist;
1059 if(!strcmp((char*)iterator->swffont->name,fontid)) {
1060 obj->swffont = iterator->swffont;
1064 iterator = iterator->next;
1068 msg("<error> No filename given for font- internal error?");
1072 SWFFONT*swffont = swf_LoadFont(filename);
1075 msg("<warning> Couldn't load font %s (%s)", fontid, filename);
1076 swffont = swf_LoadFont(0);
1079 swf_FontSetID(swffont, ++currentswfid);
1081 if(screenloglevel >= LOGLEVEL_DEBUG) {
1082 // print font information
1083 msg("<debug> Font %s (%s)",swffont->name, filename);
1084 msg("<debug> | ID: %d", swffont->id);
1085 msg("<debug> | Version: %d", swffont->version);
1086 msg("<debug> | Name: %s", fontid);
1087 msg("<debug> | Numchars: %d", swffont->numchars);
1088 msg("<debug> | Maxascii: %d", swffont->maxascii);
1089 msg("<debug> | Style: %d", swffont->style);
1090 msg("<debug> | Encoding: %d", swffont->encoding);
1091 for(int iii=0; iii<swffont->numchars;iii++) {
1092 msg("<debug> | Glyph %d) name=%s, unicode=%d\n", iii, swffont->glyphnames[iii], swffont->glyph2ascii[iii]);
1096 /* set the font name to the ID we use here */
1097 if(swffont->name) free(swffont->name);
1098 swffont->name = (U8*)strdup(fontid);
1100 iterator = new fontlist_t;
1101 iterator->swffont = swffont;
1105 last->next = iterator;
1107 fontlist = iterator;
1109 obj->swffont = swffont;
1112 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1114 fontlist_t *iterator = fontlist;
1116 if(!strcmp((char*)iterator->swffont->name,fontid))
1118 iterator = iterator->next;
1123 /* set's the matrix which is to be applied to characters drawn by
1124 swfoutput_drawchar() */
1125 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1126 double m21,double m22)
1128 if(obj->fontm11 == m11 &&
1129 obj->fontm12 == m12 &&
1130 obj->fontm21 == m21 &&
1131 obj->fontm22 == m22)
1141 /* draws a character at x,y. */
1142 int swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr, int u)
1145 m.m11 = obj->fontm11;
1146 m.m12 = obj->fontm12;
1147 m.m21 = obj->fontm21;
1148 m.m22 = obj->fontm22;
1151 return drawchar(obj, obj->swffont, character, charnr, u, &m);
1154 /* initialize the swf writer */
1155 void swfoutput_init(struct swfoutput* obj, char*_filename, int x1, int y1, int x2, int y2)
1159 memset(obj, 0, sizeof(struct swfoutput));
1160 filename = _filename;
1164 msg("<verbose> initializing swf output for size %d*%d\n", sizex,sizey);
1168 memset(&swf,0x00,sizeof(SWF));
1170 swf.fileVersion = flashversion;
1171 swf.frameRate = 0x0040; // 1 frame per 4 seconds
1172 swf.movieSize.xmin = 20*x1;
1173 swf.movieSize.ymin = 20*y1;
1174 swf.movieSize.xmax = 20*x2;
1175 swf.movieSize.ymax = 20*y2;
1179 swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1181 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1182 swf_SetRGB(tag,&rgb);
1184 if(1)/* add white rectangle */
1189 int shapeid = ++currentswfid;
1194 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
1196 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1197 swf_SetU16(tag,shapeid);
1198 swf_SetRect(tag,&r);
1199 swf_SetShapeHeader(tag,s);
1200 swf_ShapeSetAll(tag,s,x1*20,y1*20,ls1,fs1,0);
1201 swf_ShapeSetLine(tag,s,20*(x2-x1),0);
1202 swf_ShapeSetLine(tag,s,0,20*(y2-y1));
1203 swf_ShapeSetLine(tag,s,20*(x1-x2),0);
1204 swf_ShapeSetLine(tag,s,0,20*(y1-y2));
1205 swf_ShapeSetEnd(tag);
1207 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1208 swf_ObjectPlace(tag,shapeid,depth++,0,0,0);
1209 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1210 swf_ObjectPlaceClip(tag,shapeid,depth++,0,0,0,65535);
1214 tag = swf_InsertTag(tag, ST_PROTECT);
1219 void swfoutput_setprotected() //write PROTECT tag
1224 static void startshape(struct swfoutput*obj)
1232 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1234 swf_ShapeNew(&shape);
1235 linestyleid = swf_ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1236 rgb.r = obj->fillrgb.r;
1237 rgb.g = obj->fillrgb.g;
1238 rgb.b = obj->fillrgb.b;
1239 fillstyleid = swf_ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1241 shapeid = ++currentswfid;
1242 swf_SetU16(tag,shapeid); // ID
1249 swf_SetRect(tag,&r);
1251 swf_SetShapeStyles(tag,shape);
1252 swf_ShapeCountBits(shape,NULL,NULL);
1253 swf_SetShapeBits(tag,shape);
1255 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,linestyleid,0,0);
1256 swflastx=swflasty=0;
1261 static void starttext(struct swfoutput*obj)
1267 tag = swf_InsertTag(tag,ST_DEFINETEXT);
1268 textid = ++currentswfid;
1269 swf_SetU16(tag, textid);
1276 swf_SetRect(tag,&r);
1285 swf_SetMatrix(tag,&m);
1286 swflastx=swflasty=0;
1289 static void endshape()
1293 swf_ShapeSetEnd(tag);
1296 msg("<debug> empty shape");
1300 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1301 swf_ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL);
1305 static void endtext()
1311 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1312 swf_ObjectPlace(tag,textid,/*depth*/depth++,NULL,NULL,NULL);
1316 static void endpage(struct swfoutput*obj)
1323 swfoutput_endclip(obj);
1327 atag = action_Stop(atag);
1328 atag = action_End(atag);
1329 tag = swf_InsertTag(tag,ST_DOACTION);
1330 swf_ActionSet(tag,atag);
1332 tag = swf_InsertTag(tag,ST_SHOWFRAME);
1335 void swfoutput_newpage(struct swfoutput*obj)
1339 for(depth--;depth>=startdepth;depth--) {
1340 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1341 swf_SetU16(tag,depth);
1347 /* "destroy" like in (oo-terminology) "destructor". Perform cleaning
1348 up, complete the swf, and write it out. */
1349 void swfoutput_destroy(struct swfoutput* obj)
1352 fontlist_t *tmp,*iterator = fontlist;
1354 TAG*mtag = swf.firstTag;
1355 if(iterator->swffont) {
1356 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1357 swf_FontSetDefine2(mtag, iterator->swffont);
1358 swf_FontFree(iterator->swffont);
1362 iterator = iterator->next;
1369 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1374 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1378 tag = swf_InsertTag(tag,ST_END);
1381 if FAILED(swf_WriteSWC(fi,&swf))
1382 msg("<error> WriteSWC() failed.\n");
1384 if FAILED(swf_WriteSWF(fi,&swf))
1385 msg("<error> WriteSWF() failed.\n");
1390 msg("<notice> SWF written\n");
1393 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1396 if(mode == DRAWMODE_FILL)
1398 else if(mode == DRAWMODE_EOFILL)
1400 else if(mode == DRAWMODE_STROKE)
1402 else if(mode == DRAWMODE_CLIP)
1404 else if(mode == DRAWMODE_EOCLIP)
1408 void swfoutput_setfillcolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1410 if(obj->fillrgb.r == r &&
1411 obj->fillrgb.g == g &&
1412 obj->fillrgb.b == b &&
1413 obj->fillrgb.a == a) return;
1423 void swfoutput_setstrokecolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1425 if(obj->strokergb.r == r &&
1426 obj->strokergb.g == g &&
1427 obj->strokergb.b == b &&
1428 obj->strokergb.a == a) return;
1432 obj->strokergb.r = r;
1433 obj->strokergb.g = g;
1434 obj->strokergb.b = b;
1435 obj->strokergb.a = a;
1438 void swfoutput_setlinewidth(struct swfoutput*obj, double linewidth)
1440 if(obj->linewidth == (u16)(linewidth*20))
1445 obj->linewidth = (u16)(linewidth*20);
1449 void swfoutput_startclip(swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m)
1458 msg("<warning> Too many clip levels.");
1463 int olddrawmode = drawmode;
1464 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1465 swfoutput_drawpath(obj, outline, m);
1466 swf_ShapeSetEnd(tag);
1467 swfoutput_setdrawmode(obj, olddrawmode);
1469 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1470 cliptags[clippos] = tag;
1471 clipshapes[clippos] = shapeid;
1472 clipdepths[clippos] = depth++;
1477 void swfoutput_endclip(swfoutput*obj)
1485 msg("<error> Invalid end of clipping region");
1489 swf_ObjectPlaceClip(cliptags[clippos],clipshapes[clippos],clipdepths[clippos],NULL,NULL,NULL,depth++);
1492 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1494 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1497 if(!strncmp("http://pdf2swf:", url, 15)) {
1498 char*tmp = strdup(url);
1499 int l = strlen(tmp);
1502 swfoutput_namedlink(obj, tmp+15, points);
1513 actions = action_GetUrl(0, url, "_parent");
1515 actions = action_GetUrl(0, url, "_this");
1516 actions = action_End(actions);
1518 drawlink(obj, actions, 0, points,0);
1520 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1529 actions = action_GotoFrame(0, page);
1530 actions = action_End(actions);
1532 drawlink(obj, actions, 0, points,0);
1535 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
1536 of the viewer objects, like subtitles, index elements etc.
1538 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
1540 ActionTAG *actions1,*actions2;
1541 char*tmp = strdup(name);
1549 if(!strncmp(tmp, "call:", 5))
1551 char*x = strchr(&tmp[5], ':');
1553 actions1 = action_PushInt(0, 0); //number of parameters (0)
1554 actions1 = action_PushString(actions1, &tmp[5]); //function name
1555 actions1 = action_CallFunction(actions1);
1558 actions1 = action_PushString(0, x+1); //parameter
1559 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
1560 actions1 = action_PushString(actions1, &tmp[5]); //function name
1561 actions1 = action_CallFunction(actions1);
1563 actions2 = action_End(0);
1568 actions1 = action_PushString(0, "/:subtitle");
1569 actions1 = action_PushString(actions1, name);
1570 actions1 = action_SetVariable(actions1);
1571 actions1 = action_End(actions1);
1573 actions2 = action_PushString(0, "/:subtitle");
1574 actions2 = action_PushString(actions2, "");
1575 actions2 = action_SetVariable(actions2);
1576 actions2 = action_End(actions2);
1579 drawlink(obj, actions1, actions2, points,mouseover);
1581 swf_ActionFree(actions1);
1582 swf_ActionFree(actions2);
1586 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
1592 struct plotxy p1,p2,p3,p4;
1596 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
1600 int buttonid = ++currentswfid;
1603 if(points[t].x>xmax) xmax=points[t].x;
1604 if(points[t].y>ymax) ymax=points[t].y;
1605 if(points[t].x<xmin) xmin=points[t].x;
1606 if(points[t].y<ymin) ymin=points[t].y;
1609 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
1610 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
1612 /* the following code subtracts the upper left edge from all coordinates,
1613 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
1614 Necessary for preprocessing with swfcombine. */
1615 posx = xmin; posy = ymin;
1616 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
1617 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
1618 xmin -= posx; ymin -= posy;
1619 xmax -= posx; ymax -= posy;
1622 myshapeid = ++currentswfid;
1623 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1624 swf_ShapeNew(&shape);
1625 rgb.r = rgb.b = rgb.a = rgb.g = 0;
1626 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1627 swf_SetU16(tag, myshapeid);
1628 r.xmin = (int)(xmin*20);
1629 r.ymin = (int)(ymin*20);
1630 r.xmax = (int)(xmax*20);
1631 r.ymax = (int)(ymax*20);
1632 swf_SetRect(tag,&r);
1633 swf_SetShapeStyles(tag,shape);
1634 swf_ShapeCountBits(shape,NULL,NULL);
1635 swf_SetShapeBits(tag,shape);
1636 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1637 swflastx = swflasty = 0;
1643 swf_ShapeSetEnd(tag);
1646 myshapeid2 = ++currentswfid;
1647 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1648 swf_ShapeNew(&shape);
1649 rgb.r = rgb.b = rgb.a = rgb.g = 255;
1651 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1652 swf_SetU16(tag, myshapeid2);
1653 r.xmin = (int)(xmin*20);
1654 r.ymin = (int)(ymin*20);
1655 r.xmax = (int)(xmax*20);
1656 r.ymax = (int)(ymax*20);
1657 swf_SetRect(tag,&r);
1658 swf_SetShapeStyles(tag,shape);
1659 swf_ShapeCountBits(shape,NULL,NULL);
1660 swf_SetShapeBits(tag,shape);
1661 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1662 swflastx = swflasty = 0;
1668 swf_ShapeSetEnd(tag);
1672 tag = swf_InsertTag(tag,ST_DEFINEBUTTON);
1673 swf_SetU16(tag,buttonid); //id
1674 swf_ButtonSetFlags(tag, 0); //menu=no
1675 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1676 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1677 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1678 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1680 swf_ActionSet(tag,actions1);
1685 tag = swf_InsertTag(tag,ST_DEFINEBUTTON2);
1686 swf_SetU16(tag,buttonid); //id
1687 swf_ButtonSetFlags(tag, 0); //menu=no
1688 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1689 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1690 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1691 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1692 swf_SetU8(tag,0); // end of button records
1693 swf_ButtonSetCondition(tag, BC_IDLE_OVERUP);
1694 swf_ActionSet(tag,actions1);
1696 swf_ButtonSetCondition(tag, BC_OVERUP_IDLE);
1697 swf_ActionSet(tag,actions2);
1699 swf_ButtonPostProcess(tag, 2);
1702 swf_ButtonPostProcess(tag, 1);
1706 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1708 if(posx!=0 || posy!=0) {
1710 swf_GetMatrix(0,&m);
1711 m.tx = (int)(posx*20);
1712 m.ty = (int)(posy*20);
1713 swf_ObjectPlace(tag, buttonid, depth++,&m,0,0);
1716 swf_ObjectPlace(tag, buttonid, depth++,0,0,0);
1720 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
1721 double x1,double y1,
1722 double x2,double y2,
1723 double x3,double y3,
1724 double x4,double y4)
1730 struct plotxy p1,p2,p3,p4;
1732 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
1733 if(x2>xmax) xmax=x2;
1734 if(y2>ymax) ymax=y2;
1735 if(x2<xmin) xmin=x2;
1736 if(y2<ymin) ymin=y2;
1737 if(x3>xmax) xmax=x3;
1738 if(y3>ymax) ymax=y3;
1739 if(x3<xmin) xmin=x3;
1740 if(y3<ymin) ymin=y3;
1741 if(x4>xmax) xmax=x4;
1742 if(y4>ymax) ymax=y4;
1743 if(x4<xmin) xmin=x4;
1744 if(y4<ymin) ymin=y4;
1750 {p1.x = (int)(p1.x*20)/20.0;
1751 p1.y = (int)(p1.y*20)/20.0;
1752 p2.x = (int)(p2.x*20)/20.0;
1753 p2.y = (int)(p2.y*20)/20.0;
1754 p3.x = (int)(p3.x*20)/20.0;
1755 p3.y = (int)(p3.y*20)/20.0;
1756 p4.x = (int)(p4.x*20)/20.0;
1757 p4.y = (int)(p4.y*20)/20.0;}
1760 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
1761 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
1762 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
1763 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
1765 m.tx = (int)(p1.x*20);
1766 m.ty = (int)(p1.y*20);
1769 myshapeid = ++currentswfid;
1770 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1771 swf_ShapeNew(&shape);
1772 //lsid = ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1773 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1774 fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
1775 swf_SetU16(tag, myshapeid);
1776 r.xmin = (int)(xmin*20);
1777 r.ymin = (int)(ymin*20);
1778 r.xmax = (int)(xmax*20);
1779 r.ymax = (int)(ymax*20);
1780 swf_SetRect(tag,&r);
1781 swf_SetShapeStyles(tag,shape);
1782 swf_ShapeCountBits(shape,NULL,NULL);
1783 swf_SetShapeBits(tag,shape);
1784 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,lsid,fsid,0);
1785 swflastx = swflasty = 0;
1792 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
1793 ShapeSetLine (tag, shape, (int)(x1*20);
1794 ShapeSetLine (tag, shape, x*20,0);
1795 ShapeSetLine (tag, shape, 0,-y*20);
1796 ShapeSetLine (tag, shape, -x*20,0);*/
1797 swf_ShapeSetEnd(tag);
1800 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1801 swf_ObjectPlace(tag,myshapeid,/*depth*/depth++,NULL,NULL,NULL);
1804 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
1805 double x1,double y1,
1806 double x2,double y2,
1807 double x3,double y3,
1808 double x4,double y4)
1816 int bitid = ++currentswfid;
1818 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
1819 swf_SetU16(tag, bitid);
1820 if(swf_SetJPEGBits(tag, filename, jpegquality)<0) {
1826 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1830 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
1831 double x1,double y1,
1832 double x2,double y2,
1833 double x3,double y3,
1834 double x4,double y4)
1844 int bitid = ++currentswfid;
1846 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
1847 swf_SetU16(tag, bitid);
1848 swf_SetJPEGBits2(tag,sizex,sizey,mem,jpegquality);
1849 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1853 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
1854 double x1,double y1,
1855 double x2,double y2,
1856 double x3,double y3,
1857 double x4,double y4)
1865 int bitid = ++currentswfid;
1867 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS);
1868 swf_SetU16(tag, bitid);
1869 if(swf_SetLosslessBits(tag,sizex,sizey,mem, BMF_32BIT)<0) {
1875 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1879 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
1880 double x1,double y1,
1881 double x2,double y2,
1882 double x3,double y3,
1883 double x4,double y4, int n)
1894 /* SWF expects scanlines to be 4 byte aligned */
1897 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
1899 for(y=0;y<sizey;y++)
1901 for(x=0;x<sizex;x++)
1902 *ptr++ = mem[y*sizex+x];
1903 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
1908 int bitid = ++currentswfid;
1910 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS2);
1911 swf_SetU16(tag, bitid);
1912 if(swf_SetLosslessBitsIndexed(tag,sizex,sizey,mem, pal, n)<0) {
1920 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1924 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
1925 double x1,double y1,
1926 double x2,double y2,
1927 double x3,double y3,
1928 double x4,double y4)
1936 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);