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)
1145 if(charname && font->glyphnames) {
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?swffont->glyphnames[iii]:"<nonames>", 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)
1345 for(depth--;depth>=startdepth;depth--) {
1346 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1347 swf_SetU16(tag,depth);
1349 depth = startdepth = 3; /* leave room for clip and background rectangle */
1353 x1*=20;y1*=20;x2*=20;y2*=20;
1355 if(lastpagesize.xmin != x1 ||
1356 lastpagesize.xmax != x2 ||
1357 lastpagesize.ymin != y1 ||
1358 lastpagesize.ymax != y2)
1359 {/* add white clipping rectangle */
1360 msg("<notice> processing page %d (%dx%d)", pageNum,sizex,sizey);
1363 msg("<notice> Page has a different size than previous ones");
1364 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1366 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1371 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1375 int shapeid = ++currentswfid;
1380 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
1382 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1383 swf_SetU16(tag,shapeid);
1384 swf_SetRect(tag,&r);
1385 swf_SetShapeHeader(tag,s);
1386 swf_ShapeSetAll(tag,s,x1,y1,ls1,fs1,0);
1387 swf_ShapeSetLine(tag,s,(x2-x1),0);
1388 swf_ShapeSetLine(tag,s,0,(y2-y1));
1389 swf_ShapeSetLine(tag,s,(x1-x2),0);
1390 swf_ShapeSetLine(tag,s,0,(y1-y2));
1391 swf_ShapeSetEnd(tag);
1393 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1394 swf_ObjectPlace(tag,shapeid,/*depth*/1,0,0,0);
1395 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1396 swf_ObjectPlaceClip(tag,shapeid,/*depth*/2,0,0,0,65535);
1398 msg("<notice> processing page %d", pageNum);
1401 lastpagesize.xmin = x1;
1402 lastpagesize.xmax = x2;
1403 lastpagesize.ymin = y1;
1404 lastpagesize.ymax = y2;
1405 swf_ExpandRect2(&swf.movieSize, &lastpagesize);
1410 /* initialize the swf writer */
1411 void swfoutput_init(struct swfoutput* obj, char*_filename)
1415 memset(obj, 0, sizeof(struct swfoutput));
1416 filename = _filename;
1418 msg("<verbose> initializing swf output for size %d*%d\n", sizex,sizey);
1423 memset(&swf,0x00,sizeof(SWF));
1424 memset(&lastpagesize,0x00,sizeof(SRECT));
1426 swf.fileVersion = flashversion;
1427 swf.frameRate = 0x0040; // 1 frame per 4 seconds
1428 swf.movieSize.xmin = 0;
1429 swf.movieSize.ymin = 0;
1430 swf.movieSize.xmax = 0;
1431 swf.movieSize.ymax = 0;
1433 swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1435 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1436 swf_SetRGB(tag,&rgb);
1439 tag = swf_InsertTag(tag, ST_PROTECT);
1441 startdepth = depth = 0;
1444 void swfoutput_setprotected() //write PROTECT tag
1449 static void startshape(struct swfoutput*obj)
1457 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1459 swf_ShapeNew(&shape);
1460 linestyleid = swf_ShapeAddLineStyle(shape,linewidth,&obj->strokergb);
1461 rgb.r = obj->fillrgb.r;
1462 rgb.g = obj->fillrgb.g;
1463 rgb.b = obj->fillrgb.b;
1464 fillstyleid = swf_ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1466 shapeid = ++currentswfid;
1467 swf_SetU16(tag,shapeid); // ID
1469 bboxrectpos = tag->len;
1474 swf_SetRect(tag,&r);
1476 memset(&bboxrect, 0, sizeof(bboxrect));
1478 swf_SetShapeStyles(tag,shape);
1479 swf_ShapeCountBits(shape,NULL,NULL);
1480 swf_SetShapeBits(tag,shape);
1482 /* TODO: do we really need this? */
1483 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,linestyleid,0,0);
1484 swflastx=swflasty=0;
1489 static void starttext(struct swfoutput*obj)
1494 textid = ++currentswfid;
1496 swflastx=swflasty=0;
1500 /* TODO: move to ../lib/rfxswf */
1501 void changeRect(TAG*tag, int pos, SRECT*newrect)
1503 /* determine length of old rect */
1507 swf_GetRect(tag, &old);
1508 swf_ResetReadBits(tag);
1509 int pos_end = tag->pos;
1511 int len = tag->len - pos_end;
1512 U8*data = (U8*)malloc(len);
1513 memcpy(data, &tag->data[pos_end], len);
1516 swf_SetRect(tag, newrect);
1517 swf_SetBlock(tag, data, len);
1519 tag->pos = tag->readBit = 0;
1522 void cancelshape(swfoutput*obj)
1524 /* delete old shape tag */
1527 swf_DeleteTag(todel);
1532 void fixAreas(swfoutput*obj)
1534 if(!shapeisempty && fill &&
1535 (bboxrect.xmin == bboxrect.xmax ||
1536 bboxrect.ymin == bboxrect.ymax) &&
1537 minlinewidth >= 0.001
1539 msg("<debug> Shape has size 0: width=%.2f height=%.2f",
1540 (bboxrect.xmax-bboxrect.xmin)/20.0,
1541 (bboxrect.ymax-bboxrect.ymin)/20.0
1546 if(r.xmin == r.xmax && r.ymin == r.ymax) {
1547 /* this thing comes down to a single dot- nothing to fix here */
1553 RGBA save_col = obj->strokergb;
1554 int save_width = linewidth;
1556 obj->strokergb = obj->fillrgb;
1557 linewidth = (int)(minlinewidth*20);
1558 if(linewidth==0) linewidth = 1;
1562 moveto(tag, r.xmin/20.0,r.ymin/20.0);
1563 lineto(tag, r.xmax/20.0,r.ymax/20.0);
1565 obj->strokergb = save_col;
1566 linewidth = save_width;
1571 static void endshape(swfoutput*obj, int clipdepth)
1580 (bboxrect.xmin == bboxrect.xmax && bboxrect.ymin == bboxrect.ymax))
1582 // delete the shape again, we didn't do anything
1587 swf_ShapeSetEnd(tag);
1589 changeRect(tag, bboxrectpos, &bboxrect);
1591 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1593 swf_ObjectPlaceClip(tag,shapeid,depth++,NULL,NULL,NULL,clipdepth);
1595 swf_ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL);
1601 /* Perform cleaning up, complete the swf, and write it out. */
1602 void swfoutput_destroy(struct swfoutput* obj)
1605 fontlist_t *tmp,*iterator = fontlist;
1607 TAG*mtag = swf.firstTag;
1608 if(iterator->swffont) {
1609 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1610 /*if(!storeallcharacters)
1611 swf_FontReduce(iterator->swffont);*/
1612 swf_FontSetDefine2(mtag, iterator->swffont);
1613 swf_FontFree(iterator->swffont);
1617 iterator = iterator->next;
1624 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1629 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1633 tag = swf_InsertTag(tag,ST_END);
1635 if(enablezlib || flashversion>=6) {
1636 if FAILED(swf_WriteSWC(fi,&swf))
1637 msg("<error> WriteSWC() failed.\n");
1639 if FAILED(swf_WriteSWF(fi,&swf))
1640 msg("<error> WriteSWF() failed.\n");
1645 msg("<notice> SWF written\n");
1648 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1650 obj->drawmode = mode;
1651 if(mode == DRAWMODE_FILL)
1653 else if(mode == DRAWMODE_EOFILL)
1655 else if(mode == DRAWMODE_STROKE)
1657 else if(mode == DRAWMODE_CLIP)
1659 else if(mode == DRAWMODE_EOCLIP)
1663 void swfoutput_setfillcolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1665 if(obj->fillrgb.r == r &&
1666 obj->fillrgb.g == g &&
1667 obj->fillrgb.b == b &&
1668 obj->fillrgb.a == a) return;
1678 void swfoutput_setstrokecolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1680 if(obj->strokergb.r == r &&
1681 obj->strokergb.g == g &&
1682 obj->strokergb.b == b &&
1683 obj->strokergb.a == a) return;
1687 obj->strokergb.r = r;
1688 obj->strokergb.g = g;
1689 obj->strokergb.b = b;
1690 obj->strokergb.a = a;
1693 void swfoutput_setlinewidth(struct swfoutput*obj, double _linewidth)
1695 if(linewidth == (u16)(_linewidth*20))
1700 linewidth = (u16)(_linewidth*20);
1704 void swfoutput_startclip(swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m)
1713 msg("<warning> Too many clip levels.");
1718 int olddrawmode = obj->drawmode;
1719 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1720 swfoutput_drawpath(obj, outline, m);
1721 swf_ShapeSetEnd(tag);
1722 swfoutput_setdrawmode(obj, olddrawmode);
1724 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1725 cliptags[clippos] = tag;
1726 clipshapes[clippos] = shapeid;
1727 clipdepths[clippos] = depth++;
1732 void swfoutput_endclip(swfoutput*obj)
1740 msg("<error> Invalid end of clipping region");
1744 swf_ObjectPlaceClip(cliptags[clippos],clipshapes[clippos],clipdepths[clippos],NULL,NULL,NULL,depth++);
1747 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1749 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1752 if(!strncmp("http://pdf2swf:", url, 15)) {
1753 char*tmp = strdup(url);
1754 int l = strlen(tmp);
1757 swfoutput_namedlink(obj, tmp+15, points);
1768 actions = action_GetUrl(0, url, "_parent");
1770 actions = action_GetUrl(0, url, "_this");
1771 actions = action_End(actions);
1773 drawlink(obj, actions, 0, points,0);
1775 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1784 actions = action_GotoFrame(0, page);
1785 actions = action_End(actions);
1787 drawlink(obj, actions, 0, points,0);
1790 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
1791 of the viewer objects, like subtitles, index elements etc.
1793 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
1795 ActionTAG *actions1,*actions2;
1796 char*tmp = strdup(name);
1804 if(!strncmp(tmp, "call:", 5))
1806 char*x = strchr(&tmp[5], ':');
1808 actions1 = action_PushInt(0, 0); //number of parameters (0)
1809 actions1 = action_PushString(actions1, &tmp[5]); //function name
1810 actions1 = action_CallFunction(actions1);
1813 actions1 = action_PushString(0, x+1); //parameter
1814 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
1815 actions1 = action_PushString(actions1, &tmp[5]); //function name
1816 actions1 = action_CallFunction(actions1);
1818 actions2 = action_End(0);
1823 actions1 = action_PushString(0, "/:subtitle");
1824 actions1 = action_PushString(actions1, name);
1825 actions1 = action_SetVariable(actions1);
1826 actions1 = action_End(actions1);
1828 actions2 = action_PushString(0, "/:subtitle");
1829 actions2 = action_PushString(actions2, "");
1830 actions2 = action_SetVariable(actions2);
1831 actions2 = action_End(actions2);
1834 drawlink(obj, actions1, actions2, points,mouseover);
1836 swf_ActionFree(actions1);
1837 swf_ActionFree(actions2);
1841 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
1847 struct plotxy p1,p2,p3,p4;
1851 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
1855 int buttonid = ++currentswfid;
1858 if(points[t].x>xmax) xmax=points[t].x;
1859 if(points[t].y>ymax) ymax=points[t].y;
1860 if(points[t].x<xmin) xmin=points[t].x;
1861 if(points[t].y<ymin) ymin=points[t].y;
1864 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
1865 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
1867 /* the following code subtracts the upper left edge from all coordinates,
1868 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
1869 Necessary for preprocessing with swfcombine. */
1870 posx = xmin; posy = ymin;
1871 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
1872 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
1873 xmin -= posx; ymin -= posy;
1874 xmax -= posx; ymax -= posy;
1877 myshapeid = ++currentswfid;
1878 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1879 swf_ShapeNew(&shape);
1880 rgb.r = rgb.b = rgb.a = rgb.g = 0;
1881 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1882 swf_SetU16(tag, myshapeid);
1883 r.xmin = (int)(xmin*20);
1884 r.ymin = (int)(ymin*20);
1885 r.xmax = (int)(xmax*20);
1886 r.ymax = (int)(ymax*20);
1887 swf_SetRect(tag,&r);
1888 swf_SetShapeStyles(tag,shape);
1889 swf_ShapeCountBits(shape,NULL,NULL);
1890 swf_SetShapeBits(tag,shape);
1891 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1892 swflastx = swflasty = 0;
1898 swf_ShapeSetEnd(tag);
1901 myshapeid2 = ++currentswfid;
1902 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1903 swf_ShapeNew(&shape);
1904 rgb.r = rgb.b = rgb.a = rgb.g = 255;
1906 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1907 swf_SetU16(tag, myshapeid2);
1908 r.xmin = (int)(xmin*20);
1909 r.ymin = (int)(ymin*20);
1910 r.xmax = (int)(xmax*20);
1911 r.ymax = (int)(ymax*20);
1912 swf_SetRect(tag,&r);
1913 swf_SetShapeStyles(tag,shape);
1914 swf_ShapeCountBits(shape,NULL,NULL);
1915 swf_SetShapeBits(tag,shape);
1916 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1917 swflastx = swflasty = 0;
1923 swf_ShapeSetEnd(tag);
1927 tag = swf_InsertTag(tag,ST_DEFINEBUTTON);
1928 swf_SetU16(tag,buttonid); //id
1929 swf_ButtonSetFlags(tag, 0); //menu=no
1930 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1931 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1932 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1933 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1935 swf_ActionSet(tag,actions1);
1940 tag = swf_InsertTag(tag,ST_DEFINEBUTTON2);
1941 swf_SetU16(tag,buttonid); //id
1942 swf_ButtonSetFlags(tag, 0); //menu=no
1943 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1944 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1945 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1946 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1947 swf_SetU8(tag,0); // end of button records
1948 swf_ButtonSetCondition(tag, BC_IDLE_OVERUP);
1949 swf_ActionSet(tag,actions1);
1951 swf_ButtonSetCondition(tag, BC_OVERUP_IDLE);
1952 swf_ActionSet(tag,actions2);
1954 swf_ButtonPostProcess(tag, 2);
1957 swf_ButtonPostProcess(tag, 1);
1961 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1963 if(posx!=0 || posy!=0) {
1965 swf_GetMatrix(0,&m);
1966 m.tx = (int)(posx*20);
1967 m.ty = (int)(posy*20);
1968 swf_ObjectPlace(tag, buttonid, depth++,&m,0,0);
1971 swf_ObjectPlace(tag, buttonid, depth++,0,0,0);
1975 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
1976 double x1,double y1,
1977 double x2,double y2,
1978 double x3,double y3,
1979 double x4,double y4)
1985 struct plotxy p1,p2,p3,p4;
1987 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
1988 if(x2>xmax) xmax=x2;
1989 if(y2>ymax) ymax=y2;
1990 if(x2<xmin) xmin=x2;
1991 if(y2<ymin) ymin=y2;
1992 if(x3>xmax) xmax=x3;
1993 if(y3>ymax) ymax=y3;
1994 if(x3<xmin) xmin=x3;
1995 if(y3<ymin) ymin=y3;
1996 if(x4>xmax) xmax=x4;
1997 if(y4>ymax) ymax=y4;
1998 if(x4<xmin) xmin=x4;
1999 if(y4<ymin) ymin=y4;
2005 {p1.x = (int)(p1.x*20)/20.0;
2006 p1.y = (int)(p1.y*20)/20.0;
2007 p2.x = (int)(p2.x*20)/20.0;
2008 p2.y = (int)(p2.y*20)/20.0;
2009 p3.x = (int)(p3.x*20)/20.0;
2010 p3.y = (int)(p3.y*20)/20.0;
2011 p4.x = (int)(p4.x*20)/20.0;
2012 p4.y = (int)(p4.y*20)/20.0;}
2015 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
2016 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
2017 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
2018 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
2020 m.tx = (int)(p1.x*20);
2021 m.ty = (int)(p1.y*20);
2024 myshapeid = ++currentswfid;
2025 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
2026 swf_ShapeNew(&shape);
2027 //lsid = ShapeAddLineStyle(shape,linewidth,&obj->strokergb);
2028 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
2029 fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
2030 swf_SetU16(tag, myshapeid);
2031 r.xmin = (int)(xmin*20);
2032 r.ymin = (int)(ymin*20);
2033 r.xmax = (int)(xmax*20);
2034 r.ymax = (int)(ymax*20);
2035 swf_SetRect(tag,&r);
2036 swf_SetShapeStyles(tag,shape);
2037 swf_ShapeCountBits(shape,NULL,NULL);
2038 swf_SetShapeBits(tag,shape);
2039 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,lsid,fsid,0);
2040 swflastx = swflasty = 0;
2047 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
2048 ShapeSetLine (tag, shape, (int)(x1*20);
2049 ShapeSetLine (tag, shape, x*20,0);
2050 ShapeSetLine (tag, shape, 0,-y*20);
2051 ShapeSetLine (tag, shape, -x*20,0);*/
2052 swf_ShapeSetEnd(tag);
2055 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
2056 swf_ObjectPlace(tag,myshapeid,/*depth*/depth++,NULL,NULL,NULL);
2059 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
2060 double x1,double y1,
2061 double x2,double y2,
2062 double x3,double y3,
2063 double x4,double y4)
2071 int bitid = ++currentswfid;
2073 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
2074 swf_SetU16(tag, bitid);
2075 if(swf_SetJPEGBits(tag, filename, jpegquality)<0) {
2081 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2085 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2086 double x1,double y1,
2087 double x2,double y2,
2088 double x3,double y3,
2089 double x4,double y4)
2099 int bitid = ++currentswfid;
2101 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
2102 swf_SetU16(tag, bitid);
2103 swf_SetJPEGBits2(tag,sizex,sizey,mem,jpegquality);
2104 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2108 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2109 double x1,double y1,
2110 double x2,double y2,
2111 double x3,double y3,
2112 double x4,double y4)
2120 int bitid = ++currentswfid;
2122 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS);
2123 swf_SetU16(tag, bitid);
2124 if(swf_SetLosslessBits(tag,sizex,sizey,mem, BMF_32BIT)<0) {
2130 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2134 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
2135 double x1,double y1,
2136 double x2,double y2,
2137 double x3,double y3,
2138 double x4,double y4, int n)
2149 /* SWF expects scanlines to be 4 byte aligned */
2152 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
2154 for(y=0;y<sizey;y++)
2156 for(x=0;x<sizex;x++)
2157 *ptr++ = mem[y*sizex+x];
2158 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
2163 int bitid = ++currentswfid;
2165 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS2);
2166 swf_SetU16(tag, bitid);
2167 if(swf_SetLosslessBitsIndexed(tag,sizex,sizey,mem, pal, n)<0) {
2175 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2179 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
2180 double x1,double y1,
2181 double x2,double y2,
2182 double x3,double y3,
2183 double x4,double y4)
2191 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2194 void swfoutput_setparameter(char*name, char*value)
2196 if(!strcmp(name, "drawonlyshapes")) {
2197 drawonlyshapes = atoi(value);
2198 } else if(!strcmp(name, "ignoredraworder")) {
2199 ignoredraworder = atoi(value);
2200 } else if(!strcmp(name, "filloverlap")) {
2201 filloverlap = atoi(value);
2202 } else if(!strcmp(name, "linksopennewwindow")) {
2203 opennewwindow = atoi(value);
2204 } else if(!strcmp(name, "opennewwindow")) {
2205 opennewwindow = atoi(value);
2206 } else if(!strcmp(name, "storeallcharacters")) {
2207 storeallcharacters = atoi(value);
2208 } else if(!strcmp(name, "enablezlib")) {
2209 enablezlib = atoi(value);
2210 } else if(!strcmp(name, "insertstop")) {
2211 insertstoptag = atoi(value);
2212 } else if(!strcmp(name, "flashversion")) {
2213 flashversion = atoi(value);
2214 } else if(!strcmp(name, "minlinewidth")) {
2215 minlinewidth = atof(value);
2216 } else if(!strcmp(name, "jpegquality")) {
2217 int val = atoi(value);
2219 if(val>100) val=100;
2221 } else if(!strcmp(name, "splinequality")) {
2222 int v = atoi(value);
2223 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2226 } else if(!strcmp(name, "fontquality")) {
2227 int v = atoi(value);
2228 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2230 fontsplinemaxerror = v;
2232 fprintf(stderr, "unknown parameter: %s (=%s)\n", name, value);