added swf_SetVideoStreamBlackFrame().
[swftools.git] / pdf2swf / swfoutput.cc
blob440278551e73ea1eea1ddecad4a3953ea43ff002
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=5;
48 int splinemaxerror=1;
49 int fontsplinemaxerror=1;
50 int filloverlap=0;
51 float minlinewidth=0.05;
53 static char storefont = 0;
54 static int flag_protected = 0;
56 typedef unsigned char u8;
57 typedef unsigned short int u16;
58 typedef unsigned long int u32;
60 static int fi;
61 static char* filename = 0;
62 static SWF swf;
63 static TAG *tag;
64 static int currentswfid = 0;
65 static int depth = 1;
66 static int startdepth = 1;
67 static int linewidth = 0;
69 static SHAPE* shape;
70 static int shapeid = -1;
71 static int textid = -1;
73 static int fillstyleid;
74 static int linestyleid;
75 static int swflastx=0;
76 static int swflasty=0;
77 static int lastwasfill = 0;
78 static int shapeisempty = 1;
79 static char fill = 0;
80 static int sizex;
81 static int sizey;
82 TAG* cliptags[128];
83 int clipshapes[128];
84 u32 clipdepths[128];
85 int clippos = 0;
87 int CHARMIDX = 0;
88 int CHARMIDY = 0;
90 char fillstylechanged = 0;
92 int bboxrectpos = -1;
93 SRECT bboxrect;
95 static void startshape(struct swfoutput* obj);
96 static void starttext(struct swfoutput* obj);
97 static void endshape(struct swfoutput* obj,int clip);
98 static void endtext(struct swfoutput* obj);
100 // matrix multiplication. changes p0
101 static void transform (plotxy*p0,struct swfmatrix*m)
103 double x,y;
104 x = m->m11*p0->x+m->m12*p0->y;
105 y = m->m21*p0->x+m->m22*p0->y;
106 p0->x = x + m->m13;
107 p0->y = y + m->m23;
110 // write a move-to command into the swf
111 static int moveto(TAG*tag, plotxy p0)
113 int rx = (int)(p0.x*20);
114 int ry = (int)(p0.y*20);
115 if(rx!=swflastx || ry!=swflasty || fillstylechanged) {
116 swf_ShapeSetMove (tag, shape, rx,ry);
117 fillstylechanged = 0;
118 swflastx=rx;
119 swflasty=ry;
120 return 1;
122 return 0;
124 static int moveto(TAG*tag, float x, float y)
126 plotxy p;
127 p.x = x;
128 p.y = y;
129 return moveto(tag, p);
131 static void addPointToBBox(int px, int py)
133 SPOINT p;
134 p.x = px;
135 p.y = py;
136 if(fill) {
137 swf_ExpandRect(&bboxrect, p);
138 } else {
139 swf_ExpandRect3(&bboxrect, p, linewidth*3/2);
143 // write a line-to command into the swf
144 static void lineto(TAG*tag, plotxy p0)
146 int px = (int)(p0.x*20);
147 int py = (int)(p0.y*20);
148 int rx = (px-swflastx);
149 int ry = (py-swflasty);
150 /* we can't skip this for rx=0,ry=0, those
151 are plots */
152 swf_ShapeSetLine (tag, shape, rx,ry);
154 addPointToBBox(swflastx,swflasty);
155 addPointToBBox(px,py);
157 shapeisempty = 0;
158 swflastx+=rx;
159 swflasty+=ry;
161 static void lineto(TAG*tag, double x, double y)
163 plotxy p;
164 p.x = x;
165 p.y = y;
166 lineto(tag, p);
170 // write a spline-to command into the swf
171 static void splineto(TAG*tag, plotxy control,plotxy end)
173 int lastlastx = swflastx;
174 int lastlasty = swflasty;
176 int cx = ((int)(control.x*20)-swflastx);
177 int cy = ((int)(control.y*20)-swflasty);
178 swflastx += cx;
179 swflasty += cy;
180 int ex = ((int)(end.x*20)-swflastx);
181 int ey = ((int)(end.y*20)-swflasty);
182 swflastx += ex;
183 swflasty += ey;
185 if(cx || cy || ex || ey) {
186 swf_ShapeSetCurve(tag, shape, cx,cy,ex,ey);
187 addPointToBBox(lastlastx ,lastlasty );
188 addPointToBBox(lastlastx+cx,lastlasty+cy);
189 addPointToBBox(lastlastx+cx+ex,lastlasty+cy+ey);
191 shapeisempty = 0;
194 /* write a line, given two points and the transformation
195 matrix. */
196 static void line(TAG*tag, plotxy p0, plotxy p1, struct swfmatrix*m)
198 transform(&p0,m);
199 transform(&p1,m);
200 moveto(tag, p0);
201 lineto(tag, p1);
204 /* write a cubic (!) spline. This involves calling the approximate()
205 function out of spline.cc to convert it to a quadratic spline. */
206 static void spline(TAG*tag,plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m)
208 double d;
209 struct qspline q[128];
210 int num;
211 int t;
212 transform(&p0,m);
213 transform(&p1,m);
214 transform(&p2,m);
215 transform(&p3,m);
216 cspline c;
217 c.start = p3;
218 c.control1 = p2;
219 c.control2 = p1;
220 c.end = p0;
222 if(storefont) {
223 /* fonts use a different approximation than shapes */
224 num = cspline_approximate(&c, q, fontsplinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
225 //num = cspline_approximate(&c, q, 10.0, APPROXIMATE_INFLECTION);
226 } else {
227 num = cspline_approximate(&c, q, splinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
229 for(t=0;t<num;t++) {
230 if(!t)
231 moveto(tag,q[t].start);
232 splineto(tag,q[t].control, q[t].end);
236 void resetdrawer()
238 swflastx = 0;
239 swflasty = 0;
242 static void stopFill()
244 if(lastwasfill)
246 swf_ShapeSetStyle(tag,shape,linestyleid,0x8000,0);
247 fillstylechanged = 1;
248 lastwasfill = 0;
251 static void startFill()
253 if(!lastwasfill)
255 swf_ShapeSetStyle(tag,shape,0x8000,fillstyleid,0);
256 fillstylechanged = 1;
257 lastwasfill = 1;
261 /* draw an outline. These are generated by pdf2swf and by t1lib
262 (representing characters). */
263 void drawpath(struct swfoutput*output, SWF_OUTLINE*outline, struct swfmatrix*m, int log)
265 if( tag->id != ST_DEFINESHAPE &&
266 tag->id != ST_DEFINESHAPE2 &&
267 tag->id != ST_DEFINESHAPE3)
269 msg("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
270 exit(1);
272 double x=0,y=0;
273 double lastx=0,lasty=0;
274 double firstx=0,firsty=0;
275 int init=1;
277 while (outline)
279 x += (outline->dest.x/(float)0xffff);
280 y += (outline->dest.y/(float)0xffff);
281 if(outline->type == SWF_PATHTYPE_MOVE)
283 //if(!init && fill && output->drawmode != DRAWMODE_EOFILL && !ignoredraworder) {
284 if(filloverlap && !init && fill && output->drawmode != DRAWMODE_EOFILL) {
285 /* drawmode=FILL (not EOFILL) means that
286 seperate shapes do not cancel each other out.
287 On SWF side, we need to start a new shape for each
288 closed polygon, because SWF only knows EOFILL.
290 endshape(output,0);
291 startshape(output);
292 startFill();
295 if(((int)(lastx*20) != (int)(firstx*20) ||
296 (int)(lasty*20) != (int)(firsty*20)) &&
297 fill && !init)
299 plotxy p0;
300 plotxy p1;
301 p0.x=lastx;
302 p0.y=lasty;
303 p1.x=firstx;
304 p1.y=firsty;
305 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
306 line(tag, p0, p1, m);
308 firstx=x;
309 firsty=y;
310 init = 0;
312 else if(outline->type == SWF_PATHTYPE_LINE)
314 plotxy p0;
315 plotxy p1;
316 p0.x=lastx;
317 p0.y=lasty;
318 p1.x=x;
319 p1.y=y;
320 if(log) printf("line: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
321 line(tag, p0,p1,m);
323 else if(outline->type == SWF_PATHTYPE_BEZIER)
325 plotxy p0;
326 plotxy p1;
327 plotxy p2;
328 plotxy p3;
329 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
330 p0.x=x;
331 p0.y=y;
332 p1.x=o2->C.x/(float)0xffff+lastx;
333 p1.y=o2->C.y/(float)0xffff+lasty;
334 p2.x=o2->B.x/(float)0xffff+lastx;
335 p2.y=o2->B.y/(float)0xffff+lasty;
336 p3.x=lastx;
337 p3.y=lasty;
338 if(log) printf("spline: %f,%f -> %f,%f\n",p3.x,p3.y,p0.x,p0.y);
339 spline(tag,p0,p1,p2,p3,m);
341 else {
342 msg("<error> drawpath: unknown outline type:%d\n", outline->type);
344 lastx=x;
345 lasty=y;
346 outline = outline->link;
348 if(((int)(lastx*20) != (int)(firstx*20) ||
349 (int)(lasty*20) != (int)(firsty*20)) &&
350 fill)
352 plotxy p0;
353 plotxy p1;
354 p0.x=lastx;
355 p0.y=lasty;
356 p1.x=firstx;
357 p1.y=firsty;
358 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
359 line(tag, p0, p1, m);
363 plotxy getPivot(SWF_OUTLINE*outline, int dir, double line_width, int end, int trytwo)
365 SWF_PATHPOINT next, next2;
366 double xv=0,yv=0, xv2=0, yv2=0;
367 plotxy p;
368 int two = 0;
370 if(!end) {
371 if(outline->type == SWF_PATHTYPE_LINE) {
372 next = outline->dest;
373 } else {
374 next = ((SWF_BEZIERSEGMENT*)outline)->B;
375 if(next.x==0 && next.y==0) {
376 next = ((SWF_BEZIERSEGMENT*)outline)->C;
378 if(next.x==0 && next.y==0) {
379 next = ((SWF_BEZIERSEGMENT*)outline)->dest;
382 next2 = next;
383 if(trytwo && outline->last && outline->last->type != SWF_PATHTYPE_MOVE) {
384 if(outline->type == SWF_PATHTYPE_LINE) {
385 next2 = outline->last->dest;
386 } else {
387 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)(outline->last))->C;
388 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)(outline->last))->B;
389 next2.x = outline->last->dest.x - c.x;
390 next2.y = outline->last->dest.y - c.y;
391 if(next2.x==0 && next2.y==0) {
392 next2.x = outline->last->dest.x - b.x;
393 next2.y = outline->last->dest.y - b.y;
395 if(next2.x==0 && next2.y==0) {
396 next2.x = outline->last->dest.x;
397 next2.y = outline->last->dest.y;
400 two = 1;
402 } else {
403 if(outline->type == SWF_PATHTYPE_LINE) {
404 next = outline->dest;
405 } else {
406 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)outline)->C;
407 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)outline)->B;
408 next.x = outline->dest.x - c.x;
409 next.y = outline->dest.y - c.y;
410 if(next.x==0 && next.y==0) {
411 next.x = outline->dest.x - b.x;
412 next.y = outline->dest.y - b.y;
414 if(next.x==0 && next.y==0) {
415 next.x = outline->dest.x;
416 next.y = outline->dest.y;
419 next2 = next;
420 if(trytwo && outline->link && outline->link->type != SWF_PATHTYPE_MOVE) {
421 if(outline->type == SWF_PATHTYPE_LINE) {
422 next2 = outline->link->dest;
423 } else {
424 next2 = ((SWF_BEZIERSEGMENT*)(outline->link))->B;
425 if(next2.x==0 && next2.y==0) {
426 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->C;
428 if(next2.x==0 && next2.y==0) {
429 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->dest;
432 two = 1;
436 if(dir) {
437 xv = next.y/(float)0xffff;
438 yv = -next.x/(float)0xffff;
439 } else {
440 xv = -next.y/(float)0xffff;
441 yv = next.x/(float)0xffff;
444 double r = (line_width/2)/sqrt(xv*xv+yv*yv);
445 xv*=r;
446 yv*=r;
448 if(two) {
449 if(dir) {
450 xv2 = next2.y/(float)0xffff;
451 yv2 = -next2.x/(float)0xffff;
452 } else {
453 xv2 = -next2.y/(float)0xffff;
454 yv2 = next2.x/(float)0xffff;
457 double r2 = (line_width/2)/sqrt(xv2*xv2+yv2*yv2);
458 xv2*=r2;
459 yv2*=r2;
460 xv = (xv+xv2)/2;
461 yv = (yv+yv2)/2;
462 double r3 = (line_width/2)/sqrt(xv*xv+yv*yv);
463 xv *= r3;
464 yv *= r3;
467 p.x = xv;
468 p.y = yv;
469 return p;
472 void drawShortPath(struct swfoutput*output, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline)
474 double lastx=x, lasty=y;
475 while (outline && outline->type != SWF_PATHTYPE_MOVE)
477 x += (outline->dest.x/(float)0xffff);
478 y += (outline->dest.y/(float)0xffff);
480 if(outline->type == SWF_PATHTYPE_LINE)
482 plotxy p0, p1;
483 p0.x=lastx;
484 p0.y=lasty;
485 p1.x= x;
486 p1.y= y;
487 line(tag, p0, p1, m);
489 else if(outline->type == SWF_PATHTYPE_BEZIER)
491 plotxy p0,p1,p2,p3;
492 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
493 p3.x=lastx;
494 p3.y=lasty;
495 p1.x=o2->C.x/(float)0xffff+lastx;
496 p1.y=o2->C.y/(float)0xffff+lasty;
497 p2.x=o2->B.x/(float)0xffff+lastx;
498 p2.y=o2->B.y/(float)0xffff+lasty;
499 p0.x=x;
500 p0.y=y;
501 spline(tag,p0,p1,p2,p3,m);
503 lastx=x;
504 lasty=y;
505 outline = outline->link;
509 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)
511 plotxy d,d2;
512 int back = 0;
514 if(line_cap == LINE_CAP_BUTT || line_cap == LINE_CAP_SQUARE) {
515 endshape(output,0);
516 startshape(output);
517 SWF_OUTLINE *last, *tmp=outline;
518 plotxy s,e,p0,p1,p2,p3,m0,m1,m2,m3;
519 double x2 = x;
520 double y2 = y;
521 double lx=x,ly=y;
522 double ee = 1.0;
523 int nr;
524 while(tmp && tmp->type != SWF_PATHTYPE_MOVE) {
525 last = tmp;
526 lx += (tmp->dest.x/(float)0xffff);
527 ly += (tmp->dest.y/(float)0xffff);
528 tmp = tmp->link;
530 s = getPivot(outline, 0, line_width, 0, 0);
531 e = getPivot(last, 0, line_width, 1, 0);
533 if(line_cap == LINE_CAP_BUTT) {
534 /* make the clipping rectangle slighly bigger
535 than the line ending, so that it get's clipped
536 propertly */
537 //ee = 1.01;
538 ee=1.0;
541 p0.x = x2 + s.x*ee;
542 p0.y = y2 + s.y*ee;
543 p1.x = x2 - s.x*ee;
544 p1.y = y2 - s.y*ee;
545 p2.x = x2 - s.y - s.x*ee;
546 p2.y = y2 + s.x - s.y*ee;
547 p3.x = x2 - s.y + s.x*ee;
548 p3.y = y2 + s.x + s.y*ee;
549 m0.x = lx + e.x*ee;
550 m0.y = ly + e.y*ee;
551 m1.x = lx - e.x*ee;
552 m1.y = ly - e.y*ee;
553 m2.x = lx + e.y - e.x*ee;
554 m2.y = ly - e.x - e.y*ee;
555 m3.x = lx + e.y + e.x*ee;
556 m3.y = ly - e.x + e.y*ee;
558 for(nr=0;nr<2;nr++) {
559 int dir=0;
560 struct plotxy q0,q1,q2,q3,q4,q5;
562 startFill();
563 if(line_cap == LINE_CAP_BUTT) {
564 if(dir) {
565 q0.x = 0; q0.y = 0;
566 q1.x = sizex; q1.y = 0;
567 q2.x = sizex; q2.y = sizey;
568 q3.x = 0; q3.y = sizey;
569 } else {
570 q0.x = sizex; q0.y = sizey;
571 q1.x = 0; q1.y = sizey;
572 q2.x = 0; q2.y = 0;
573 q3.x = sizex; q3.y = 0;
575 q4.x = p0.x;
576 q4.y = p0.y;
577 moveto(tag, q0);
578 lineto(tag, q1);
579 lineto(tag, q2);
580 lineto(tag, q3);
581 lineto(tag, q0);
583 transform(&q4,m);
584 lineto(tag, q4);
587 line(tag, p0, p1, m);
588 line(tag, p1, p2, m);
589 line(tag, p2, p3, m);
590 line(tag, p3, p0, m);
592 if(line_cap == LINE_CAP_BUTT) {
593 lineto(tag, q0);
594 endshape(output, depth+2-nr);
595 startshape(output);
597 p0 = m0;
598 p1 = m1;
599 p2 = m2;
600 p3 = m3;
603 stopFill();
606 drawShortPath(output,x,y,m,outline);
608 if(line_cap == LINE_CAP_BUTT) {
609 endshape(output,0);
610 startshape(output);
614 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)
616 plotxy d1,d2,p1,p2,p3,p4;
618 d1.x = (outline->dest.x/(float)0xffff);
619 d1.y = (outline->dest.y/(float)0xffff);
620 d2 = getPivot(outline, 0, line_width, 0, 0);
622 assert(line_cap != LINE_CAP_ROUND);
623 if(line_cap == LINE_CAP_SQUARE) {
624 x -= +d2.y;
625 y -= -d2.x;
626 d1.x += +2*d2.y;
627 d1.y += -2*d2.x;
630 p1.x = x + d2.x;
631 p1.y = y + d2.y;
632 p2.x = x + d2.x + d1.x;
633 p2.y = y + d2.y + d1.y;
634 p3.x = x - d2.x + d1.x;
635 p3.y = y - d2.y + d1.y;
636 p4.x = x - d2.x;
637 p4.y = y - d2.y;
639 line(tag, p1,p2, m);
640 line(tag, p2,p3, m);
641 line(tag, p3,p4, m);
642 line(tag, p4,p1, m);
645 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)
647 SWF_OUTLINE*tmp=outline;
648 double xx=x,yy=y;
649 int stop=0;
650 assert(shapeid>=0);
652 startFill();
653 drawT1toRect(output, x, y, m,outline, num, line_cap, line_join, line_width);
655 while(tmp->link && tmp->link->type!=SWF_PATHTYPE_MOVE) {
656 xx += (tmp->dest.x/(float)0xffff);
657 yy += (tmp->dest.y/(float)0xffff);
658 tmp = tmp->link;
661 assert(tmp->type == SWF_PATHTYPE_LINE);
662 assert(outline->type == SWF_PATHTYPE_LINE);
664 if(tmp!=outline) {
666 if(outline->link == tmp) {
667 /* the two straight line segments (which are everything we
668 need to draw) are very likely to overlap. To avoid that
669 they cancel each other out at the end points, start a new
670 shape for the second one */
671 endshape(output,0);startshape(output);
672 startFill();
675 drawT1toRect(output, xx, yy, m, tmp, num, line_cap, line_join, line_width);
677 if(outline->link != tmp)
679 stopFill();stop=1;
680 int save= tmp->type;
681 tmp->type = SWF_PATHTYPE_MOVE;
682 x += (outline->dest.x/(float)0xffff);
683 y += (outline->dest.y/(float)0xffff);
684 outline = outline->link;
685 drawShortPath(output, x, y, m, outline);
686 tmp->type = save;
689 if(!stop)
690 stopFill();
693 static int t1len(SWF_OUTLINE*line)
695 int num=0;
696 while(line && line->type != SWF_PATHTYPE_MOVE) {
697 num++;
698 line = line->link;
700 return num;
703 static float t1linelen(SWF_OUTLINE*line)
705 float x,y;
706 x = (line->dest.x/(float)0xffff);
707 y = (line->dest.y/(float)0xffff);
708 return sqrt(x*x+y*y);
711 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)
713 if( tag->id != ST_DEFINESHAPE &&
714 tag->id != ST_DEFINESHAPE2 &&
715 tag->id != ST_DEFINESHAPE3) {
716 msg("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
717 exit(1);
719 assert(shapeid>=0);
720 double x=0,y=0;
721 double lastx=0,lasty=0;
722 int valid = 0;
723 int lastwasline = 0;
724 SWF_OUTLINE*tmp = outline, *last = 0;
725 tmp->last = 0;
727 while(1) {
728 if(tmp) {
729 x += (tmp->dest.x/(float)0xffff);
730 y += (tmp->dest.y/(float)0xffff);
732 if(!tmp || tmp->type == SWF_PATHTYPE_MOVE) {
733 if(valid && last) {
734 if(last->type == SWF_PATHTYPE_LINE && t1linelen(last)>line_width*2 &&
735 lastwasline && line_cap != LINE_CAP_ROUND)
736 drawShortPathWithStraightEnds(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
737 else
738 drawShortPathWithEnds(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
740 if(!tmp)
741 break;
742 valid = 0;
743 last = 0;
744 lastx = x;
745 lasty = y;
746 } else {
747 if(!last)
748 last = tmp;
749 valid++;
752 if(tmp && tmp->type == SWF_PATHTYPE_LINE && t1linelen(tmp)>line_width*2)
753 lastwasline = 1;
754 else
755 lastwasline = 0;
757 if(tmp->link)
758 tmp->link->last = tmp; // make sure list is properly linked in both directions
759 tmp = tmp->link;
763 static inline int colorcompare(RGBA*a,RGBA*b)
766 if(a->r!=b->r ||
767 a->g!=b->g ||
768 a->b!=b->b ||
769 a->a!=b->a) {
770 return 0;
772 return 1;
775 static const int CHARDATAMAX = 8192;
776 struct chardata {
777 int charid;
778 int fontid; /* TODO: use a SWFFONT instead */
779 int x;
780 int y;
781 int size;
782 RGBA color;
783 } chardata[CHARDATAMAX];
784 int chardatapos = 0;
786 static SRECT getcharacterbbox(SWFFONT*font)
788 SRECT r;
789 char debug = 0;
790 memset(&r, 0, sizeof(r));
792 int t;
793 if(debug) printf("\n");
794 for(t=0;t<chardatapos;t++)
796 if(chardata[t].fontid != font->id) {
797 msg("<error> Internal error: fontid %d != fontid %d", chardata[t].fontid, font->id);
798 exit(1);
800 SRECT b = font->layout->bounds[chardata[t].charid];
801 b.xmin *= chardata[t].size;
802 b.ymin *= chardata[t].size;
803 b.xmax *= chardata[t].size;
804 b.ymax *= chardata[t].size;
805 b.xmin /= 1024;
806 b.ymin /= 1024;
807 b.xmax /= 1024;
808 b.ymax /= 1024;
809 b.xmin += chardata[t].x;
810 b.ymin += chardata[t].y;
811 b.xmax += chardata[t].x;
812 b.ymax += chardata[t].y;
814 /* until we solve the INTERNAL_SCALING problem (see below)
815 make sure the bounding box is big enough */
816 b.xmin -= 20;
817 b.ymin -= 20;
818 b.xmax += 20;
819 b.ymax += 20;
821 if(debug) printf("(%f,%f,%f,%f) -> (%f,%f,%f,%f) [font %d/%d, char %d]\n",
822 font->layout->bounds[chardata[t].charid].xmin/20.0,
823 font->layout->bounds[chardata[t].charid].ymin/20.0,
824 font->layout->bounds[chardata[t].charid].xmax/20.0,
825 font->layout->bounds[chardata[t].charid].ymax/20.0,
826 b.xmin/20.0,
827 b.ymin/20.0,
828 b.xmax/20.0,
829 b.ymax/20.0,
830 chardata[t].fontid,
831 font->id,
832 chardata[t].charid
834 swf_ExpandRect2(&r, &b);
836 if(debug) printf("-----> (%f,%f,%f,%f)\n",
837 r.xmin/20.0,
838 r.ymin/20.0,
839 r.xmax/20.0,
840 r.ymax/20.0);
841 return r;
844 static void putcharacters(TAG*tag)
846 int t;
847 SWFFONT font;
848 RGBA color;
849 color.r = chardata[0].color.r^255;
850 color.g = 0;
851 color.b = 0;
852 color.a = 0;
853 int lastfontid;
854 int lastx;
855 int lasty;
856 int lastsize;
857 int charids[128];
858 int charadvance[128];
859 int charstorepos;
860 int pass;
861 int glyphbits=1; //TODO: can this be zero?
862 int advancebits=1;
864 if(tag->id != ST_DEFINETEXT &&
865 tag->id != ST_DEFINETEXT2) {
866 msg("<error> internal error: putcharacters needs an text tag, not %d\n",tag->id);
867 exit(1);
869 if(!chardatapos) {
870 msg("<warning> putcharacters called with zero characters");
873 for(pass = 0; pass < 2; pass++)
875 charstorepos = 0;
876 lastfontid = -1;
877 lastx = CHARMIDX;
878 lasty = CHARMIDY;
879 lastsize = -1;
881 if(pass==1)
883 advancebits++; // add sign bit
884 swf_SetU8(tag, glyphbits);
885 swf_SetU8(tag, advancebits);
888 for(t=0;t<=chardatapos;t++)
890 if(lastfontid != chardata[t].fontid ||
891 lastx!=chardata[t].x ||
892 lasty!=chardata[t].y ||
893 !colorcompare(&color, &chardata[t].color) ||
894 charstorepos==127 ||
895 lastsize != chardata[t].size ||
896 t == chardatapos)
898 if(charstorepos && pass==0)
900 int s;
901 for(s=0;s<charstorepos;s++)
903 while(charids[s]>=(1<<glyphbits))
904 glyphbits++;
905 while(charadvance[s]>=(1<<advancebits))
906 advancebits++;
909 if(charstorepos && pass==1)
911 tag->writeBit = 0; // Q&D
912 swf_SetBits(tag, 0, 1); // GLYPH Record
913 swf_SetBits(tag, charstorepos, 7); // number of glyphs
914 int s;
915 for(s=0;s<charstorepos;s++)
917 swf_SetBits(tag, charids[s], glyphbits);
918 swf_SetBits(tag, charadvance[s], advancebits);
921 charstorepos = 0;
923 if(pass == 1 && t<chardatapos)
925 RGBA*newcolor=0;
926 SWFFONT*newfont=0;
927 int newx = 0;
928 int newy = 0;
929 if(lastx != chardata[t].x ||
930 lasty != chardata[t].y)
932 newx = chardata[t].x;
933 newy = chardata[t].y;
934 if(newx == 0)
935 newx = SET_TO_ZERO;
936 if(newy == 0)
937 newy = SET_TO_ZERO;
939 if(!colorcompare(&color, &chardata[t].color))
941 color = chardata[t].color;
942 newcolor = &color;
944 font.id = chardata[t].fontid;
945 if(lastfontid != chardata[t].fontid || lastsize != chardata[t].size)
946 newfont = &font;
948 tag->writeBit = 0; // Q&D
949 swf_TextSetInfoRecord(tag, newfont, chardata[t].size, newcolor, newx,newy);
952 lastfontid = chardata[t].fontid;
953 lastx = chardata[t].x;
954 lasty = chardata[t].y;
955 lastsize = chardata[t].size;
958 if(t==chardatapos)
959 break;
961 int advance;
962 int nextt = t==chardatapos-1?t:t+1;
963 int rel = chardata[nextt].x-chardata[t].x;
964 if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) {
965 advance = rel;
966 lastx=chardata[nextt].x;
968 else {
969 advance = 0;
970 lastx=chardata[t].x;
972 charids[charstorepos] = chardata[t].charid;
973 charadvance[charstorepos] = advance;
974 charstorepos ++;
977 chardatapos = 0;
980 static void putcharacter(struct swfoutput*obj, int fontid, int charid,
981 int x,int y, int size)
983 if(chardatapos == CHARDATAMAX)
985 msg("<warning> Character buffer too small. SWF will be slightly bigger");
986 endtext(obj);
987 starttext(obj);
989 chardata[chardatapos].fontid = fontid;
990 chardata[chardatapos].charid = charid;
991 chardata[chardatapos].x = x;
992 chardata[chardatapos].y = y;
993 chardata[chardatapos].color = obj->fillrgb;
994 chardata[chardatapos].size = size;
995 chardatapos++;
998 struct fontlist_t
1000 SWFFONT *swffont;
1001 fontlist_t*next;
1002 } *fontlist = 0;
1004 /* todo: why don't higher values (64, 1024) work here? */
1005 #define FONT_INTERNAL_SIZE 1
1007 /* process a character. */
1008 static int drawchar(struct swfoutput*obj, SWFFONT *swffont, char*character, int charnr, int u, swfmatrix*m)
1010 if(!swffont) {
1011 msg("<warning> Font is NULL");
1012 return 0;
1015 int charid = getCharID(swffont, charnr, character, u);
1017 if(charid<0) {
1018 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1019 FIXNULL(character),charnr, u, FIXNULL((char*)swffont->name), swffont->numchars);
1020 return 0;
1023 if(shapeid>=0)
1024 endshape(obj,0);
1025 if(textid<0)
1026 starttext(obj);
1028 float x = m->m13;
1029 float y = m->m23;
1030 float det = ((m->m11*m->m22)-(m->m21*m->m12));
1031 if(fabs(det) < 0.0005) {
1032 /* x direction equals y direction- the text is invisible */
1033 return 1;
1035 det = 20*FONT_INTERNAL_SIZE / det;
1037 SPOINT p;
1038 p.x = (SCOORD)(( x * m->m22 - y * m->m12)*det);
1039 p.y = (SCOORD)((- x * m->m21 + y * m->m11)*det);
1041 putcharacter(obj, swffont->id, charid,p.x,p.y,FONT_INTERNAL_SIZE);
1042 swf_FontUseGlyph(swffont, charid);
1043 return 1;
1045 /*else
1047 SWF_OUTLINE*outline = font->getOutline(character, charnr);
1048 char* charname = character;
1050 if(!outline) {
1051 msg("<warning> Didn't find character '%s' (%d) in current charset (%s)",
1052 FIXNULL(character),charnr,FIXNULL(font->getName()));
1053 return;
1056 swfmatrix m2=*m;
1057 m2.m11/=100;
1058 m2.m21/=100;
1059 m2.m12/=100;
1060 m2.m22/=100;
1062 if(textid>=0)
1063 endtext(obj);
1064 if(shapeid<0)
1065 startshape(obj);
1067 startFill();
1069 int lf = fill;
1070 fill = 1;
1071 drawpath(tag, outline, &m2, 0);
1072 fill = lf;
1076 static void endtext(swfoutput*obj)
1078 if(textid<0)
1079 return;
1081 tag = swf_InsertTag(tag,ST_DEFINETEXT);
1082 swf_SetU16(tag, textid);
1084 SRECT r;
1085 r = getcharacterbbox(obj->swffont);
1087 swf_SetRect(tag,&r);
1089 MATRIX m;
1090 swf_GetMatrix(0, &m);
1091 swf_SetMatrix(tag,&m);
1093 putcharacters(tag);
1094 swf_SetU8(tag,0);
1095 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1096 swf_ObjectPlace(tag,textid,/*depth*/depth++,&obj->fontmatrix,NULL,NULL);
1097 textid = -1;
1101 /* draw a curved polygon. */
1102 void swfoutput_drawpath(swfoutput*output, SWF_OUTLINE*outline,
1103 struct swfmatrix*m)
1105 if(textid>=0)
1106 endtext(output);
1108 /* Multiple polygons in one shape don't overlap correctly,
1109 so we better start a new shape here if the polygon is filled
1111 if(shapeid>=0 && fill && !ignoredraworder) {
1112 endshape(output,0);
1115 if(shapeid<0)
1116 startshape(output);
1118 if(!fill)
1119 stopFill();
1120 else
1121 startFill();
1123 drawpath(output, outline,m, 0);
1126 void swfoutput_drawpath2poly(struct swfoutput*output, SWF_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
1128 if(textid>=0)
1129 endtext(output);
1130 if(shapeid>=0)
1131 endshape(output,0);
1132 assert(shapeid<0);
1133 startshape(output);
1134 stopFill();
1136 drawpath2poly(output, outline, m, 0, line_join, line_cap, line_width, miter_limit);
1139 int getCharID(SWFFONT *font, int charnr, char *charname, int u)
1141 int t;
1142 if(charname) {
1143 for(t=0;t<font->numchars;t++) {
1144 if(font->glyphnames[t] && !strcmp(font->glyphnames[t],charname)) {
1145 return t;
1148 /* if we didn't find the character, maybe
1149 we can find the capitalized version */
1150 for(t=0;t<font->numchars;t++) {
1151 if(font->glyphnames[t] && !strcasecmp(font->glyphnames[t],charname)) {
1152 return t;
1157 if(u>0) {
1158 /* try to use the unicode id */
1159 if(u>=0 && u<font->maxascii && font->ascii2glyph[u]>=0) {
1160 return font->ascii2glyph[u];
1164 if(charnr>=0 && charnr<font->numchars) {
1165 return charnr;
1168 if(font->encoding != FONT_ENCODING_UNICODE) {
1169 /* the following only works if the font encoding
1170 is US-ASCII based. It's needed for fonts which return broken unicode
1171 indices */
1172 if(charnr>=0 && charnr<font->maxascii && font->ascii2glyph[charnr]>=0) {
1173 return font->ascii2glyph[charnr];
1177 return -1;
1181 /* set's the t1 font index of the font to use for swfoutput_drawchar(). */
1182 void swfoutput_setfont(struct swfoutput*obj, char*fontid, char*filename)
1184 fontlist_t*last=0,*iterator;
1185 if(!fontid) {
1186 msg("<error> No fontid");
1187 return;
1190 if(obj->swffont && obj->swffont->name && !strcmp((char*)obj->swffont->name,fontid))
1191 return;
1193 /* TODO: remove the need for this (enhance getcharacterbbox so that it can cope
1194 with multiple fonts */
1195 endtext(obj);
1197 iterator = fontlist;
1198 while(iterator) {
1199 if(!strcmp((char*)iterator->swffont->name,fontid)) {
1200 obj->swffont = iterator->swffont;
1201 return;
1203 last = iterator;
1204 iterator = iterator->next;
1207 if(!filename) {
1208 msg("<error> No filename given for font- internal error?");
1209 return;
1212 swf_SetLoadFontParameters(64,/*skip unused*/0,/*full unicode*/1);
1213 SWFFONT*swffont = swf_LoadFont(filename);
1215 if(swffont == 0) {
1216 msg("<warning> Couldn't load font %s (%s)", fontid, filename);
1217 swffont = swf_LoadFont(0);
1220 swf_FontSetID(swffont, ++currentswfid);
1222 if(screenloglevel >= LOGLEVEL_DEBUG) {
1223 // print font information
1224 msg("<debug> Font %s (%s)",swffont->name, filename);
1225 msg("<debug> | ID: %d", swffont->id);
1226 msg("<debug> | Version: %d", swffont->version);
1227 msg("<debug> | Name: %s", fontid);
1228 msg("<debug> | Numchars: %d", swffont->numchars);
1229 msg("<debug> | Maxascii: %d", swffont->maxascii);
1230 msg("<debug> | Style: %d", swffont->style);
1231 msg("<debug> | Encoding: %d", swffont->encoding);
1232 for(int iii=0; iii<swffont->numchars;iii++) {
1233 msg("<debug> | Glyph %d) name=%s, unicode=%d size=%d bbox=(%.2f,%.2f,%.2f,%.2f)\n", iii, swffont->glyphnames[iii], swffont->glyph2ascii[iii], swffont->glyph[iii].shape->bitlen,
1234 swffont->layout->bounds[iii].xmin/20.0,
1235 swffont->layout->bounds[iii].ymin/20.0,
1236 swffont->layout->bounds[iii].xmax/20.0,
1237 swffont->layout->bounds[iii].ymax/20.0
1239 int t;
1240 for(t=0;t<swffont->maxascii;t++) {
1241 if(swffont->ascii2glyph[t] == iii)
1242 msg("<debug> | - maps to %d",t);
1247 /* set the font name to the ID we use here */
1248 if(swffont->name) free(swffont->name);
1249 swffont->name = (U8*)strdup(fontid);
1251 iterator = new fontlist_t;
1252 iterator->swffont = swffont;
1253 iterator->next = 0;
1255 if(last)
1256 last->next = iterator;
1257 else
1258 fontlist = iterator;
1260 obj->swffont = swffont;
1263 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1265 fontlist_t *iterator = fontlist;
1266 while(iterator) {
1267 if(!strcmp((char*)iterator->swffont->name,fontid))
1268 return 1;
1269 iterator = iterator->next;
1271 return 0;
1274 /* set's the matrix which is to be applied to characters drawn by
1275 swfoutput_drawchar() */
1276 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1277 double m21,double m22)
1279 if(obj->fontm11 == m11 &&
1280 obj->fontm12 == m12 &&
1281 obj->fontm21 == m21 &&
1282 obj->fontm22 == m22)
1283 return;
1284 if(textid>=0)
1285 endtext(obj);
1286 obj->fontm11 = m11;
1287 obj->fontm12 = m12;
1288 obj->fontm21 = m21;
1289 obj->fontm22 = m22;
1291 MATRIX m;
1292 m.sx = (U32)(((obj->fontm11)*65536)/FONT_INTERNAL_SIZE); m.r1 = (U32)(((obj->fontm12)*65536)/FONT_INTERNAL_SIZE);
1293 m.r0 = (U32)(((obj->fontm21)*65536)/FONT_INTERNAL_SIZE); m.sy = (U32)(((obj->fontm22)*65536)/FONT_INTERNAL_SIZE);
1294 m.tx = 0;
1295 m.ty = 0;
1296 obj->fontmatrix = m;
1299 /* draws a character at x,y. */
1300 int swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr, int u)
1302 swfmatrix m;
1303 m.m11 = obj->fontm11;
1304 m.m12 = obj->fontm12;
1305 m.m21 = obj->fontm21;
1306 m.m22 = obj->fontm22;
1307 m.m13 = x;
1308 m.m23 = y;
1309 return drawchar(obj, obj->swffont, character, charnr, u, &m);
1312 /* initialize the swf writer */
1313 void swfoutput_init(struct swfoutput* obj, char*_filename, int x1, int y1, int x2, int y2)
1315 RGBA rgb;
1316 SRECT r;
1317 memset(obj, 0, sizeof(struct swfoutput));
1318 filename = _filename;
1319 sizex = x2;
1320 sizey = y2;
1322 msg("<verbose> initializing swf output for size %d*%d\n", sizex,sizey);
1324 obj->swffont = 0;
1325 obj->drawmode = -1;
1327 memset(&swf,0x00,sizeof(SWF));
1329 swf.fileVersion = flashversion;
1330 swf.frameRate = 0x0040; // 1 frame per 4 seconds
1331 swf.movieSize.xmin = 20*x1;
1332 swf.movieSize.ymin = 20*y1;
1333 swf.movieSize.xmax = 20*x2;
1334 swf.movieSize.ymax = 20*y2;
1336 depth = 1;
1338 swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1339 tag = swf.firstTag;
1340 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1341 swf_SetRGB(tag,&rgb);
1343 if(1)/* add white rectangle */
1345 SRECT r;
1346 SHAPE* s;
1347 int ls1=0,fs1=0;
1348 int shapeid = ++currentswfid;
1349 r.xmin = x1*20;
1350 r.ymin = y1*20;
1351 r.xmax = x2*20;
1352 r.ymax = y2*20;
1353 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
1354 swf_ShapeNew(&s);
1355 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1356 swf_SetU16(tag,shapeid);
1357 swf_SetRect(tag,&r);
1358 swf_SetShapeHeader(tag,s);
1359 swf_ShapeSetAll(tag,s,x1*20,y1*20,ls1,fs1,0);
1360 swf_ShapeSetLine(tag,s,20*(x2-x1),0);
1361 swf_ShapeSetLine(tag,s,0,20*(y2-y1));
1362 swf_ShapeSetLine(tag,s,20*(x1-x2),0);
1363 swf_ShapeSetLine(tag,s,0,20*(y1-y2));
1364 swf_ShapeSetEnd(tag);
1365 swf_ShapeFree(s);
1366 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1367 swf_ObjectPlace(tag,shapeid,depth++,0,0,0);
1368 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1369 swf_ObjectPlaceClip(tag,shapeid,depth++,0,0,0,65535);
1372 if(flag_protected)
1373 tag = swf_InsertTag(tag, ST_PROTECT);
1375 startdepth = depth;
1378 void swfoutput_setprotected() //write PROTECT tag
1380 flag_protected = 1;
1383 static void startshape(struct swfoutput*obj)
1385 RGBA rgb;
1386 SRECT r;
1388 if(textid>=0)
1389 endtext(obj);
1391 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1393 swf_ShapeNew(&shape);
1394 linestyleid = swf_ShapeAddLineStyle(shape,linewidth,&obj->strokergb);
1395 rgb.r = obj->fillrgb.r;
1396 rgb.g = obj->fillrgb.g;
1397 rgb.b = obj->fillrgb.b;
1398 fillstyleid = swf_ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1400 shapeid = ++currentswfid;
1401 swf_SetU16(tag,shapeid); // ID
1403 /* TODO: patch back */
1404 bboxrectpos = tag->len;
1405 r.xmin = 0;
1406 r.ymin = 0;
1407 r.xmax = 20*sizex;
1408 r.ymax = 20*sizey;
1409 swf_SetRect(tag,&r);
1411 memset(&bboxrect, 0, sizeof(bboxrect));
1413 swf_SetShapeStyles(tag,shape);
1414 swf_ShapeCountBits(shape,NULL,NULL);
1415 swf_SetShapeBits(tag,shape);
1417 /* TODO: do we really need this? */
1418 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,linestyleid,0,0);
1419 swflastx=swflasty=0;
1420 lastwasfill = 0;
1421 shapeisempty = 1;
1424 static void starttext(struct swfoutput*obj)
1426 if(shapeid>=0)
1427 endshape(obj,0);
1429 textid = ++currentswfid;
1431 swflastx=swflasty=0;
1435 /* TODO: move to ../lib/rfxswf */
1436 void changeRect(TAG*tag, int pos, SRECT*newrect)
1438 /* determine length of old rect */
1439 tag->pos = pos;
1440 tag->readBit = 0;
1441 SRECT old;
1442 swf_GetRect(tag, &old);
1443 swf_ResetReadBits(tag);
1444 int pos_end = tag->pos;
1446 int len = tag->len - pos_end;
1447 U8*data = (U8*)malloc(len);
1448 memcpy(data, &tag->data[pos_end], len);
1449 tag->writeBit = 0;
1450 tag->len = pos;
1451 swf_SetRect(tag, newrect);
1452 swf_SetBlock(tag, data, len);
1453 free(data);
1454 tag->pos = tag->readBit = 0;
1457 void cancelshape(swfoutput*obj)
1459 /* delete old shape tag */
1460 TAG*todel = tag;
1461 tag = tag->prev;
1462 swf_DeleteTag(todel);
1463 shapeid = -1;
1464 bboxrectpos = -1;
1467 void fixAreas(swfoutput*obj)
1469 if(!shapeisempty && fill &&
1470 (bboxrect.xmin == bboxrect.xmax ||
1471 bboxrect.ymin == bboxrect.ymax) &&
1472 minlinewidth >= 0.001
1474 msg("<debug> Shape has size 0: width=%.2f height=%.2f",
1475 (bboxrect.xmax-bboxrect.xmin)/20.0,
1476 (bboxrect.ymax-bboxrect.ymin)/20.0
1479 SRECT r = bboxrect;
1481 if(r.xmin == r.xmax && r.ymin == r.ymax) {
1482 /* this thing comes down to a single dot- nothing to fix here */
1483 return;
1486 cancelshape(obj);
1488 RGBA save_col = obj->strokergb;
1489 int save_width = linewidth;
1491 obj->strokergb = obj->fillrgb;
1492 linewidth = (int)(minlinewidth*20);
1493 if(linewidth==0) linewidth = 1;
1495 startshape(obj);
1497 moveto(tag, r.xmin/20.0,r.ymin/20.0);
1498 lineto(tag, r.xmax/20.0,r.ymax/20.0);
1500 obj->strokergb = save_col;
1501 linewidth = save_width;
1506 static void endshape(swfoutput*obj, int clipdepth)
1508 if(shapeid<0)
1509 return;
1511 if(!clipdepth)
1512 fixAreas(obj);
1514 if(shapeisempty ||
1515 (bboxrect.xmin == bboxrect.xmax && bboxrect.ymin == bboxrect.ymax))
1517 // delete the shape again, we didn't do anything
1518 cancelshape(obj);
1519 return;
1522 swf_ShapeSetEnd(tag);
1524 changeRect(tag, bboxrectpos, &bboxrect);
1526 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1527 if(clipdepth)
1528 swf_ObjectPlaceClip(tag,shapeid,depth++,NULL,NULL,NULL,clipdepth);
1529 else
1530 swf_ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL);
1532 shapeid = -1;
1533 bboxrectpos = -1;
1536 static void endpage(struct swfoutput*obj)
1538 if(shapeid>=0)
1539 endshape(obj,0);
1540 if(textid>=0)
1541 endtext(obj);
1542 while(clippos)
1543 swfoutput_endclip(obj);
1545 if(insertstoptag) {
1546 ActionTAG*atag=0;
1547 atag = action_Stop(atag);
1548 atag = action_End(atag);
1549 tag = swf_InsertTag(tag,ST_DOACTION);
1550 swf_ActionSet(tag,atag);
1552 tag = swf_InsertTag(tag,ST_SHOWFRAME);
1555 void swfoutput_newpage(struct swfoutput*obj)
1557 endpage(obj);
1559 for(depth--;depth>=startdepth;depth--) {
1560 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1561 swf_SetU16(tag,depth);
1564 depth = startdepth;
1567 /* Perform cleaning up, complete the swf, and write it out. */
1568 void swfoutput_destroy(struct swfoutput* obj)
1570 endpage(obj);
1571 fontlist_t *tmp,*iterator = fontlist;
1572 while(iterator) {
1573 TAG*mtag = swf.firstTag;
1574 if(iterator->swffont) {
1575 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1576 /*if(!storeallcharacters)
1577 swf_FontReduce(iterator->swffont);*/
1578 swf_FontSetDefine2(mtag, iterator->swffont);
1579 swf_FontFree(iterator->swffont);
1582 tmp = iterator;
1583 iterator = iterator->next;
1584 delete tmp;
1587 if(!filename)
1588 return;
1589 if(filename)
1590 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1591 else
1592 fi = 1; // stdout
1594 if(fi<=0) {
1595 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1596 exit(1);
1599 tag = swf_InsertTag(tag,ST_END);
1601 if(enablezlib || flashversion>=6) {
1602 if FAILED(swf_WriteSWC(fi,&swf))
1603 msg("<error> WriteSWC() failed.\n");
1604 } else {
1605 if FAILED(swf_WriteSWF(fi,&swf))
1606 msg("<error> WriteSWF() failed.\n");
1609 if(filename)
1610 close(fi);
1611 msg("<notice> SWF written\n");
1614 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1616 obj->drawmode = mode;
1617 if(mode == DRAWMODE_FILL)
1618 fill = 1;
1619 else if(mode == DRAWMODE_EOFILL)
1620 fill = 1;
1621 else if(mode == DRAWMODE_STROKE)
1622 fill = 0;
1623 else if(mode == DRAWMODE_CLIP)
1624 fill = 1;
1625 else if(mode == DRAWMODE_EOCLIP)
1626 fill = 1;
1629 void swfoutput_setfillcolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1631 if(obj->fillrgb.r == r &&
1632 obj->fillrgb.g == g &&
1633 obj->fillrgb.b == b &&
1634 obj->fillrgb.a == a) return;
1635 if(shapeid>=0)
1636 endshape(obj,0);
1638 obj->fillrgb.r = r;
1639 obj->fillrgb.g = g;
1640 obj->fillrgb.b = b;
1641 obj->fillrgb.a = a;
1644 void swfoutput_setstrokecolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1646 if(obj->strokergb.r == r &&
1647 obj->strokergb.g == g &&
1648 obj->strokergb.b == b &&
1649 obj->strokergb.a == a) return;
1651 if(shapeid>=0)
1652 endshape(obj,0);
1653 obj->strokergb.r = r;
1654 obj->strokergb.g = g;
1655 obj->strokergb.b = b;
1656 obj->strokergb.a = a;
1659 void swfoutput_setlinewidth(struct swfoutput*obj, double _linewidth)
1661 if(linewidth == (u16)(_linewidth*20))
1662 return;
1664 if(shapeid>=0)
1665 endshape(obj,0);
1666 linewidth = (u16)(_linewidth*20);
1670 void swfoutput_startclip(swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m)
1672 if(textid>=0)
1673 endtext(obj);
1674 if(shapeid>=0)
1675 endshape(obj,0);
1677 if(clippos >= 127)
1679 msg("<warning> Too many clip levels.");
1680 clippos --;
1683 startshape(obj);
1684 int olddrawmode = obj->drawmode;
1685 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1686 swfoutput_drawpath(obj, outline, m);
1687 swf_ShapeSetEnd(tag);
1688 swfoutput_setdrawmode(obj, olddrawmode);
1690 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1691 cliptags[clippos] = tag;
1692 clipshapes[clippos] = shapeid;
1693 clipdepths[clippos] = depth++;
1694 clippos++;
1695 shapeid = -1;
1698 void swfoutput_endclip(swfoutput*obj)
1700 if(textid>=0)
1701 endtext(obj);
1702 if(shapeid>=0)
1703 endshape(obj,0);
1705 if(!clippos) {
1706 msg("<error> Invalid end of clipping region");
1707 return;
1709 clippos--;
1710 swf_ObjectPlaceClip(cliptags[clippos],clipshapes[clippos],clipdepths[clippos],NULL,NULL,NULL,depth++);
1713 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1715 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1717 ActionTAG* actions;
1718 if(!strncmp("http://pdf2swf:", url, 15)) {
1719 char*tmp = strdup(url);
1720 int l = strlen(tmp);
1721 if(tmp[l-1] == '/')
1722 tmp[l-1] = 0;
1723 swfoutput_namedlink(obj, tmp+15, points);
1724 free(tmp);
1725 return;
1728 if(shapeid>=0)
1729 endshape(obj,0);
1730 if(textid>=0)
1731 endtext(obj);
1733 if(opennewwindow)
1734 actions = action_GetUrl(0, url, "_parent");
1735 else
1736 actions = action_GetUrl(0, url, "_this");
1737 actions = action_End(actions);
1739 drawlink(obj, actions, 0, points,0);
1741 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1743 ActionTAG* actions;
1745 if(shapeid>=0)
1746 endshape(obj,0);
1747 if(textid>=0)
1748 endtext(obj);
1750 actions = action_GotoFrame(0, page);
1751 actions = action_End(actions);
1753 drawlink(obj, actions, 0, points,0);
1756 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
1757 of the viewer objects, like subtitles, index elements etc.
1759 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
1761 ActionTAG *actions1,*actions2;
1762 char*tmp = strdup(name);
1763 char mouseover = 1;
1765 if(shapeid>=0)
1766 endshape(obj,0);
1767 if(textid>=0)
1768 endtext(obj);
1770 if(!strncmp(tmp, "call:", 5))
1772 char*x = strchr(&tmp[5], ':');
1773 if(!x) {
1774 actions1 = action_PushInt(0, 0); //number of parameters (0)
1775 actions1 = action_PushString(actions1, &tmp[5]); //function name
1776 actions1 = action_CallFunction(actions1);
1777 } else {
1778 *x = 0;
1779 actions1 = action_PushString(0, x+1); //parameter
1780 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
1781 actions1 = action_PushString(actions1, &tmp[5]); //function name
1782 actions1 = action_CallFunction(actions1);
1784 actions2 = action_End(0);
1785 mouseover = 0;
1787 else
1789 actions1 = action_PushString(0, "/:subtitle");
1790 actions1 = action_PushString(actions1, name);
1791 actions1 = action_SetVariable(actions1);
1792 actions1 = action_End(actions1);
1794 actions2 = action_PushString(0, "/:subtitle");
1795 actions2 = action_PushString(actions2, "");
1796 actions2 = action_SetVariable(actions2);
1797 actions2 = action_End(actions2);
1800 drawlink(obj, actions1, actions2, points,mouseover);
1802 swf_ActionFree(actions1);
1803 swf_ActionFree(actions2);
1804 free(tmp);
1807 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
1809 RGBA rgb;
1810 SRECT r;
1811 int lsid=0;
1812 int fsid;
1813 struct plotxy p1,p2,p3,p4;
1814 int myshapeid;
1815 int myshapeid2;
1816 double xmin,ymin;
1817 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
1818 double posx = 0;
1819 double posy = 0;
1820 int t;
1821 int buttonid = ++currentswfid;
1822 for(t=1;t<4;t++)
1824 if(points[t].x>xmax) xmax=points[t].x;
1825 if(points[t].y>ymax) ymax=points[t].y;
1826 if(points[t].x<xmin) xmin=points[t].x;
1827 if(points[t].y<ymin) ymin=points[t].y;
1830 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
1831 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
1833 /* the following code subtracts the upper left edge from all coordinates,
1834 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
1835 Necessary for preprocessing with swfcombine. */
1836 posx = xmin; posy = ymin;
1837 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
1838 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
1839 xmin -= posx; ymin -= posy;
1840 xmax -= posx; ymax -= posy;
1842 /* shape */
1843 myshapeid = ++currentswfid;
1844 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1845 swf_ShapeNew(&shape);
1846 rgb.r = rgb.b = rgb.a = rgb.g = 0;
1847 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1848 swf_SetU16(tag, myshapeid);
1849 r.xmin = (int)(xmin*20);
1850 r.ymin = (int)(ymin*20);
1851 r.xmax = (int)(xmax*20);
1852 r.ymax = (int)(ymax*20);
1853 swf_SetRect(tag,&r);
1854 swf_SetShapeStyles(tag,shape);
1855 swf_ShapeCountBits(shape,NULL,NULL);
1856 swf_SetShapeBits(tag,shape);
1857 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1858 swflastx = swflasty = 0;
1859 moveto(tag, p1);
1860 lineto(tag, p2);
1861 lineto(tag, p3);
1862 lineto(tag, p4);
1863 lineto(tag, p1);
1864 swf_ShapeSetEnd(tag);
1866 /* shape2 */
1867 myshapeid2 = ++currentswfid;
1868 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1869 swf_ShapeNew(&shape);
1870 rgb.r = rgb.b = rgb.a = rgb.g = 255;
1871 rgb.a = 40;
1872 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1873 swf_SetU16(tag, myshapeid2);
1874 r.xmin = (int)(xmin*20);
1875 r.ymin = (int)(ymin*20);
1876 r.xmax = (int)(xmax*20);
1877 r.ymax = (int)(ymax*20);
1878 swf_SetRect(tag,&r);
1879 swf_SetShapeStyles(tag,shape);
1880 swf_ShapeCountBits(shape,NULL,NULL);
1881 swf_SetShapeBits(tag,shape);
1882 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1883 swflastx = swflasty = 0;
1884 moveto(tag, p1);
1885 lineto(tag, p2);
1886 lineto(tag, p3);
1887 lineto(tag, p4);
1888 lineto(tag, p1);
1889 swf_ShapeSetEnd(tag);
1891 if(!mouseover)
1893 tag = swf_InsertTag(tag,ST_DEFINEBUTTON);
1894 swf_SetU16(tag,buttonid); //id
1895 swf_ButtonSetFlags(tag, 0); //menu=no
1896 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1897 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1898 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1899 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1900 swf_SetU8(tag,0);
1901 swf_ActionSet(tag,actions1);
1902 swf_SetU8(tag,0);
1904 else
1906 tag = swf_InsertTag(tag,ST_DEFINEBUTTON2);
1907 swf_SetU16(tag,buttonid); //id
1908 swf_ButtonSetFlags(tag, 0); //menu=no
1909 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1910 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1911 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1912 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1913 swf_SetU8(tag,0); // end of button records
1914 swf_ButtonSetCondition(tag, BC_IDLE_OVERUP);
1915 swf_ActionSet(tag,actions1);
1916 if(actions2) {
1917 swf_ButtonSetCondition(tag, BC_OVERUP_IDLE);
1918 swf_ActionSet(tag,actions2);
1919 swf_SetU8(tag,0);
1920 swf_ButtonPostProcess(tag, 2);
1921 } else {
1922 swf_SetU8(tag,0);
1923 swf_ButtonPostProcess(tag, 1);
1927 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1929 if(posx!=0 || posy!=0) {
1930 MATRIX m;
1931 swf_GetMatrix(0,&m);
1932 m.tx = (int)(posx*20);
1933 m.ty = (int)(posy*20);
1934 swf_ObjectPlace(tag, buttonid, depth++,&m,0,0);
1936 else {
1937 swf_ObjectPlace(tag, buttonid, depth++,0,0,0);
1941 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
1942 double x1,double y1,
1943 double x2,double y2,
1944 double x3,double y3,
1945 double x4,double y4)
1947 RGBA rgb;
1948 SRECT r;
1949 int lsid=0;
1950 int fsid;
1951 struct plotxy p1,p2,p3,p4;
1952 int myshapeid;
1953 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
1954 if(x2>xmax) xmax=x2;
1955 if(y2>ymax) ymax=y2;
1956 if(x2<xmin) xmin=x2;
1957 if(y2<ymin) ymin=y2;
1958 if(x3>xmax) xmax=x3;
1959 if(y3>ymax) ymax=y3;
1960 if(x3<xmin) xmin=x3;
1961 if(y3<ymin) ymin=y3;
1962 if(x4>xmax) xmax=x4;
1963 if(y4>ymax) ymax=y4;
1964 if(x4<xmin) xmin=x4;
1965 if(y4<ymin) ymin=y4;
1966 p1.x=x1; p1.y=y1;
1967 p2.x=x2; p2.y=y2;
1968 p3.x=x3; p3.y=y3;
1969 p4.x=x4; p4.y=y4;
1971 {p1.x = (int)(p1.x*20)/20.0;
1972 p1.y = (int)(p1.y*20)/20.0;
1973 p2.x = (int)(p2.x*20)/20.0;
1974 p2.y = (int)(p2.y*20)/20.0;
1975 p3.x = (int)(p3.x*20)/20.0;
1976 p3.y = (int)(p3.y*20)/20.0;
1977 p4.x = (int)(p4.x*20)/20.0;
1978 p4.y = (int)(p4.y*20)/20.0;}
1980 MATRIX m;
1981 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
1982 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
1983 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
1984 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
1986 m.tx = (int)(p1.x*20);
1987 m.ty = (int)(p1.y*20);
1989 /* shape */
1990 myshapeid = ++currentswfid;
1991 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1992 swf_ShapeNew(&shape);
1993 //lsid = ShapeAddLineStyle(shape,linewidth,&obj->strokergb);
1994 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1995 fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
1996 swf_SetU16(tag, myshapeid);
1997 r.xmin = (int)(xmin*20);
1998 r.ymin = (int)(ymin*20);
1999 r.xmax = (int)(xmax*20);
2000 r.ymax = (int)(ymax*20);
2001 swf_SetRect(tag,&r);
2002 swf_SetShapeStyles(tag,shape);
2003 swf_ShapeCountBits(shape,NULL,NULL);
2004 swf_SetShapeBits(tag,shape);
2005 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,lsid,fsid,0);
2006 swflastx = swflasty = 0;
2007 moveto(tag, p1);
2008 lineto(tag, p2);
2009 lineto(tag, p3);
2010 lineto(tag, p4);
2011 lineto(tag, p1);
2013 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
2014 ShapeSetLine (tag, shape, (int)(x1*20);
2015 ShapeSetLine (tag, shape, x*20,0);
2016 ShapeSetLine (tag, shape, 0,-y*20);
2017 ShapeSetLine (tag, shape, -x*20,0);*/
2018 swf_ShapeSetEnd(tag);
2020 /* instance */
2021 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
2022 swf_ObjectPlace(tag,myshapeid,/*depth*/depth++,NULL,NULL,NULL);
2025 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
2026 double x1,double y1,
2027 double x2,double y2,
2028 double x3,double y3,
2029 double x4,double y4)
2031 TAG*oldtag;
2032 if(shapeid>=0)
2033 endshape(obj,0);
2034 if(textid>=0)
2035 endtext(obj);
2037 int bitid = ++currentswfid;
2038 oldtag = tag;
2039 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
2040 swf_SetU16(tag, bitid);
2041 if(swf_SetJPEGBits(tag, filename, jpegquality)<0) {
2042 swf_DeleteTag(tag);
2043 tag = oldtag;
2044 return -1;
2047 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2048 return bitid;
2051 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2052 double x1,double y1,
2053 double x2,double y2,
2054 double x3,double y3,
2055 double x4,double y4)
2057 TAG*oldtag;
2058 JPEGBITS*jpeg;
2060 if(shapeid>=0)
2061 endshape(obj,0);
2062 if(textid>=0)
2063 endtext(obj);
2065 int bitid = ++currentswfid;
2066 oldtag = tag;
2067 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
2068 swf_SetU16(tag, bitid);
2069 swf_SetJPEGBits2(tag,sizex,sizey,mem,jpegquality);
2070 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2071 return bitid;
2074 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2075 double x1,double y1,
2076 double x2,double y2,
2077 double x3,double y3,
2078 double x4,double y4)
2080 TAG*oldtag;
2081 if(shapeid>=0)
2082 endshape(obj,0);
2083 if(textid>=0)
2084 endtext(obj);
2086 int bitid = ++currentswfid;
2087 oldtag = tag;
2088 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS);
2089 swf_SetU16(tag, bitid);
2090 if(swf_SetLosslessBits(tag,sizex,sizey,mem, BMF_32BIT)<0) {
2091 swf_DeleteTag(tag);
2092 tag = oldtag;
2093 return -1;
2096 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2097 return bitid;
2100 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
2101 double x1,double y1,
2102 double x2,double y2,
2103 double x3,double y3,
2104 double x4,double y4, int n)
2106 TAG*oldtag;
2107 U8*mem2 = 0;
2108 if(shapeid>=0)
2109 endshape(obj,0);
2110 if(textid>=0)
2111 endtext(obj);
2113 if(sizex&3)
2115 /* SWF expects scanlines to be 4 byte aligned */
2116 int x,y;
2117 U8*ptr;
2118 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
2119 ptr = mem2;
2120 for(y=0;y<sizey;y++)
2122 for(x=0;x<sizex;x++)
2123 *ptr++ = mem[y*sizex+x];
2124 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
2126 mem = mem2;
2129 int bitid = ++currentswfid;
2130 oldtag = tag;
2131 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS2);
2132 swf_SetU16(tag, bitid);
2133 if(swf_SetLosslessBitsIndexed(tag,sizex,sizey,mem, pal, n)<0) {
2134 swf_DeleteTag(tag);
2135 tag = oldtag;
2136 return -1;
2138 if(mem2)
2139 free(mem2);
2141 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2142 return bitid;
2145 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
2146 double x1,double y1,
2147 double x2,double y2,
2148 double x3,double y3,
2149 double x4,double y4)
2151 if(id<0) return;
2152 if(shapeid>=0)
2153 endshape(obj,0);
2154 if(textid>=0)
2155 endtext(obj);
2157 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2160 void swfoutput_setparameter(char*name, char*value)
2162 if(!strcmp(name, "drawonlyshapes")) {
2163 drawonlyshapes = atoi(value);
2164 } else if(!strcmp(name, "ignoredraworder")) {
2165 ignoredraworder = atoi(value);
2166 } else if(!strcmp(name, "filloverlap")) {
2167 filloverlap = atoi(value);
2168 } else if(!strcmp(name, "linksopennewwindow")) {
2169 opennewwindow = atoi(value);
2170 } else if(!strcmp(name, "opennewwindow")) {
2171 opennewwindow = atoi(value);
2172 } else if(!strcmp(name, "storeallcharacters")) {
2173 storeallcharacters = atoi(value);
2174 } else if(!strcmp(name, "enablezlib")) {
2175 enablezlib = atoi(value);
2176 } else if(!strcmp(name, "insertstop")) {
2177 insertstoptag = atoi(value);
2178 } else if(!strcmp(name, "flashversion")) {
2179 flashversion = atoi(value);
2180 } else if(!strcmp(name, "minlinewidth")) {
2181 minlinewidth = atof(value);
2182 } else if(!strcmp(name, "jpegquality")) {
2183 int val = atoi(value);
2184 if(val<0) val=0;
2185 if(val>100) val=100;
2186 jpegquality = val;
2187 } else if(!strcmp(name, "splinequality")) {
2188 int v = atoi(value);
2189 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2190 if(v<1) v = 1;
2191 splinemaxerror = v;
2192 } else if(!strcmp(name, "fontquality")) {
2193 int v = atoi(value);
2194 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2195 if(v<1) v = 1;
2196 fontsplinemaxerror = v;
2197 } else {
2198 fprintf(stderr, "unknown parameter: %s (=%s)\n", name, value);