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