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
107 char fillstylechanged;
112 chardata_t chardata[CHARDATAMAX];
115 } swfoutput_internal;
117 static swfoutput_internal* init_internal_struct()
119 swfoutput_internal*i = (swfoutput_internal*)malloc(sizeof(swfoutput_internal));
120 memset(i, 0, sizeof(swfoutput_internal));
140 i->fillstylechanged = 0;
149 static void startshape(struct swfoutput* obj);
150 static void starttext(struct swfoutput* obj);
151 static void endshape(struct swfoutput* obj,int clip);
152 static void endtext(struct swfoutput* obj);
154 // matrix multiplication. changes p0
155 static void transform (plotxy*p0,struct swfmatrix*m)
158 x = m->m11*p0->x+m->m12*p0->y;
159 y = m->m21*p0->x+m->m22*p0->y;
164 // write a move-to command into the swf
165 static int moveto(struct swfoutput*obj, TAG*tag, plotxy p0)
167 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
168 int rx = (int)(p0.x*20);
169 int ry = (int)(p0.y*20);
170 if(rx!=i->swflastx || ry!=i->swflasty || i->fillstylechanged) {
171 swf_ShapeSetMove (tag, i->shape, rx,ry);
172 i->fillstylechanged = 0;
179 static int moveto(struct swfoutput*obj, TAG*tag, float x, float y)
181 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
185 return moveto(obj, tag, p);
187 static void addPointToBBox(struct swfoutput*obj, int px, int py)
189 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
195 swf_ExpandRect(&i->bboxrect, p);
197 swf_ExpandRect3(&i->bboxrect, p, i->linewidth*3/2);
201 // write a line-to command into the swf
202 static void lineto(struct swfoutput*obj, TAG*tag, plotxy p0)
204 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
205 int px = (int)(p0.x*20);
206 int py = (int)(p0.y*20);
207 int rx = (px-i->swflastx);
208 int ry = (py-i->swflasty);
209 /* we can't skip this for rx=0,ry=0, those
211 swf_ShapeSetLine (tag, i->shape, rx,ry);
213 addPointToBBox(obj, i->swflastx,i->swflasty);
214 addPointToBBox(obj, px,py);
220 static void lineto(struct swfoutput*obj, TAG*tag, double x, double y)
228 // write a spline-to command into the swf
229 static void splineto(struct swfoutput*obj, TAG*tag, plotxy control,plotxy end)
231 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
232 int lastlastx = i->swflastx;
233 int lastlasty = i->swflasty;
235 int cx = ((int)(control.x*20)-i->swflastx);
236 int cy = ((int)(control.y*20)-i->swflasty);
239 int ex = ((int)(end.x*20)-i->swflastx);
240 int ey = ((int)(end.y*20)-i->swflasty);
244 if(cx || cy || ex || ey) {
245 swf_ShapeSetCurve(tag, i->shape, cx,cy,ex,ey);
246 addPointToBBox(obj, lastlastx ,lastlasty );
247 addPointToBBox(obj, lastlastx+cx,lastlasty+cy);
248 addPointToBBox(obj, lastlastx+cx+ex,lastlasty+cy+ey);
253 /* write a line, given two points and the transformation
255 static void line(struct swfoutput*obj, TAG*tag, plotxy p0, plotxy p1, struct swfmatrix*m)
259 moveto(obj, tag, p0);
260 lineto(obj, tag, p1);
263 /* write a cubic (!) spline. This involves calling the approximate()
264 function out of spline.cc to convert it to a quadratic spline. */
265 static void spline(struct swfoutput*obj, TAG*tag,plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m)
267 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
269 struct qspline q[128];
283 /* fonts use a different approximation than shapes */
284 num = cspline_approximate(&c, q, config_fontsplinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
285 //num = cspline_approximate(&c, q, 10.0, APPROXIMATE_INFLECTION);
287 num = cspline_approximate(&c, q, config_splinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
291 moveto(obj, tag,q[t].start);
292 splineto(obj, tag,q[t].control, q[t].end);
296 void resetdrawer(struct swfoutput*obj)
298 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
303 static void stopFill(struct swfoutput*obj)
305 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
308 swf_ShapeSetStyle(i->tag,i->shape,i->linestyleid,0x8000,0);
309 i->fillstylechanged = 1;
313 static void startFill(struct swfoutput*obj)
315 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
318 swf_ShapeSetStyle(i->tag,i->shape,0x8000,i->fillstyleid,0);
319 i->fillstylechanged = 1;
324 /* draw an outline. These are generated by pdf2swf and by t1lib
325 (representing characters). */
326 void drawpath(struct swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m, int log)
328 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
329 if( i->tag->id != ST_DEFINESHAPE &&
330 i->tag->id != ST_DEFINESHAPE2 &&
331 i->tag->id != ST_DEFINESHAPE3)
333 msg("<error> internal error: drawpath needs a shape tag, not %d\n",i->tag->id);
337 double lastx=0,lasty=0;
338 double firstx=0,firsty=0;
343 x += (outline->dest.x/(float)0xffff);
344 y += (outline->dest.y/(float)0xffff);
345 if(outline->type == SWF_PATHTYPE_MOVE)
347 //if(!init && fill && obj->drawmode != DRAWMODE_EOFILL && !ignoredraworder) {
348 if(config_filloverlap && !init && i->fill && obj->drawmode != DRAWMODE_EOFILL) {
349 /* drawmode=FILL (not EOFILL) means that
350 seperate shapes do not cancel each other out.
351 On SWF side, we need to start a new shape for each
352 closed polygon, because SWF only knows EOFILL.
359 if(((int)(lastx*20) != (int)(firstx*20) ||
360 (int)(lasty*20) != (int)(firsty*20)) &&
369 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
370 line(obj,i->tag, p0, p1, m);
376 else if(outline->type == SWF_PATHTYPE_LINE)
384 if(log) printf("line: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
385 line(obj,i->tag, p0,p1,m);
387 else if(outline->type == SWF_PATHTYPE_BEZIER)
393 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
396 p1.x=o2->C.x/(float)0xffff+lastx;
397 p1.y=o2->C.y/(float)0xffff+lasty;
398 p2.x=o2->B.x/(float)0xffff+lastx;
399 p2.y=o2->B.y/(float)0xffff+lasty;
402 if(log) printf("spline: %f,%f -> %f,%f\n",p3.x,p3.y,p0.x,p0.y);
403 spline(obj,i->tag,p0,p1,p2,p3,m);
406 msg("<error> drawpath: unknown outline type:%d\n", outline->type);
410 outline = outline->link;
412 if(((int)(lastx*20) != (int)(firstx*20) ||
413 (int)(lasty*20) != (int)(firsty*20)) &&
422 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
423 line(obj, i->tag, p0, p1, m);
427 plotxy getPivot(struct swfoutput*obj, SWF_OUTLINE*outline, int dir, double line_width, int end, int trytwo)
429 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
430 SWF_PATHPOINT next, next2;
431 double xv=0,yv=0, xv2=0, yv2=0;
436 if(outline->type == SWF_PATHTYPE_LINE) {
437 next = outline->dest;
439 next = ((SWF_BEZIERSEGMENT*)outline)->B;
440 if(next.x==0 && next.y==0) {
441 next = ((SWF_BEZIERSEGMENT*)outline)->C;
443 if(next.x==0 && next.y==0) {
444 next = ((SWF_BEZIERSEGMENT*)outline)->dest;
448 if(trytwo && outline->last && outline->last->type != SWF_PATHTYPE_MOVE) {
449 if(outline->type == SWF_PATHTYPE_LINE) {
450 next2 = outline->last->dest;
452 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)(outline->last))->C;
453 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)(outline->last))->B;
454 next2.x = outline->last->dest.x - c.x;
455 next2.y = outline->last->dest.y - c.y;
456 if(next2.x==0 && next2.y==0) {
457 next2.x = outline->last->dest.x - b.x;
458 next2.y = outline->last->dest.y - b.y;
460 if(next2.x==0 && next2.y==0) {
461 next2.x = outline->last->dest.x;
462 next2.y = outline->last->dest.y;
468 if(outline->type == SWF_PATHTYPE_LINE) {
469 next = outline->dest;
471 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)outline)->C;
472 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)outline)->B;
473 next.x = outline->dest.x - c.x;
474 next.y = outline->dest.y - c.y;
475 if(next.x==0 && next.y==0) {
476 next.x = outline->dest.x - b.x;
477 next.y = outline->dest.y - b.y;
479 if(next.x==0 && next.y==0) {
480 next.x = outline->dest.x;
481 next.y = outline->dest.y;
485 if(trytwo && outline->link && outline->link->type != SWF_PATHTYPE_MOVE) {
486 if(outline->type == SWF_PATHTYPE_LINE) {
487 next2 = outline->link->dest;
489 next2 = ((SWF_BEZIERSEGMENT*)(outline->link))->B;
490 if(next2.x==0 && next2.y==0) {
491 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->C;
493 if(next2.x==0 && next2.y==0) {
494 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->dest;
502 xv = next.y/(float)0xffff;
503 yv = -next.x/(float)0xffff;
505 xv = -next.y/(float)0xffff;
506 yv = next.x/(float)0xffff;
509 double r = (line_width/2)/sqrt(xv*xv+yv*yv);
515 xv2 = next2.y/(float)0xffff;
516 yv2 = -next2.x/(float)0xffff;
518 xv2 = -next2.y/(float)0xffff;
519 yv2 = next2.x/(float)0xffff;
522 double r2 = (line_width/2)/sqrt(xv2*xv2+yv2*yv2);
527 double r3 = (line_width/2)/sqrt(xv*xv+yv*yv);
537 void drawShortPath(struct swfoutput*obj, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline)
539 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
540 double lastx=x, lasty=y;
541 while (outline && outline->type != SWF_PATHTYPE_MOVE)
543 x += (outline->dest.x/(float)0xffff);
544 y += (outline->dest.y/(float)0xffff);
546 if(outline->type == SWF_PATHTYPE_LINE)
553 line(obj, i->tag, p0, p1, m);
555 else if(outline->type == SWF_PATHTYPE_BEZIER)
558 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
561 p1.x=o2->C.x/(float)0xffff+lastx;
562 p1.y=o2->C.y/(float)0xffff+lasty;
563 p2.x=o2->B.x/(float)0xffff+lastx;
564 p2.y=o2->B.y/(float)0xffff+lasty;
567 spline(obj, i->tag,p0,p1,p2,p3,m);
571 outline = outline->link;
575 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)
577 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
581 if(line_cap == LINE_CAP_BUTT || line_cap == LINE_CAP_SQUARE) {
584 SWF_OUTLINE *last, *tmp=outline;
585 plotxy s,e,p0,p1,p2,p3,m0,m1,m2,m3;
591 while(tmp && tmp->type != SWF_PATHTYPE_MOVE) {
593 lx += (tmp->dest.x/(float)0xffff);
594 ly += (tmp->dest.y/(float)0xffff);
597 s = getPivot(obj, outline, 0, line_width, 0, 0);
598 e = getPivot(obj, last, 0, line_width, 1, 0);
600 if(line_cap == LINE_CAP_BUTT) {
601 /* make the clipping rectangle slighly bigger
602 than the line ending, so that it get's clipped
612 p2.x = x2 - s.y - s.x*ee;
613 p2.y = y2 + s.x - s.y*ee;
614 p3.x = x2 - s.y + s.x*ee;
615 p3.y = y2 + s.x + s.y*ee;
620 m2.x = lx + e.y - e.x*ee;
621 m2.y = ly - e.x - e.y*ee;
622 m3.x = lx + e.y + e.x*ee;
623 m3.y = ly - e.x + e.y*ee;
625 for(nr=0;nr<2;nr++) {
627 struct plotxy q0,q1,q2,q3,q4,q5;
630 if(line_cap == LINE_CAP_BUTT) {
632 /* FIXME: box should be smaller */
634 q1.x = i->sizex; q1.y = 0;
635 q2.x = i->sizex; q2.y = i->sizey;
636 q3.x = 0; q3.y = i->sizey;
638 /* FIXME: box should be smaller */
639 q0.x = i->sizex; q0.y = i->sizey;
640 q1.x = 0; q1.y = i->sizey;
642 q3.x = i->sizex; q3.y = 0;
646 moveto(obj, i->tag, q0);
647 lineto(obj, i->tag, q1);
648 lineto(obj, i->tag, q2);
649 lineto(obj, i->tag, q3);
650 lineto(obj, i->tag, q0);
653 lineto(obj, i->tag, q4);
656 line(obj, i->tag, p0, p1, m);
657 line(obj, i->tag, p1, p2, m);
658 line(obj, i->tag, p2, p3, m);
659 line(obj, i->tag, p3, p0, m);
661 if(line_cap == LINE_CAP_BUTT) {
662 lineto(obj, i->tag, q0);
663 endshape(obj, i->depth+2-nr);
675 drawShortPath(obj,x,y,m,outline);
677 if(line_cap == LINE_CAP_BUTT) {
683 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)
685 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
686 plotxy d1,d2,p1,p2,p3,p4;
688 d1.x = (outline->dest.x/(float)0xffff);
689 d1.y = (outline->dest.y/(float)0xffff);
690 d2 = getPivot(obj, outline, 0, line_width, 0, 0);
692 assert(line_cap != LINE_CAP_ROUND);
693 if(line_cap == LINE_CAP_SQUARE) {
702 p2.x = x + d2.x + d1.x;
703 p2.y = y + d2.y + d1.y;
704 p3.x = x - d2.x + d1.x;
705 p3.y = y - d2.y + d1.y;
709 line(obj, i->tag, p1,p2, m);
710 line(obj, i->tag, p2,p3, m);
711 line(obj, i->tag, p3,p4, m);
712 line(obj, i->tag, p4,p1, m);
715 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)
717 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
718 SWF_OUTLINE*tmp=outline;
721 assert(i->shapeid>=0);
724 drawT1toRect(obj, x, y, m,outline, num, line_cap, line_join, line_width);
726 while(tmp->link && tmp->link->type!=SWF_PATHTYPE_MOVE) {
727 xx += (tmp->dest.x/(float)0xffff);
728 yy += (tmp->dest.y/(float)0xffff);
732 assert(tmp->type == SWF_PATHTYPE_LINE);
733 assert(outline->type == SWF_PATHTYPE_LINE);
737 if(outline->link == tmp) {
738 /* the two straight line segments (which are everything we
739 need to draw) are very likely to overlap. To avoid that
740 they cancel each other out at the end points, start a new
741 shape for the second one */
742 endshape(obj,0);startshape(obj);
746 drawT1toRect(obj, xx, yy, m, tmp, num, line_cap, line_join, line_width);
748 if(outline->link != tmp)
750 stopFill(obj);stop=1;
752 tmp->type = SWF_PATHTYPE_MOVE;
753 x += (outline->dest.x/(float)0xffff);
754 y += (outline->dest.y/(float)0xffff);
755 outline = outline->link;
756 drawShortPath(obj, x, y, m, outline);
764 static int t1len(struct swfoutput*obj, SWF_OUTLINE*line)
766 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
768 while(line && line->type != SWF_PATHTYPE_MOVE) {
775 static float t1linelen(struct swfoutput*obj, SWF_OUTLINE*line)
777 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
779 x = (line->dest.x/(float)0xffff);
780 y = (line->dest.y/(float)0xffff);
781 return sqrt(x*x+y*y);
784 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)
786 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
787 if( i->tag->id != ST_DEFINESHAPE &&
788 i->tag->id != ST_DEFINESHAPE2 &&
789 i->tag->id != ST_DEFINESHAPE3) {
790 msg("<error> internal error: drawpath needs a shape tag, not %d\n",i->tag->id);
793 assert(i->shapeid>=0);
795 double lastx=0,lasty=0;
798 SWF_OUTLINE*tmp = outline, *last = 0;
803 x += (tmp->dest.x/(float)0xffff);
804 y += (tmp->dest.y/(float)0xffff);
806 if(!tmp || tmp->type == SWF_PATHTYPE_MOVE) {
808 if(last->type == SWF_PATHTYPE_LINE && t1linelen(obj,last)>line_width*2 &&
809 lastwasline && line_cap != LINE_CAP_ROUND)
810 drawShortPathWithStraightEnds(obj, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
812 drawShortPathWithEnds(obj, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
826 if(tmp && tmp->type == SWF_PATHTYPE_LINE && t1linelen(obj,tmp)>line_width*2)
832 tmp->link->last = tmp; // make sure list is properly linked in both directions
837 static inline int colorcompare(struct swfoutput*obj, RGBA*a,RGBA*b)
849 static SRECT getcharacterbbox(struct swfoutput*obj, SWFFONT*font)
851 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
854 memset(&r, 0, sizeof(r));
857 if(debug) printf("\n");
858 for(t=0;t<i->chardatapos;t++)
860 if(i->chardata[t].fontid != font->id) {
861 msg("<error> Internal error: fontid %d != fontid %d", i->chardata[t].fontid, font->id);
864 SRECT b = font->layout->bounds[i->chardata[t].charid];
865 b.xmin *= i->chardata[t].size;
866 b.ymin *= i->chardata[t].size;
867 b.xmax *= i->chardata[t].size;
868 b.ymax *= i->chardata[t].size;
873 b.xmin += i->chardata[t].x;
874 b.ymin += i->chardata[t].y;
875 b.xmax += i->chardata[t].x;
876 b.ymax += i->chardata[t].y;
878 /* until we solve the INTERNAL_SCALING problem (see below)
879 make sure the bounding box is big enough */
885 if(debug) printf("(%f,%f,%f,%f) -> (%f,%f,%f,%f) [font %d/%d, char %d]\n",
886 font->layout->bounds[i->chardata[t].charid].xmin/20.0,
887 font->layout->bounds[i->chardata[t].charid].ymin/20.0,
888 font->layout->bounds[i->chardata[t].charid].xmax/20.0,
889 font->layout->bounds[i->chardata[t].charid].ymax/20.0,
894 i->chardata[t].fontid,
896 i->chardata[t].charid
898 swf_ExpandRect2(&r, &b);
900 if(debug) printf("-----> (%f,%f,%f,%f)\n",
908 static void putcharacters(struct swfoutput*obj, TAG*tag)
910 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
914 color.r = i->chardata[0].color.r^255;
923 int charadvance[128];
926 int glyphbits=1; //TODO: can this be zero?
929 if(tag->id != ST_DEFINETEXT &&
930 tag->id != ST_DEFINETEXT2) {
931 msg("<error> internal error: putcharacters needs an text tag, not %d\n",tag->id);
934 if(!i->chardatapos) {
935 msg("<warning> putcharacters called with zero characters");
938 for(pass = 0; pass < 2; pass++)
948 advancebits++; // add sign bit
949 swf_SetU8(tag, glyphbits);
950 swf_SetU8(tag, advancebits);
953 for(t=0;t<=i->chardatapos;t++)
955 if(lastfontid != i->chardata[t].fontid ||
956 lastx!=i->chardata[t].x ||
957 lasty!=i->chardata[t].y ||
958 !colorcompare(obj,&color, &i->chardata[t].color) ||
960 lastsize != i->chardata[t].size ||
963 if(charstorepos && pass==0)
966 for(s=0;s<charstorepos;s++)
968 while(charids[s]>=(1<<glyphbits))
970 while(charadvance[s]>=(1<<advancebits))
974 if(charstorepos && pass==1)
976 tag->writeBit = 0; // Q&D
977 swf_SetBits(tag, 0, 1); // GLYPH Record
978 swf_SetBits(tag, charstorepos, 7); // number of glyphs
980 for(s=0;s<charstorepos;s++)
982 swf_SetBits(tag, charids[s], glyphbits);
983 swf_SetBits(tag, charadvance[s], advancebits);
988 if(pass == 1 && t<i->chardatapos)
994 if(lastx != i->chardata[t].x ||
995 lasty != i->chardata[t].y)
997 newx = i->chardata[t].x;
998 newy = i->chardata[t].y;
1004 if(!colorcompare(obj,&color, &i->chardata[t].color))
1006 color = i->chardata[t].color;
1009 font.id = i->chardata[t].fontid;
1010 if(lastfontid != i->chardata[t].fontid || lastsize != i->chardata[t].size)
1013 tag->writeBit = 0; // Q&D
1014 swf_TextSetInfoRecord(tag, newfont, i->chardata[t].size, newcolor, newx,newy);
1017 lastfontid = i->chardata[t].fontid;
1018 lastx = i->chardata[t].x;
1019 lasty = i->chardata[t].y;
1020 lastsize = i->chardata[t].size;
1023 if(t==i->chardatapos)
1027 int nextt = t==i->chardatapos-1?t:t+1;
1028 int rel = i->chardata[nextt].x-i->chardata[t].x;
1029 if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) {
1031 lastx=i->chardata[nextt].x;
1035 lastx=i->chardata[t].x;
1037 charids[charstorepos] = i->chardata[t].charid;
1038 charadvance[charstorepos] = advance;
1045 static void putcharacter(struct swfoutput*obj, int fontid, int charid,
1046 int x,int y, int size)
1048 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1049 if(i->chardatapos == CHARDATAMAX)
1051 msg("<warning> Character buffer too small. SWF will be slightly bigger");
1055 i->chardata[i->chardatapos].fontid = fontid;
1056 i->chardata[i->chardatapos].charid = charid;
1057 i->chardata[i->chardatapos].x = x;
1058 i->chardata[i->chardatapos].y = y;
1059 i->chardata[i->chardatapos].color = obj->fillrgb;
1060 i->chardata[i->chardatapos].size = size;
1064 /* Notice: we can only put chars in the range -1639,1638 (-32768/20,32768/20).
1065 So if we set this value to high, the char coordinates will overflow.
1066 If we set it to low, however, the char positions will be inaccurate */
1067 #define FONT_INTERNAL_SIZE 4
1069 /* process a character. */
1070 static int drawchar(struct swfoutput*obj, SWFFONT *swffont, char*character, int charnr, int u, swfmatrix*m)
1072 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1074 msg("<warning> Font is NULL");
1078 int charid = getCharID(swffont, charnr, character, u);
1081 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1082 FIXNULL(character),charnr, u, FIXNULL((char*)swffont->name), swffont->numchars);
1093 float det = ((m->m11*m->m22)-(m->m21*m->m12));
1094 if(fabs(det) < 0.0005) {
1095 /* x direction equals y direction- the text is invisible */
1098 det = 20*FONT_INTERNAL_SIZE / det;
1101 p.x = (SCOORD)(( x * m->m22 - y * m->m12)*det);
1102 p.y = (SCOORD)((- x * m->m21 + y * m->m11)*det);
1104 putcharacter(obj, swffont->id, charid,p.x,p.y,FONT_INTERNAL_SIZE);
1105 swf_FontUseGlyph(swffont, charid);
1110 SWF_OUTLINE*outline = font->getOutline(character, charnr);
1111 char* charname = character;
1114 msg("<warning> Didn't find character '%s' (%d) in current charset (%s)",
1115 FIXNULL(character),charnr,FIXNULL(font->getName()));
1134 drawpath(tag, outline, &m2, 0);
1139 static void endtext(swfoutput*obj)
1141 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1145 i->tag = swf_InsertTag(i->tag,ST_DEFINETEXT);
1146 swf_SetU16(i->tag, i->textid);
1149 r = getcharacterbbox(obj, obj->swffont);
1151 swf_SetRect(i->tag,&r);
1154 swf_GetMatrix(0, &m);
1155 swf_SetMatrix(i->tag,&m);
1157 putcharacters(obj, i->tag);
1158 swf_SetU8(i->tag,0);
1159 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
1160 //swf_ObjectPlace(i->tag,i->textid,/*depth*/i->depth++,&i->page_matrix,NULL,NULL);
1162 swf_MatrixJoin(&m2,&obj->fontmatrix, &i->page_matrix);
1164 swf_ObjectPlace(i->tag,i->textid,/*depth*/i->depth++,&m2,NULL,NULL);
1169 /* draw a curved polygon. */
1170 void swfoutput_drawpath(swfoutput*obj, SWF_OUTLINE*outline,
1173 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1177 /* Multiple polygons in one shape don't overlap correctly,
1178 so we better start a new shape here if the polygon is filled
1180 if(i->shapeid>=0 && i->fill && !config_ignoredraworder) {
1193 drawpath(obj, outline,m, 0);
1196 void swfoutput_drawpath2poly(struct swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
1198 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1203 assert(i->shapeid<0);
1207 drawpath2poly(obj, outline, m, 0, line_join, line_cap, line_width, miter_limit);
1210 int getCharID(SWFFONT *font, int charnr, char *charname, int u)
1213 if(charname && font->glyphnames) {
1214 for(t=0;t<font->numchars;t++) {
1215 if(font->glyphnames[t] && !strcmp(font->glyphnames[t],charname)) {
1216 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1220 /* if we didn't find the character, maybe
1221 we can find the capitalized version */
1222 for(t=0;t<font->numchars;t++) {
1223 if(font->glyphnames[t] && !strcasecmp(font->glyphnames[t],charname)) {
1224 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1231 /* try to use the unicode id */
1232 if(u>=0 && u<font->maxascii && font->ascii2glyph[u]>=0) {
1233 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->ascii2glyph[u]);
1234 return font->ascii2glyph[u];
1238 if(font->encoding != FONT_ENCODING_UNICODE) {
1239 /* the following only works if the font encoding
1240 is US-ASCII based. It's needed for fonts which return broken unicode
1242 if(charnr>=0 && charnr<font->maxascii && font->ascii2glyph[charnr]>=0) {
1243 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, font->ascii2glyph[charnr]);
1244 return font->ascii2glyph[charnr];
1248 if(charnr>=0 && charnr<font->numchars) {
1249 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1257 /* set's the t1 font index of the font to use for swfoutput_drawchar(). */
1258 void swfoutput_setfont(struct swfoutput*obj, char*fontid, char*filename)
1260 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1261 fontlist_t*last=0,*iterator;
1263 msg("<error> No fontid");
1267 if(obj->swffont && obj->swffont->name && !strcmp((char*)obj->swffont->name,fontid))
1270 /* TODO: remove the need for this (enhance getcharacterbbox so that it can cope
1271 with multiple fonts */
1274 iterator = i->fontlist;
1276 if(!strcmp((char*)iterator->swffont->name,fontid)) {
1277 obj->swffont = iterator->swffont;
1281 iterator = iterator->next;
1285 msg("<error> No filename given for font- internal error?");
1289 swf_SetLoadFontParameters(64,/*skip unused*/0,/*full unicode*/1);
1290 SWFFONT*swffont = swf_LoadFont(filename);
1293 msg("<warning> Couldn't load font %s (%s)", fontid, filename);
1294 swffont = swf_LoadFont(0);
1297 swf_FontSetID(swffont, ++i->currentswfid);
1299 if(screenloglevel >= LOGLEVEL_DEBUG) {
1300 // print font information
1301 msg("<debug> Font %s (%s)",swffont->name, filename);
1302 msg("<debug> | ID: %d", swffont->id);
1303 msg("<debug> | Version: %d", swffont->version);
1304 msg("<debug> | Name: %s", fontid);
1305 msg("<debug> | Numchars: %d", swffont->numchars);
1306 msg("<debug> | Maxascii: %d", swffont->maxascii);
1307 msg("<debug> | Style: %d", swffont->style);
1308 msg("<debug> | Encoding: %d", swffont->encoding);
1309 for(int iii=0; iii<swffont->numchars;iii++) {
1310 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,
1311 swffont->layout->bounds[iii].xmin/20.0,
1312 swffont->layout->bounds[iii].ymin/20.0,
1313 swffont->layout->bounds[iii].xmax/20.0,
1314 swffont->layout->bounds[iii].ymax/20.0
1317 for(t=0;t<swffont->maxascii;t++) {
1318 if(swffont->ascii2glyph[t] == iii)
1319 msg("<debug> | - maps to %d",t);
1324 /* set the font name to the ID we use here */
1325 if(swffont->name) free(swffont->name);
1326 swffont->name = (U8*)strdup(fontid);
1328 iterator = new fontlist_t;
1329 iterator->swffont = swffont;
1333 last->next = iterator;
1335 i->fontlist = iterator;
1337 obj->swffont = swffont;
1340 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1342 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1343 fontlist_t *iterator = i->fontlist;
1345 if(!strcmp((char*)iterator->swffont->name,fontid))
1347 iterator = iterator->next;
1352 /* set's the matrix which is to be applied to characters drawn by
1353 swfoutput_drawchar() */
1354 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1355 double m21,double m22)
1357 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1358 if(obj->fontm11 == m11 &&
1359 obj->fontm12 == m12 &&
1360 obj->fontm21 == m21 &&
1361 obj->fontm22 == m22)
1371 m.sx = (U32)(((obj->fontm11)*65536)/FONT_INTERNAL_SIZE); m.r1 = (U32)(((obj->fontm12)*65536)/FONT_INTERNAL_SIZE);
1372 m.r0 = (U32)(((obj->fontm21)*65536)/FONT_INTERNAL_SIZE); m.sy = (U32)(((obj->fontm22)*65536)/FONT_INTERNAL_SIZE);
1375 obj->fontmatrix = m;
1378 /* draws a character at x,y. */
1379 int swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr, int u)
1381 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1383 m.m11 = obj->fontm11;
1384 m.m12 = obj->fontm12;
1385 m.m21 = obj->fontm21;
1386 m.m22 = obj->fontm22;
1389 return drawchar(obj, obj->swffont, character, charnr, u, &m);
1392 static void endpage(struct swfoutput*obj)
1394 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1400 swfoutput_endclip(obj);
1402 if(config_insertstoptag) {
1404 atag = action_Stop(atag);
1405 atag = action_End(atag);
1406 i->tag = swf_InsertTag(i->tag,ST_DOACTION);
1407 swf_ActionSet(i->tag,atag);
1409 i->tag = swf_InsertTag(i->tag,ST_SHOWFRAME);
1412 void swfoutput_newpage(struct swfoutput*obj, int pageNum, int movex, int movey, int x1, int y1, int x2, int y2)
1414 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1418 swf_GetMatrix(0, &i->page_matrix);
1419 i->page_matrix.tx = movex;
1420 i->page_matrix.ty = movey;
1422 for(i->depth--;i->depth>=i->startdepth;i->depth--) {
1423 i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2);
1424 swf_SetU16(i->tag,i->depth);
1426 i->depth = i->startdepth = 3; /* leave room for clip and background rectangle */
1430 x1*=20;y1*=20;x2*=20;y2*=20;
1432 if(i->lastpagesize.xmin != x1 ||
1433 i->lastpagesize.xmax != x2 ||
1434 i->lastpagesize.ymin != y1 ||
1435 i->lastpagesize.ymax != y2)
1436 {/* add white clipping rectangle */
1437 msg("<notice> processing page %d (%dx%d)", pageNum,i->sizex,i->sizey);
1440 msg("<notice> Page has a different size than previous ones");
1441 i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2);
1442 swf_SetU16(i->tag,1);
1443 i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2);
1444 swf_SetU16(i->tag,2);
1448 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1452 int shapeid = ++i->currentswfid;
1457 i->tag = swf_InsertTag(i->tag, ST_DEFINESHAPE);
1459 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1460 swf_SetU16(i->tag,shapeid);
1461 swf_SetRect(i->tag,&r);
1462 swf_SetShapeHeader(i->tag,s);
1463 swf_ShapeSetAll(i->tag,s,x1,y1,ls1,fs1,0);
1464 swf_ShapeSetLine(i->tag,s,(x2-x1),0);
1465 swf_ShapeSetLine(i->tag,s,0,(y2-y1));
1466 swf_ShapeSetLine(i->tag,s,(x1-x2),0);
1467 swf_ShapeSetLine(i->tag,s,0,(y1-y2));
1468 swf_ShapeSetEnd(i->tag);
1470 i->tag = swf_InsertTag(i->tag, ST_PLACEOBJECT2);
1471 swf_ObjectPlace(i->tag,shapeid,/*depth*/1,0,0,0);
1472 i->tag = swf_InsertTag(i->tag, ST_PLACEOBJECT2);
1473 swf_ObjectPlaceClip(i->tag,shapeid,/*depth*/2,0,0,0,65535);
1475 msg("<notice> processing page %d", pageNum);
1478 i->lastpagesize.xmin = x1;
1479 i->lastpagesize.xmax = x2;
1480 i->lastpagesize.ymin = y1;
1481 i->lastpagesize.ymax = y2;
1482 swf_ExpandRect2(&i->swf.movieSize, &i->lastpagesize);
1487 /* initialize the swf writer */
1488 void swfoutput_init(struct swfoutput* obj)
1490 memset(obj, 0, sizeof(struct swfoutput));
1491 obj->internal = init_internal_struct();
1493 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1498 msg("<verbose> initializing swf output for size %d*%d\n", i->sizex,i->sizey);
1503 memset(&i->swf,0x00,sizeof(SWF));
1504 memset(&i->lastpagesize,0x00,sizeof(SRECT));
1506 i->swf.fileVersion = config_flashversion;
1507 i->swf.frameRate = 0x0040; // 1 frame per 4 seconds
1508 i->swf.movieSize.xmin = 0;
1509 i->swf.movieSize.ymin = 0;
1510 i->swf.movieSize.xmax = 0;
1511 i->swf.movieSize.ymax = 0;
1513 i->swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1514 i->tag = i->swf.firstTag;
1515 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1516 swf_SetRGB(i->tag,&rgb);
1518 i->startdepth = i->depth = 0;
1521 i->tag = swf_InsertTag(i->tag, ST_PROTECT);
1524 static void startshape(struct swfoutput*obj)
1526 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1533 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE);
1535 swf_ShapeNew(&i->shape);
1536 i->linestyleid = swf_ShapeAddLineStyle(i->shape,i->linewidth,&obj->strokergb);
1537 rgb.r = obj->fillrgb.r;
1538 rgb.g = obj->fillrgb.g;
1539 rgb.b = obj->fillrgb.b;
1540 i->fillstyleid = swf_ShapeAddSolidFillStyle(i->shape,&obj->fillrgb);
1542 i->shapeid = ++i->currentswfid;
1543 swf_SetU16(i->tag,i->shapeid); // ID
1545 i->bboxrectpos = i->tag->len;
1548 r.xmax = 20*i->sizex;
1549 r.ymax = 20*i->sizey;
1550 swf_SetRect(i->tag,&r);
1552 memset(&i->bboxrect, 0, sizeof(i->bboxrect));
1554 swf_SetShapeStyles(i->tag,i->shape);
1555 swf_ShapeCountBits(i->shape,NULL,NULL);
1556 swf_SetShapeBits(i->tag,i->shape);
1558 /* TODO: do we really need this? */
1559 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,i->linestyleid,0,0);
1560 i->swflastx=i->swflasty=0;
1562 i->shapeisempty = 1;
1565 static void starttext(struct swfoutput*obj)
1567 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1571 i->textid = ++i->currentswfid;
1573 i->swflastx=i->swflasty=0;
1577 /* TODO: move to ../lib/rfxswf */
1578 void changeRect(struct swfoutput*obj, TAG*tag, int pos, SRECT*newrect)
1580 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1581 /* determine length of old rect */
1585 swf_GetRect(tag, &old);
1586 swf_ResetReadBits(tag);
1587 int pos_end = tag->pos;
1589 int len = tag->len - pos_end;
1590 U8*data = (U8*)malloc(len);
1591 memcpy(data, &tag->data[pos_end], len);
1594 swf_SetRect(tag, newrect);
1595 swf_SetBlock(tag, data, len);
1597 tag->pos = tag->readBit = 0;
1600 void cancelshape(swfoutput*obj)
1602 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1603 /* delete old shape tag */
1605 i->tag = i->tag->prev;
1606 swf_DeleteTag(todel);
1607 if(i->shape) {swf_ShapeFree(i->shape);i->shape=0;}
1609 i->bboxrectpos = -1;
1612 void fixAreas(swfoutput*obj)
1614 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1615 if(!i->shapeisempty && i->fill &&
1616 (i->bboxrect.xmin == i->bboxrect.xmax ||
1617 i->bboxrect.ymin == i->bboxrect.ymax) &&
1618 config_minlinewidth >= 0.001
1620 msg("<debug> Shape has size 0: width=%.2f height=%.2f",
1621 (i->bboxrect.xmax-i->bboxrect.xmin)/20.0,
1622 (i->bboxrect.ymax-i->bboxrect.ymin)/20.0
1625 SRECT r = i->bboxrect;
1627 if(r.xmin == r.xmax && r.ymin == r.ymax) {
1628 /* this thing comes down to a single dot- nothing to fix here */
1634 RGBA save_col = obj->strokergb;
1635 int save_width = i->linewidth;
1637 obj->strokergb = obj->fillrgb;
1638 i->linewidth = (int)(config_minlinewidth*20);
1639 if(i->linewidth==0) i->linewidth = 1;
1643 moveto(obj, i->tag, r.xmin/20.0,r.ymin/20.0);
1644 lineto(obj, i->tag, r.xmax/20.0,r.ymax/20.0);
1646 obj->strokergb = save_col;
1647 i->linewidth = save_width;
1652 static void endshape_noput(swfoutput*obj)
1654 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1657 //changeRect(obj, i->tag, i->bboxrectpos, &i->bboxrect);
1660 swf_ShapeFree(i->shape);
1665 static void endshape(swfoutput*obj, int clipdepth)
1667 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1674 if(i->shapeisempty ||
1675 (i->bboxrect.xmin == i->bboxrect.xmax &&
1676 i->bboxrect.ymin == i->bboxrect.ymax))
1678 // delete the shape again, we didn't do anything
1683 swf_ShapeSetEnd(i->tag);
1685 changeRect(obj, i->tag, i->bboxrectpos, &i->bboxrect);
1687 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
1690 swf_ObjectPlaceClip(i->tag,i->shapeid,i->depth++,&i->page_matrix,NULL,NULL,clipdepth);
1692 swf_ObjectPlace(i->tag,i->shapeid,/*depth*/i->depth++,&i->page_matrix,NULL,NULL);
1694 swf_ShapeFree(i->shape);
1697 i->bboxrectpos = -1;
1700 void swfoutput_save(struct swfoutput* obj, char*filename)
1702 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1704 fontlist_t *tmp,*iterator = i->fontlist;
1706 TAG*mtag = i->swf.firstTag;
1707 if(iterator->swffont) {
1708 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1709 /*if(!storeallcharacters)
1710 swf_FontReduce(iterator->swffont);*/
1711 swf_FontSetDefine2(mtag, iterator->swffont);
1714 iterator = iterator->next;
1719 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1724 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1728 i->tag = swf_InsertTag(i->tag,ST_END);
1730 if(config_enablezlib || config_flashversion>=6) {
1731 if FAILED(swf_WriteSWC(fi,&i->swf))
1732 msg("<error> WriteSWC() failed.\n");
1734 if FAILED(swf_WriteSWF(fi,&i->swf))
1735 msg("<error> WriteSWF() failed.\n");
1740 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(&i->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);