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;
70 static int shapeid = -1;
71 static int textid = -1;
73 static int fillstyleid;
74 static int linestyleid;
75 static int swflastx=0;
76 static int swflasty=0;
77 static int lastwasfill = 0;
78 static int shapeisempty = 1;
90 char fillstylechanged = 0;
95 static void startshape(struct swfoutput* obj);
96 static void starttext(struct swfoutput* obj);
97 static void endshape(struct swfoutput* obj,int clip);
98 static void endtext(struct swfoutput* obj);
100 // matrix multiplication. changes p0
101 static void transform (plotxy*p0,struct swfmatrix*m)
104 x = m->m11*p0->x+m->m12*p0->y;
105 y = m->m21*p0->x+m->m22*p0->y;
110 // write a move-to command into the swf
111 static int moveto(TAG*tag, plotxy p0)
113 int rx = (int)(p0.x*20);
114 int ry = (int)(p0.y*20);
115 if(rx!=swflastx || ry!=swflasty || fillstylechanged) {
116 swf_ShapeSetMove (tag, shape, rx,ry);
117 fillstylechanged = 0;
124 static int moveto(TAG*tag, float x, float y)
129 return moveto(tag, p);
131 static void addPointToBBox(int px, int py)
137 swf_ExpandRect(&bboxrect, p);
139 swf_ExpandRect3(&bboxrect, p, linewidth*3/2);
143 // write a line-to command into the swf
144 static void lineto(TAG*tag, plotxy p0)
146 int px = (int)(p0.x*20);
147 int py = (int)(p0.y*20);
148 int rx = (px-swflastx);
149 int ry = (py-swflasty);
150 /* we can't skip this for rx=0,ry=0, those
152 swf_ShapeSetLine (tag, shape, rx,ry);
154 addPointToBBox(swflastx,swflasty);
155 addPointToBBox(px,py);
161 static void lineto(TAG*tag, double x, double y)
170 // write a spline-to command into the swf
171 static void splineto(TAG*tag, plotxy control,plotxy end)
173 int lastlastx = swflastx;
174 int lastlasty = swflasty;
176 int cx = ((int)(control.x*20)-swflastx);
177 int cy = ((int)(control.y*20)-swflasty);
180 int ex = ((int)(end.x*20)-swflastx);
181 int ey = ((int)(end.y*20)-swflasty);
185 if(cx || cy || ex || ey) {
186 swf_ShapeSetCurve(tag, shape, cx,cy,ex,ey);
187 addPointToBBox(lastlastx ,lastlasty );
188 addPointToBBox(lastlastx+cx,lastlasty+cy);
189 addPointToBBox(lastlastx+cx+ex,lastlasty+cy+ey);
194 /* write a line, given two points and the transformation
196 static void line(TAG*tag, plotxy p0, plotxy p1, struct swfmatrix*m)
204 /* write a cubic (!) spline. This involves calling the approximate()
205 function out of spline.cc to convert it to a quadratic spline. */
206 static void spline(TAG*tag,plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m)
209 struct qspline q[128];
223 /* fonts use a different approximation than shapes */
224 num = cspline_approximate(&c, q, fontsplinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
225 //num = cspline_approximate(&c, q, 10.0, APPROXIMATE_INFLECTION);
227 num = cspline_approximate(&c, q, splinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
231 moveto(tag,q[t].start);
232 splineto(tag,q[t].control, q[t].end);
242 static void stopFill()
246 swf_ShapeSetStyle(tag,shape,linestyleid,0x8000,0);
247 fillstylechanged = 1;
251 static void startFill()
255 swf_ShapeSetStyle(tag,shape,0x8000,fillstyleid,0);
256 fillstylechanged = 1;
261 /* draw an outline. These are generated by pdf2swf and by t1lib
262 (representing characters). */
263 void drawpath(struct swfoutput*output, SWF_OUTLINE*outline, struct swfmatrix*m, int log)
265 if( tag->id != ST_DEFINESHAPE &&
266 tag->id != ST_DEFINESHAPE2 &&
267 tag->id != ST_DEFINESHAPE3)
269 msg("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
273 double lastx=0,lasty=0;
274 double firstx=0,firsty=0;
279 x += (outline->dest.x/(float)0xffff);
280 y += (outline->dest.y/(float)0xffff);
281 if(outline->type == SWF_PATHTYPE_MOVE)
283 //if(!init && fill && output->drawmode != DRAWMODE_EOFILL && !ignoredraworder) {
284 if(filloverlap && !init && fill && output->drawmode != DRAWMODE_EOFILL) {
285 /* drawmode=FILL (not EOFILL) means that
286 seperate shapes do not cancel each other out.
287 On SWF side, we need to start a new shape for each
288 closed polygon, because SWF only knows EOFILL.
295 if(((int)(lastx*20) != (int)(firstx*20) ||
296 (int)(lasty*20) != (int)(firsty*20)) &&
305 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
306 line(tag, p0, p1, m);
312 else if(outline->type == SWF_PATHTYPE_LINE)
320 if(log) printf("line: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
323 else if(outline->type == SWF_PATHTYPE_BEZIER)
329 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
332 p1.x=o2->C.x/(float)0xffff+lastx;
333 p1.y=o2->C.y/(float)0xffff+lasty;
334 p2.x=o2->B.x/(float)0xffff+lastx;
335 p2.y=o2->B.y/(float)0xffff+lasty;
338 if(log) printf("spline: %f,%f -> %f,%f\n",p3.x,p3.y,p0.x,p0.y);
339 spline(tag,p0,p1,p2,p3,m);
342 msg("<error> drawpath: unknown outline type:%d\n", outline->type);
346 outline = outline->link;
348 if(((int)(lastx*20) != (int)(firstx*20) ||
349 (int)(lasty*20) != (int)(firsty*20)) &&
358 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
359 line(tag, p0, p1, m);
363 plotxy getPivot(SWF_OUTLINE*outline, int dir, double line_width, int end, int trytwo)
365 SWF_PATHPOINT next, next2;
366 double xv=0,yv=0, xv2=0, yv2=0;
371 if(outline->type == SWF_PATHTYPE_LINE) {
372 next = outline->dest;
374 next = ((SWF_BEZIERSEGMENT*)outline)->B;
375 if(next.x==0 && next.y==0) {
376 next = ((SWF_BEZIERSEGMENT*)outline)->C;
378 if(next.x==0 && next.y==0) {
379 next = ((SWF_BEZIERSEGMENT*)outline)->dest;
383 if(trytwo && outline->last && outline->last->type != SWF_PATHTYPE_MOVE) {
384 if(outline->type == SWF_PATHTYPE_LINE) {
385 next2 = outline->last->dest;
387 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)(outline->last))->C;
388 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)(outline->last))->B;
389 next2.x = outline->last->dest.x - c.x;
390 next2.y = outline->last->dest.y - c.y;
391 if(next2.x==0 && next2.y==0) {
392 next2.x = outline->last->dest.x - b.x;
393 next2.y = outline->last->dest.y - b.y;
395 if(next2.x==0 && next2.y==0) {
396 next2.x = outline->last->dest.x;
397 next2.y = outline->last->dest.y;
403 if(outline->type == SWF_PATHTYPE_LINE) {
404 next = outline->dest;
406 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)outline)->C;
407 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)outline)->B;
408 next.x = outline->dest.x - c.x;
409 next.y = outline->dest.y - c.y;
410 if(next.x==0 && next.y==0) {
411 next.x = outline->dest.x - b.x;
412 next.y = outline->dest.y - b.y;
414 if(next.x==0 && next.y==0) {
415 next.x = outline->dest.x;
416 next.y = outline->dest.y;
420 if(trytwo && outline->link && outline->link->type != SWF_PATHTYPE_MOVE) {
421 if(outline->type == SWF_PATHTYPE_LINE) {
422 next2 = outline->link->dest;
424 next2 = ((SWF_BEZIERSEGMENT*)(outline->link))->B;
425 if(next2.x==0 && next2.y==0) {
426 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->C;
428 if(next2.x==0 && next2.y==0) {
429 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->dest;
437 xv = next.y/(float)0xffff;
438 yv = -next.x/(float)0xffff;
440 xv = -next.y/(float)0xffff;
441 yv = next.x/(float)0xffff;
444 double r = (line_width/2)/sqrt(xv*xv+yv*yv);
450 xv2 = next2.y/(float)0xffff;
451 yv2 = -next2.x/(float)0xffff;
453 xv2 = -next2.y/(float)0xffff;
454 yv2 = next2.x/(float)0xffff;
457 double r2 = (line_width/2)/sqrt(xv2*xv2+yv2*yv2);
462 double r3 = (line_width/2)/sqrt(xv*xv+yv*yv);
472 void drawShortPath(struct swfoutput*output, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline)
474 double lastx=x, lasty=y;
475 while (outline && outline->type != SWF_PATHTYPE_MOVE)
477 x += (outline->dest.x/(float)0xffff);
478 y += (outline->dest.y/(float)0xffff);
480 if(outline->type == SWF_PATHTYPE_LINE)
487 line(tag, p0, p1, m);
489 else if(outline->type == SWF_PATHTYPE_BEZIER)
492 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
495 p1.x=o2->C.x/(float)0xffff+lastx;
496 p1.y=o2->C.y/(float)0xffff+lasty;
497 p2.x=o2->B.x/(float)0xffff+lastx;
498 p2.y=o2->B.y/(float)0xffff+lasty;
501 spline(tag,p0,p1,p2,p3,m);
505 outline = outline->link;
509 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)
514 if(line_cap == LINE_CAP_BUTT || line_cap == LINE_CAP_SQUARE) {
517 SWF_OUTLINE *last, *tmp=outline;
518 plotxy s,e,p0,p1,p2,p3,m0,m1,m2,m3;
524 while(tmp && tmp->type != SWF_PATHTYPE_MOVE) {
526 lx += (tmp->dest.x/(float)0xffff);
527 ly += (tmp->dest.y/(float)0xffff);
530 s = getPivot(outline, 0, line_width, 0, 0);
531 e = getPivot(last, 0, line_width, 1, 0);
533 if(line_cap == LINE_CAP_BUTT) {
534 /* make the clipping rectangle slighly bigger
535 than the line ending, so that it get's clipped
545 p2.x = x2 - s.y - s.x*ee;
546 p2.y = y2 + s.x - s.y*ee;
547 p3.x = x2 - s.y + s.x*ee;
548 p3.y = y2 + s.x + s.y*ee;
553 m2.x = lx + e.y - e.x*ee;
554 m2.y = ly - e.x - e.y*ee;
555 m3.x = lx + e.y + e.x*ee;
556 m3.y = ly - e.x + e.y*ee;
558 for(nr=0;nr<2;nr++) {
560 struct plotxy q0,q1,q2,q3,q4,q5;
563 if(line_cap == LINE_CAP_BUTT) {
566 q1.x = sizex; q1.y = 0;
567 q2.x = sizex; q2.y = sizey;
568 q3.x = 0; q3.y = sizey;
570 q0.x = sizex; q0.y = sizey;
571 q1.x = 0; q1.y = sizey;
573 q3.x = sizex; q3.y = 0;
587 line(tag, p0, p1, m);
588 line(tag, p1, p2, m);
589 line(tag, p2, p3, m);
590 line(tag, p3, p0, m);
592 if(line_cap == LINE_CAP_BUTT) {
594 endshape(output, depth+2-nr);
606 drawShortPath(output,x,y,m,outline);
608 if(line_cap == LINE_CAP_BUTT) {
614 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)
616 plotxy d1,d2,p1,p2,p3,p4;
618 d1.x = (outline->dest.x/(float)0xffff);
619 d1.y = (outline->dest.y/(float)0xffff);
620 d2 = getPivot(outline, 0, line_width, 0, 0);
622 assert(line_cap != LINE_CAP_ROUND);
623 if(line_cap == LINE_CAP_SQUARE) {
632 p2.x = x + d2.x + d1.x;
633 p2.y = y + d2.y + d1.y;
634 p3.x = x - d2.x + d1.x;
635 p3.y = y - d2.y + d1.y;
645 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)
647 SWF_OUTLINE*tmp=outline;
653 drawT1toRect(output, x, y, m,outline, num, line_cap, line_join, line_width);
655 while(tmp->link && tmp->link->type!=SWF_PATHTYPE_MOVE) {
656 xx += (tmp->dest.x/(float)0xffff);
657 yy += (tmp->dest.y/(float)0xffff);
661 assert(tmp->type == SWF_PATHTYPE_LINE);
662 assert(outline->type == SWF_PATHTYPE_LINE);
666 if(outline->link == tmp) {
667 /* the two straight line segments (which are everything we
668 need to draw) are very likely to overlap. To avoid that
669 they cancel each other out at the end points, start a new
670 shape for the second one */
671 endshape(output,0);startshape(output);
675 drawT1toRect(output, xx, yy, m, tmp, num, line_cap, line_join, line_width);
677 if(outline->link != tmp)
681 tmp->type = SWF_PATHTYPE_MOVE;
682 x += (outline->dest.x/(float)0xffff);
683 y += (outline->dest.y/(float)0xffff);
684 outline = outline->link;
685 drawShortPath(output, x, y, m, outline);
693 static int t1len(SWF_OUTLINE*line)
696 while(line && line->type != SWF_PATHTYPE_MOVE) {
703 static float t1linelen(SWF_OUTLINE*line)
706 x = (line->dest.x/(float)0xffff);
707 y = (line->dest.y/(float)0xffff);
708 return sqrt(x*x+y*y);
711 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)
713 if( tag->id != ST_DEFINESHAPE &&
714 tag->id != ST_DEFINESHAPE2 &&
715 tag->id != ST_DEFINESHAPE3) {
716 msg("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
721 double lastx=0,lasty=0;
724 SWF_OUTLINE*tmp = outline, *last = 0;
729 x += (tmp->dest.x/(float)0xffff);
730 y += (tmp->dest.y/(float)0xffff);
732 if(!tmp || tmp->type == SWF_PATHTYPE_MOVE) {
734 if(last->type == SWF_PATHTYPE_LINE && t1linelen(last)>line_width*2 &&
735 lastwasline && line_cap != LINE_CAP_ROUND)
736 drawShortPathWithStraightEnds(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
738 drawShortPathWithEnds(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
752 if(tmp && tmp->type == SWF_PATHTYPE_LINE && t1linelen(tmp)>line_width*2)
758 tmp->link->last = tmp; // make sure list is properly linked in both directions
763 static inline int colorcompare(RGBA*a,RGBA*b)
775 static const int CHARDATAMAX = 8192;
778 int fontid; /* TODO: use a SWFFONT instead */
783 } chardata[CHARDATAMAX];
786 static SRECT getcharacterbbox(SWFFONT*font)
790 memset(&r, 0, sizeof(r));
793 if(debug) printf("\n");
794 for(t=0;t<chardatapos;t++)
796 if(chardata[t].fontid != font->id) {
797 msg("<error> Internal error: fontid %d != fontid %d", chardata[t].fontid, font->id);
800 SRECT b = font->layout->bounds[chardata[t].charid];
801 b.xmin *= chardata[t].size;
802 b.ymin *= chardata[t].size;
803 b.xmax *= chardata[t].size;
804 b.ymax *= chardata[t].size;
809 b.xmin += chardata[t].x;
810 b.ymin += chardata[t].y;
811 b.xmax += chardata[t].x;
812 b.ymax += chardata[t].y;
814 /* until we solve the INTERNAL_SCALING problem (see below)
815 make sure the bounding box is big enough */
821 if(debug) printf("(%f,%f,%f,%f) -> (%f,%f,%f,%f) [font %d/%d, char %d]\n",
822 font->layout->bounds[chardata[t].charid].xmin/20.0,
823 font->layout->bounds[chardata[t].charid].ymin/20.0,
824 font->layout->bounds[chardata[t].charid].xmax/20.0,
825 font->layout->bounds[chardata[t].charid].ymax/20.0,
834 swf_ExpandRect2(&r, &b);
836 if(debug) printf("-----> (%f,%f,%f,%f)\n",
844 static void putcharacters(TAG*tag)
849 color.r = chardata[0].color.r^255;
858 int charadvance[128];
861 int glyphbits=1; //TODO: can this be zero?
864 if(tag->id != ST_DEFINETEXT &&
865 tag->id != ST_DEFINETEXT2) {
866 msg("<error> internal error: putcharacters needs an text tag, not %d\n",tag->id);
870 msg("<warning> putcharacters called with zero characters");
873 for(pass = 0; pass < 2; pass++)
883 advancebits++; // add sign bit
884 swf_SetU8(tag, glyphbits);
885 swf_SetU8(tag, advancebits);
888 for(t=0;t<=chardatapos;t++)
890 if(lastfontid != chardata[t].fontid ||
891 lastx!=chardata[t].x ||
892 lasty!=chardata[t].y ||
893 !colorcompare(&color, &chardata[t].color) ||
895 lastsize != chardata[t].size ||
898 if(charstorepos && pass==0)
901 for(s=0;s<charstorepos;s++)
903 while(charids[s]>=(1<<glyphbits))
905 while(charadvance[s]>=(1<<advancebits))
909 if(charstorepos && pass==1)
911 tag->writeBit = 0; // Q&D
912 swf_SetBits(tag, 0, 1); // GLYPH Record
913 swf_SetBits(tag, charstorepos, 7); // number of glyphs
915 for(s=0;s<charstorepos;s++)
917 swf_SetBits(tag, charids[s], glyphbits);
918 swf_SetBits(tag, charadvance[s], advancebits);
923 if(pass == 1 && t<chardatapos)
929 if(lastx != chardata[t].x ||
930 lasty != chardata[t].y)
932 newx = chardata[t].x;
933 newy = chardata[t].y;
939 if(!colorcompare(&color, &chardata[t].color))
941 color = chardata[t].color;
944 font.id = chardata[t].fontid;
945 if(lastfontid != chardata[t].fontid || lastsize != chardata[t].size)
948 tag->writeBit = 0; // Q&D
949 swf_TextSetInfoRecord(tag, newfont, chardata[t].size, newcolor, newx,newy);
952 lastfontid = chardata[t].fontid;
953 lastx = chardata[t].x;
954 lasty = chardata[t].y;
955 lastsize = chardata[t].size;
962 int nextt = t==chardatapos-1?t:t+1;
963 int rel = chardata[nextt].x-chardata[t].x;
964 if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) {
966 lastx=chardata[nextt].x;
972 charids[charstorepos] = chardata[t].charid;
973 charadvance[charstorepos] = advance;
980 static void putcharacter(struct swfoutput*obj, int fontid, int charid,
981 int x,int y, int size)
983 if(chardatapos == CHARDATAMAX)
985 msg("<warning> Character buffer too small. SWF will be slightly bigger");
989 chardata[chardatapos].fontid = fontid;
990 chardata[chardatapos].charid = charid;
991 chardata[chardatapos].x = x;
992 chardata[chardatapos].y = y;
993 chardata[chardatapos].color = obj->fillrgb;
994 chardata[chardatapos].size = size;
1004 /* Notice: we can only put chars in the range -1639,1638 (-32768/20,32768/20).
1005 So if we set this value to high, the char coordinates will overflow.
1006 If we set it to low, however, the char positions will be inaccurate */
1007 #define FONT_INTERNAL_SIZE 4
1009 /* process a character. */
1010 static int drawchar(struct swfoutput*obj, SWFFONT *swffont, char*character, int charnr, int u, swfmatrix*m)
1013 msg("<warning> Font is NULL");
1017 int charid = getCharID(swffont, charnr, character, u);
1020 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1021 FIXNULL(character),charnr, u, FIXNULL((char*)swffont->name), swffont->numchars);
1032 float det = ((m->m11*m->m22)-(m->m21*m->m12));
1033 if(fabs(det) < 0.0005) {
1034 /* x direction equals y direction- the text is invisible */
1037 det = 20*FONT_INTERNAL_SIZE / det;
1040 p.x = (SCOORD)(( x * m->m22 - y * m->m12)*det);
1041 p.y = (SCOORD)((- x * m->m21 + y * m->m11)*det);
1043 putcharacter(obj, swffont->id, charid,p.x,p.y,FONT_INTERNAL_SIZE);
1044 swf_FontUseGlyph(swffont, charid);
1049 SWF_OUTLINE*outline = font->getOutline(character, charnr);
1050 char* charname = character;
1053 msg("<warning> Didn't find character '%s' (%d) in current charset (%s)",
1054 FIXNULL(character),charnr,FIXNULL(font->getName()));
1073 drawpath(tag, outline, &m2, 0);
1078 static void endtext(swfoutput*obj)
1083 tag = swf_InsertTag(tag,ST_DEFINETEXT);
1084 swf_SetU16(tag, textid);
1087 r = getcharacterbbox(obj->swffont);
1089 swf_SetRect(tag,&r);
1092 swf_GetMatrix(0, &m);
1093 swf_SetMatrix(tag,&m);
1097 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1098 swf_ObjectPlace(tag,textid,/*depth*/depth++,&obj->fontmatrix,NULL,NULL);
1103 /* draw a curved polygon. */
1104 void swfoutput_drawpath(swfoutput*output, SWF_OUTLINE*outline,
1110 /* Multiple polygons in one shape don't overlap correctly,
1111 so we better start a new shape here if the polygon is filled
1113 if(shapeid>=0 && fill && !ignoredraworder) {
1125 drawpath(output, outline,m, 0);
1128 void swfoutput_drawpath2poly(struct swfoutput*output, SWF_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
1138 drawpath2poly(output, outline, m, 0, line_join, line_cap, line_width, miter_limit);
1141 int getCharID(SWFFONT *font, int charnr, char *charname, int u)
1145 for(t=0;t<font->numchars;t++) {
1146 if(font->glyphnames[t] && !strcmp(font->glyphnames[t],charname)) {
1147 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1151 /* if we didn't find the character, maybe
1152 we can find the capitalized version */
1153 for(t=0;t<font->numchars;t++) {
1154 if(font->glyphnames[t] && !strcasecmp(font->glyphnames[t],charname)) {
1155 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1162 /* try to use the unicode id */
1163 if(u>=0 && u<font->maxascii && font->ascii2glyph[u]>=0) {
1164 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->ascii2glyph[u]);
1165 return font->ascii2glyph[u];
1169 if(charnr>=0 && charnr<font->numchars) {
1170 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1174 if(font->encoding != FONT_ENCODING_UNICODE) {
1175 /* the following only works if the font encoding
1176 is US-ASCII based. It's needed for fonts which return broken unicode
1178 if(charnr>=0 && charnr<font->maxascii && font->ascii2glyph[charnr]>=0) {
1179 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, font->ascii2glyph[charnr]);
1180 return font->ascii2glyph[charnr];
1188 /* set's the t1 font index of the font to use for swfoutput_drawchar(). */
1189 void swfoutput_setfont(struct swfoutput*obj, char*fontid, char*filename)
1191 fontlist_t*last=0,*iterator;
1193 msg("<error> No fontid");
1197 if(obj->swffont && obj->swffont->name && !strcmp((char*)obj->swffont->name,fontid))
1200 /* TODO: remove the need for this (enhance getcharacterbbox so that it can cope
1201 with multiple fonts */
1204 iterator = fontlist;
1206 if(!strcmp((char*)iterator->swffont->name,fontid)) {
1207 obj->swffont = iterator->swffont;
1211 iterator = iterator->next;
1215 msg("<error> No filename given for font- internal error?");
1219 swf_SetLoadFontParameters(64,/*skip unused*/0,/*full unicode*/1);
1220 SWFFONT*swffont = swf_LoadFont(filename);
1223 msg("<warning> Couldn't load font %s (%s)", fontid, filename);
1224 swffont = swf_LoadFont(0);
1227 swf_FontSetID(swffont, ++currentswfid);
1229 if(screenloglevel >= LOGLEVEL_DEBUG) {
1230 // print font information
1231 msg("<debug> Font %s (%s)",swffont->name, filename);
1232 msg("<debug> | ID: %d", swffont->id);
1233 msg("<debug> | Version: %d", swffont->version);
1234 msg("<debug> | Name: %s", fontid);
1235 msg("<debug> | Numchars: %d", swffont->numchars);
1236 msg("<debug> | Maxascii: %d", swffont->maxascii);
1237 msg("<debug> | Style: %d", swffont->style);
1238 msg("<debug> | Encoding: %d", swffont->encoding);
1239 for(int iii=0; iii<swffont->numchars;iii++) {
1240 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,
1241 swffont->layout->bounds[iii].xmin/20.0,
1242 swffont->layout->bounds[iii].ymin/20.0,
1243 swffont->layout->bounds[iii].xmax/20.0,
1244 swffont->layout->bounds[iii].ymax/20.0
1247 for(t=0;t<swffont->maxascii;t++) {
1248 if(swffont->ascii2glyph[t] == iii)
1249 msg("<debug> | - maps to %d",t);
1254 /* set the font name to the ID we use here */
1255 if(swffont->name) free(swffont->name);
1256 swffont->name = (U8*)strdup(fontid);
1258 iterator = new fontlist_t;
1259 iterator->swffont = swffont;
1263 last->next = iterator;
1265 fontlist = iterator;
1267 obj->swffont = swffont;
1270 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1272 fontlist_t *iterator = fontlist;
1274 if(!strcmp((char*)iterator->swffont->name,fontid))
1276 iterator = iterator->next;
1281 /* set's the matrix which is to be applied to characters drawn by
1282 swfoutput_drawchar() */
1283 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1284 double m21,double m22)
1286 if(obj->fontm11 == m11 &&
1287 obj->fontm12 == m12 &&
1288 obj->fontm21 == m21 &&
1289 obj->fontm22 == m22)
1299 m.sx = (U32)(((obj->fontm11)*65536)/FONT_INTERNAL_SIZE); m.r1 = (U32)(((obj->fontm12)*65536)/FONT_INTERNAL_SIZE);
1300 m.r0 = (U32)(((obj->fontm21)*65536)/FONT_INTERNAL_SIZE); m.sy = (U32)(((obj->fontm22)*65536)/FONT_INTERNAL_SIZE);
1303 obj->fontmatrix = m;
1306 /* draws a character at x,y. */
1307 int swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr, int u)
1310 m.m11 = obj->fontm11;
1311 m.m12 = obj->fontm12;
1312 m.m21 = obj->fontm21;
1313 m.m22 = obj->fontm22;
1316 return drawchar(obj, obj->swffont, character, charnr, u, &m);
1319 /* initialize the swf writer */
1320 void swfoutput_init(struct swfoutput* obj, char*_filename, int x1, int y1, int x2, int y2)
1324 memset(obj, 0, sizeof(struct swfoutput));
1325 filename = _filename;
1329 msg("<verbose> initializing swf output for size %d*%d\n", sizex,sizey);
1334 memset(&swf,0x00,sizeof(SWF));
1336 swf.fileVersion = flashversion;
1337 swf.frameRate = 0x0040; // 1 frame per 4 seconds
1338 swf.movieSize.xmin = 20*x1;
1339 swf.movieSize.ymin = 20*y1;
1340 swf.movieSize.xmax = 20*x2;
1341 swf.movieSize.ymax = 20*y2;
1345 swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1347 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1348 swf_SetRGB(tag,&rgb);
1350 if(1)/* add white rectangle */
1355 int shapeid = ++currentswfid;
1360 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
1362 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1363 swf_SetU16(tag,shapeid);
1364 swf_SetRect(tag,&r);
1365 swf_SetShapeHeader(tag,s);
1366 swf_ShapeSetAll(tag,s,x1*20,y1*20,ls1,fs1,0);
1367 swf_ShapeSetLine(tag,s,20*(x2-x1),0);
1368 swf_ShapeSetLine(tag,s,0,20*(y2-y1));
1369 swf_ShapeSetLine(tag,s,20*(x1-x2),0);
1370 swf_ShapeSetLine(tag,s,0,20*(y1-y2));
1371 swf_ShapeSetEnd(tag);
1373 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1374 swf_ObjectPlace(tag,shapeid,depth++,0,0,0);
1375 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1376 swf_ObjectPlaceClip(tag,shapeid,depth++,0,0,0,65535);
1380 tag = swf_InsertTag(tag, ST_PROTECT);
1385 void swfoutput_setprotected() //write PROTECT tag
1390 static void startshape(struct swfoutput*obj)
1398 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1400 swf_ShapeNew(&shape);
1401 linestyleid = swf_ShapeAddLineStyle(shape,linewidth,&obj->strokergb);
1402 rgb.r = obj->fillrgb.r;
1403 rgb.g = obj->fillrgb.g;
1404 rgb.b = obj->fillrgb.b;
1405 fillstyleid = swf_ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1407 shapeid = ++currentswfid;
1408 swf_SetU16(tag,shapeid); // ID
1410 bboxrectpos = tag->len;
1415 swf_SetRect(tag,&r);
1417 memset(&bboxrect, 0, sizeof(bboxrect));
1419 swf_SetShapeStyles(tag,shape);
1420 swf_ShapeCountBits(shape,NULL,NULL);
1421 swf_SetShapeBits(tag,shape);
1423 /* TODO: do we really need this? */
1424 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,linestyleid,0,0);
1425 swflastx=swflasty=0;
1430 static void starttext(struct swfoutput*obj)
1435 textid = ++currentswfid;
1437 swflastx=swflasty=0;
1441 /* TODO: move to ../lib/rfxswf */
1442 void changeRect(TAG*tag, int pos, SRECT*newrect)
1444 /* determine length of old rect */
1448 swf_GetRect(tag, &old);
1449 swf_ResetReadBits(tag);
1450 int pos_end = tag->pos;
1452 int len = tag->len - pos_end;
1453 U8*data = (U8*)malloc(len);
1454 memcpy(data, &tag->data[pos_end], len);
1457 swf_SetRect(tag, newrect);
1458 swf_SetBlock(tag, data, len);
1460 tag->pos = tag->readBit = 0;
1463 void cancelshape(swfoutput*obj)
1465 /* delete old shape tag */
1468 swf_DeleteTag(todel);
1473 void fixAreas(swfoutput*obj)
1475 if(!shapeisempty && fill &&
1476 (bboxrect.xmin == bboxrect.xmax ||
1477 bboxrect.ymin == bboxrect.ymax) &&
1478 minlinewidth >= 0.001
1480 msg("<debug> Shape has size 0: width=%.2f height=%.2f",
1481 (bboxrect.xmax-bboxrect.xmin)/20.0,
1482 (bboxrect.ymax-bboxrect.ymin)/20.0
1487 if(r.xmin == r.xmax && r.ymin == r.ymax) {
1488 /* this thing comes down to a single dot- nothing to fix here */
1494 RGBA save_col = obj->strokergb;
1495 int save_width = linewidth;
1497 obj->strokergb = obj->fillrgb;
1498 linewidth = (int)(minlinewidth*20);
1499 if(linewidth==0) linewidth = 1;
1503 moveto(tag, r.xmin/20.0,r.ymin/20.0);
1504 lineto(tag, r.xmax/20.0,r.ymax/20.0);
1506 obj->strokergb = save_col;
1507 linewidth = save_width;
1512 static void endshape(swfoutput*obj, int clipdepth)
1521 (bboxrect.xmin == bboxrect.xmax && bboxrect.ymin == bboxrect.ymax))
1523 // delete the shape again, we didn't do anything
1528 swf_ShapeSetEnd(tag);
1530 changeRect(tag, bboxrectpos, &bboxrect);
1532 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1534 swf_ObjectPlaceClip(tag,shapeid,depth++,NULL,NULL,NULL,clipdepth);
1536 swf_ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL);
1542 static void endpage(struct swfoutput*obj)
1549 swfoutput_endclip(obj);
1553 atag = action_Stop(atag);
1554 atag = action_End(atag);
1555 tag = swf_InsertTag(tag,ST_DOACTION);
1556 swf_ActionSet(tag,atag);
1558 tag = swf_InsertTag(tag,ST_SHOWFRAME);
1561 void swfoutput_newpage(struct swfoutput*obj)
1565 for(depth--;depth>=startdepth;depth--) {
1566 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1567 swf_SetU16(tag,depth);
1573 /* Perform cleaning up, complete the swf, and write it out. */
1574 void swfoutput_destroy(struct swfoutput* obj)
1577 fontlist_t *tmp,*iterator = fontlist;
1579 TAG*mtag = swf.firstTag;
1580 if(iterator->swffont) {
1581 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1582 /*if(!storeallcharacters)
1583 swf_FontReduce(iterator->swffont);*/
1584 swf_FontSetDefine2(mtag, iterator->swffont);
1585 swf_FontFree(iterator->swffont);
1589 iterator = iterator->next;
1596 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1601 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1605 tag = swf_InsertTag(tag,ST_END);
1607 if(enablezlib || flashversion>=6) {
1608 if FAILED(swf_WriteSWC(fi,&swf))
1609 msg("<error> WriteSWC() failed.\n");
1611 if FAILED(swf_WriteSWF(fi,&swf))
1612 msg("<error> WriteSWF() failed.\n");
1617 msg("<notice> SWF written\n");
1620 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1622 obj->drawmode = mode;
1623 if(mode == DRAWMODE_FILL)
1625 else if(mode == DRAWMODE_EOFILL)
1627 else if(mode == DRAWMODE_STROKE)
1629 else if(mode == DRAWMODE_CLIP)
1631 else if(mode == DRAWMODE_EOCLIP)
1635 void swfoutput_setfillcolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1637 if(obj->fillrgb.r == r &&
1638 obj->fillrgb.g == g &&
1639 obj->fillrgb.b == b &&
1640 obj->fillrgb.a == a) return;
1650 void swfoutput_setstrokecolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1652 if(obj->strokergb.r == r &&
1653 obj->strokergb.g == g &&
1654 obj->strokergb.b == b &&
1655 obj->strokergb.a == a) return;
1659 obj->strokergb.r = r;
1660 obj->strokergb.g = g;
1661 obj->strokergb.b = b;
1662 obj->strokergb.a = a;
1665 void swfoutput_setlinewidth(struct swfoutput*obj, double _linewidth)
1667 if(linewidth == (u16)(_linewidth*20))
1672 linewidth = (u16)(_linewidth*20);
1676 void swfoutput_startclip(swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m)
1685 msg("<warning> Too many clip levels.");
1690 int olddrawmode = obj->drawmode;
1691 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1692 swfoutput_drawpath(obj, outline, m);
1693 swf_ShapeSetEnd(tag);
1694 swfoutput_setdrawmode(obj, olddrawmode);
1696 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1697 cliptags[clippos] = tag;
1698 clipshapes[clippos] = shapeid;
1699 clipdepths[clippos] = depth++;
1704 void swfoutput_endclip(swfoutput*obj)
1712 msg("<error> Invalid end of clipping region");
1716 swf_ObjectPlaceClip(cliptags[clippos],clipshapes[clippos],clipdepths[clippos],NULL,NULL,NULL,depth++);
1719 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1721 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1724 if(!strncmp("http://pdf2swf:", url, 15)) {
1725 char*tmp = strdup(url);
1726 int l = strlen(tmp);
1729 swfoutput_namedlink(obj, tmp+15, points);
1740 actions = action_GetUrl(0, url, "_parent");
1742 actions = action_GetUrl(0, url, "_this");
1743 actions = action_End(actions);
1745 drawlink(obj, actions, 0, points,0);
1747 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1756 actions = action_GotoFrame(0, page);
1757 actions = action_End(actions);
1759 drawlink(obj, actions, 0, points,0);
1762 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
1763 of the viewer objects, like subtitles, index elements etc.
1765 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
1767 ActionTAG *actions1,*actions2;
1768 char*tmp = strdup(name);
1776 if(!strncmp(tmp, "call:", 5))
1778 char*x = strchr(&tmp[5], ':');
1780 actions1 = action_PushInt(0, 0); //number of parameters (0)
1781 actions1 = action_PushString(actions1, &tmp[5]); //function name
1782 actions1 = action_CallFunction(actions1);
1785 actions1 = action_PushString(0, x+1); //parameter
1786 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
1787 actions1 = action_PushString(actions1, &tmp[5]); //function name
1788 actions1 = action_CallFunction(actions1);
1790 actions2 = action_End(0);
1795 actions1 = action_PushString(0, "/:subtitle");
1796 actions1 = action_PushString(actions1, name);
1797 actions1 = action_SetVariable(actions1);
1798 actions1 = action_End(actions1);
1800 actions2 = action_PushString(0, "/:subtitle");
1801 actions2 = action_PushString(actions2, "");
1802 actions2 = action_SetVariable(actions2);
1803 actions2 = action_End(actions2);
1806 drawlink(obj, actions1, actions2, points,mouseover);
1808 swf_ActionFree(actions1);
1809 swf_ActionFree(actions2);
1813 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
1819 struct plotxy p1,p2,p3,p4;
1823 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
1827 int buttonid = ++currentswfid;
1830 if(points[t].x>xmax) xmax=points[t].x;
1831 if(points[t].y>ymax) ymax=points[t].y;
1832 if(points[t].x<xmin) xmin=points[t].x;
1833 if(points[t].y<ymin) ymin=points[t].y;
1836 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
1837 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
1839 /* the following code subtracts the upper left edge from all coordinates,
1840 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
1841 Necessary for preprocessing with swfcombine. */
1842 posx = xmin; posy = ymin;
1843 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
1844 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
1845 xmin -= posx; ymin -= posy;
1846 xmax -= posx; ymax -= posy;
1849 myshapeid = ++currentswfid;
1850 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1851 swf_ShapeNew(&shape);
1852 rgb.r = rgb.b = rgb.a = rgb.g = 0;
1853 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1854 swf_SetU16(tag, myshapeid);
1855 r.xmin = (int)(xmin*20);
1856 r.ymin = (int)(ymin*20);
1857 r.xmax = (int)(xmax*20);
1858 r.ymax = (int)(ymax*20);
1859 swf_SetRect(tag,&r);
1860 swf_SetShapeStyles(tag,shape);
1861 swf_ShapeCountBits(shape,NULL,NULL);
1862 swf_SetShapeBits(tag,shape);
1863 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1864 swflastx = swflasty = 0;
1870 swf_ShapeSetEnd(tag);
1873 myshapeid2 = ++currentswfid;
1874 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1875 swf_ShapeNew(&shape);
1876 rgb.r = rgb.b = rgb.a = rgb.g = 255;
1878 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1879 swf_SetU16(tag, myshapeid2);
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);
1899 tag = swf_InsertTag(tag,ST_DEFINEBUTTON);
1900 swf_SetU16(tag,buttonid); //id
1901 swf_ButtonSetFlags(tag, 0); //menu=no
1902 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1903 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1904 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1905 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1907 swf_ActionSet(tag,actions1);
1912 tag = swf_InsertTag(tag,ST_DEFINEBUTTON2);
1913 swf_SetU16(tag,buttonid); //id
1914 swf_ButtonSetFlags(tag, 0); //menu=no
1915 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1916 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1917 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1918 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1919 swf_SetU8(tag,0); // end of button records
1920 swf_ButtonSetCondition(tag, BC_IDLE_OVERUP);
1921 swf_ActionSet(tag,actions1);
1923 swf_ButtonSetCondition(tag, BC_OVERUP_IDLE);
1924 swf_ActionSet(tag,actions2);
1926 swf_ButtonPostProcess(tag, 2);
1929 swf_ButtonPostProcess(tag, 1);
1933 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1935 if(posx!=0 || posy!=0) {
1937 swf_GetMatrix(0,&m);
1938 m.tx = (int)(posx*20);
1939 m.ty = (int)(posy*20);
1940 swf_ObjectPlace(tag, buttonid, depth++,&m,0,0);
1943 swf_ObjectPlace(tag, buttonid, depth++,0,0,0);
1947 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
1948 double x1,double y1,
1949 double x2,double y2,
1950 double x3,double y3,
1951 double x4,double y4)
1957 struct plotxy p1,p2,p3,p4;
1959 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
1960 if(x2>xmax) xmax=x2;
1961 if(y2>ymax) ymax=y2;
1962 if(x2<xmin) xmin=x2;
1963 if(y2<ymin) ymin=y2;
1964 if(x3>xmax) xmax=x3;
1965 if(y3>ymax) ymax=y3;
1966 if(x3<xmin) xmin=x3;
1967 if(y3<ymin) ymin=y3;
1968 if(x4>xmax) xmax=x4;
1969 if(y4>ymax) ymax=y4;
1970 if(x4<xmin) xmin=x4;
1971 if(y4<ymin) ymin=y4;
1977 {p1.x = (int)(p1.x*20)/20.0;
1978 p1.y = (int)(p1.y*20)/20.0;
1979 p2.x = (int)(p2.x*20)/20.0;
1980 p2.y = (int)(p2.y*20)/20.0;
1981 p3.x = (int)(p3.x*20)/20.0;
1982 p3.y = (int)(p3.y*20)/20.0;
1983 p4.x = (int)(p4.x*20)/20.0;
1984 p4.y = (int)(p4.y*20)/20.0;}
1987 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
1988 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
1989 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
1990 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
1992 m.tx = (int)(p1.x*20);
1993 m.ty = (int)(p1.y*20);
1996 myshapeid = ++currentswfid;
1997 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1998 swf_ShapeNew(&shape);
1999 //lsid = ShapeAddLineStyle(shape,linewidth,&obj->strokergb);
2000 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
2001 fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
2002 swf_SetU16(tag, myshapeid);
2003 r.xmin = (int)(xmin*20);
2004 r.ymin = (int)(ymin*20);
2005 r.xmax = (int)(xmax*20);
2006 r.ymax = (int)(ymax*20);
2007 swf_SetRect(tag,&r);
2008 swf_SetShapeStyles(tag,shape);
2009 swf_ShapeCountBits(shape,NULL,NULL);
2010 swf_SetShapeBits(tag,shape);
2011 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,lsid,fsid,0);
2012 swflastx = swflasty = 0;
2019 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
2020 ShapeSetLine (tag, shape, (int)(x1*20);
2021 ShapeSetLine (tag, shape, x*20,0);
2022 ShapeSetLine (tag, shape, 0,-y*20);
2023 ShapeSetLine (tag, shape, -x*20,0);*/
2024 swf_ShapeSetEnd(tag);
2027 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
2028 swf_ObjectPlace(tag,myshapeid,/*depth*/depth++,NULL,NULL,NULL);
2031 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
2032 double x1,double y1,
2033 double x2,double y2,
2034 double x3,double y3,
2035 double x4,double y4)
2043 int bitid = ++currentswfid;
2045 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
2046 swf_SetU16(tag, bitid);
2047 if(swf_SetJPEGBits(tag, filename, jpegquality)<0) {
2053 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2057 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2058 double x1,double y1,
2059 double x2,double y2,
2060 double x3,double y3,
2061 double x4,double y4)
2071 int bitid = ++currentswfid;
2073 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
2074 swf_SetU16(tag, bitid);
2075 swf_SetJPEGBits2(tag,sizex,sizey,mem,jpegquality);
2076 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2080 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2081 double x1,double y1,
2082 double x2,double y2,
2083 double x3,double y3,
2084 double x4,double y4)
2092 int bitid = ++currentswfid;
2094 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS);
2095 swf_SetU16(tag, bitid);
2096 if(swf_SetLosslessBits(tag,sizex,sizey,mem, BMF_32BIT)<0) {
2102 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2106 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
2107 double x1,double y1,
2108 double x2,double y2,
2109 double x3,double y3,
2110 double x4,double y4, int n)
2121 /* SWF expects scanlines to be 4 byte aligned */
2124 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
2126 for(y=0;y<sizey;y++)
2128 for(x=0;x<sizex;x++)
2129 *ptr++ = mem[y*sizex+x];
2130 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
2135 int bitid = ++currentswfid;
2137 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS2);
2138 swf_SetU16(tag, bitid);
2139 if(swf_SetLosslessBitsIndexed(tag,sizex,sizey,mem, pal, n)<0) {
2147 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2151 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
2152 double x1,double y1,
2153 double x2,double y2,
2154 double x3,double y3,
2155 double x4,double y4)
2163 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2166 void swfoutput_setparameter(char*name, char*value)
2168 if(!strcmp(name, "drawonlyshapes")) {
2169 drawonlyshapes = atoi(value);
2170 } else if(!strcmp(name, "ignoredraworder")) {
2171 ignoredraworder = atoi(value);
2172 } else if(!strcmp(name, "filloverlap")) {
2173 filloverlap = atoi(value);
2174 } else if(!strcmp(name, "linksopennewwindow")) {
2175 opennewwindow = atoi(value);
2176 } else if(!strcmp(name, "opennewwindow")) {
2177 opennewwindow = atoi(value);
2178 } else if(!strcmp(name, "storeallcharacters")) {
2179 storeallcharacters = atoi(value);
2180 } else if(!strcmp(name, "enablezlib")) {
2181 enablezlib = atoi(value);
2182 } else if(!strcmp(name, "insertstop")) {
2183 insertstoptag = atoi(value);
2184 } else if(!strcmp(name, "flashversion")) {
2185 flashversion = atoi(value);
2186 } else if(!strcmp(name, "minlinewidth")) {
2187 minlinewidth = atof(value);
2188 } else if(!strcmp(name, "jpegquality")) {
2189 int val = atoi(value);
2191 if(val>100) val=100;
2193 } else if(!strcmp(name, "splinequality")) {
2194 int v = atoi(value);
2195 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2198 } else if(!strcmp(name, "fontquality")) {
2199 int v = atoi(value);
2200 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2202 fontsplinemaxerror = v;
2204 fprintf(stderr, "unknown parameter: %s (=%s)\n", name, value);