2 Implements generation of swf files using the rfxswf lib. The routines
3 in this file are called from pdf2swf.
5 This file is part of swftools.
7 Swftools is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 Swftools is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with swftools; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
24 #include "../config.h"
33 #include "swfoutput.h"
36 #include "../lib/log.h"
37 #include "../lib/rfxswf.h"
40 #define CHARDATAMAX 8192
44 typedef struct _chardata {
46 int fontid; /* TODO: use a SWFFONT instead */
59 int config_opennewwindow=0;
60 int config_ignoredraworder=0;
61 int config_drawonlyshapes=0;
62 int config_jpegquality=85;
63 int config_storeallcharacters=0;
64 int config_enablezlib=0;
65 int config_insertstoptag=0;
66 int config_flashversion=5;
67 int config_splinemaxerror=1;
68 int config_fontsplinemaxerror=1;
69 int config_filloverlap=0;
71 float config_minlinewidth=0.05;
73 typedef struct _swfoutput_internal
110 char fillstylechanged;
117 chardata_t chardata[CHARDATAMAX];
121 } swfoutput_internal;
123 static swfoutput_internal* init_internal_struct()
125 swfoutput_internal*i = (swfoutput_internal*)malloc(sizeof(swfoutput_internal));
126 memset(i, 0, sizeof(swfoutput_internal));
148 i->fillstylechanged = 0;
158 static void startshape(struct swfoutput* obj);
159 static void starttext(struct swfoutput* obj);
160 static void endshape(struct swfoutput* obj,int clip);
161 static void endtext(struct swfoutput* obj);
163 // matrix multiplication. changes p0
164 static void transform (plotxy*p0,struct swfmatrix*m)
167 x = m->m11*p0->x+m->m12*p0->y;
168 y = m->m21*p0->x+m->m22*p0->y;
173 // write a move-to command into the swf
174 static int moveto(struct swfoutput*obj, TAG*tag, plotxy p0)
176 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
177 int rx = (int)(p0.x*20);
178 int ry = (int)(p0.y*20);
179 if(rx!=i->swflastx || ry!=i->swflasty || i->fillstylechanged) {
180 swf_ShapeSetMove (tag, i->shape, rx,ry);
181 i->fillstylechanged = 0;
188 static int moveto(struct swfoutput*obj, TAG*tag, float x, float y)
190 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
194 return moveto(obj, tag, p);
196 static void addPointToBBox(struct swfoutput*obj, int px, int py)
198 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
204 swf_ExpandRect(&i->bboxrect, p);
206 swf_ExpandRect3(&i->bboxrect, p, i->linewidth*3/2);
210 // write a line-to command into the swf
211 static void lineto(struct swfoutput*obj, TAG*tag, plotxy p0)
213 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
214 int px = (int)(p0.x*20);
215 int py = (int)(p0.y*20);
216 int rx = (px-i->swflastx);
217 int ry = (py-i->swflasty);
218 /* we can't skip this for rx=0,ry=0, those
220 swf_ShapeSetLine (tag, i->shape, rx,ry);
222 addPointToBBox(obj, i->swflastx,i->swflasty);
223 addPointToBBox(obj, px,py);
229 static void lineto(struct swfoutput*obj, TAG*tag, double x, double y)
237 // write a spline-to command into the swf
238 static void splineto(struct swfoutput*obj, TAG*tag, plotxy control,plotxy end)
240 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
241 int lastlastx = i->swflastx;
242 int lastlasty = i->swflasty;
244 int cx = ((int)(control.x*20)-i->swflastx);
245 int cy = ((int)(control.y*20)-i->swflasty);
248 int ex = ((int)(end.x*20)-i->swflastx);
249 int ey = ((int)(end.y*20)-i->swflasty);
253 if(cx || cy || ex || ey) {
254 swf_ShapeSetCurve(tag, i->shape, cx,cy,ex,ey);
255 addPointToBBox(obj, lastlastx ,lastlasty );
256 addPointToBBox(obj, lastlastx+cx,lastlasty+cy);
257 addPointToBBox(obj, lastlastx+cx+ex,lastlasty+cy+ey);
262 /* write a line, given two points and the transformation
264 static void line(struct swfoutput*obj, TAG*tag, plotxy p0, plotxy p1, struct swfmatrix*m)
268 moveto(obj, tag, p0);
269 lineto(obj, tag, p1);
272 /* write a cubic (!) spline. This involves calling the approximate()
273 function out of spline.cc to convert it to a quadratic spline. */
274 static void spline(struct swfoutput*obj, TAG*tag,plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m)
276 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
278 struct qspline q[128];
292 /* fonts use a different approximation than shapes */
293 num = cspline_approximate(&c, q, config_fontsplinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
294 //num = cspline_approximate(&c, q, 10.0, APPROXIMATE_INFLECTION);
296 num = cspline_approximate(&c, q, config_splinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
300 moveto(obj, tag,q[t].start);
301 splineto(obj, tag,q[t].control, q[t].end);
305 void resetdrawer(struct swfoutput*obj)
307 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
312 static void stopFill(struct swfoutput*obj)
314 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
317 swf_ShapeSetStyle(i->tag,i->shape,i->linestyleid,0x8000,0);
318 i->fillstylechanged = 1;
322 static void startFill(struct swfoutput*obj)
324 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
327 swf_ShapeSetStyle(i->tag,i->shape,0x8000,i->fillstyleid,0);
328 i->fillstylechanged = 1;
333 /* draw an outline. These are generated by pdf2swf and by t1lib
334 (representing characters). */
335 void drawpath(struct swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m, int log)
337 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
338 if( i->tag->id != ST_DEFINESHAPE &&
339 i->tag->id != ST_DEFINESHAPE2 &&
340 i->tag->id != ST_DEFINESHAPE3)
342 msg("<error> internal error: drawpath needs a shape tag, not %d\n",i->tag->id);
346 double lastx=0,lasty=0;
347 double firstx=0,firsty=0;
352 x += (outline->dest.x/(float)0xffff);
353 y += (outline->dest.y/(float)0xffff);
354 if(outline->type == SWF_PATHTYPE_MOVE)
356 //if(!init && fill && obj->drawmode != DRAWMODE_EOFILL && !ignoredraworder) {
357 if(config_filloverlap && !init && i->fill && obj->drawmode != DRAWMODE_EOFILL) {
358 /* drawmode=FILL (not EOFILL) means that
359 seperate shapes do not cancel each other out.
360 On SWF side, we need to start a new shape for each
361 closed polygon, because SWF only knows EOFILL.
368 if(((int)(lastx*20) != (int)(firstx*20) ||
369 (int)(lasty*20) != (int)(firsty*20)) &&
378 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
379 line(obj,i->tag, p0, p1, m);
385 else if(outline->type == SWF_PATHTYPE_LINE)
393 if(log) printf("line: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
394 line(obj,i->tag, p0,p1,m);
396 else if(outline->type == SWF_PATHTYPE_BEZIER)
402 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
405 p1.x=o2->C.x/(float)0xffff+lastx;
406 p1.y=o2->C.y/(float)0xffff+lasty;
407 p2.x=o2->B.x/(float)0xffff+lastx;
408 p2.y=o2->B.y/(float)0xffff+lasty;
411 if(log) printf("spline: %f,%f -> %f,%f\n",p3.x,p3.y,p0.x,p0.y);
412 spline(obj,i->tag,p0,p1,p2,p3,m);
415 msg("<error> drawpath: unknown outline type:%d\n", outline->type);
419 outline = outline->link;
421 if(((int)(lastx*20) != (int)(firstx*20) ||
422 (int)(lasty*20) != (int)(firsty*20)) &&
431 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
432 line(obj, i->tag, p0, p1, m);
436 plotxy getPivot(struct swfoutput*obj, SWF_OUTLINE*outline, int dir, double line_width, int end, int trytwo)
438 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
439 SWF_PATHPOINT next, next2;
440 double xv=0,yv=0, xv2=0, yv2=0;
445 if(outline->type == SWF_PATHTYPE_LINE) {
446 next = outline->dest;
448 next = ((SWF_BEZIERSEGMENT*)outline)->B;
449 if(next.x==0 && next.y==0) {
450 next = ((SWF_BEZIERSEGMENT*)outline)->C;
452 if(next.x==0 && next.y==0) {
453 next = ((SWF_BEZIERSEGMENT*)outline)->dest;
457 if(trytwo && outline->last && outline->last->type != SWF_PATHTYPE_MOVE) {
458 if(outline->type == SWF_PATHTYPE_LINE) {
459 next2 = outline->last->dest;
461 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)(outline->last))->C;
462 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)(outline->last))->B;
463 next2.x = outline->last->dest.x - c.x;
464 next2.y = outline->last->dest.y - c.y;
465 if(next2.x==0 && next2.y==0) {
466 next2.x = outline->last->dest.x - b.x;
467 next2.y = outline->last->dest.y - b.y;
469 if(next2.x==0 && next2.y==0) {
470 next2.x = outline->last->dest.x;
471 next2.y = outline->last->dest.y;
477 if(outline->type == SWF_PATHTYPE_LINE) {
478 next = outline->dest;
480 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)outline)->C;
481 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)outline)->B;
482 next.x = outline->dest.x - c.x;
483 next.y = outline->dest.y - c.y;
484 if(next.x==0 && next.y==0) {
485 next.x = outline->dest.x - b.x;
486 next.y = outline->dest.y - b.y;
488 if(next.x==0 && next.y==0) {
489 next.x = outline->dest.x;
490 next.y = outline->dest.y;
494 if(trytwo && outline->link && outline->link->type != SWF_PATHTYPE_MOVE) {
495 if(outline->type == SWF_PATHTYPE_LINE) {
496 next2 = outline->link->dest;
498 next2 = ((SWF_BEZIERSEGMENT*)(outline->link))->B;
499 if(next2.x==0 && next2.y==0) {
500 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->C;
502 if(next2.x==0 && next2.y==0) {
503 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->dest;
511 xv = next.y/(float)0xffff;
512 yv = -next.x/(float)0xffff;
514 xv = -next.y/(float)0xffff;
515 yv = next.x/(float)0xffff;
518 double r = (line_width/2)/sqrt(xv*xv+yv*yv);
524 xv2 = next2.y/(float)0xffff;
525 yv2 = -next2.x/(float)0xffff;
527 xv2 = -next2.y/(float)0xffff;
528 yv2 = next2.x/(float)0xffff;
531 double r2 = (line_width/2)/sqrt(xv2*xv2+yv2*yv2);
536 double r3 = (line_width/2)/sqrt(xv*xv+yv*yv);
546 void drawShortPath(struct swfoutput*obj, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline)
548 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
549 double lastx=x, lasty=y;
550 while (outline && outline->type != SWF_PATHTYPE_MOVE)
552 x += (outline->dest.x/(float)0xffff);
553 y += (outline->dest.y/(float)0xffff);
555 if(outline->type == SWF_PATHTYPE_LINE)
562 line(obj, i->tag, p0, p1, m);
564 else if(outline->type == SWF_PATHTYPE_BEZIER)
567 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
570 p1.x=o2->C.x/(float)0xffff+lastx;
571 p1.y=o2->C.y/(float)0xffff+lasty;
572 p2.x=o2->B.x/(float)0xffff+lastx;
573 p2.y=o2->B.y/(float)0xffff+lasty;
576 spline(obj, i->tag,p0,p1,p2,p3,m);
580 outline = outline->link;
584 void drawShortPathWithEnds(struct swfoutput*obj, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline, int num, int line_cap, int line_join, double line_width)
586 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
590 if(line_cap == LINE_CAP_BUTT || line_cap == LINE_CAP_SQUARE) {
593 SWF_OUTLINE *last, *tmp=outline;
594 plotxy s,e,p0,p1,p2,p3,m0,m1,m2,m3;
600 while(tmp && tmp->type != SWF_PATHTYPE_MOVE) {
602 lx += (tmp->dest.x/(float)0xffff);
603 ly += (tmp->dest.y/(float)0xffff);
606 s = getPivot(obj, outline, 0, line_width, 0, 0);
607 e = getPivot(obj, last, 0, line_width, 1, 0);
609 if(line_cap == LINE_CAP_BUTT) {
610 /* make the clipping rectangle slighly bigger
611 than the line ending, so that it get's clipped
621 p2.x = x2 - s.y - s.x*ee;
622 p2.y = y2 + s.x - s.y*ee;
623 p3.x = x2 - s.y + s.x*ee;
624 p3.y = y2 + s.x + s.y*ee;
629 m2.x = lx + e.y - e.x*ee;
630 m2.y = ly - e.x - e.y*ee;
631 m3.x = lx + e.y + e.x*ee;
632 m3.y = ly - e.x + e.y*ee;
634 for(nr=0;nr<2;nr++) {
636 struct plotxy q0,q1,q2,q3,q4,q5;
639 if(line_cap == LINE_CAP_BUTT) {
641 /* FIXME: box should be smaller */
643 q1.x = i->max_x; q1.y = 0;
644 q2.x = i->max_x; q2.y = i->max_y;
645 q3.x = 0; q3.y = i->max_y;
647 /* FIXME: box should be smaller */
648 q0.x = i->max_x; q0.y = i->max_y;
649 q1.x = 0; q1.y = i->max_y;
651 q3.x = i->max_x; q3.y = 0;
655 moveto(obj, i->tag, q0);
656 lineto(obj, i->tag, q1);
657 lineto(obj, i->tag, q2);
658 lineto(obj, i->tag, q3);
659 lineto(obj, i->tag, q0);
662 lineto(obj, i->tag, q4);
665 line(obj, i->tag, p0, p1, m);
666 line(obj, i->tag, p1, p2, m);
667 line(obj, i->tag, p2, p3, m);
668 line(obj, i->tag, p3, p0, m);
670 if(line_cap == LINE_CAP_BUTT) {
671 lineto(obj, i->tag, q0);
672 endshape(obj, i->depth+2-nr);
684 drawShortPath(obj,x,y,m,outline);
686 if(line_cap == LINE_CAP_BUTT) {
692 void drawT1toRect(struct swfoutput*obj, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline, int num, int line_cap, int line_join, double line_width)
694 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
695 plotxy d1,d2,p1,p2,p3,p4;
697 d1.x = (outline->dest.x/(float)0xffff);
698 d1.y = (outline->dest.y/(float)0xffff);
699 d2 = getPivot(obj, outline, 0, line_width, 0, 0);
701 assert(line_cap != LINE_CAP_ROUND);
702 if(line_cap == LINE_CAP_SQUARE) {
711 p2.x = x + d2.x + d1.x;
712 p2.y = y + d2.y + d1.y;
713 p3.x = x - d2.x + d1.x;
714 p3.y = y - d2.y + d1.y;
718 line(obj, i->tag, p1,p2, m);
719 line(obj, i->tag, p2,p3, m);
720 line(obj, i->tag, p3,p4, m);
721 line(obj, i->tag, p4,p1, m);
724 void drawShortPathWithStraightEnds(struct swfoutput*obj, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline, int num, int line_cap, int line_join, double line_width)
726 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
727 SWF_OUTLINE*tmp=outline;
730 assert(i->shapeid>=0);
733 drawT1toRect(obj, x, y, m,outline, num, line_cap, line_join, line_width);
735 while(tmp->link && tmp->link->type!=SWF_PATHTYPE_MOVE) {
736 xx += (tmp->dest.x/(float)0xffff);
737 yy += (tmp->dest.y/(float)0xffff);
741 assert(tmp->type == SWF_PATHTYPE_LINE);
742 assert(outline->type == SWF_PATHTYPE_LINE);
746 if(outline->link == tmp) {
747 /* the two straight line segments (which are everything we
748 need to draw) are very likely to overlap. To avoid that
749 they cancel each other out at the end points, start a new
750 shape for the second one */
751 endshape(obj,0);startshape(obj);
755 drawT1toRect(obj, xx, yy, m, tmp, num, line_cap, line_join, line_width);
757 if(outline->link != tmp)
759 stopFill(obj);stop=1;
761 tmp->type = SWF_PATHTYPE_MOVE;
762 x += (outline->dest.x/(float)0xffff);
763 y += (outline->dest.y/(float)0xffff);
764 outline = outline->link;
765 drawShortPath(obj, x, y, m, outline);
773 static int t1len(struct swfoutput*obj, SWF_OUTLINE*line)
775 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
777 while(line && line->type != SWF_PATHTYPE_MOVE) {
784 static float t1linelen(struct swfoutput*obj, SWF_OUTLINE*line)
786 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
788 x = (line->dest.x/(float)0xffff);
789 y = (line->dest.y/(float)0xffff);
790 return sqrt(x*x+y*y);
793 void drawpath2poly(struct swfoutput *obj, SWF_OUTLINE*outline, struct swfmatrix*m, int log, int line_join, int line_cap, double line_width, double miter_limit)
795 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
796 if( i->tag->id != ST_DEFINESHAPE &&
797 i->tag->id != ST_DEFINESHAPE2 &&
798 i->tag->id != ST_DEFINESHAPE3) {
799 msg("<error> internal error: drawpath needs a shape tag, not %d\n",i->tag->id);
802 assert(i->shapeid>=0);
804 double lastx=0,lasty=0;
807 SWF_OUTLINE*tmp = outline, *last = 0;
812 x += (tmp->dest.x/(float)0xffff);
813 y += (tmp->dest.y/(float)0xffff);
815 if(!tmp || tmp->type == SWF_PATHTYPE_MOVE) {
817 if(last->type == SWF_PATHTYPE_LINE && t1linelen(obj,last)>line_width*2 &&
818 lastwasline && line_cap != LINE_CAP_ROUND)
819 drawShortPathWithStraightEnds(obj, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
821 drawShortPathWithEnds(obj, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
835 if(tmp && tmp->type == SWF_PATHTYPE_LINE && t1linelen(obj,tmp)>line_width*2)
841 tmp->link->last = tmp; // make sure list is properly linked in both directions
846 static inline int colorcompare(struct swfoutput*obj, RGBA*a,RGBA*b)
858 static SRECT getcharacterbbox(struct swfoutput*obj, SWFFONT*font)
860 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
863 memset(&r, 0, sizeof(r));
866 if(debug) printf("\n");
867 for(t=0;t<i->chardatapos;t++)
869 if(i->chardata[t].fontid != font->id) {
870 msg("<error> Internal error: fontid %d != fontid %d", i->chardata[t].fontid, font->id);
873 SRECT b = font->layout->bounds[i->chardata[t].charid];
874 b.xmin *= i->chardata[t].size;
875 b.ymin *= i->chardata[t].size;
876 b.xmax *= i->chardata[t].size;
877 b.ymax *= i->chardata[t].size;
882 b.xmin += i->chardata[t].x;
883 b.ymin += i->chardata[t].y;
884 b.xmax += i->chardata[t].x;
885 b.ymax += i->chardata[t].y;
887 /* until we solve the INTERNAL_SCALING problem (see below)
888 make sure the bounding box is big enough */
894 if(debug) printf("(%f,%f,%f,%f) -> (%f,%f,%f,%f) [font %d/%d, char %d]\n",
895 font->layout->bounds[i->chardata[t].charid].xmin/20.0,
896 font->layout->bounds[i->chardata[t].charid].ymin/20.0,
897 font->layout->bounds[i->chardata[t].charid].xmax/20.0,
898 font->layout->bounds[i->chardata[t].charid].ymax/20.0,
903 i->chardata[t].fontid,
905 i->chardata[t].charid
907 swf_ExpandRect2(&r, &b);
909 if(debug) printf("-----> (%f,%f,%f,%f)\n",
917 static void putcharacters(struct swfoutput*obj, TAG*tag)
919 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
923 color.r = i->chardata[0].color.r^255;
932 int charadvance[128];
935 int glyphbits=1; //TODO: can this be zero?
938 if(tag->id != ST_DEFINETEXT &&
939 tag->id != ST_DEFINETEXT2) {
940 msg("<error> internal error: putcharacters needs an text tag, not %d\n",tag->id);
943 if(!i->chardatapos) {
944 msg("<warning> putcharacters called with zero characters");
947 for(pass = 0; pass < 2; pass++)
957 advancebits++; // add sign bit
958 swf_SetU8(tag, glyphbits);
959 swf_SetU8(tag, advancebits);
962 for(t=0;t<=i->chardatapos;t++)
964 if(lastfontid != i->chardata[t].fontid ||
965 lastx!=i->chardata[t].x ||
966 lasty!=i->chardata[t].y ||
967 !colorcompare(obj,&color, &i->chardata[t].color) ||
969 lastsize != i->chardata[t].size ||
972 if(charstorepos && pass==0)
975 for(s=0;s<charstorepos;s++)
977 while(charids[s]>=(1<<glyphbits))
979 while(charadvance[s]>=(1<<advancebits))
983 if(charstorepos && pass==1)
985 tag->writeBit = 0; // Q&D
986 swf_SetBits(tag, 0, 1); // GLYPH Record
987 swf_SetBits(tag, charstorepos, 7); // number of glyphs
989 for(s=0;s<charstorepos;s++)
991 swf_SetBits(tag, charids[s], glyphbits);
992 swf_SetBits(tag, charadvance[s], advancebits);
997 if(pass == 1 && t<i->chardatapos)
1003 if(lastx != i->chardata[t].x ||
1004 lasty != i->chardata[t].y)
1006 newx = i->chardata[t].x;
1007 newy = i->chardata[t].y;
1013 if(!colorcompare(obj,&color, &i->chardata[t].color))
1015 color = i->chardata[t].color;
1018 font.id = i->chardata[t].fontid;
1019 if(lastfontid != i->chardata[t].fontid || lastsize != i->chardata[t].size)
1022 tag->writeBit = 0; // Q&D
1023 swf_TextSetInfoRecord(tag, newfont, i->chardata[t].size, newcolor, newx,newy);
1026 lastfontid = i->chardata[t].fontid;
1027 lastx = i->chardata[t].x;
1028 lasty = i->chardata[t].y;
1029 lastsize = i->chardata[t].size;
1032 if(t==i->chardatapos)
1036 int nextt = t==i->chardatapos-1?t:t+1;
1037 int rel = i->chardata[nextt].x-i->chardata[t].x;
1038 if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) {
1040 lastx=i->chardata[nextt].x;
1044 lastx=i->chardata[t].x;
1046 charids[charstorepos] = i->chardata[t].charid;
1047 charadvance[charstorepos] = advance;
1054 static void putcharacter(struct swfoutput*obj, int fontid, int charid,
1055 int x,int y, int size)
1057 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1058 if(i->chardatapos == CHARDATAMAX)
1060 msg("<warning> Character buffer too small. SWF will be slightly bigger");
1064 i->chardata[i->chardatapos].fontid = fontid;
1065 i->chardata[i->chardatapos].charid = charid;
1066 i->chardata[i->chardatapos].x = x;
1067 i->chardata[i->chardatapos].y = y;
1068 i->chardata[i->chardatapos].color = obj->fillrgb;
1069 i->chardata[i->chardatapos].size = size;
1073 /* Notice: we can only put chars in the range -1639,1638 (-32768/20,32768/20).
1074 So if we set this value to high, the char coordinates will overflow.
1075 If we set it to low, however, the char positions will be inaccurate */
1076 #define FONT_INTERNAL_SIZE 4
1078 /* process a character. */
1079 static int drawchar(struct swfoutput*obj, SWFFONT *swffont, char*character, int charnr, int u, swfmatrix*m)
1081 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1083 msg("<warning> Font is NULL");
1087 int charid = getCharID(swffont, charnr, character, u);
1090 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1091 FIXNULL(character),charnr, u, FIXNULL((char*)swffont->name), swffont->numchars);
1102 float det = ((m->m11*m->m22)-(m->m21*m->m12));
1103 if(fabs(det) < 0.0005) {
1104 /* x direction equals y direction- the text is invisible */
1107 det = 20*FONT_INTERNAL_SIZE / det;
1110 p.x = (SCOORD)(( x * m->m22 - y * m->m12)*det);
1111 p.y = (SCOORD)((- x * m->m21 + y * m->m11)*det);
1113 putcharacter(obj, swffont->id, charid,p.x,p.y,FONT_INTERNAL_SIZE);
1114 swf_FontUseGlyph(swffont, charid);
1119 SWF_OUTLINE*outline = font->getOutline(character, charnr);
1120 char* charname = character;
1123 msg("<warning> Didn't find character '%s' (%d) in current charset (%s)",
1124 FIXNULL(character),charnr,FIXNULL(font->getName()));
1143 drawpath(tag, outline, &m2, 0);
1148 static void endtext(swfoutput*obj)
1150 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1154 i->tag = swf_InsertTag(i->tag,ST_DEFINETEXT);
1155 swf_SetU16(i->tag, i->textid);
1158 r = getcharacterbbox(obj, obj->swffont);
1160 swf_SetRect(i->tag,&r);
1163 swf_GetMatrix(0, &m); /* set unit matrix- the real matrix is in the placeobject */
1164 swf_SetMatrix(i->tag,&m);
1166 putcharacters(obj, i->tag);
1167 swf_SetU8(i->tag,0);
1168 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
1169 //swf_ObjectPlace(i->tag,i->textid,/*depth*/i->depth++,&i->page_matrix,NULL,NULL);
1171 swf_MatrixJoin(&m2,&obj->fontmatrix, &i->page_matrix);
1173 swf_ObjectPlace(i->tag,i->textid,/*depth*/i->depth++,&m2,NULL,NULL);
1178 /* draw a curved polygon. */
1179 void swfoutput_drawpath(swfoutput*obj, SWF_OUTLINE*outline,
1182 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1186 /* Multiple polygons in one shape don't overlap correctly,
1187 so we better start a new shape here if the polygon is filled
1189 if(i->shapeid>=0 && i->fill && !config_ignoredraworder) {
1202 drawpath(obj, outline,m, 0);
1205 void swfoutput_drawpath2poly(struct swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
1207 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1212 assert(i->shapeid<0);
1216 drawpath2poly(obj, outline, m, 0, line_join, line_cap, line_width, miter_limit);
1219 int getCharID(SWFFONT *font, int charnr, char *charname, int u)
1222 if(charname && font->glyphnames) {
1223 for(t=0;t<font->numchars;t++) {
1224 if(font->glyphnames[t] && !strcmp(font->glyphnames[t],charname)) {
1225 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1229 /* if we didn't find the character, maybe
1230 we can find the capitalized version */
1231 for(t=0;t<font->numchars;t++) {
1232 if(font->glyphnames[t] && !strcasecmp(font->glyphnames[t],charname)) {
1233 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1239 if(u>0 && font->encoding != 255) {
1240 /* try to use the unicode id */
1241 if(u>=0 && u<font->maxascii && font->ascii2glyph[u]>=0) {
1242 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->ascii2glyph[u]);
1243 return font->ascii2glyph[u];
1247 if(font->encoding != FONT_ENCODING_UNICODE) {
1248 /* the following only works if the font encoding
1249 is US-ASCII based. It's needed for fonts which return broken unicode
1251 if(charnr>=0 && charnr<font->maxascii && font->ascii2glyph[charnr]>=0) {
1252 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, font->ascii2glyph[charnr]);
1253 return font->ascii2glyph[charnr];
1257 if(charnr>=0 && charnr<font->numchars) {
1258 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1266 /* set's the t1 font index of the font to use for swfoutput_drawchar(). */
1267 void swfoutput_setfont(struct swfoutput*obj, char*fontid, char*filename)
1269 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1270 fontlist_t*last=0,*iterator;
1272 msg("<error> No fontid");
1276 if(obj->swffont && obj->swffont->name && !strcmp((char*)obj->swffont->name,fontid))
1279 /* TODO: remove the need for this (enhance getcharacterbbox so that it can cope
1280 with multiple fonts */
1283 iterator = i->fontlist;
1285 if(!strcmp((char*)iterator->swffont->name,fontid)) {
1286 obj->swffont = iterator->swffont;
1290 iterator = iterator->next;
1294 msg("<error> No filename given for font- internal error?");
1298 swf_SetLoadFontParameters(64,/*skip unused*/0,/*full unicode*/1);
1299 SWFFONT*swffont = swf_LoadFont(filename);
1302 msg("<warning> Couldn't load font %s (%s)", fontid, filename);
1303 swffont = swf_LoadFont(0);
1306 if(swffont->glyph2ascii) {
1309 /* check whether the Unicode indices look o.k.
1310 If they don't, disable the unicode lookup by setting
1311 the encoding to 255 */
1312 for(t=0;t<swffont->numchars;t++) {
1313 int c = swffont->glyph2ascii[t];
1314 if(c && c < 32 && swffont->glyph[t].shape->bitlen > 16) {
1315 // the character maps into the unicode control character range
1316 // between 0001-001f. Yet it is not empty. Treat the one
1317 // mapping as broken, and look how many of those we find.
1322 msg("<warning> Font %s has bad unicode mapping", swffont->name);
1323 swffont->encoding = 255;
1327 swf_FontSetID(swffont, ++i->currentswfid);
1329 if(getScreenLogLevel() >= LOGLEVEL_DEBUG) {
1330 // print font information
1331 msg("<debug> Font %s (%s)",swffont->name, filename);
1332 msg("<debug> | ID: %d", swffont->id);
1333 msg("<debug> | Version: %d", swffont->version);
1334 msg("<debug> | Name: %s", fontid);
1335 msg("<debug> | Numchars: %d", swffont->numchars);
1336 msg("<debug> | Maxascii: %d", swffont->maxascii);
1337 msg("<debug> | Style: %d", swffont->style);
1338 msg("<debug> | Encoding: %d", swffont->encoding);
1339 for(int iii=0; iii<swffont->numchars;iii++) {
1340 msg("<debug> | Glyph %d) name=%s, unicode=%d size=%d bbox=(%.2f,%.2f,%.2f,%.2f)\n", iii, swffont->glyphnames?swffont->glyphnames[iii]:"<nonames>", swffont->glyph2ascii[iii], swffont->glyph[iii].shape->bitlen,
1341 swffont->layout->bounds[iii].xmin/20.0,
1342 swffont->layout->bounds[iii].ymin/20.0,
1343 swffont->layout->bounds[iii].xmax/20.0,
1344 swffont->layout->bounds[iii].ymax/20.0
1347 for(t=0;t<swffont->maxascii;t++) {
1348 if(swffont->ascii2glyph[t] == iii)
1349 msg("<debug> | - maps to %d",t);
1354 /* set the font name to the ID we use here */
1355 if(swffont->name) free(swffont->name);
1356 swffont->name = (U8*)strdup(fontid);
1358 iterator = new fontlist_t;
1359 iterator->swffont = swffont;
1363 last->next = iterator;
1365 i->fontlist = iterator;
1367 obj->swffont = swffont;
1370 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1372 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1373 fontlist_t *iterator = i->fontlist;
1375 if(!strcmp((char*)iterator->swffont->name,fontid))
1377 iterator = iterator->next;
1382 /* set's the matrix which is to be applied to characters drawn by
1383 swfoutput_drawchar() */
1384 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1385 double m21,double m22)
1387 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1388 if(obj->fontm11 == m11 &&
1389 obj->fontm12 == m12 &&
1390 obj->fontm21 == m21 &&
1391 obj->fontm22 == m22)
1401 m.sx = (U32)(((obj->fontm11)*65536)/FONT_INTERNAL_SIZE); m.r1 = (U32)(((obj->fontm12)*65536)/FONT_INTERNAL_SIZE);
1402 m.r0 = (U32)(((obj->fontm21)*65536)/FONT_INTERNAL_SIZE); m.sy = (U32)(((obj->fontm22)*65536)/FONT_INTERNAL_SIZE);
1405 obj->fontmatrix = m;
1408 /* draws a character at x,y. */
1409 int swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr, int u)
1411 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1413 m.m11 = obj->fontm11;
1414 m.m12 = obj->fontm12;
1415 m.m21 = obj->fontm21;
1416 m.m22 = obj->fontm22;
1419 return drawchar(obj, obj->swffont, character, charnr, u, &m);
1422 static void endpage(struct swfoutput*obj)
1424 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1430 swfoutput_endclip(obj);
1431 i->pagefinished = 1;
1434 void swfoutput_pagefeed(struct swfoutput*obj)
1436 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1438 if(!i->pagefinished)
1441 if(config_insertstoptag) {
1443 atag = action_Stop(atag);
1444 atag = action_End(atag);
1445 i->tag = swf_InsertTag(i->tag,ST_DOACTION);
1446 swf_ActionSet(i->tag,atag);
1448 i->tag = swf_InsertTag(i->tag,ST_SHOWFRAME);
1451 for(i->depth--;i->depth>=i->startdepth;i->depth--) {
1452 i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2);
1453 swf_SetU16(i->tag,i->depth);
1455 i->depth = i->startdepth;
1458 static void setBackground(struct swfoutput*obj, int x1, int y1, int x2, int y2)
1460 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1462 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1466 int shapeid = ++i->currentswfid;
1471 i->tag = swf_InsertTag(i->tag, ST_DEFINESHAPE);
1473 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1474 swf_SetU16(i->tag,shapeid);
1475 swf_SetRect(i->tag,&r);
1476 swf_SetShapeHeader(i->tag,s);
1477 swf_ShapeSetAll(i->tag,s,x1,y1,ls1,fs1,0);
1478 swf_ShapeSetLine(i->tag,s,(x2-x1),0);
1479 swf_ShapeSetLine(i->tag,s,0,(y2-y1));
1480 swf_ShapeSetLine(i->tag,s,(x1-x2),0);
1481 swf_ShapeSetLine(i->tag,s,0,(y1-y2));
1482 swf_ShapeSetEnd(i->tag);
1484 i->tag = swf_InsertTag(i->tag, ST_PLACEOBJECT2);
1485 swf_ObjectPlace(i->tag,shapeid,i->depth++,0,0,0);
1486 i->tag = swf_InsertTag(i->tag, ST_PLACEOBJECT2);
1487 swf_ObjectPlaceClip(i->tag,shapeid,i->depth++,0,0,0,65535);
1488 i->cliptag = i->tag;
1491 void swfoutput_newpage(struct swfoutput*obj, int pageNum, int movex, int movey, int x1, int y1, int x2, int y2)
1493 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1494 if(!i->firstpage && !i->pagefinished)
1497 swf_GetMatrix(0, &i->page_matrix);
1498 i->page_matrix.tx = movex*20;
1499 i->page_matrix.ty = movey*20;
1501 if(i->cliptag && i->frameno == i->lastframeno) {
1503 swf_GetPlaceObject(i->cliptag, &obj);
1504 obj.clipdepth = i->depth++;
1505 swf_ResetTag(i->cliptag, i->cliptag->id);
1506 swf_SetPlaceObject(i->cliptag, &obj);
1507 swf_PlaceObjectFree(&obj);
1515 msg("<notice> processing page %d (%dx%d:%d:%d)", pageNum,x2-x1,y2-y1, x1, y1);
1517 x1*=20;y1*=20;x2*=20;y2*=20;
1519 /* set clipping/background rectangle */
1520 /* TODO: this should all be done in SWFOutputDev */
1521 setBackground(obj, x1, y1, x2, y2);
1523 /* increase SWF's bounding box */
1529 swf_ExpandRect2(&i->swf.movieSize, &r);
1531 i->lastframeno = i->frameno;
1533 i->pagefinished = 0;
1536 /* initialize the swf writer */
1537 void swfoutput_init(struct swfoutput* obj)
1539 memset(obj, 0, sizeof(struct swfoutput));
1540 obj->internal = init_internal_struct();
1542 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1547 msg("<verbose> initializing swf output for size %d*%d\n", i->max_x,i->max_y);
1552 memset(&i->swf,0x00,sizeof(SWF));
1554 i->swf.fileVersion = config_flashversion;
1555 i->swf.frameRate = 0x0040; // 1 frame per 4 seconds
1556 i->swf.movieSize.xmin = 0;
1557 i->swf.movieSize.ymin = 0;
1558 i->swf.movieSize.xmax = 0;
1559 i->swf.movieSize.ymax = 0;
1561 i->swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1562 i->tag = i->swf.firstTag;
1563 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1564 swf_SetRGB(i->tag,&rgb);
1566 i->startdepth = i->depth = 3; /* leave room for clip and background rectangle */
1569 i->tag = swf_InsertTag(i->tag, ST_PROTECT);
1572 static void startshape(struct swfoutput*obj)
1574 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1581 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE);
1583 swf_ShapeNew(&i->shape);
1584 i->linestyleid = swf_ShapeAddLineStyle(i->shape,i->linewidth,&obj->strokergb);
1585 rgb.r = obj->fillrgb.r;
1586 rgb.g = obj->fillrgb.g;
1587 rgb.b = obj->fillrgb.b;
1588 i->fillstyleid = swf_ShapeAddSolidFillStyle(i->shape,&obj->fillrgb);
1590 i->shapeid = ++i->currentswfid;
1591 swf_SetU16(i->tag,i->shapeid); // ID
1593 i->bboxrectpos = i->tag->len;
1596 r.xmax = 20*i->max_x;
1597 r.ymax = 20*i->max_y;
1598 swf_SetRect(i->tag,&r);
1600 memset(&i->bboxrect, 0, sizeof(i->bboxrect));
1602 swf_SetShapeStyles(i->tag,i->shape);
1603 swf_ShapeCountBits(i->shape,NULL,NULL);
1604 swf_SetShapeBits(i->tag,i->shape);
1606 /* TODO: do we really need this? */
1607 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,i->linestyleid,0,0);
1608 i->swflastx=i->swflasty=0;
1610 i->shapeisempty = 1;
1613 static void starttext(struct swfoutput*obj)
1615 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1619 i->textid = ++i->currentswfid;
1621 i->swflastx=i->swflasty=0;
1625 /* TODO: move to ../lib/rfxswf */
1626 void changeRect(struct swfoutput*obj, TAG*tag, int pos, SRECT*newrect)
1628 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1629 /* determine length of old rect */
1633 swf_GetRect(tag, &old);
1634 swf_ResetReadBits(tag);
1635 int pos_end = tag->pos;
1637 int len = tag->len - pos_end;
1638 U8*data = (U8*)malloc(len);
1639 memcpy(data, &tag->data[pos_end], len);
1642 swf_SetRect(tag, newrect);
1643 swf_SetBlock(tag, data, len);
1645 tag->pos = tag->readBit = 0;
1648 void cancelshape(swfoutput*obj)
1650 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1651 /* delete old shape tag */
1653 i->tag = i->tag->prev;
1654 swf_DeleteTag(todel);
1655 if(i->shape) {swf_ShapeFree(i->shape);i->shape=0;}
1657 i->bboxrectpos = -1;
1660 void fixAreas(swfoutput*obj)
1662 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1663 if(!i->shapeisempty && i->fill &&
1664 (i->bboxrect.xmin == i->bboxrect.xmax ||
1665 i->bboxrect.ymin == i->bboxrect.ymax) &&
1666 config_minlinewidth >= 0.001
1668 msg("<debug> Shape has size 0: width=%.2f height=%.2f",
1669 (i->bboxrect.xmax-i->bboxrect.xmin)/20.0,
1670 (i->bboxrect.ymax-i->bboxrect.ymin)/20.0
1673 SRECT r = i->bboxrect;
1675 if(r.xmin == r.xmax && r.ymin == r.ymax) {
1676 /* this thing comes down to a single dot- nothing to fix here */
1682 RGBA save_col = obj->strokergb;
1683 int save_width = i->linewidth;
1685 obj->strokergb = obj->fillrgb;
1686 i->linewidth = (int)(config_minlinewidth*20);
1687 if(i->linewidth==0) i->linewidth = 1;
1691 moveto(obj, i->tag, r.xmin/20.0,r.ymin/20.0);
1692 lineto(obj, i->tag, r.xmax/20.0,r.ymax/20.0);
1694 obj->strokergb = save_col;
1695 i->linewidth = save_width;
1700 static void endshape_noput(swfoutput*obj)
1702 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1705 //changeRect(obj, i->tag, i->bboxrectpos, &i->bboxrect);
1708 swf_ShapeFree(i->shape);
1713 static void endshape(swfoutput*obj, int clipdepth)
1715 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1722 if(i->shapeisempty ||
1724 (i->bboxrect.xmin == i->bboxrect.xmax &&
1725 i->bboxrect.ymin == i->bboxrect.ymax) ||
1726 /*bbox outside page?*/
1727 (i->bboxrect.xmax <= i->min_x ||
1728 i->bboxrect.ymax <= i->min_y ||
1729 i->bboxrect.xmin >= i->max_x ||
1730 i->bboxrect.ymin >= i->max_y)
1733 // delete the shape again, we didn't do anything
1738 swf_ShapeSetEnd(i->tag);
1740 changeRect(obj, i->tag, i->bboxrectpos, &i->bboxrect);
1742 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
1745 swf_ObjectPlaceClip(i->tag,i->shapeid,i->depth++,&i->page_matrix,NULL,NULL,clipdepth);
1747 swf_ObjectPlace(i->tag,i->shapeid,/*depth*/i->depth++,&i->page_matrix,NULL,NULL);
1749 swf_ShapeFree(i->shape);
1752 i->bboxrectpos = -1;
1755 void swfoutput_finalize(struct swfoutput*obj)
1757 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1759 if(i->tag && i->tag->id == ST_END)
1760 return; //already done
1762 if(i->frameno == i->lastframeno) // fix: add missing pagefeed
1763 swfoutput_pagefeed(obj);
1766 fontlist_t *tmp,*iterator = i->fontlist;
1768 TAG*mtag = i->swf.firstTag;
1769 if(iterator->swffont) {
1770 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1771 /*if(!storeallcharacters)
1772 swf_FontReduce(iterator->swffont);*/
1773 swf_FontSetDefine2(mtag, iterator->swffont);
1776 iterator = iterator->next;
1778 i->tag = swf_InsertTag(i->tag,ST_END);
1779 TAG* tag = i->tag->prev;
1781 /* remove the removeobject2 tags between the last ST_SHOWFRAME
1782 and the ST_END- they confuse the flash player */
1783 while(tag->id == ST_REMOVEOBJECT2) {
1784 TAG* prev = tag->prev;
1790 SWF* swfoutput_get(struct swfoutput*obj)
1792 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1794 swfoutput_finalize(obj);
1796 return swf_CopySWF(&i->swf);
1799 void swfoutput_getdimensions(struct swfoutput*obj, int*x1, int*y1, int*x2, int*y2)
1801 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1802 if(x1) *x1 = i->swf.movieSize.xmin/20;
1803 if(y1) *y1 = i->swf.movieSize.ymin/20;
1804 if(x2) *x2 = i->swf.movieSize.xmax/20;
1805 if(y2) *y2 = i->swf.movieSize.ymax/20;
1808 int swfoutput_save(struct swfoutput* obj, char*filename)
1810 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1811 swfoutput_finalize(obj);
1815 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1820 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1824 if(config_enablezlib || config_flashversion>=6) {
1825 if FAILED(swf_WriteSWC(fi,&i->swf))
1826 msg("<error> WriteSWC() failed.\n");
1828 if FAILED(swf_WriteSWF(fi,&i->swf))
1829 msg("<error> WriteSWF() failed.\n");
1834 msg("<notice> SWF written\n");
1838 /* Perform cleaning up, complete the swf, and write it out. */
1839 void swfoutput_destroy(struct swfoutput* obj)
1841 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1843 /* not initialized yet- nothing to destroy */
1847 fontlist_t *tmp,*iterator = i->fontlist;
1849 if(iterator->swffont) {
1850 swf_FontFree(iterator->swffont);iterator->swffont=0;
1853 iterator = iterator->next;
1856 swf_FreeTags(&i->swf);
1859 memset(obj, 0, sizeof(swfoutput));
1862 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1864 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1865 obj->drawmode = mode;
1866 if(mode == DRAWMODE_FILL)
1868 else if(mode == DRAWMODE_EOFILL)
1870 else if(mode == DRAWMODE_STROKE)
1872 else if(mode == DRAWMODE_CLIP)
1874 else if(mode == DRAWMODE_EOCLIP)
1878 void swfoutput_setfillcolor(swfoutput* obj, U8 r, U8 g, U8 b, U8 a)
1880 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1881 if(obj->fillrgb.r == r &&
1882 obj->fillrgb.g == g &&
1883 obj->fillrgb.b == b &&
1884 obj->fillrgb.a == a) return;
1894 void swfoutput_setstrokecolor(swfoutput* obj, U8 r, U8 g, U8 b, U8 a)
1896 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1897 if(obj->strokergb.r == r &&
1898 obj->strokergb.g == g &&
1899 obj->strokergb.b == b &&
1900 obj->strokergb.a == a) return;
1904 obj->strokergb.r = r;
1905 obj->strokergb.g = g;
1906 obj->strokergb.b = b;
1907 obj->strokergb.a = a;
1910 void swfoutput_setlinewidth(struct swfoutput*obj, double _linewidth)
1912 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1913 if(i->linewidth == (U16)(_linewidth*20))
1918 i->linewidth = (U16)(_linewidth*20);
1922 void swfoutput_startclip(swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m)
1924 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1930 if(i->clippos >= 127)
1932 msg("<warning> Too many clip levels.");
1937 int olddrawmode = obj->drawmode;
1938 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1939 swfoutput_drawpath(obj, outline, m);
1940 swf_ShapeSetEnd(i->tag);
1941 swfoutput_setdrawmode(obj, olddrawmode);
1943 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
1944 i->cliptags[i->clippos] = i->tag;
1945 i->clipshapes[i->clippos] = i->shapeid;
1946 i->clipdepths[i->clippos] = i->depth++;
1949 endshape_noput(obj);
1952 void swfoutput_endclip(swfoutput*obj)
1954 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1961 msg("<error> Invalid end of clipping region");
1965 swf_ObjectPlaceClip(i->cliptags[i->clippos],i->clipshapes[i->clippos],i->clipdepths[i->clippos],&i->page_matrix,NULL,NULL,i->depth++);
1968 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1970 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1972 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1974 if(!strncmp("http://pdf2swf:", url, 15)) {
1975 char*tmp = strdup(url);
1976 int l = strlen(tmp);
1979 swfoutput_namedlink(obj, tmp+15, points);
1989 if(config_opennewwindow)
1990 actions = action_GetUrl(0, url, "_parent");
1992 actions = action_GetUrl(0, url, "_this");
1993 actions = action_End(actions);
1995 drawlink(obj, actions, 0, points,0);
1997 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1999 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2007 actions = action_GotoFrame(0, page);
2008 actions = action_End(actions);
2010 drawlink(obj, actions, 0, points,0);
2013 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
2014 of the viewer objects, like subtitles, index elements etc.
2016 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
2018 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2019 ActionTAG *actions1,*actions2;
2020 char*tmp = strdup(name);
2028 if(!strncmp(tmp, "call:", 5))
2030 char*x = strchr(&tmp[5], ':');
2032 actions1 = action_PushInt(0, 0); //number of parameters (0)
2033 actions1 = action_PushString(actions1, &tmp[5]); //function name
2034 actions1 = action_CallFunction(actions1);
2037 actions1 = action_PushString(0, x+1); //parameter
2038 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
2039 actions1 = action_PushString(actions1, &tmp[5]); //function name
2040 actions1 = action_CallFunction(actions1);
2042 actions2 = action_End(0);
2047 actions1 = action_PushString(0, "/:subtitle");
2048 actions1 = action_PushString(actions1, name);
2049 actions1 = action_SetVariable(actions1);
2050 actions1 = action_End(actions1);
2052 actions2 = action_PushString(0, "/:subtitle");
2053 actions2 = action_PushString(actions2, "");
2054 actions2 = action_SetVariable(actions2);
2055 actions2 = action_End(actions2);
2058 drawlink(obj, actions1, actions2, points,mouseover);
2060 swf_ActionFree(actions1);
2061 swf_ActionFree(actions2);
2065 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
2067 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2072 struct plotxy p1,p2,p3,p4;
2076 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
2080 int buttonid = ++i->currentswfid;
2083 if(points[t].x>xmax) xmax=points[t].x;
2084 if(points[t].y>ymax) ymax=points[t].y;
2085 if(points[t].x<xmin) xmin=points[t].x;
2086 if(points[t].y<ymin) ymin=points[t].y;
2089 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
2090 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
2092 /* the following code subtracts the upper left edge from all coordinates,
2093 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
2094 Necessary for preprocessing with swfcombine. */
2095 posx = xmin; posy = ymin;
2096 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
2097 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
2098 xmin -= posx; ymin -= posy;
2099 xmax -= posx; ymax -= posy;
2102 myshapeid = ++i->currentswfid;
2103 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE3);
2104 swf_ShapeNew(&i->shape);
2105 rgb.r = rgb.b = rgb.a = rgb.g = 0;
2106 fsid = swf_ShapeAddSolidFillStyle(i->shape,&rgb);
2107 swf_SetU16(i->tag, myshapeid);
2108 r.xmin = (int)(xmin*20);
2109 r.ymin = (int)(ymin*20);
2110 r.xmax = (int)(xmax*20);
2111 r.ymax = (int)(ymax*20);
2112 swf_SetRect(i->tag,&r);
2113 swf_SetShapeStyles(i->tag,i->shape);
2114 swf_ShapeCountBits(i->shape,NULL,NULL);
2115 swf_SetShapeBits(i->tag,i->shape);
2116 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,0,fsid,0);
2117 i->swflastx = i->swflasty = 0;
2118 moveto(obj, i->tag, p1);
2119 lineto(obj, i->tag, p2);
2120 lineto(obj, i->tag, p3);
2121 lineto(obj, i->tag, p4);
2122 lineto(obj, i->tag, p1);
2123 swf_ShapeSetEnd(i->tag);
2126 myshapeid2 = ++i->currentswfid;
2127 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE3);
2128 swf_ShapeNew(&i->shape);
2129 rgb.r = rgb.b = rgb.a = rgb.g = 255;
2131 fsid = swf_ShapeAddSolidFillStyle(i->shape,&rgb);
2132 swf_SetU16(i->tag, myshapeid2);
2133 r.xmin = (int)(xmin*20);
2134 r.ymin = (int)(ymin*20);
2135 r.xmax = (int)(xmax*20);
2136 r.ymax = (int)(ymax*20);
2137 swf_SetRect(i->tag,&r);
2138 swf_SetShapeStyles(i->tag,i->shape);
2139 swf_ShapeCountBits(i->shape,NULL,NULL);
2140 swf_SetShapeBits(i->tag,i->shape);
2141 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,0,fsid,0);
2142 i->swflastx = i->swflasty = 0;
2143 moveto(obj, i->tag, p1);
2144 lineto(obj, i->tag, p2);
2145 lineto(obj, i->tag, p3);
2146 lineto(obj, i->tag, p4);
2147 lineto(obj, i->tag, p1);
2148 swf_ShapeSetEnd(i->tag);
2152 i->tag = swf_InsertTag(i->tag,ST_DEFINEBUTTON);
2153 swf_SetU16(i->tag,buttonid); //id
2154 swf_ButtonSetFlags(i->tag, 0); //menu=no
2155 swf_ButtonSetRecord(i->tag,0x01,myshapeid,i->depth,0,0);
2156 swf_ButtonSetRecord(i->tag,0x02,myshapeid2,i->depth,0,0);
2157 swf_ButtonSetRecord(i->tag,0x04,myshapeid2,i->depth,0,0);
2158 swf_ButtonSetRecord(i->tag,0x08,myshapeid,i->depth,0,0);
2159 swf_SetU8(i->tag,0);
2160 swf_ActionSet(i->tag,actions1);
2161 swf_SetU8(i->tag,0);
2165 i->tag = swf_InsertTag(i->tag,ST_DEFINEBUTTON2);
2166 swf_SetU16(i->tag,buttonid); //id
2167 swf_ButtonSetFlags(i->tag, 0); //menu=no
2168 swf_ButtonSetRecord(i->tag,0x01,myshapeid,i->depth,0,0);
2169 swf_ButtonSetRecord(i->tag,0x02,myshapeid2,i->depth,0,0);
2170 swf_ButtonSetRecord(i->tag,0x04,myshapeid2,i->depth,0,0);
2171 swf_ButtonSetRecord(i->tag,0x08,myshapeid,i->depth,0,0);
2172 swf_SetU8(i->tag,0); // end of button records
2173 swf_ButtonSetCondition(i->tag, BC_IDLE_OVERUP);
2174 swf_ActionSet(i->tag,actions1);
2176 swf_ButtonSetCondition(i->tag, BC_OVERUP_IDLE);
2177 swf_ActionSet(i->tag,actions2);
2178 swf_SetU8(i->tag,0);
2179 swf_ButtonPostProcess(i->tag, 2);
2181 swf_SetU8(i->tag,0);
2182 swf_ButtonPostProcess(i->tag, 1);
2186 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
2188 if(posx!=0 || posy!=0) {
2190 p.x = (int)(posx*20);
2191 p.y = (int)(posy*20);
2192 p = swf_TurnPoint(p, &i->page_matrix);
2197 swf_ObjectPlace(i->tag, buttonid, i->depth++,&m,0,0);
2200 swf_ObjectPlace(i->tag, buttonid, i->depth++,&i->page_matrix,0,0);
2204 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
2205 double x1,double y1,
2206 double x2,double y2,
2207 double x3,double y3,
2208 double x4,double y4)
2210 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2215 struct plotxy p1,p2,p3,p4;
2217 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
2218 if(x2>xmax) xmax=x2;
2219 if(y2>ymax) ymax=y2;
2220 if(x2<xmin) xmin=x2;
2221 if(y2<ymin) ymin=y2;
2222 if(x3>xmax) xmax=x3;
2223 if(y3>ymax) ymax=y3;
2224 if(x3<xmin) xmin=x3;
2225 if(y3<ymin) ymin=y3;
2226 if(x4>xmax) xmax=x4;
2227 if(y4>ymax) ymax=y4;
2228 if(x4<xmin) xmin=x4;
2229 if(y4<ymin) ymin=y4;
2235 {p1.x = (int)(p1.x*20)/20.0;
2236 p1.y = (int)(p1.y*20)/20.0;
2237 p2.x = (int)(p2.x*20)/20.0;
2238 p2.y = (int)(p2.y*20)/20.0;
2239 p3.x = (int)(p3.x*20)/20.0;
2240 p3.y = (int)(p3.y*20)/20.0;
2241 p4.x = (int)(p4.x*20)/20.0;
2242 p4.y = (int)(p4.y*20)/20.0;}
2245 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
2246 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
2247 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
2248 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
2250 m.tx = (int)(p1.x*20);
2251 m.ty = (int)(p1.y*20);
2254 myshapeid = ++i->currentswfid;
2255 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE);
2257 swf_ShapeNew(&shape);
2258 //lsid = ShapeAddLineStyle(shape,linewidth,&obj->strokergb);
2259 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
2260 fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
2261 swf_SetU16(i->tag, myshapeid);
2262 r.xmin = (int)(xmin*20);
2263 r.ymin = (int)(ymin*20);
2264 r.xmax = (int)(xmax*20);
2265 r.ymax = (int)(ymax*20);
2266 swf_SetRect(i->tag,&r);
2267 swf_SetShapeStyles(i->tag,shape);
2268 swf_ShapeCountBits(shape,NULL,NULL);
2269 swf_SetShapeBits(i->tag,shape);
2270 swf_ShapeSetAll(i->tag,shape,/*x*/0,/*y*/0,lsid,fsid,0);
2271 i->swflastx = i->swflasty = 0;
2272 moveto(obj, i->tag, p1);
2273 lineto(obj, i->tag, p2);
2274 lineto(obj, i->tag, p3);
2275 lineto(obj, i->tag, p4);
2276 lineto(obj, i->tag, p1);
2278 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
2279 ShapeSetLine (tag, shape, (int)(x1*20);
2280 ShapeSetLine (tag, shape, x*20,0);
2281 ShapeSetLine (tag, shape, 0,-y*20);
2282 ShapeSetLine (tag, shape, -x*20,0);*/
2283 swf_ShapeSetEnd(i->tag);
2284 swf_ShapeFree(shape);
2287 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
2289 swf_ObjectPlace(i->tag,myshapeid,/*depth*/i->depth++,&i->page_matrix,NULL,NULL);
2292 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
2293 double x1,double y1,
2294 double x2,double y2,
2295 double x3,double y3,
2296 double x4,double y4)
2298 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2305 int bitid = ++i->currentswfid;
2307 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSJPEG2);
2308 swf_SetU16(i->tag, bitid);
2309 if(swf_SetJPEGBits(i->tag, filename, config_jpegquality)<0) {
2310 swf_DeleteTag(i->tag);
2315 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2319 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2320 double x1,double y1,
2321 double x2,double y2,
2322 double x3,double y3,
2323 double x4,double y4)
2325 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2334 int bitid = ++i->currentswfid;
2336 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSJPEG2);
2337 swf_SetU16(i->tag, bitid);
2338 swf_SetJPEGBits2(i->tag,sizex,sizey,mem,config_jpegquality);
2339 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2343 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2344 double x1,double y1,
2345 double x2,double y2,
2346 double x3,double y3,
2347 double x4,double y4)
2349 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2356 int bitid = ++i->currentswfid;
2358 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSLOSSLESS);
2359 swf_SetU16(i->tag, bitid);
2360 if(swf_SetLosslessBits(i->tag,sizex,sizey,mem, BMF_32BIT)<0) {
2361 swf_DeleteTag(i->tag);
2366 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2370 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
2371 double x1,double y1,
2372 double x2,double y2,
2373 double x3,double y3,
2374 double x4,double y4, int n)
2376 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2386 /* SWF expects scanlines to be 4 byte aligned */
2389 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
2391 for(y=0;y<sizey;y++)
2393 for(x=0;x<sizex;x++)
2394 *ptr++ = mem[y*sizex+x];
2395 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
2400 int bitid = ++i->currentswfid;
2402 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSLOSSLESS2);
2403 swf_SetU16(i->tag, bitid);
2404 if(swf_SetLosslessBitsIndexed(i->tag,sizex,sizey,mem, pal, n)<0) {
2405 swf_DeleteTag(i->tag);
2412 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2416 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
2417 double x1,double y1,
2418 double x2,double y2,
2419 double x3,double y3,
2420 double x4,double y4)
2422 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2429 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2432 void swfoutput_setparameter(char*name, char*value)
2434 if(!strcmp(name, "drawonlyshapes")) {
2435 config_drawonlyshapes = atoi(value);
2436 } else if(!strcmp(name, "ignoredraworder")) {
2437 config_ignoredraworder = atoi(value);
2438 } else if(!strcmp(name, "filloverlap")) {
2439 config_filloverlap = atoi(value);
2440 } else if(!strcmp(name, "linksopennewwindow")) {
2441 config_opennewwindow = atoi(value);
2442 } else if(!strcmp(name, "opennewwindow")) {
2443 config_opennewwindow = atoi(value);
2444 } else if(!strcmp(name, "storeallcharacters")) {
2445 config_storeallcharacters = atoi(value);
2446 } else if(!strcmp(name, "enablezlib")) {
2447 config_enablezlib = atoi(value);
2448 } else if(!strcmp(name, "insertstop")) {
2449 config_insertstoptag = atoi(value);
2450 } else if(!strcmp(name, "protected")) {
2451 config_protect = atoi(value);
2452 } else if(!strcmp(name, "flashversion")) {
2453 config_flashversion = atoi(value);
2454 } else if(!strcmp(name, "minlinewidth")) {
2455 config_minlinewidth = atof(value);
2456 } else if(!strcmp(name, "jpegquality")) {
2457 int val = atoi(value);
2459 if(val>100) val=100;
2460 config_jpegquality = val;
2461 } else if(!strcmp(name, "splinequality")) {
2462 int v = atoi(value);
2463 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2465 config_splinemaxerror = v;
2466 } else if(!strcmp(name, "fontquality")) {
2467 int v = atoi(value);
2468 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2470 config_fontsplinemaxerror = v;
2472 fprintf(stderr, "unknown parameter: %s (=%s)\n", name, value);