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
106 char fillstylechanged;
111 chardata_t chardata[CHARDATAMAX];
114 } swfoutput_internal;
116 static swfoutput_internal* init_internal_struct()
118 swfoutput_internal*i = (swfoutput_internal*)malloc(sizeof(swfoutput_internal));
119 memset(i, 0, sizeof(swfoutput_internal));
139 i->fillstylechanged = 0;
148 static void startshape(struct swfoutput* obj);
149 static void starttext(struct swfoutput* obj);
150 static void endshape(struct swfoutput* obj,int clip);
151 static void endtext(struct swfoutput* obj);
153 // matrix multiplication. changes p0
154 static void transform (plotxy*p0,struct swfmatrix*m)
157 x = m->m11*p0->x+m->m12*p0->y;
158 y = m->m21*p0->x+m->m22*p0->y;
163 // write a move-to command into the swf
164 static int moveto(struct swfoutput*obj, TAG*tag, plotxy p0)
166 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
167 int rx = (int)(p0.x*20);
168 int ry = (int)(p0.y*20);
169 if(rx!=i->swflastx || ry!=i->swflasty || i->fillstylechanged) {
170 swf_ShapeSetMove (tag, i->shape, rx,ry);
171 i->fillstylechanged = 0;
178 static int moveto(struct swfoutput*obj, TAG*tag, float x, float y)
180 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
184 return moveto(obj, tag, p);
186 static void addPointToBBox(struct swfoutput*obj, int px, int py)
188 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
194 swf_ExpandRect(&i->bboxrect, p);
196 swf_ExpandRect3(&i->bboxrect, p, i->linewidth*3/2);
200 // write a line-to command into the swf
201 static void lineto(struct swfoutput*obj, TAG*tag, plotxy p0)
203 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
204 int px = (int)(p0.x*20);
205 int py = (int)(p0.y*20);
206 int rx = (px-i->swflastx);
207 int ry = (py-i->swflasty);
208 /* we can't skip this for rx=0,ry=0, those
210 swf_ShapeSetLine (tag, i->shape, rx,ry);
212 addPointToBBox(obj, i->swflastx,i->swflasty);
213 addPointToBBox(obj, px,py);
219 static void lineto(struct swfoutput*obj, TAG*tag, double x, double y)
227 // write a spline-to command into the swf
228 static void splineto(struct swfoutput*obj, TAG*tag, plotxy control,plotxy end)
230 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
231 int lastlastx = i->swflastx;
232 int lastlasty = i->swflasty;
234 int cx = ((int)(control.x*20)-i->swflastx);
235 int cy = ((int)(control.y*20)-i->swflasty);
238 int ex = ((int)(end.x*20)-i->swflastx);
239 int ey = ((int)(end.y*20)-i->swflasty);
243 if(cx || cy || ex || ey) {
244 swf_ShapeSetCurve(tag, i->shape, cx,cy,ex,ey);
245 addPointToBBox(obj, lastlastx ,lastlasty );
246 addPointToBBox(obj, lastlastx+cx,lastlasty+cy);
247 addPointToBBox(obj, lastlastx+cx+ex,lastlasty+cy+ey);
252 /* write a line, given two points and the transformation
254 static void line(struct swfoutput*obj, TAG*tag, plotxy p0, plotxy p1, struct swfmatrix*m)
258 moveto(obj, tag, p0);
259 lineto(obj, tag, p1);
262 /* write a cubic (!) spline. This involves calling the approximate()
263 function out of spline.cc to convert it to a quadratic spline. */
264 static void spline(struct swfoutput*obj, TAG*tag,plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m)
266 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
268 struct qspline q[128];
282 /* fonts use a different approximation than shapes */
283 num = cspline_approximate(&c, q, config_fontsplinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
284 //num = cspline_approximate(&c, q, 10.0, APPROXIMATE_INFLECTION);
286 num = cspline_approximate(&c, q, config_splinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
290 moveto(obj, tag,q[t].start);
291 splineto(obj, tag,q[t].control, q[t].end);
295 void resetdrawer(struct swfoutput*obj)
297 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
302 static void stopFill(struct swfoutput*obj)
304 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
307 swf_ShapeSetStyle(i->tag,i->shape,i->linestyleid,0x8000,0);
308 i->fillstylechanged = 1;
312 static void startFill(struct swfoutput*obj)
314 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
317 swf_ShapeSetStyle(i->tag,i->shape,0x8000,i->fillstyleid,0);
318 i->fillstylechanged = 1;
323 /* draw an outline. These are generated by pdf2swf and by t1lib
324 (representing characters). */
325 void drawpath(struct swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m, int log)
327 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
328 if( i->tag->id != ST_DEFINESHAPE &&
329 i->tag->id != ST_DEFINESHAPE2 &&
330 i->tag->id != ST_DEFINESHAPE3)
332 msg("<error> internal error: drawpath needs a shape tag, not %d\n",i->tag->id);
336 double lastx=0,lasty=0;
337 double firstx=0,firsty=0;
342 x += (outline->dest.x/(float)0xffff);
343 y += (outline->dest.y/(float)0xffff);
344 if(outline->type == SWF_PATHTYPE_MOVE)
346 //if(!init && fill && obj->drawmode != DRAWMODE_EOFILL && !ignoredraworder) {
347 if(config_filloverlap && !init && i->fill && obj->drawmode != DRAWMODE_EOFILL) {
348 /* drawmode=FILL (not EOFILL) means that
349 seperate shapes do not cancel each other out.
350 On SWF side, we need to start a new shape for each
351 closed polygon, because SWF only knows EOFILL.
358 if(((int)(lastx*20) != (int)(firstx*20) ||
359 (int)(lasty*20) != (int)(firsty*20)) &&
368 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
369 line(obj,i->tag, p0, p1, m);
375 else if(outline->type == SWF_PATHTYPE_LINE)
383 if(log) printf("line: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
384 line(obj,i->tag, p0,p1,m);
386 else if(outline->type == SWF_PATHTYPE_BEZIER)
392 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
395 p1.x=o2->C.x/(float)0xffff+lastx;
396 p1.y=o2->C.y/(float)0xffff+lasty;
397 p2.x=o2->B.x/(float)0xffff+lastx;
398 p2.y=o2->B.y/(float)0xffff+lasty;
401 if(log) printf("spline: %f,%f -> %f,%f\n",p3.x,p3.y,p0.x,p0.y);
402 spline(obj,i->tag,p0,p1,p2,p3,m);
405 msg("<error> drawpath: unknown outline type:%d\n", outline->type);
409 outline = outline->link;
411 if(((int)(lastx*20) != (int)(firstx*20) ||
412 (int)(lasty*20) != (int)(firsty*20)) &&
421 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
422 line(obj, i->tag, p0, p1, m);
426 plotxy getPivot(struct swfoutput*obj, SWF_OUTLINE*outline, int dir, double line_width, int end, int trytwo)
428 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
429 SWF_PATHPOINT next, next2;
430 double xv=0,yv=0, xv2=0, yv2=0;
435 if(outline->type == SWF_PATHTYPE_LINE) {
436 next = outline->dest;
438 next = ((SWF_BEZIERSEGMENT*)outline)->B;
439 if(next.x==0 && next.y==0) {
440 next = ((SWF_BEZIERSEGMENT*)outline)->C;
442 if(next.x==0 && next.y==0) {
443 next = ((SWF_BEZIERSEGMENT*)outline)->dest;
447 if(trytwo && outline->last && outline->last->type != SWF_PATHTYPE_MOVE) {
448 if(outline->type == SWF_PATHTYPE_LINE) {
449 next2 = outline->last->dest;
451 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)(outline->last))->C;
452 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)(outline->last))->B;
453 next2.x = outline->last->dest.x - c.x;
454 next2.y = outline->last->dest.y - c.y;
455 if(next2.x==0 && next2.y==0) {
456 next2.x = outline->last->dest.x - b.x;
457 next2.y = outline->last->dest.y - b.y;
459 if(next2.x==0 && next2.y==0) {
460 next2.x = outline->last->dest.x;
461 next2.y = outline->last->dest.y;
467 if(outline->type == SWF_PATHTYPE_LINE) {
468 next = outline->dest;
470 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)outline)->C;
471 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)outline)->B;
472 next.x = outline->dest.x - c.x;
473 next.y = outline->dest.y - c.y;
474 if(next.x==0 && next.y==0) {
475 next.x = outline->dest.x - b.x;
476 next.y = outline->dest.y - b.y;
478 if(next.x==0 && next.y==0) {
479 next.x = outline->dest.x;
480 next.y = outline->dest.y;
484 if(trytwo && outline->link && outline->link->type != SWF_PATHTYPE_MOVE) {
485 if(outline->type == SWF_PATHTYPE_LINE) {
486 next2 = outline->link->dest;
488 next2 = ((SWF_BEZIERSEGMENT*)(outline->link))->B;
489 if(next2.x==0 && next2.y==0) {
490 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->C;
492 if(next2.x==0 && next2.y==0) {
493 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->dest;
501 xv = next.y/(float)0xffff;
502 yv = -next.x/(float)0xffff;
504 xv = -next.y/(float)0xffff;
505 yv = next.x/(float)0xffff;
508 double r = (line_width/2)/sqrt(xv*xv+yv*yv);
514 xv2 = next2.y/(float)0xffff;
515 yv2 = -next2.x/(float)0xffff;
517 xv2 = -next2.y/(float)0xffff;
518 yv2 = next2.x/(float)0xffff;
521 double r2 = (line_width/2)/sqrt(xv2*xv2+yv2*yv2);
526 double r3 = (line_width/2)/sqrt(xv*xv+yv*yv);
536 void drawShortPath(struct swfoutput*obj, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline)
538 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
539 double lastx=x, lasty=y;
540 while (outline && outline->type != SWF_PATHTYPE_MOVE)
542 x += (outline->dest.x/(float)0xffff);
543 y += (outline->dest.y/(float)0xffff);
545 if(outline->type == SWF_PATHTYPE_LINE)
552 line(obj, i->tag, p0, p1, m);
554 else if(outline->type == SWF_PATHTYPE_BEZIER)
557 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
560 p1.x=o2->C.x/(float)0xffff+lastx;
561 p1.y=o2->C.y/(float)0xffff+lasty;
562 p2.x=o2->B.x/(float)0xffff+lastx;
563 p2.y=o2->B.y/(float)0xffff+lasty;
566 spline(obj, i->tag,p0,p1,p2,p3,m);
570 outline = outline->link;
574 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)
576 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
580 if(line_cap == LINE_CAP_BUTT || line_cap == LINE_CAP_SQUARE) {
583 SWF_OUTLINE *last, *tmp=outline;
584 plotxy s,e,p0,p1,p2,p3,m0,m1,m2,m3;
590 while(tmp && tmp->type != SWF_PATHTYPE_MOVE) {
592 lx += (tmp->dest.x/(float)0xffff);
593 ly += (tmp->dest.y/(float)0xffff);
596 s = getPivot(obj, outline, 0, line_width, 0, 0);
597 e = getPivot(obj, last, 0, line_width, 1, 0);
599 if(line_cap == LINE_CAP_BUTT) {
600 /* make the clipping rectangle slighly bigger
601 than the line ending, so that it get's clipped
611 p2.x = x2 - s.y - s.x*ee;
612 p2.y = y2 + s.x - s.y*ee;
613 p3.x = x2 - s.y + s.x*ee;
614 p3.y = y2 + s.x + s.y*ee;
619 m2.x = lx + e.y - e.x*ee;
620 m2.y = ly - e.x - e.y*ee;
621 m3.x = lx + e.y + e.x*ee;
622 m3.y = ly - e.x + e.y*ee;
624 for(nr=0;nr<2;nr++) {
626 struct plotxy q0,q1,q2,q3,q4,q5;
629 if(line_cap == LINE_CAP_BUTT) {
631 /* FIXME: box should be smaller */
633 q1.x = i->sizex; q1.y = 0;
634 q2.x = i->sizex; q2.y = i->sizey;
635 q3.x = 0; q3.y = i->sizey;
637 /* FIXME: box should be smaller */
638 q0.x = i->sizex; q0.y = i->sizey;
639 q1.x = 0; q1.y = i->sizey;
641 q3.x = i->sizex; q3.y = 0;
645 moveto(obj, i->tag, q0);
646 lineto(obj, i->tag, q1);
647 lineto(obj, i->tag, q2);
648 lineto(obj, i->tag, q3);
649 lineto(obj, i->tag, q0);
652 lineto(obj, i->tag, q4);
655 line(obj, i->tag, p0, p1, m);
656 line(obj, i->tag, p1, p2, m);
657 line(obj, i->tag, p2, p3, m);
658 line(obj, i->tag, p3, p0, m);
660 if(line_cap == LINE_CAP_BUTT) {
661 lineto(obj, i->tag, q0);
662 endshape(obj, i->depth+2-nr);
674 drawShortPath(obj,x,y,m,outline);
676 if(line_cap == LINE_CAP_BUTT) {
682 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)
684 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
685 plotxy d1,d2,p1,p2,p3,p4;
687 d1.x = (outline->dest.x/(float)0xffff);
688 d1.y = (outline->dest.y/(float)0xffff);
689 d2 = getPivot(obj, outline, 0, line_width, 0, 0);
691 assert(line_cap != LINE_CAP_ROUND);
692 if(line_cap == LINE_CAP_SQUARE) {
701 p2.x = x + d2.x + d1.x;
702 p2.y = y + d2.y + d1.y;
703 p3.x = x - d2.x + d1.x;
704 p3.y = y - d2.y + d1.y;
708 line(obj, i->tag, p1,p2, m);
709 line(obj, i->tag, p2,p3, m);
710 line(obj, i->tag, p3,p4, m);
711 line(obj, i->tag, p4,p1, m);
714 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)
716 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
717 SWF_OUTLINE*tmp=outline;
720 assert(i->shapeid>=0);
723 drawT1toRect(obj, x, y, m,outline, num, line_cap, line_join, line_width);
725 while(tmp->link && tmp->link->type!=SWF_PATHTYPE_MOVE) {
726 xx += (tmp->dest.x/(float)0xffff);
727 yy += (tmp->dest.y/(float)0xffff);
731 assert(tmp->type == SWF_PATHTYPE_LINE);
732 assert(outline->type == SWF_PATHTYPE_LINE);
736 if(outline->link == tmp) {
737 /* the two straight line segments (which are everything we
738 need to draw) are very likely to overlap. To avoid that
739 they cancel each other out at the end points, start a new
740 shape for the second one */
741 endshape(obj,0);startshape(obj);
745 drawT1toRect(obj, xx, yy, m, tmp, num, line_cap, line_join, line_width);
747 if(outline->link != tmp)
749 stopFill(obj);stop=1;
751 tmp->type = SWF_PATHTYPE_MOVE;
752 x += (outline->dest.x/(float)0xffff);
753 y += (outline->dest.y/(float)0xffff);
754 outline = outline->link;
755 drawShortPath(obj, x, y, m, outline);
763 static int t1len(struct swfoutput*obj, SWF_OUTLINE*line)
765 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
767 while(line && line->type != SWF_PATHTYPE_MOVE) {
774 static float t1linelen(struct swfoutput*obj, SWF_OUTLINE*line)
776 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
778 x = (line->dest.x/(float)0xffff);
779 y = (line->dest.y/(float)0xffff);
780 return sqrt(x*x+y*y);
783 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)
785 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
786 if( i->tag->id != ST_DEFINESHAPE &&
787 i->tag->id != ST_DEFINESHAPE2 &&
788 i->tag->id != ST_DEFINESHAPE3) {
789 msg("<error> internal error: drawpath needs a shape tag, not %d\n",i->tag->id);
792 assert(i->shapeid>=0);
794 double lastx=0,lasty=0;
797 SWF_OUTLINE*tmp = outline, *last = 0;
802 x += (tmp->dest.x/(float)0xffff);
803 y += (tmp->dest.y/(float)0xffff);
805 if(!tmp || tmp->type == SWF_PATHTYPE_MOVE) {
807 if(last->type == SWF_PATHTYPE_LINE && t1linelen(obj,last)>line_width*2 &&
808 lastwasline && line_cap != LINE_CAP_ROUND)
809 drawShortPathWithStraightEnds(obj, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
811 drawShortPathWithEnds(obj, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
825 if(tmp && tmp->type == SWF_PATHTYPE_LINE && t1linelen(obj,tmp)>line_width*2)
831 tmp->link->last = tmp; // make sure list is properly linked in both directions
836 static inline int colorcompare(struct swfoutput*obj, RGBA*a,RGBA*b)
848 static SRECT getcharacterbbox(struct swfoutput*obj, SWFFONT*font)
850 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
853 memset(&r, 0, sizeof(r));
856 if(debug) printf("\n");
857 for(t=0;t<i->chardatapos;t++)
859 if(i->chardata[t].fontid != font->id) {
860 msg("<error> Internal error: fontid %d != fontid %d", i->chardata[t].fontid, font->id);
863 SRECT b = font->layout->bounds[i->chardata[t].charid];
864 b.xmin *= i->chardata[t].size;
865 b.ymin *= i->chardata[t].size;
866 b.xmax *= i->chardata[t].size;
867 b.ymax *= i->chardata[t].size;
872 b.xmin += i->chardata[t].x;
873 b.ymin += i->chardata[t].y;
874 b.xmax += i->chardata[t].x;
875 b.ymax += i->chardata[t].y;
877 /* until we solve the INTERNAL_SCALING problem (see below)
878 make sure the bounding box is big enough */
884 if(debug) printf("(%f,%f,%f,%f) -> (%f,%f,%f,%f) [font %d/%d, char %d]\n",
885 font->layout->bounds[i->chardata[t].charid].xmin/20.0,
886 font->layout->bounds[i->chardata[t].charid].ymin/20.0,
887 font->layout->bounds[i->chardata[t].charid].xmax/20.0,
888 font->layout->bounds[i->chardata[t].charid].ymax/20.0,
893 i->chardata[t].fontid,
895 i->chardata[t].charid
897 swf_ExpandRect2(&r, &b);
899 if(debug) printf("-----> (%f,%f,%f,%f)\n",
907 static void putcharacters(struct swfoutput*obj, TAG*tag)
909 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
913 color.r = i->chardata[0].color.r^255;
922 int charadvance[128];
925 int glyphbits=1; //TODO: can this be zero?
928 if(tag->id != ST_DEFINETEXT &&
929 tag->id != ST_DEFINETEXT2) {
930 msg("<error> internal error: putcharacters needs an text tag, not %d\n",tag->id);
933 if(!i->chardatapos) {
934 msg("<warning> putcharacters called with zero characters");
937 for(pass = 0; pass < 2; pass++)
947 advancebits++; // add sign bit
948 swf_SetU8(tag, glyphbits);
949 swf_SetU8(tag, advancebits);
952 for(t=0;t<=i->chardatapos;t++)
954 if(lastfontid != i->chardata[t].fontid ||
955 lastx!=i->chardata[t].x ||
956 lasty!=i->chardata[t].y ||
957 !colorcompare(obj,&color, &i->chardata[t].color) ||
959 lastsize != i->chardata[t].size ||
962 if(charstorepos && pass==0)
965 for(s=0;s<charstorepos;s++)
967 while(charids[s]>=(1<<glyphbits))
969 while(charadvance[s]>=(1<<advancebits))
973 if(charstorepos && pass==1)
975 tag->writeBit = 0; // Q&D
976 swf_SetBits(tag, 0, 1); // GLYPH Record
977 swf_SetBits(tag, charstorepos, 7); // number of glyphs
979 for(s=0;s<charstorepos;s++)
981 swf_SetBits(tag, charids[s], glyphbits);
982 swf_SetBits(tag, charadvance[s], advancebits);
987 if(pass == 1 && t<i->chardatapos)
993 if(lastx != i->chardata[t].x ||
994 lasty != i->chardata[t].y)
996 newx = i->chardata[t].x;
997 newy = i->chardata[t].y;
1003 if(!colorcompare(obj,&color, &i->chardata[t].color))
1005 color = i->chardata[t].color;
1008 font.id = i->chardata[t].fontid;
1009 if(lastfontid != i->chardata[t].fontid || lastsize != i->chardata[t].size)
1012 tag->writeBit = 0; // Q&D
1013 swf_TextSetInfoRecord(tag, newfont, i->chardata[t].size, newcolor, newx,newy);
1016 lastfontid = i->chardata[t].fontid;
1017 lastx = i->chardata[t].x;
1018 lasty = i->chardata[t].y;
1019 lastsize = i->chardata[t].size;
1022 if(t==i->chardatapos)
1026 int nextt = t==i->chardatapos-1?t:t+1;
1027 int rel = i->chardata[nextt].x-i->chardata[t].x;
1028 if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) {
1030 lastx=i->chardata[nextt].x;
1034 lastx=i->chardata[t].x;
1036 charids[charstorepos] = i->chardata[t].charid;
1037 charadvance[charstorepos] = advance;
1044 static void putcharacter(struct swfoutput*obj, int fontid, int charid,
1045 int x,int y, int size)
1047 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1048 if(i->chardatapos == CHARDATAMAX)
1050 msg("<warning> Character buffer too small. SWF will be slightly bigger");
1054 i->chardata[i->chardatapos].fontid = fontid;
1055 i->chardata[i->chardatapos].charid = charid;
1056 i->chardata[i->chardatapos].x = x;
1057 i->chardata[i->chardatapos].y = y;
1058 i->chardata[i->chardatapos].color = obj->fillrgb;
1059 i->chardata[i->chardatapos].size = size;
1063 /* Notice: we can only put chars in the range -1639,1638 (-32768/20,32768/20).
1064 So if we set this value to high, the char coordinates will overflow.
1065 If we set it to low, however, the char positions will be inaccurate */
1066 #define FONT_INTERNAL_SIZE 4
1068 /* process a character. */
1069 static int drawchar(struct swfoutput*obj, SWFFONT *swffont, char*character, int charnr, int u, swfmatrix*m)
1071 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1073 msg("<warning> Font is NULL");
1077 int charid = getCharID(swffont, charnr, character, u);
1080 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1081 FIXNULL(character),charnr, u, FIXNULL((char*)swffont->name), swffont->numchars);
1092 float det = ((m->m11*m->m22)-(m->m21*m->m12));
1093 if(fabs(det) < 0.0005) {
1094 /* x direction equals y direction- the text is invisible */
1097 det = 20*FONT_INTERNAL_SIZE / det;
1100 p.x = (SCOORD)(( x * m->m22 - y * m->m12)*det);
1101 p.y = (SCOORD)((- x * m->m21 + y * m->m11)*det);
1103 putcharacter(obj, swffont->id, charid,p.x,p.y,FONT_INTERNAL_SIZE);
1104 swf_FontUseGlyph(swffont, charid);
1109 SWF_OUTLINE*outline = font->getOutline(character, charnr);
1110 char* charname = character;
1113 msg("<warning> Didn't find character '%s' (%d) in current charset (%s)",
1114 FIXNULL(character),charnr,FIXNULL(font->getName()));
1133 drawpath(tag, outline, &m2, 0);
1138 static void endtext(swfoutput*obj)
1140 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1144 i->tag = swf_InsertTag(i->tag,ST_DEFINETEXT);
1145 swf_SetU16(i->tag, i->textid);
1148 r = getcharacterbbox(obj, obj->swffont);
1150 swf_SetRect(i->tag,&r);
1153 swf_GetMatrix(0, &m);
1154 swf_SetMatrix(i->tag,&m);
1156 putcharacters(obj, i->tag);
1157 swf_SetU8(i->tag,0);
1158 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
1159 //swf_ObjectPlace(i->tag,i->textid,/*depth*/i->depth++,&i->page_matrix,NULL,NULL);
1161 swf_MatrixJoin(&m2,&obj->fontmatrix, &i->page_matrix);
1163 swf_ObjectPlace(i->tag,i->textid,/*depth*/i->depth++,&m2,NULL,NULL);
1168 /* draw a curved polygon. */
1169 void swfoutput_drawpath(swfoutput*obj, SWF_OUTLINE*outline,
1172 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1176 /* Multiple polygons in one shape don't overlap correctly,
1177 so we better start a new shape here if the polygon is filled
1179 if(i->shapeid>=0 && i->fill && !config_ignoredraworder) {
1192 drawpath(obj, outline,m, 0);
1195 void swfoutput_drawpath2poly(struct swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
1197 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1202 assert(i->shapeid<0);
1206 drawpath2poly(obj, outline, m, 0, line_join, line_cap, line_width, miter_limit);
1209 int getCharID(SWFFONT *font, int charnr, char *charname, int u)
1212 if(charname && font->glyphnames) {
1213 for(t=0;t<font->numchars;t++) {
1214 if(font->glyphnames[t] && !strcmp(font->glyphnames[t],charname)) {
1215 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1219 /* if we didn't find the character, maybe
1220 we can find the capitalized version */
1221 for(t=0;t<font->numchars;t++) {
1222 if(font->glyphnames[t] && !strcasecmp(font->glyphnames[t],charname)) {
1223 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1230 /* try to use the unicode id */
1231 if(u>=0 && u<font->maxascii && font->ascii2glyph[u]>=0) {
1232 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->ascii2glyph[u]);
1233 return font->ascii2glyph[u];
1237 if(font->encoding != FONT_ENCODING_UNICODE) {
1238 /* the following only works if the font encoding
1239 is US-ASCII based. It's needed for fonts which return broken unicode
1241 if(charnr>=0 && charnr<font->maxascii && font->ascii2glyph[charnr]>=0) {
1242 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, font->ascii2glyph[charnr]);
1243 return font->ascii2glyph[charnr];
1247 if(charnr>=0 && charnr<font->numchars) {
1248 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1256 /* set's the t1 font index of the font to use for swfoutput_drawchar(). */
1257 void swfoutput_setfont(struct swfoutput*obj, char*fontid, char*filename)
1259 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1260 fontlist_t*last=0,*iterator;
1262 msg("<error> No fontid");
1266 if(obj->swffont && obj->swffont->name && !strcmp((char*)obj->swffont->name,fontid))
1269 /* TODO: remove the need for this (enhance getcharacterbbox so that it can cope
1270 with multiple fonts */
1273 iterator = i->fontlist;
1275 if(!strcmp((char*)iterator->swffont->name,fontid)) {
1276 obj->swffont = iterator->swffont;
1280 iterator = iterator->next;
1284 msg("<error> No filename given for font- internal error?");
1288 swf_SetLoadFontParameters(64,/*skip unused*/0,/*full unicode*/1);
1289 SWFFONT*swffont = swf_LoadFont(filename);
1292 msg("<warning> Couldn't load font %s (%s)", fontid, filename);
1293 swffont = swf_LoadFont(0);
1296 swf_FontSetID(swffont, ++i->currentswfid);
1298 if(getScreenLogLevel() >= LOGLEVEL_DEBUG) {
1299 // print font information
1300 msg("<debug> Font %s (%s)",swffont->name, filename);
1301 msg("<debug> | ID: %d", swffont->id);
1302 msg("<debug> | Version: %d", swffont->version);
1303 msg("<debug> | Name: %s", fontid);
1304 msg("<debug> | Numchars: %d", swffont->numchars);
1305 msg("<debug> | Maxascii: %d", swffont->maxascii);
1306 msg("<debug> | Style: %d", swffont->style);
1307 msg("<debug> | Encoding: %d", swffont->encoding);
1308 for(int iii=0; iii<swffont->numchars;iii++) {
1309 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,
1310 swffont->layout->bounds[iii].xmin/20.0,
1311 swffont->layout->bounds[iii].ymin/20.0,
1312 swffont->layout->bounds[iii].xmax/20.0,
1313 swffont->layout->bounds[iii].ymax/20.0
1316 for(t=0;t<swffont->maxascii;t++) {
1317 if(swffont->ascii2glyph[t] == iii)
1318 msg("<debug> | - maps to %d",t);
1323 /* set the font name to the ID we use here */
1324 if(swffont->name) free(swffont->name);
1325 swffont->name = (U8*)strdup(fontid);
1327 iterator = new fontlist_t;
1328 iterator->swffont = swffont;
1332 last->next = iterator;
1334 i->fontlist = iterator;
1336 obj->swffont = swffont;
1339 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1341 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1342 fontlist_t *iterator = i->fontlist;
1344 if(!strcmp((char*)iterator->swffont->name,fontid))
1346 iterator = iterator->next;
1351 /* set's the matrix which is to be applied to characters drawn by
1352 swfoutput_drawchar() */
1353 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1354 double m21,double m22)
1356 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1357 if(obj->fontm11 == m11 &&
1358 obj->fontm12 == m12 &&
1359 obj->fontm21 == m21 &&
1360 obj->fontm22 == m22)
1370 m.sx = (U32)(((obj->fontm11)*65536)/FONT_INTERNAL_SIZE); m.r1 = (U32)(((obj->fontm12)*65536)/FONT_INTERNAL_SIZE);
1371 m.r0 = (U32)(((obj->fontm21)*65536)/FONT_INTERNAL_SIZE); m.sy = (U32)(((obj->fontm22)*65536)/FONT_INTERNAL_SIZE);
1374 obj->fontmatrix = m;
1377 /* draws a character at x,y. */
1378 int swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr, int u)
1380 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1382 m.m11 = obj->fontm11;
1383 m.m12 = obj->fontm12;
1384 m.m21 = obj->fontm21;
1385 m.m22 = obj->fontm22;
1388 return drawchar(obj, obj->swffont, character, charnr, u, &m);
1391 static void endpage(struct swfoutput*obj)
1393 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1399 swfoutput_endclip(obj);
1401 if(config_insertstoptag) {
1403 atag = action_Stop(atag);
1404 atag = action_End(atag);
1405 i->tag = swf_InsertTag(i->tag,ST_DOACTION);
1406 swf_ActionSet(i->tag,atag);
1408 i->tag = swf_InsertTag(i->tag,ST_SHOWFRAME);
1411 void swfoutput_newpage(struct swfoutput*obj, int pageNum, int movex, int movey, int x1, int y1, int x2, int y2)
1413 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1417 swf_GetMatrix(0, &i->page_matrix);
1418 i->page_matrix.tx = movex*20;
1419 i->page_matrix.ty = movey*20;
1421 for(i->depth--;i->depth>=i->startdepth;i->depth--) {
1422 i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2);
1423 swf_SetU16(i->tag,i->depth);
1425 i->depth = i->startdepth = 3; /* leave room for clip and background rectangle */
1429 x1*=20;y1*=20;x2*=20;y2*=20;
1431 if(i->lastpagesize.xmin != x1 ||
1432 i->lastpagesize.xmax != x2 ||
1433 i->lastpagesize.ymin != y1 ||
1434 i->lastpagesize.ymax != y2)
1435 {/* add white clipping rectangle */
1436 msg("<notice> processing page %d (%dx%d)", pageNum,i->sizex,i->sizey);
1439 msg("<notice> Page has a different size than previous ones");
1440 i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2);
1441 swf_SetU16(i->tag,1);
1442 i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2);
1443 swf_SetU16(i->tag,2);
1447 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1451 int shapeid = ++i->currentswfid;
1456 i->tag = swf_InsertTag(i->tag, ST_DEFINESHAPE);
1458 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1459 swf_SetU16(i->tag,shapeid);
1460 swf_SetRect(i->tag,&r);
1461 swf_SetShapeHeader(i->tag,s);
1462 swf_ShapeSetAll(i->tag,s,x1,y1,ls1,fs1,0);
1463 swf_ShapeSetLine(i->tag,s,(x2-x1),0);
1464 swf_ShapeSetLine(i->tag,s,0,(y2-y1));
1465 swf_ShapeSetLine(i->tag,s,(x1-x2),0);
1466 swf_ShapeSetLine(i->tag,s,0,(y1-y2));
1467 swf_ShapeSetEnd(i->tag);
1469 i->tag = swf_InsertTag(i->tag, ST_PLACEOBJECT2);
1470 swf_ObjectPlace(i->tag,shapeid,/*depth*/1,0,0,0);
1471 i->tag = swf_InsertTag(i->tag, ST_PLACEOBJECT2);
1472 swf_ObjectPlaceClip(i->tag,shapeid,/*depth*/2,0,0,0,65535);
1474 msg("<notice> processing page %d", pageNum);
1477 i->lastpagesize.xmin = x1;
1478 i->lastpagesize.xmax = x2;
1479 i->lastpagesize.ymin = y1;
1480 i->lastpagesize.ymax = y2;
1481 swf_ExpandRect2(&obj->swf.movieSize, &i->lastpagesize);
1486 /* initialize the swf writer */
1487 void swfoutput_init(struct swfoutput* obj)
1489 memset(obj, 0, sizeof(struct swfoutput));
1490 obj->internal = init_internal_struct();
1492 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1497 msg("<verbose> initializing swf output for size %d*%d\n", i->sizex,i->sizey);
1502 memset(&obj->swf,0x00,sizeof(SWF));
1503 memset(&i->lastpagesize,0x00,sizeof(SRECT));
1505 obj->swf.fileVersion = config_flashversion;
1506 obj->swf.frameRate = 0x0040; // 1 frame per 4 seconds
1507 obj->swf.movieSize.xmin = 0;
1508 obj->swf.movieSize.ymin = 0;
1509 obj->swf.movieSize.xmax = 0;
1510 obj->swf.movieSize.ymax = 0;
1512 obj->swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1513 i->tag = obj->swf.firstTag;
1514 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1515 swf_SetRGB(i->tag,&rgb);
1517 i->startdepth = i->depth = 0;
1520 i->tag = swf_InsertTag(i->tag, ST_PROTECT);
1523 static void startshape(struct swfoutput*obj)
1525 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1532 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE);
1534 swf_ShapeNew(&i->shape);
1535 i->linestyleid = swf_ShapeAddLineStyle(i->shape,i->linewidth,&obj->strokergb);
1536 rgb.r = obj->fillrgb.r;
1537 rgb.g = obj->fillrgb.g;
1538 rgb.b = obj->fillrgb.b;
1539 i->fillstyleid = swf_ShapeAddSolidFillStyle(i->shape,&obj->fillrgb);
1541 i->shapeid = ++i->currentswfid;
1542 swf_SetU16(i->tag,i->shapeid); // ID
1544 i->bboxrectpos = i->tag->len;
1547 r.xmax = 20*i->sizex;
1548 r.ymax = 20*i->sizey;
1549 swf_SetRect(i->tag,&r);
1551 memset(&i->bboxrect, 0, sizeof(i->bboxrect));
1553 swf_SetShapeStyles(i->tag,i->shape);
1554 swf_ShapeCountBits(i->shape,NULL,NULL);
1555 swf_SetShapeBits(i->tag,i->shape);
1557 /* TODO: do we really need this? */
1558 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,i->linestyleid,0,0);
1559 i->swflastx=i->swflasty=0;
1561 i->shapeisempty = 1;
1564 static void starttext(struct swfoutput*obj)
1566 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1570 i->textid = ++i->currentswfid;
1572 i->swflastx=i->swflasty=0;
1576 /* TODO: move to ../lib/rfxswf */
1577 void changeRect(struct swfoutput*obj, TAG*tag, int pos, SRECT*newrect)
1579 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1580 /* determine length of old rect */
1584 swf_GetRect(tag, &old);
1585 swf_ResetReadBits(tag);
1586 int pos_end = tag->pos;
1588 int len = tag->len - pos_end;
1589 U8*data = (U8*)malloc(len);
1590 memcpy(data, &tag->data[pos_end], len);
1593 swf_SetRect(tag, newrect);
1594 swf_SetBlock(tag, data, len);
1596 tag->pos = tag->readBit = 0;
1599 void cancelshape(swfoutput*obj)
1601 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1602 /* delete old shape tag */
1604 i->tag = i->tag->prev;
1605 swf_DeleteTag(todel);
1606 if(i->shape) {swf_ShapeFree(i->shape);i->shape=0;}
1608 i->bboxrectpos = -1;
1611 void fixAreas(swfoutput*obj)
1613 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1614 if(!i->shapeisempty && i->fill &&
1615 (i->bboxrect.xmin == i->bboxrect.xmax ||
1616 i->bboxrect.ymin == i->bboxrect.ymax) &&
1617 config_minlinewidth >= 0.001
1619 msg("<debug> Shape has size 0: width=%.2f height=%.2f",
1620 (i->bboxrect.xmax-i->bboxrect.xmin)/20.0,
1621 (i->bboxrect.ymax-i->bboxrect.ymin)/20.0
1624 SRECT r = i->bboxrect;
1626 if(r.xmin == r.xmax && r.ymin == r.ymax) {
1627 /* this thing comes down to a single dot- nothing to fix here */
1633 RGBA save_col = obj->strokergb;
1634 int save_width = i->linewidth;
1636 obj->strokergb = obj->fillrgb;
1637 i->linewidth = (int)(config_minlinewidth*20);
1638 if(i->linewidth==0) i->linewidth = 1;
1642 moveto(obj, i->tag, r.xmin/20.0,r.ymin/20.0);
1643 lineto(obj, i->tag, r.xmax/20.0,r.ymax/20.0);
1645 obj->strokergb = save_col;
1646 i->linewidth = save_width;
1651 static void endshape_noput(swfoutput*obj)
1653 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1656 //changeRect(obj, i->tag, i->bboxrectpos, &i->bboxrect);
1659 swf_ShapeFree(i->shape);
1664 static void endshape(swfoutput*obj, int clipdepth)
1666 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1673 if(i->shapeisempty ||
1674 (i->bboxrect.xmin == i->bboxrect.xmax &&
1675 i->bboxrect.ymin == i->bboxrect.ymax))
1677 // delete the shape again, we didn't do anything
1682 swf_ShapeSetEnd(i->tag);
1684 changeRect(obj, i->tag, i->bboxrectpos, &i->bboxrect);
1686 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
1689 swf_ObjectPlaceClip(i->tag,i->shapeid,i->depth++,&i->page_matrix,NULL,NULL,clipdepth);
1691 swf_ObjectPlace(i->tag,i->shapeid,/*depth*/i->depth++,&i->page_matrix,NULL,NULL);
1693 swf_ShapeFree(i->shape);
1696 i->bboxrectpos = -1;
1699 int swfoutput_save(struct swfoutput* obj, char*filename)
1701 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1703 fontlist_t *tmp,*iterator = i->fontlist;
1705 TAG*mtag = obj->swf.firstTag;
1706 if(iterator->swffont) {
1707 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1708 /*if(!storeallcharacters)
1709 swf_FontReduce(iterator->swffont);*/
1710 swf_FontSetDefine2(mtag, iterator->swffont);
1713 iterator = iterator->next;
1718 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1723 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1727 i->tag = swf_InsertTag(i->tag,ST_END);
1729 if(config_enablezlib || config_flashversion>=6) {
1730 if FAILED(swf_WriteSWC(fi,&obj->swf))
1731 msg("<error> WriteSWC() failed.\n");
1733 if FAILED(swf_WriteSWF(fi,&obj->swf))
1734 msg("<error> WriteSWF() failed.\n");
1739 msg("<notice> SWF written\n");
1743 /* Perform cleaning up, complete the swf, and write it out. */
1744 void swfoutput_destroy(struct swfoutput* obj)
1746 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1748 /* not initialized yet- nothing to destroy */
1752 fontlist_t *tmp,*iterator = i->fontlist;
1754 if(iterator->swffont) {
1755 swf_FontFree(iterator->swffont);iterator->swffont=0;
1758 iterator = iterator->next;
1761 swf_FreeTags(&obj->swf);
1764 memset(obj, 0, sizeof(swfoutput));
1767 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1769 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1770 obj->drawmode = mode;
1771 if(mode == DRAWMODE_FILL)
1773 else if(mode == DRAWMODE_EOFILL)
1775 else if(mode == DRAWMODE_STROKE)
1777 else if(mode == DRAWMODE_CLIP)
1779 else if(mode == DRAWMODE_EOCLIP)
1783 void swfoutput_setfillcolor(swfoutput* obj, U8 r, U8 g, U8 b, U8 a)
1785 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1786 if(obj->fillrgb.r == r &&
1787 obj->fillrgb.g == g &&
1788 obj->fillrgb.b == b &&
1789 obj->fillrgb.a == a) return;
1799 void swfoutput_setstrokecolor(swfoutput* obj, U8 r, U8 g, U8 b, U8 a)
1801 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1802 if(obj->strokergb.r == r &&
1803 obj->strokergb.g == g &&
1804 obj->strokergb.b == b &&
1805 obj->strokergb.a == a) return;
1809 obj->strokergb.r = r;
1810 obj->strokergb.g = g;
1811 obj->strokergb.b = b;
1812 obj->strokergb.a = a;
1815 void swfoutput_setlinewidth(struct swfoutput*obj, double _linewidth)
1817 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1818 if(i->linewidth == (U16)(_linewidth*20))
1823 i->linewidth = (U16)(_linewidth*20);
1827 void swfoutput_startclip(swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m)
1829 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1835 if(i->clippos >= 127)
1837 msg("<warning> Too many clip levels.");
1842 int olddrawmode = obj->drawmode;
1843 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1844 swfoutput_drawpath(obj, outline, m);
1845 swf_ShapeSetEnd(i->tag);
1846 swfoutput_setdrawmode(obj, olddrawmode);
1848 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
1849 i->cliptags[i->clippos] = i->tag;
1850 i->clipshapes[i->clippos] = i->shapeid;
1851 i->clipdepths[i->clippos] = i->depth++;
1854 endshape_noput(obj);
1857 void swfoutput_endclip(swfoutput*obj)
1859 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1866 msg("<error> Invalid end of clipping region");
1870 swf_ObjectPlaceClip(i->cliptags[i->clippos],i->clipshapes[i->clippos],i->clipdepths[i->clippos],&i->page_matrix,NULL,NULL,i->depth++);
1873 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1875 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1877 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1879 if(!strncmp("http://pdf2swf:", url, 15)) {
1880 char*tmp = strdup(url);
1881 int l = strlen(tmp);
1884 swfoutput_namedlink(obj, tmp+15, points);
1894 if(config_opennewwindow)
1895 actions = action_GetUrl(0, url, "_parent");
1897 actions = action_GetUrl(0, url, "_this");
1898 actions = action_End(actions);
1900 drawlink(obj, actions, 0, points,0);
1902 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1904 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1912 actions = action_GotoFrame(0, page);
1913 actions = action_End(actions);
1915 drawlink(obj, actions, 0, points,0);
1918 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
1919 of the viewer objects, like subtitles, index elements etc.
1921 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
1923 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1924 ActionTAG *actions1,*actions2;
1925 char*tmp = strdup(name);
1933 if(!strncmp(tmp, "call:", 5))
1935 char*x = strchr(&tmp[5], ':');
1937 actions1 = action_PushInt(0, 0); //number of parameters (0)
1938 actions1 = action_PushString(actions1, &tmp[5]); //function name
1939 actions1 = action_CallFunction(actions1);
1942 actions1 = action_PushString(0, x+1); //parameter
1943 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
1944 actions1 = action_PushString(actions1, &tmp[5]); //function name
1945 actions1 = action_CallFunction(actions1);
1947 actions2 = action_End(0);
1952 actions1 = action_PushString(0, "/:subtitle");
1953 actions1 = action_PushString(actions1, name);
1954 actions1 = action_SetVariable(actions1);
1955 actions1 = action_End(actions1);
1957 actions2 = action_PushString(0, "/:subtitle");
1958 actions2 = action_PushString(actions2, "");
1959 actions2 = action_SetVariable(actions2);
1960 actions2 = action_End(actions2);
1963 drawlink(obj, actions1, actions2, points,mouseover);
1965 swf_ActionFree(actions1);
1966 swf_ActionFree(actions2);
1970 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
1972 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1977 struct plotxy p1,p2,p3,p4;
1981 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
1985 int buttonid = ++i->currentswfid;
1988 if(points[t].x>xmax) xmax=points[t].x;
1989 if(points[t].y>ymax) ymax=points[t].y;
1990 if(points[t].x<xmin) xmin=points[t].x;
1991 if(points[t].y<ymin) ymin=points[t].y;
1994 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
1995 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
1997 /* the following code subtracts the upper left edge from all coordinates,
1998 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
1999 Necessary for preprocessing with swfcombine. */
2000 posx = xmin; posy = ymin;
2001 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
2002 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
2003 xmin -= posx; ymin -= posy;
2004 xmax -= posx; ymax -= posy;
2007 myshapeid = ++i->currentswfid;
2008 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE3);
2009 swf_ShapeNew(&i->shape);
2010 rgb.r = rgb.b = rgb.a = rgb.g = 0;
2011 fsid = swf_ShapeAddSolidFillStyle(i->shape,&rgb);
2012 swf_SetU16(i->tag, myshapeid);
2013 r.xmin = (int)(xmin*20);
2014 r.ymin = (int)(ymin*20);
2015 r.xmax = (int)(xmax*20);
2016 r.ymax = (int)(ymax*20);
2017 swf_SetRect(i->tag,&r);
2018 swf_SetShapeStyles(i->tag,i->shape);
2019 swf_ShapeCountBits(i->shape,NULL,NULL);
2020 swf_SetShapeBits(i->tag,i->shape);
2021 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,0,fsid,0);
2022 i->swflastx = i->swflasty = 0;
2023 moveto(obj, i->tag, p1);
2024 lineto(obj, i->tag, p2);
2025 lineto(obj, i->tag, p3);
2026 lineto(obj, i->tag, p4);
2027 lineto(obj, i->tag, p1);
2028 swf_ShapeSetEnd(i->tag);
2031 myshapeid2 = ++i->currentswfid;
2032 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE3);
2033 swf_ShapeNew(&i->shape);
2034 rgb.r = rgb.b = rgb.a = rgb.g = 255;
2036 fsid = swf_ShapeAddSolidFillStyle(i->shape,&rgb);
2037 swf_SetU16(i->tag, myshapeid2);
2038 r.xmin = (int)(xmin*20);
2039 r.ymin = (int)(ymin*20);
2040 r.xmax = (int)(xmax*20);
2041 r.ymax = (int)(ymax*20);
2042 swf_SetRect(i->tag,&r);
2043 swf_SetShapeStyles(i->tag,i->shape);
2044 swf_ShapeCountBits(i->shape,NULL,NULL);
2045 swf_SetShapeBits(i->tag,i->shape);
2046 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,0,fsid,0);
2047 i->swflastx = i->swflasty = 0;
2048 moveto(obj, i->tag, p1);
2049 lineto(obj, i->tag, p2);
2050 lineto(obj, i->tag, p3);
2051 lineto(obj, i->tag, p4);
2052 lineto(obj, i->tag, p1);
2053 swf_ShapeSetEnd(i->tag);
2057 i->tag = swf_InsertTag(i->tag,ST_DEFINEBUTTON);
2058 swf_SetU16(i->tag,buttonid); //id
2059 swf_ButtonSetFlags(i->tag, 0); //menu=no
2060 swf_ButtonSetRecord(i->tag,0x01,myshapeid,i->depth,0,0);
2061 swf_ButtonSetRecord(i->tag,0x02,myshapeid2,i->depth,0,0);
2062 swf_ButtonSetRecord(i->tag,0x04,myshapeid2,i->depth,0,0);
2063 swf_ButtonSetRecord(i->tag,0x08,myshapeid,i->depth,0,0);
2064 swf_SetU8(i->tag,0);
2065 swf_ActionSet(i->tag,actions1);
2066 swf_SetU8(i->tag,0);
2070 i->tag = swf_InsertTag(i->tag,ST_DEFINEBUTTON2);
2071 swf_SetU16(i->tag,buttonid); //id
2072 swf_ButtonSetFlags(i->tag, 0); //menu=no
2073 swf_ButtonSetRecord(i->tag,0x01,myshapeid,i->depth,0,0);
2074 swf_ButtonSetRecord(i->tag,0x02,myshapeid2,i->depth,0,0);
2075 swf_ButtonSetRecord(i->tag,0x04,myshapeid2,i->depth,0,0);
2076 swf_ButtonSetRecord(i->tag,0x08,myshapeid,i->depth,0,0);
2077 swf_SetU8(i->tag,0); // end of button records
2078 swf_ButtonSetCondition(i->tag, BC_IDLE_OVERUP);
2079 swf_ActionSet(i->tag,actions1);
2081 swf_ButtonSetCondition(i->tag, BC_OVERUP_IDLE);
2082 swf_ActionSet(i->tag,actions2);
2083 swf_SetU8(i->tag,0);
2084 swf_ButtonPostProcess(i->tag, 2);
2086 swf_SetU8(i->tag,0);
2087 swf_ButtonPostProcess(i->tag, 1);
2091 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
2093 if(posx!=0 || posy!=0) {
2095 p.x = (int)(posx*20);
2096 p.y = (int)(posy*20);
2097 p = swf_TurnPoint(p, &i->page_matrix);
2102 swf_ObjectPlace(i->tag, buttonid, i->depth++,&m,0,0);
2105 swf_ObjectPlace(i->tag, buttonid, i->depth++,&i->page_matrix,0,0);
2109 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
2110 double x1,double y1,
2111 double x2,double y2,
2112 double x3,double y3,
2113 double x4,double y4)
2115 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2120 struct plotxy p1,p2,p3,p4;
2122 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
2123 if(x2>xmax) xmax=x2;
2124 if(y2>ymax) ymax=y2;
2125 if(x2<xmin) xmin=x2;
2126 if(y2<ymin) ymin=y2;
2127 if(x3>xmax) xmax=x3;
2128 if(y3>ymax) ymax=y3;
2129 if(x3<xmin) xmin=x3;
2130 if(y3<ymin) ymin=y3;
2131 if(x4>xmax) xmax=x4;
2132 if(y4>ymax) ymax=y4;
2133 if(x4<xmin) xmin=x4;
2134 if(y4<ymin) ymin=y4;
2140 {p1.x = (int)(p1.x*20)/20.0;
2141 p1.y = (int)(p1.y*20)/20.0;
2142 p2.x = (int)(p2.x*20)/20.0;
2143 p2.y = (int)(p2.y*20)/20.0;
2144 p3.x = (int)(p3.x*20)/20.0;
2145 p3.y = (int)(p3.y*20)/20.0;
2146 p4.x = (int)(p4.x*20)/20.0;
2147 p4.y = (int)(p4.y*20)/20.0;}
2150 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
2151 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
2152 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
2153 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
2155 m.tx = (int)(p1.x*20);
2156 m.ty = (int)(p1.y*20);
2159 myshapeid = ++i->currentswfid;
2160 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE);
2162 swf_ShapeNew(&shape);
2163 //lsid = ShapeAddLineStyle(shape,linewidth,&obj->strokergb);
2164 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
2165 fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
2166 swf_SetU16(i->tag, myshapeid);
2167 r.xmin = (int)(xmin*20);
2168 r.ymin = (int)(ymin*20);
2169 r.xmax = (int)(xmax*20);
2170 r.ymax = (int)(ymax*20);
2171 swf_SetRect(i->tag,&r);
2172 swf_SetShapeStyles(i->tag,shape);
2173 swf_ShapeCountBits(shape,NULL,NULL);
2174 swf_SetShapeBits(i->tag,shape);
2175 swf_ShapeSetAll(i->tag,shape,/*x*/0,/*y*/0,lsid,fsid,0);
2176 i->swflastx = i->swflasty = 0;
2177 moveto(obj, i->tag, p1);
2178 lineto(obj, i->tag, p2);
2179 lineto(obj, i->tag, p3);
2180 lineto(obj, i->tag, p4);
2181 lineto(obj, i->tag, p1);
2183 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
2184 ShapeSetLine (tag, shape, (int)(x1*20);
2185 ShapeSetLine (tag, shape, x*20,0);
2186 ShapeSetLine (tag, shape, 0,-y*20);
2187 ShapeSetLine (tag, shape, -x*20,0);*/
2188 swf_ShapeSetEnd(i->tag);
2189 swf_ShapeFree(shape);
2192 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
2194 swf_ObjectPlace(i->tag,myshapeid,/*depth*/i->depth++,&i->page_matrix,NULL,NULL);
2197 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
2198 double x1,double y1,
2199 double x2,double y2,
2200 double x3,double y3,
2201 double x4,double y4)
2203 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2210 int bitid = ++i->currentswfid;
2212 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSJPEG2);
2213 swf_SetU16(i->tag, bitid);
2214 if(swf_SetJPEGBits(i->tag, filename, config_jpegquality)<0) {
2215 swf_DeleteTag(i->tag);
2220 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2224 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2225 double x1,double y1,
2226 double x2,double y2,
2227 double x3,double y3,
2228 double x4,double y4)
2230 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2239 int bitid = ++i->currentswfid;
2241 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSJPEG2);
2242 swf_SetU16(i->tag, bitid);
2243 swf_SetJPEGBits2(i->tag,sizex,sizey,mem,config_jpegquality);
2244 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2248 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2249 double x1,double y1,
2250 double x2,double y2,
2251 double x3,double y3,
2252 double x4,double y4)
2254 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2261 int bitid = ++i->currentswfid;
2263 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSLOSSLESS);
2264 swf_SetU16(i->tag, bitid);
2265 if(swf_SetLosslessBits(i->tag,sizex,sizey,mem, BMF_32BIT)<0) {
2266 swf_DeleteTag(i->tag);
2271 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2275 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
2276 double x1,double y1,
2277 double x2,double y2,
2278 double x3,double y3,
2279 double x4,double y4, int n)
2281 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2291 /* SWF expects scanlines to be 4 byte aligned */
2294 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
2296 for(y=0;y<sizey;y++)
2298 for(x=0;x<sizex;x++)
2299 *ptr++ = mem[y*sizex+x];
2300 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
2305 int bitid = ++i->currentswfid;
2307 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSLOSSLESS2);
2308 swf_SetU16(i->tag, bitid);
2309 if(swf_SetLosslessBitsIndexed(i->tag,sizex,sizey,mem, pal, n)<0) {
2310 swf_DeleteTag(i->tag);
2317 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2321 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
2322 double x1,double y1,
2323 double x2,double y2,
2324 double x3,double y3,
2325 double x4,double y4)
2327 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2334 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2337 void swfoutput_setparameter(char*name, char*value)
2339 if(!strcmp(name, "drawonlyshapes")) {
2340 config_drawonlyshapes = atoi(value);
2341 } else if(!strcmp(name, "ignoredraworder")) {
2342 config_ignoredraworder = atoi(value);
2343 } else if(!strcmp(name, "filloverlap")) {
2344 config_filloverlap = atoi(value);
2345 } else if(!strcmp(name, "linksopennewwindow")) {
2346 config_opennewwindow = atoi(value);
2347 } else if(!strcmp(name, "opennewwindow")) {
2348 config_opennewwindow = atoi(value);
2349 } else if(!strcmp(name, "storeallcharacters")) {
2350 config_storeallcharacters = atoi(value);
2351 } else if(!strcmp(name, "enablezlib")) {
2352 config_enablezlib = atoi(value);
2353 } else if(!strcmp(name, "insertstop")) {
2354 config_insertstoptag = atoi(value);
2355 } else if(!strcmp(name, "protected")) {
2356 config_protect = atoi(value);
2357 } else if(!strcmp(name, "flashversion")) {
2358 config_flashversion = atoi(value);
2359 } else if(!strcmp(name, "minlinewidth")) {
2360 config_minlinewidth = atof(value);
2361 } else if(!strcmp(name, "jpegquality")) {
2362 int val = atoi(value);
2364 if(val>100) val=100;
2365 config_jpegquality = val;
2366 } else if(!strcmp(name, "splinequality")) {
2367 int v = atoi(value);
2368 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2370 config_splinemaxerror = v;
2371 } else if(!strcmp(name, "fontquality")) {
2372 int v = atoi(value);
2373 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2375 config_fontsplinemaxerror = v;
2377 fprintf(stderr, "unknown parameter: %s (=%s)\n", name, value);