2 Implements generation of swf files using the rfxswf lib. The routines
3 in this file are called from pdf2swf.
5 This file is part of swftools.
7 Swftools is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 Swftools is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with swftools; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
24 #include "../config.h"
33 #include "swfoutput.h"
36 #include "../lib/log.h"
37 #include "../lib/rfxswf.h"
40 #define CHARDATAMAX 8192
44 typedef struct _chardata {
46 int fontid; /* TODO: use a SWFFONT instead */
59 int config_opennewwindow=0;
60 int config_ignoredraworder=0;
61 int config_drawonlyshapes=0;
62 int config_jpegquality=85;
63 int config_storeallcharacters=0;
64 int config_enablezlib=0;
65 int config_insertstoptag=0;
66 int config_flashversion=5;
67 int config_splinemaxerror=1;
68 int config_fontsplinemaxerror=1;
69 int config_filloverlap=0;
71 float config_minlinewidth=0.05;
73 typedef struct _swfoutput_internal
105 char fillstylechanged;
110 chardata_t chardata[CHARDATAMAX];
113 } swfoutput_internal;
115 static swfoutput_internal* init_internal_struct()
117 swfoutput_internal*i = (swfoutput_internal*)malloc(sizeof(swfoutput_internal));
118 memset(i, 0, sizeof(swfoutput_internal));
138 i->fillstylechanged = 0;
147 static void startshape(struct swfoutput* obj);
148 static void starttext(struct swfoutput* obj);
149 static void endshape(struct swfoutput* obj,int clip);
150 static void endtext(struct swfoutput* obj);
152 // matrix multiplication. changes p0
153 static void transform (plotxy*p0,struct swfmatrix*m)
156 x = m->m11*p0->x+m->m12*p0->y;
157 y = m->m21*p0->x+m->m22*p0->y;
162 // write a move-to command into the swf
163 static int moveto(struct swfoutput*obj, TAG*tag, plotxy p0)
165 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
166 int rx = (int)(p0.x*20);
167 int ry = (int)(p0.y*20);
168 if(rx!=i->swflastx || ry!=i->swflasty || i->fillstylechanged) {
169 swf_ShapeSetMove (tag, i->shape, rx,ry);
170 i->fillstylechanged = 0;
177 static int moveto(struct swfoutput*obj, TAG*tag, float x, float y)
179 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
183 return moveto(obj, tag, p);
185 static void addPointToBBox(struct swfoutput*obj, int px, int py)
187 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
193 swf_ExpandRect(&i->bboxrect, p);
195 swf_ExpandRect3(&i->bboxrect, p, i->linewidth*3/2);
199 // write a line-to command into the swf
200 static void lineto(struct swfoutput*obj, TAG*tag, plotxy p0)
202 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
203 int px = (int)(p0.x*20);
204 int py = (int)(p0.y*20);
205 int rx = (px-i->swflastx);
206 int ry = (py-i->swflasty);
207 /* we can't skip this for rx=0,ry=0, those
209 swf_ShapeSetLine (tag, i->shape, rx,ry);
211 addPointToBBox(obj, i->swflastx,i->swflasty);
212 addPointToBBox(obj, px,py);
218 static void lineto(struct swfoutput*obj, TAG*tag, double x, double y)
226 // write a spline-to command into the swf
227 static void splineto(struct swfoutput*obj, TAG*tag, plotxy control,plotxy end)
229 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
230 int lastlastx = i->swflastx;
231 int lastlasty = i->swflasty;
233 int cx = ((int)(control.x*20)-i->swflastx);
234 int cy = ((int)(control.y*20)-i->swflasty);
237 int ex = ((int)(end.x*20)-i->swflastx);
238 int ey = ((int)(end.y*20)-i->swflasty);
242 if(cx || cy || ex || ey) {
243 swf_ShapeSetCurve(tag, i->shape, cx,cy,ex,ey);
244 addPointToBBox(obj, lastlastx ,lastlasty );
245 addPointToBBox(obj, lastlastx+cx,lastlasty+cy);
246 addPointToBBox(obj, lastlastx+cx+ex,lastlasty+cy+ey);
251 /* write a line, given two points and the transformation
253 static void line(struct swfoutput*obj, TAG*tag, plotxy p0, plotxy p1, struct swfmatrix*m)
257 moveto(obj, tag, p0);
258 lineto(obj, tag, p1);
261 /* write a cubic (!) spline. This involves calling the approximate()
262 function out of spline.cc to convert it to a quadratic spline. */
263 static void spline(struct swfoutput*obj, TAG*tag,plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m)
265 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
267 struct qspline q[128];
281 /* fonts use a different approximation than shapes */
282 num = cspline_approximate(&c, q, config_fontsplinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
283 //num = cspline_approximate(&c, q, 10.0, APPROXIMATE_INFLECTION);
285 num = cspline_approximate(&c, q, config_splinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
289 moveto(obj, tag,q[t].start);
290 splineto(obj, tag,q[t].control, q[t].end);
294 void resetdrawer(struct swfoutput*obj)
296 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
301 static void stopFill(struct swfoutput*obj)
303 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
306 swf_ShapeSetStyle(i->tag,i->shape,i->linestyleid,0x8000,0);
307 i->fillstylechanged = 1;
311 static void startFill(struct swfoutput*obj)
313 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
316 swf_ShapeSetStyle(i->tag,i->shape,0x8000,i->fillstyleid,0);
317 i->fillstylechanged = 1;
322 /* draw an outline. These are generated by pdf2swf and by t1lib
323 (representing characters). */
324 void drawpath(struct swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m, int log)
326 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
327 if( i->tag->id != ST_DEFINESHAPE &&
328 i->tag->id != ST_DEFINESHAPE2 &&
329 i->tag->id != ST_DEFINESHAPE3)
331 msg("<error> internal error: drawpath needs a shape tag, not %d\n",i->tag->id);
335 double lastx=0,lasty=0;
336 double firstx=0,firsty=0;
341 x += (outline->dest.x/(float)0xffff);
342 y += (outline->dest.y/(float)0xffff);
343 if(outline->type == SWF_PATHTYPE_MOVE)
345 //if(!init && fill && obj->drawmode != DRAWMODE_EOFILL && !ignoredraworder) {
346 if(config_filloverlap && !init && i->fill && obj->drawmode != DRAWMODE_EOFILL) {
347 /* drawmode=FILL (not EOFILL) means that
348 seperate shapes do not cancel each other out.
349 On SWF side, we need to start a new shape for each
350 closed polygon, because SWF only knows EOFILL.
357 if(((int)(lastx*20) != (int)(firstx*20) ||
358 (int)(lasty*20) != (int)(firsty*20)) &&
367 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
368 line(obj,i->tag, p0, p1, m);
374 else if(outline->type == SWF_PATHTYPE_LINE)
382 if(log) printf("line: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
383 line(obj,i->tag, p0,p1,m);
385 else if(outline->type == SWF_PATHTYPE_BEZIER)
391 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
394 p1.x=o2->C.x/(float)0xffff+lastx;
395 p1.y=o2->C.y/(float)0xffff+lasty;
396 p2.x=o2->B.x/(float)0xffff+lastx;
397 p2.y=o2->B.y/(float)0xffff+lasty;
400 if(log) printf("spline: %f,%f -> %f,%f\n",p3.x,p3.y,p0.x,p0.y);
401 spline(obj,i->tag,p0,p1,p2,p3,m);
404 msg("<error> drawpath: unknown outline type:%d\n", outline->type);
408 outline = outline->link;
410 if(((int)(lastx*20) != (int)(firstx*20) ||
411 (int)(lasty*20) != (int)(firsty*20)) &&
420 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
421 line(obj, i->tag, p0, p1, m);
425 plotxy getPivot(struct swfoutput*obj, SWF_OUTLINE*outline, int dir, double line_width, int end, int trytwo)
427 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
428 SWF_PATHPOINT next, next2;
429 double xv=0,yv=0, xv2=0, yv2=0;
434 if(outline->type == SWF_PATHTYPE_LINE) {
435 next = outline->dest;
437 next = ((SWF_BEZIERSEGMENT*)outline)->B;
438 if(next.x==0 && next.y==0) {
439 next = ((SWF_BEZIERSEGMENT*)outline)->C;
441 if(next.x==0 && next.y==0) {
442 next = ((SWF_BEZIERSEGMENT*)outline)->dest;
446 if(trytwo && outline->last && outline->last->type != SWF_PATHTYPE_MOVE) {
447 if(outline->type == SWF_PATHTYPE_LINE) {
448 next2 = outline->last->dest;
450 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)(outline->last))->C;
451 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)(outline->last))->B;
452 next2.x = outline->last->dest.x - c.x;
453 next2.y = outline->last->dest.y - c.y;
454 if(next2.x==0 && next2.y==0) {
455 next2.x = outline->last->dest.x - b.x;
456 next2.y = outline->last->dest.y - b.y;
458 if(next2.x==0 && next2.y==0) {
459 next2.x = outline->last->dest.x;
460 next2.y = outline->last->dest.y;
466 if(outline->type == SWF_PATHTYPE_LINE) {
467 next = outline->dest;
469 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)outline)->C;
470 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)outline)->B;
471 next.x = outline->dest.x - c.x;
472 next.y = outline->dest.y - c.y;
473 if(next.x==0 && next.y==0) {
474 next.x = outline->dest.x - b.x;
475 next.y = outline->dest.y - b.y;
477 if(next.x==0 && next.y==0) {
478 next.x = outline->dest.x;
479 next.y = outline->dest.y;
483 if(trytwo && outline->link && outline->link->type != SWF_PATHTYPE_MOVE) {
484 if(outline->type == SWF_PATHTYPE_LINE) {
485 next2 = outline->link->dest;
487 next2 = ((SWF_BEZIERSEGMENT*)(outline->link))->B;
488 if(next2.x==0 && next2.y==0) {
489 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->C;
491 if(next2.x==0 && next2.y==0) {
492 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->dest;
500 xv = next.y/(float)0xffff;
501 yv = -next.x/(float)0xffff;
503 xv = -next.y/(float)0xffff;
504 yv = next.x/(float)0xffff;
507 double r = (line_width/2)/sqrt(xv*xv+yv*yv);
513 xv2 = next2.y/(float)0xffff;
514 yv2 = -next2.x/(float)0xffff;
516 xv2 = -next2.y/(float)0xffff;
517 yv2 = next2.x/(float)0xffff;
520 double r2 = (line_width/2)/sqrt(xv2*xv2+yv2*yv2);
525 double r3 = (line_width/2)/sqrt(xv*xv+yv*yv);
535 void drawShortPath(struct swfoutput*obj, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline)
537 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
538 double lastx=x, lasty=y;
539 while (outline && outline->type != SWF_PATHTYPE_MOVE)
541 x += (outline->dest.x/(float)0xffff);
542 y += (outline->dest.y/(float)0xffff);
544 if(outline->type == SWF_PATHTYPE_LINE)
551 line(obj, i->tag, p0, p1, m);
553 else if(outline->type == SWF_PATHTYPE_BEZIER)
556 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
559 p1.x=o2->C.x/(float)0xffff+lastx;
560 p1.y=o2->C.y/(float)0xffff+lasty;
561 p2.x=o2->B.x/(float)0xffff+lastx;
562 p2.y=o2->B.y/(float)0xffff+lasty;
565 spline(obj, i->tag,p0,p1,p2,p3,m);
569 outline = outline->link;
573 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)
575 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
579 if(line_cap == LINE_CAP_BUTT || line_cap == LINE_CAP_SQUARE) {
582 SWF_OUTLINE *last, *tmp=outline;
583 plotxy s,e,p0,p1,p2,p3,m0,m1,m2,m3;
589 while(tmp && tmp->type != SWF_PATHTYPE_MOVE) {
591 lx += (tmp->dest.x/(float)0xffff);
592 ly += (tmp->dest.y/(float)0xffff);
595 s = getPivot(obj, outline, 0, line_width, 0, 0);
596 e = getPivot(obj, last, 0, line_width, 1, 0);
598 if(line_cap == LINE_CAP_BUTT) {
599 /* make the clipping rectangle slighly bigger
600 than the line ending, so that it get's clipped
610 p2.x = x2 - s.y - s.x*ee;
611 p2.y = y2 + s.x - s.y*ee;
612 p3.x = x2 - s.y + s.x*ee;
613 p3.y = y2 + s.x + s.y*ee;
618 m2.x = lx + e.y - e.x*ee;
619 m2.y = ly - e.x - e.y*ee;
620 m3.x = lx + e.y + e.x*ee;
621 m3.y = ly - e.x + e.y*ee;
623 for(nr=0;nr<2;nr++) {
625 struct plotxy q0,q1,q2,q3,q4,q5;
628 if(line_cap == LINE_CAP_BUTT) {
630 /* FIXME: box should be smaller */
632 q1.x = i->sizex; q1.y = 0;
633 q2.x = i->sizex; q2.y = i->sizey;
634 q3.x = 0; q3.y = i->sizey;
636 /* FIXME: box should be smaller */
637 q0.x = i->sizex; q0.y = i->sizey;
638 q1.x = 0; q1.y = i->sizey;
640 q3.x = i->sizex; q3.y = 0;
644 moveto(obj, i->tag, q0);
645 lineto(obj, i->tag, q1);
646 lineto(obj, i->tag, q2);
647 lineto(obj, i->tag, q3);
648 lineto(obj, i->tag, q0);
651 lineto(obj, i->tag, q4);
654 line(obj, i->tag, p0, p1, m);
655 line(obj, i->tag, p1, p2, m);
656 line(obj, i->tag, p2, p3, m);
657 line(obj, i->tag, p3, p0, m);
659 if(line_cap == LINE_CAP_BUTT) {
660 lineto(obj, i->tag, q0);
661 endshape(obj, i->depth+2-nr);
673 drawShortPath(obj,x,y,m,outline);
675 if(line_cap == LINE_CAP_BUTT) {
681 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)
683 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
684 plotxy d1,d2,p1,p2,p3,p4;
686 d1.x = (outline->dest.x/(float)0xffff);
687 d1.y = (outline->dest.y/(float)0xffff);
688 d2 = getPivot(obj, outline, 0, line_width, 0, 0);
690 assert(line_cap != LINE_CAP_ROUND);
691 if(line_cap == LINE_CAP_SQUARE) {
700 p2.x = x + d2.x + d1.x;
701 p2.y = y + d2.y + d1.y;
702 p3.x = x - d2.x + d1.x;
703 p3.y = y - d2.y + d1.y;
707 line(obj, i->tag, p1,p2, m);
708 line(obj, i->tag, p2,p3, m);
709 line(obj, i->tag, p3,p4, m);
710 line(obj, i->tag, p4,p1, m);
713 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)
715 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
716 SWF_OUTLINE*tmp=outline;
719 assert(i->shapeid>=0);
722 drawT1toRect(obj, x, y, m,outline, num, line_cap, line_join, line_width);
724 while(tmp->link && tmp->link->type!=SWF_PATHTYPE_MOVE) {
725 xx += (tmp->dest.x/(float)0xffff);
726 yy += (tmp->dest.y/(float)0xffff);
730 assert(tmp->type == SWF_PATHTYPE_LINE);
731 assert(outline->type == SWF_PATHTYPE_LINE);
735 if(outline->link == tmp) {
736 /* the two straight line segments (which are everything we
737 need to draw) are very likely to overlap. To avoid that
738 they cancel each other out at the end points, start a new
739 shape for the second one */
740 endshape(obj,0);startshape(obj);
744 drawT1toRect(obj, xx, yy, m, tmp, num, line_cap, line_join, line_width);
746 if(outline->link != tmp)
748 stopFill(obj);stop=1;
750 tmp->type = SWF_PATHTYPE_MOVE;
751 x += (outline->dest.x/(float)0xffff);
752 y += (outline->dest.y/(float)0xffff);
753 outline = outline->link;
754 drawShortPath(obj, x, y, m, outline);
762 static int t1len(struct swfoutput*obj, SWF_OUTLINE*line)
764 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
766 while(line && line->type != SWF_PATHTYPE_MOVE) {
773 static float t1linelen(struct swfoutput*obj, SWF_OUTLINE*line)
775 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
777 x = (line->dest.x/(float)0xffff);
778 y = (line->dest.y/(float)0xffff);
779 return sqrt(x*x+y*y);
782 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)
784 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
785 if( i->tag->id != ST_DEFINESHAPE &&
786 i->tag->id != ST_DEFINESHAPE2 &&
787 i->tag->id != ST_DEFINESHAPE3) {
788 msg("<error> internal error: drawpath needs a shape tag, not %d\n",i->tag->id);
791 assert(i->shapeid>=0);
793 double lastx=0,lasty=0;
796 SWF_OUTLINE*tmp = outline, *last = 0;
801 x += (tmp->dest.x/(float)0xffff);
802 y += (tmp->dest.y/(float)0xffff);
804 if(!tmp || tmp->type == SWF_PATHTYPE_MOVE) {
806 if(last->type == SWF_PATHTYPE_LINE && t1linelen(obj,last)>line_width*2 &&
807 lastwasline && line_cap != LINE_CAP_ROUND)
808 drawShortPathWithStraightEnds(obj, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
810 drawShortPathWithEnds(obj, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
824 if(tmp && tmp->type == SWF_PATHTYPE_LINE && t1linelen(obj,tmp)>line_width*2)
830 tmp->link->last = tmp; // make sure list is properly linked in both directions
835 static inline int colorcompare(struct swfoutput*obj, RGBA*a,RGBA*b)
847 static SRECT getcharacterbbox(struct swfoutput*obj, SWFFONT*font)
849 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
852 memset(&r, 0, sizeof(r));
855 if(debug) printf("\n");
856 for(t=0;t<i->chardatapos;t++)
858 if(i->chardata[t].fontid != font->id) {
859 msg("<error> Internal error: fontid %d != fontid %d", i->chardata[t].fontid, font->id);
862 SRECT b = font->layout->bounds[i->chardata[t].charid];
863 b.xmin *= i->chardata[t].size;
864 b.ymin *= i->chardata[t].size;
865 b.xmax *= i->chardata[t].size;
866 b.ymax *= i->chardata[t].size;
871 b.xmin += i->chardata[t].x;
872 b.ymin += i->chardata[t].y;
873 b.xmax += i->chardata[t].x;
874 b.ymax += i->chardata[t].y;
876 /* until we solve the INTERNAL_SCALING problem (see below)
877 make sure the bounding box is big enough */
883 if(debug) printf("(%f,%f,%f,%f) -> (%f,%f,%f,%f) [font %d/%d, char %d]\n",
884 font->layout->bounds[i->chardata[t].charid].xmin/20.0,
885 font->layout->bounds[i->chardata[t].charid].ymin/20.0,
886 font->layout->bounds[i->chardata[t].charid].xmax/20.0,
887 font->layout->bounds[i->chardata[t].charid].ymax/20.0,
892 i->chardata[t].fontid,
894 i->chardata[t].charid
896 swf_ExpandRect2(&r, &b);
898 if(debug) printf("-----> (%f,%f,%f,%f)\n",
906 static void putcharacters(struct swfoutput*obj, TAG*tag)
908 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
912 color.r = i->chardata[0].color.r^255;
921 int charadvance[128];
924 int glyphbits=1; //TODO: can this be zero?
927 if(tag->id != ST_DEFINETEXT &&
928 tag->id != ST_DEFINETEXT2) {
929 msg("<error> internal error: putcharacters needs an text tag, not %d\n",tag->id);
932 if(!i->chardatapos) {
933 msg("<warning> putcharacters called with zero characters");
936 for(pass = 0; pass < 2; pass++)
946 advancebits++; // add sign bit
947 swf_SetU8(tag, glyphbits);
948 swf_SetU8(tag, advancebits);
951 for(t=0;t<=i->chardatapos;t++)
953 if(lastfontid != i->chardata[t].fontid ||
954 lastx!=i->chardata[t].x ||
955 lasty!=i->chardata[t].y ||
956 !colorcompare(obj,&color, &i->chardata[t].color) ||
958 lastsize != i->chardata[t].size ||
961 if(charstorepos && pass==0)
964 for(s=0;s<charstorepos;s++)
966 while(charids[s]>=(1<<glyphbits))
968 while(charadvance[s]>=(1<<advancebits))
972 if(charstorepos && pass==1)
974 tag->writeBit = 0; // Q&D
975 swf_SetBits(tag, 0, 1); // GLYPH Record
976 swf_SetBits(tag, charstorepos, 7); // number of glyphs
978 for(s=0;s<charstorepos;s++)
980 swf_SetBits(tag, charids[s], glyphbits);
981 swf_SetBits(tag, charadvance[s], advancebits);
986 if(pass == 1 && t<i->chardatapos)
992 if(lastx != i->chardata[t].x ||
993 lasty != i->chardata[t].y)
995 newx = i->chardata[t].x;
996 newy = i->chardata[t].y;
1002 if(!colorcompare(obj,&color, &i->chardata[t].color))
1004 color = i->chardata[t].color;
1007 font.id = i->chardata[t].fontid;
1008 if(lastfontid != i->chardata[t].fontid || lastsize != i->chardata[t].size)
1011 tag->writeBit = 0; // Q&D
1012 swf_TextSetInfoRecord(tag, newfont, i->chardata[t].size, newcolor, newx,newy);
1015 lastfontid = i->chardata[t].fontid;
1016 lastx = i->chardata[t].x;
1017 lasty = i->chardata[t].y;
1018 lastsize = i->chardata[t].size;
1021 if(t==i->chardatapos)
1025 int nextt = t==i->chardatapos-1?t:t+1;
1026 int rel = i->chardata[nextt].x-i->chardata[t].x;
1027 if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) {
1029 lastx=i->chardata[nextt].x;
1033 lastx=i->chardata[t].x;
1035 charids[charstorepos] = i->chardata[t].charid;
1036 charadvance[charstorepos] = advance;
1043 static void putcharacter(struct swfoutput*obj, int fontid, int charid,
1044 int x,int y, int size)
1046 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1047 if(i->chardatapos == CHARDATAMAX)
1049 msg("<warning> Character buffer too small. SWF will be slightly bigger");
1053 i->chardata[i->chardatapos].fontid = fontid;
1054 i->chardata[i->chardatapos].charid = charid;
1055 i->chardata[i->chardatapos].x = x;
1056 i->chardata[i->chardatapos].y = y;
1057 i->chardata[i->chardatapos].color = obj->fillrgb;
1058 i->chardata[i->chardatapos].size = size;
1062 /* Notice: we can only put chars in the range -1639,1638 (-32768/20,32768/20).
1063 So if we set this value to high, the char coordinates will overflow.
1064 If we set it to low, however, the char positions will be inaccurate */
1065 #define FONT_INTERNAL_SIZE 4
1067 /* process a character. */
1068 static int drawchar(struct swfoutput*obj, SWFFONT *swffont, char*character, int charnr, int u, swfmatrix*m)
1070 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1072 msg("<warning> Font is NULL");
1076 int charid = getCharID(swffont, charnr, character, u);
1079 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1080 FIXNULL(character),charnr, u, FIXNULL((char*)swffont->name), swffont->numchars);
1091 float det = ((m->m11*m->m22)-(m->m21*m->m12));
1092 if(fabs(det) < 0.0005) {
1093 /* x direction equals y direction- the text is invisible */
1096 det = 20*FONT_INTERNAL_SIZE / det;
1099 p.x = (SCOORD)(( x * m->m22 - y * m->m12)*det);
1100 p.y = (SCOORD)((- x * m->m21 + y * m->m11)*det);
1102 putcharacter(obj, swffont->id, charid,p.x,p.y,FONT_INTERNAL_SIZE);
1103 swf_FontUseGlyph(swffont, charid);
1108 SWF_OUTLINE*outline = font->getOutline(character, charnr);
1109 char* charname = character;
1112 msg("<warning> Didn't find character '%s' (%d) in current charset (%s)",
1113 FIXNULL(character),charnr,FIXNULL(font->getName()));
1132 drawpath(tag, outline, &m2, 0);
1137 static void endtext(swfoutput*obj)
1139 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1143 i->tag = swf_InsertTag(i->tag,ST_DEFINETEXT);
1144 swf_SetU16(i->tag, i->textid);
1147 r = getcharacterbbox(obj, obj->swffont);
1149 swf_SetRect(i->tag,&r);
1152 swf_GetMatrix(0, &m);
1153 swf_SetMatrix(i->tag,&m);
1155 putcharacters(obj, i->tag);
1156 swf_SetU8(i->tag,0);
1157 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
1158 swf_ObjectPlace(i->tag,i->textid,/*depth*/i->depth++,&obj->fontmatrix,NULL,NULL);
1163 /* draw a curved polygon. */
1164 void swfoutput_drawpath(swfoutput*obj, SWF_OUTLINE*outline,
1167 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1171 /* Multiple polygons in one shape don't overlap correctly,
1172 so we better start a new shape here if the polygon is filled
1174 if(i->shapeid>=0 && i->fill && !config_ignoredraworder) {
1187 drawpath(obj, outline,m, 0);
1190 void swfoutput_drawpath2poly(struct swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
1192 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1197 assert(i->shapeid<0);
1201 drawpath2poly(obj, outline, m, 0, line_join, line_cap, line_width, miter_limit);
1204 int getCharID(SWFFONT *font, int charnr, char *charname, int u)
1207 if(charname && font->glyphnames) {
1208 for(t=0;t<font->numchars;t++) {
1209 if(font->glyphnames[t] && !strcmp(font->glyphnames[t],charname)) {
1210 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1214 /* if we didn't find the character, maybe
1215 we can find the capitalized version */
1216 for(t=0;t<font->numchars;t++) {
1217 if(font->glyphnames[t] && !strcasecmp(font->glyphnames[t],charname)) {
1218 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1225 /* try to use the unicode id */
1226 if(u>=0 && u<font->maxascii && font->ascii2glyph[u]>=0) {
1227 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->ascii2glyph[u]);
1228 return font->ascii2glyph[u];
1232 if(font->encoding != FONT_ENCODING_UNICODE) {
1233 /* the following only works if the font encoding
1234 is US-ASCII based. It's needed for fonts which return broken unicode
1236 if(charnr>=0 && charnr<font->maxascii && font->ascii2glyph[charnr]>=0) {
1237 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, font->ascii2glyph[charnr]);
1238 return font->ascii2glyph[charnr];
1242 if(charnr>=0 && charnr<font->numchars) {
1243 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1251 /* set's the t1 font index of the font to use for swfoutput_drawchar(). */
1252 void swfoutput_setfont(struct swfoutput*obj, char*fontid, char*filename)
1254 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1255 fontlist_t*last=0,*iterator;
1257 msg("<error> No fontid");
1261 if(obj->swffont && obj->swffont->name && !strcmp((char*)obj->swffont->name,fontid))
1264 /* TODO: remove the need for this (enhance getcharacterbbox so that it can cope
1265 with multiple fonts */
1268 iterator = i->fontlist;
1270 if(!strcmp((char*)iterator->swffont->name,fontid)) {
1271 obj->swffont = iterator->swffont;
1275 iterator = iterator->next;
1279 msg("<error> No filename given for font- internal error?");
1283 swf_SetLoadFontParameters(64,/*skip unused*/0,/*full unicode*/1);
1284 SWFFONT*swffont = swf_LoadFont(filename);
1287 msg("<warning> Couldn't load font %s (%s)", fontid, filename);
1288 swffont = swf_LoadFont(0);
1291 swf_FontSetID(swffont, ++i->currentswfid);
1293 if(screenloglevel >= LOGLEVEL_DEBUG) {
1294 // print font information
1295 msg("<debug> Font %s (%s)",swffont->name, filename);
1296 msg("<debug> | ID: %d", swffont->id);
1297 msg("<debug> | Version: %d", swffont->version);
1298 msg("<debug> | Name: %s", fontid);
1299 msg("<debug> | Numchars: %d", swffont->numchars);
1300 msg("<debug> | Maxascii: %d", swffont->maxascii);
1301 msg("<debug> | Style: %d", swffont->style);
1302 msg("<debug> | Encoding: %d", swffont->encoding);
1303 for(int iii=0; iii<swffont->numchars;iii++) {
1304 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,
1305 swffont->layout->bounds[iii].xmin/20.0,
1306 swffont->layout->bounds[iii].ymin/20.0,
1307 swffont->layout->bounds[iii].xmax/20.0,
1308 swffont->layout->bounds[iii].ymax/20.0
1311 for(t=0;t<swffont->maxascii;t++) {
1312 if(swffont->ascii2glyph[t] == iii)
1313 msg("<debug> | - maps to %d",t);
1318 /* set the font name to the ID we use here */
1319 if(swffont->name) free(swffont->name);
1320 swffont->name = (U8*)strdup(fontid);
1322 iterator = new fontlist_t;
1323 iterator->swffont = swffont;
1327 last->next = iterator;
1329 i->fontlist = iterator;
1331 obj->swffont = swffont;
1334 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1336 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1337 fontlist_t *iterator = i->fontlist;
1339 if(!strcmp((char*)iterator->swffont->name,fontid))
1341 iterator = iterator->next;
1346 /* set's the matrix which is to be applied to characters drawn by
1347 swfoutput_drawchar() */
1348 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1349 double m21,double m22)
1351 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1352 if(obj->fontm11 == m11 &&
1353 obj->fontm12 == m12 &&
1354 obj->fontm21 == m21 &&
1355 obj->fontm22 == m22)
1365 m.sx = (U32)(((obj->fontm11)*65536)/FONT_INTERNAL_SIZE); m.r1 = (U32)(((obj->fontm12)*65536)/FONT_INTERNAL_SIZE);
1366 m.r0 = (U32)(((obj->fontm21)*65536)/FONT_INTERNAL_SIZE); m.sy = (U32)(((obj->fontm22)*65536)/FONT_INTERNAL_SIZE);
1369 obj->fontmatrix = m;
1372 /* draws a character at x,y. */
1373 int swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr, int u)
1375 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1377 m.m11 = obj->fontm11;
1378 m.m12 = obj->fontm12;
1379 m.m21 = obj->fontm21;
1380 m.m22 = obj->fontm22;
1383 return drawchar(obj, obj->swffont, character, charnr, u, &m);
1386 static void endpage(struct swfoutput*obj)
1388 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1394 swfoutput_endclip(obj);
1396 if(config_insertstoptag) {
1398 atag = action_Stop(atag);
1399 atag = action_End(atag);
1400 i->tag = swf_InsertTag(i->tag,ST_DOACTION);
1401 swf_ActionSet(i->tag,atag);
1403 i->tag = swf_InsertTag(i->tag,ST_SHOWFRAME);
1406 void swfoutput_newpage(struct swfoutput*obj, int pageNum, int x1, int y1, int x2, int y2)
1408 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1412 for(i->depth--;i->depth>=i->startdepth;i->depth--) {
1413 i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2);
1414 swf_SetU16(i->tag,i->depth);
1416 i->depth = i->startdepth = 3; /* leave room for clip and background rectangle */
1420 x1*=20;y1*=20;x2*=20;y2*=20;
1422 if(i->lastpagesize.xmin != x1 ||
1423 i->lastpagesize.xmax != x2 ||
1424 i->lastpagesize.ymin != y1 ||
1425 i->lastpagesize.ymax != y2)
1426 {/* add white clipping rectangle */
1427 msg("<notice> processing page %d (%dx%d)", pageNum,i->sizex,i->sizey);
1430 msg("<notice> Page has a different size than previous ones");
1431 i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2);
1432 swf_SetU16(i->tag,1);
1433 i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2);
1434 swf_SetU16(i->tag,2);
1438 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1442 int shapeid = ++i->currentswfid;
1447 i->tag = swf_InsertTag(i->tag, ST_DEFINESHAPE);
1449 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1450 swf_SetU16(i->tag,shapeid);
1451 swf_SetRect(i->tag,&r);
1452 swf_SetShapeHeader(i->tag,s);
1453 swf_ShapeSetAll(i->tag,s,x1,y1,ls1,fs1,0);
1454 swf_ShapeSetLine(i->tag,s,(x2-x1),0);
1455 swf_ShapeSetLine(i->tag,s,0,(y2-y1));
1456 swf_ShapeSetLine(i->tag,s,(x1-x2),0);
1457 swf_ShapeSetLine(i->tag,s,0,(y1-y2));
1458 swf_ShapeSetEnd(i->tag);
1460 i->tag = swf_InsertTag(i->tag, ST_PLACEOBJECT2);
1461 swf_ObjectPlace(i->tag,shapeid,/*depth*/1,0,0,0);
1462 i->tag = swf_InsertTag(i->tag, ST_PLACEOBJECT2);
1463 swf_ObjectPlaceClip(i->tag,shapeid,/*depth*/2,0,0,0,65535);
1465 msg("<notice> processing page %d", pageNum);
1468 i->lastpagesize.xmin = x1;
1469 i->lastpagesize.xmax = x2;
1470 i->lastpagesize.ymin = y1;
1471 i->lastpagesize.ymax = y2;
1472 swf_ExpandRect2(&i->swf.movieSize, &i->lastpagesize);
1477 /* initialize the swf writer */
1478 void swfoutput_init(struct swfoutput* obj)
1480 memset(obj, 0, sizeof(struct swfoutput));
1481 obj->internal = init_internal_struct();
1483 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1488 msg("<verbose> initializing swf output for size %d*%d\n", i->sizex,i->sizey);
1493 memset(&i->swf,0x00,sizeof(SWF));
1494 memset(&i->lastpagesize,0x00,sizeof(SRECT));
1496 i->swf.fileVersion = config_flashversion;
1497 i->swf.frameRate = 0x0040; // 1 frame per 4 seconds
1498 i->swf.movieSize.xmin = 0;
1499 i->swf.movieSize.ymin = 0;
1500 i->swf.movieSize.xmax = 0;
1501 i->swf.movieSize.ymax = 0;
1503 i->swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1504 i->tag = i->swf.firstTag;
1505 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1506 swf_SetRGB(i->tag,&rgb);
1508 i->startdepth = i->depth = 0;
1511 i->tag = swf_InsertTag(i->tag, ST_PROTECT);
1514 static void startshape(struct swfoutput*obj)
1516 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1523 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE);
1525 swf_ShapeNew(&i->shape);
1526 i->linestyleid = swf_ShapeAddLineStyle(i->shape,i->linewidth,&obj->strokergb);
1527 rgb.r = obj->fillrgb.r;
1528 rgb.g = obj->fillrgb.g;
1529 rgb.b = obj->fillrgb.b;
1530 i->fillstyleid = swf_ShapeAddSolidFillStyle(i->shape,&obj->fillrgb);
1532 i->shapeid = ++i->currentswfid;
1533 swf_SetU16(i->tag,i->shapeid); // ID
1535 i->bboxrectpos = i->tag->len;
1538 r.xmax = 20*i->sizex;
1539 r.ymax = 20*i->sizey;
1540 swf_SetRect(i->tag,&r);
1542 memset(&i->bboxrect, 0, sizeof(i->bboxrect));
1544 swf_SetShapeStyles(i->tag,i->shape);
1545 swf_ShapeCountBits(i->shape,NULL,NULL);
1546 swf_SetShapeBits(i->tag,i->shape);
1548 /* TODO: do we really need this? */
1549 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,i->linestyleid,0,0);
1550 i->swflastx=i->swflasty=0;
1552 i->shapeisempty = 1;
1555 static void starttext(struct swfoutput*obj)
1557 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1561 i->textid = ++i->currentswfid;
1563 i->swflastx=i->swflasty=0;
1567 /* TODO: move to ../lib/rfxswf */
1568 void changeRect(struct swfoutput*obj, TAG*tag, int pos, SRECT*newrect)
1570 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1571 /* determine length of old rect */
1575 swf_GetRect(tag, &old);
1576 swf_ResetReadBits(tag);
1577 int pos_end = tag->pos;
1579 int len = tag->len - pos_end;
1580 U8*data = (U8*)malloc(len);
1581 memcpy(data, &tag->data[pos_end], len);
1584 swf_SetRect(tag, newrect);
1585 swf_SetBlock(tag, data, len);
1587 tag->pos = tag->readBit = 0;
1590 void cancelshape(swfoutput*obj)
1592 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1593 /* delete old shape tag */
1595 i->tag = i->tag->prev;
1596 swf_DeleteTag(todel);
1597 if(i->shape) {swf_ShapeFree(i->shape);i->shape=0;}
1599 i->bboxrectpos = -1;
1602 void fixAreas(swfoutput*obj)
1604 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1605 if(!i->shapeisempty && i->fill &&
1606 (i->bboxrect.xmin == i->bboxrect.xmax ||
1607 i->bboxrect.ymin == i->bboxrect.ymax) &&
1608 config_minlinewidth >= 0.001
1610 msg("<debug> Shape has size 0: width=%.2f height=%.2f",
1611 (i->bboxrect.xmax-i->bboxrect.xmin)/20.0,
1612 (i->bboxrect.ymax-i->bboxrect.ymin)/20.0
1615 SRECT r = i->bboxrect;
1617 if(r.xmin == r.xmax && r.ymin == r.ymax) {
1618 /* this thing comes down to a single dot- nothing to fix here */
1624 RGBA save_col = obj->strokergb;
1625 int save_width = i->linewidth;
1627 obj->strokergb = obj->fillrgb;
1628 i->linewidth = (int)(config_minlinewidth*20);
1629 if(i->linewidth==0) i->linewidth = 1;
1633 moveto(obj, i->tag, r.xmin/20.0,r.ymin/20.0);
1634 lineto(obj, i->tag, r.xmax/20.0,r.ymax/20.0);
1636 obj->strokergb = save_col;
1637 i->linewidth = save_width;
1642 static void endshape_noput(swfoutput*obj)
1644 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1647 //changeRect(obj, i->tag, i->bboxrectpos, &i->bboxrect);
1650 swf_ShapeFree(i->shape);
1655 static void endshape(swfoutput*obj, int clipdepth)
1657 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1664 if(i->shapeisempty ||
1665 (i->bboxrect.xmin == i->bboxrect.xmax &&
1666 i->bboxrect.ymin == i->bboxrect.ymax))
1668 // delete the shape again, we didn't do anything
1673 swf_ShapeSetEnd(i->tag);
1675 changeRect(obj, i->tag, i->bboxrectpos, &i->bboxrect);
1677 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
1679 swf_ObjectPlaceClip(i->tag,i->shapeid,i->depth++,NULL,NULL,NULL,clipdepth);
1681 swf_ObjectPlace(i->tag,i->shapeid,/*depth*/i->depth++,NULL,NULL,NULL);
1683 swf_ShapeFree(i->shape);
1686 i->bboxrectpos = -1;
1689 void swfoutput_save(struct swfoutput* obj, char*filename)
1691 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1693 fontlist_t *tmp,*iterator = i->fontlist;
1695 TAG*mtag = i->swf.firstTag;
1696 if(iterator->swffont) {
1697 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1698 /*if(!storeallcharacters)
1699 swf_FontReduce(iterator->swffont);*/
1700 swf_FontSetDefine2(mtag, iterator->swffont);
1703 iterator = iterator->next;
1708 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1713 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1717 i->tag = swf_InsertTag(i->tag,ST_END);
1719 if(config_enablezlib || config_flashversion>=6) {
1720 if FAILED(swf_WriteSWC(fi,&i->swf))
1721 msg("<error> WriteSWC() failed.\n");
1723 if FAILED(swf_WriteSWF(fi,&i->swf))
1724 msg("<error> WriteSWF() failed.\n");
1729 msg("<notice> SWF written\n");
1732 /* Perform cleaning up, complete the swf, and write it out. */
1733 void swfoutput_destroy(struct swfoutput* obj)
1735 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1737 fontlist_t *tmp,*iterator = i->fontlist;
1739 if(iterator->swffont) {
1740 swf_FontFree(iterator->swffont);
1743 iterator = iterator->next;
1746 swf_FreeTags(&i->swf);
1749 memset(obj, 0, sizeof(swfoutput));
1752 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1754 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1755 obj->drawmode = mode;
1756 if(mode == DRAWMODE_FILL)
1758 else if(mode == DRAWMODE_EOFILL)
1760 else if(mode == DRAWMODE_STROKE)
1762 else if(mode == DRAWMODE_CLIP)
1764 else if(mode == DRAWMODE_EOCLIP)
1768 void swfoutput_setfillcolor(swfoutput* obj, U8 r, U8 g, U8 b, U8 a)
1770 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1771 if(obj->fillrgb.r == r &&
1772 obj->fillrgb.g == g &&
1773 obj->fillrgb.b == b &&
1774 obj->fillrgb.a == a) return;
1784 void swfoutput_setstrokecolor(swfoutput* obj, U8 r, U8 g, U8 b, U8 a)
1786 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1787 if(obj->strokergb.r == r &&
1788 obj->strokergb.g == g &&
1789 obj->strokergb.b == b &&
1790 obj->strokergb.a == a) return;
1794 obj->strokergb.r = r;
1795 obj->strokergb.g = g;
1796 obj->strokergb.b = b;
1797 obj->strokergb.a = a;
1800 void swfoutput_setlinewidth(struct swfoutput*obj, double _linewidth)
1802 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1803 if(i->linewidth == (U16)(_linewidth*20))
1808 i->linewidth = (U16)(_linewidth*20);
1812 void swfoutput_startclip(swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m)
1814 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1820 if(i->clippos >= 127)
1822 msg("<warning> Too many clip levels.");
1827 int olddrawmode = obj->drawmode;
1828 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1829 swfoutput_drawpath(obj, outline, m);
1830 swf_ShapeSetEnd(i->tag);
1831 swfoutput_setdrawmode(obj, olddrawmode);
1833 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
1834 i->cliptags[i->clippos] = i->tag;
1835 i->clipshapes[i->clippos] = i->shapeid;
1836 i->clipdepths[i->clippos] = i->depth++;
1839 endshape_noput(obj);
1842 void swfoutput_endclip(swfoutput*obj)
1844 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1851 msg("<error> Invalid end of clipping region");
1855 swf_ObjectPlaceClip(i->cliptags[i->clippos],i->clipshapes[i->clippos],i->clipdepths[i->clippos],NULL,NULL,NULL,i->depth++);
1858 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1860 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1862 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1864 if(!strncmp("http://pdf2swf:", url, 15)) {
1865 char*tmp = strdup(url);
1866 int l = strlen(tmp);
1869 swfoutput_namedlink(obj, tmp+15, points);
1879 if(config_opennewwindow)
1880 actions = action_GetUrl(0, url, "_parent");
1882 actions = action_GetUrl(0, url, "_this");
1883 actions = action_End(actions);
1885 drawlink(obj, actions, 0, points,0);
1887 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1889 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1897 actions = action_GotoFrame(0, page);
1898 actions = action_End(actions);
1900 drawlink(obj, actions, 0, points,0);
1903 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
1904 of the viewer objects, like subtitles, index elements etc.
1906 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
1908 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1909 ActionTAG *actions1,*actions2;
1910 char*tmp = strdup(name);
1918 if(!strncmp(tmp, "call:", 5))
1920 char*x = strchr(&tmp[5], ':');
1922 actions1 = action_PushInt(0, 0); //number of parameters (0)
1923 actions1 = action_PushString(actions1, &tmp[5]); //function name
1924 actions1 = action_CallFunction(actions1);
1927 actions1 = action_PushString(0, x+1); //parameter
1928 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
1929 actions1 = action_PushString(actions1, &tmp[5]); //function name
1930 actions1 = action_CallFunction(actions1);
1932 actions2 = action_End(0);
1937 actions1 = action_PushString(0, "/:subtitle");
1938 actions1 = action_PushString(actions1, name);
1939 actions1 = action_SetVariable(actions1);
1940 actions1 = action_End(actions1);
1942 actions2 = action_PushString(0, "/:subtitle");
1943 actions2 = action_PushString(actions2, "");
1944 actions2 = action_SetVariable(actions2);
1945 actions2 = action_End(actions2);
1948 drawlink(obj, actions1, actions2, points,mouseover);
1950 swf_ActionFree(actions1);
1951 swf_ActionFree(actions2);
1955 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
1957 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1962 struct plotxy p1,p2,p3,p4;
1966 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
1970 int buttonid = ++i->currentswfid;
1973 if(points[t].x>xmax) xmax=points[t].x;
1974 if(points[t].y>ymax) ymax=points[t].y;
1975 if(points[t].x<xmin) xmin=points[t].x;
1976 if(points[t].y<ymin) ymin=points[t].y;
1979 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
1980 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
1982 /* the following code subtracts the upper left edge from all coordinates,
1983 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
1984 Necessary for preprocessing with swfcombine. */
1985 posx = xmin; posy = ymin;
1986 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
1987 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
1988 xmin -= posx; ymin -= posy;
1989 xmax -= posx; ymax -= posy;
1992 myshapeid = ++i->currentswfid;
1993 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE3);
1994 swf_ShapeNew(&i->shape);
1995 rgb.r = rgb.b = rgb.a = rgb.g = 0;
1996 fsid = swf_ShapeAddSolidFillStyle(i->shape,&rgb);
1997 swf_SetU16(i->tag, myshapeid);
1998 r.xmin = (int)(xmin*20);
1999 r.ymin = (int)(ymin*20);
2000 r.xmax = (int)(xmax*20);
2001 r.ymax = (int)(ymax*20);
2002 swf_SetRect(i->tag,&r);
2003 swf_SetShapeStyles(i->tag,i->shape);
2004 swf_ShapeCountBits(i->shape,NULL,NULL);
2005 swf_SetShapeBits(i->tag,i->shape);
2006 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,0,fsid,0);
2007 i->swflastx = i->swflasty = 0;
2008 moveto(obj, i->tag, p1);
2009 lineto(obj, i->tag, p2);
2010 lineto(obj, i->tag, p3);
2011 lineto(obj, i->tag, p4);
2012 lineto(obj, i->tag, p1);
2013 swf_ShapeSetEnd(i->tag);
2016 myshapeid2 = ++i->currentswfid;
2017 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE3);
2018 swf_ShapeNew(&i->shape);
2019 rgb.r = rgb.b = rgb.a = rgb.g = 255;
2021 fsid = swf_ShapeAddSolidFillStyle(i->shape,&rgb);
2022 swf_SetU16(i->tag, myshapeid2);
2023 r.xmin = (int)(xmin*20);
2024 r.ymin = (int)(ymin*20);
2025 r.xmax = (int)(xmax*20);
2026 r.ymax = (int)(ymax*20);
2027 swf_SetRect(i->tag,&r);
2028 swf_SetShapeStyles(i->tag,i->shape);
2029 swf_ShapeCountBits(i->shape,NULL,NULL);
2030 swf_SetShapeBits(i->tag,i->shape);
2031 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,0,fsid,0);
2032 i->swflastx = i->swflasty = 0;
2033 moveto(obj, i->tag, p1);
2034 lineto(obj, i->tag, p2);
2035 lineto(obj, i->tag, p3);
2036 lineto(obj, i->tag, p4);
2037 lineto(obj, i->tag, p1);
2038 swf_ShapeSetEnd(i->tag);
2042 i->tag = swf_InsertTag(i->tag,ST_DEFINEBUTTON);
2043 swf_SetU16(i->tag,buttonid); //id
2044 swf_ButtonSetFlags(i->tag, 0); //menu=no
2045 swf_ButtonSetRecord(i->tag,0x01,myshapeid,i->depth,0,0);
2046 swf_ButtonSetRecord(i->tag,0x02,myshapeid2,i->depth,0,0);
2047 swf_ButtonSetRecord(i->tag,0x04,myshapeid2,i->depth,0,0);
2048 swf_ButtonSetRecord(i->tag,0x08,myshapeid,i->depth,0,0);
2049 swf_SetU8(i->tag,0);
2050 swf_ActionSet(i->tag,actions1);
2051 swf_SetU8(i->tag,0);
2055 i->tag = swf_InsertTag(i->tag,ST_DEFINEBUTTON2);
2056 swf_SetU16(i->tag,buttonid); //id
2057 swf_ButtonSetFlags(i->tag, 0); //menu=no
2058 swf_ButtonSetRecord(i->tag,0x01,myshapeid,i->depth,0,0);
2059 swf_ButtonSetRecord(i->tag,0x02,myshapeid2,i->depth,0,0);
2060 swf_ButtonSetRecord(i->tag,0x04,myshapeid2,i->depth,0,0);
2061 swf_ButtonSetRecord(i->tag,0x08,myshapeid,i->depth,0,0);
2062 swf_SetU8(i->tag,0); // end of button records
2063 swf_ButtonSetCondition(i->tag, BC_IDLE_OVERUP);
2064 swf_ActionSet(i->tag,actions1);
2066 swf_ButtonSetCondition(i->tag, BC_OVERUP_IDLE);
2067 swf_ActionSet(i->tag,actions2);
2068 swf_SetU8(i->tag,0);
2069 swf_ButtonPostProcess(i->tag, 2);
2071 swf_SetU8(i->tag,0);
2072 swf_ButtonPostProcess(i->tag, 1);
2076 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
2078 if(posx!=0 || posy!=0) {
2080 swf_GetMatrix(0,&m);
2081 m.tx = (int)(posx*20);
2082 m.ty = (int)(posy*20);
2083 swf_ObjectPlace(i->tag, buttonid, i->depth++,&m,0,0);
2086 swf_ObjectPlace(i->tag, buttonid, i->depth++,0,0,0);
2090 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
2091 double x1,double y1,
2092 double x2,double y2,
2093 double x3,double y3,
2094 double x4,double y4)
2096 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2101 struct plotxy p1,p2,p3,p4;
2103 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
2104 if(x2>xmax) xmax=x2;
2105 if(y2>ymax) ymax=y2;
2106 if(x2<xmin) xmin=x2;
2107 if(y2<ymin) ymin=y2;
2108 if(x3>xmax) xmax=x3;
2109 if(y3>ymax) ymax=y3;
2110 if(x3<xmin) xmin=x3;
2111 if(y3<ymin) ymin=y3;
2112 if(x4>xmax) xmax=x4;
2113 if(y4>ymax) ymax=y4;
2114 if(x4<xmin) xmin=x4;
2115 if(y4<ymin) ymin=y4;
2121 {p1.x = (int)(p1.x*20)/20.0;
2122 p1.y = (int)(p1.y*20)/20.0;
2123 p2.x = (int)(p2.x*20)/20.0;
2124 p2.y = (int)(p2.y*20)/20.0;
2125 p3.x = (int)(p3.x*20)/20.0;
2126 p3.y = (int)(p3.y*20)/20.0;
2127 p4.x = (int)(p4.x*20)/20.0;
2128 p4.y = (int)(p4.y*20)/20.0;}
2131 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
2132 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
2133 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
2134 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
2136 m.tx = (int)(p1.x*20);
2137 m.ty = (int)(p1.y*20);
2140 myshapeid = ++i->currentswfid;
2141 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE);
2143 swf_ShapeNew(&shape);
2144 //lsid = ShapeAddLineStyle(shape,linewidth,&obj->strokergb);
2145 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
2146 fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
2147 swf_SetU16(i->tag, myshapeid);
2148 r.xmin = (int)(xmin*20);
2149 r.ymin = (int)(ymin*20);
2150 r.xmax = (int)(xmax*20);
2151 r.ymax = (int)(ymax*20);
2152 swf_SetRect(i->tag,&r);
2153 swf_SetShapeStyles(i->tag,shape);
2154 swf_ShapeCountBits(shape,NULL,NULL);
2155 swf_SetShapeBits(i->tag,shape);
2156 swf_ShapeSetAll(i->tag,shape,/*x*/0,/*y*/0,lsid,fsid,0);
2157 i->swflastx = i->swflasty = 0;
2158 moveto(obj, i->tag, p1);
2159 lineto(obj, i->tag, p2);
2160 lineto(obj, i->tag, p3);
2161 lineto(obj, i->tag, p4);
2162 lineto(obj, i->tag, p1);
2164 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
2165 ShapeSetLine (tag, shape, (int)(x1*20);
2166 ShapeSetLine (tag, shape, x*20,0);
2167 ShapeSetLine (tag, shape, 0,-y*20);
2168 ShapeSetLine (tag, shape, -x*20,0);*/
2169 swf_ShapeSetEnd(i->tag);
2170 swf_ShapeFree(shape);
2173 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
2174 swf_ObjectPlace(i->tag,myshapeid,/*depth*/i->depth++,NULL,NULL,NULL);
2177 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
2178 double x1,double y1,
2179 double x2,double y2,
2180 double x3,double y3,
2181 double x4,double y4)
2183 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2190 int bitid = ++i->currentswfid;
2192 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSJPEG2);
2193 swf_SetU16(i->tag, bitid);
2194 if(swf_SetJPEGBits(i->tag, filename, config_jpegquality)<0) {
2195 swf_DeleteTag(i->tag);
2200 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2204 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2205 double x1,double y1,
2206 double x2,double y2,
2207 double x3,double y3,
2208 double x4,double y4)
2210 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2219 int bitid = ++i->currentswfid;
2221 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSJPEG2);
2222 swf_SetU16(i->tag, bitid);
2223 swf_SetJPEGBits2(i->tag,sizex,sizey,mem,config_jpegquality);
2224 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2228 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2229 double x1,double y1,
2230 double x2,double y2,
2231 double x3,double y3,
2232 double x4,double y4)
2234 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2241 int bitid = ++i->currentswfid;
2243 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSLOSSLESS);
2244 swf_SetU16(i->tag, bitid);
2245 if(swf_SetLosslessBits(i->tag,sizex,sizey,mem, BMF_32BIT)<0) {
2246 swf_DeleteTag(i->tag);
2251 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2255 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
2256 double x1,double y1,
2257 double x2,double y2,
2258 double x3,double y3,
2259 double x4,double y4, int n)
2261 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2271 /* SWF expects scanlines to be 4 byte aligned */
2274 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
2276 for(y=0;y<sizey;y++)
2278 for(x=0;x<sizex;x++)
2279 *ptr++ = mem[y*sizex+x];
2280 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
2285 int bitid = ++i->currentswfid;
2287 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSLOSSLESS2);
2288 swf_SetU16(i->tag, bitid);
2289 if(swf_SetLosslessBitsIndexed(i->tag,sizex,sizey,mem, pal, n)<0) {
2290 swf_DeleteTag(i->tag);
2297 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2301 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
2302 double x1,double y1,
2303 double x2,double y2,
2304 double x3,double y3,
2305 double x4,double y4)
2307 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2314 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2317 void swfoutput_setparameter(char*name, char*value)
2319 if(!strcmp(name, "drawonlyshapes")) {
2320 config_drawonlyshapes = atoi(value);
2321 } else if(!strcmp(name, "ignoredraworder")) {
2322 config_ignoredraworder = atoi(value);
2323 } else if(!strcmp(name, "filloverlap")) {
2324 config_filloverlap = atoi(value);
2325 } else if(!strcmp(name, "linksopennewwindow")) {
2326 config_opennewwindow = atoi(value);
2327 } else if(!strcmp(name, "opennewwindow")) {
2328 config_opennewwindow = atoi(value);
2329 } else if(!strcmp(name, "storeallcharacters")) {
2330 config_storeallcharacters = atoi(value);
2331 } else if(!strcmp(name, "enablezlib")) {
2332 config_enablezlib = atoi(value);
2333 } else if(!strcmp(name, "insertstop")) {
2334 config_insertstoptag = atoi(value);
2335 } else if(!strcmp(name, "protected")) {
2336 config_protect = atoi(value);
2337 } else if(!strcmp(name, "flashversion")) {
2338 config_flashversion = atoi(value);
2339 } else if(!strcmp(name, "minlinewidth")) {
2340 config_minlinewidth = atof(value);
2341 } else if(!strcmp(name, "jpegquality")) {
2342 int val = atoi(value);
2344 if(val>100) val=100;
2345 config_jpegquality = val;
2346 } else if(!strcmp(name, "splinequality")) {
2347 int v = atoi(value);
2348 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2350 config_splinemaxerror = v;
2351 } else if(!strcmp(name, "fontquality")) {
2352 int v = atoi(value);
2353 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2355 config_fontsplinemaxerror = v;
2357 fprintf(stderr, "unknown parameter: %s (=%s)\n", name, value);