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 */
65 int storeallcharacters;
70 int fontsplinemaxerror;
76 typedef struct _swfoutput_internal
110 char fillstylechanged;
115 chardata_t chardata[CHARDATAMAX];
118 } swfoutput_internal;
120 static int global_init;
122 static swfoutput_internal* init_internal_struct()
124 swfoutput_internal*i = (swfoutput_internal*)malloc(sizeof(swfoutput_internal));
125 memset(i, 0, sizeof(swfoutput_internal));
128 config.opennewwindow=0;
129 config.ignoredraworder=0;
130 config.drawonlyshapes=0;
131 config.jpegquality=85;
132 config.storeallcharacters=0;
134 config.insertstoptag=0;
135 config.flashversion=5;
136 config.splinemaxerror=1;
137 config.fontsplinemaxerror=1;
138 config.filloverlap=0;
139 config.minlinewidth=0.05;
143 i->flag_protected = 0;
160 i->fillstylechanged = 0;
169 static void startshape(struct swfoutput* obj);
170 static void starttext(struct swfoutput* obj);
171 static void endshape(struct swfoutput* obj,int clip);
172 static void endtext(struct swfoutput* obj);
174 // matrix multiplication. changes p0
175 static void transform (plotxy*p0,struct swfmatrix*m)
178 x = m->m11*p0->x+m->m12*p0->y;
179 y = m->m21*p0->x+m->m22*p0->y;
184 // write a move-to command into the swf
185 static int moveto(struct swfoutput*obj, TAG*tag, plotxy p0)
187 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
188 int rx = (int)(p0.x*20);
189 int ry = (int)(p0.y*20);
190 if(rx!=i->swflastx || ry!=i->swflasty || i->fillstylechanged) {
191 swf_ShapeSetMove (tag, i->shape, rx,ry);
192 i->fillstylechanged = 0;
199 static int moveto(struct swfoutput*obj, TAG*tag, float x, float y)
201 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
205 return moveto(obj, tag, p);
207 static void addPointToBBox(struct swfoutput*obj, int px, int py)
209 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
215 swf_ExpandRect(&i->bboxrect, p);
217 swf_ExpandRect3(&i->bboxrect, p, i->linewidth*3/2);
221 // write a line-to command into the swf
222 static void lineto(struct swfoutput*obj, TAG*tag, plotxy p0)
224 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
225 int px = (int)(p0.x*20);
226 int py = (int)(p0.y*20);
227 int rx = (px-i->swflastx);
228 int ry = (py-i->swflasty);
229 /* we can't skip this for rx=0,ry=0, those
231 swf_ShapeSetLine (tag, i->shape, rx,ry);
233 addPointToBBox(obj, i->swflastx,i->swflasty);
234 addPointToBBox(obj, px,py);
240 static void lineto(struct swfoutput*obj, TAG*tag, double x, double y)
248 // write a spline-to command into the swf
249 static void splineto(struct swfoutput*obj, TAG*tag, plotxy control,plotxy end)
251 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
252 int lastlastx = i->swflastx;
253 int lastlasty = i->swflasty;
255 int cx = ((int)(control.x*20)-i->swflastx);
256 int cy = ((int)(control.y*20)-i->swflasty);
259 int ex = ((int)(end.x*20)-i->swflastx);
260 int ey = ((int)(end.y*20)-i->swflasty);
264 if(cx || cy || ex || ey) {
265 swf_ShapeSetCurve(tag, i->shape, cx,cy,ex,ey);
266 addPointToBBox(obj, lastlastx ,lastlasty );
267 addPointToBBox(obj, lastlastx+cx,lastlasty+cy);
268 addPointToBBox(obj, lastlastx+cx+ex,lastlasty+cy+ey);
273 /* write a line, given two points and the transformation
275 static void line(struct swfoutput*obj, TAG*tag, plotxy p0, plotxy p1, struct swfmatrix*m)
279 moveto(obj, tag, p0);
280 lineto(obj, tag, p1);
283 /* write a cubic (!) spline. This involves calling the approximate()
284 function out of spline.cc to convert it to a quadratic spline. */
285 static void spline(struct swfoutput*obj, TAG*tag,plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m)
287 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
289 struct qspline q[128];
303 /* fonts use a different approximation than shapes */
304 num = cspline_approximate(&c, q, config.fontsplinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
305 //num = cspline_approximate(&c, q, 10.0, APPROXIMATE_INFLECTION);
307 num = cspline_approximate(&c, q, config.splinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
311 moveto(obj, tag,q[t].start);
312 splineto(obj, tag,q[t].control, q[t].end);
316 void resetdrawer(struct swfoutput*obj)
318 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
323 static void stopFill(struct swfoutput*obj)
325 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
328 swf_ShapeSetStyle(i->tag,i->shape,i->linestyleid,0x8000,0);
329 i->fillstylechanged = 1;
333 static void startFill(struct swfoutput*obj)
335 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
338 swf_ShapeSetStyle(i->tag,i->shape,0x8000,i->fillstyleid,0);
339 i->fillstylechanged = 1;
344 /* draw an outline. These are generated by pdf2swf and by t1lib
345 (representing characters). */
346 void drawpath(struct swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m, int log)
348 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
349 if( i->tag->id != ST_DEFINESHAPE &&
350 i->tag->id != ST_DEFINESHAPE2 &&
351 i->tag->id != ST_DEFINESHAPE3)
353 msg("<error> internal error: drawpath needs a shape tag, not %d\n",i->tag->id);
357 double lastx=0,lasty=0;
358 double firstx=0,firsty=0;
363 x += (outline->dest.x/(float)0xffff);
364 y += (outline->dest.y/(float)0xffff);
365 if(outline->type == SWF_PATHTYPE_MOVE)
367 //if(!init && fill && obj->drawmode != DRAWMODE_EOFILL && !ignoredraworder) {
368 if(config.filloverlap && !init && i->fill && obj->drawmode != DRAWMODE_EOFILL) {
369 /* drawmode=FILL (not EOFILL) means that
370 seperate shapes do not cancel each other out.
371 On SWF side, we need to start a new shape for each
372 closed polygon, because SWF only knows EOFILL.
379 if(((int)(lastx*20) != (int)(firstx*20) ||
380 (int)(lasty*20) != (int)(firsty*20)) &&
389 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
390 line(obj,i->tag, p0, p1, m);
396 else if(outline->type == SWF_PATHTYPE_LINE)
404 if(log) printf("line: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
405 line(obj,i->tag, p0,p1,m);
407 else if(outline->type == SWF_PATHTYPE_BEZIER)
413 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
416 p1.x=o2->C.x/(float)0xffff+lastx;
417 p1.y=o2->C.y/(float)0xffff+lasty;
418 p2.x=o2->B.x/(float)0xffff+lastx;
419 p2.y=o2->B.y/(float)0xffff+lasty;
422 if(log) printf("spline: %f,%f -> %f,%f\n",p3.x,p3.y,p0.x,p0.y);
423 spline(obj,i->tag,p0,p1,p2,p3,m);
426 msg("<error> drawpath: unknown outline type:%d\n", outline->type);
430 outline = outline->link;
432 if(((int)(lastx*20) != (int)(firstx*20) ||
433 (int)(lasty*20) != (int)(firsty*20)) &&
442 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
443 line(obj, i->tag, p0, p1, m);
447 plotxy getPivot(struct swfoutput*obj, SWF_OUTLINE*outline, int dir, double line_width, int end, int trytwo)
449 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
450 SWF_PATHPOINT next, next2;
451 double xv=0,yv=0, xv2=0, yv2=0;
456 if(outline->type == SWF_PATHTYPE_LINE) {
457 next = outline->dest;
459 next = ((SWF_BEZIERSEGMENT*)outline)->B;
460 if(next.x==0 && next.y==0) {
461 next = ((SWF_BEZIERSEGMENT*)outline)->C;
463 if(next.x==0 && next.y==0) {
464 next = ((SWF_BEZIERSEGMENT*)outline)->dest;
468 if(trytwo && outline->last && outline->last->type != SWF_PATHTYPE_MOVE) {
469 if(outline->type == SWF_PATHTYPE_LINE) {
470 next2 = outline->last->dest;
472 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)(outline->last))->C;
473 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)(outline->last))->B;
474 next2.x = outline->last->dest.x - c.x;
475 next2.y = outline->last->dest.y - c.y;
476 if(next2.x==0 && next2.y==0) {
477 next2.x = outline->last->dest.x - b.x;
478 next2.y = outline->last->dest.y - b.y;
480 if(next2.x==0 && next2.y==0) {
481 next2.x = outline->last->dest.x;
482 next2.y = outline->last->dest.y;
488 if(outline->type == SWF_PATHTYPE_LINE) {
489 next = outline->dest;
491 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)outline)->C;
492 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)outline)->B;
493 next.x = outline->dest.x - c.x;
494 next.y = outline->dest.y - c.y;
495 if(next.x==0 && next.y==0) {
496 next.x = outline->dest.x - b.x;
497 next.y = outline->dest.y - b.y;
499 if(next.x==0 && next.y==0) {
500 next.x = outline->dest.x;
501 next.y = outline->dest.y;
505 if(trytwo && outline->link && outline->link->type != SWF_PATHTYPE_MOVE) {
506 if(outline->type == SWF_PATHTYPE_LINE) {
507 next2 = outline->link->dest;
509 next2 = ((SWF_BEZIERSEGMENT*)(outline->link))->B;
510 if(next2.x==0 && next2.y==0) {
511 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->C;
513 if(next2.x==0 && next2.y==0) {
514 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->dest;
522 xv = next.y/(float)0xffff;
523 yv = -next.x/(float)0xffff;
525 xv = -next.y/(float)0xffff;
526 yv = next.x/(float)0xffff;
529 double r = (line_width/2)/sqrt(xv*xv+yv*yv);
535 xv2 = next2.y/(float)0xffff;
536 yv2 = -next2.x/(float)0xffff;
538 xv2 = -next2.y/(float)0xffff;
539 yv2 = next2.x/(float)0xffff;
542 double r2 = (line_width/2)/sqrt(xv2*xv2+yv2*yv2);
547 double r3 = (line_width/2)/sqrt(xv*xv+yv*yv);
557 void drawShortPath(struct swfoutput*obj, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline)
559 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
560 double lastx=x, lasty=y;
561 while (outline && outline->type != SWF_PATHTYPE_MOVE)
563 x += (outline->dest.x/(float)0xffff);
564 y += (outline->dest.y/(float)0xffff);
566 if(outline->type == SWF_PATHTYPE_LINE)
573 line(obj, i->tag, p0, p1, m);
575 else if(outline->type == SWF_PATHTYPE_BEZIER)
578 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
581 p1.x=o2->C.x/(float)0xffff+lastx;
582 p1.y=o2->C.y/(float)0xffff+lasty;
583 p2.x=o2->B.x/(float)0xffff+lastx;
584 p2.y=o2->B.y/(float)0xffff+lasty;
587 spline(obj, i->tag,p0,p1,p2,p3,m);
591 outline = outline->link;
595 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)
597 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
601 if(line_cap == LINE_CAP_BUTT || line_cap == LINE_CAP_SQUARE) {
604 SWF_OUTLINE *last, *tmp=outline;
605 plotxy s,e,p0,p1,p2,p3,m0,m1,m2,m3;
611 while(tmp && tmp->type != SWF_PATHTYPE_MOVE) {
613 lx += (tmp->dest.x/(float)0xffff);
614 ly += (tmp->dest.y/(float)0xffff);
617 s = getPivot(obj, outline, 0, line_width, 0, 0);
618 e = getPivot(obj, last, 0, line_width, 1, 0);
620 if(line_cap == LINE_CAP_BUTT) {
621 /* make the clipping rectangle slighly bigger
622 than the line ending, so that it get's clipped
632 p2.x = x2 - s.y - s.x*ee;
633 p2.y = y2 + s.x - s.y*ee;
634 p3.x = x2 - s.y + s.x*ee;
635 p3.y = y2 + s.x + s.y*ee;
640 m2.x = lx + e.y - e.x*ee;
641 m2.y = ly - e.x - e.y*ee;
642 m3.x = lx + e.y + e.x*ee;
643 m3.y = ly - e.x + e.y*ee;
645 for(nr=0;nr<2;nr++) {
647 struct plotxy q0,q1,q2,q3,q4,q5;
650 if(line_cap == LINE_CAP_BUTT) {
652 /* FIXME: box should be smaller */
654 q1.x = i->sizex; q1.y = 0;
655 q2.x = i->sizex; q2.y = i->sizey;
656 q3.x = 0; q3.y = i->sizey;
658 /* FIXME: box should be smaller */
659 q0.x = i->sizex; q0.y = i->sizey;
660 q1.x = 0; q1.y = i->sizey;
662 q3.x = i->sizex; q3.y = 0;
666 moveto(obj, i->tag, q0);
667 lineto(obj, i->tag, q1);
668 lineto(obj, i->tag, q2);
669 lineto(obj, i->tag, q3);
670 lineto(obj, i->tag, q0);
673 lineto(obj, i->tag, q4);
676 line(obj, i->tag, p0, p1, m);
677 line(obj, i->tag, p1, p2, m);
678 line(obj, i->tag, p2, p3, m);
679 line(obj, i->tag, p3, p0, m);
681 if(line_cap == LINE_CAP_BUTT) {
682 lineto(obj, i->tag, q0);
683 endshape(obj, i->depth+2-nr);
695 drawShortPath(obj,x,y,m,outline);
697 if(line_cap == LINE_CAP_BUTT) {
703 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)
705 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
706 plotxy d1,d2,p1,p2,p3,p4;
708 d1.x = (outline->dest.x/(float)0xffff);
709 d1.y = (outline->dest.y/(float)0xffff);
710 d2 = getPivot(obj, outline, 0, line_width, 0, 0);
712 assert(line_cap != LINE_CAP_ROUND);
713 if(line_cap == LINE_CAP_SQUARE) {
722 p2.x = x + d2.x + d1.x;
723 p2.y = y + d2.y + d1.y;
724 p3.x = x - d2.x + d1.x;
725 p3.y = y - d2.y + d1.y;
729 line(obj, i->tag, p1,p2, m);
730 line(obj, i->tag, p2,p3, m);
731 line(obj, i->tag, p3,p4, m);
732 line(obj, i->tag, p4,p1, m);
735 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)
737 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
738 SWF_OUTLINE*tmp=outline;
741 assert(i->shapeid>=0);
744 drawT1toRect(obj, x, y, m,outline, num, line_cap, line_join, line_width);
746 while(tmp->link && tmp->link->type!=SWF_PATHTYPE_MOVE) {
747 xx += (tmp->dest.x/(float)0xffff);
748 yy += (tmp->dest.y/(float)0xffff);
752 assert(tmp->type == SWF_PATHTYPE_LINE);
753 assert(outline->type == SWF_PATHTYPE_LINE);
757 if(outline->link == tmp) {
758 /* the two straight line segments (which are everything we
759 need to draw) are very likely to overlap. To avoid that
760 they cancel each other out at the end points, start a new
761 shape for the second one */
762 endshape(obj,0);startshape(obj);
766 drawT1toRect(obj, xx, yy, m, tmp, num, line_cap, line_join, line_width);
768 if(outline->link != tmp)
770 stopFill(obj);stop=1;
772 tmp->type = SWF_PATHTYPE_MOVE;
773 x += (outline->dest.x/(float)0xffff);
774 y += (outline->dest.y/(float)0xffff);
775 outline = outline->link;
776 drawShortPath(obj, x, y, m, outline);
784 static int t1len(struct swfoutput*obj, SWF_OUTLINE*line)
786 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
788 while(line && line->type != SWF_PATHTYPE_MOVE) {
795 static float t1linelen(struct swfoutput*obj, SWF_OUTLINE*line)
797 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
799 x = (line->dest.x/(float)0xffff);
800 y = (line->dest.y/(float)0xffff);
801 return sqrt(x*x+y*y);
804 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)
806 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
807 if( i->tag->id != ST_DEFINESHAPE &&
808 i->tag->id != ST_DEFINESHAPE2 &&
809 i->tag->id != ST_DEFINESHAPE3) {
810 msg("<error> internal error: drawpath needs a shape tag, not %d\n",i->tag->id);
813 assert(i->shapeid>=0);
815 double lastx=0,lasty=0;
818 SWF_OUTLINE*tmp = outline, *last = 0;
823 x += (tmp->dest.x/(float)0xffff);
824 y += (tmp->dest.y/(float)0xffff);
826 if(!tmp || tmp->type == SWF_PATHTYPE_MOVE) {
828 if(last->type == SWF_PATHTYPE_LINE && t1linelen(obj,last)>line_width*2 &&
829 lastwasline && line_cap != LINE_CAP_ROUND)
830 drawShortPathWithStraightEnds(obj, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
832 drawShortPathWithEnds(obj, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
846 if(tmp && tmp->type == SWF_PATHTYPE_LINE && t1linelen(obj,tmp)>line_width*2)
852 tmp->link->last = tmp; // make sure list is properly linked in both directions
857 static inline int colorcompare(struct swfoutput*obj, RGBA*a,RGBA*b)
869 static SRECT getcharacterbbox(struct swfoutput*obj, SWFFONT*font)
871 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
874 memset(&r, 0, sizeof(r));
877 if(debug) printf("\n");
878 for(t=0;t<i->chardatapos;t++)
880 if(i->chardata[t].fontid != font->id) {
881 msg("<error> Internal error: fontid %d != fontid %d", i->chardata[t].fontid, font->id);
884 SRECT b = font->layout->bounds[i->chardata[t].charid];
885 b.xmin *= i->chardata[t].size;
886 b.ymin *= i->chardata[t].size;
887 b.xmax *= i->chardata[t].size;
888 b.ymax *= i->chardata[t].size;
893 b.xmin += i->chardata[t].x;
894 b.ymin += i->chardata[t].y;
895 b.xmax += i->chardata[t].x;
896 b.ymax += i->chardata[t].y;
898 /* until we solve the INTERNAL_SCALING problem (see below)
899 make sure the bounding box is big enough */
905 if(debug) printf("(%f,%f,%f,%f) -> (%f,%f,%f,%f) [font %d/%d, char %d]\n",
906 font->layout->bounds[i->chardata[t].charid].xmin/20.0,
907 font->layout->bounds[i->chardata[t].charid].ymin/20.0,
908 font->layout->bounds[i->chardata[t].charid].xmax/20.0,
909 font->layout->bounds[i->chardata[t].charid].ymax/20.0,
914 i->chardata[t].fontid,
916 i->chardata[t].charid
918 swf_ExpandRect2(&r, &b);
920 if(debug) printf("-----> (%f,%f,%f,%f)\n",
928 static void putcharacters(struct swfoutput*obj, TAG*tag)
930 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
934 color.r = i->chardata[0].color.r^255;
943 int charadvance[128];
946 int glyphbits=1; //TODO: can this be zero?
949 if(tag->id != ST_DEFINETEXT &&
950 tag->id != ST_DEFINETEXT2) {
951 msg("<error> internal error: putcharacters needs an text tag, not %d\n",tag->id);
954 if(!i->chardatapos) {
955 msg("<warning> putcharacters called with zero characters");
958 for(pass = 0; pass < 2; pass++)
968 advancebits++; // add sign bit
969 swf_SetU8(tag, glyphbits);
970 swf_SetU8(tag, advancebits);
973 for(t=0;t<=i->chardatapos;t++)
975 if(lastfontid != i->chardata[t].fontid ||
976 lastx!=i->chardata[t].x ||
977 lasty!=i->chardata[t].y ||
978 !colorcompare(obj,&color, &i->chardata[t].color) ||
980 lastsize != i->chardata[t].size ||
983 if(charstorepos && pass==0)
986 for(s=0;s<charstorepos;s++)
988 while(charids[s]>=(1<<glyphbits))
990 while(charadvance[s]>=(1<<advancebits))
994 if(charstorepos && pass==1)
996 tag->writeBit = 0; // Q&D
997 swf_SetBits(tag, 0, 1); // GLYPH Record
998 swf_SetBits(tag, charstorepos, 7); // number of glyphs
1000 for(s=0;s<charstorepos;s++)
1002 swf_SetBits(tag, charids[s], glyphbits);
1003 swf_SetBits(tag, charadvance[s], advancebits);
1008 if(pass == 1 && t<i->chardatapos)
1014 if(lastx != i->chardata[t].x ||
1015 lasty != i->chardata[t].y)
1017 newx = i->chardata[t].x;
1018 newy = i->chardata[t].y;
1024 if(!colorcompare(obj,&color, &i->chardata[t].color))
1026 color = i->chardata[t].color;
1029 font.id = i->chardata[t].fontid;
1030 if(lastfontid != i->chardata[t].fontid || lastsize != i->chardata[t].size)
1033 tag->writeBit = 0; // Q&D
1034 swf_TextSetInfoRecord(tag, newfont, i->chardata[t].size, newcolor, newx,newy);
1037 lastfontid = i->chardata[t].fontid;
1038 lastx = i->chardata[t].x;
1039 lasty = i->chardata[t].y;
1040 lastsize = i->chardata[t].size;
1043 if(t==i->chardatapos)
1047 int nextt = t==i->chardatapos-1?t:t+1;
1048 int rel = i->chardata[nextt].x-i->chardata[t].x;
1049 if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) {
1051 lastx=i->chardata[nextt].x;
1055 lastx=i->chardata[t].x;
1057 charids[charstorepos] = i->chardata[t].charid;
1058 charadvance[charstorepos] = advance;
1065 static void putcharacter(struct swfoutput*obj, int fontid, int charid,
1066 int x,int y, int size)
1068 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1069 if(i->chardatapos == CHARDATAMAX)
1071 msg("<warning> Character buffer too small. SWF will be slightly bigger");
1075 i->chardata[i->chardatapos].fontid = fontid;
1076 i->chardata[i->chardatapos].charid = charid;
1077 i->chardata[i->chardatapos].x = x;
1078 i->chardata[i->chardatapos].y = y;
1079 i->chardata[i->chardatapos].color = obj->fillrgb;
1080 i->chardata[i->chardatapos].size = size;
1084 /* Notice: we can only put chars in the range -1639,1638 (-32768/20,32768/20).
1085 So if we set this value to high, the char coordinates will overflow.
1086 If we set it to low, however, the char positions will be inaccurate */
1087 #define FONT_INTERNAL_SIZE 4
1089 /* process a character. */
1090 static int drawchar(struct swfoutput*obj, SWFFONT *swffont, char*character, int charnr, int u, swfmatrix*m)
1092 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1094 msg("<warning> Font is NULL");
1098 int charid = getCharID(swffont, charnr, character, u);
1101 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1102 FIXNULL(character),charnr, u, FIXNULL((char*)swffont->name), swffont->numchars);
1113 float det = ((m->m11*m->m22)-(m->m21*m->m12));
1114 if(fabs(det) < 0.0005) {
1115 /* x direction equals y direction- the text is invisible */
1118 det = 20*FONT_INTERNAL_SIZE / det;
1121 p.x = (SCOORD)(( x * m->m22 - y * m->m12)*det);
1122 p.y = (SCOORD)((- x * m->m21 + y * m->m11)*det);
1124 putcharacter(obj, swffont->id, charid,p.x,p.y,FONT_INTERNAL_SIZE);
1125 swf_FontUseGlyph(swffont, charid);
1130 SWF_OUTLINE*outline = font->getOutline(character, charnr);
1131 char* charname = character;
1134 msg("<warning> Didn't find character '%s' (%d) in current charset (%s)",
1135 FIXNULL(character),charnr,FIXNULL(font->getName()));
1154 drawpath(tag, outline, &m2, 0);
1159 static void endtext(swfoutput*obj)
1161 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1165 i->tag = swf_InsertTag(i->tag,ST_DEFINETEXT);
1166 swf_SetU16(i->tag, i->textid);
1169 r = getcharacterbbox(obj, obj->swffont);
1171 swf_SetRect(i->tag,&r);
1174 swf_GetMatrix(0, &m);
1175 swf_SetMatrix(i->tag,&m);
1177 putcharacters(obj, i->tag);
1178 swf_SetU8(i->tag,0);
1179 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
1180 swf_ObjectPlace(i->tag,i->textid,/*depth*/i->depth++,&obj->fontmatrix,NULL,NULL);
1185 /* draw a curved polygon. */
1186 void swfoutput_drawpath(swfoutput*obj, SWF_OUTLINE*outline,
1189 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1193 /* Multiple polygons in one shape don't overlap correctly,
1194 so we better start a new shape here if the polygon is filled
1196 if(i->shapeid>=0 && i->fill && !config.ignoredraworder) {
1208 drawpath(obj, outline,m, 0);
1211 void swfoutput_drawpath2poly(struct swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
1213 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1218 assert(i->shapeid<0);
1222 drawpath2poly(obj, outline, m, 0, line_join, line_cap, line_width, miter_limit);
1225 int getCharID(SWFFONT *font, int charnr, char *charname, int u)
1228 if(charname && font->glyphnames) {
1229 for(t=0;t<font->numchars;t++) {
1230 if(font->glyphnames[t] && !strcmp(font->glyphnames[t],charname)) {
1231 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1235 /* if we didn't find the character, maybe
1236 we can find the capitalized version */
1237 for(t=0;t<font->numchars;t++) {
1238 if(font->glyphnames[t] && !strcasecmp(font->glyphnames[t],charname)) {
1239 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1246 /* try to use the unicode id */
1247 if(u>=0 && u<font->maxascii && font->ascii2glyph[u]>=0) {
1248 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->ascii2glyph[u]);
1249 return font->ascii2glyph[u];
1253 if(font->encoding != FONT_ENCODING_UNICODE) {
1254 /* the following only works if the font encoding
1255 is US-ASCII based. It's needed for fonts which return broken unicode
1257 if(charnr>=0 && charnr<font->maxascii && font->ascii2glyph[charnr]>=0) {
1258 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, font->ascii2glyph[charnr]);
1259 return font->ascii2glyph[charnr];
1263 if(charnr>=0 && charnr<font->numchars) {
1264 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1272 /* set's the t1 font index of the font to use for swfoutput_drawchar(). */
1273 void swfoutput_setfont(struct swfoutput*obj, char*fontid, char*filename)
1275 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1276 fontlist_t*last=0,*iterator;
1278 msg("<error> No fontid");
1282 if(obj->swffont && obj->swffont->name && !strcmp((char*)obj->swffont->name,fontid))
1285 /* TODO: remove the need for this (enhance getcharacterbbox so that it can cope
1286 with multiple fonts */
1289 iterator = i->fontlist;
1291 if(!strcmp((char*)iterator->swffont->name,fontid)) {
1292 obj->swffont = iterator->swffont;
1296 iterator = iterator->next;
1300 msg("<error> No filename given for font- internal error?");
1304 swf_SetLoadFontParameters(64,/*skip unused*/0,/*full unicode*/1);
1305 SWFFONT*swffont = swf_LoadFont(filename);
1308 msg("<warning> Couldn't load font %s (%s)", fontid, filename);
1309 swffont = swf_LoadFont(0);
1312 swf_FontSetID(swffont, ++i->currentswfid);
1314 if(screenloglevel >= LOGLEVEL_DEBUG) {
1315 // print font information
1316 msg("<debug> Font %s (%s)",swffont->name, filename);
1317 msg("<debug> | ID: %d", swffont->id);
1318 msg("<debug> | Version: %d", swffont->version);
1319 msg("<debug> | Name: %s", fontid);
1320 msg("<debug> | Numchars: %d", swffont->numchars);
1321 msg("<debug> | Maxascii: %d", swffont->maxascii);
1322 msg("<debug> | Style: %d", swffont->style);
1323 msg("<debug> | Encoding: %d", swffont->encoding);
1324 for(int iii=0; iii<swffont->numchars;iii++) {
1325 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,
1326 swffont->layout->bounds[iii].xmin/20.0,
1327 swffont->layout->bounds[iii].ymin/20.0,
1328 swffont->layout->bounds[iii].xmax/20.0,
1329 swffont->layout->bounds[iii].ymax/20.0
1332 for(t=0;t<swffont->maxascii;t++) {
1333 if(swffont->ascii2glyph[t] == iii)
1334 msg("<debug> | - maps to %d",t);
1339 /* set the font name to the ID we use here */
1340 if(swffont->name) free(swffont->name);
1341 swffont->name = (U8*)strdup(fontid);
1343 iterator = new fontlist_t;
1344 iterator->swffont = swffont;
1348 last->next = iterator;
1350 i->fontlist = iterator;
1352 obj->swffont = swffont;
1355 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1357 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1358 fontlist_t *iterator = i->fontlist;
1360 if(!strcmp((char*)iterator->swffont->name,fontid))
1362 iterator = iterator->next;
1367 /* set's the matrix which is to be applied to characters drawn by
1368 swfoutput_drawchar() */
1369 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1370 double m21,double m22)
1372 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1373 if(obj->fontm11 == m11 &&
1374 obj->fontm12 == m12 &&
1375 obj->fontm21 == m21 &&
1376 obj->fontm22 == m22)
1386 m.sx = (U32)(((obj->fontm11)*65536)/FONT_INTERNAL_SIZE); m.r1 = (U32)(((obj->fontm12)*65536)/FONT_INTERNAL_SIZE);
1387 m.r0 = (U32)(((obj->fontm21)*65536)/FONT_INTERNAL_SIZE); m.sy = (U32)(((obj->fontm22)*65536)/FONT_INTERNAL_SIZE);
1390 obj->fontmatrix = m;
1393 /* draws a character at x,y. */
1394 int swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr, int u)
1396 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1398 m.m11 = obj->fontm11;
1399 m.m12 = obj->fontm12;
1400 m.m21 = obj->fontm21;
1401 m.m22 = obj->fontm22;
1404 return drawchar(obj, obj->swffont, character, charnr, u, &m);
1407 static void endpage(struct swfoutput*obj)
1409 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1415 swfoutput_endclip(obj);
1417 if(config.insertstoptag) {
1419 atag = action_Stop(atag);
1420 atag = action_End(atag);
1421 i->tag = swf_InsertTag(i->tag,ST_DOACTION);
1422 swf_ActionSet(i->tag,atag);
1424 i->tag = swf_InsertTag(i->tag,ST_SHOWFRAME);
1427 void swfoutput_newpage(struct swfoutput*obj, int pageNum, int x1, int y1, int x2, int y2)
1429 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1433 for(i->depth--;i->depth>=i->startdepth;i->depth--) {
1434 i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2);
1435 swf_SetU16(i->tag,i->depth);
1437 i->depth = i->startdepth = 3; /* leave room for clip and background rectangle */
1441 x1*=20;y1*=20;x2*=20;y2*=20;
1443 if(i->lastpagesize.xmin != x1 ||
1444 i->lastpagesize.xmax != x2 ||
1445 i->lastpagesize.ymin != y1 ||
1446 i->lastpagesize.ymax != y2)
1447 {/* add white clipping rectangle */
1448 msg("<notice> processing page %d (%dx%d)", pageNum,i->sizex,i->sizey);
1451 msg("<notice> Page has a different size than previous ones");
1452 i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2);
1453 swf_SetU16(i->tag,1);
1454 i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2);
1455 swf_SetU16(i->tag,2);
1459 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1463 int shapeid = ++i->currentswfid;
1468 i->tag = swf_InsertTag(i->tag, ST_DEFINESHAPE);
1470 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1471 swf_SetU16(i->tag,shapeid);
1472 swf_SetRect(i->tag,&r);
1473 swf_SetShapeHeader(i->tag,s);
1474 swf_ShapeSetAll(i->tag,s,x1,y1,ls1,fs1,0);
1475 swf_ShapeSetLine(i->tag,s,(x2-x1),0);
1476 swf_ShapeSetLine(i->tag,s,0,(y2-y1));
1477 swf_ShapeSetLine(i->tag,s,(x1-x2),0);
1478 swf_ShapeSetLine(i->tag,s,0,(y1-y2));
1479 swf_ShapeSetEnd(i->tag);
1481 i->tag = swf_InsertTag(i->tag, ST_PLACEOBJECT2);
1482 swf_ObjectPlace(i->tag,shapeid,/*depth*/1,0,0,0);
1483 i->tag = swf_InsertTag(i->tag, ST_PLACEOBJECT2);
1484 swf_ObjectPlaceClip(i->tag,shapeid,/*depth*/2,0,0,0,65535);
1486 msg("<notice> processing page %d", pageNum);
1489 i->lastpagesize.xmin = x1;
1490 i->lastpagesize.xmax = x2;
1491 i->lastpagesize.ymin = y1;
1492 i->lastpagesize.ymax = y2;
1493 swf_ExpandRect2(&i->swf.movieSize, &i->lastpagesize);
1498 /* initialize the swf writer */
1499 void swfoutput_init(struct swfoutput* obj)
1501 memset(obj, 0, sizeof(struct swfoutput));
1502 obj->internal = init_internal_struct();
1504 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1509 msg("<verbose> initializing swf output for size %d*%d\n", i->sizex,i->sizey);
1514 memset(&i->swf,0x00,sizeof(SWF));
1515 memset(&i->lastpagesize,0x00,sizeof(SRECT));
1517 i->swf.fileVersion = config.flashversion;
1518 i->swf.frameRate = 0x0040; // 1 frame per 4 seconds
1519 i->swf.movieSize.xmin = 0;
1520 i->swf.movieSize.ymin = 0;
1521 i->swf.movieSize.xmax = 0;
1522 i->swf.movieSize.ymax = 0;
1524 i->swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1525 i->tag = i->swf.firstTag;
1526 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1527 swf_SetRGB(i->tag,&rgb);
1529 i->startdepth = i->depth = 0;
1532 void swfoutput_setprotected(struct swfoutput*obj) //write PROTECT tag
1534 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1535 if(!i->flag_protected)
1536 i->tag = swf_InsertTag(i->tag, ST_PROTECT);
1537 i->flag_protected = 1;
1540 static void startshape(struct swfoutput*obj)
1542 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1549 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE);
1551 swf_ShapeNew(&i->shape);
1552 i->linestyleid = swf_ShapeAddLineStyle(i->shape,i->linewidth,&obj->strokergb);
1553 rgb.r = obj->fillrgb.r;
1554 rgb.g = obj->fillrgb.g;
1555 rgb.b = obj->fillrgb.b;
1556 i->fillstyleid = swf_ShapeAddSolidFillStyle(i->shape,&obj->fillrgb);
1558 i->shapeid = ++i->currentswfid;
1559 swf_SetU16(i->tag,i->shapeid); // ID
1561 i->bboxrectpos = i->tag->len;
1564 r.xmax = 20*i->sizex;
1565 r.ymax = 20*i->sizey;
1566 swf_SetRect(i->tag,&r);
1568 memset(&i->bboxrect, 0, sizeof(i->bboxrect));
1570 swf_SetShapeStyles(i->tag,i->shape);
1571 swf_ShapeCountBits(i->shape,NULL,NULL);
1572 swf_SetShapeBits(i->tag,i->shape);
1574 /* TODO: do we really need this? */
1575 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,i->linestyleid,0,0);
1576 i->swflastx=i->swflasty=0;
1578 i->shapeisempty = 1;
1581 static void starttext(struct swfoutput*obj)
1583 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1587 i->textid = ++i->currentswfid;
1589 i->swflastx=i->swflasty=0;
1593 /* TODO: move to ../lib/rfxswf */
1594 void changeRect(struct swfoutput*obj, TAG*tag, int pos, SRECT*newrect)
1596 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1597 /* determine length of old rect */
1601 swf_GetRect(tag, &old);
1602 swf_ResetReadBits(tag);
1603 int pos_end = tag->pos;
1605 int len = tag->len - pos_end;
1606 U8*data = (U8*)malloc(len);
1607 memcpy(data, &tag->data[pos_end], len);
1610 swf_SetRect(tag, newrect);
1611 swf_SetBlock(tag, data, len);
1613 tag->pos = tag->readBit = 0;
1616 void cancelshape(swfoutput*obj)
1618 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1619 /* delete old shape tag */
1621 i->tag = i->tag->prev;
1622 swf_DeleteTag(todel);
1624 i->bboxrectpos = -1;
1627 void fixAreas(swfoutput*obj)
1629 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1630 if(!i->shapeisempty && i->fill &&
1631 (i->bboxrect.xmin == i->bboxrect.xmax ||
1632 i->bboxrect.ymin == i->bboxrect.ymax) &&
1633 config.minlinewidth >= 0.001
1635 msg("<debug> Shape has size 0: width=%.2f height=%.2f",
1636 (i->bboxrect.xmax-i->bboxrect.xmin)/20.0,
1637 (i->bboxrect.ymax-i->bboxrect.ymin)/20.0
1640 SRECT r = i->bboxrect;
1642 if(r.xmin == r.xmax && r.ymin == r.ymax) {
1643 /* this thing comes down to a single dot- nothing to fix here */
1649 RGBA save_col = obj->strokergb;
1650 int save_width = i->linewidth;
1652 obj->strokergb = obj->fillrgb;
1653 i->linewidth = (int)(config.minlinewidth*20);
1654 if(i->linewidth==0) i->linewidth = 1;
1658 moveto(obj, i->tag, r.xmin/20.0,r.ymin/20.0);
1659 lineto(obj, i->tag, r.xmax/20.0,r.ymax/20.0);
1661 obj->strokergb = save_col;
1662 i->linewidth = save_width;
1667 static void endshape(swfoutput*obj, int clipdepth)
1669 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1676 if(i->shapeisempty ||
1677 (i->bboxrect.xmin == i->bboxrect.xmax &&
1678 i->bboxrect.ymin == i->bboxrect.ymax))
1680 // delete the shape again, we didn't do anything
1685 swf_ShapeSetEnd(i->tag);
1687 changeRect(obj, i->tag, i->bboxrectpos, &i->bboxrect);
1689 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
1691 swf_ObjectPlaceClip(i->tag,i->shapeid,i->depth++,NULL,NULL,NULL,clipdepth);
1693 swf_ObjectPlace(i->tag,i->shapeid,/*depth*/i->depth++,NULL,NULL,NULL);
1696 i->bboxrectpos = -1;
1699 void swfoutput_save(struct swfoutput* obj, char*filename)
1701 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1703 fontlist_t *tmp,*iterator = i->fontlist;
1705 TAG*mtag = i->swf.firstTag;
1706 if(iterator->swffont) {
1707 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1708 /*if(!storeallcharacters)
1709 swf_FontReduce(iterator->swffont);*/
1710 swf_FontSetDefine2(mtag, iterator->swffont);
1713 iterator = iterator->next;
1718 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1723 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1727 i->tag = swf_InsertTag(i->tag,ST_END);
1729 if(config.enablezlib || config.flashversion>=6) {
1730 if FAILED(swf_WriteSWC(fi,&i->swf))
1731 msg("<error> WriteSWC() failed.\n");
1733 if FAILED(swf_WriteSWF(fi,&i->swf))
1734 msg("<error> WriteSWF() failed.\n");
1739 msg("<notice> SWF written\n");
1742 /* Perform cleaning up, complete the swf, and write it out. */
1743 void swfoutput_destroy(struct swfoutput* obj)
1745 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1747 fontlist_t *tmp,*iterator = i->fontlist;
1749 if(iterator->swffont) {
1750 swf_FontFree(iterator->swffont);
1753 iterator = iterator->next;
1757 memset(obj, 0, sizeof(swfoutput));
1760 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1762 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1763 obj->drawmode = mode;
1764 if(mode == DRAWMODE_FILL)
1766 else if(mode == DRAWMODE_EOFILL)
1768 else if(mode == DRAWMODE_STROKE)
1770 else if(mode == DRAWMODE_CLIP)
1772 else if(mode == DRAWMODE_EOCLIP)
1776 void swfoutput_setfillcolor(swfoutput* obj, U8 r, U8 g, U8 b, U8 a)
1778 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1779 if(obj->fillrgb.r == r &&
1780 obj->fillrgb.g == g &&
1781 obj->fillrgb.b == b &&
1782 obj->fillrgb.a == a) return;
1792 void swfoutput_setstrokecolor(swfoutput* obj, U8 r, U8 g, U8 b, U8 a)
1794 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1795 if(obj->strokergb.r == r &&
1796 obj->strokergb.g == g &&
1797 obj->strokergb.b == b &&
1798 obj->strokergb.a == a) return;
1802 obj->strokergb.r = r;
1803 obj->strokergb.g = g;
1804 obj->strokergb.b = b;
1805 obj->strokergb.a = a;
1808 void swfoutput_setlinewidth(struct swfoutput*obj, double _linewidth)
1810 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1811 if(i->linewidth == (U16)(_linewidth*20))
1816 i->linewidth = (U16)(_linewidth*20);
1820 void swfoutput_startclip(swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m)
1822 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1828 if(i->clippos >= 127)
1830 msg("<warning> Too many clip levels.");
1835 int olddrawmode = obj->drawmode;
1836 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1837 swfoutput_drawpath(obj, outline, m);
1838 swf_ShapeSetEnd(i->tag);
1839 swfoutput_setdrawmode(obj, olddrawmode);
1841 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
1842 i->cliptags[i->clippos] = i->tag;
1843 i->clipshapes[i->clippos] = i->shapeid;
1844 i->clipdepths[i->clippos] = i->depth++;
1849 void swfoutput_endclip(swfoutput*obj)
1851 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1858 msg("<error> Invalid end of clipping region");
1862 swf_ObjectPlaceClip(i->cliptags[i->clippos],i->clipshapes[i->clippos],i->clipdepths[i->clippos],NULL,NULL,NULL,i->depth++);
1865 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1867 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1869 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1871 if(!strncmp("http://pdf2swf:", url, 15)) {
1872 char*tmp = strdup(url);
1873 int l = strlen(tmp);
1876 swfoutput_namedlink(obj, tmp+15, points);
1886 if(config.opennewwindow)
1887 actions = action_GetUrl(0, url, "_parent");
1889 actions = action_GetUrl(0, url, "_this");
1890 actions = action_End(actions);
1892 drawlink(obj, actions, 0, points,0);
1894 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1896 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1904 actions = action_GotoFrame(0, page);
1905 actions = action_End(actions);
1907 drawlink(obj, actions, 0, points,0);
1910 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
1911 of the viewer objects, like subtitles, index elements etc.
1913 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
1915 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1916 ActionTAG *actions1,*actions2;
1917 char*tmp = strdup(name);
1925 if(!strncmp(tmp, "call:", 5))
1927 char*x = strchr(&tmp[5], ':');
1929 actions1 = action_PushInt(0, 0); //number of parameters (0)
1930 actions1 = action_PushString(actions1, &tmp[5]); //function name
1931 actions1 = action_CallFunction(actions1);
1934 actions1 = action_PushString(0, x+1); //parameter
1935 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
1936 actions1 = action_PushString(actions1, &tmp[5]); //function name
1937 actions1 = action_CallFunction(actions1);
1939 actions2 = action_End(0);
1944 actions1 = action_PushString(0, "/:subtitle");
1945 actions1 = action_PushString(actions1, name);
1946 actions1 = action_SetVariable(actions1);
1947 actions1 = action_End(actions1);
1949 actions2 = action_PushString(0, "/:subtitle");
1950 actions2 = action_PushString(actions2, "");
1951 actions2 = action_SetVariable(actions2);
1952 actions2 = action_End(actions2);
1955 drawlink(obj, actions1, actions2, points,mouseover);
1957 swf_ActionFree(actions1);
1958 swf_ActionFree(actions2);
1962 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
1964 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1969 struct plotxy p1,p2,p3,p4;
1973 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
1977 int buttonid = ++i->currentswfid;
1980 if(points[t].x>xmax) xmax=points[t].x;
1981 if(points[t].y>ymax) ymax=points[t].y;
1982 if(points[t].x<xmin) xmin=points[t].x;
1983 if(points[t].y<ymin) ymin=points[t].y;
1986 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
1987 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
1989 /* the following code subtracts the upper left edge from all coordinates,
1990 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
1991 Necessary for preprocessing with swfcombine. */
1992 posx = xmin; posy = ymin;
1993 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
1994 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
1995 xmin -= posx; ymin -= posy;
1996 xmax -= posx; ymax -= posy;
1999 myshapeid = ++i->currentswfid;
2000 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE3);
2001 swf_ShapeNew(&i->shape);
2002 rgb.r = rgb.b = rgb.a = rgb.g = 0;
2003 fsid = swf_ShapeAddSolidFillStyle(i->shape,&rgb);
2004 swf_SetU16(i->tag, myshapeid);
2005 r.xmin = (int)(xmin*20);
2006 r.ymin = (int)(ymin*20);
2007 r.xmax = (int)(xmax*20);
2008 r.ymax = (int)(ymax*20);
2009 swf_SetRect(i->tag,&r);
2010 swf_SetShapeStyles(i->tag,i->shape);
2011 swf_ShapeCountBits(i->shape,NULL,NULL);
2012 swf_SetShapeBits(i->tag,i->shape);
2013 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,0,fsid,0);
2014 i->swflastx = i->swflasty = 0;
2015 moveto(obj, i->tag, p1);
2016 lineto(obj, i->tag, p2);
2017 lineto(obj, i->tag, p3);
2018 lineto(obj, i->tag, p4);
2019 lineto(obj, i->tag, p1);
2020 swf_ShapeSetEnd(i->tag);
2023 myshapeid2 = ++i->currentswfid;
2024 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE3);
2025 swf_ShapeNew(&i->shape);
2026 rgb.r = rgb.b = rgb.a = rgb.g = 255;
2028 fsid = swf_ShapeAddSolidFillStyle(i->shape,&rgb);
2029 swf_SetU16(i->tag, myshapeid2);
2030 r.xmin = (int)(xmin*20);
2031 r.ymin = (int)(ymin*20);
2032 r.xmax = (int)(xmax*20);
2033 r.ymax = (int)(ymax*20);
2034 swf_SetRect(i->tag,&r);
2035 swf_SetShapeStyles(i->tag,i->shape);
2036 swf_ShapeCountBits(i->shape,NULL,NULL);
2037 swf_SetShapeBits(i->tag,i->shape);
2038 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,0,fsid,0);
2039 i->swflastx = i->swflasty = 0;
2040 moveto(obj, i->tag, p1);
2041 lineto(obj, i->tag, p2);
2042 lineto(obj, i->tag, p3);
2043 lineto(obj, i->tag, p4);
2044 lineto(obj, i->tag, p1);
2045 swf_ShapeSetEnd(i->tag);
2049 i->tag = swf_InsertTag(i->tag,ST_DEFINEBUTTON);
2050 swf_SetU16(i->tag,buttonid); //id
2051 swf_ButtonSetFlags(i->tag, 0); //menu=no
2052 swf_ButtonSetRecord(i->tag,0x01,myshapeid,i->depth,0,0);
2053 swf_ButtonSetRecord(i->tag,0x02,myshapeid2,i->depth,0,0);
2054 swf_ButtonSetRecord(i->tag,0x04,myshapeid2,i->depth,0,0);
2055 swf_ButtonSetRecord(i->tag,0x08,myshapeid,i->depth,0,0);
2056 swf_SetU8(i->tag,0);
2057 swf_ActionSet(i->tag,actions1);
2058 swf_SetU8(i->tag,0);
2062 i->tag = swf_InsertTag(i->tag,ST_DEFINEBUTTON2);
2063 swf_SetU16(i->tag,buttonid); //id
2064 swf_ButtonSetFlags(i->tag, 0); //menu=no
2065 swf_ButtonSetRecord(i->tag,0x01,myshapeid,i->depth,0,0);
2066 swf_ButtonSetRecord(i->tag,0x02,myshapeid2,i->depth,0,0);
2067 swf_ButtonSetRecord(i->tag,0x04,myshapeid2,i->depth,0,0);
2068 swf_ButtonSetRecord(i->tag,0x08,myshapeid,i->depth,0,0);
2069 swf_SetU8(i->tag,0); // end of button records
2070 swf_ButtonSetCondition(i->tag, BC_IDLE_OVERUP);
2071 swf_ActionSet(i->tag,actions1);
2073 swf_ButtonSetCondition(i->tag, BC_OVERUP_IDLE);
2074 swf_ActionSet(i->tag,actions2);
2075 swf_SetU8(i->tag,0);
2076 swf_ButtonPostProcess(i->tag, 2);
2078 swf_SetU8(i->tag,0);
2079 swf_ButtonPostProcess(i->tag, 1);
2083 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
2085 if(posx!=0 || posy!=0) {
2087 swf_GetMatrix(0,&m);
2088 m.tx = (int)(posx*20);
2089 m.ty = (int)(posy*20);
2090 swf_ObjectPlace(i->tag, buttonid, i->depth++,&m,0,0);
2093 swf_ObjectPlace(i->tag, buttonid, i->depth++,0,0,0);
2097 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
2098 double x1,double y1,
2099 double x2,double y2,
2100 double x3,double y3,
2101 double x4,double y4)
2103 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2108 struct plotxy p1,p2,p3,p4;
2110 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
2111 if(x2>xmax) xmax=x2;
2112 if(y2>ymax) ymax=y2;
2113 if(x2<xmin) xmin=x2;
2114 if(y2<ymin) ymin=y2;
2115 if(x3>xmax) xmax=x3;
2116 if(y3>ymax) ymax=y3;
2117 if(x3<xmin) xmin=x3;
2118 if(y3<ymin) ymin=y3;
2119 if(x4>xmax) xmax=x4;
2120 if(y4>ymax) ymax=y4;
2121 if(x4<xmin) xmin=x4;
2122 if(y4<ymin) ymin=y4;
2128 {p1.x = (int)(p1.x*20)/20.0;
2129 p1.y = (int)(p1.y*20)/20.0;
2130 p2.x = (int)(p2.x*20)/20.0;
2131 p2.y = (int)(p2.y*20)/20.0;
2132 p3.x = (int)(p3.x*20)/20.0;
2133 p3.y = (int)(p3.y*20)/20.0;
2134 p4.x = (int)(p4.x*20)/20.0;
2135 p4.y = (int)(p4.y*20)/20.0;}
2138 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
2139 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
2140 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
2141 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
2143 m.tx = (int)(p1.x*20);
2144 m.ty = (int)(p1.y*20);
2147 myshapeid = ++i->currentswfid;
2148 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE);
2149 swf_ShapeNew(&i->shape);
2150 //lsid = ShapeAddLineStyle(shape,linewidth,&obj->strokergb);
2151 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
2152 fsid = swf_ShapeAddBitmapFillStyle(i->shape,&m,bitid,1);
2153 swf_SetU16(i->tag, myshapeid);
2154 r.xmin = (int)(xmin*20);
2155 r.ymin = (int)(ymin*20);
2156 r.xmax = (int)(xmax*20);
2157 r.ymax = (int)(ymax*20);
2158 swf_SetRect(i->tag,&r);
2159 swf_SetShapeStyles(i->tag,i->shape);
2160 swf_ShapeCountBits(i->shape,NULL,NULL);
2161 swf_SetShapeBits(i->tag,i->shape);
2162 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,lsid,fsid,0);
2163 i->swflastx = i->swflasty = 0;
2164 moveto(obj, i->tag, p1);
2165 lineto(obj, i->tag, p2);
2166 lineto(obj, i->tag, p3);
2167 lineto(obj, i->tag, p4);
2168 lineto(obj, i->tag, p1);
2170 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
2171 ShapeSetLine (tag, shape, (int)(x1*20);
2172 ShapeSetLine (tag, shape, x*20,0);
2173 ShapeSetLine (tag, shape, 0,-y*20);
2174 ShapeSetLine (tag, shape, -x*20,0);*/
2175 swf_ShapeSetEnd(i->tag);
2178 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
2179 swf_ObjectPlace(i->tag,myshapeid,/*depth*/i->depth++,NULL,NULL,NULL);
2182 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
2183 double x1,double y1,
2184 double x2,double y2,
2185 double x3,double y3,
2186 double x4,double y4)
2188 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2195 int bitid = ++i->currentswfid;
2197 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSJPEG2);
2198 swf_SetU16(i->tag, bitid);
2199 if(swf_SetJPEGBits(i->tag, filename, config.jpegquality)<0) {
2200 swf_DeleteTag(i->tag);
2205 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2209 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2210 double x1,double y1,
2211 double x2,double y2,
2212 double x3,double y3,
2213 double x4,double y4)
2215 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2224 int bitid = ++i->currentswfid;
2226 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSJPEG2);
2227 swf_SetU16(i->tag, bitid);
2228 swf_SetJPEGBits2(i->tag,sizex,sizey,mem,config.jpegquality);
2229 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2233 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2234 double x1,double y1,
2235 double x2,double y2,
2236 double x3,double y3,
2237 double x4,double y4)
2239 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2246 int bitid = ++i->currentswfid;
2248 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSLOSSLESS);
2249 swf_SetU16(i->tag, bitid);
2250 if(swf_SetLosslessBits(i->tag,sizex,sizey,mem, BMF_32BIT)<0) {
2251 swf_DeleteTag(i->tag);
2256 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2260 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
2261 double x1,double y1,
2262 double x2,double y2,
2263 double x3,double y3,
2264 double x4,double y4, int n)
2266 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2276 /* SWF expects scanlines to be 4 byte aligned */
2279 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
2281 for(y=0;y<sizey;y++)
2283 for(x=0;x<sizex;x++)
2284 *ptr++ = mem[y*sizex+x];
2285 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
2290 int bitid = ++i->currentswfid;
2292 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSLOSSLESS2);
2293 swf_SetU16(i->tag, bitid);
2294 if(swf_SetLosslessBitsIndexed(i->tag,sizex,sizey,mem, pal, n)<0) {
2295 swf_DeleteTag(i->tag);
2302 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2306 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
2307 double x1,double y1,
2308 double x2,double y2,
2309 double x3,double y3,
2310 double x4,double y4)
2312 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2319 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2322 void swfoutput_setparameter(char*name, char*value)
2324 if(!strcmp(name, "drawonlyshapes")) {
2325 config.drawonlyshapes = atoi(value);
2326 } else if(!strcmp(name, "ignoredraworder")) {
2327 config.ignoredraworder = atoi(value);
2328 } else if(!strcmp(name, "filloverlap")) {
2329 config.filloverlap = atoi(value);
2330 } else if(!strcmp(name, "linksopennewwindow")) {
2331 config.opennewwindow = atoi(value);
2332 } else if(!strcmp(name, "opennewwindow")) {
2333 config.opennewwindow = atoi(value);
2334 } else if(!strcmp(name, "storeallcharacters")) {
2335 config.storeallcharacters = atoi(value);
2336 } else if(!strcmp(name, "enablezlib")) {
2337 config.enablezlib = atoi(value);
2338 } else if(!strcmp(name, "insertstop")) {
2339 config.insertstoptag = atoi(value);
2340 } else if(!strcmp(name, "protected")) {
2341 config.protect = atoi(value);
2342 } else if(!strcmp(name, "flashversion")) {
2343 config.flashversion = atoi(value);
2344 } else if(!strcmp(name, "minlinewidth")) {
2345 config.minlinewidth = atof(value);
2346 } else if(!strcmp(name, "jpegquality")) {
2347 int val = atoi(value);
2349 if(val>100) val=100;
2350 config.jpegquality = val;
2351 } else if(!strcmp(name, "splinequality")) {
2352 int v = atoi(value);
2353 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2355 config.splinemaxerror = v;
2356 } else if(!strcmp(name, "fontquality")) {
2357 int v = atoi(value);
2358 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2360 config.fontsplinemaxerror = v;
2362 fprintf(stderr, "unknown parameter: %s (=%s)\n", name, value);