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"
41 int ignoredraworder=0;
44 int storeallcharacters=0;
49 int fontsplinemaxerror=1;
51 float minlinewidth=0.05;
53 static char storefont = 0;
54 static int flag_protected = 0;
56 typedef unsigned char u8;
57 typedef unsigned short int u16;
58 typedef unsigned long int u32;
61 static char* filename = 0;
64 static int currentswfid = 0;
66 static int startdepth = 1;
67 static int linewidth = 0;
68 static SRECT lastpagesize;
71 static int shapeid = -1;
72 static int textid = -1;
74 static int fillstyleid;
75 static int linestyleid;
76 static int swflastx=0;
77 static int swflasty=0;
78 static int lastwasfill = 0;
79 static int shapeisempty = 1;
91 char fillstylechanged = 0;
96 static void startshape(struct swfoutput* obj);
97 static void starttext(struct swfoutput* obj);
98 static void endshape(struct swfoutput* obj,int clip);
99 static void endtext(struct swfoutput* obj);
101 // matrix multiplication. changes p0
102 static void transform (plotxy*p0,struct swfmatrix*m)
105 x = m->m11*p0->x+m->m12*p0->y;
106 y = m->m21*p0->x+m->m22*p0->y;
111 // write a move-to command into the swf
112 static int moveto(TAG*tag, plotxy p0)
114 int rx = (int)(p0.x*20);
115 int ry = (int)(p0.y*20);
116 if(rx!=swflastx || ry!=swflasty || fillstylechanged) {
117 swf_ShapeSetMove (tag, shape, rx,ry);
118 fillstylechanged = 0;
125 static int moveto(TAG*tag, float x, float y)
130 return moveto(tag, p);
132 static void addPointToBBox(int px, int py)
138 swf_ExpandRect(&bboxrect, p);
140 swf_ExpandRect3(&bboxrect, p, linewidth*3/2);
144 // write a line-to command into the swf
145 static void lineto(TAG*tag, plotxy p0)
147 int px = (int)(p0.x*20);
148 int py = (int)(p0.y*20);
149 int rx = (px-swflastx);
150 int ry = (py-swflasty);
151 /* we can't skip this for rx=0,ry=0, those
153 swf_ShapeSetLine (tag, shape, rx,ry);
155 addPointToBBox(swflastx,swflasty);
156 addPointToBBox(px,py);
162 static void lineto(TAG*tag, double x, double y)
171 // write a spline-to command into the swf
172 static void splineto(TAG*tag, plotxy control,plotxy end)
174 int lastlastx = swflastx;
175 int lastlasty = swflasty;
177 int cx = ((int)(control.x*20)-swflastx);
178 int cy = ((int)(control.y*20)-swflasty);
181 int ex = ((int)(end.x*20)-swflastx);
182 int ey = ((int)(end.y*20)-swflasty);
186 if(cx || cy || ex || ey) {
187 swf_ShapeSetCurve(tag, shape, cx,cy,ex,ey);
188 addPointToBBox(lastlastx ,lastlasty );
189 addPointToBBox(lastlastx+cx,lastlasty+cy);
190 addPointToBBox(lastlastx+cx+ex,lastlasty+cy+ey);
195 /* write a line, given two points and the transformation
197 static void line(TAG*tag, plotxy p0, plotxy p1, struct swfmatrix*m)
205 /* write a cubic (!) spline. This involves calling the approximate()
206 function out of spline.cc to convert it to a quadratic spline. */
207 static void spline(TAG*tag,plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m)
210 struct qspline q[128];
224 /* fonts use a different approximation than shapes */
225 num = cspline_approximate(&c, q, fontsplinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
226 //num = cspline_approximate(&c, q, 10.0, APPROXIMATE_INFLECTION);
228 num = cspline_approximate(&c, q, splinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
232 moveto(tag,q[t].start);
233 splineto(tag,q[t].control, q[t].end);
243 static void stopFill()
247 swf_ShapeSetStyle(tag,shape,linestyleid,0x8000,0);
248 fillstylechanged = 1;
252 static void startFill()
256 swf_ShapeSetStyle(tag,shape,0x8000,fillstyleid,0);
257 fillstylechanged = 1;
262 /* draw an outline. These are generated by pdf2swf and by t1lib
263 (representing characters). */
264 void drawpath(struct swfoutput*output, SWF_OUTLINE*outline, struct swfmatrix*m, int log)
266 if( tag->id != ST_DEFINESHAPE &&
267 tag->id != ST_DEFINESHAPE2 &&
268 tag->id != ST_DEFINESHAPE3)
270 msg("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
274 double lastx=0,lasty=0;
275 double firstx=0,firsty=0;
280 x += (outline->dest.x/(float)0xffff);
281 y += (outline->dest.y/(float)0xffff);
282 if(outline->type == SWF_PATHTYPE_MOVE)
284 //if(!init && fill && output->drawmode != DRAWMODE_EOFILL && !ignoredraworder) {
285 if(filloverlap && !init && fill && output->drawmode != DRAWMODE_EOFILL) {
286 /* drawmode=FILL (not EOFILL) means that
287 seperate shapes do not cancel each other out.
288 On SWF side, we need to start a new shape for each
289 closed polygon, because SWF only knows EOFILL.
296 if(((int)(lastx*20) != (int)(firstx*20) ||
297 (int)(lasty*20) != (int)(firsty*20)) &&
306 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
307 line(tag, p0, p1, m);
313 else if(outline->type == SWF_PATHTYPE_LINE)
321 if(log) printf("line: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
324 else if(outline->type == SWF_PATHTYPE_BEZIER)
330 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
333 p1.x=o2->C.x/(float)0xffff+lastx;
334 p1.y=o2->C.y/(float)0xffff+lasty;
335 p2.x=o2->B.x/(float)0xffff+lastx;
336 p2.y=o2->B.y/(float)0xffff+lasty;
339 if(log) printf("spline: %f,%f -> %f,%f\n",p3.x,p3.y,p0.x,p0.y);
340 spline(tag,p0,p1,p2,p3,m);
343 msg("<error> drawpath: unknown outline type:%d\n", outline->type);
347 outline = outline->link;
349 if(((int)(lastx*20) != (int)(firstx*20) ||
350 (int)(lasty*20) != (int)(firsty*20)) &&
359 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
360 line(tag, p0, p1, m);
364 plotxy getPivot(SWF_OUTLINE*outline, int dir, double line_width, int end, int trytwo)
366 SWF_PATHPOINT next, next2;
367 double xv=0,yv=0, xv2=0, yv2=0;
372 if(outline->type == SWF_PATHTYPE_LINE) {
373 next = outline->dest;
375 next = ((SWF_BEZIERSEGMENT*)outline)->B;
376 if(next.x==0 && next.y==0) {
377 next = ((SWF_BEZIERSEGMENT*)outline)->C;
379 if(next.x==0 && next.y==0) {
380 next = ((SWF_BEZIERSEGMENT*)outline)->dest;
384 if(trytwo && outline->last && outline->last->type != SWF_PATHTYPE_MOVE) {
385 if(outline->type == SWF_PATHTYPE_LINE) {
386 next2 = outline->last->dest;
388 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)(outline->last))->C;
389 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)(outline->last))->B;
390 next2.x = outline->last->dest.x - c.x;
391 next2.y = outline->last->dest.y - c.y;
392 if(next2.x==0 && next2.y==0) {
393 next2.x = outline->last->dest.x - b.x;
394 next2.y = outline->last->dest.y - b.y;
396 if(next2.x==0 && next2.y==0) {
397 next2.x = outline->last->dest.x;
398 next2.y = outline->last->dest.y;
404 if(outline->type == SWF_PATHTYPE_LINE) {
405 next = outline->dest;
407 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)outline)->C;
408 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)outline)->B;
409 next.x = outline->dest.x - c.x;
410 next.y = outline->dest.y - c.y;
411 if(next.x==0 && next.y==0) {
412 next.x = outline->dest.x - b.x;
413 next.y = outline->dest.y - b.y;
415 if(next.x==0 && next.y==0) {
416 next.x = outline->dest.x;
417 next.y = outline->dest.y;
421 if(trytwo && outline->link && outline->link->type != SWF_PATHTYPE_MOVE) {
422 if(outline->type == SWF_PATHTYPE_LINE) {
423 next2 = outline->link->dest;
425 next2 = ((SWF_BEZIERSEGMENT*)(outline->link))->B;
426 if(next2.x==0 && next2.y==0) {
427 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->C;
429 if(next2.x==0 && next2.y==0) {
430 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->dest;
438 xv = next.y/(float)0xffff;
439 yv = -next.x/(float)0xffff;
441 xv = -next.y/(float)0xffff;
442 yv = next.x/(float)0xffff;
445 double r = (line_width/2)/sqrt(xv*xv+yv*yv);
451 xv2 = next2.y/(float)0xffff;
452 yv2 = -next2.x/(float)0xffff;
454 xv2 = -next2.y/(float)0xffff;
455 yv2 = next2.x/(float)0xffff;
458 double r2 = (line_width/2)/sqrt(xv2*xv2+yv2*yv2);
463 double r3 = (line_width/2)/sqrt(xv*xv+yv*yv);
473 void drawShortPath(struct swfoutput*output, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline)
475 double lastx=x, lasty=y;
476 while (outline && outline->type != SWF_PATHTYPE_MOVE)
478 x += (outline->dest.x/(float)0xffff);
479 y += (outline->dest.y/(float)0xffff);
481 if(outline->type == SWF_PATHTYPE_LINE)
488 line(tag, p0, p1, m);
490 else if(outline->type == SWF_PATHTYPE_BEZIER)
493 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
496 p1.x=o2->C.x/(float)0xffff+lastx;
497 p1.y=o2->C.y/(float)0xffff+lasty;
498 p2.x=o2->B.x/(float)0xffff+lastx;
499 p2.y=o2->B.y/(float)0xffff+lasty;
502 spline(tag,p0,p1,p2,p3,m);
506 outline = outline->link;
510 void drawShortPathWithEnds(struct swfoutput*output, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline, int num, int line_cap, int line_join, double line_width)
515 if(line_cap == LINE_CAP_BUTT || line_cap == LINE_CAP_SQUARE) {
518 SWF_OUTLINE *last, *tmp=outline;
519 plotxy s,e,p0,p1,p2,p3,m0,m1,m2,m3;
525 while(tmp && tmp->type != SWF_PATHTYPE_MOVE) {
527 lx += (tmp->dest.x/(float)0xffff);
528 ly += (tmp->dest.y/(float)0xffff);
531 s = getPivot(outline, 0, line_width, 0, 0);
532 e = getPivot(last, 0, line_width, 1, 0);
534 if(line_cap == LINE_CAP_BUTT) {
535 /* make the clipping rectangle slighly bigger
536 than the line ending, so that it get's clipped
546 p2.x = x2 - s.y - s.x*ee;
547 p2.y = y2 + s.x - s.y*ee;
548 p3.x = x2 - s.y + s.x*ee;
549 p3.y = y2 + s.x + s.y*ee;
554 m2.x = lx + e.y - e.x*ee;
555 m2.y = ly - e.x - e.y*ee;
556 m3.x = lx + e.y + e.x*ee;
557 m3.y = ly - e.x + e.y*ee;
559 for(nr=0;nr<2;nr++) {
561 struct plotxy q0,q1,q2,q3,q4,q5;
564 if(line_cap == LINE_CAP_BUTT) {
567 q1.x = sizex; q1.y = 0;
568 q2.x = sizex; q2.y = sizey;
569 q3.x = 0; q3.y = sizey;
571 q0.x = sizex; q0.y = sizey;
572 q1.x = 0; q1.y = sizey;
574 q3.x = sizex; q3.y = 0;
588 line(tag, p0, p1, m);
589 line(tag, p1, p2, m);
590 line(tag, p2, p3, m);
591 line(tag, p3, p0, m);
593 if(line_cap == LINE_CAP_BUTT) {
595 endshape(output, depth+2-nr);
607 drawShortPath(output,x,y,m,outline);
609 if(line_cap == LINE_CAP_BUTT) {
615 void drawT1toRect(struct swfoutput*output, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline, int num, int line_cap, int line_join, double line_width)
617 plotxy d1,d2,p1,p2,p3,p4;
619 d1.x = (outline->dest.x/(float)0xffff);
620 d1.y = (outline->dest.y/(float)0xffff);
621 d2 = getPivot(outline, 0, line_width, 0, 0);
623 assert(line_cap != LINE_CAP_ROUND);
624 if(line_cap == LINE_CAP_SQUARE) {
633 p2.x = x + d2.x + d1.x;
634 p2.y = y + d2.y + d1.y;
635 p3.x = x - d2.x + d1.x;
636 p3.y = y - d2.y + d1.y;
646 void drawShortPathWithStraightEnds(struct swfoutput*output, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline, int num, int line_cap, int line_join, double line_width)
648 SWF_OUTLINE*tmp=outline;
654 drawT1toRect(output, x, y, m,outline, num, line_cap, line_join, line_width);
656 while(tmp->link && tmp->link->type!=SWF_PATHTYPE_MOVE) {
657 xx += (tmp->dest.x/(float)0xffff);
658 yy += (tmp->dest.y/(float)0xffff);
662 assert(tmp->type == SWF_PATHTYPE_LINE);
663 assert(outline->type == SWF_PATHTYPE_LINE);
667 if(outline->link == tmp) {
668 /* the two straight line segments (which are everything we
669 need to draw) are very likely to overlap. To avoid that
670 they cancel each other out at the end points, start a new
671 shape for the second one */
672 endshape(output,0);startshape(output);
676 drawT1toRect(output, xx, yy, m, tmp, num, line_cap, line_join, line_width);
678 if(outline->link != tmp)
682 tmp->type = SWF_PATHTYPE_MOVE;
683 x += (outline->dest.x/(float)0xffff);
684 y += (outline->dest.y/(float)0xffff);
685 outline = outline->link;
686 drawShortPath(output, x, y, m, outline);
694 static int t1len(SWF_OUTLINE*line)
697 while(line && line->type != SWF_PATHTYPE_MOVE) {
704 static float t1linelen(SWF_OUTLINE*line)
707 x = (line->dest.x/(float)0xffff);
708 y = (line->dest.y/(float)0xffff);
709 return sqrt(x*x+y*y);
712 void drawpath2poly(struct swfoutput *output, SWF_OUTLINE*outline, struct swfmatrix*m, int log, int line_join, int line_cap, double line_width, double miter_limit)
714 if( tag->id != ST_DEFINESHAPE &&
715 tag->id != ST_DEFINESHAPE2 &&
716 tag->id != ST_DEFINESHAPE3) {
717 msg("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
722 double lastx=0,lasty=0;
725 SWF_OUTLINE*tmp = outline, *last = 0;
730 x += (tmp->dest.x/(float)0xffff);
731 y += (tmp->dest.y/(float)0xffff);
733 if(!tmp || tmp->type == SWF_PATHTYPE_MOVE) {
735 if(last->type == SWF_PATHTYPE_LINE && t1linelen(last)>line_width*2 &&
736 lastwasline && line_cap != LINE_CAP_ROUND)
737 drawShortPathWithStraightEnds(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
739 drawShortPathWithEnds(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
753 if(tmp && tmp->type == SWF_PATHTYPE_LINE && t1linelen(tmp)>line_width*2)
759 tmp->link->last = tmp; // make sure list is properly linked in both directions
764 static inline int colorcompare(RGBA*a,RGBA*b)
776 static const int CHARDATAMAX = 8192;
779 int fontid; /* TODO: use a SWFFONT instead */
784 } chardata[CHARDATAMAX];
787 static SRECT getcharacterbbox(SWFFONT*font)
791 memset(&r, 0, sizeof(r));
794 if(debug) printf("\n");
795 for(t=0;t<chardatapos;t++)
797 if(chardata[t].fontid != font->id) {
798 msg("<error> Internal error: fontid %d != fontid %d", chardata[t].fontid, font->id);
801 SRECT b = font->layout->bounds[chardata[t].charid];
802 b.xmin *= chardata[t].size;
803 b.ymin *= chardata[t].size;
804 b.xmax *= chardata[t].size;
805 b.ymax *= chardata[t].size;
810 b.xmin += chardata[t].x;
811 b.ymin += chardata[t].y;
812 b.xmax += chardata[t].x;
813 b.ymax += chardata[t].y;
815 /* until we solve the INTERNAL_SCALING problem (see below)
816 make sure the bounding box is big enough */
822 if(debug) printf("(%f,%f,%f,%f) -> (%f,%f,%f,%f) [font %d/%d, char %d]\n",
823 font->layout->bounds[chardata[t].charid].xmin/20.0,
824 font->layout->bounds[chardata[t].charid].ymin/20.0,
825 font->layout->bounds[chardata[t].charid].xmax/20.0,
826 font->layout->bounds[chardata[t].charid].ymax/20.0,
835 swf_ExpandRect2(&r, &b);
837 if(debug) printf("-----> (%f,%f,%f,%f)\n",
845 static void putcharacters(TAG*tag)
850 color.r = chardata[0].color.r^255;
859 int charadvance[128];
862 int glyphbits=1; //TODO: can this be zero?
865 if(tag->id != ST_DEFINETEXT &&
866 tag->id != ST_DEFINETEXT2) {
867 msg("<error> internal error: putcharacters needs an text tag, not %d\n",tag->id);
871 msg("<warning> putcharacters called with zero characters");
874 for(pass = 0; pass < 2; pass++)
884 advancebits++; // add sign bit
885 swf_SetU8(tag, glyphbits);
886 swf_SetU8(tag, advancebits);
889 for(t=0;t<=chardatapos;t++)
891 if(lastfontid != chardata[t].fontid ||
892 lastx!=chardata[t].x ||
893 lasty!=chardata[t].y ||
894 !colorcompare(&color, &chardata[t].color) ||
896 lastsize != chardata[t].size ||
899 if(charstorepos && pass==0)
902 for(s=0;s<charstorepos;s++)
904 while(charids[s]>=(1<<glyphbits))
906 while(charadvance[s]>=(1<<advancebits))
910 if(charstorepos && pass==1)
912 tag->writeBit = 0; // Q&D
913 swf_SetBits(tag, 0, 1); // GLYPH Record
914 swf_SetBits(tag, charstorepos, 7); // number of glyphs
916 for(s=0;s<charstorepos;s++)
918 swf_SetBits(tag, charids[s], glyphbits);
919 swf_SetBits(tag, charadvance[s], advancebits);
924 if(pass == 1 && t<chardatapos)
930 if(lastx != chardata[t].x ||
931 lasty != chardata[t].y)
933 newx = chardata[t].x;
934 newy = chardata[t].y;
940 if(!colorcompare(&color, &chardata[t].color))
942 color = chardata[t].color;
945 font.id = chardata[t].fontid;
946 if(lastfontid != chardata[t].fontid || lastsize != chardata[t].size)
949 tag->writeBit = 0; // Q&D
950 swf_TextSetInfoRecord(tag, newfont, chardata[t].size, newcolor, newx,newy);
953 lastfontid = chardata[t].fontid;
954 lastx = chardata[t].x;
955 lasty = chardata[t].y;
956 lastsize = chardata[t].size;
963 int nextt = t==chardatapos-1?t:t+1;
964 int rel = chardata[nextt].x-chardata[t].x;
965 if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) {
967 lastx=chardata[nextt].x;
973 charids[charstorepos] = chardata[t].charid;
974 charadvance[charstorepos] = advance;
981 static void putcharacter(struct swfoutput*obj, int fontid, int charid,
982 int x,int y, int size)
984 if(chardatapos == CHARDATAMAX)
986 msg("<warning> Character buffer too small. SWF will be slightly bigger");
990 chardata[chardatapos].fontid = fontid;
991 chardata[chardatapos].charid = charid;
992 chardata[chardatapos].x = x;
993 chardata[chardatapos].y = y;
994 chardata[chardatapos].color = obj->fillrgb;
995 chardata[chardatapos].size = size;
1005 /* Notice: we can only put chars in the range -1639,1638 (-32768/20,32768/20).
1006 So if we set this value to high, the char coordinates will overflow.
1007 If we set it to low, however, the char positions will be inaccurate */
1008 #define FONT_INTERNAL_SIZE 4
1010 /* process a character. */
1011 static int drawchar(struct swfoutput*obj, SWFFONT *swffont, char*character, int charnr, int u, swfmatrix*m)
1014 msg("<warning> Font is NULL");
1018 int charid = getCharID(swffont, charnr, character, u);
1021 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1022 FIXNULL(character),charnr, u, FIXNULL((char*)swffont->name), swffont->numchars);
1033 float det = ((m->m11*m->m22)-(m->m21*m->m12));
1034 if(fabs(det) < 0.0005) {
1035 /* x direction equals y direction- the text is invisible */
1038 det = 20*FONT_INTERNAL_SIZE / det;
1041 p.x = (SCOORD)(( x * m->m22 - y * m->m12)*det);
1042 p.y = (SCOORD)((- x * m->m21 + y * m->m11)*det);
1044 putcharacter(obj, swffont->id, charid,p.x,p.y,FONT_INTERNAL_SIZE);
1045 swf_FontUseGlyph(swffont, charid);
1050 SWF_OUTLINE*outline = font->getOutline(character, charnr);
1051 char* charname = character;
1054 msg("<warning> Didn't find character '%s' (%d) in current charset (%s)",
1055 FIXNULL(character),charnr,FIXNULL(font->getName()));
1074 drawpath(tag, outline, &m2, 0);
1079 static void endtext(swfoutput*obj)
1084 tag = swf_InsertTag(tag,ST_DEFINETEXT);
1085 swf_SetU16(tag, textid);
1088 r = getcharacterbbox(obj->swffont);
1090 swf_SetRect(tag,&r);
1093 swf_GetMatrix(0, &m);
1094 swf_SetMatrix(tag,&m);
1098 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1099 swf_ObjectPlace(tag,textid,/*depth*/depth++,&obj->fontmatrix,NULL,NULL);
1104 /* draw a curved polygon. */
1105 void swfoutput_drawpath(swfoutput*output, SWF_OUTLINE*outline,
1111 /* Multiple polygons in one shape don't overlap correctly,
1112 so we better start a new shape here if the polygon is filled
1114 if(shapeid>=0 && fill && !ignoredraworder) {
1126 drawpath(output, outline,m, 0);
1129 void swfoutput_drawpath2poly(struct swfoutput*output, SWF_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
1139 drawpath2poly(output, outline, m, 0, line_join, line_cap, line_width, miter_limit);
1142 int getCharID(SWFFONT *font, int charnr, char *charname, int u)
1146 for(t=0;t<font->numchars;t++) {
1147 if(font->glyphnames[t] && !strcmp(font->glyphnames[t],charname)) {
1148 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1152 /* if we didn't find the character, maybe
1153 we can find the capitalized version */
1154 for(t=0;t<font->numchars;t++) {
1155 if(font->glyphnames[t] && !strcasecmp(font->glyphnames[t],charname)) {
1156 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1163 /* try to use the unicode id */
1164 if(u>=0 && u<font->maxascii && font->ascii2glyph[u]>=0) {
1165 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->ascii2glyph[u]);
1166 return font->ascii2glyph[u];
1170 if(charnr>=0 && charnr<font->numchars) {
1171 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1175 if(font->encoding != FONT_ENCODING_UNICODE) {
1176 /* the following only works if the font encoding
1177 is US-ASCII based. It's needed for fonts which return broken unicode
1179 if(charnr>=0 && charnr<font->maxascii && font->ascii2glyph[charnr]>=0) {
1180 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, font->ascii2glyph[charnr]);
1181 return font->ascii2glyph[charnr];
1189 /* set's the t1 font index of the font to use for swfoutput_drawchar(). */
1190 void swfoutput_setfont(struct swfoutput*obj, char*fontid, char*filename)
1192 fontlist_t*last=0,*iterator;
1194 msg("<error> No fontid");
1198 if(obj->swffont && obj->swffont->name && !strcmp((char*)obj->swffont->name,fontid))
1201 /* TODO: remove the need for this (enhance getcharacterbbox so that it can cope
1202 with multiple fonts */
1205 iterator = fontlist;
1207 if(!strcmp((char*)iterator->swffont->name,fontid)) {
1208 obj->swffont = iterator->swffont;
1212 iterator = iterator->next;
1216 msg("<error> No filename given for font- internal error?");
1220 swf_SetLoadFontParameters(64,/*skip unused*/0,/*full unicode*/1);
1221 SWFFONT*swffont = swf_LoadFont(filename);
1224 msg("<warning> Couldn't load font %s (%s)", fontid, filename);
1225 swffont = swf_LoadFont(0);
1228 swf_FontSetID(swffont, ++currentswfid);
1230 if(screenloglevel >= LOGLEVEL_DEBUG) {
1231 // print font information
1232 msg("<debug> Font %s (%s)",swffont->name, filename);
1233 msg("<debug> | ID: %d", swffont->id);
1234 msg("<debug> | Version: %d", swffont->version);
1235 msg("<debug> | Name: %s", fontid);
1236 msg("<debug> | Numchars: %d", swffont->numchars);
1237 msg("<debug> | Maxascii: %d", swffont->maxascii);
1238 msg("<debug> | Style: %d", swffont->style);
1239 msg("<debug> | Encoding: %d", swffont->encoding);
1240 for(int iii=0; iii<swffont->numchars;iii++) {
1241 msg("<debug> | Glyph %d) name=%s, unicode=%d size=%d bbox=(%.2f,%.2f,%.2f,%.2f)\n", iii, swffont->glyphnames[iii], swffont->glyph2ascii[iii], swffont->glyph[iii].shape->bitlen,
1242 swffont->layout->bounds[iii].xmin/20.0,
1243 swffont->layout->bounds[iii].ymin/20.0,
1244 swffont->layout->bounds[iii].xmax/20.0,
1245 swffont->layout->bounds[iii].ymax/20.0
1248 for(t=0;t<swffont->maxascii;t++) {
1249 if(swffont->ascii2glyph[t] == iii)
1250 msg("<debug> | - maps to %d",t);
1255 /* set the font name to the ID we use here */
1256 if(swffont->name) free(swffont->name);
1257 swffont->name = (U8*)strdup(fontid);
1259 iterator = new fontlist_t;
1260 iterator->swffont = swffont;
1264 last->next = iterator;
1266 fontlist = iterator;
1268 obj->swffont = swffont;
1271 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1273 fontlist_t *iterator = fontlist;
1275 if(!strcmp((char*)iterator->swffont->name,fontid))
1277 iterator = iterator->next;
1282 /* set's the matrix which is to be applied to characters drawn by
1283 swfoutput_drawchar() */
1284 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1285 double m21,double m22)
1287 if(obj->fontm11 == m11 &&
1288 obj->fontm12 == m12 &&
1289 obj->fontm21 == m21 &&
1290 obj->fontm22 == m22)
1300 m.sx = (U32)(((obj->fontm11)*65536)/FONT_INTERNAL_SIZE); m.r1 = (U32)(((obj->fontm12)*65536)/FONT_INTERNAL_SIZE);
1301 m.r0 = (U32)(((obj->fontm21)*65536)/FONT_INTERNAL_SIZE); m.sy = (U32)(((obj->fontm22)*65536)/FONT_INTERNAL_SIZE);
1304 obj->fontmatrix = m;
1307 /* draws a character at x,y. */
1308 int swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr, int u)
1311 m.m11 = obj->fontm11;
1312 m.m12 = obj->fontm12;
1313 m.m21 = obj->fontm21;
1314 m.m22 = obj->fontm22;
1317 return drawchar(obj, obj->swffont, character, charnr, u, &m);
1320 static void endpage(struct swfoutput*obj)
1327 swfoutput_endclip(obj);
1331 atag = action_Stop(atag);
1332 atag = action_End(atag);
1333 tag = swf_InsertTag(tag,ST_DOACTION);
1334 swf_ActionSet(tag,atag);
1336 tag = swf_InsertTag(tag,ST_SHOWFRAME);
1339 static int firstpage = 1;
1340 void swfoutput_newpage(struct swfoutput*obj, int pageNum, int x1, int y1, int x2, int y2)
1344 for(depth--;depth>=startdepth;depth--) {
1345 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1346 swf_SetU16(tag,depth);
1348 depth = startdepth = 3; /* leave room for clip and background rectangle */
1350 if(lastpagesize.xmin != x1 ||
1351 lastpagesize.xmax != x2 ||
1352 lastpagesize.ymin != y1 ||
1353 lastpagesize.ymax != y2)
1354 {/* add white clipping rectangle */
1357 msg("<notice> processing page %d (%dx%d)", pageNum,sizex,sizey);
1360 msg("<notice> Page has a different size than previous ones");
1361 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1363 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1368 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1372 int shapeid = ++currentswfid;
1377 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
1379 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1380 swf_SetU16(tag,shapeid);
1381 swf_SetRect(tag,&r);
1382 swf_SetShapeHeader(tag,s);
1383 swf_ShapeSetAll(tag,s,x1*20,y1*20,ls1,fs1,0);
1384 swf_ShapeSetLine(tag,s,20*(x2-x1),0);
1385 swf_ShapeSetLine(tag,s,0,20*(y2-y1));
1386 swf_ShapeSetLine(tag,s,20*(x1-x2),0);
1387 swf_ShapeSetLine(tag,s,0,20*(y1-y2));
1388 swf_ShapeSetEnd(tag);
1390 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1391 swf_ObjectPlace(tag,shapeid,/*depth*/1,0,0,0);
1392 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1393 swf_ObjectPlaceClip(tag,shapeid,/*depth*/2,0,0,0,65535);
1395 msg("<notice> processing page %d", pageNum);
1398 lastpagesize.xmin = x1;
1399 lastpagesize.xmax = x2;
1400 lastpagesize.ymin = y1;
1401 lastpagesize.ymax = y2;
1402 swf_ExpandRect2(&swf.movieSize, &lastpagesize);
1407 /* initialize the swf writer */
1408 void swfoutput_init(struct swfoutput* obj, char*_filename)
1412 memset(obj, 0, sizeof(struct swfoutput));
1413 filename = _filename;
1415 msg("<verbose> initializing swf output for size %d*%d\n", sizex,sizey);
1420 memset(&swf,0x00,sizeof(SWF));
1421 memset(&lastpagesize,0x00,sizeof(SRECT));
1423 swf.fileVersion = flashversion;
1424 swf.frameRate = 0x0040; // 1 frame per 4 seconds
1425 swf.movieSize.xmin = 0;
1426 swf.movieSize.ymin = 0;
1427 swf.movieSize.xmax = 0;
1428 swf.movieSize.ymax = 0;
1430 swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1432 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1433 swf_SetRGB(tag,&rgb);
1436 tag = swf_InsertTag(tag, ST_PROTECT);
1438 startdepth = depth = 0;
1441 void swfoutput_setprotected() //write PROTECT tag
1446 static void startshape(struct swfoutput*obj)
1454 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1456 swf_ShapeNew(&shape);
1457 linestyleid = swf_ShapeAddLineStyle(shape,linewidth,&obj->strokergb);
1458 rgb.r = obj->fillrgb.r;
1459 rgb.g = obj->fillrgb.g;
1460 rgb.b = obj->fillrgb.b;
1461 fillstyleid = swf_ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1463 shapeid = ++currentswfid;
1464 swf_SetU16(tag,shapeid); // ID
1466 bboxrectpos = tag->len;
1471 swf_SetRect(tag,&r);
1473 memset(&bboxrect, 0, sizeof(bboxrect));
1475 swf_SetShapeStyles(tag,shape);
1476 swf_ShapeCountBits(shape,NULL,NULL);
1477 swf_SetShapeBits(tag,shape);
1479 /* TODO: do we really need this? */
1480 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,linestyleid,0,0);
1481 swflastx=swflasty=0;
1486 static void starttext(struct swfoutput*obj)
1491 textid = ++currentswfid;
1493 swflastx=swflasty=0;
1497 /* TODO: move to ../lib/rfxswf */
1498 void changeRect(TAG*tag, int pos, SRECT*newrect)
1500 /* determine length of old rect */
1504 swf_GetRect(tag, &old);
1505 swf_ResetReadBits(tag);
1506 int pos_end = tag->pos;
1508 int len = tag->len - pos_end;
1509 U8*data = (U8*)malloc(len);
1510 memcpy(data, &tag->data[pos_end], len);
1513 swf_SetRect(tag, newrect);
1514 swf_SetBlock(tag, data, len);
1516 tag->pos = tag->readBit = 0;
1519 void cancelshape(swfoutput*obj)
1521 /* delete old shape tag */
1524 swf_DeleteTag(todel);
1529 void fixAreas(swfoutput*obj)
1531 if(!shapeisempty && fill &&
1532 (bboxrect.xmin == bboxrect.xmax ||
1533 bboxrect.ymin == bboxrect.ymax) &&
1534 minlinewidth >= 0.001
1536 msg("<debug> Shape has size 0: width=%.2f height=%.2f",
1537 (bboxrect.xmax-bboxrect.xmin)/20.0,
1538 (bboxrect.ymax-bboxrect.ymin)/20.0
1543 if(r.xmin == r.xmax && r.ymin == r.ymax) {
1544 /* this thing comes down to a single dot- nothing to fix here */
1550 RGBA save_col = obj->strokergb;
1551 int save_width = linewidth;
1553 obj->strokergb = obj->fillrgb;
1554 linewidth = (int)(minlinewidth*20);
1555 if(linewidth==0) linewidth = 1;
1559 moveto(tag, r.xmin/20.0,r.ymin/20.0);
1560 lineto(tag, r.xmax/20.0,r.ymax/20.0);
1562 obj->strokergb = save_col;
1563 linewidth = save_width;
1568 static void endshape(swfoutput*obj, int clipdepth)
1577 (bboxrect.xmin == bboxrect.xmax && bboxrect.ymin == bboxrect.ymax))
1579 // delete the shape again, we didn't do anything
1584 swf_ShapeSetEnd(tag);
1586 changeRect(tag, bboxrectpos, &bboxrect);
1588 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1590 swf_ObjectPlaceClip(tag,shapeid,depth++,NULL,NULL,NULL,clipdepth);
1592 swf_ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL);
1598 /* Perform cleaning up, complete the swf, and write it out. */
1599 void swfoutput_destroy(struct swfoutput* obj)
1602 fontlist_t *tmp,*iterator = fontlist;
1604 TAG*mtag = swf.firstTag;
1605 if(iterator->swffont) {
1606 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1607 /*if(!storeallcharacters)
1608 swf_FontReduce(iterator->swffont);*/
1609 swf_FontSetDefine2(mtag, iterator->swffont);
1610 swf_FontFree(iterator->swffont);
1614 iterator = iterator->next;
1621 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1626 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1630 tag = swf_InsertTag(tag,ST_END);
1632 if(enablezlib || flashversion>=6) {
1633 if FAILED(swf_WriteSWC(fi,&swf))
1634 msg("<error> WriteSWC() failed.\n");
1636 if FAILED(swf_WriteSWF(fi,&swf))
1637 msg("<error> WriteSWF() failed.\n");
1642 msg("<notice> SWF written\n");
1645 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1647 obj->drawmode = mode;
1648 if(mode == DRAWMODE_FILL)
1650 else if(mode == DRAWMODE_EOFILL)
1652 else if(mode == DRAWMODE_STROKE)
1654 else if(mode == DRAWMODE_CLIP)
1656 else if(mode == DRAWMODE_EOCLIP)
1660 void swfoutput_setfillcolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1662 if(obj->fillrgb.r == r &&
1663 obj->fillrgb.g == g &&
1664 obj->fillrgb.b == b &&
1665 obj->fillrgb.a == a) return;
1675 void swfoutput_setstrokecolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1677 if(obj->strokergb.r == r &&
1678 obj->strokergb.g == g &&
1679 obj->strokergb.b == b &&
1680 obj->strokergb.a == a) return;
1684 obj->strokergb.r = r;
1685 obj->strokergb.g = g;
1686 obj->strokergb.b = b;
1687 obj->strokergb.a = a;
1690 void swfoutput_setlinewidth(struct swfoutput*obj, double _linewidth)
1692 if(linewidth == (u16)(_linewidth*20))
1697 linewidth = (u16)(_linewidth*20);
1701 void swfoutput_startclip(swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m)
1710 msg("<warning> Too many clip levels.");
1715 int olddrawmode = obj->drawmode;
1716 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1717 swfoutput_drawpath(obj, outline, m);
1718 swf_ShapeSetEnd(tag);
1719 swfoutput_setdrawmode(obj, olddrawmode);
1721 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1722 cliptags[clippos] = tag;
1723 clipshapes[clippos] = shapeid;
1724 clipdepths[clippos] = depth++;
1729 void swfoutput_endclip(swfoutput*obj)
1737 msg("<error> Invalid end of clipping region");
1741 swf_ObjectPlaceClip(cliptags[clippos],clipshapes[clippos],clipdepths[clippos],NULL,NULL,NULL,depth++);
1744 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1746 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1749 if(!strncmp("http://pdf2swf:", url, 15)) {
1750 char*tmp = strdup(url);
1751 int l = strlen(tmp);
1754 swfoutput_namedlink(obj, tmp+15, points);
1765 actions = action_GetUrl(0, url, "_parent");
1767 actions = action_GetUrl(0, url, "_this");
1768 actions = action_End(actions);
1770 drawlink(obj, actions, 0, points,0);
1772 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1781 actions = action_GotoFrame(0, page);
1782 actions = action_End(actions);
1784 drawlink(obj, actions, 0, points,0);
1787 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
1788 of the viewer objects, like subtitles, index elements etc.
1790 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
1792 ActionTAG *actions1,*actions2;
1793 char*tmp = strdup(name);
1801 if(!strncmp(tmp, "call:", 5))
1803 char*x = strchr(&tmp[5], ':');
1805 actions1 = action_PushInt(0, 0); //number of parameters (0)
1806 actions1 = action_PushString(actions1, &tmp[5]); //function name
1807 actions1 = action_CallFunction(actions1);
1810 actions1 = action_PushString(0, x+1); //parameter
1811 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
1812 actions1 = action_PushString(actions1, &tmp[5]); //function name
1813 actions1 = action_CallFunction(actions1);
1815 actions2 = action_End(0);
1820 actions1 = action_PushString(0, "/:subtitle");
1821 actions1 = action_PushString(actions1, name);
1822 actions1 = action_SetVariable(actions1);
1823 actions1 = action_End(actions1);
1825 actions2 = action_PushString(0, "/:subtitle");
1826 actions2 = action_PushString(actions2, "");
1827 actions2 = action_SetVariable(actions2);
1828 actions2 = action_End(actions2);
1831 drawlink(obj, actions1, actions2, points,mouseover);
1833 swf_ActionFree(actions1);
1834 swf_ActionFree(actions2);
1838 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
1844 struct plotxy p1,p2,p3,p4;
1848 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
1852 int buttonid = ++currentswfid;
1855 if(points[t].x>xmax) xmax=points[t].x;
1856 if(points[t].y>ymax) ymax=points[t].y;
1857 if(points[t].x<xmin) xmin=points[t].x;
1858 if(points[t].y<ymin) ymin=points[t].y;
1861 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
1862 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
1864 /* the following code subtracts the upper left edge from all coordinates,
1865 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
1866 Necessary for preprocessing with swfcombine. */
1867 posx = xmin; posy = ymin;
1868 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
1869 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
1870 xmin -= posx; ymin -= posy;
1871 xmax -= posx; ymax -= posy;
1874 myshapeid = ++currentswfid;
1875 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1876 swf_ShapeNew(&shape);
1877 rgb.r = rgb.b = rgb.a = rgb.g = 0;
1878 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1879 swf_SetU16(tag, myshapeid);
1880 r.xmin = (int)(xmin*20);
1881 r.ymin = (int)(ymin*20);
1882 r.xmax = (int)(xmax*20);
1883 r.ymax = (int)(ymax*20);
1884 swf_SetRect(tag,&r);
1885 swf_SetShapeStyles(tag,shape);
1886 swf_ShapeCountBits(shape,NULL,NULL);
1887 swf_SetShapeBits(tag,shape);
1888 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1889 swflastx = swflasty = 0;
1895 swf_ShapeSetEnd(tag);
1898 myshapeid2 = ++currentswfid;
1899 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1900 swf_ShapeNew(&shape);
1901 rgb.r = rgb.b = rgb.a = rgb.g = 255;
1903 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1904 swf_SetU16(tag, myshapeid2);
1905 r.xmin = (int)(xmin*20);
1906 r.ymin = (int)(ymin*20);
1907 r.xmax = (int)(xmax*20);
1908 r.ymax = (int)(ymax*20);
1909 swf_SetRect(tag,&r);
1910 swf_SetShapeStyles(tag,shape);
1911 swf_ShapeCountBits(shape,NULL,NULL);
1912 swf_SetShapeBits(tag,shape);
1913 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1914 swflastx = swflasty = 0;
1920 swf_ShapeSetEnd(tag);
1924 tag = swf_InsertTag(tag,ST_DEFINEBUTTON);
1925 swf_SetU16(tag,buttonid); //id
1926 swf_ButtonSetFlags(tag, 0); //menu=no
1927 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1928 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1929 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1930 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1932 swf_ActionSet(tag,actions1);
1937 tag = swf_InsertTag(tag,ST_DEFINEBUTTON2);
1938 swf_SetU16(tag,buttonid); //id
1939 swf_ButtonSetFlags(tag, 0); //menu=no
1940 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1941 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1942 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1943 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1944 swf_SetU8(tag,0); // end of button records
1945 swf_ButtonSetCondition(tag, BC_IDLE_OVERUP);
1946 swf_ActionSet(tag,actions1);
1948 swf_ButtonSetCondition(tag, BC_OVERUP_IDLE);
1949 swf_ActionSet(tag,actions2);
1951 swf_ButtonPostProcess(tag, 2);
1954 swf_ButtonPostProcess(tag, 1);
1958 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1960 if(posx!=0 || posy!=0) {
1962 swf_GetMatrix(0,&m);
1963 m.tx = (int)(posx*20);
1964 m.ty = (int)(posy*20);
1965 swf_ObjectPlace(tag, buttonid, depth++,&m,0,0);
1968 swf_ObjectPlace(tag, buttonid, depth++,0,0,0);
1972 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
1973 double x1,double y1,
1974 double x2,double y2,
1975 double x3,double y3,
1976 double x4,double y4)
1982 struct plotxy p1,p2,p3,p4;
1984 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
1985 if(x2>xmax) xmax=x2;
1986 if(y2>ymax) ymax=y2;
1987 if(x2<xmin) xmin=x2;
1988 if(y2<ymin) ymin=y2;
1989 if(x3>xmax) xmax=x3;
1990 if(y3>ymax) ymax=y3;
1991 if(x3<xmin) xmin=x3;
1992 if(y3<ymin) ymin=y3;
1993 if(x4>xmax) xmax=x4;
1994 if(y4>ymax) ymax=y4;
1995 if(x4<xmin) xmin=x4;
1996 if(y4<ymin) ymin=y4;
2002 {p1.x = (int)(p1.x*20)/20.0;
2003 p1.y = (int)(p1.y*20)/20.0;
2004 p2.x = (int)(p2.x*20)/20.0;
2005 p2.y = (int)(p2.y*20)/20.0;
2006 p3.x = (int)(p3.x*20)/20.0;
2007 p3.y = (int)(p3.y*20)/20.0;
2008 p4.x = (int)(p4.x*20)/20.0;
2009 p4.y = (int)(p4.y*20)/20.0;}
2012 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
2013 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
2014 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
2015 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
2017 m.tx = (int)(p1.x*20);
2018 m.ty = (int)(p1.y*20);
2021 myshapeid = ++currentswfid;
2022 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
2023 swf_ShapeNew(&shape);
2024 //lsid = ShapeAddLineStyle(shape,linewidth,&obj->strokergb);
2025 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
2026 fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
2027 swf_SetU16(tag, myshapeid);
2028 r.xmin = (int)(xmin*20);
2029 r.ymin = (int)(ymin*20);
2030 r.xmax = (int)(xmax*20);
2031 r.ymax = (int)(ymax*20);
2032 swf_SetRect(tag,&r);
2033 swf_SetShapeStyles(tag,shape);
2034 swf_ShapeCountBits(shape,NULL,NULL);
2035 swf_SetShapeBits(tag,shape);
2036 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,lsid,fsid,0);
2037 swflastx = swflasty = 0;
2044 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
2045 ShapeSetLine (tag, shape, (int)(x1*20);
2046 ShapeSetLine (tag, shape, x*20,0);
2047 ShapeSetLine (tag, shape, 0,-y*20);
2048 ShapeSetLine (tag, shape, -x*20,0);*/
2049 swf_ShapeSetEnd(tag);
2052 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
2053 swf_ObjectPlace(tag,myshapeid,/*depth*/depth++,NULL,NULL,NULL);
2056 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
2057 double x1,double y1,
2058 double x2,double y2,
2059 double x3,double y3,
2060 double x4,double y4)
2068 int bitid = ++currentswfid;
2070 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
2071 swf_SetU16(tag, bitid);
2072 if(swf_SetJPEGBits(tag, filename, jpegquality)<0) {
2078 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2082 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2083 double x1,double y1,
2084 double x2,double y2,
2085 double x3,double y3,
2086 double x4,double y4)
2096 int bitid = ++currentswfid;
2098 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
2099 swf_SetU16(tag, bitid);
2100 swf_SetJPEGBits2(tag,sizex,sizey,mem,jpegquality);
2101 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2105 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2106 double x1,double y1,
2107 double x2,double y2,
2108 double x3,double y3,
2109 double x4,double y4)
2117 int bitid = ++currentswfid;
2119 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS);
2120 swf_SetU16(tag, bitid);
2121 if(swf_SetLosslessBits(tag,sizex,sizey,mem, BMF_32BIT)<0) {
2127 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2131 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
2132 double x1,double y1,
2133 double x2,double y2,
2134 double x3,double y3,
2135 double x4,double y4, int n)
2146 /* SWF expects scanlines to be 4 byte aligned */
2149 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
2151 for(y=0;y<sizey;y++)
2153 for(x=0;x<sizex;x++)
2154 *ptr++ = mem[y*sizex+x];
2155 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
2160 int bitid = ++currentswfid;
2162 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS2);
2163 swf_SetU16(tag, bitid);
2164 if(swf_SetLosslessBitsIndexed(tag,sizex,sizey,mem, pal, n)<0) {
2172 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2176 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
2177 double x1,double y1,
2178 double x2,double y2,
2179 double x3,double y3,
2180 double x4,double y4)
2188 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2191 void swfoutput_setparameter(char*name, char*value)
2193 if(!strcmp(name, "drawonlyshapes")) {
2194 drawonlyshapes = atoi(value);
2195 } else if(!strcmp(name, "ignoredraworder")) {
2196 ignoredraworder = atoi(value);
2197 } else if(!strcmp(name, "filloverlap")) {
2198 filloverlap = atoi(value);
2199 } else if(!strcmp(name, "linksopennewwindow")) {
2200 opennewwindow = atoi(value);
2201 } else if(!strcmp(name, "opennewwindow")) {
2202 opennewwindow = atoi(value);
2203 } else if(!strcmp(name, "storeallcharacters")) {
2204 storeallcharacters = atoi(value);
2205 } else if(!strcmp(name, "enablezlib")) {
2206 enablezlib = atoi(value);
2207 } else if(!strcmp(name, "insertstop")) {
2208 insertstoptag = atoi(value);
2209 } else if(!strcmp(name, "flashversion")) {
2210 flashversion = atoi(value);
2211 } else if(!strcmp(name, "minlinewidth")) {
2212 minlinewidth = atof(value);
2213 } else if(!strcmp(name, "jpegquality")) {
2214 int val = atoi(value);
2216 if(val>100) val=100;
2218 } else if(!strcmp(name, "splinequality")) {
2219 int v = atoi(value);
2220 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2223 } else if(!strcmp(name, "fontquality")) {
2224 int v = atoi(value);
2225 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2227 fontsplinemaxerror = v;
2229 fprintf(stderr, "unknown parameter: %s (=%s)\n", name, value);