* remove empty shapes from output
[swftools.git] / pdf2swf / swfoutput.cc
blob6ed1c312607ee1fb1eda08927d7ee353c36894cf
1 /* swfoutput.cc
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 */
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include "../config.h"
25 #include <fcntl.h>
26 #include <unistd.h>
27 #ifdef HAVE_ASSERT_H
28 #include <assert.h>
29 #else
30 #define assert(a)
31 #endif
32 #include <math.h>
33 #include "swfoutput.h"
34 #include "spline.h"
35 extern "C" {
36 #include "../lib/log.h"
37 #include "../lib/rfxswf.h"
40 int opennewwindow=0;
41 int ignoredraworder=0;
42 int drawonlyshapes=0;
43 int jpegquality=85;
44 int storeallcharacters=0;
45 int enablezlib=0;
46 int insertstoptag=0;
47 int flashversion=4;
48 int splinemaxerror=1;
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;
58 static int fi;
59 static char* filename = 0;
60 static SWF swf;
61 static TAG *tag;
62 static int currentswfid = 0;
63 static int depth = 1;
64 static int startdepth = 1;
66 static SHAPE* shape;
67 static int shapeid = -1;
68 static int textid = -1;
70 static int fillstyleid;
71 static int linestyleid;
72 static int swflastx=0;
73 static int swflasty=0;
74 static int lastwasfill = 0;
75 static int shapeisempty = 1;
76 static char fill = 0;
77 static int sizex;
78 static int sizey;
79 TAG* cliptags[128];
80 int clipshapes[128];
81 u32 clipdepths[128];
82 int clippos = 0;
84 int CHARMIDX = 0;
85 int CHARMIDY = 0;
87 char fillstylechanged = 0;
89 static void startshape(struct swfoutput* obj);
90 static void starttext(struct swfoutput* obj);
91 static void endshape();
92 static void endtext();
94 // matrix multiplication. changes p0
95 static void transform (plotxy*p0,struct swfmatrix*m)
97 double x,y;
98 x = m->m11*p0->x+m->m12*p0->y;
99 y = m->m21*p0->x+m->m22*p0->y;
100 p0->x = x + m->m13;
101 p0->y = y + m->m23;
104 // write a move-to command into the swf
105 static int moveto(TAG*tag, plotxy p0)
107 int rx = (int)(p0.x*20);
108 int ry = (int)(p0.y*20);
109 if(rx!=swflastx || ry!=swflasty || fillstylechanged) {
110 swf_ShapeSetMove (tag, shape, rx,ry);
111 fillstylechanged = 0;
112 swflastx=rx;
113 swflasty=ry;
114 return 1;
116 return 0;
119 // write a line-to command into the swf
120 static void lineto(TAG*tag, plotxy p0)
122 int rx = ((int)(p0.x*20)-swflastx);
123 int ry = ((int)(p0.y*20)-swflasty);
124 /* we can't skip this for rx=0,ry=0, those
125 are plots */
126 swf_ShapeSetLine (tag, shape, rx,ry);
127 shapeisempty = 0;
128 swflastx+=rx;
129 swflasty+=ry;
132 // write a spline-to command into the swf
133 static void splineto(TAG*tag, plotxy control,plotxy end)
135 int cx = ((int)(control.x*20)-swflastx);
136 int cy = ((int)(control.y*20)-swflasty);
137 swflastx += cx;
138 swflasty += cy;
139 int ex = ((int)(end.x*20)-swflastx);
140 int ey = ((int)(end.y*20)-swflasty);
141 swflastx += ex;
142 swflasty += ey;
143 if(cx || cy || ex || ey)
144 swf_ShapeSetCurve(tag, shape, cx,cy,ex,ey);
145 shapeisempty = 0;
148 /* write a line, given two points and the transformation
149 matrix. */
150 static void line(TAG*tag, plotxy p0, plotxy p1, struct swfmatrix*m)
152 transform(&p0,m);
153 transform(&p1,m);
154 moveto(tag, p0);
155 lineto(tag, p1);
158 /* write a cubic (!) spline. This involves calling the approximate()
159 function out of spline.cc to convert it to a quadratic spline. */
160 static void spline(TAG*tag,plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m)
162 double d;
163 struct qspline q[128];
164 int num;
165 int t;
166 transform(&p0,m);
167 transform(&p1,m);
168 transform(&p2,m);
169 transform(&p3,m);
170 cspline c;
171 c.start = p3;
172 c.control1 = p2;
173 c.control2 = p1;
174 c.end = p0;
176 if(storefont) {
177 /* fonts use a different approximation than shapes */
178 num = cspline_approximate(&c, q, fontsplinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
179 //num = cspline_approximate(&c, q, 10.0, APPROXIMATE_INFLECTION);
180 } else {
181 num = cspline_approximate(&c, q, splinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
183 for(t=0;t<num;t++) {
184 if(!t)
185 moveto(tag,q[t].start);
186 splineto(tag,q[t].control, q[t].end);
190 void resetdrawer()
192 swflastx = 0;
193 swflasty = 0;
196 static void stopFill()
198 if(lastwasfill)
200 swf_ShapeSetStyle(tag,shape,linestyleid,0x8000,0);
201 fillstylechanged = 1;
202 lastwasfill = 0;
205 static void startFill()
207 if(!lastwasfill)
209 swf_ShapeSetStyle(tag,shape,0x8000,fillstyleid,0);
210 fillstylechanged = 1;
211 lastwasfill = 1;
215 /* draw an outline. These are generated by pdf2swf and by t1lib
216 (representing characters). */
217 void drawpath(struct swfoutput*output, SWF_OUTLINE*outline, struct swfmatrix*m, int log)
219 if( tag->id != ST_DEFINESHAPE &&
220 tag->id != ST_DEFINESHAPE2 &&
221 tag->id != ST_DEFINESHAPE3)
223 msg("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
224 exit(1);
226 double x=0,y=0;
227 double lastx=0,lasty=0;
228 double firstx=0,firsty=0;
229 int init=1;
231 while (outline)
233 x += (outline->dest.x/(float)0xffff);
234 y += (outline->dest.y/(float)0xffff);
235 if(outline->type == SWF_PATHTYPE_MOVE)
237 if(!init && fill && output->drawmode != DRAWMODE_EOFILL && !ignoredraworder) {
238 /* drawmode=FILL (not EOFILL) means that
239 seperate shapes do not cancel each other out.
240 On SWF side, we need to start a new shape for each
241 closed polygon, because SWF only knows EOFILL.
243 endshape();
244 startshape(output);
245 startFill();
248 if(((int)(lastx*20) != (int)(firstx*20) ||
249 (int)(lasty*20) != (int)(firsty*20)) &&
250 fill && !init)
252 plotxy p0;
253 plotxy p1;
254 p0.x=lastx;
255 p0.y=lasty;
256 p1.x=firstx;
257 p1.y=firsty;
258 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
259 line(tag, p0, p1, m);
261 firstx=x;
262 firsty=y;
263 init = 0;
265 else if(outline->type == SWF_PATHTYPE_LINE)
267 plotxy p0;
268 plotxy p1;
269 p0.x=lastx;
270 p0.y=lasty;
271 p1.x=x;
272 p1.y=y;
273 if(log) printf("line: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
274 line(tag, p0,p1,m);
276 else if(outline->type == SWF_PATHTYPE_BEZIER)
278 plotxy p0;
279 plotxy p1;
280 plotxy p2;
281 plotxy p3;
282 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
283 p0.x=x;
284 p0.y=y;
285 p1.x=o2->C.x/(float)0xffff+lastx;
286 p1.y=o2->C.y/(float)0xffff+lasty;
287 p2.x=o2->B.x/(float)0xffff+lastx;
288 p2.y=o2->B.y/(float)0xffff+lasty;
289 p3.x=lastx;
290 p3.y=lasty;
291 if(log) printf("spline: %f,%f -> %f,%f\n",p3.x,p3.y,p0.x,p0.y);
292 spline(tag,p0,p1,p2,p3,m);
294 else {
295 msg("<error> drawpath: unknown outline type:%d\n", outline->type);
297 lastx=x;
298 lasty=y;
299 outline = outline->link;
301 if(((int)(lastx*20) != (int)(firstx*20) ||
302 (int)(lasty*20) != (int)(firsty*20)) &&
303 fill)
305 plotxy p0;
306 plotxy p1;
307 p0.x=lastx;
308 p0.y=lasty;
309 p1.x=firstx;
310 p1.y=firsty;
311 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
312 line(tag, p0, p1, m);
316 plotxy getPivot(SWF_OUTLINE*outline, int dir, double line_width, int end, int trytwo)
318 SWF_PATHPOINT next, next2;
319 double xv=0,yv=0, xv2=0, yv2=0;
320 plotxy p;
321 int two = 0;
323 if(!end) {
324 if(outline->type == SWF_PATHTYPE_LINE) {
325 next = outline->dest;
326 } else {
327 next = ((SWF_BEZIERSEGMENT*)outline)->B;
328 if(next.x==0 && next.y==0) {
329 next = ((SWF_BEZIERSEGMENT*)outline)->C;
331 if(next.x==0 && next.y==0) {
332 next = ((SWF_BEZIERSEGMENT*)outline)->dest;
335 next2 = next;
336 if(trytwo && outline->last && outline->last->type != SWF_PATHTYPE_MOVE) {
337 if(outline->type == SWF_PATHTYPE_LINE) {
338 next2 = outline->last->dest;
339 } else {
340 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)(outline->last))->C;
341 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)(outline->last))->B;
342 next2.x = outline->last->dest.x - c.x;
343 next2.y = outline->last->dest.y - c.y;
344 if(next2.x==0 && next2.y==0) {
345 next2.x = outline->last->dest.x - b.x;
346 next2.y = outline->last->dest.y - b.y;
348 if(next2.x==0 && next2.y==0) {
349 next2.x = outline->last->dest.x;
350 next2.y = outline->last->dest.y;
353 two = 1;
355 } else {
356 if(outline->type == SWF_PATHTYPE_LINE) {
357 next = outline->dest;
358 } else {
359 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)outline)->C;
360 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)outline)->B;
361 next.x = outline->dest.x - c.x;
362 next.y = outline->dest.y - c.y;
363 if(next.x==0 && next.y==0) {
364 next.x = outline->dest.x - b.x;
365 next.y = outline->dest.y - b.y;
367 if(next.x==0 && next.y==0) {
368 next.x = outline->dest.x;
369 next.y = outline->dest.y;
372 next2 = next;
373 if(trytwo && outline->link && outline->link->type != SWF_PATHTYPE_MOVE) {
374 if(outline->type == SWF_PATHTYPE_LINE) {
375 next2 = outline->link->dest;
376 } else {
377 next2 = ((SWF_BEZIERSEGMENT*)(outline->link))->B;
378 if(next2.x==0 && next2.y==0) {
379 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->C;
381 if(next2.x==0 && next2.y==0) {
382 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->dest;
385 two = 1;
389 if(dir) {
390 xv = next.y/(float)0xffff;
391 yv = -next.x/(float)0xffff;
392 } else {
393 xv = -next.y/(float)0xffff;
394 yv = next.x/(float)0xffff;
397 double r = (line_width/2)/sqrt(xv*xv+yv*yv);
398 xv*=r;
399 yv*=r;
401 if(two) {
402 if(dir) {
403 xv2 = next2.y/(float)0xffff;
404 yv2 = -next2.x/(float)0xffff;
405 } else {
406 xv2 = -next2.y/(float)0xffff;
407 yv2 = next2.x/(float)0xffff;
410 double r2 = (line_width/2)/sqrt(xv2*xv2+yv2*yv2);
411 xv2*=r2;
412 yv2*=r2;
413 xv = (xv+xv2)/2;
414 yv = (yv+yv2)/2;
415 double r3 = (line_width/2)/sqrt(xv*xv+yv*yv);
416 xv *= r3;
417 yv *= r3;
420 p.x = xv;
421 p.y = yv;
422 return p;
425 void drawShortPath(struct swfoutput*output, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline)
427 double lastx=x, lasty=y;
428 while (outline && outline->type != SWF_PATHTYPE_MOVE)
430 x += (outline->dest.x/(float)0xffff);
431 y += (outline->dest.y/(float)0xffff);
433 if(outline->type == SWF_PATHTYPE_LINE)
435 plotxy p0, p1;
436 p0.x=lastx;
437 p0.y=lasty;
438 p1.x= x;
439 p1.y= y;
440 line(tag, p0, p1, m);
442 else if(outline->type == SWF_PATHTYPE_BEZIER)
444 plotxy p0,p1,p2,p3;
445 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
446 p3.x=lastx;
447 p3.y=lasty;
448 p1.x=o2->C.x/(float)0xffff+lastx;
449 p1.y=o2->C.y/(float)0xffff+lasty;
450 p2.x=o2->B.x/(float)0xffff+lastx;
451 p2.y=o2->B.y/(float)0xffff+lasty;
452 p0.x=x;
453 p0.y=y;
454 spline(tag,p0,p1,p2,p3,m);
456 lastx=x;
457 lasty=y;
458 outline = outline->link;
462 void drawShortPathWithEnds(struct swfoutput*output, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline, int num, int line_cap, int line_join, double line_width)
464 plotxy d,d2;
465 int back = 0;
467 if(line_cap == LINE_CAP_BUTT || line_cap == LINE_CAP_SQUARE) {
468 endshape();
469 startshape(output);
470 SWF_OUTLINE *last, *tmp=outline;
471 plotxy s,e,p0,p1,p2,p3,m0,m1,m2,m3;
472 double x2 = x;
473 double y2 = y;
474 double lx=x,ly=y;
475 double ee = 1.0;
476 int nr;
477 while(tmp && tmp->type != SWF_PATHTYPE_MOVE) {
478 last = tmp;
479 lx += (tmp->dest.x/(float)0xffff);
480 ly += (tmp->dest.y/(float)0xffff);
481 tmp = tmp->link;
483 s = getPivot(outline, 0, line_width, 0, 0);
484 e = getPivot(last, 0, line_width, 1, 0);
486 if(line_cap == LINE_CAP_BUTT) {
487 /* make the clipping rectangle slighly bigger
488 than the line ending, so that it get's clipped
489 propertly */
490 //ee = 1.01;
491 ee=1.0;
494 p0.x = x2 + s.x*ee;
495 p0.y = y2 + s.y*ee;
496 p1.x = x2 - s.x*ee;
497 p1.y = y2 - s.y*ee;
498 p2.x = x2 - s.y - s.x*ee;
499 p2.y = y2 + s.x - s.y*ee;
500 p3.x = x2 - s.y + s.x*ee;
501 p3.y = y2 + s.x + s.y*ee;
502 m0.x = lx + e.x*ee;
503 m0.y = ly + e.y*ee;
504 m1.x = lx - e.x*ee;
505 m1.y = ly - e.y*ee;
506 m2.x = lx + e.y - e.x*ee;
507 m2.y = ly - e.x - e.y*ee;
508 m3.x = lx + e.y + e.x*ee;
509 m3.y = ly - e.x + e.y*ee;
511 for(nr=0;nr<2;nr++) {
512 int dir=0;
513 struct plotxy q0,q1,q2,q3,q4,q5;
514 startFill();
515 if(line_cap == LINE_CAP_BUTT) {
516 if(dir) {
517 q0.x = 0; q0.y = 0;
518 q1.x = sizex; q1.y = 0;
519 q2.x = sizex; q2.y = sizey;
520 q3.x = 0; q3.y = sizey;
521 } else {
522 q0.x = sizex; q0.y = sizey;
523 q1.x = 0; q1.y = sizey;
524 q2.x = 0; q2.y = 0;
525 q3.x = sizex; q3.y = 0;
527 q4.x = p0.x;
528 q4.y = p0.y;
529 moveto(tag, q0);
530 lineto(tag, q1);
531 lineto(tag, q2);
532 lineto(tag, q3);
533 lineto(tag, q0);
535 transform(&q4,m);
536 lineto(tag, q4);
539 line(tag, p0, p1, m);
540 line(tag, p1, p2, m);
541 line(tag, p2, p3, m);
542 line(tag, p3, p0, m);
544 if(line_cap == LINE_CAP_BUTT) {
545 lineto(tag, q0);
546 swf_ShapeSetEnd(tag);
547 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
548 swf_ObjectPlaceClip(tag,shapeid,depth,NULL,NULL,NULL,depth+2-nr);
549 depth++;
550 shapeid = -1;
551 startshape(output);
553 p0 = m0;
554 p1 = m1;
555 p2 = m2;
556 p3 = m3;
559 stopFill();
562 drawShortPath(output,x,y,m,outline);
564 if(line_cap == LINE_CAP_BUTT) {
565 endshape();
566 startshape(output);
570 void drawT1toRect(struct swfoutput*output, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline, int num, int line_cap, int line_join, double line_width)
572 plotxy d1,d2,p1,p2,p3,p4;
574 d1.x = (outline->dest.x/(float)0xffff);
575 d1.y = (outline->dest.y/(float)0xffff);
576 d2 = getPivot(outline, 0, line_width, 0, 0);
578 assert(line_cap != LINE_CAP_ROUND);
579 if(line_cap == LINE_CAP_SQUARE) {
580 x -= +d2.y;
581 y -= -d2.x;
582 d1.x += +2*d2.y;
583 d1.y += -2*d2.x;
586 p1.x = x + d2.x;
587 p1.y = y + d2.y;
588 p2.x = x + d2.x + d1.x;
589 p2.y = y + d2.y + d1.y;
590 p3.x = x - d2.x + d1.x;
591 p3.y = y - d2.y + d1.y;
592 p4.x = x - d2.x;
593 p4.y = y - d2.y;
595 line(tag, p1,p2, m);
596 line(tag, p2,p3, m);
597 line(tag, p3,p4, m);
598 line(tag, p4,p1, m);
601 void drawShortPathWithStraightEnds(struct swfoutput*output, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline, int num, int line_cap, int line_join, double line_width)
603 SWF_OUTLINE*tmp=outline;
604 double xx=x,yy=y;
605 int stop=0;
606 assert(shapeid>=0);
608 startFill();
609 drawT1toRect(output, x, y, m,outline, num, line_cap, line_join, line_width);
611 while(tmp->link && tmp->link->type!=SWF_PATHTYPE_MOVE) {
612 xx += (tmp->dest.x/(float)0xffff);
613 yy += (tmp->dest.y/(float)0xffff);
614 tmp = tmp->link;
617 assert(tmp->type == SWF_PATHTYPE_LINE);
618 assert(outline->type == SWF_PATHTYPE_LINE);
620 if(tmp!=outline) {
622 if(outline->link == tmp) {
623 /* the two straight line segments (which are everything we
624 need to draw) are very likely to overlap. To avoid that
625 they cancel each other out at the end points, start a new
626 shape for the second one */
627 endshape();startshape(output);
628 startFill();
631 drawT1toRect(output, xx, yy, m, tmp, num, line_cap, line_join, line_width);
633 if(outline->link != tmp)
635 stopFill();stop=1;
636 int save= tmp->type;
637 tmp->type = SWF_PATHTYPE_MOVE;
638 x += (outline->dest.x/(float)0xffff);
639 y += (outline->dest.y/(float)0xffff);
640 outline = outline->link;
641 drawShortPath(output, x, y, m, outline);
642 tmp->type = save;
645 if(!stop)
646 stopFill();
649 static int t1len(SWF_OUTLINE*line)
651 int num=0;
652 while(line && line->type != SWF_PATHTYPE_MOVE) {
653 num++;
654 line = line->link;
656 return num;
659 static float t1linelen(SWF_OUTLINE*line)
661 float x,y;
662 x = (line->dest.x/(float)0xffff);
663 y = (line->dest.y/(float)0xffff);
664 return sqrt(x*x+y*y);
667 void drawpath2poly(struct swfoutput *output, SWF_OUTLINE*outline, struct swfmatrix*m, int log, int line_join, int line_cap, double line_width, double miter_limit)
669 if( tag->id != ST_DEFINESHAPE &&
670 tag->id != ST_DEFINESHAPE2 &&
671 tag->id != ST_DEFINESHAPE3) {
672 msg("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
673 exit(1);
675 assert(shapeid>=0);
676 double x=0,y=0;
677 double lastx=0,lasty=0;
678 int valid = 0;
679 int lastwasline = 0;
680 SWF_OUTLINE*tmp = outline, *last = 0;
681 tmp->last = 0;
683 while(1) {
684 if(tmp) {
685 x += (tmp->dest.x/(float)0xffff);
686 y += (tmp->dest.y/(float)0xffff);
688 if(!tmp || tmp->type == SWF_PATHTYPE_MOVE) {
689 if(valid && last) {
690 if(last->type == SWF_PATHTYPE_LINE && t1linelen(last)>line_width*2 &&
691 lastwasline && line_cap != LINE_CAP_ROUND)
692 drawShortPathWithStraightEnds(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
693 else
694 drawShortPathWithEnds(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
696 if(!tmp)
697 break;
698 valid = 0;
699 last = 0;
700 lastx = x;
701 lasty = y;
702 } else {
703 if(!last)
704 last = tmp;
705 valid++;
708 if(tmp && tmp->type == SWF_PATHTYPE_LINE && t1linelen(tmp)>line_width*2)
709 lastwasline = 1;
710 else
711 lastwasline = 0;
713 if(tmp->link)
714 tmp->link->last = tmp; // make sure list is properly linked in both directions
715 tmp = tmp->link;
719 static inline int colorcompare(RGBA*a,RGBA*b)
722 if(a->r!=b->r ||
723 a->g!=b->g ||
724 a->b!=b->b ||
725 a->a!=b->a) {
726 return 0;
728 return 1;
731 static const int CHARDATAMAX = 8192;
732 struct chardata {
733 int charid;
734 int fontid;
735 int x;
736 int y;
737 int size;
738 RGBA color;
739 } chardata[CHARDATAMAX];
740 int chardatapos = 0;
742 static void putcharacters(TAG*tag)
744 int t;
745 SWFFONT font;
746 RGBA color;
747 color.r = chardata[0].color.r^255;
748 color.g = 0;
749 color.b = 0;
750 color.a = 0;
751 int lastfontid;
752 int lastx;
753 int lasty;
754 int lastsize;
755 int charids[128];
756 int charadvance[128];
757 int charstorepos;
758 int pass;
759 int glyphbits=1; //TODO: can this be zero?
760 int advancebits=1;
762 if(tag->id != ST_DEFINETEXT &&
763 tag->id != ST_DEFINETEXT2) {
764 msg("<error> internal error: putcharacters needs an text tag, not %d\n",tag->id);
765 exit(1);
767 if(!chardatapos) {
768 msg("<warning> putcharacters called with zero characters");
771 for(pass = 0; pass < 2; pass++)
773 charstorepos = 0;
774 lastfontid = -1;
775 lastx = CHARMIDX;
776 lasty = CHARMIDY;
777 lastsize = -1;
779 if(pass==1)
781 advancebits++; // add sign bit
782 swf_SetU8(tag, glyphbits);
783 swf_SetU8(tag, advancebits);
786 for(t=0;t<=chardatapos;t++)
788 if(lastfontid != chardata[t].fontid ||
789 lastx!=chardata[t].x ||
790 lasty!=chardata[t].y ||
791 !colorcompare(&color, &chardata[t].color) ||
792 charstorepos==127 ||
793 lastsize != chardata[t].size ||
794 t == chardatapos)
796 if(charstorepos && pass==0)
798 int s;
799 for(s=0;s<charstorepos;s++)
801 while(charids[s]>=(1<<glyphbits))
802 glyphbits++;
803 while(charadvance[s]>=(1<<advancebits))
804 advancebits++;
807 if(charstorepos && pass==1)
809 tag->writeBit = 0; // Q&D
810 swf_SetBits(tag, 0, 1); // GLYPH Record
811 swf_SetBits(tag, charstorepos, 7); // number of glyphs
812 int s;
813 for(s=0;s<charstorepos;s++)
815 swf_SetBits(tag, charids[s], glyphbits);
816 swf_SetBits(tag, charadvance[s], advancebits);
819 charstorepos = 0;
821 if(pass == 1 && t<chardatapos)
823 RGBA*newcolor=0;
824 SWFFONT*newfont=0;
825 int newx = 0;
826 int newy = 0;
827 if(lastx != chardata[t].x ||
828 lasty != chardata[t].y)
830 newx = chardata[t].x;
831 newy = chardata[t].y;
832 if(newx == 0)
833 newx = SET_TO_ZERO;
834 if(newy == 0)
835 newy = SET_TO_ZERO;
837 if(!colorcompare(&color, &chardata[t].color))
839 color = chardata[t].color;
840 newcolor = &color;
842 font.id = chardata[t].fontid;
843 if(lastfontid != chardata[t].fontid || lastsize != chardata[t].size)
844 newfont = &font;
846 tag->writeBit = 0; // Q&D
847 swf_TextSetInfoRecord(tag, newfont, chardata[t].size, newcolor, newx,newy);
850 lastfontid = chardata[t].fontid;
851 lastx = chardata[t].x;
852 lasty = chardata[t].y;
853 lastsize = chardata[t].size;
856 if(t==chardatapos)
857 break;
859 int advance;
860 int nextt = t==chardatapos-1?t:t+1;
861 int rel = chardata[nextt].x-chardata[t].x;
862 if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) {
863 advance = rel;
864 lastx=chardata[nextt].x;
866 else {
867 advance = 0;
868 lastx=chardata[t].x;
870 charids[charstorepos] = chardata[t].charid;
871 charadvance[charstorepos] = advance;
872 charstorepos ++;
875 chardatapos = 0;
878 static void putcharacter(struct swfoutput*obj, int fontid, int charid,
879 int x,int y, int size)
881 if(chardatapos == CHARDATAMAX)
883 msg("<warning> Character buffer too small. SWF will be slightly bigger");
884 endtext();
885 starttext(obj);
887 chardata[chardatapos].fontid = fontid;
888 chardata[chardatapos].charid = charid;
889 chardata[chardatapos].x = x;
890 chardata[chardatapos].y = y;
891 chardata[chardatapos].color = obj->fillrgb;
892 chardata[chardatapos].size = size;
893 chardatapos++;
896 struct fontlist_t
898 SWFFONT *swffont;
899 fontlist_t*next;
900 } *fontlist = 0;
902 /* process a character. */
903 static int drawchar(struct swfoutput*obj, SWFFONT *swffont, char*character, int charnr, int u, swfmatrix*m)
905 int usefonts=1;
906 if(m->m12!=0 || m->m21!=0)
907 usefonts=0;
908 if(m->m11 != m->m22)
909 usefonts=0;
911 if(!swffont) {
912 msg("<warning> Font is NULL");
913 return 0;
916 if(!usefonts) {
917 msg("<verbose> Non diagonal font matrix: %f %f", m->m11, m->m21);
918 msg("<verbose> | %f %f", m->m12, m->m22);
921 //if(usefonts && ! drawonlyshapes)
922 if (1)
924 int charid = getCharID(swffont, charnr, character, u);
926 if(charid<0) {
927 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
928 FIXNULL(character),charnr, u, FIXNULL((char*)swffont->name), swffont->numchars);
929 /*fontlist_t*it = fontlist;
930 while(it) {
931 msg("<warning> Font history: %s [%d]", it->swffont->name, getCharID(it->swffont, charnr, character, u));
932 it = it->next;
934 return 0;
937 if(shapeid>=0)
938 endshape();
939 if(textid<0)
940 starttext(obj);
942 putcharacter(obj, swffont->id, charid,(int)(m->m13*20),(int)(m->m23*20),
943 (int)(m->m11+0.5));
944 return 1;
946 /*else
948 SWF_OUTLINE*outline = font->getOutline(character, charnr);
949 char* charname = character;
951 if(!outline) {
952 msg("<warning> Didn't find character '%s' (%d) in current charset (%s)",
953 FIXNULL(character),charnr,FIXNULL(font->getName()));
954 return;
957 swfmatrix m2=*m;
958 m2.m11/=100;
959 m2.m21/=100;
960 m2.m12/=100;
961 m2.m22/=100;
963 if(textid>=0)
964 endtext();
965 if(shapeid<0)
966 startshape(obj);
968 startFill();
970 int lf = fill;
971 fill = 1;
972 drawpath(tag, outline, &m2, 0);
973 fill = lf;
977 /* draw a curved polygon. */
978 void swfoutput_drawpath(swfoutput*output, SWF_OUTLINE*outline,
979 struct swfmatrix*m)
981 if(textid>=0)
982 endtext();
984 /* Multiple polygons in one shape don't overlap correctly,
985 so we better start a new shape here if the polygon is filled
987 if(shapeid>=0 && fill && !ignoredraworder) {
988 endshape();
991 if(shapeid<0)
992 startshape(output);
994 if(!fill)
995 stopFill();
996 else
997 startFill();
999 drawpath(output, outline,m, 0);
1002 void swfoutput_drawpath2poly(struct swfoutput*output, SWF_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
1004 if(textid>=0)
1005 endtext();
1006 if(shapeid>=0)
1007 endshape();
1008 assert(shapeid<0);
1009 startshape(output);
1010 stopFill();
1012 drawpath2poly(output, outline, m, 0, line_join, line_cap, line_width, miter_limit);
1015 int getCharID(SWFFONT *font, int charnr, char *charname, int u)
1017 int t;
1018 if(charname) {
1019 for(t=0;t<font->numchars;t++) {
1020 if(font->glyphnames[t] && !strcmp(font->glyphnames[t],charname)) {
1021 return t;
1024 /* if we didn't find the character, maybe
1025 we can find the capitalized version */
1026 for(t=0;t<font->numchars;t++) {
1027 if(font->glyphnames[t] && !strcasecmp(font->glyphnames[t],charname)) {
1028 return t;
1033 if(u>0) {
1034 if(u>=font->maxascii)
1035 msg("<debug> u=%d, font->maxascii=%d",u,font->maxascii);
1036 else
1037 msg("<debug> u=%d, font->maxascii=%d ascci2glyph[%d]=%d",u,font->maxascii,u,font->ascii2glyph[u]);
1039 /* try to use the unicode id */
1040 if(u>=0 && u<font->maxascii && font->ascii2glyph[u]>=0) {
1041 return font->ascii2glyph[u];
1045 if(charnr>=0 && charnr<font->numchars) {
1046 return charnr;
1049 return -1;
1053 /* set's the t1 font index of the font to use for swfoutput_drawchar(). */
1054 void swfoutput_setfont(struct swfoutput*obj, char*fontid, char*filename)
1056 fontlist_t*last=0,*iterator;
1057 if(!fontid) {
1058 msg("<error> No fontid");
1059 return;
1062 if(obj->swffont && obj->swffont->name && !strcmp((char*)obj->swffont->name,fontid))
1063 return;
1065 iterator = fontlist;
1066 while(iterator) {
1067 if(!strcmp((char*)iterator->swffont->name,fontid)) {
1068 obj->swffont = iterator->swffont;
1069 return;
1071 last = iterator;
1072 iterator = iterator->next;
1075 if(!filename) {
1076 msg("<error> No filename given for font- internal error?");
1077 return;
1080 SWFFONT*swffont = swf_LoadFont(filename);
1082 if(swffont == 0) {
1083 msg("<warning> Couldn't load font %s (%s)", fontid, filename);
1084 swffont = swf_LoadFont(0);
1087 swf_FontSetID(swffont, ++currentswfid);
1089 if(screenloglevel >= LOGLEVEL_DEBUG) {
1090 // print font information
1091 msg("<debug> Font %s (%s)",swffont->name, filename);
1092 msg("<debug> | ID: %d", swffont->id);
1093 msg("<debug> | Version: %d", swffont->version);
1094 msg("<debug> | Name: %s", fontid);
1095 msg("<debug> | Numchars: %d", swffont->numchars);
1096 msg("<debug> | Maxascii: %d", swffont->maxascii);
1097 msg("<debug> | Style: %d", swffont->style);
1098 msg("<debug> | Encoding: %d", swffont->encoding);
1099 for(int iii=0; iii<swffont->numchars;iii++) {
1100 msg("<debug> | Glyph %d) name=%s, unicode=%d\n", iii, swffont->glyphnames[iii], swffont->glyph2ascii[iii]);
1104 /* set the font name to the ID we use here */
1105 if(swffont->name) free(swffont->name);
1106 swffont->name = (U8*)strdup(fontid);
1108 iterator = new fontlist_t;
1109 iterator->swffont = swffont;
1110 iterator->next = 0;
1112 if(last)
1113 last->next = iterator;
1114 else
1115 fontlist = iterator;
1117 obj->swffont = swffont;
1120 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1122 fontlist_t *iterator = fontlist;
1123 while(iterator) {
1124 if(!strcmp((char*)iterator->swffont->name,fontid))
1125 return 1;
1126 iterator = iterator->next;
1128 return 0;
1131 /* set's the matrix which is to be applied to characters drawn by
1132 swfoutput_drawchar() */
1133 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1134 double m21,double m22)
1136 if(obj->fontm11 == m11 &&
1137 obj->fontm12 == m12 &&
1138 obj->fontm21 == m21 &&
1139 obj->fontm22 == m22)
1140 return;
1141 // if(textid>=0)
1142 // endtext();
1143 obj->fontm11 = m11;
1144 obj->fontm12 = m12;
1145 obj->fontm21 = m21;
1146 obj->fontm22 = m22;
1149 /* draws a character at x,y. */
1150 int swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr, int u)
1152 swfmatrix m;
1153 m.m11 = obj->fontm11;
1154 m.m12 = obj->fontm12;
1155 m.m21 = obj->fontm21;
1156 m.m22 = obj->fontm22;
1157 m.m13 = x;
1158 m.m23 = y;
1159 return drawchar(obj, obj->swffont, character, charnr, u, &m);
1162 /* initialize the swf writer */
1163 void swfoutput_init(struct swfoutput* obj, char*_filename, int x1, int y1, int x2, int y2)
1165 RGBA rgb;
1166 SRECT r;
1167 memset(obj, 0, sizeof(struct swfoutput));
1168 filename = _filename;
1169 sizex = x2;
1170 sizey = y2;
1172 msg("<verbose> initializing swf output for size %d*%d\n", sizex,sizey);
1174 obj->swffont = 0;
1175 obj->drawmode = -1;
1177 memset(&swf,0x00,sizeof(SWF));
1179 swf.fileVersion = flashversion;
1180 swf.frameRate = 0x0040; // 1 frame per 4 seconds
1181 swf.movieSize.xmin = 20*x1;
1182 swf.movieSize.ymin = 20*y1;
1183 swf.movieSize.xmax = 20*x2;
1184 swf.movieSize.ymax = 20*y2;
1186 depth = 1;
1188 swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1189 tag = swf.firstTag;
1190 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1191 swf_SetRGB(tag,&rgb);
1193 if(1)/* add white rectangle */
1195 SRECT r;
1196 SHAPE* s;
1197 int ls1=0,fs1=0;
1198 int shapeid = ++currentswfid;
1199 r.xmin = x1*20;
1200 r.ymin = y1*20;
1201 r.xmax = x2*20;
1202 r.ymax = y2*20;
1203 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
1204 swf_ShapeNew(&s);
1205 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1206 swf_SetU16(tag,shapeid);
1207 swf_SetRect(tag,&r);
1208 swf_SetShapeHeader(tag,s);
1209 swf_ShapeSetAll(tag,s,x1*20,y1*20,ls1,fs1,0);
1210 swf_ShapeSetLine(tag,s,20*(x2-x1),0);
1211 swf_ShapeSetLine(tag,s,0,20*(y2-y1));
1212 swf_ShapeSetLine(tag,s,20*(x1-x2),0);
1213 swf_ShapeSetLine(tag,s,0,20*(y1-y2));
1214 swf_ShapeSetEnd(tag);
1215 swf_ShapeFree(s);
1216 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1217 swf_ObjectPlace(tag,shapeid,depth++,0,0,0);
1218 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1219 swf_ObjectPlaceClip(tag,shapeid,depth++,0,0,0,65535);
1222 if(flag_protected)
1223 tag = swf_InsertTag(tag, ST_PROTECT);
1225 startdepth = depth;
1228 void swfoutput_setprotected() //write PROTECT tag
1230 flag_protected = 1;
1233 static void startshape(struct swfoutput*obj)
1235 RGBA rgb;
1236 SRECT r;
1238 if(textid>=0)
1239 endtext();
1241 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1243 swf_ShapeNew(&shape);
1244 linestyleid = swf_ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1245 rgb.r = obj->fillrgb.r;
1246 rgb.g = obj->fillrgb.g;
1247 rgb.b = obj->fillrgb.b;
1248 fillstyleid = swf_ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1250 shapeid = ++currentswfid;
1251 swf_SetU16(tag,shapeid); // ID
1253 r.xmin = 0;
1254 r.ymin = 0;
1255 r.xmax = 20*sizex;
1256 r.ymax = 20*sizey;
1258 swf_SetRect(tag,&r);
1260 swf_SetShapeStyles(tag,shape);
1261 swf_ShapeCountBits(shape,NULL,NULL);
1262 swf_SetShapeBits(tag,shape);
1264 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,linestyleid,0,0);
1265 swflastx=swflasty=0;
1266 lastwasfill = 0;
1267 shapeisempty = 1;
1270 static void starttext(struct swfoutput*obj)
1272 SRECT r;
1273 MATRIX m;
1274 if(shapeid>=0)
1275 endshape();
1276 tag = swf_InsertTag(tag,ST_DEFINETEXT);
1277 textid = ++currentswfid;
1278 swf_SetU16(tag, textid);
1280 r.xmin = 0;
1281 r.ymin = 0;
1282 r.xmax = 20*sizex;
1283 r.ymax = 20*sizey;
1285 swf_SetRect(tag,&r);
1287 m.sx = 65536;
1288 m.sy = 65536;
1289 m.r0 = 0;
1290 m.r1 = 0;
1291 m.tx = 0;
1292 m.ty = 0;
1294 swf_SetMatrix(tag,&m);
1295 swflastx=swflasty=0;
1298 static void endshape()
1300 if(shapeid<0)
1301 return;
1302 swf_ShapeSetEnd(tag);
1304 if(shapeisempty) {
1305 // delete the tag again, we didn't do anything
1306 TAG*todel = tag;
1307 tag = tag->prev;
1308 swf_DeleteTag(todel);
1309 } else {
1310 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1311 swf_ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL);
1313 shapeid = -1;
1316 static void endtext()
1318 if(textid<0)
1319 return;
1320 putcharacters(tag);
1321 swf_SetU8(tag,0);
1322 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1323 swf_ObjectPlace(tag,textid,/*depth*/depth++,NULL,NULL,NULL);
1324 textid = -1;
1327 static void endpage(struct swfoutput*obj)
1329 if(shapeid>=0)
1330 endshape();
1331 if(textid>=0)
1332 endtext();
1333 while(clippos)
1334 swfoutput_endclip(obj);
1336 if(insertstoptag) {
1337 ActionTAG*atag=0;
1338 atag = action_Stop(atag);
1339 atag = action_End(atag);
1340 tag = swf_InsertTag(tag,ST_DOACTION);
1341 swf_ActionSet(tag,atag);
1343 tag = swf_InsertTag(tag,ST_SHOWFRAME);
1346 void swfoutput_newpage(struct swfoutput*obj)
1348 endpage(obj);
1350 for(depth--;depth>=startdepth;depth--) {
1351 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1352 swf_SetU16(tag,depth);
1355 depth = startdepth;
1358 /* "destroy" like in (oo-terminology) "destructor". Perform cleaning
1359 up, complete the swf, and write it out. */
1360 void swfoutput_destroy(struct swfoutput* obj)
1362 endpage(obj);
1363 fontlist_t *tmp,*iterator = fontlist;
1364 while(iterator) {
1365 TAG*mtag = swf.firstTag;
1366 if(iterator->swffont) {
1367 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1368 swf_FontSetDefine2(mtag, iterator->swffont);
1369 swf_FontFree(iterator->swffont);
1372 tmp = iterator;
1373 iterator = iterator->next;
1374 delete tmp;
1377 if(!filename)
1378 return;
1379 if(filename)
1380 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1381 else
1382 fi = 1; // stdout
1384 if(fi<=0) {
1385 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1386 exit(1);
1389 tag = swf_InsertTag(tag,ST_END);
1391 if(enablezlib) {
1392 if FAILED(swf_WriteSWC(fi,&swf))
1393 msg("<error> WriteSWC() failed.\n");
1394 } else {
1395 if FAILED(swf_WriteSWF(fi,&swf))
1396 msg("<error> WriteSWF() failed.\n");
1399 if(filename)
1400 close(fi);
1401 msg("<notice> SWF written\n");
1404 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1406 obj->drawmode = mode;
1407 if(mode == DRAWMODE_FILL)
1408 fill = 1;
1409 else if(mode == DRAWMODE_EOFILL)
1410 fill = 1;
1411 else if(mode == DRAWMODE_STROKE)
1412 fill = 0;
1413 else if(mode == DRAWMODE_CLIP)
1414 fill = 1;
1415 else if(mode == DRAWMODE_EOCLIP)
1416 fill = 1;
1419 void swfoutput_setfillcolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1421 if(obj->fillrgb.r == r &&
1422 obj->fillrgb.g == g &&
1423 obj->fillrgb.b == b &&
1424 obj->fillrgb.a == a) return;
1425 if(shapeid>=0)
1426 endshape();
1428 obj->fillrgb.r = r;
1429 obj->fillrgb.g = g;
1430 obj->fillrgb.b = b;
1431 obj->fillrgb.a = a;
1434 void swfoutput_setstrokecolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1436 if(obj->strokergb.r == r &&
1437 obj->strokergb.g == g &&
1438 obj->strokergb.b == b &&
1439 obj->strokergb.a == a) return;
1441 if(shapeid>=0)
1442 endshape();
1443 obj->strokergb.r = r;
1444 obj->strokergb.g = g;
1445 obj->strokergb.b = b;
1446 obj->strokergb.a = a;
1449 void swfoutput_setlinewidth(struct swfoutput*obj, double linewidth)
1451 if(obj->linewidth == (u16)(linewidth*20))
1452 return;
1454 if(shapeid>=0)
1455 endshape();
1456 obj->linewidth = (u16)(linewidth*20);
1460 void swfoutput_startclip(swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m)
1462 if(textid>=0)
1463 endtext();
1464 if(shapeid>=0)
1465 endshape();
1467 if(clippos >= 127)
1469 msg("<warning> Too many clip levels.");
1470 clippos --;
1473 startshape(obj);
1474 int olddrawmode = obj->drawmode;
1475 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1476 swfoutput_drawpath(obj, outline, m);
1477 swf_ShapeSetEnd(tag);
1478 swfoutput_setdrawmode(obj, olddrawmode);
1480 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1481 cliptags[clippos] = tag;
1482 clipshapes[clippos] = shapeid;
1483 clipdepths[clippos] = depth++;
1484 clippos++;
1485 shapeid = -1;
1488 void swfoutput_endclip(swfoutput*obj)
1490 if(textid>=0)
1491 endtext();
1492 if(shapeid>=0)
1493 endshape();
1495 if(!clippos) {
1496 msg("<error> Invalid end of clipping region");
1497 return;
1499 clippos--;
1500 swf_ObjectPlaceClip(cliptags[clippos],clipshapes[clippos],clipdepths[clippos],NULL,NULL,NULL,depth++);
1503 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1505 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1507 ActionTAG* actions;
1508 if(!strncmp("http://pdf2swf:", url, 15)) {
1509 char*tmp = strdup(url);
1510 int l = strlen(tmp);
1511 if(tmp[l-1] == '/')
1512 tmp[l-1] = 0;
1513 swfoutput_namedlink(obj, tmp+15, points);
1514 free(tmp);
1515 return;
1518 if(shapeid>=0)
1519 endshape();
1520 if(textid>=0)
1521 endtext();
1523 if(opennewwindow)
1524 actions = action_GetUrl(0, url, "_parent");
1525 else
1526 actions = action_GetUrl(0, url, "_this");
1527 actions = action_End(actions);
1529 drawlink(obj, actions, 0, points,0);
1531 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1533 ActionTAG* actions;
1535 if(shapeid>=0)
1536 endshape();
1537 if(textid>=0)
1538 endtext();
1540 actions = action_GotoFrame(0, page);
1541 actions = action_End(actions);
1543 drawlink(obj, actions, 0, points,0);
1546 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
1547 of the viewer objects, like subtitles, index elements etc.
1549 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
1551 ActionTAG *actions1,*actions2;
1552 char*tmp = strdup(name);
1553 char mouseover = 1;
1555 if(shapeid>=0)
1556 endshape();
1557 if(textid>=0)
1558 endtext();
1560 if(!strncmp(tmp, "call:", 5))
1562 char*x = strchr(&tmp[5], ':');
1563 if(!x) {
1564 actions1 = action_PushInt(0, 0); //number of parameters (0)
1565 actions1 = action_PushString(actions1, &tmp[5]); //function name
1566 actions1 = action_CallFunction(actions1);
1567 } else {
1568 *x = 0;
1569 actions1 = action_PushString(0, x+1); //parameter
1570 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
1571 actions1 = action_PushString(actions1, &tmp[5]); //function name
1572 actions1 = action_CallFunction(actions1);
1574 actions2 = action_End(0);
1575 mouseover = 0;
1577 else
1579 actions1 = action_PushString(0, "/:subtitle");
1580 actions1 = action_PushString(actions1, name);
1581 actions1 = action_SetVariable(actions1);
1582 actions1 = action_End(actions1);
1584 actions2 = action_PushString(0, "/:subtitle");
1585 actions2 = action_PushString(actions2, "");
1586 actions2 = action_SetVariable(actions2);
1587 actions2 = action_End(actions2);
1590 drawlink(obj, actions1, actions2, points,mouseover);
1592 swf_ActionFree(actions1);
1593 swf_ActionFree(actions2);
1594 free(tmp);
1597 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
1599 RGBA rgb;
1600 SRECT r;
1601 int lsid=0;
1602 int fsid;
1603 struct plotxy p1,p2,p3,p4;
1604 int myshapeid;
1605 int myshapeid2;
1606 double xmin,ymin;
1607 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
1608 double posx = 0;
1609 double posy = 0;
1610 int t;
1611 int buttonid = ++currentswfid;
1612 for(t=1;t<4;t++)
1614 if(points[t].x>xmax) xmax=points[t].x;
1615 if(points[t].y>ymax) ymax=points[t].y;
1616 if(points[t].x<xmin) xmin=points[t].x;
1617 if(points[t].y<ymin) ymin=points[t].y;
1620 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
1621 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
1623 /* the following code subtracts the upper left edge from all coordinates,
1624 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
1625 Necessary for preprocessing with swfcombine. */
1626 posx = xmin; posy = ymin;
1627 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
1628 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
1629 xmin -= posx; ymin -= posy;
1630 xmax -= posx; ymax -= posy;
1632 /* shape */
1633 myshapeid = ++currentswfid;
1634 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1635 swf_ShapeNew(&shape);
1636 rgb.r = rgb.b = rgb.a = rgb.g = 0;
1637 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1638 swf_SetU16(tag, myshapeid);
1639 r.xmin = (int)(xmin*20);
1640 r.ymin = (int)(ymin*20);
1641 r.xmax = (int)(xmax*20);
1642 r.ymax = (int)(ymax*20);
1643 swf_SetRect(tag,&r);
1644 swf_SetShapeStyles(tag,shape);
1645 swf_ShapeCountBits(shape,NULL,NULL);
1646 swf_SetShapeBits(tag,shape);
1647 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1648 swflastx = swflasty = 0;
1649 moveto(tag, p1);
1650 lineto(tag, p2);
1651 lineto(tag, p3);
1652 lineto(tag, p4);
1653 lineto(tag, p1);
1654 swf_ShapeSetEnd(tag);
1656 /* shape2 */
1657 myshapeid2 = ++currentswfid;
1658 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1659 swf_ShapeNew(&shape);
1660 rgb.r = rgb.b = rgb.a = rgb.g = 255;
1661 rgb.a = 40;
1662 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1663 swf_SetU16(tag, myshapeid2);
1664 r.xmin = (int)(xmin*20);
1665 r.ymin = (int)(ymin*20);
1666 r.xmax = (int)(xmax*20);
1667 r.ymax = (int)(ymax*20);
1668 swf_SetRect(tag,&r);
1669 swf_SetShapeStyles(tag,shape);
1670 swf_ShapeCountBits(shape,NULL,NULL);
1671 swf_SetShapeBits(tag,shape);
1672 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1673 swflastx = swflasty = 0;
1674 moveto(tag, p1);
1675 lineto(tag, p2);
1676 lineto(tag, p3);
1677 lineto(tag, p4);
1678 lineto(tag, p1);
1679 swf_ShapeSetEnd(tag);
1681 if(!mouseover)
1683 tag = swf_InsertTag(tag,ST_DEFINEBUTTON);
1684 swf_SetU16(tag,buttonid); //id
1685 swf_ButtonSetFlags(tag, 0); //menu=no
1686 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1687 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1688 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1689 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1690 swf_SetU8(tag,0);
1691 swf_ActionSet(tag,actions1);
1692 swf_SetU8(tag,0);
1694 else
1696 tag = swf_InsertTag(tag,ST_DEFINEBUTTON2);
1697 swf_SetU16(tag,buttonid); //id
1698 swf_ButtonSetFlags(tag, 0); //menu=no
1699 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1700 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1701 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1702 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1703 swf_SetU8(tag,0); // end of button records
1704 swf_ButtonSetCondition(tag, BC_IDLE_OVERUP);
1705 swf_ActionSet(tag,actions1);
1706 if(actions2) {
1707 swf_ButtonSetCondition(tag, BC_OVERUP_IDLE);
1708 swf_ActionSet(tag,actions2);
1709 swf_SetU8(tag,0);
1710 swf_ButtonPostProcess(tag, 2);
1711 } else {
1712 swf_SetU8(tag,0);
1713 swf_ButtonPostProcess(tag, 1);
1717 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1719 if(posx!=0 || posy!=0) {
1720 MATRIX m;
1721 swf_GetMatrix(0,&m);
1722 m.tx = (int)(posx*20);
1723 m.ty = (int)(posy*20);
1724 swf_ObjectPlace(tag, buttonid, depth++,&m,0,0);
1726 else {
1727 swf_ObjectPlace(tag, buttonid, depth++,0,0,0);
1731 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
1732 double x1,double y1,
1733 double x2,double y2,
1734 double x3,double y3,
1735 double x4,double y4)
1737 RGBA rgb;
1738 SRECT r;
1739 int lsid=0;
1740 int fsid;
1741 struct plotxy p1,p2,p3,p4;
1742 int myshapeid;
1743 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
1744 if(x2>xmax) xmax=x2;
1745 if(y2>ymax) ymax=y2;
1746 if(x2<xmin) xmin=x2;
1747 if(y2<ymin) ymin=y2;
1748 if(x3>xmax) xmax=x3;
1749 if(y3>ymax) ymax=y3;
1750 if(x3<xmin) xmin=x3;
1751 if(y3<ymin) ymin=y3;
1752 if(x4>xmax) xmax=x4;
1753 if(y4>ymax) ymax=y4;
1754 if(x4<xmin) xmin=x4;
1755 if(y4<ymin) ymin=y4;
1756 p1.x=x1; p1.y=y1;
1757 p2.x=x2; p2.y=y2;
1758 p3.x=x3; p3.y=y3;
1759 p4.x=x4; p4.y=y4;
1761 {p1.x = (int)(p1.x*20)/20.0;
1762 p1.y = (int)(p1.y*20)/20.0;
1763 p2.x = (int)(p2.x*20)/20.0;
1764 p2.y = (int)(p2.y*20)/20.0;
1765 p3.x = (int)(p3.x*20)/20.0;
1766 p3.y = (int)(p3.y*20)/20.0;
1767 p4.x = (int)(p4.x*20)/20.0;
1768 p4.y = (int)(p4.y*20)/20.0;}
1770 MATRIX m;
1771 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
1772 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
1773 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
1774 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
1776 m.tx = (int)(p1.x*20);
1777 m.ty = (int)(p1.y*20);
1779 /* shape */
1780 myshapeid = ++currentswfid;
1781 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1782 swf_ShapeNew(&shape);
1783 //lsid = ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1784 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1785 fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
1786 swf_SetU16(tag, myshapeid);
1787 r.xmin = (int)(xmin*20);
1788 r.ymin = (int)(ymin*20);
1789 r.xmax = (int)(xmax*20);
1790 r.ymax = (int)(ymax*20);
1791 swf_SetRect(tag,&r);
1792 swf_SetShapeStyles(tag,shape);
1793 swf_ShapeCountBits(shape,NULL,NULL);
1794 swf_SetShapeBits(tag,shape);
1795 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,lsid,fsid,0);
1796 swflastx = swflasty = 0;
1797 moveto(tag, p1);
1798 lineto(tag, p2);
1799 lineto(tag, p3);
1800 lineto(tag, p4);
1801 lineto(tag, p1);
1803 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
1804 ShapeSetLine (tag, shape, (int)(x1*20);
1805 ShapeSetLine (tag, shape, x*20,0);
1806 ShapeSetLine (tag, shape, 0,-y*20);
1807 ShapeSetLine (tag, shape, -x*20,0);*/
1808 swf_ShapeSetEnd(tag);
1810 /* instance */
1811 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1812 swf_ObjectPlace(tag,myshapeid,/*depth*/depth++,NULL,NULL,NULL);
1815 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
1816 double x1,double y1,
1817 double x2,double y2,
1818 double x3,double y3,
1819 double x4,double y4)
1821 TAG*oldtag;
1822 if(shapeid>=0)
1823 endshape();
1824 if(textid>=0)
1825 endtext();
1827 int bitid = ++currentswfid;
1828 oldtag = tag;
1829 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
1830 swf_SetU16(tag, bitid);
1831 if(swf_SetJPEGBits(tag, filename, jpegquality)<0) {
1832 swf_DeleteTag(tag);
1833 tag = oldtag;
1834 return -1;
1837 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1838 return bitid;
1841 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
1842 double x1,double y1,
1843 double x2,double y2,
1844 double x3,double y3,
1845 double x4,double y4)
1847 TAG*oldtag;
1848 JPEGBITS*jpeg;
1850 if(shapeid>=0)
1851 endshape();
1852 if(textid>=0)
1853 endtext();
1855 int bitid = ++currentswfid;
1856 oldtag = tag;
1857 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
1858 swf_SetU16(tag, bitid);
1859 swf_SetJPEGBits2(tag,sizex,sizey,mem,jpegquality);
1860 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1861 return bitid;
1864 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
1865 double x1,double y1,
1866 double x2,double y2,
1867 double x3,double y3,
1868 double x4,double y4)
1870 TAG*oldtag;
1871 if(shapeid>=0)
1872 endshape();
1873 if(textid>=0)
1874 endtext();
1876 int bitid = ++currentswfid;
1877 oldtag = tag;
1878 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS);
1879 swf_SetU16(tag, bitid);
1880 if(swf_SetLosslessBits(tag,sizex,sizey,mem, BMF_32BIT)<0) {
1881 swf_DeleteTag(tag);
1882 tag = oldtag;
1883 return -1;
1886 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1887 return bitid;
1890 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
1891 double x1,double y1,
1892 double x2,double y2,
1893 double x3,double y3,
1894 double x4,double y4, int n)
1896 TAG*oldtag;
1897 U8*mem2 = 0;
1898 if(shapeid>=0)
1899 endshape();
1900 if(textid>=0)
1901 endtext();
1903 if(sizex&3)
1905 /* SWF expects scanlines to be 4 byte aligned */
1906 int x,y;
1907 U8*ptr;
1908 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
1909 ptr = mem2;
1910 for(y=0;y<sizey;y++)
1912 for(x=0;x<sizex;x++)
1913 *ptr++ = mem[y*sizex+x];
1914 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
1916 mem = mem2;
1919 int bitid = ++currentswfid;
1920 oldtag = tag;
1921 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS2);
1922 swf_SetU16(tag, bitid);
1923 if(swf_SetLosslessBitsIndexed(tag,sizex,sizey,mem, pal, n)<0) {
1924 swf_DeleteTag(tag);
1925 tag = oldtag;
1926 return -1;
1928 if(mem2)
1929 free(mem2);
1931 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1932 return bitid;
1935 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
1936 double x1,double y1,
1937 double x2,double y2,
1938 double x3,double y3,
1939 double x4,double y4)
1941 if(id<0) return;
1942 if(shapeid>=0)
1943 endshape();
1944 if(textid>=0)
1945 endtext();
1947 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);