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
111 char fillstylechanged;
116 chardata_t chardata[CHARDATAMAX];
119 } swfoutput_internal;
121 static int global_init;
123 static swfoutput_internal* init_internal_struct()
125 swfoutput_internal*i = (swfoutput_internal*)malloc(sizeof(swfoutput_internal));
126 memset(i, 0, sizeof(swfoutput_internal));
129 config.opennewwindow=0;
130 config.ignoredraworder=0;
131 config.drawonlyshapes=0;
132 config.jpegquality=85;
133 config.storeallcharacters=0;
135 config.insertstoptag=0;
136 config.flashversion=5;
137 config.splinemaxerror=1;
138 config.fontsplinemaxerror=1;
139 config.filloverlap=0;
140 config.minlinewidth=0.05;
144 i->flag_protected = 0;
162 i->fillstylechanged = 0;
171 static void startshape(struct swfoutput* obj);
172 static void starttext(struct swfoutput* obj);
173 static void endshape(struct swfoutput* obj,int clip);
174 static void endtext(struct swfoutput* obj);
176 // matrix multiplication. changes p0
177 static void transform (plotxy*p0,struct swfmatrix*m)
180 x = m->m11*p0->x+m->m12*p0->y;
181 y = m->m21*p0->x+m->m22*p0->y;
186 // write a move-to command into the swf
187 static int moveto(struct swfoutput*obj, TAG*tag, plotxy p0)
189 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
190 int rx = (int)(p0.x*20);
191 int ry = (int)(p0.y*20);
192 if(rx!=i->swflastx || ry!=i->swflasty || i->fillstylechanged) {
193 swf_ShapeSetMove (tag, i->shape, rx,ry);
194 i->fillstylechanged = 0;
201 static int moveto(struct swfoutput*obj, TAG*tag, float x, float y)
203 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
207 return moveto(obj, tag, p);
209 static void addPointToBBox(struct swfoutput*obj, int px, int py)
211 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
217 swf_ExpandRect(&i->bboxrect, p);
219 swf_ExpandRect3(&i->bboxrect, p, i->linewidth*3/2);
223 // write a line-to command into the swf
224 static void lineto(struct swfoutput*obj, TAG*tag, plotxy p0)
226 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
227 int px = (int)(p0.x*20);
228 int py = (int)(p0.y*20);
229 int rx = (px-i->swflastx);
230 int ry = (py-i->swflasty);
231 /* we can't skip this for rx=0,ry=0, those
233 swf_ShapeSetLine (tag, i->shape, rx,ry);
235 addPointToBBox(obj, i->swflastx,i->swflasty);
236 addPointToBBox(obj, px,py);
242 static void lineto(struct swfoutput*obj, TAG*tag, double x, double y)
250 // write a spline-to command into the swf
251 static void splineto(struct swfoutput*obj, TAG*tag, plotxy control,plotxy end)
253 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
254 int lastlastx = i->swflastx;
255 int lastlasty = i->swflasty;
257 int cx = ((int)(control.x*20)-i->swflastx);
258 int cy = ((int)(control.y*20)-i->swflasty);
261 int ex = ((int)(end.x*20)-i->swflastx);
262 int ey = ((int)(end.y*20)-i->swflasty);
266 if(cx || cy || ex || ey) {
267 swf_ShapeSetCurve(tag, i->shape, cx,cy,ex,ey);
268 addPointToBBox(obj, lastlastx ,lastlasty );
269 addPointToBBox(obj, lastlastx+cx,lastlasty+cy);
270 addPointToBBox(obj, lastlastx+cx+ex,lastlasty+cy+ey);
275 /* write a line, given two points and the transformation
277 static void line(struct swfoutput*obj, TAG*tag, plotxy p0, plotxy p1, struct swfmatrix*m)
281 moveto(obj, tag, p0);
282 lineto(obj, tag, p1);
285 /* write a cubic (!) spline. This involves calling the approximate()
286 function out of spline.cc to convert it to a quadratic spline. */
287 static void spline(struct swfoutput*obj, TAG*tag,plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m)
289 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
291 struct qspline q[128];
305 /* fonts use a different approximation than shapes */
306 num = cspline_approximate(&c, q, config.fontsplinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
307 //num = cspline_approximate(&c, q, 10.0, APPROXIMATE_INFLECTION);
309 num = cspline_approximate(&c, q, config.splinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
313 moveto(obj, tag,q[t].start);
314 splineto(obj, tag,q[t].control, q[t].end);
318 void resetdrawer(struct swfoutput*obj)
320 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
325 static void stopFill(struct swfoutput*obj)
327 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
330 swf_ShapeSetStyle(i->tag,i->shape,i->linestyleid,0x8000,0);
331 i->fillstylechanged = 1;
335 static void startFill(struct swfoutput*obj)
337 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
340 swf_ShapeSetStyle(i->tag,i->shape,0x8000,i->fillstyleid,0);
341 i->fillstylechanged = 1;
346 /* draw an outline. These are generated by pdf2swf and by t1lib
347 (representing characters). */
348 void drawpath(struct swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m, int log)
350 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
351 if( i->tag->id != ST_DEFINESHAPE &&
352 i->tag->id != ST_DEFINESHAPE2 &&
353 i->tag->id != ST_DEFINESHAPE3)
355 msg("<error> internal error: drawpath needs a shape tag, not %d\n",i->tag->id);
359 double lastx=0,lasty=0;
360 double firstx=0,firsty=0;
365 x += (outline->dest.x/(float)0xffff);
366 y += (outline->dest.y/(float)0xffff);
367 if(outline->type == SWF_PATHTYPE_MOVE)
369 //if(!init && fill && obj->drawmode != DRAWMODE_EOFILL && !ignoredraworder) {
370 if(config.filloverlap && !init && i->fill && obj->drawmode != DRAWMODE_EOFILL) {
371 /* drawmode=FILL (not EOFILL) means that
372 seperate shapes do not cancel each other out.
373 On SWF side, we need to start a new shape for each
374 closed polygon, because SWF only knows EOFILL.
381 if(((int)(lastx*20) != (int)(firstx*20) ||
382 (int)(lasty*20) != (int)(firsty*20)) &&
391 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
392 line(obj,i->tag, p0, p1, m);
398 else if(outline->type == SWF_PATHTYPE_LINE)
406 if(log) printf("line: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
407 line(obj,i->tag, p0,p1,m);
409 else if(outline->type == SWF_PATHTYPE_BEZIER)
415 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
418 p1.x=o2->C.x/(float)0xffff+lastx;
419 p1.y=o2->C.y/(float)0xffff+lasty;
420 p2.x=o2->B.x/(float)0xffff+lastx;
421 p2.y=o2->B.y/(float)0xffff+lasty;
424 if(log) printf("spline: %f,%f -> %f,%f\n",p3.x,p3.y,p0.x,p0.y);
425 spline(obj,i->tag,p0,p1,p2,p3,m);
428 msg("<error> drawpath: unknown outline type:%d\n", outline->type);
432 outline = outline->link;
434 if(((int)(lastx*20) != (int)(firstx*20) ||
435 (int)(lasty*20) != (int)(firsty*20)) &&
444 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
445 line(obj, i->tag, p0, p1, m);
449 plotxy getPivot(struct swfoutput*obj, SWF_OUTLINE*outline, int dir, double line_width, int end, int trytwo)
451 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
452 SWF_PATHPOINT next, next2;
453 double xv=0,yv=0, xv2=0, yv2=0;
458 if(outline->type == SWF_PATHTYPE_LINE) {
459 next = outline->dest;
461 next = ((SWF_BEZIERSEGMENT*)outline)->B;
462 if(next.x==0 && next.y==0) {
463 next = ((SWF_BEZIERSEGMENT*)outline)->C;
465 if(next.x==0 && next.y==0) {
466 next = ((SWF_BEZIERSEGMENT*)outline)->dest;
470 if(trytwo && outline->last && outline->last->type != SWF_PATHTYPE_MOVE) {
471 if(outline->type == SWF_PATHTYPE_LINE) {
472 next2 = outline->last->dest;
474 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)(outline->last))->C;
475 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)(outline->last))->B;
476 next2.x = outline->last->dest.x - c.x;
477 next2.y = outline->last->dest.y - c.y;
478 if(next2.x==0 && next2.y==0) {
479 next2.x = outline->last->dest.x - b.x;
480 next2.y = outline->last->dest.y - b.y;
482 if(next2.x==0 && next2.y==0) {
483 next2.x = outline->last->dest.x;
484 next2.y = outline->last->dest.y;
490 if(outline->type == SWF_PATHTYPE_LINE) {
491 next = outline->dest;
493 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)outline)->C;
494 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)outline)->B;
495 next.x = outline->dest.x - c.x;
496 next.y = outline->dest.y - c.y;
497 if(next.x==0 && next.y==0) {
498 next.x = outline->dest.x - b.x;
499 next.y = outline->dest.y - b.y;
501 if(next.x==0 && next.y==0) {
502 next.x = outline->dest.x;
503 next.y = outline->dest.y;
507 if(trytwo && outline->link && outline->link->type != SWF_PATHTYPE_MOVE) {
508 if(outline->type == SWF_PATHTYPE_LINE) {
509 next2 = outline->link->dest;
511 next2 = ((SWF_BEZIERSEGMENT*)(outline->link))->B;
512 if(next2.x==0 && next2.y==0) {
513 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->C;
515 if(next2.x==0 && next2.y==0) {
516 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->dest;
524 xv = next.y/(float)0xffff;
525 yv = -next.x/(float)0xffff;
527 xv = -next.y/(float)0xffff;
528 yv = next.x/(float)0xffff;
531 double r = (line_width/2)/sqrt(xv*xv+yv*yv);
537 xv2 = next2.y/(float)0xffff;
538 yv2 = -next2.x/(float)0xffff;
540 xv2 = -next2.y/(float)0xffff;
541 yv2 = next2.x/(float)0xffff;
544 double r2 = (line_width/2)/sqrt(xv2*xv2+yv2*yv2);
549 double r3 = (line_width/2)/sqrt(xv*xv+yv*yv);
559 void drawShortPath(struct swfoutput*obj, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline)
561 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
562 double lastx=x, lasty=y;
563 while (outline && outline->type != SWF_PATHTYPE_MOVE)
565 x += (outline->dest.x/(float)0xffff);
566 y += (outline->dest.y/(float)0xffff);
568 if(outline->type == SWF_PATHTYPE_LINE)
575 line(obj, i->tag, p0, p1, m);
577 else if(outline->type == SWF_PATHTYPE_BEZIER)
580 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
583 p1.x=o2->C.x/(float)0xffff+lastx;
584 p1.y=o2->C.y/(float)0xffff+lasty;
585 p2.x=o2->B.x/(float)0xffff+lastx;
586 p2.y=o2->B.y/(float)0xffff+lasty;
589 spline(obj, i->tag,p0,p1,p2,p3,m);
593 outline = outline->link;
597 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)
599 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
603 if(line_cap == LINE_CAP_BUTT || line_cap == LINE_CAP_SQUARE) {
606 SWF_OUTLINE *last, *tmp=outline;
607 plotxy s,e,p0,p1,p2,p3,m0,m1,m2,m3;
613 while(tmp && tmp->type != SWF_PATHTYPE_MOVE) {
615 lx += (tmp->dest.x/(float)0xffff);
616 ly += (tmp->dest.y/(float)0xffff);
619 s = getPivot(obj, outline, 0, line_width, 0, 0);
620 e = getPivot(obj, last, 0, line_width, 1, 0);
622 if(line_cap == LINE_CAP_BUTT) {
623 /* make the clipping rectangle slighly bigger
624 than the line ending, so that it get's clipped
634 p2.x = x2 - s.y - s.x*ee;
635 p2.y = y2 + s.x - s.y*ee;
636 p3.x = x2 - s.y + s.x*ee;
637 p3.y = y2 + s.x + s.y*ee;
642 m2.x = lx + e.y - e.x*ee;
643 m2.y = ly - e.x - e.y*ee;
644 m3.x = lx + e.y + e.x*ee;
645 m3.y = ly - e.x + e.y*ee;
647 for(nr=0;nr<2;nr++) {
649 struct plotxy q0,q1,q2,q3,q4,q5;
652 if(line_cap == LINE_CAP_BUTT) {
654 /* FIXME: box should be smaller */
656 q1.x = i->sizex; q1.y = 0;
657 q2.x = i->sizex; q2.y = i->sizey;
658 q3.x = 0; q3.y = i->sizey;
660 /* FIXME: box should be smaller */
661 q0.x = i->sizex; q0.y = i->sizey;
662 q1.x = 0; q1.y = i->sizey;
664 q3.x = i->sizex; q3.y = 0;
668 moveto(obj, i->tag, q0);
669 lineto(obj, i->tag, q1);
670 lineto(obj, i->tag, q2);
671 lineto(obj, i->tag, q3);
672 lineto(obj, i->tag, q0);
675 lineto(obj, i->tag, q4);
678 line(obj, i->tag, p0, p1, m);
679 line(obj, i->tag, p1, p2, m);
680 line(obj, i->tag, p2, p3, m);
681 line(obj, i->tag, p3, p0, m);
683 if(line_cap == LINE_CAP_BUTT) {
684 lineto(obj, i->tag, q0);
685 endshape(obj, i->depth+2-nr);
697 drawShortPath(obj,x,y,m,outline);
699 if(line_cap == LINE_CAP_BUTT) {
705 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)
707 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
708 plotxy d1,d2,p1,p2,p3,p4;
710 d1.x = (outline->dest.x/(float)0xffff);
711 d1.y = (outline->dest.y/(float)0xffff);
712 d2 = getPivot(obj, outline, 0, line_width, 0, 0);
714 assert(line_cap != LINE_CAP_ROUND);
715 if(line_cap == LINE_CAP_SQUARE) {
724 p2.x = x + d2.x + d1.x;
725 p2.y = y + d2.y + d1.y;
726 p3.x = x - d2.x + d1.x;
727 p3.y = y - d2.y + d1.y;
731 line(obj, i->tag, p1,p2, m);
732 line(obj, i->tag, p2,p3, m);
733 line(obj, i->tag, p3,p4, m);
734 line(obj, i->tag, p4,p1, m);
737 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)
739 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
740 SWF_OUTLINE*tmp=outline;
743 assert(i->shapeid>=0);
746 drawT1toRect(obj, x, y, m,outline, num, line_cap, line_join, line_width);
748 while(tmp->link && tmp->link->type!=SWF_PATHTYPE_MOVE) {
749 xx += (tmp->dest.x/(float)0xffff);
750 yy += (tmp->dest.y/(float)0xffff);
754 assert(tmp->type == SWF_PATHTYPE_LINE);
755 assert(outline->type == SWF_PATHTYPE_LINE);
759 if(outline->link == tmp) {
760 /* the two straight line segments (which are everything we
761 need to draw) are very likely to overlap. To avoid that
762 they cancel each other out at the end points, start a new
763 shape for the second one */
764 endshape(obj,0);startshape(obj);
768 drawT1toRect(obj, xx, yy, m, tmp, num, line_cap, line_join, line_width);
770 if(outline->link != tmp)
772 stopFill(obj);stop=1;
774 tmp->type = SWF_PATHTYPE_MOVE;
775 x += (outline->dest.x/(float)0xffff);
776 y += (outline->dest.y/(float)0xffff);
777 outline = outline->link;
778 drawShortPath(obj, x, y, m, outline);
786 static int t1len(struct swfoutput*obj, SWF_OUTLINE*line)
788 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
790 while(line && line->type != SWF_PATHTYPE_MOVE) {
797 static float t1linelen(struct swfoutput*obj, SWF_OUTLINE*line)
799 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
801 x = (line->dest.x/(float)0xffff);
802 y = (line->dest.y/(float)0xffff);
803 return sqrt(x*x+y*y);
806 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)
808 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
809 if( i->tag->id != ST_DEFINESHAPE &&
810 i->tag->id != ST_DEFINESHAPE2 &&
811 i->tag->id != ST_DEFINESHAPE3) {
812 msg("<error> internal error: drawpath needs a shape tag, not %d\n",i->tag->id);
815 assert(i->shapeid>=0);
817 double lastx=0,lasty=0;
820 SWF_OUTLINE*tmp = outline, *last = 0;
825 x += (tmp->dest.x/(float)0xffff);
826 y += (tmp->dest.y/(float)0xffff);
828 if(!tmp || tmp->type == SWF_PATHTYPE_MOVE) {
830 if(last->type == SWF_PATHTYPE_LINE && t1linelen(obj,last)>line_width*2 &&
831 lastwasline && line_cap != LINE_CAP_ROUND)
832 drawShortPathWithStraightEnds(obj, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
834 drawShortPathWithEnds(obj, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
848 if(tmp && tmp->type == SWF_PATHTYPE_LINE && t1linelen(obj,tmp)>line_width*2)
854 tmp->link->last = tmp; // make sure list is properly linked in both directions
859 static inline int colorcompare(struct swfoutput*obj, RGBA*a,RGBA*b)
871 static SRECT getcharacterbbox(struct swfoutput*obj, SWFFONT*font)
873 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
876 memset(&r, 0, sizeof(r));
879 if(debug) printf("\n");
880 for(t=0;t<i->chardatapos;t++)
882 if(i->chardata[t].fontid != font->id) {
883 msg("<error> Internal error: fontid %d != fontid %d", i->chardata[t].fontid, font->id);
886 SRECT b = font->layout->bounds[i->chardata[t].charid];
887 b.xmin *= i->chardata[t].size;
888 b.ymin *= i->chardata[t].size;
889 b.xmax *= i->chardata[t].size;
890 b.ymax *= i->chardata[t].size;
895 b.xmin += i->chardata[t].x;
896 b.ymin += i->chardata[t].y;
897 b.xmax += i->chardata[t].x;
898 b.ymax += i->chardata[t].y;
900 /* until we solve the INTERNAL_SCALING problem (see below)
901 make sure the bounding box is big enough */
907 if(debug) printf("(%f,%f,%f,%f) -> (%f,%f,%f,%f) [font %d/%d, char %d]\n",
908 font->layout->bounds[i->chardata[t].charid].xmin/20.0,
909 font->layout->bounds[i->chardata[t].charid].ymin/20.0,
910 font->layout->bounds[i->chardata[t].charid].xmax/20.0,
911 font->layout->bounds[i->chardata[t].charid].ymax/20.0,
916 i->chardata[t].fontid,
918 i->chardata[t].charid
920 swf_ExpandRect2(&r, &b);
922 if(debug) printf("-----> (%f,%f,%f,%f)\n",
930 static void putcharacters(struct swfoutput*obj, TAG*tag)
932 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
936 color.r = i->chardata[0].color.r^255;
945 int charadvance[128];
948 int glyphbits=1; //TODO: can this be zero?
951 if(tag->id != ST_DEFINETEXT &&
952 tag->id != ST_DEFINETEXT2) {
953 msg("<error> internal error: putcharacters needs an text tag, not %d\n",tag->id);
956 if(!i->chardatapos) {
957 msg("<warning> putcharacters called with zero characters");
960 for(pass = 0; pass < 2; pass++)
970 advancebits++; // add sign bit
971 swf_SetU8(tag, glyphbits);
972 swf_SetU8(tag, advancebits);
975 for(t=0;t<=i->chardatapos;t++)
977 if(lastfontid != i->chardata[t].fontid ||
978 lastx!=i->chardata[t].x ||
979 lasty!=i->chardata[t].y ||
980 !colorcompare(obj,&color, &i->chardata[t].color) ||
982 lastsize != i->chardata[t].size ||
985 if(charstorepos && pass==0)
988 for(s=0;s<charstorepos;s++)
990 while(charids[s]>=(1<<glyphbits))
992 while(charadvance[s]>=(1<<advancebits))
996 if(charstorepos && pass==1)
998 tag->writeBit = 0; // Q&D
999 swf_SetBits(tag, 0, 1); // GLYPH Record
1000 swf_SetBits(tag, charstorepos, 7); // number of glyphs
1002 for(s=0;s<charstorepos;s++)
1004 swf_SetBits(tag, charids[s], glyphbits);
1005 swf_SetBits(tag, charadvance[s], advancebits);
1010 if(pass == 1 && t<i->chardatapos)
1016 if(lastx != i->chardata[t].x ||
1017 lasty != i->chardata[t].y)
1019 newx = i->chardata[t].x;
1020 newy = i->chardata[t].y;
1026 if(!colorcompare(obj,&color, &i->chardata[t].color))
1028 color = i->chardata[t].color;
1031 font.id = i->chardata[t].fontid;
1032 if(lastfontid != i->chardata[t].fontid || lastsize != i->chardata[t].size)
1035 tag->writeBit = 0; // Q&D
1036 swf_TextSetInfoRecord(tag, newfont, i->chardata[t].size, newcolor, newx,newy);
1039 lastfontid = i->chardata[t].fontid;
1040 lastx = i->chardata[t].x;
1041 lasty = i->chardata[t].y;
1042 lastsize = i->chardata[t].size;
1045 if(t==i->chardatapos)
1049 int nextt = t==i->chardatapos-1?t:t+1;
1050 int rel = i->chardata[nextt].x-i->chardata[t].x;
1051 if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) {
1053 lastx=i->chardata[nextt].x;
1057 lastx=i->chardata[t].x;
1059 charids[charstorepos] = i->chardata[t].charid;
1060 charadvance[charstorepos] = advance;
1067 static void putcharacter(struct swfoutput*obj, int fontid, int charid,
1068 int x,int y, int size)
1070 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1071 if(i->chardatapos == CHARDATAMAX)
1073 msg("<warning> Character buffer too small. SWF will be slightly bigger");
1077 i->chardata[i->chardatapos].fontid = fontid;
1078 i->chardata[i->chardatapos].charid = charid;
1079 i->chardata[i->chardatapos].x = x;
1080 i->chardata[i->chardatapos].y = y;
1081 i->chardata[i->chardatapos].color = obj->fillrgb;
1082 i->chardata[i->chardatapos].size = size;
1086 /* Notice: we can only put chars in the range -1639,1638 (-32768/20,32768/20).
1087 So if we set this value to high, the char coordinates will overflow.
1088 If we set it to low, however, the char positions will be inaccurate */
1089 #define FONT_INTERNAL_SIZE 4
1091 /* process a character. */
1092 static int drawchar(struct swfoutput*obj, SWFFONT *swffont, char*character, int charnr, int u, swfmatrix*m)
1094 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1096 msg("<warning> Font is NULL");
1100 int charid = getCharID(swffont, charnr, character, u);
1103 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1104 FIXNULL(character),charnr, u, FIXNULL((char*)swffont->name), swffont->numchars);
1115 float det = ((m->m11*m->m22)-(m->m21*m->m12));
1116 if(fabs(det) < 0.0005) {
1117 /* x direction equals y direction- the text is invisible */
1120 det = 20*FONT_INTERNAL_SIZE / det;
1123 p.x = (SCOORD)(( x * m->m22 - y * m->m12)*det);
1124 p.y = (SCOORD)((- x * m->m21 + y * m->m11)*det);
1126 putcharacter(obj, swffont->id, charid,p.x,p.y,FONT_INTERNAL_SIZE);
1127 swf_FontUseGlyph(swffont, charid);
1132 SWF_OUTLINE*outline = font->getOutline(character, charnr);
1133 char* charname = character;
1136 msg("<warning> Didn't find character '%s' (%d) in current charset (%s)",
1137 FIXNULL(character),charnr,FIXNULL(font->getName()));
1156 drawpath(tag, outline, &m2, 0);
1161 static void endtext(swfoutput*obj)
1163 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1167 i->tag = swf_InsertTag(i->tag,ST_DEFINETEXT);
1168 swf_SetU16(i->tag, i->textid);
1171 r = getcharacterbbox(obj, obj->swffont);
1173 swf_SetRect(i->tag,&r);
1176 swf_GetMatrix(0, &m);
1177 swf_SetMatrix(i->tag,&m);
1179 putcharacters(obj, i->tag);
1180 swf_SetU8(i->tag,0);
1181 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
1182 swf_ObjectPlace(i->tag,i->textid,/*depth*/i->depth++,&obj->fontmatrix,NULL,NULL);
1187 /* draw a curved polygon. */
1188 void swfoutput_drawpath(swfoutput*obj, SWF_OUTLINE*outline,
1191 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1195 /* Multiple polygons in one shape don't overlap correctly,
1196 so we better start a new shape here if the polygon is filled
1198 if(i->shapeid>=0 && i->fill && !config.ignoredraworder) {
1210 drawpath(obj, outline,m, 0);
1213 void swfoutput_drawpath2poly(struct swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
1215 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1220 assert(i->shapeid<0);
1224 drawpath2poly(obj, outline, m, 0, line_join, line_cap, line_width, miter_limit);
1227 int getCharID(SWFFONT *font, int charnr, char *charname, int u)
1230 if(charname && font->glyphnames) {
1231 for(t=0;t<font->numchars;t++) {
1232 if(font->glyphnames[t] && !strcmp(font->glyphnames[t],charname)) {
1233 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1237 /* if we didn't find the character, maybe
1238 we can find the capitalized version */
1239 for(t=0;t<font->numchars;t++) {
1240 if(font->glyphnames[t] && !strcasecmp(font->glyphnames[t],charname)) {
1241 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1248 /* try to use the unicode id */
1249 if(u>=0 && u<font->maxascii && font->ascii2glyph[u]>=0) {
1250 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->ascii2glyph[u]);
1251 return font->ascii2glyph[u];
1255 if(font->encoding != FONT_ENCODING_UNICODE) {
1256 /* the following only works if the font encoding
1257 is US-ASCII based. It's needed for fonts which return broken unicode
1259 if(charnr>=0 && charnr<font->maxascii && font->ascii2glyph[charnr]>=0) {
1260 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, font->ascii2glyph[charnr]);
1261 return font->ascii2glyph[charnr];
1265 if(charnr>=0 && charnr<font->numchars) {
1266 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1274 /* set's the t1 font index of the font to use for swfoutput_drawchar(). */
1275 void swfoutput_setfont(struct swfoutput*obj, char*fontid, char*filename)
1277 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1278 fontlist_t*last=0,*iterator;
1280 msg("<error> No fontid");
1284 if(obj->swffont && obj->swffont->name && !strcmp((char*)obj->swffont->name,fontid))
1287 /* TODO: remove the need for this (enhance getcharacterbbox so that it can cope
1288 with multiple fonts */
1291 iterator = i->fontlist;
1293 if(!strcmp((char*)iterator->swffont->name,fontid)) {
1294 obj->swffont = iterator->swffont;
1298 iterator = iterator->next;
1302 msg("<error> No filename given for font- internal error?");
1306 swf_SetLoadFontParameters(64,/*skip unused*/0,/*full unicode*/1);
1307 SWFFONT*swffont = swf_LoadFont(filename);
1310 msg("<warning> Couldn't load font %s (%s)", fontid, filename);
1311 swffont = swf_LoadFont(0);
1314 swf_FontSetID(swffont, ++i->currentswfid);
1316 if(screenloglevel >= LOGLEVEL_DEBUG) {
1317 // print font information
1318 msg("<debug> Font %s (%s)",swffont->name, filename);
1319 msg("<debug> | ID: %d", swffont->id);
1320 msg("<debug> | Version: %d", swffont->version);
1321 msg("<debug> | Name: %s", fontid);
1322 msg("<debug> | Numchars: %d", swffont->numchars);
1323 msg("<debug> | Maxascii: %d", swffont->maxascii);
1324 msg("<debug> | Style: %d", swffont->style);
1325 msg("<debug> | Encoding: %d", swffont->encoding);
1326 for(int iii=0; iii<swffont->numchars;iii++) {
1327 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,
1328 swffont->layout->bounds[iii].xmin/20.0,
1329 swffont->layout->bounds[iii].ymin/20.0,
1330 swffont->layout->bounds[iii].xmax/20.0,
1331 swffont->layout->bounds[iii].ymax/20.0
1334 for(t=0;t<swffont->maxascii;t++) {
1335 if(swffont->ascii2glyph[t] == iii)
1336 msg("<debug> | - maps to %d",t);
1341 /* set the font name to the ID we use here */
1342 if(swffont->name) free(swffont->name);
1343 swffont->name = (U8*)strdup(fontid);
1345 iterator = new fontlist_t;
1346 iterator->swffont = swffont;
1350 last->next = iterator;
1352 i->fontlist = iterator;
1354 obj->swffont = swffont;
1357 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1359 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1360 fontlist_t *iterator = i->fontlist;
1362 if(!strcmp((char*)iterator->swffont->name,fontid))
1364 iterator = iterator->next;
1369 /* set's the matrix which is to be applied to characters drawn by
1370 swfoutput_drawchar() */
1371 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1372 double m21,double m22)
1374 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1375 if(obj->fontm11 == m11 &&
1376 obj->fontm12 == m12 &&
1377 obj->fontm21 == m21 &&
1378 obj->fontm22 == m22)
1388 m.sx = (U32)(((obj->fontm11)*65536)/FONT_INTERNAL_SIZE); m.r1 = (U32)(((obj->fontm12)*65536)/FONT_INTERNAL_SIZE);
1389 m.r0 = (U32)(((obj->fontm21)*65536)/FONT_INTERNAL_SIZE); m.sy = (U32)(((obj->fontm22)*65536)/FONT_INTERNAL_SIZE);
1392 obj->fontmatrix = m;
1395 /* draws a character at x,y. */
1396 int swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr, int u)
1398 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1400 m.m11 = obj->fontm11;
1401 m.m12 = obj->fontm12;
1402 m.m21 = obj->fontm21;
1403 m.m22 = obj->fontm22;
1406 return drawchar(obj, obj->swffont, character, charnr, u, &m);
1409 static void endpage(struct swfoutput*obj)
1411 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1417 swfoutput_endclip(obj);
1419 if(config.insertstoptag) {
1421 atag = action_Stop(atag);
1422 atag = action_End(atag);
1423 i->tag = swf_InsertTag(i->tag,ST_DOACTION);
1424 swf_ActionSet(i->tag,atag);
1426 i->tag = swf_InsertTag(i->tag,ST_SHOWFRAME);
1429 void swfoutput_newpage(struct swfoutput*obj, int pageNum, int x1, int y1, int x2, int y2)
1431 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1435 for(i->depth--;i->depth>=i->startdepth;i->depth--) {
1436 i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2);
1437 swf_SetU16(i->tag,i->depth);
1439 i->depth = i->startdepth = 3; /* leave room for clip and background rectangle */
1443 x1*=20;y1*=20;x2*=20;y2*=20;
1445 if(i->lastpagesize.xmin != x1 ||
1446 i->lastpagesize.xmax != x2 ||
1447 i->lastpagesize.ymin != y1 ||
1448 i->lastpagesize.ymax != y2)
1449 {/* add white clipping rectangle */
1450 msg("<notice> processing page %d (%dx%d)", pageNum,i->sizex,i->sizey);
1453 msg("<notice> Page has a different size than previous ones");
1454 i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2);
1455 swf_SetU16(i->tag,1);
1456 i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2);
1457 swf_SetU16(i->tag,2);
1461 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1465 int shapeid = ++i->currentswfid;
1470 i->tag = swf_InsertTag(i->tag, ST_DEFINESHAPE);
1472 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1473 swf_SetU16(i->tag,shapeid);
1474 swf_SetRect(i->tag,&r);
1475 swf_SetShapeHeader(i->tag,s);
1476 swf_ShapeSetAll(i->tag,s,x1,y1,ls1,fs1,0);
1477 swf_ShapeSetLine(i->tag,s,(x2-x1),0);
1478 swf_ShapeSetLine(i->tag,s,0,(y2-y1));
1479 swf_ShapeSetLine(i->tag,s,(x1-x2),0);
1480 swf_ShapeSetLine(i->tag,s,0,(y1-y2));
1481 swf_ShapeSetEnd(i->tag);
1483 i->tag = swf_InsertTag(i->tag, ST_PLACEOBJECT2);
1484 swf_ObjectPlace(i->tag,shapeid,/*depth*/1,0,0,0);
1485 i->tag = swf_InsertTag(i->tag, ST_PLACEOBJECT2);
1486 swf_ObjectPlaceClip(i->tag,shapeid,/*depth*/2,0,0,0,65535);
1488 msg("<notice> processing page %d", pageNum);
1491 i->lastpagesize.xmin = x1;
1492 i->lastpagesize.xmax = x2;
1493 i->lastpagesize.ymin = y1;
1494 i->lastpagesize.ymax = y2;
1495 swf_ExpandRect2(&i->swf.movieSize, &i->lastpagesize);
1500 /* initialize the swf writer */
1501 void swfoutput_init(struct swfoutput* obj, char*_filename)
1503 memset(obj, 0, sizeof(struct swfoutput));
1504 obj->internal = init_internal_struct();
1506 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1510 i->filename = _filename;
1512 msg("<verbose> initializing swf output for size %d*%d\n", i->sizex,i->sizey);
1517 memset(&i->swf,0x00,sizeof(SWF));
1518 memset(&i->lastpagesize,0x00,sizeof(SRECT));
1520 i->swf.fileVersion = config.flashversion;
1521 i->swf.frameRate = 0x0040; // 1 frame per 4 seconds
1522 i->swf.movieSize.xmin = 0;
1523 i->swf.movieSize.ymin = 0;
1524 i->swf.movieSize.xmax = 0;
1525 i->swf.movieSize.ymax = 0;
1527 i->swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1528 i->tag = i->swf.firstTag;
1529 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1530 swf_SetRGB(i->tag,&rgb);
1532 i->startdepth = i->depth = 0;
1535 void swfoutput_setprotected(struct swfoutput*obj) //write PROTECT tag
1537 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1538 if(!i->flag_protected)
1539 i->tag = swf_InsertTag(i->tag, ST_PROTECT);
1540 i->flag_protected = 1;
1543 static void startshape(struct swfoutput*obj)
1545 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1552 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE);
1554 swf_ShapeNew(&i->shape);
1555 i->linestyleid = swf_ShapeAddLineStyle(i->shape,i->linewidth,&obj->strokergb);
1556 rgb.r = obj->fillrgb.r;
1557 rgb.g = obj->fillrgb.g;
1558 rgb.b = obj->fillrgb.b;
1559 i->fillstyleid = swf_ShapeAddSolidFillStyle(i->shape,&obj->fillrgb);
1561 i->shapeid = ++i->currentswfid;
1562 swf_SetU16(i->tag,i->shapeid); // ID
1564 i->bboxrectpos = i->tag->len;
1567 r.xmax = 20*i->sizex;
1568 r.ymax = 20*i->sizey;
1569 swf_SetRect(i->tag,&r);
1571 memset(&i->bboxrect, 0, sizeof(i->bboxrect));
1573 swf_SetShapeStyles(i->tag,i->shape);
1574 swf_ShapeCountBits(i->shape,NULL,NULL);
1575 swf_SetShapeBits(i->tag,i->shape);
1577 /* TODO: do we really need this? */
1578 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,i->linestyleid,0,0);
1579 i->swflastx=i->swflasty=0;
1581 i->shapeisempty = 1;
1584 static void starttext(struct swfoutput*obj)
1586 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1590 i->textid = ++i->currentswfid;
1592 i->swflastx=i->swflasty=0;
1596 /* TODO: move to ../lib/rfxswf */
1597 void changeRect(struct swfoutput*obj, TAG*tag, int pos, SRECT*newrect)
1599 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1600 /* determine length of old rect */
1604 swf_GetRect(tag, &old);
1605 swf_ResetReadBits(tag);
1606 int pos_end = tag->pos;
1608 int len = tag->len - pos_end;
1609 U8*data = (U8*)malloc(len);
1610 memcpy(data, &tag->data[pos_end], len);
1613 swf_SetRect(tag, newrect);
1614 swf_SetBlock(tag, data, len);
1616 tag->pos = tag->readBit = 0;
1619 void cancelshape(swfoutput*obj)
1621 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1622 /* delete old shape tag */
1624 i->tag = i->tag->prev;
1625 swf_DeleteTag(todel);
1627 i->bboxrectpos = -1;
1630 void fixAreas(swfoutput*obj)
1632 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1633 if(!i->shapeisempty && i->fill &&
1634 (i->bboxrect.xmin == i->bboxrect.xmax ||
1635 i->bboxrect.ymin == i->bboxrect.ymax) &&
1636 config.minlinewidth >= 0.001
1638 msg("<debug> Shape has size 0: width=%.2f height=%.2f",
1639 (i->bboxrect.xmax-i->bboxrect.xmin)/20.0,
1640 (i->bboxrect.ymax-i->bboxrect.ymin)/20.0
1643 SRECT r = i->bboxrect;
1645 if(r.xmin == r.xmax && r.ymin == r.ymax) {
1646 /* this thing comes down to a single dot- nothing to fix here */
1652 RGBA save_col = obj->strokergb;
1653 int save_width = i->linewidth;
1655 obj->strokergb = obj->fillrgb;
1656 i->linewidth = (int)(config.minlinewidth*20);
1657 if(i->linewidth==0) i->linewidth = 1;
1661 moveto(obj, i->tag, r.xmin/20.0,r.ymin/20.0);
1662 lineto(obj, i->tag, r.xmax/20.0,r.ymax/20.0);
1664 obj->strokergb = save_col;
1665 i->linewidth = save_width;
1670 static void endshape(swfoutput*obj, int clipdepth)
1672 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1679 if(i->shapeisempty ||
1680 (i->bboxrect.xmin == i->bboxrect.xmax &&
1681 i->bboxrect.ymin == i->bboxrect.ymax))
1683 // delete the shape again, we didn't do anything
1688 swf_ShapeSetEnd(i->tag);
1690 changeRect(obj, i->tag, i->bboxrectpos, &i->bboxrect);
1692 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
1694 swf_ObjectPlaceClip(i->tag,i->shapeid,i->depth++,NULL,NULL,NULL,clipdepth);
1696 swf_ObjectPlace(i->tag,i->shapeid,/*depth*/i->depth++,NULL,NULL,NULL);
1699 i->bboxrectpos = -1;
1702 void swfoutput_save(struct swfoutput* obj)
1704 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1706 fontlist_t *tmp,*iterator = i->fontlist;
1708 TAG*mtag = i->swf.firstTag;
1709 if(iterator->swffont) {
1710 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1711 /*if(!storeallcharacters)
1712 swf_FontReduce(iterator->swffont);*/
1713 swf_FontSetDefine2(mtag, iterator->swffont);
1716 iterator = iterator->next;
1723 fi = open(i->filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1728 msg("<fatal> Could not create \"%s\". ", FIXNULL(i->filename));
1732 i->tag = swf_InsertTag(i->tag,ST_END);
1734 if(config.enablezlib || config.flashversion>=6) {
1735 if FAILED(swf_WriteSWC(fi,&i->swf))
1736 msg("<error> WriteSWC() failed.\n");
1738 if FAILED(swf_WriteSWF(fi,&i->swf))
1739 msg("<error> WriteSWF() failed.\n");
1744 msg("<notice> SWF written\n");
1747 /* Perform cleaning up, complete the swf, and write it out. */
1748 void swfoutput_destroy(struct swfoutput* obj)
1750 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1752 swfoutput_save(obj);
1754 fontlist_t *tmp,*iterator = i->fontlist;
1756 if(iterator->swffont) {
1757 swf_FontFree(iterator->swffont);
1760 iterator = iterator->next;
1764 memset(obj, 0, sizeof(swfoutput));
1767 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1769 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1770 obj->drawmode = mode;
1771 if(mode == DRAWMODE_FILL)
1773 else if(mode == DRAWMODE_EOFILL)
1775 else if(mode == DRAWMODE_STROKE)
1777 else if(mode == DRAWMODE_CLIP)
1779 else if(mode == DRAWMODE_EOCLIP)
1783 void swfoutput_setfillcolor(swfoutput* obj, U8 r, U8 g, U8 b, U8 a)
1785 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1786 if(obj->fillrgb.r == r &&
1787 obj->fillrgb.g == g &&
1788 obj->fillrgb.b == b &&
1789 obj->fillrgb.a == a) return;
1799 void swfoutput_setstrokecolor(swfoutput* obj, U8 r, U8 g, U8 b, U8 a)
1801 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1802 if(obj->strokergb.r == r &&
1803 obj->strokergb.g == g &&
1804 obj->strokergb.b == b &&
1805 obj->strokergb.a == a) return;
1809 obj->strokergb.r = r;
1810 obj->strokergb.g = g;
1811 obj->strokergb.b = b;
1812 obj->strokergb.a = a;
1815 void swfoutput_setlinewidth(struct swfoutput*obj, double _linewidth)
1817 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1818 if(i->linewidth == (U16)(_linewidth*20))
1823 i->linewidth = (U16)(_linewidth*20);
1827 void swfoutput_startclip(swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m)
1829 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1835 if(i->clippos >= 127)
1837 msg("<warning> Too many clip levels.");
1842 int olddrawmode = obj->drawmode;
1843 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1844 swfoutput_drawpath(obj, outline, m);
1845 swf_ShapeSetEnd(i->tag);
1846 swfoutput_setdrawmode(obj, olddrawmode);
1848 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
1849 i->cliptags[i->clippos] = i->tag;
1850 i->clipshapes[i->clippos] = i->shapeid;
1851 i->clipdepths[i->clippos] = i->depth++;
1856 void swfoutput_endclip(swfoutput*obj)
1858 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1865 msg("<error> Invalid end of clipping region");
1869 swf_ObjectPlaceClip(i->cliptags[i->clippos],i->clipshapes[i->clippos],i->clipdepths[i->clippos],NULL,NULL,NULL,i->depth++);
1872 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1874 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1876 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1878 if(!strncmp("http://pdf2swf:", url, 15)) {
1879 char*tmp = strdup(url);
1880 int l = strlen(tmp);
1883 swfoutput_namedlink(obj, tmp+15, points);
1893 if(config.opennewwindow)
1894 actions = action_GetUrl(0, url, "_parent");
1896 actions = action_GetUrl(0, url, "_this");
1897 actions = action_End(actions);
1899 drawlink(obj, actions, 0, points,0);
1901 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1903 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1911 actions = action_GotoFrame(0, page);
1912 actions = action_End(actions);
1914 drawlink(obj, actions, 0, points,0);
1917 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
1918 of the viewer objects, like subtitles, index elements etc.
1920 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
1922 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1923 ActionTAG *actions1,*actions2;
1924 char*tmp = strdup(name);
1932 if(!strncmp(tmp, "call:", 5))
1934 char*x = strchr(&tmp[5], ':');
1936 actions1 = action_PushInt(0, 0); //number of parameters (0)
1937 actions1 = action_PushString(actions1, &tmp[5]); //function name
1938 actions1 = action_CallFunction(actions1);
1941 actions1 = action_PushString(0, x+1); //parameter
1942 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
1943 actions1 = action_PushString(actions1, &tmp[5]); //function name
1944 actions1 = action_CallFunction(actions1);
1946 actions2 = action_End(0);
1951 actions1 = action_PushString(0, "/:subtitle");
1952 actions1 = action_PushString(actions1, name);
1953 actions1 = action_SetVariable(actions1);
1954 actions1 = action_End(actions1);
1956 actions2 = action_PushString(0, "/:subtitle");
1957 actions2 = action_PushString(actions2, "");
1958 actions2 = action_SetVariable(actions2);
1959 actions2 = action_End(actions2);
1962 drawlink(obj, actions1, actions2, points,mouseover);
1964 swf_ActionFree(actions1);
1965 swf_ActionFree(actions2);
1969 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
1971 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1976 struct plotxy p1,p2,p3,p4;
1980 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
1984 int buttonid = ++i->currentswfid;
1987 if(points[t].x>xmax) xmax=points[t].x;
1988 if(points[t].y>ymax) ymax=points[t].y;
1989 if(points[t].x<xmin) xmin=points[t].x;
1990 if(points[t].y<ymin) ymin=points[t].y;
1993 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
1994 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
1996 /* the following code subtracts the upper left edge from all coordinates,
1997 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
1998 Necessary for preprocessing with swfcombine. */
1999 posx = xmin; posy = ymin;
2000 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
2001 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
2002 xmin -= posx; ymin -= posy;
2003 xmax -= posx; ymax -= posy;
2006 myshapeid = ++i->currentswfid;
2007 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE3);
2008 swf_ShapeNew(&i->shape);
2009 rgb.r = rgb.b = rgb.a = rgb.g = 0;
2010 fsid = swf_ShapeAddSolidFillStyle(i->shape,&rgb);
2011 swf_SetU16(i->tag, myshapeid);
2012 r.xmin = (int)(xmin*20);
2013 r.ymin = (int)(ymin*20);
2014 r.xmax = (int)(xmax*20);
2015 r.ymax = (int)(ymax*20);
2016 swf_SetRect(i->tag,&r);
2017 swf_SetShapeStyles(i->tag,i->shape);
2018 swf_ShapeCountBits(i->shape,NULL,NULL);
2019 swf_SetShapeBits(i->tag,i->shape);
2020 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,0,fsid,0);
2021 i->swflastx = i->swflasty = 0;
2022 moveto(obj, i->tag, p1);
2023 lineto(obj, i->tag, p2);
2024 lineto(obj, i->tag, p3);
2025 lineto(obj, i->tag, p4);
2026 lineto(obj, i->tag, p1);
2027 swf_ShapeSetEnd(i->tag);
2030 myshapeid2 = ++i->currentswfid;
2031 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE3);
2032 swf_ShapeNew(&i->shape);
2033 rgb.r = rgb.b = rgb.a = rgb.g = 255;
2035 fsid = swf_ShapeAddSolidFillStyle(i->shape,&rgb);
2036 swf_SetU16(i->tag, myshapeid2);
2037 r.xmin = (int)(xmin*20);
2038 r.ymin = (int)(ymin*20);
2039 r.xmax = (int)(xmax*20);
2040 r.ymax = (int)(ymax*20);
2041 swf_SetRect(i->tag,&r);
2042 swf_SetShapeStyles(i->tag,i->shape);
2043 swf_ShapeCountBits(i->shape,NULL,NULL);
2044 swf_SetShapeBits(i->tag,i->shape);
2045 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,0,fsid,0);
2046 i->swflastx = i->swflasty = 0;
2047 moveto(obj, i->tag, p1);
2048 lineto(obj, i->tag, p2);
2049 lineto(obj, i->tag, p3);
2050 lineto(obj, i->tag, p4);
2051 lineto(obj, i->tag, p1);
2052 swf_ShapeSetEnd(i->tag);
2056 i->tag = swf_InsertTag(i->tag,ST_DEFINEBUTTON);
2057 swf_SetU16(i->tag,buttonid); //id
2058 swf_ButtonSetFlags(i->tag, 0); //menu=no
2059 swf_ButtonSetRecord(i->tag,0x01,myshapeid,i->depth,0,0);
2060 swf_ButtonSetRecord(i->tag,0x02,myshapeid2,i->depth,0,0);
2061 swf_ButtonSetRecord(i->tag,0x04,myshapeid2,i->depth,0,0);
2062 swf_ButtonSetRecord(i->tag,0x08,myshapeid,i->depth,0,0);
2063 swf_SetU8(i->tag,0);
2064 swf_ActionSet(i->tag,actions1);
2065 swf_SetU8(i->tag,0);
2069 i->tag = swf_InsertTag(i->tag,ST_DEFINEBUTTON2);
2070 swf_SetU16(i->tag,buttonid); //id
2071 swf_ButtonSetFlags(i->tag, 0); //menu=no
2072 swf_ButtonSetRecord(i->tag,0x01,myshapeid,i->depth,0,0);
2073 swf_ButtonSetRecord(i->tag,0x02,myshapeid2,i->depth,0,0);
2074 swf_ButtonSetRecord(i->tag,0x04,myshapeid2,i->depth,0,0);
2075 swf_ButtonSetRecord(i->tag,0x08,myshapeid,i->depth,0,0);
2076 swf_SetU8(i->tag,0); // end of button records
2077 swf_ButtonSetCondition(i->tag, BC_IDLE_OVERUP);
2078 swf_ActionSet(i->tag,actions1);
2080 swf_ButtonSetCondition(i->tag, BC_OVERUP_IDLE);
2081 swf_ActionSet(i->tag,actions2);
2082 swf_SetU8(i->tag,0);
2083 swf_ButtonPostProcess(i->tag, 2);
2085 swf_SetU8(i->tag,0);
2086 swf_ButtonPostProcess(i->tag, 1);
2090 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
2092 if(posx!=0 || posy!=0) {
2094 swf_GetMatrix(0,&m);
2095 m.tx = (int)(posx*20);
2096 m.ty = (int)(posy*20);
2097 swf_ObjectPlace(i->tag, buttonid, i->depth++,&m,0,0);
2100 swf_ObjectPlace(i->tag, buttonid, i->depth++,0,0,0);
2104 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
2105 double x1,double y1,
2106 double x2,double y2,
2107 double x3,double y3,
2108 double x4,double y4)
2110 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2115 struct plotxy p1,p2,p3,p4;
2117 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
2118 if(x2>xmax) xmax=x2;
2119 if(y2>ymax) ymax=y2;
2120 if(x2<xmin) xmin=x2;
2121 if(y2<ymin) ymin=y2;
2122 if(x3>xmax) xmax=x3;
2123 if(y3>ymax) ymax=y3;
2124 if(x3<xmin) xmin=x3;
2125 if(y3<ymin) ymin=y3;
2126 if(x4>xmax) xmax=x4;
2127 if(y4>ymax) ymax=y4;
2128 if(x4<xmin) xmin=x4;
2129 if(y4<ymin) ymin=y4;
2135 {p1.x = (int)(p1.x*20)/20.0;
2136 p1.y = (int)(p1.y*20)/20.0;
2137 p2.x = (int)(p2.x*20)/20.0;
2138 p2.y = (int)(p2.y*20)/20.0;
2139 p3.x = (int)(p3.x*20)/20.0;
2140 p3.y = (int)(p3.y*20)/20.0;
2141 p4.x = (int)(p4.x*20)/20.0;
2142 p4.y = (int)(p4.y*20)/20.0;}
2145 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
2146 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
2147 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
2148 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
2150 m.tx = (int)(p1.x*20);
2151 m.ty = (int)(p1.y*20);
2154 myshapeid = ++i->currentswfid;
2155 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE);
2156 swf_ShapeNew(&i->shape);
2157 //lsid = ShapeAddLineStyle(shape,linewidth,&obj->strokergb);
2158 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
2159 fsid = swf_ShapeAddBitmapFillStyle(i->shape,&m,bitid,1);
2160 swf_SetU16(i->tag, myshapeid);
2161 r.xmin = (int)(xmin*20);
2162 r.ymin = (int)(ymin*20);
2163 r.xmax = (int)(xmax*20);
2164 r.ymax = (int)(ymax*20);
2165 swf_SetRect(i->tag,&r);
2166 swf_SetShapeStyles(i->tag,i->shape);
2167 swf_ShapeCountBits(i->shape,NULL,NULL);
2168 swf_SetShapeBits(i->tag,i->shape);
2169 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,lsid,fsid,0);
2170 i->swflastx = i->swflasty = 0;
2171 moveto(obj, i->tag, p1);
2172 lineto(obj, i->tag, p2);
2173 lineto(obj, i->tag, p3);
2174 lineto(obj, i->tag, p4);
2175 lineto(obj, i->tag, p1);
2177 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
2178 ShapeSetLine (tag, shape, (int)(x1*20);
2179 ShapeSetLine (tag, shape, x*20,0);
2180 ShapeSetLine (tag, shape, 0,-y*20);
2181 ShapeSetLine (tag, shape, -x*20,0);*/
2182 swf_ShapeSetEnd(i->tag);
2185 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
2186 swf_ObjectPlace(i->tag,myshapeid,/*depth*/i->depth++,NULL,NULL,NULL);
2189 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
2190 double x1,double y1,
2191 double x2,double y2,
2192 double x3,double y3,
2193 double x4,double y4)
2195 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2202 int bitid = ++i->currentswfid;
2204 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSJPEG2);
2205 swf_SetU16(i->tag, bitid);
2206 if(swf_SetJPEGBits(i->tag, filename, config.jpegquality)<0) {
2207 swf_DeleteTag(i->tag);
2212 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2216 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2217 double x1,double y1,
2218 double x2,double y2,
2219 double x3,double y3,
2220 double x4,double y4)
2222 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2231 int bitid = ++i->currentswfid;
2233 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSJPEG2);
2234 swf_SetU16(i->tag, bitid);
2235 swf_SetJPEGBits2(i->tag,sizex,sizey,mem,config.jpegquality);
2236 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2240 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2241 double x1,double y1,
2242 double x2,double y2,
2243 double x3,double y3,
2244 double x4,double y4)
2246 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2253 int bitid = ++i->currentswfid;
2255 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSLOSSLESS);
2256 swf_SetU16(i->tag, bitid);
2257 if(swf_SetLosslessBits(i->tag,sizex,sizey,mem, BMF_32BIT)<0) {
2258 swf_DeleteTag(i->tag);
2263 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2267 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
2268 double x1,double y1,
2269 double x2,double y2,
2270 double x3,double y3,
2271 double x4,double y4, int n)
2273 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2283 /* SWF expects scanlines to be 4 byte aligned */
2286 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
2288 for(y=0;y<sizey;y++)
2290 for(x=0;x<sizex;x++)
2291 *ptr++ = mem[y*sizex+x];
2292 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
2297 int bitid = ++i->currentswfid;
2299 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSLOSSLESS2);
2300 swf_SetU16(i->tag, bitid);
2301 if(swf_SetLosslessBitsIndexed(i->tag,sizex,sizey,mem, pal, n)<0) {
2302 swf_DeleteTag(i->tag);
2309 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2313 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
2314 double x1,double y1,
2315 double x2,double y2,
2316 double x3,double y3,
2317 double x4,double y4)
2319 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2326 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2329 void swfoutput_setparameter(char*name, char*value)
2331 if(!strcmp(name, "drawonlyshapes")) {
2332 config.drawonlyshapes = atoi(value);
2333 } else if(!strcmp(name, "ignoredraworder")) {
2334 config.ignoredraworder = atoi(value);
2335 } else if(!strcmp(name, "filloverlap")) {
2336 config.filloverlap = atoi(value);
2337 } else if(!strcmp(name, "linksopennewwindow")) {
2338 config.opennewwindow = atoi(value);
2339 } else if(!strcmp(name, "opennewwindow")) {
2340 config.opennewwindow = atoi(value);
2341 } else if(!strcmp(name, "storeallcharacters")) {
2342 config.storeallcharacters = atoi(value);
2343 } else if(!strcmp(name, "enablezlib")) {
2344 config.enablezlib = atoi(value);
2345 } else if(!strcmp(name, "insertstop")) {
2346 config.insertstoptag = atoi(value);
2347 } else if(!strcmp(name, "protected")) {
2348 config.protect = atoi(value);
2349 } else if(!strcmp(name, "flashversion")) {
2350 config.flashversion = atoi(value);
2351 } else if(!strcmp(name, "minlinewidth")) {
2352 config.minlinewidth = atof(value);
2353 } else if(!strcmp(name, "jpegquality")) {
2354 int val = atoi(value);
2356 if(val>100) val=100;
2357 config.jpegquality = val;
2358 } else if(!strcmp(name, "splinequality")) {
2359 int v = atoi(value);
2360 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2362 config.splinemaxerror = v;
2363 } else if(!strcmp(name, "fontquality")) {
2364 int v = atoi(value);
2365 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2367 config.fontsplinemaxerror = v;
2369 fprintf(stderr, "unknown parameter: %s (=%s)\n", name, value);