fixed "startdepth" white background bug.
[swftools.git] / pdf2swf / swfoutput.cc
blob81d9a8b6570419fb87a85afab93d5b7a134b2271
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"
39 #define standardEncodingSize 335
40 extern char *standardEncodingNames[standardEncodingSize];
42 int opennewwindow=0;
43 int ignoredraworder=0;
44 int drawonlyshapes=0;
45 int jpegquality=85;
46 int storeallcharacters=0;
47 int enablezlib=0;
48 int insertstoptag=0;
49 int flashversion=4;
50 int splinemaxerror=1;
51 int fontsplinemaxerror=1;
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 drawmode = -1;
71 static char storefont = 0;
72 static int fillstyleid;
73 static int linestyleid;
74 static int swflastx=0;
75 static int swflasty=0;
76 static int lastwasfill = 0;
77 static char fill = 0;
78 static int sizex;
79 static int sizey;
80 TAG* cliptags[128];
81 int clipshapes[128];
82 u32 clipdepths[128];
83 int clippos = 0;
85 int CHARMIDX = 0;
86 int CHARMIDY = 0;
88 char fillstylechanged = 0;
90 static void startshape(struct swfoutput* obj);
91 static void starttext(struct swfoutput* obj);
92 static void endshape();
93 static void endtext();
95 // matrix multiplication. changes p0
96 static void transform (plotxy*p0,struct swfmatrix*m)
98 double x,y;
99 x = m->m11*p0->x+m->m12*p0->y;
100 y = m->m21*p0->x+m->m22*p0->y;
101 p0->x = x + m->m13;
102 p0->y = y + m->m23;
105 // write a move-to command into the swf
106 static int moveto(TAG*tag, plotxy p0)
108 int rx = (int)(p0.x*20);
109 int ry = (int)(p0.y*20);
110 if(rx!=swflastx || ry!=swflasty || fillstylechanged) {
111 swf_ShapeSetMove (tag, shape, rx,ry);
112 fillstylechanged = 0;
113 swflastx=rx;
114 swflasty=ry;
115 return 1;
117 return 0;
120 // write a line-to command into the swf
121 static void lineto(TAG*tag, plotxy p0)
123 int rx = ((int)(p0.x*20)-swflastx);
124 int ry = ((int)(p0.y*20)-swflasty);
125 /* we can't skip this for rx=0,ry=0, those
126 are plots */
127 swf_ShapeSetLine (tag, shape, rx,ry);
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);
147 /* write a line, given two points and the transformation
148 matrix. */
149 static void line(TAG*tag, plotxy p0, plotxy p1, struct swfmatrix*m)
151 transform(&p0,m);
152 transform(&p1,m);
153 moveto(tag, p0);
154 lineto(tag, p1);
157 /* write a cubic (!) spline. This involves calling the approximate()
158 function out of spline.cc to convert it to a quadratic spline. */
159 static void spline(TAG*tag,plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m)
161 double d;
162 struct qspline q[128];
163 int num;
164 int t;
165 transform(&p0,m);
166 transform(&p1,m);
167 transform(&p2,m);
168 transform(&p3,m);
169 cspline c;
170 c.start = p3;
171 c.control1 = p2;
172 c.control2 = p1;
173 c.end = p0;
175 if(storefont) {
176 /* fonts use a different approximation than shapes */
177 num = cspline_approximate(&c, q, fontsplinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
178 //num = cspline_approximate(&c, q, 10.0, APPROXIMATE_INFLECTION);
179 } else {
180 num = cspline_approximate(&c, q, splinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
182 for(t=0;t<num;t++) {
183 if(!t)
184 moveto(tag,q[t].start);
185 splineto(tag,q[t].control, q[t].end);
189 void resetdrawer()
191 swflastx = 0;
192 swflasty = 0;
195 static void stopFill()
197 if(lastwasfill)
199 swf_ShapeSetStyle(tag,shape,linestyleid,0x8000,0);
200 fillstylechanged = 1;
201 lastwasfill = 0;
204 static void startFill()
206 if(!lastwasfill)
208 swf_ShapeSetStyle(tag,shape,0x8000,fillstyleid,0);
209 fillstylechanged = 1;
210 lastwasfill = 1;
214 /* draw a T1 outline. These are generated by pdf2swf and by t1lib
215 (representing characters). */
216 void drawpath(TAG*tag, T1_OUTLINE*outline, struct swfmatrix*m, int log)
218 if(tag->id != ST_DEFINEFONT &&
219 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 == T1_PATHTYPE_MOVE)
237 if(((int)(lastx*20) != (int)(firstx*20) ||
238 (int)(lasty*20) != (int)(firsty*20)) &&
239 fill && !init)
241 plotxy p0;
242 plotxy p1;
243 p0.x=lastx;
244 p0.y=lasty;
245 p1.x=firstx;
246 p1.y=firsty;
247 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
248 line(tag, p0, p1, m);
250 firstx=x;
251 firsty=y;
252 init = 0;
254 else if(outline->type == T1_PATHTYPE_LINE)
256 plotxy p0;
257 plotxy p1;
258 p0.x=lastx;
259 p0.y=lasty;
260 p1.x=x;
261 p1.y=y;
262 if(log) printf("line: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
263 line(tag, p0,p1,m);
265 else if(outline->type == T1_PATHTYPE_BEZIER)
267 plotxy p0;
268 plotxy p1;
269 plotxy p2;
270 plotxy p3;
271 T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline;
272 p0.x=x;
273 p0.y=y;
274 p1.x=o2->C.x/(float)0xffff+lastx;
275 p1.y=o2->C.y/(float)0xffff+lasty;
276 p2.x=o2->B.x/(float)0xffff+lastx;
277 p2.y=o2->B.y/(float)0xffff+lasty;
278 p3.x=lastx;
279 p3.y=lasty;
280 if(log) printf("spline: %f,%f -> %f,%f\n",p3.x,p3.y,p0.x,p0.y);
281 spline(tag,p0,p1,p2,p3,m);
283 else {
284 msg("<error> drawpath: unknown outline type:%d\n", outline->type);
286 lastx=x;
287 lasty=y;
288 outline = outline->link;
290 if(((int)(lastx*20) != (int)(firstx*20) ||
291 (int)(lasty*20) != (int)(firsty*20)) &&
292 fill)
294 plotxy p0;
295 plotxy p1;
296 p0.x=lastx;
297 p0.y=lasty;
298 p1.x=firstx;
299 p1.y=firsty;
300 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
301 line(tag, p0, p1, m);
305 plotxy getPivot(T1_OUTLINE*outline, int dir, double line_width, int end, int trytwo)
307 T1_PATHPOINT next, next2;
308 double xv=0,yv=0, xv2=0, yv2=0;
309 plotxy p;
310 int two = 0;
312 if(!end) {
313 if(outline->type == T1_PATHTYPE_LINE) {
314 next = outline->dest;
315 } else {
316 next = ((T1_BEZIERSEGMENT*)outline)->B;
317 if(next.x==0 && next.y==0) {
318 next = ((T1_BEZIERSEGMENT*)outline)->C;
320 if(next.x==0 && next.y==0) {
321 next = ((T1_BEZIERSEGMENT*)outline)->dest;
324 next2 = next;
325 if(trytwo && outline->last && outline->last->type != T1_PATHTYPE_MOVE) {
326 if(outline->type == T1_PATHTYPE_LINE) {
327 next2 = outline->last->dest;
328 } else {
329 T1_PATHPOINT c = ((T1_BEZIERSEGMENT*)(outline->last))->C;
330 T1_PATHPOINT b = ((T1_BEZIERSEGMENT*)(outline->last))->B;
331 next2.x = outline->last->dest.x - c.x;
332 next2.y = outline->last->dest.y - c.y;
333 if(next2.x==0 && next2.y==0) {
334 next2.x = outline->last->dest.x - b.x;
335 next2.y = outline->last->dest.y - b.y;
337 if(next2.x==0 && next2.y==0) {
338 next2.x = outline->last->dest.x;
339 next2.y = outline->last->dest.y;
342 two = 1;
344 } else {
345 if(outline->type == T1_PATHTYPE_LINE) {
346 next = outline->dest;
347 } else {
348 T1_PATHPOINT c = ((T1_BEZIERSEGMENT*)outline)->C;
349 T1_PATHPOINT b = ((T1_BEZIERSEGMENT*)outline)->B;
350 next.x = outline->dest.x - c.x;
351 next.y = outline->dest.y - c.y;
352 if(next.x==0 && next.y==0) {
353 next.x = outline->dest.x - b.x;
354 next.y = outline->dest.y - b.y;
356 if(next.x==0 && next.y==0) {
357 next.x = outline->dest.x;
358 next.y = outline->dest.y;
361 next2 = next;
362 if(trytwo && outline->link && outline->link->type != T1_PATHTYPE_MOVE) {
363 if(outline->type == T1_PATHTYPE_LINE) {
364 next2 = outline->link->dest;
365 } else {
366 next2 = ((T1_BEZIERSEGMENT*)(outline->link))->B;
367 if(next2.x==0 && next2.y==0) {
368 next2 = ((T1_BEZIERSEGMENT*)outline->link)->C;
370 if(next2.x==0 && next2.y==0) {
371 next2 = ((T1_BEZIERSEGMENT*)outline->link)->dest;
374 two = 1;
378 if(dir) {
379 xv = next.y/(float)0xffff;
380 yv = -next.x/(float)0xffff;
381 } else {
382 xv = -next.y/(float)0xffff;
383 yv = next.x/(float)0xffff;
386 double r = (line_width/2)/sqrt(xv*xv+yv*yv);
387 xv*=r;
388 yv*=r;
390 if(two) {
391 if(dir) {
392 xv2 = next2.y/(float)0xffff;
393 yv2 = -next2.x/(float)0xffff;
394 } else {
395 xv2 = -next2.y/(float)0xffff;
396 yv2 = next2.x/(float)0xffff;
399 double r2 = (line_width/2)/sqrt(xv2*xv2+yv2*yv2);
400 xv2*=r2;
401 yv2*=r2;
402 xv = (xv+xv2)/2;
403 yv = (yv+yv2)/2;
404 double r3 = (line_width/2)/sqrt(xv*xv+yv*yv);
405 xv *= r3;
406 yv *= r3;
409 p.x = xv;
410 p.y = yv;
411 return p;
414 void drawShortPath(struct swfoutput*output, double x, double y, struct swfmatrix* m, T1_OUTLINE*outline)
416 double lastx=x, lasty=y;
417 while (outline && outline->type != T1_PATHTYPE_MOVE)
419 x += (outline->dest.x/(float)0xffff);
420 y += (outline->dest.y/(float)0xffff);
422 if(outline->type == T1_PATHTYPE_LINE)
424 plotxy p0, p1;
425 p0.x=lastx;
426 p0.y=lasty;
427 p1.x= x;
428 p1.y= y;
429 line(tag, p0, p1, m);
431 else if(outline->type == T1_PATHTYPE_BEZIER)
433 plotxy p0,p1,p2,p3;
434 T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline;
435 p3.x=lastx;
436 p3.y=lasty;
437 p1.x=o2->C.x/(float)0xffff+lastx;
438 p1.y=o2->C.y/(float)0xffff+lasty;
439 p2.x=o2->B.x/(float)0xffff+lastx;
440 p2.y=o2->B.y/(float)0xffff+lasty;
441 p0.x=x;
442 p0.y=y;
443 spline(tag,p0,p1,p2,p3,m);
445 lastx=x;
446 lasty=y;
447 outline = outline->link;
451 void drawShortPathWithEnds(struct swfoutput*output, double x, double y, struct swfmatrix* m, T1_OUTLINE*outline, int num, int line_cap, int line_join, double line_width)
453 plotxy d,d2;
454 int back = 0;
456 if(line_cap == LINE_CAP_BUTT || line_cap == LINE_CAP_SQUARE) {
457 endshape();
458 startshape(output);
459 T1_OUTLINE *last, *tmp=outline;
460 plotxy s,e,p0,p1,p2,p3,m0,m1,m2,m3;
461 double x2 = x;
462 double y2 = y;
463 double lx=x,ly=y;
464 double ee = 1.0;
465 int nr;
466 while(tmp && tmp->type != T1_PATHTYPE_MOVE) {
467 last = tmp;
468 lx += (tmp->dest.x/(float)0xffff);
469 ly += (tmp->dest.y/(float)0xffff);
470 tmp = tmp->link;
472 s = getPivot(outline, 0, line_width, 0, 0);
473 e = getPivot(last, 0, line_width, 1, 0);
475 if(line_cap == LINE_CAP_BUTT) {
476 /* make the clipping rectangle slighly bigger
477 than the line ending, so that it get's clipped
478 propertly */
479 //ee = 1.01;
480 ee=1.0;
483 p0.x = x2 + s.x*ee;
484 p0.y = y2 + s.y*ee;
485 p1.x = x2 - s.x*ee;
486 p1.y = y2 - s.y*ee;
487 p2.x = x2 - s.y - s.x*ee;
488 p2.y = y2 + s.x - s.y*ee;
489 p3.x = x2 - s.y + s.x*ee;
490 p3.y = y2 + s.x + s.y*ee;
491 m0.x = lx + e.x*ee;
492 m0.y = ly + e.y*ee;
493 m1.x = lx - e.x*ee;
494 m1.y = ly - e.y*ee;
495 m2.x = lx + e.y - e.x*ee;
496 m2.y = ly - e.x - e.y*ee;
497 m3.x = lx + e.y + e.x*ee;
498 m3.y = ly - e.x + e.y*ee;
500 for(nr=0;nr<2;nr++) {
501 int dir=0;
502 struct plotxy q0,q1,q2,q3,q4,q5;
503 startFill();
504 if(line_cap == LINE_CAP_BUTT) {
505 if(dir) {
506 q0.x = 0; q0.y = 0;
507 q1.x = sizex; q1.y = 0;
508 q2.x = sizex; q2.y = sizey;
509 q3.x = 0; q3.y = sizey;
510 } else {
511 q0.x = sizex; q0.y = sizey;
512 q1.x = 0; q1.y = sizey;
513 q2.x = 0; q2.y = 0;
514 q3.x = sizex; q3.y = 0;
516 q4.x = p0.x;
517 q4.y = p0.y;
518 moveto(tag, q0);
519 lineto(tag, q1);
520 lineto(tag, q2);
521 lineto(tag, q3);
522 lineto(tag, q0);
524 transform(&q4,m);
525 lineto(tag, q4);
528 line(tag, p0, p1, m);
529 line(tag, p1, p2, m);
530 line(tag, p2, p3, m);
531 line(tag, p3, p0, m);
533 if(line_cap == LINE_CAP_BUTT) {
534 lineto(tag, q0);
535 swf_ShapeSetEnd(tag);
536 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
537 swf_ObjectPlaceClip(tag,shapeid,depth,NULL,NULL,NULL,depth+2-nr);
538 depth++;
539 shapeid = -1;
540 startshape(output);
542 p0 = m0;
543 p1 = m1;
544 p2 = m2;
545 p3 = m3;
548 stopFill();
551 drawShortPath(output,x,y,m,outline);
553 if(line_cap == LINE_CAP_BUTT) {
554 endshape();
555 startshape(output);
559 void drawT1toRect(struct swfoutput*output, double x, double y, struct swfmatrix* m, T1_OUTLINE*outline, int num, int line_cap, int line_join, double line_width)
561 plotxy d1,d2,p1,p2,p3,p4;
563 d1.x = (outline->dest.x/(float)0xffff);
564 d1.y = (outline->dest.y/(float)0xffff);
565 d2 = getPivot(outline, 0, line_width, 0, 0);
567 assert(line_cap != LINE_CAP_ROUND);
568 if(line_cap == LINE_CAP_SQUARE) {
569 x -= +d2.y;
570 y -= -d2.x;
571 d1.x += +2*d2.y;
572 d1.y += -2*d2.x;
575 p1.x = x + d2.x;
576 p1.y = y + d2.y;
577 p2.x = x + d2.x + d1.x;
578 p2.y = y + d2.y + d1.y;
579 p3.x = x - d2.x + d1.x;
580 p3.y = y - d2.y + d1.y;
581 p4.x = x - d2.x;
582 p4.y = y - d2.y;
584 line(tag, p1,p2, m);
585 line(tag, p2,p3, m);
586 line(tag, p3,p4, m);
587 line(tag, p4,p1, m);
590 void drawShortPathWithStraightEnds(struct swfoutput*output, double x, double y, struct swfmatrix* m, T1_OUTLINE*outline, int num, int line_cap, int line_join, double line_width)
592 T1_OUTLINE*tmp=outline;
593 double xx=x,yy=y;
594 int stop=0;
595 assert(shapeid>=0);
597 startFill();
598 drawT1toRect(output, x, y, m,outline, num, line_cap, line_join, line_width);
600 while(tmp->link && tmp->link->type!=T1_PATHTYPE_MOVE) {
601 xx += (tmp->dest.x/(float)0xffff);
602 yy += (tmp->dest.y/(float)0xffff);
603 tmp = tmp->link;
606 assert(tmp->type == T1_PATHTYPE_LINE);
607 assert(outline->type == T1_PATHTYPE_LINE);
609 if(tmp!=outline) {
611 if(outline->link == tmp) {
612 /* the two straight line segments (which are everything we
613 need to draw) are very likely to overlap. To avoid that
614 they cancel each other out at the end points, start a new
615 shape for the second one */
616 endshape();startshape(output);
617 startFill();
620 drawT1toRect(output, xx, yy, m, tmp, num, line_cap, line_join, line_width);
622 if(outline->link != tmp)
624 stopFill();stop=1;
625 int save= tmp->type;
626 tmp->type = T1_PATHTYPE_MOVE;
627 x += (outline->dest.x/(float)0xffff);
628 y += (outline->dest.y/(float)0xffff);
629 outline = outline->link;
630 drawShortPath(output, x, y, m, outline);
631 tmp->type = save;
634 if(!stop)
635 stopFill();
638 static int t1len(T1_OUTLINE*line)
640 int num=0;
641 while(line && line->type != T1_PATHTYPE_MOVE) {
642 num++;
643 line = line->link;
645 return num;
648 static float t1linelen(T1_OUTLINE*line)
650 float x,y;
651 x = (line->dest.x/(float)0xffff);
652 y = (line->dest.y/(float)0xffff);
653 return sqrt(x*x+y*y);
656 void drawpath2poly(struct swfoutput *output, T1_OUTLINE*outline, struct swfmatrix*m, int log, int line_join, int line_cap, double line_width, double miter_limit)
658 if(tag->id != ST_DEFINEFONT &&
659 tag->id != ST_DEFINESHAPE &&
660 tag->id != ST_DEFINESHAPE2 &&
661 tag->id != ST_DEFINESHAPE3) {
662 msg("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
663 exit(1);
665 assert(shapeid>=0);
666 double x=0,y=0;
667 double lastx=0,lasty=0;
668 int valid = 0;
669 int lastwasline = 0;
670 T1_OUTLINE*tmp = outline, *last = 0;
671 tmp->last = 0;
673 while(1) {
674 if(tmp) {
675 x += (tmp->dest.x/(float)0xffff);
676 y += (tmp->dest.y/(float)0xffff);
678 if(!tmp || tmp->type == T1_PATHTYPE_MOVE) {
679 if(valid && last) {
680 if(last->type == T1_PATHTYPE_LINE && t1linelen(last)>line_width*2 &&
681 lastwasline && line_cap != LINE_CAP_ROUND)
682 drawShortPathWithStraightEnds(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
683 else
684 drawShortPathWithEnds(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
686 if(!tmp)
687 break;
688 valid = 0;
689 last = 0;
690 lastx = x;
691 lasty = y;
692 } else {
693 if(!last)
694 last = tmp;
695 valid++;
698 if(tmp && tmp->type == T1_PATHTYPE_LINE && t1linelen(tmp)>line_width*2)
699 lastwasline = 1;
700 else
701 lastwasline = 0;
703 if(tmp->link)
704 tmp->link->last = tmp; // make sure list is properly linked in both directions
705 tmp = tmp->link;
709 static inline int colorcompare(RGBA*a,RGBA*b)
712 if(a->r!=b->r ||
713 a->g!=b->g ||
714 a->b!=b->b ||
715 a->a!=b->a) {
716 return 0;
718 return 1;
721 static const int CHARDATAMAX = 1024;
722 struct chardata {
723 int charid;
724 int fontid;
725 int x;
726 int y;
727 int size;
728 RGBA color;
729 } chardata[CHARDATAMAX];
730 int chardatapos = 0;
732 static void putcharacters(TAG*tag)
734 int t;
735 SWFFONT font;
736 RGBA color;
737 color.r = chardata[0].color.r^255;
738 color.g = 0;
739 color.b = 0;
740 color.a = 0;
741 int lastfontid;
742 int lastx;
743 int lasty;
744 int lastsize;
745 int charids[128];
746 int charadvance[128];
747 int charstorepos;
748 int pass;
749 int glyphbits=1; //TODO: can this be zero?
750 int advancebits=1;
752 if(tag->id != ST_DEFINETEXT &&
753 tag->id != ST_DEFINETEXT2) {
754 msg("<error> internal error: putcharacters needs an text tag, not %d\n",tag->id);
755 exit(1);
757 if(!chardatapos) {
758 msg("<warning> putcharacters called with zero characters");
761 for(pass = 0; pass < 2; pass++)
763 charstorepos = 0;
764 lastfontid = -1;
765 lastx = CHARMIDX;
766 lasty = CHARMIDY;
767 lastsize = -1;
769 if(pass==1)
771 advancebits++; // add sign bit
772 swf_SetU8(tag, glyphbits);
773 swf_SetU8(tag, advancebits);
776 for(t=0;t<=chardatapos;t++)
778 if(lastfontid != chardata[t].fontid ||
779 lastx!=chardata[t].x ||
780 lasty!=chardata[t].y ||
781 !colorcompare(&color, &chardata[t].color) ||
782 charstorepos==127 ||
783 lastsize != chardata[t].size ||
784 t == chardatapos)
786 if(charstorepos && pass==0)
788 int s;
789 for(s=0;s<charstorepos;s++)
791 while(charids[s]>=(1<<glyphbits))
792 glyphbits++;
793 while(charadvance[s]>=(1<<advancebits))
794 advancebits++;
797 if(charstorepos && pass==1)
799 tag->writeBit = 0; // Q&D
800 swf_SetBits(tag, 0, 1); // GLYPH Record
801 swf_SetBits(tag, charstorepos, 7); // number of glyphs
802 int s;
803 for(s=0;s<charstorepos;s++)
805 swf_SetBits(tag, charids[s], glyphbits);
806 swf_SetBits(tag, charadvance[s], advancebits);
809 charstorepos = 0;
811 if(pass == 1 && t<chardatapos)
813 RGBA*newcolor=0;
814 SWFFONT*newfont=0;
815 int newx = 0;
816 int newy = 0;
817 if(lastx != chardata[t].x ||
818 lasty != chardata[t].y)
820 newx = chardata[t].x;
821 newy = chardata[t].y;
822 if(newx == 0)
823 newx = SET_TO_ZERO;
824 if(newy == 0)
825 newy = SET_TO_ZERO;
827 if(!colorcompare(&color, &chardata[t].color))
829 color = chardata[t].color;
830 newcolor = &color;
832 font.id = chardata[t].fontid;
833 if(lastfontid != chardata[t].fontid || lastsize != chardata[t].size)
834 newfont = &font;
836 tag->writeBit = 0; // Q&D
837 swf_TextSetInfoRecord(tag, newfont, chardata[t].size, newcolor, newx,newy);
840 lastfontid = chardata[t].fontid;
841 lastx = chardata[t].x;
842 lasty = chardata[t].y;
843 lastsize = chardata[t].size;
846 if(t==chardatapos)
847 break;
849 int advance;
850 int nextt = t==chardatapos-1?t:t+1;
851 int rel = chardata[nextt].x-chardata[t].x;
852 if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) {
853 advance = rel;
854 lastx=chardata[nextt].x;
856 else {
857 advance = 0;
858 lastx=chardata[t].x;
860 charids[charstorepos] = chardata[t].charid;
861 charadvance[charstorepos] = advance;
862 charstorepos ++;
865 chardatapos = 0;
868 static void putcharacter(struct swfoutput*obj, int fontid, int charid,
869 int x,int y, int size)
871 if(chardatapos == CHARDATAMAX)
873 endtext();
874 starttext(obj);
876 chardata[chardatapos].fontid = fontid;
877 chardata[chardatapos].charid = charid;
878 chardata[chardatapos].x = x;
879 chardata[chardatapos].y = y;
880 chardata[chardatapos].color = obj->fillrgb;
881 chardata[chardatapos].size = size;
882 chardatapos++;
886 /* process a character. */
887 static void drawchar(struct swfoutput*obj, SWFFont*font, char*character, int charnr, swfmatrix*m)
889 int usefonts=1;
890 if(m->m12!=0 || m->m21!=0)
891 usefonts=0;
892 if(m->m11 != m->m22)
893 usefonts=0;
895 if(!font) {
896 msg("<warning> Font is NULL");
899 if(usefonts && ! drawonlyshapes)
901 int charid = font->getSWFCharID(character, charnr);
902 if(charid<0) {
903 msg("<warning> Didn't find character '%s' (%d) in current charset (%s)",
904 FIXNULL(character),charnr, FIXNULL(font->getName()));
905 return;
907 if(shapeid>=0)
908 endshape();
909 if(textid<0)
910 starttext(obj);
911 putcharacter(obj, font->swfid, charid,(int)(m->m13*20),(int)(m->m23*20),
912 (int)(m->m11*20/2+0.5)); //where does the /2 come from?
914 else
916 T1_OUTLINE*outline = font->getOutline(character, charnr);
917 char* charname = character;
919 if(!outline) {
920 msg("<warning> Didn't find character '%s' (%d) in current charset (%s)",
921 FIXNULL(character),charnr,FIXNULL(font->getName()));
922 return;
925 swfmatrix m2=*m;
926 m2.m11/=100;
927 m2.m21/=100;
928 m2.m12/=100;
929 m2.m22/=100;
931 if(textid>=0)
932 endtext();
933 if(shapeid<0)
934 startshape(obj);
936 startFill();
938 int lf = fill;
939 fill = 1;
940 drawpath(tag, outline, &m2, 0);
941 fill = lf;
945 /* draw a curved polygon. */
946 void swfoutput_drawpath(swfoutput*output, T1_OUTLINE*outline,
947 struct swfmatrix*m)
949 if(textid>=0)
950 endtext();
952 /* Multiple polygons in one shape don't overlap correctly,
953 so we better start a new shape here if the polygon is filled
955 if(shapeid>=0 && fill && !ignoredraworder) {
956 endshape();
959 if(shapeid<0)
960 startshape(output);
962 if(!fill)
963 stopFill();
964 else
965 startFill();
967 drawpath(tag, outline,m, 0);
970 void swfoutput_drawpath2poly(struct swfoutput*output, T1_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
972 if(textid>=0)
973 endtext();
974 if(shapeid>=0)
975 endshape();
976 assert(shapeid<0);
977 startshape(output);
978 stopFill();
980 drawpath2poly(output, outline, m, 0, line_join, line_cap, line_width, miter_limit);
983 /* SWFFont: copy all t1 font outlines to a local
984 array. */
985 SWFFont::SWFFont(char*name, int id, char*filename)
987 if(!T1_GetFontName(id))
988 T1_LoadFont(id);
990 this->name = strdup(T1_GetFontFileName(id));
991 this->fontid = strdup(name);
992 this->t1id = id;
994 char**charnamebase= T1_GetAllCharNames(id);
995 char**a= charnamebase;
996 int t, outlinepos=0;
997 char*map[256];
999 char*null = 0;
1000 if(!a)
1001 a=&null;
1003 t=0;
1004 while(a[t])
1005 t++;
1006 this->charnum = t;
1008 if(!charnum) {
1009 this->standardtablesize = 0;
1011 msg("<verbose> Font %s(%d): Storing %d outlines.\n", FIXNULL(name), id, charnum);
1013 this->standardtablesize = 256;
1014 if(this->charnum < this->standardtablesize)
1015 this->standardtablesize = this->charnum;
1016 this->standardtable = (char**)malloc(standardtablesize*sizeof(char*));
1018 for(t = 0; t < this->standardtablesize; t++) {
1019 char*name = T1_GetCharName(id,t);
1020 char chh[2] = "";
1021 chh[0] = t;
1022 if(!name || !strstr(name, "notdef")) {
1023 if(t<standardEncodingSize) {
1024 name = standardEncodingNames[t];
1026 if(!name) {
1027 name = ""; //TODO: store something like <%d>
1030 standardtable[t] = strdup(name);
1031 msg("<debug> Char %d is named %s\n", t, name);
1034 outline = (T1_OUTLINE**)malloc(charnum*sizeof(T1_OUTLINE*));
1035 charname = (char**)malloc(charnum*sizeof(char*));
1036 width = (int*)malloc(charnum*sizeof(int));
1037 memset(width, 0, charnum*sizeof(int));
1038 memset(charname, 0, charnum*sizeof(char*));
1039 used = (char*)malloc(charnum*sizeof(char));
1040 char2swfcharid = (U16*)malloc(charnum*2);
1041 swfcharid2char = (U16*)malloc(charnum*2);
1042 swfcharpos = 0;
1044 memset(used,0,charnum*sizeof(char));
1046 this->swfid = ++currentswfid;
1048 t=0;
1049 while(*a)
1051 map[t] = strdup(*a);
1052 a++;
1053 t++;
1054 if(t==256 || !*a) {
1055 int s;
1056 for(s=t;s<256;s++)
1057 map[s] = ".notdef";
1059 int ret = T1_ReencodeFont(id, map);
1060 if(ret) {
1061 T1_DeleteFont(id);
1062 T1_LoadFont(id);
1063 int ret = T1_ReencodeFont(id, map);
1064 if(ret)
1065 fprintf(stderr,"Can't reencode font: (%s) ret:%d\n",filename, ret);
1066 /* Deleting the font invalidates the charname array,
1067 so we have to ask for it again now.
1068 We continue at the position we were, hoping the font
1069 didn't shrink in the meantime or something.
1071 a = T1_GetAllCharNames(id) + (a - charnamebase);
1074 // parsecharacters
1075 for(s=0;s<t;s++)
1077 char* name = T1_GetCharName(id, s);
1078 if(!name) name = "";
1079 this->outline[outlinepos] = T1_CopyOutline(T1_GetCharOutline(id, s, 100.0, 0));
1080 this->width[outlinepos] = T1_GetCharWidth(id, s);
1081 this->charname[outlinepos] = strdup(name);
1082 outlinepos++;
1085 for(s=0;s<t;s++)
1086 free(map[s]);
1087 t=0;
1092 /* free all tables, write out definefont tags */
1093 SWFFont::~SWFFont()
1095 int t,usednum=0;
1096 int*ptr;
1098 if(storeallcharacters)
1100 int t;
1101 for(t=0;t<this->charnum;t++)
1103 if(this->charname[t])
1104 getSWFCharID(this->charname[t], -1);
1108 ptr = (int*)malloc(swfcharpos*sizeof(int));
1110 for(t=0;t<charnum;t++)
1111 if(used[t]) usednum++;
1113 if(usednum && !drawonlyshapes)
1115 msg("<verbose> Font %s has %d used characters",FIXNULL(fontid), usednum);
1116 TAG*ftag = swf_InsertTag(swf.firstTag,ST_DEFINEFONT);
1117 swf_SetU16(ftag, this->swfid);
1118 int initpos = swf_GetTagLen(ftag);
1119 swfmatrix m;
1120 m.m11 = m.m22 = 1;
1121 m.m21 = m.m12 = 0;
1122 m.m13 = CHARMIDX;
1123 m.m23 = CHARMIDY;
1125 for(t=0;t<swfcharpos;t++)
1127 ptr[t] = swf_GetTagLen(ftag);
1128 swf_SetU16(ftag, 0x1234);
1130 for(t=0;t<swfcharpos;t++)
1132 *(U16*)&ftag->data[ptr[t]] =
1133 SWAP16(swf_GetTagLen(ftag)-initpos);
1135 swflastx=0;
1136 swflasty=0;
1137 swf_SetU8(ftag,0x10); //1 fill bits, 0 linestyle bits
1138 SHAPE s;
1139 s.bits.fill = 1;
1140 s.bits.line = 0;
1141 swf_ShapeSetStyle(ftag,&s,0,1,0);
1142 fillstylechanged = 1;
1143 int lastfill = fill;
1144 fill = 1;
1145 storefont = 1;
1146 drawpath(ftag, outline[swfcharid2char[t]],&m, 0);
1147 storefont = 0;
1148 fill = lastfill;
1149 swf_ShapeSetEnd(ftag);
1151 ftag = swf_InsertTag(ftag,ST_DEFINEFONTINFO);
1152 swf_SetU16(ftag, this->swfid);
1153 if(this->fontid) {
1154 swf_SetU8(ftag, strlen(this->fontid));
1155 swf_SetBlock(ftag, (U8*)this->fontid, strlen(this->fontid));
1156 } else {
1157 swf_SetU8(ftag, 0);
1159 swf_SetU8(ftag, 0); //flags
1160 for(t=0;t<swfcharpos;t++)
1162 int s;
1163 char * name = this->charname[this->swfcharid2char[t]];
1164 for(s=0;s<256;s++) {
1165 if(standardEncodingNames[s] &&
1166 !strcmp(name,standardEncodingNames[s]))
1167 break;
1169 swf_SetU8(ftag, (U8)s);
1173 free(ptr);
1174 if(outline)
1175 free(outline);
1176 for(t=0;t<charnum;t++)
1177 free(charname[t]);
1178 for(t=0;t<standardtablesize;t++)
1179 if(standardtable[t]) {
1180 free(standardtable[t]);
1182 free(standardtable);
1183 free(charname);
1184 free(width);
1185 free(used);
1186 free(swfcharid2char);
1187 free(char2swfcharid);
1190 T1_OUTLINE*SWFFont::getOutline(char*name, int charnr)
1192 int t;
1193 for(t=0;t<this->charnum;t++) {
1194 if(!strcmp(this->charname[t],name)) {
1195 return outline[t];
1199 /* if we didn't find the character, maybe
1200 we can find the capitalized version */
1201 for(t=0;t<this->charnum;t++) {
1202 if(!strcasecmp(this->charname[t],name))
1203 return outline[t];
1206 /* if we didn't find it by name, use the names of the first 256 characters
1207 of the font to try a new name based on charnr */
1208 if(this->standardtable && charnr>=0 && charnr < this->standardtablesize) {
1209 T1_OUTLINE*ret = getOutline(this->standardtable[charnr], -1);
1210 if(ret) return ret;
1213 return 0;
1216 int SWFFont::getSWFCharID(char*name, int charnr)
1218 int t;
1219 for(t=0;t<this->charnum;t++) {
1220 if(!strcmp(this->charname[t],name)) {
1221 if(!used[t])
1223 swfcharid2char[swfcharpos] = t;
1224 char2swfcharid[t] = swfcharpos++;
1225 used[t] = 1;
1227 return char2swfcharid[t];
1231 /* if we didn't find the character, maybe
1232 we can find the capitalized version */
1233 for(t=0;t<this->charnum;t++) {
1234 if(!strcasecmp(this->charname[t],name)) {
1235 if(!used[t])
1237 swfcharid2char[swfcharpos] = t;
1238 char2swfcharid[t] = swfcharpos++;
1239 used[t] = 1;
1241 return char2swfcharid[t];
1245 /* if we didn't find it by name, use the names of the first 256 (or so) characters
1246 of the font to try a new name based on charnr */
1247 if(this->standardtable && charnr>=0 && charnr < this->standardtablesize) {
1248 int ret = getSWFCharID(this->standardtable[charnr], -1);
1249 if(ret) return ret;
1251 return -1;
1254 int SWFFont::getWidth(char*name)
1256 int t;
1257 for(t=0;t<this->charnum;t++) {
1258 if(!strcmp(this->charname[t],name)) {
1259 return this->width[t];
1262 return 0;
1265 char*SWFFont::getName()
1267 return this->name;
1270 struct fontlist_t
1272 SWFFont * font;
1273 fontlist_t*next;
1274 } *fontlist = 0;
1276 /* set's the t1 font index of the font to use for swfoutput_drawchar(). */
1277 void swfoutput_setfont(struct swfoutput*obj, char*fontid, int t1id, char*filename)
1279 fontlist_t*last=0,*iterator;
1280 if(obj->font && !strcmp(obj->font->fontid,fontid))
1281 return;
1283 iterator = fontlist;
1284 while(iterator) {
1285 if(!strcmp(iterator->font->fontid,fontid))
1286 break;
1287 last = iterator;
1288 iterator = iterator->next;
1290 if(iterator)
1292 obj->font = iterator->font;
1293 return ;
1296 if(t1id<0) {
1297 msg("<error> internal error: t1id:%d, fontid:%s\n", t1id,FIXNULL(fontid));
1300 SWFFont*font = new SWFFont(fontid, t1id, filename);
1301 iterator = new fontlist_t;
1302 iterator->font = font;
1303 iterator->next = 0;
1305 if(last)
1306 last->next = iterator;
1307 else
1308 fontlist = iterator;
1309 obj->font = font;
1312 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1314 fontlist_t *iterator = fontlist;
1315 while(iterator) {
1316 if(!strcmp(iterator->font->fontid,fontid))
1317 return 1;
1318 iterator = iterator->next;
1320 return 0;
1323 /* set's the matrix which is to be applied to characters drawn by
1324 swfoutput_drawchar() */
1325 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1326 double m21,double m22)
1328 if(obj->fontm11 == m11 &&
1329 obj->fontm12 == m12 &&
1330 obj->fontm21 == m21 &&
1331 obj->fontm22 == m22)
1332 return;
1333 // if(textid>=0)
1334 // endtext();
1335 obj->fontm11 = m11;
1336 obj->fontm12 = m12;
1337 obj->fontm21 = m21;
1338 obj->fontm22 = m22;
1341 /* draws a character at x,y. */
1342 void swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr)
1344 swfmatrix m;
1345 m.m11 = obj->fontm11;
1346 m.m12 = obj->fontm12;
1347 m.m21 = obj->fontm21;
1348 m.m22 = obj->fontm22;
1349 m.m13 = x;
1350 m.m23 = y;
1351 drawchar(obj, obj->font, character, charnr, &m);
1354 /* initialize the swf writer */
1355 void swfoutput_init(struct swfoutput* obj, char*_filename, int x1, int y1, int x2, int y2)
1357 GLYPH *glyph;
1358 RGBA rgb;
1359 SRECT r;
1360 memset(obj, 0, sizeof(struct swfoutput));
1361 filename = _filename;
1362 sizex = x2;
1363 sizey = y2;
1365 msg("<verbose> initializing swf output for size %d*%d\n", sizex,sizey);
1367 obj->font = 0;
1369 memset(&swf,0x00,sizeof(SWF));
1371 swf.fileVersion = flashversion;
1372 swf.frameRate = 0x0040; // 1 frame per 4 seconds
1373 swf.movieSize.xmin = 20*x1;
1374 swf.movieSize.ymin = 20*y1;
1375 swf.movieSize.xmax = 20*x2;
1376 swf.movieSize.ymax = 20*y2;
1378 depth = 1;
1380 swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1381 tag = swf.firstTag;
1382 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1383 swf_SetRGB(tag,&rgb);
1385 if(1)/* add white rectangle */
1387 SRECT r;
1388 SHAPE* s;
1389 int ls1=0,fs1=0;
1390 int shapeid = ++currentswfid;
1391 r.xmin = x1*20;
1392 r.ymin = y1*20;
1393 r.xmax = x2*20;
1394 r.ymax = y2*20;
1395 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
1396 swf_ShapeNew(&s);
1397 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1398 swf_SetU16(tag,shapeid);
1399 swf_SetRect(tag,&r);
1400 swf_SetShapeHeader(tag,s);
1401 swf_ShapeSetAll(tag,s,x1*20,y1*20,ls1,fs1,0);
1402 swf_ShapeSetLine(tag,s,20*(x2-x1),0);
1403 swf_ShapeSetLine(tag,s,0,20*(y2-y1));
1404 swf_ShapeSetLine(tag,s,20*(x1-x2),0);
1405 swf_ShapeSetLine(tag,s,0,20*(y1-y2));
1406 swf_ShapeSetEnd(tag);
1407 swf_ShapeFree(s);
1408 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1409 swf_ObjectPlace(tag,shapeid,depth++,0,0,0);
1412 if(flag_protected)
1413 tag = swf_InsertTag(tag, ST_PROTECT);
1415 startdepth = depth;
1418 void swfoutput_setprotected() //write PROTECT tag
1420 flag_protected = 1;
1423 static void startshape(struct swfoutput*obj)
1425 RGBA rgb;
1426 SRECT r;
1428 if(textid>=0)
1429 endtext();
1431 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1433 swf_ShapeNew(&shape);
1434 linestyleid = swf_ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1435 rgb.r = obj->fillrgb.r;
1436 rgb.g = obj->fillrgb.g;
1437 rgb.b = obj->fillrgb.b;
1438 fillstyleid = swf_ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1440 shapeid = ++currentswfid;
1441 swf_SetU16(tag,shapeid); // ID
1443 r.xmin = 0;
1444 r.ymin = 0;
1445 r.xmax = 20*sizex;
1446 r.ymax = 20*sizey;
1448 swf_SetRect(tag,&r);
1450 swf_SetShapeStyles(tag,shape);
1451 swf_ShapeCountBits(shape,NULL,NULL);
1452 swf_SetShapeBits(tag,shape);
1454 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,linestyleid,0,0);
1455 swflastx=swflasty=0;
1456 lastwasfill = 0;
1459 static void starttext(struct swfoutput*obj)
1461 SRECT r;
1462 MATRIX m;
1463 if(shapeid>=0)
1464 endshape();
1465 tag = swf_InsertTag(tag,ST_DEFINETEXT);
1466 textid = ++currentswfid;
1467 swf_SetU16(tag, textid);
1469 r.xmin = 0;
1470 r.ymin = 0;
1471 r.xmax = 20*sizex;
1472 r.ymax = 20*sizey;
1474 swf_SetRect(tag,&r);
1476 m.sx = 65536;
1477 m.sy = 65536;
1478 m.r0 = 0;
1479 m.r1 = 0;
1480 m.tx = 0;
1481 m.ty = 0;
1483 swf_SetMatrix(tag,&m);
1484 swflastx=swflasty=0;
1487 static void endshape()
1489 if(shapeid<0)
1490 return;
1491 swf_ShapeSetEnd(tag);
1492 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1493 swf_ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL);
1494 shapeid = -1;
1497 static void endtext()
1499 if(textid<0)
1500 return;
1501 putcharacters(tag);
1502 swf_SetU8(tag,0);
1503 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1504 swf_ObjectPlace(tag,textid,/*depth*/depth++,NULL,NULL,NULL);
1505 textid = -1;
1508 static void endpage(struct swfoutput*obj)
1510 if(shapeid>=0)
1511 endshape();
1512 if(textid>=0)
1513 endtext();
1514 while(clippos)
1515 swfoutput_endclip(obj);
1517 if(insertstoptag) {
1518 ActionTAG*atag=0;
1519 atag = action_Stop(atag);
1520 atag = action_End(atag);
1521 tag = swf_InsertTag(tag,ST_DOACTION);
1522 swf_ActionSet(tag,atag);
1524 tag = swf_InsertTag(tag,ST_SHOWFRAME);
1527 void swfoutput_newpage(struct swfoutput*obj)
1529 endpage(obj);
1531 for(depth--;depth>=startdepth;depth--) {
1532 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1533 swf_SetU16(tag,depth);
1536 depth = startdepth;
1539 /* "destroy" like in (oo-terminology) "destructor". Perform cleaning
1540 up, complete the swf, and write it out. */
1541 void swfoutput_destroy(struct swfoutput* obj)
1543 endpage(obj);
1544 fontlist_t *tmp,*iterator = fontlist;
1545 while(iterator) {
1546 delete iterator->font;
1547 iterator->font = 0;
1548 tmp = iterator;
1549 iterator = iterator->next;
1550 delete tmp;
1553 T1_CloseLib();
1554 if(!filename)
1555 return;
1556 if(filename)
1557 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1558 else
1559 fi = 1; // stdout
1561 if(fi<=0) {
1562 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1563 exit(1);
1566 tag = swf_InsertTag(tag,ST_END);
1568 if(enablezlib) {
1569 if FAILED(swf_WriteSWC(fi,&swf))
1570 msg("<error> WriteSWC() failed.\n");
1571 } else {
1572 if FAILED(swf_WriteSWF(fi,&swf))
1573 msg("<error> WriteSWF() failed.\n");
1576 if(filename)
1577 close(fi);
1578 msg("<notice> SWF written\n");
1581 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1583 drawmode = mode;
1584 if(mode == DRAWMODE_FILL)
1585 fill = 1;
1586 else if(mode == DRAWMODE_EOFILL)
1587 fill = 1;
1588 else if(mode == DRAWMODE_STROKE)
1589 fill = 0;
1590 else if(mode == DRAWMODE_CLIP)
1591 fill = 1;
1592 else if(mode == DRAWMODE_EOCLIP)
1593 fill = 1;
1596 void swfoutput_setfillcolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1598 if(obj->fillrgb.r == r &&
1599 obj->fillrgb.g == g &&
1600 obj->fillrgb.b == b &&
1601 obj->fillrgb.a == a) return;
1602 if(shapeid>=0)
1603 endshape();
1605 obj->fillrgb.r = r;
1606 obj->fillrgb.g = g;
1607 obj->fillrgb.b = b;
1608 obj->fillrgb.a = a;
1611 void swfoutput_setstrokecolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1613 if(obj->strokergb.r == r &&
1614 obj->strokergb.g == g &&
1615 obj->strokergb.b == b &&
1616 obj->strokergb.a == a) return;
1618 if(shapeid>=0)
1619 endshape();
1620 obj->strokergb.r = r;
1621 obj->strokergb.g = g;
1622 obj->strokergb.b = b;
1623 obj->strokergb.a = a;
1626 void swfoutput_setlinewidth(struct swfoutput*obj, double linewidth)
1628 if(obj->linewidth == (u16)(linewidth*20))
1629 return;
1631 if(shapeid>=0)
1632 endshape();
1633 obj->linewidth = (u16)(linewidth*20);
1637 void swfoutput_startclip(swfoutput*obj, T1_OUTLINE*outline, struct swfmatrix*m)
1639 if(textid>=0)
1640 endtext();
1641 if(shapeid>=0)
1642 endshape();
1644 if(clippos >= 127)
1646 msg("<warning> Too many clip levels.");
1647 clippos --;
1650 startshape(obj);
1651 int olddrawmode = drawmode;
1652 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1653 swfoutput_drawpath(obj, outline, m);
1654 swf_ShapeSetEnd(tag);
1655 swfoutput_setdrawmode(obj, olddrawmode);
1657 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1658 cliptags[clippos] = tag;
1659 clipshapes[clippos] = shapeid;
1660 clipdepths[clippos] = depth++;
1661 clippos++;
1662 shapeid = -1;
1665 void swfoutput_endclip(swfoutput*obj)
1667 if(textid>=0)
1668 endtext();
1669 if(shapeid>=0)
1670 endshape();
1672 if(!clippos) {
1673 msg("<error> Invalid end of clipping region");
1674 return;
1676 clippos--;
1677 swf_ObjectPlaceClip(cliptags[clippos],clipshapes[clippos],clipdepths[clippos],NULL,NULL,NULL,depth++);
1680 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1682 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1684 ActionTAG* actions;
1685 if(!strncmp("http://pdf2swf:", url, 15)) {
1686 char*tmp = strdup(url);
1687 int l = strlen(tmp);
1688 if(tmp[l-1] == '/')
1689 tmp[l-1] = 0;
1690 swfoutput_namedlink(obj, tmp+15, points);
1691 free(tmp);
1692 return;
1695 if(shapeid>=0)
1696 endshape();
1697 if(textid>=0)
1698 endtext();
1700 if(opennewwindow)
1701 actions = action_GetUrl(0, url, "_parent");
1702 else
1703 actions = action_GetUrl(0, url, "_this");
1704 actions = action_End(actions);
1706 drawlink(obj, actions, 0, points,0);
1708 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1710 ActionTAG* actions;
1712 if(shapeid>=0)
1713 endshape();
1714 if(textid>=0)
1715 endtext();
1717 actions = action_GotoFrame(0, page);
1718 actions = action_End(actions);
1720 drawlink(obj, actions, 0, points,0);
1723 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
1724 of the viewer objects, like subtitles, index elements etc.
1726 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
1728 ActionTAG *actions1,*actions2;
1729 char*tmp = strdup(name);
1730 char mouseover = 1;
1732 if(shapeid>=0)
1733 endshape();
1734 if(textid>=0)
1735 endtext();
1737 if(!strncmp(tmp, "call:", 5))
1739 char*x = strchr(&tmp[5], ':');
1740 if(!x) {
1741 actions1 = action_PushInt(0, 0); //number of parameters (0)
1742 actions1 = action_PushString(actions1, &tmp[5]); //function name
1743 actions1 = action_CallFunction(actions1);
1744 } else {
1745 *x = 0;
1746 actions1 = action_PushString(0, x+1); //parameter
1747 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
1748 actions1 = action_PushString(actions1, &tmp[5]); //function name
1749 actions1 = action_CallFunction(actions1);
1751 actions2 = action_End(0);
1752 mouseover = 0;
1754 else
1756 actions1 = action_PushString(0, "/:subtitle");
1757 actions1 = action_PushString(actions1, name);
1758 actions1 = action_SetVariable(actions1);
1759 actions1 = action_End(actions1);
1761 actions2 = action_PushString(0, "/:subtitle");
1762 actions2 = action_PushString(actions2, "");
1763 actions2 = action_SetVariable(actions2);
1764 actions2 = action_End(actions2);
1767 drawlink(obj, actions1, actions2, points,mouseover);
1769 swf_ActionFree(actions1);
1770 swf_ActionFree(actions2);
1771 free(tmp);
1774 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
1776 RGBA rgb;
1777 SRECT r;
1778 int lsid=0;
1779 int fsid;
1780 struct plotxy p1,p2,p3,p4;
1781 int myshapeid;
1782 int myshapeid2;
1783 double xmin,ymin;
1784 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
1785 double posx = 0;
1786 double posy = 0;
1787 int t;
1788 int buttonid = ++currentswfid;
1789 for(t=1;t<4;t++)
1791 if(points[t].x>xmax) xmax=points[t].x;
1792 if(points[t].y>ymax) ymax=points[t].y;
1793 if(points[t].x<xmin) xmin=points[t].x;
1794 if(points[t].y<ymin) ymin=points[t].y;
1797 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
1798 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
1800 /* the following code subtracts the upper left edge from all coordinates,
1801 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
1802 Necessary for preprocessing with swfcombine. */
1803 posx = xmin; posy = ymin;
1804 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
1805 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
1806 xmin -= posx; ymin -= posy;
1807 xmax -= posx; ymax -= posy;
1809 /* shape */
1810 myshapeid = ++currentswfid;
1811 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1812 swf_ShapeNew(&shape);
1813 rgb.r = rgb.b = rgb.a = rgb.g = 0;
1814 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1815 swf_SetU16(tag, myshapeid);
1816 r.xmin = (int)(xmin*20);
1817 r.ymin = (int)(ymin*20);
1818 r.xmax = (int)(xmax*20);
1819 r.ymax = (int)(ymax*20);
1820 swf_SetRect(tag,&r);
1821 swf_SetShapeStyles(tag,shape);
1822 swf_ShapeCountBits(shape,NULL,NULL);
1823 swf_SetShapeBits(tag,shape);
1824 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1825 swflastx = swflasty = 0;
1826 moveto(tag, p1);
1827 lineto(tag, p2);
1828 lineto(tag, p3);
1829 lineto(tag, p4);
1830 lineto(tag, p1);
1831 swf_ShapeSetEnd(tag);
1833 /* shape2 */
1834 myshapeid2 = ++currentswfid;
1835 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1836 swf_ShapeNew(&shape);
1837 rgb.r = rgb.b = rgb.a = rgb.g = 255;
1838 rgb.a = 40;
1839 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1840 swf_SetU16(tag, myshapeid2);
1841 r.xmin = (int)(xmin*20);
1842 r.ymin = (int)(ymin*20);
1843 r.xmax = (int)(xmax*20);
1844 r.ymax = (int)(ymax*20);
1845 swf_SetRect(tag,&r);
1846 swf_SetShapeStyles(tag,shape);
1847 swf_ShapeCountBits(shape,NULL,NULL);
1848 swf_SetShapeBits(tag,shape);
1849 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1850 swflastx = swflasty = 0;
1851 moveto(tag, p1);
1852 lineto(tag, p2);
1853 lineto(tag, p3);
1854 lineto(tag, p4);
1855 lineto(tag, p1);
1856 swf_ShapeSetEnd(tag);
1858 if(!mouseover)
1860 tag = swf_InsertTag(tag,ST_DEFINEBUTTON);
1861 swf_SetU16(tag,buttonid); //id
1862 swf_ButtonSetFlags(tag, 0); //menu=no
1863 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1864 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1865 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1866 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1867 swf_SetU8(tag,0);
1868 swf_ActionSet(tag,actions1);
1869 swf_SetU8(tag,0);
1871 else
1873 tag = swf_InsertTag(tag,ST_DEFINEBUTTON2);
1874 swf_SetU16(tag,buttonid); //id
1875 swf_ButtonSetFlags(tag, 0); //menu=no
1876 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1877 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1878 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1879 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1880 swf_SetU8(tag,0); // end of button records
1881 swf_ButtonSetCondition(tag, BC_IDLE_OVERUP);
1882 swf_ActionSet(tag,actions1);
1883 if(actions2) {
1884 swf_ButtonSetCondition(tag, BC_OVERUP_IDLE);
1885 swf_ActionSet(tag,actions2);
1886 swf_SetU8(tag,0);
1887 swf_ButtonPostProcess(tag, 2);
1888 } else {
1889 swf_SetU8(tag,0);
1890 swf_ButtonPostProcess(tag, 1);
1894 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1896 if(posx!=0 || posy!=0) {
1897 MATRIX m;
1898 swf_GetMatrix(0,&m);
1899 m.tx = (int)(posx*20);
1900 m.ty = (int)(posy*20);
1901 swf_ObjectPlace(tag, buttonid, depth++,&m,0,0);
1903 else {
1904 swf_ObjectPlace(tag, buttonid, depth++,0,0,0);
1908 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
1909 double x1,double y1,
1910 double x2,double y2,
1911 double x3,double y3,
1912 double x4,double y4)
1914 RGBA rgb;
1915 SRECT r;
1916 int lsid=0;
1917 int fsid;
1918 struct plotxy p1,p2,p3,p4;
1919 int myshapeid;
1920 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
1921 if(x2>xmax) xmax=x2;
1922 if(y2>ymax) ymax=y2;
1923 if(x2<xmin) xmin=x2;
1924 if(y2<ymin) ymin=y2;
1925 if(x3>xmax) xmax=x3;
1926 if(y3>ymax) ymax=y3;
1927 if(x3<xmin) xmin=x3;
1928 if(y3<ymin) ymin=y3;
1929 if(x4>xmax) xmax=x4;
1930 if(y4>ymax) ymax=y4;
1931 if(x4<xmin) xmin=x4;
1932 if(y4<ymin) ymin=y4;
1933 p1.x=x1; p1.y=y1;
1934 p2.x=x2; p2.y=y2;
1935 p3.x=x3; p3.y=y3;
1936 p4.x=x4; p4.y=y4;
1938 {p1.x = (int)(p1.x*20)/20.0;
1939 p1.y = (int)(p1.y*20)/20.0;
1940 p2.x = (int)(p2.x*20)/20.0;
1941 p2.y = (int)(p2.y*20)/20.0;
1942 p3.x = (int)(p3.x*20)/20.0;
1943 p3.y = (int)(p3.y*20)/20.0;
1944 p4.x = (int)(p4.x*20)/20.0;
1945 p4.y = (int)(p4.y*20)/20.0;}
1947 MATRIX m;
1948 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
1949 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
1950 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
1951 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
1953 m.tx = (int)(p1.x*20);
1954 m.ty = (int)(p1.y*20);
1956 /* shape */
1957 myshapeid = ++currentswfid;
1958 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1959 swf_ShapeNew(&shape);
1960 //lsid = ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1961 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1962 fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
1963 swf_SetU16(tag, myshapeid);
1964 r.xmin = (int)(xmin*20);
1965 r.ymin = (int)(ymin*20);
1966 r.xmax = (int)(xmax*20);
1967 r.ymax = (int)(ymax*20);
1968 swf_SetRect(tag,&r);
1969 swf_SetShapeStyles(tag,shape);
1970 swf_ShapeCountBits(shape,NULL,NULL);
1971 swf_SetShapeBits(tag,shape);
1972 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,lsid,fsid,0);
1973 swflastx = swflasty = 0;
1974 moveto(tag, p1);
1975 lineto(tag, p2);
1976 lineto(tag, p3);
1977 lineto(tag, p4);
1978 lineto(tag, p1);
1980 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
1981 ShapeSetLine (tag, shape, (int)(x1*20);
1982 ShapeSetLine (tag, shape, x*20,0);
1983 ShapeSetLine (tag, shape, 0,-y*20);
1984 ShapeSetLine (tag, shape, -x*20,0);*/
1985 swf_ShapeSetEnd(tag);
1987 /* instance */
1988 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1989 swf_ObjectPlace(tag,myshapeid,/*depth*/depth++,NULL,NULL,NULL);
1992 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
1993 double x1,double y1,
1994 double x2,double y2,
1995 double x3,double y3,
1996 double x4,double y4)
1998 TAG*oldtag;
1999 if(shapeid>=0)
2000 endshape();
2001 if(textid>=0)
2002 endtext();
2004 int bitid = ++currentswfid;
2005 oldtag = tag;
2006 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
2007 swf_SetU16(tag, bitid);
2008 if(swf_SetJPEGBits(tag, filename, jpegquality)<0) {
2009 swf_DeleteTag(tag);
2010 tag = oldtag;
2011 return -1;
2014 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2015 return bitid;
2018 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2019 double x1,double y1,
2020 double x2,double y2,
2021 double x3,double y3,
2022 double x4,double y4)
2024 TAG*oldtag;
2025 JPEGBITS*jpeg;
2027 if(shapeid>=0)
2028 endshape();
2029 if(textid>=0)
2030 endtext();
2032 int bitid = ++currentswfid;
2033 oldtag = tag;
2034 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
2035 swf_SetU16(tag, bitid);
2036 swf_SetJPEGBits2(tag,sizex,sizey,mem,jpegquality);
2037 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2038 return bitid;
2041 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2042 double x1,double y1,
2043 double x2,double y2,
2044 double x3,double y3,
2045 double x4,double y4)
2047 TAG*oldtag;
2048 if(shapeid>=0)
2049 endshape();
2050 if(textid>=0)
2051 endtext();
2053 int bitid = ++currentswfid;
2054 oldtag = tag;
2055 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS);
2056 swf_SetU16(tag, bitid);
2057 if(swf_SetLosslessBits(tag,sizex,sizey,mem, BMF_32BIT)<0) {
2058 swf_DeleteTag(tag);
2059 tag = oldtag;
2060 return -1;
2063 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2064 return bitid;
2067 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
2068 double x1,double y1,
2069 double x2,double y2,
2070 double x3,double y3,
2071 double x4,double y4, int n)
2073 TAG*oldtag;
2074 U8*mem2 = 0;
2075 if(shapeid>=0)
2076 endshape();
2077 if(textid>=0)
2078 endtext();
2080 if(sizex&3)
2082 /* SWF expects scanlines to be 4 byte aligned */
2083 int x,y;
2084 U8*ptr;
2085 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
2086 ptr = mem2;
2087 for(y=0;y<sizey;y++)
2089 for(x=0;x<sizex;x++)
2090 *ptr++ = mem[y*sizex+x];
2091 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
2093 mem = mem2;
2096 int bitid = ++currentswfid;
2097 oldtag = tag;
2098 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS2);
2099 swf_SetU16(tag, bitid);
2100 if(swf_SetLosslessBitsIndexed(tag,sizex,sizey,mem, pal, n)<0) {
2101 swf_DeleteTag(tag);
2102 tag = oldtag;
2103 return -1;
2105 if(mem2)
2106 free(mem2);
2108 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2109 return bitid;
2112 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
2113 double x1,double y1,
2114 double x2,double y2,
2115 double x3,double y3,
2116 double x4,double y4)
2118 if(id<0) return;
2119 if(shapeid>=0)
2120 endshape();
2121 if(textid>=0)
2122 endtext();
2124 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);