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)
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 */
1352 x1*=20;y1*=20;x2*=20;y2*=20;
1354 if(lastpagesize.xmin != x1 ||
1355 lastpagesize.xmax != x2 ||
1356 lastpagesize.ymin != y1 ||
1357 lastpagesize.ymax != y2)
1358 {/* add white clipping rectangle */
1359 msg("<notice> processing page %d (%dx%d)", pageNum,sizex,sizey);
1362 msg("<notice> Page has a different size than previous ones");
1363 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1365 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1370 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1374 int shapeid = ++currentswfid;
1379 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
1381 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1382 swf_SetU16(tag,shapeid);
1383 swf_SetRect(tag,&r);
1384 swf_SetShapeHeader(tag,s);
1385 swf_ShapeSetAll(tag,s,x1,y1,ls1,fs1,0);
1386 swf_ShapeSetLine(tag,s,(x2-x1),0);
1387 swf_ShapeSetLine(tag,s,0,(y2-y1));
1388 swf_ShapeSetLine(tag,s,(x1-x2),0);
1389 swf_ShapeSetLine(tag,s,0,(y1-y2));
1390 swf_ShapeSetEnd(tag);
1392 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1393 swf_ObjectPlace(tag,shapeid,/*depth*/1,0,0,0);
1394 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1395 swf_ObjectPlaceClip(tag,shapeid,/*depth*/2,0,0,0,65535);
1397 msg("<notice> processing page %d", pageNum);
1400 lastpagesize.xmin = x1;
1401 lastpagesize.xmax = x2;
1402 lastpagesize.ymin = y1;
1403 lastpagesize.ymax = y2;
1404 swf_ExpandRect2(&swf.movieSize, &lastpagesize);
1409 /* initialize the swf writer */
1410 void swfoutput_init(struct swfoutput* obj, char*_filename)
1414 memset(obj, 0, sizeof(struct swfoutput));
1415 filename = _filename;
1417 msg("<verbose> initializing swf output for size %d*%d\n", sizex,sizey);
1422 memset(&swf,0x00,sizeof(SWF));
1423 memset(&lastpagesize,0x00,sizeof(SRECT));
1425 swf.fileVersion = flashversion;
1426 swf.frameRate = 0x0040; // 1 frame per 4 seconds
1427 swf.movieSize.xmin = 0;
1428 swf.movieSize.ymin = 0;
1429 swf.movieSize.xmax = 0;
1430 swf.movieSize.ymax = 0;
1432 swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1434 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1435 swf_SetRGB(tag,&rgb);
1438 tag = swf_InsertTag(tag, ST_PROTECT);
1440 startdepth = depth = 0;
1443 void swfoutput_setprotected() //write PROTECT tag
1448 static void startshape(struct swfoutput*obj)
1456 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1458 swf_ShapeNew(&shape);
1459 linestyleid = swf_ShapeAddLineStyle(shape,linewidth,&obj->strokergb);
1460 rgb.r = obj->fillrgb.r;
1461 rgb.g = obj->fillrgb.g;
1462 rgb.b = obj->fillrgb.b;
1463 fillstyleid = swf_ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1465 shapeid = ++currentswfid;
1466 swf_SetU16(tag,shapeid); // ID
1468 bboxrectpos = tag->len;
1473 swf_SetRect(tag,&r);
1475 memset(&bboxrect, 0, sizeof(bboxrect));
1477 swf_SetShapeStyles(tag,shape);
1478 swf_ShapeCountBits(shape,NULL,NULL);
1479 swf_SetShapeBits(tag,shape);
1481 /* TODO: do we really need this? */
1482 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,linestyleid,0,0);
1483 swflastx=swflasty=0;
1488 static void starttext(struct swfoutput*obj)
1493 textid = ++currentswfid;
1495 swflastx=swflasty=0;
1499 /* TODO: move to ../lib/rfxswf */
1500 void changeRect(TAG*tag, int pos, SRECT*newrect)
1502 /* determine length of old rect */
1506 swf_GetRect(tag, &old);
1507 swf_ResetReadBits(tag);
1508 int pos_end = tag->pos;
1510 int len = tag->len - pos_end;
1511 U8*data = (U8*)malloc(len);
1512 memcpy(data, &tag->data[pos_end], len);
1515 swf_SetRect(tag, newrect);
1516 swf_SetBlock(tag, data, len);
1518 tag->pos = tag->readBit = 0;
1521 void cancelshape(swfoutput*obj)
1523 /* delete old shape tag */
1526 swf_DeleteTag(todel);
1531 void fixAreas(swfoutput*obj)
1533 if(!shapeisempty && fill &&
1534 (bboxrect.xmin == bboxrect.xmax ||
1535 bboxrect.ymin == bboxrect.ymax) &&
1536 minlinewidth >= 0.001
1538 msg("<debug> Shape has size 0: width=%.2f height=%.2f",
1539 (bboxrect.xmax-bboxrect.xmin)/20.0,
1540 (bboxrect.ymax-bboxrect.ymin)/20.0
1545 if(r.xmin == r.xmax && r.ymin == r.ymax) {
1546 /* this thing comes down to a single dot- nothing to fix here */
1552 RGBA save_col = obj->strokergb;
1553 int save_width = linewidth;
1555 obj->strokergb = obj->fillrgb;
1556 linewidth = (int)(minlinewidth*20);
1557 if(linewidth==0) linewidth = 1;
1561 moveto(tag, r.xmin/20.0,r.ymin/20.0);
1562 lineto(tag, r.xmax/20.0,r.ymax/20.0);
1564 obj->strokergb = save_col;
1565 linewidth = save_width;
1570 static void endshape(swfoutput*obj, int clipdepth)
1579 (bboxrect.xmin == bboxrect.xmax && bboxrect.ymin == bboxrect.ymax))
1581 // delete the shape again, we didn't do anything
1586 swf_ShapeSetEnd(tag);
1588 changeRect(tag, bboxrectpos, &bboxrect);
1590 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1592 swf_ObjectPlaceClip(tag,shapeid,depth++,NULL,NULL,NULL,clipdepth);
1594 swf_ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL);
1600 /* Perform cleaning up, complete the swf, and write it out. */
1601 void swfoutput_destroy(struct swfoutput* obj)
1604 fontlist_t *tmp,*iterator = fontlist;
1606 TAG*mtag = swf.firstTag;
1607 if(iterator->swffont) {
1608 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1609 /*if(!storeallcharacters)
1610 swf_FontReduce(iterator->swffont);*/
1611 swf_FontSetDefine2(mtag, iterator->swffont);
1612 swf_FontFree(iterator->swffont);
1616 iterator = iterator->next;
1623 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1628 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1632 tag = swf_InsertTag(tag,ST_END);
1634 if(enablezlib || flashversion>=6) {
1635 if FAILED(swf_WriteSWC(fi,&swf))
1636 msg("<error> WriteSWC() failed.\n");
1638 if FAILED(swf_WriteSWF(fi,&swf))
1639 msg("<error> WriteSWF() failed.\n");
1644 msg("<notice> SWF written\n");
1647 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1649 obj->drawmode = mode;
1650 if(mode == DRAWMODE_FILL)
1652 else if(mode == DRAWMODE_EOFILL)
1654 else if(mode == DRAWMODE_STROKE)
1656 else if(mode == DRAWMODE_CLIP)
1658 else if(mode == DRAWMODE_EOCLIP)
1662 void swfoutput_setfillcolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1664 if(obj->fillrgb.r == r &&
1665 obj->fillrgb.g == g &&
1666 obj->fillrgb.b == b &&
1667 obj->fillrgb.a == a) return;
1677 void swfoutput_setstrokecolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1679 if(obj->strokergb.r == r &&
1680 obj->strokergb.g == g &&
1681 obj->strokergb.b == b &&
1682 obj->strokergb.a == a) return;
1686 obj->strokergb.r = r;
1687 obj->strokergb.g = g;
1688 obj->strokergb.b = b;
1689 obj->strokergb.a = a;
1692 void swfoutput_setlinewidth(struct swfoutput*obj, double _linewidth)
1694 if(linewidth == (u16)(_linewidth*20))
1699 linewidth = (u16)(_linewidth*20);
1703 void swfoutput_startclip(swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m)
1712 msg("<warning> Too many clip levels.");
1717 int olddrawmode = obj->drawmode;
1718 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1719 swfoutput_drawpath(obj, outline, m);
1720 swf_ShapeSetEnd(tag);
1721 swfoutput_setdrawmode(obj, olddrawmode);
1723 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1724 cliptags[clippos] = tag;
1725 clipshapes[clippos] = shapeid;
1726 clipdepths[clippos] = depth++;
1731 void swfoutput_endclip(swfoutput*obj)
1739 msg("<error> Invalid end of clipping region");
1743 swf_ObjectPlaceClip(cliptags[clippos],clipshapes[clippos],clipdepths[clippos],NULL,NULL,NULL,depth++);
1746 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1748 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1751 if(!strncmp("http://pdf2swf:", url, 15)) {
1752 char*tmp = strdup(url);
1753 int l = strlen(tmp);
1756 swfoutput_namedlink(obj, tmp+15, points);
1767 actions = action_GetUrl(0, url, "_parent");
1769 actions = action_GetUrl(0, url, "_this");
1770 actions = action_End(actions);
1772 drawlink(obj, actions, 0, points,0);
1774 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1783 actions = action_GotoFrame(0, page);
1784 actions = action_End(actions);
1786 drawlink(obj, actions, 0, points,0);
1789 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
1790 of the viewer objects, like subtitles, index elements etc.
1792 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
1794 ActionTAG *actions1,*actions2;
1795 char*tmp = strdup(name);
1803 if(!strncmp(tmp, "call:", 5))
1805 char*x = strchr(&tmp[5], ':');
1807 actions1 = action_PushInt(0, 0); //number of parameters (0)
1808 actions1 = action_PushString(actions1, &tmp[5]); //function name
1809 actions1 = action_CallFunction(actions1);
1812 actions1 = action_PushString(0, x+1); //parameter
1813 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
1814 actions1 = action_PushString(actions1, &tmp[5]); //function name
1815 actions1 = action_CallFunction(actions1);
1817 actions2 = action_End(0);
1822 actions1 = action_PushString(0, "/:subtitle");
1823 actions1 = action_PushString(actions1, name);
1824 actions1 = action_SetVariable(actions1);
1825 actions1 = action_End(actions1);
1827 actions2 = action_PushString(0, "/:subtitle");
1828 actions2 = action_PushString(actions2, "");
1829 actions2 = action_SetVariable(actions2);
1830 actions2 = action_End(actions2);
1833 drawlink(obj, actions1, actions2, points,mouseover);
1835 swf_ActionFree(actions1);
1836 swf_ActionFree(actions2);
1840 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
1846 struct plotxy p1,p2,p3,p4;
1850 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
1854 int buttonid = ++currentswfid;
1857 if(points[t].x>xmax) xmax=points[t].x;
1858 if(points[t].y>ymax) ymax=points[t].y;
1859 if(points[t].x<xmin) xmin=points[t].x;
1860 if(points[t].y<ymin) ymin=points[t].y;
1863 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
1864 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
1866 /* the following code subtracts the upper left edge from all coordinates,
1867 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
1868 Necessary for preprocessing with swfcombine. */
1869 posx = xmin; posy = ymin;
1870 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
1871 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
1872 xmin -= posx; ymin -= posy;
1873 xmax -= posx; ymax -= posy;
1876 myshapeid = ++currentswfid;
1877 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1878 swf_ShapeNew(&shape);
1879 rgb.r = rgb.b = rgb.a = rgb.g = 0;
1880 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1881 swf_SetU16(tag, myshapeid);
1882 r.xmin = (int)(xmin*20);
1883 r.ymin = (int)(ymin*20);
1884 r.xmax = (int)(xmax*20);
1885 r.ymax = (int)(ymax*20);
1886 swf_SetRect(tag,&r);
1887 swf_SetShapeStyles(tag,shape);
1888 swf_ShapeCountBits(shape,NULL,NULL);
1889 swf_SetShapeBits(tag,shape);
1890 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1891 swflastx = swflasty = 0;
1897 swf_ShapeSetEnd(tag);
1900 myshapeid2 = ++currentswfid;
1901 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1902 swf_ShapeNew(&shape);
1903 rgb.r = rgb.b = rgb.a = rgb.g = 255;
1905 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1906 swf_SetU16(tag, myshapeid2);
1907 r.xmin = (int)(xmin*20);
1908 r.ymin = (int)(ymin*20);
1909 r.xmax = (int)(xmax*20);
1910 r.ymax = (int)(ymax*20);
1911 swf_SetRect(tag,&r);
1912 swf_SetShapeStyles(tag,shape);
1913 swf_ShapeCountBits(shape,NULL,NULL);
1914 swf_SetShapeBits(tag,shape);
1915 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1916 swflastx = swflasty = 0;
1922 swf_ShapeSetEnd(tag);
1926 tag = swf_InsertTag(tag,ST_DEFINEBUTTON);
1927 swf_SetU16(tag,buttonid); //id
1928 swf_ButtonSetFlags(tag, 0); //menu=no
1929 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1930 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1931 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1932 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1934 swf_ActionSet(tag,actions1);
1939 tag = swf_InsertTag(tag,ST_DEFINEBUTTON2);
1940 swf_SetU16(tag,buttonid); //id
1941 swf_ButtonSetFlags(tag, 0); //menu=no
1942 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1943 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1944 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1945 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1946 swf_SetU8(tag,0); // end of button records
1947 swf_ButtonSetCondition(tag, BC_IDLE_OVERUP);
1948 swf_ActionSet(tag,actions1);
1950 swf_ButtonSetCondition(tag, BC_OVERUP_IDLE);
1951 swf_ActionSet(tag,actions2);
1953 swf_ButtonPostProcess(tag, 2);
1956 swf_ButtonPostProcess(tag, 1);
1960 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1962 if(posx!=0 || posy!=0) {
1964 swf_GetMatrix(0,&m);
1965 m.tx = (int)(posx*20);
1966 m.ty = (int)(posy*20);
1967 swf_ObjectPlace(tag, buttonid, depth++,&m,0,0);
1970 swf_ObjectPlace(tag, buttonid, depth++,0,0,0);
1974 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
1975 double x1,double y1,
1976 double x2,double y2,
1977 double x3,double y3,
1978 double x4,double y4)
1984 struct plotxy p1,p2,p3,p4;
1986 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
1987 if(x2>xmax) xmax=x2;
1988 if(y2>ymax) ymax=y2;
1989 if(x2<xmin) xmin=x2;
1990 if(y2<ymin) ymin=y2;
1991 if(x3>xmax) xmax=x3;
1992 if(y3>ymax) ymax=y3;
1993 if(x3<xmin) xmin=x3;
1994 if(y3<ymin) ymin=y3;
1995 if(x4>xmax) xmax=x4;
1996 if(y4>ymax) ymax=y4;
1997 if(x4<xmin) xmin=x4;
1998 if(y4<ymin) ymin=y4;
2004 {p1.x = (int)(p1.x*20)/20.0;
2005 p1.y = (int)(p1.y*20)/20.0;
2006 p2.x = (int)(p2.x*20)/20.0;
2007 p2.y = (int)(p2.y*20)/20.0;
2008 p3.x = (int)(p3.x*20)/20.0;
2009 p3.y = (int)(p3.y*20)/20.0;
2010 p4.x = (int)(p4.x*20)/20.0;
2011 p4.y = (int)(p4.y*20)/20.0;}
2014 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
2015 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
2016 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
2017 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
2019 m.tx = (int)(p1.x*20);
2020 m.ty = (int)(p1.y*20);
2023 myshapeid = ++currentswfid;
2024 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
2025 swf_ShapeNew(&shape);
2026 //lsid = ShapeAddLineStyle(shape,linewidth,&obj->strokergb);
2027 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
2028 fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
2029 swf_SetU16(tag, myshapeid);
2030 r.xmin = (int)(xmin*20);
2031 r.ymin = (int)(ymin*20);
2032 r.xmax = (int)(xmax*20);
2033 r.ymax = (int)(ymax*20);
2034 swf_SetRect(tag,&r);
2035 swf_SetShapeStyles(tag,shape);
2036 swf_ShapeCountBits(shape,NULL,NULL);
2037 swf_SetShapeBits(tag,shape);
2038 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,lsid,fsid,0);
2039 swflastx = swflasty = 0;
2046 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
2047 ShapeSetLine (tag, shape, (int)(x1*20);
2048 ShapeSetLine (tag, shape, x*20,0);
2049 ShapeSetLine (tag, shape, 0,-y*20);
2050 ShapeSetLine (tag, shape, -x*20,0);*/
2051 swf_ShapeSetEnd(tag);
2054 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
2055 swf_ObjectPlace(tag,myshapeid,/*depth*/depth++,NULL,NULL,NULL);
2058 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
2059 double x1,double y1,
2060 double x2,double y2,
2061 double x3,double y3,
2062 double x4,double y4)
2070 int bitid = ++currentswfid;
2072 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
2073 swf_SetU16(tag, bitid);
2074 if(swf_SetJPEGBits(tag, filename, jpegquality)<0) {
2080 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2084 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2085 double x1,double y1,
2086 double x2,double y2,
2087 double x3,double y3,
2088 double x4,double y4)
2098 int bitid = ++currentswfid;
2100 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
2101 swf_SetU16(tag, bitid);
2102 swf_SetJPEGBits2(tag,sizex,sizey,mem,jpegquality);
2103 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2107 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2108 double x1,double y1,
2109 double x2,double y2,
2110 double x3,double y3,
2111 double x4,double y4)
2119 int bitid = ++currentswfid;
2121 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS);
2122 swf_SetU16(tag, bitid);
2123 if(swf_SetLosslessBits(tag,sizex,sizey,mem, BMF_32BIT)<0) {
2129 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2133 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
2134 double x1,double y1,
2135 double x2,double y2,
2136 double x3,double y3,
2137 double x4,double y4, int n)
2148 /* SWF expects scanlines to be 4 byte aligned */
2151 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
2153 for(y=0;y<sizey;y++)
2155 for(x=0;x<sizex;x++)
2156 *ptr++ = mem[y*sizex+x];
2157 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
2162 int bitid = ++currentswfid;
2164 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS2);
2165 swf_SetU16(tag, bitid);
2166 if(swf_SetLosslessBitsIndexed(tag,sizex,sizey,mem, pal, n)<0) {
2174 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2178 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
2179 double x1,double y1,
2180 double x2,double y2,
2181 double x3,double y3,
2182 double x4,double y4)
2190 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2193 void swfoutput_setparameter(char*name, char*value)
2195 if(!strcmp(name, "drawonlyshapes")) {
2196 drawonlyshapes = atoi(value);
2197 } else if(!strcmp(name, "ignoredraworder")) {
2198 ignoredraworder = atoi(value);
2199 } else if(!strcmp(name, "filloverlap")) {
2200 filloverlap = atoi(value);
2201 } else if(!strcmp(name, "linksopennewwindow")) {
2202 opennewwindow = atoi(value);
2203 } else if(!strcmp(name, "opennewwindow")) {
2204 opennewwindow = atoi(value);
2205 } else if(!strcmp(name, "storeallcharacters")) {
2206 storeallcharacters = atoi(value);
2207 } else if(!strcmp(name, "enablezlib")) {
2208 enablezlib = atoi(value);
2209 } else if(!strcmp(name, "insertstop")) {
2210 insertstoptag = atoi(value);
2211 } else if(!strcmp(name, "flashversion")) {
2212 flashversion = atoi(value);
2213 } else if(!strcmp(name, "minlinewidth")) {
2214 minlinewidth = atof(value);
2215 } else if(!strcmp(name, "jpegquality")) {
2216 int val = atoi(value);
2218 if(val>100) val=100;
2220 } else if(!strcmp(name, "splinequality")) {
2221 int v = atoi(value);
2222 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2225 } else if(!strcmp(name, "fontquality")) {
2226 int v = atoi(value);
2227 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2229 fontsplinemaxerror = v;
2231 fprintf(stderr, "unknown parameter: %s (=%s)\n", name, value);