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 static char storefont = 0;
52 static int flag_protected = 0;
54 typedef unsigned char u8;
55 typedef unsigned short int u16;
56 typedef unsigned long int u32;
59 static char* filename = 0;
62 static int currentswfid = 0;
64 static int startdepth = 1;
67 static int shapeid = -1;
68 static int textid = -1;
70 static int fillstyleid;
71 static int linestyleid;
72 static int swflastx=0;
73 static int swflasty=0;
74 static int lastwasfill = 0;
75 static int shapeisempty = 1;
87 char fillstylechanged = 0;
89 static void startshape(struct swfoutput* obj);
90 static void starttext(struct swfoutput* obj);
91 static void endshape();
92 static void endtext(struct swfoutput* obj);
94 // matrix multiplication. changes p0
95 static void transform (plotxy*p0,struct swfmatrix*m)
98 x = m->m11*p0->x+m->m12*p0->y;
99 y = m->m21*p0->x+m->m22*p0->y;
104 // write a move-to command into the swf
105 static int moveto(TAG*tag, plotxy p0)
107 int rx = (int)(p0.x*20);
108 int ry = (int)(p0.y*20);
109 if(rx!=swflastx || ry!=swflasty || fillstylechanged) {
110 swf_ShapeSetMove (tag, shape, rx,ry);
111 fillstylechanged = 0;
119 // write a line-to command into the swf
120 static void lineto(TAG*tag, plotxy p0)
122 int px = (int)(p0.x*20);
123 int py = (int)(p0.y*20);
124 int rx = (px-swflastx);
125 int ry = (py-swflasty);
126 /* we can't skip this for rx=0,ry=0, those
128 swf_ShapeSetLine (tag, shape, rx,ry);
130 //swf_ExpandRect3(boundingBox, px, py, linewidth);
131 //swf_ExpandRect3(boundingBox, swflastx, swflasty, linewidth);
138 // write a spline-to command into the swf
139 static void splineto(TAG*tag, plotxy control,plotxy end)
141 int cx = ((int)(control.x*20)-swflastx);
142 int cy = ((int)(control.y*20)-swflasty);
145 int ex = ((int)(end.x*20)-swflastx);
146 int ey = ((int)(end.y*20)-swflasty);
149 if(cx || cy || ex || ey)
150 swf_ShapeSetCurve(tag, shape, cx,cy,ex,ey);
154 /* write a line, given two points and the transformation
156 static void line(TAG*tag, plotxy p0, plotxy p1, struct swfmatrix*m)
164 /* write a cubic (!) spline. This involves calling the approximate()
165 function out of spline.cc to convert it to a quadratic spline. */
166 static void spline(TAG*tag,plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m)
169 struct qspline q[128];
183 /* fonts use a different approximation than shapes */
184 num = cspline_approximate(&c, q, fontsplinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
185 //num = cspline_approximate(&c, q, 10.0, APPROXIMATE_INFLECTION);
187 num = cspline_approximate(&c, q, splinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
191 moveto(tag,q[t].start);
192 splineto(tag,q[t].control, q[t].end);
202 static void stopFill()
206 swf_ShapeSetStyle(tag,shape,linestyleid,0x8000,0);
207 fillstylechanged = 1;
211 static void startFill()
215 swf_ShapeSetStyle(tag,shape,0x8000,fillstyleid,0);
216 fillstylechanged = 1;
221 /* draw an outline. These are generated by pdf2swf and by t1lib
222 (representing characters). */
223 void drawpath(struct swfoutput*output, SWF_OUTLINE*outline, struct swfmatrix*m, int log)
225 if( tag->id != ST_DEFINESHAPE &&
226 tag->id != ST_DEFINESHAPE2 &&
227 tag->id != ST_DEFINESHAPE3)
229 msg("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
233 double lastx=0,lasty=0;
234 double firstx=0,firsty=0;
239 x += (outline->dest.x/(float)0xffff);
240 y += (outline->dest.y/(float)0xffff);
241 if(outline->type == SWF_PATHTYPE_MOVE)
243 if(!init && fill && output->drawmode != DRAWMODE_EOFILL && !ignoredraworder) {
244 /* drawmode=FILL (not EOFILL) means that
245 seperate shapes do not cancel each other out.
246 On SWF side, we need to start a new shape for each
247 closed polygon, because SWF only knows EOFILL.
254 if(((int)(lastx*20) != (int)(firstx*20) ||
255 (int)(lasty*20) != (int)(firsty*20)) &&
264 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
265 line(tag, p0, p1, m);
271 else if(outline->type == SWF_PATHTYPE_LINE)
279 if(log) printf("line: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
282 else if(outline->type == SWF_PATHTYPE_BEZIER)
288 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
291 p1.x=o2->C.x/(float)0xffff+lastx;
292 p1.y=o2->C.y/(float)0xffff+lasty;
293 p2.x=o2->B.x/(float)0xffff+lastx;
294 p2.y=o2->B.y/(float)0xffff+lasty;
297 if(log) printf("spline: %f,%f -> %f,%f\n",p3.x,p3.y,p0.x,p0.y);
298 spline(tag,p0,p1,p2,p3,m);
301 msg("<error> drawpath: unknown outline type:%d\n", outline->type);
305 outline = outline->link;
307 if(((int)(lastx*20) != (int)(firstx*20) ||
308 (int)(lasty*20) != (int)(firsty*20)) &&
317 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
318 line(tag, p0, p1, m);
322 plotxy getPivot(SWF_OUTLINE*outline, int dir, double line_width, int end, int trytwo)
324 SWF_PATHPOINT next, next2;
325 double xv=0,yv=0, xv2=0, yv2=0;
330 if(outline->type == SWF_PATHTYPE_LINE) {
331 next = outline->dest;
333 next = ((SWF_BEZIERSEGMENT*)outline)->B;
334 if(next.x==0 && next.y==0) {
335 next = ((SWF_BEZIERSEGMENT*)outline)->C;
337 if(next.x==0 && next.y==0) {
338 next = ((SWF_BEZIERSEGMENT*)outline)->dest;
342 if(trytwo && outline->last && outline->last->type != SWF_PATHTYPE_MOVE) {
343 if(outline->type == SWF_PATHTYPE_LINE) {
344 next2 = outline->last->dest;
346 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)(outline->last))->C;
347 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)(outline->last))->B;
348 next2.x = outline->last->dest.x - c.x;
349 next2.y = outline->last->dest.y - c.y;
350 if(next2.x==0 && next2.y==0) {
351 next2.x = outline->last->dest.x - b.x;
352 next2.y = outline->last->dest.y - b.y;
354 if(next2.x==0 && next2.y==0) {
355 next2.x = outline->last->dest.x;
356 next2.y = outline->last->dest.y;
362 if(outline->type == SWF_PATHTYPE_LINE) {
363 next = outline->dest;
365 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)outline)->C;
366 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)outline)->B;
367 next.x = outline->dest.x - c.x;
368 next.y = outline->dest.y - c.y;
369 if(next.x==0 && next.y==0) {
370 next.x = outline->dest.x - b.x;
371 next.y = outline->dest.y - b.y;
373 if(next.x==0 && next.y==0) {
374 next.x = outline->dest.x;
375 next.y = outline->dest.y;
379 if(trytwo && outline->link && outline->link->type != SWF_PATHTYPE_MOVE) {
380 if(outline->type == SWF_PATHTYPE_LINE) {
381 next2 = outline->link->dest;
383 next2 = ((SWF_BEZIERSEGMENT*)(outline->link))->B;
384 if(next2.x==0 && next2.y==0) {
385 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->C;
387 if(next2.x==0 && next2.y==0) {
388 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->dest;
396 xv = next.y/(float)0xffff;
397 yv = -next.x/(float)0xffff;
399 xv = -next.y/(float)0xffff;
400 yv = next.x/(float)0xffff;
403 double r = (line_width/2)/sqrt(xv*xv+yv*yv);
409 xv2 = next2.y/(float)0xffff;
410 yv2 = -next2.x/(float)0xffff;
412 xv2 = -next2.y/(float)0xffff;
413 yv2 = next2.x/(float)0xffff;
416 double r2 = (line_width/2)/sqrt(xv2*xv2+yv2*yv2);
421 double r3 = (line_width/2)/sqrt(xv*xv+yv*yv);
431 void drawShortPath(struct swfoutput*output, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline)
433 double lastx=x, lasty=y;
434 while (outline && outline->type != SWF_PATHTYPE_MOVE)
436 x += (outline->dest.x/(float)0xffff);
437 y += (outline->dest.y/(float)0xffff);
439 if(outline->type == SWF_PATHTYPE_LINE)
446 line(tag, p0, p1, m);
448 else if(outline->type == SWF_PATHTYPE_BEZIER)
451 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
454 p1.x=o2->C.x/(float)0xffff+lastx;
455 p1.y=o2->C.y/(float)0xffff+lasty;
456 p2.x=o2->B.x/(float)0xffff+lastx;
457 p2.y=o2->B.y/(float)0xffff+lasty;
460 spline(tag,p0,p1,p2,p3,m);
464 outline = outline->link;
468 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)
473 if(line_cap == LINE_CAP_BUTT || line_cap == LINE_CAP_SQUARE) {
476 SWF_OUTLINE *last, *tmp=outline;
477 plotxy s,e,p0,p1,p2,p3,m0,m1,m2,m3;
483 while(tmp && tmp->type != SWF_PATHTYPE_MOVE) {
485 lx += (tmp->dest.x/(float)0xffff);
486 ly += (tmp->dest.y/(float)0xffff);
489 s = getPivot(outline, 0, line_width, 0, 0);
490 e = getPivot(last, 0, line_width, 1, 0);
492 if(line_cap == LINE_CAP_BUTT) {
493 /* make the clipping rectangle slighly bigger
494 than the line ending, so that it get's clipped
504 p2.x = x2 - s.y - s.x*ee;
505 p2.y = y2 + s.x - s.y*ee;
506 p3.x = x2 - s.y + s.x*ee;
507 p3.y = y2 + s.x + s.y*ee;
512 m2.x = lx + e.y - e.x*ee;
513 m2.y = ly - e.x - e.y*ee;
514 m3.x = lx + e.y + e.x*ee;
515 m3.y = ly - e.x + e.y*ee;
517 for(nr=0;nr<2;nr++) {
519 struct plotxy q0,q1,q2,q3,q4,q5;
521 if(line_cap == LINE_CAP_BUTT) {
524 q1.x = sizex; q1.y = 0;
525 q2.x = sizex; q2.y = sizey;
526 q3.x = 0; q3.y = sizey;
528 q0.x = sizex; q0.y = sizey;
529 q1.x = 0; q1.y = sizey;
531 q3.x = sizex; q3.y = 0;
545 line(tag, p0, p1, m);
546 line(tag, p1, p2, m);
547 line(tag, p2, p3, m);
548 line(tag, p3, p0, m);
550 if(line_cap == LINE_CAP_BUTT) {
552 swf_ShapeSetEnd(tag);
553 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
554 swf_ObjectPlaceClip(tag,shapeid,depth,NULL,NULL,NULL,depth+2-nr);
568 drawShortPath(output,x,y,m,outline);
570 if(line_cap == LINE_CAP_BUTT) {
576 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)
578 plotxy d1,d2,p1,p2,p3,p4;
580 d1.x = (outline->dest.x/(float)0xffff);
581 d1.y = (outline->dest.y/(float)0xffff);
582 d2 = getPivot(outline, 0, line_width, 0, 0);
584 assert(line_cap != LINE_CAP_ROUND);
585 if(line_cap == LINE_CAP_SQUARE) {
594 p2.x = x + d2.x + d1.x;
595 p2.y = y + d2.y + d1.y;
596 p3.x = x - d2.x + d1.x;
597 p3.y = y - d2.y + d1.y;
607 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)
609 SWF_OUTLINE*tmp=outline;
615 drawT1toRect(output, x, y, m,outline, num, line_cap, line_join, line_width);
617 while(tmp->link && tmp->link->type!=SWF_PATHTYPE_MOVE) {
618 xx += (tmp->dest.x/(float)0xffff);
619 yy += (tmp->dest.y/(float)0xffff);
623 assert(tmp->type == SWF_PATHTYPE_LINE);
624 assert(outline->type == SWF_PATHTYPE_LINE);
628 if(outline->link == tmp) {
629 /* the two straight line segments (which are everything we
630 need to draw) are very likely to overlap. To avoid that
631 they cancel each other out at the end points, start a new
632 shape for the second one */
633 endshape();startshape(output);
637 drawT1toRect(output, xx, yy, m, tmp, num, line_cap, line_join, line_width);
639 if(outline->link != tmp)
643 tmp->type = SWF_PATHTYPE_MOVE;
644 x += (outline->dest.x/(float)0xffff);
645 y += (outline->dest.y/(float)0xffff);
646 outline = outline->link;
647 drawShortPath(output, x, y, m, outline);
655 static int t1len(SWF_OUTLINE*line)
658 while(line && line->type != SWF_PATHTYPE_MOVE) {
665 static float t1linelen(SWF_OUTLINE*line)
668 x = (line->dest.x/(float)0xffff);
669 y = (line->dest.y/(float)0xffff);
670 return sqrt(x*x+y*y);
673 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)
675 if( tag->id != ST_DEFINESHAPE &&
676 tag->id != ST_DEFINESHAPE2 &&
677 tag->id != ST_DEFINESHAPE3) {
678 msg("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
683 double lastx=0,lasty=0;
686 SWF_OUTLINE*tmp = outline, *last = 0;
691 x += (tmp->dest.x/(float)0xffff);
692 y += (tmp->dest.y/(float)0xffff);
694 if(!tmp || tmp->type == SWF_PATHTYPE_MOVE) {
696 if(last->type == SWF_PATHTYPE_LINE && t1linelen(last)>line_width*2 &&
697 lastwasline && line_cap != LINE_CAP_ROUND)
698 drawShortPathWithStraightEnds(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
700 drawShortPathWithEnds(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
714 if(tmp && tmp->type == SWF_PATHTYPE_LINE && t1linelen(tmp)>line_width*2)
720 tmp->link->last = tmp; // make sure list is properly linked in both directions
725 static inline int colorcompare(RGBA*a,RGBA*b)
737 static const int CHARDATAMAX = 8192;
745 } chardata[CHARDATAMAX];
748 static void putcharacters(TAG*tag)
753 color.r = chardata[0].color.r^255;
762 int charadvance[128];
765 int glyphbits=1; //TODO: can this be zero?
768 if(tag->id != ST_DEFINETEXT &&
769 tag->id != ST_DEFINETEXT2) {
770 msg("<error> internal error: putcharacters needs an text tag, not %d\n",tag->id);
774 msg("<warning> putcharacters called with zero characters");
777 for(pass = 0; pass < 2; pass++)
787 advancebits++; // add sign bit
788 swf_SetU8(tag, glyphbits);
789 swf_SetU8(tag, advancebits);
792 for(t=0;t<=chardatapos;t++)
794 if(lastfontid != chardata[t].fontid ||
795 lastx!=chardata[t].x ||
796 lasty!=chardata[t].y ||
797 !colorcompare(&color, &chardata[t].color) ||
799 lastsize != chardata[t].size ||
802 if(charstorepos && pass==0)
805 for(s=0;s<charstorepos;s++)
807 while(charids[s]>=(1<<glyphbits))
809 while(charadvance[s]>=(1<<advancebits))
813 if(charstorepos && pass==1)
815 tag->writeBit = 0; // Q&D
816 swf_SetBits(tag, 0, 1); // GLYPH Record
817 swf_SetBits(tag, charstorepos, 7); // number of glyphs
819 for(s=0;s<charstorepos;s++)
821 swf_SetBits(tag, charids[s], glyphbits);
822 swf_SetBits(tag, charadvance[s], advancebits);
827 if(pass == 1 && t<chardatapos)
833 if(lastx != chardata[t].x ||
834 lasty != chardata[t].y)
836 newx = chardata[t].x;
837 newy = chardata[t].y;
843 if(!colorcompare(&color, &chardata[t].color))
845 color = chardata[t].color;
848 font.id = chardata[t].fontid;
849 if(lastfontid != chardata[t].fontid || lastsize != chardata[t].size)
852 tag->writeBit = 0; // Q&D
853 swf_TextSetInfoRecord(tag, newfont, chardata[t].size, newcolor, newx,newy);
856 lastfontid = chardata[t].fontid;
857 lastx = chardata[t].x;
858 lasty = chardata[t].y;
859 lastsize = chardata[t].size;
866 int nextt = t==chardatapos-1?t:t+1;
867 int rel = chardata[nextt].x-chardata[t].x;
868 if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) {
870 lastx=chardata[nextt].x;
876 charids[charstorepos] = chardata[t].charid;
877 charadvance[charstorepos] = advance;
884 static void putcharacter(struct swfoutput*obj, int fontid, int charid,
885 int x,int y, int size)
887 if(chardatapos == CHARDATAMAX)
889 msg("<warning> Character buffer too small. SWF will be slightly bigger");
893 chardata[chardatapos].fontid = fontid;
894 chardata[chardatapos].charid = charid;
895 chardata[chardatapos].x = x;
896 chardata[chardatapos].y = y;
897 chardata[chardatapos].color = obj->fillrgb;
898 chardata[chardatapos].size = size;
908 /* process a character. */
909 static int drawchar(struct swfoutput*obj, SWFFONT *swffont, char*character, int charnr, int u, swfmatrix*m)
912 msg("<warning> Font is NULL");
916 int charid = getCharID(swffont, charnr, character, u);
919 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
920 FIXNULL(character),charnr, u, FIXNULL((char*)swffont->name), swffont->numchars);
931 float det = ((m->m11*m->m22)-(m->m21*m->m12));
932 if(fabs(det) < 0.0005) {
933 /* x direction equals y direction- the text is invisible */
939 p.x = (SCOORD)(( x * m->m22 - y * m->m12)*det);
940 p.y = (SCOORD)((- x * m->m21 + y * m->m11)*det);
942 putcharacter(obj, swffont->id, charid,p.x,p.y,1);
943 swf_FontUseGlyph(swffont, charid);
948 SWF_OUTLINE*outline = font->getOutline(character, charnr);
949 char* charname = character;
952 msg("<warning> Didn't find character '%s' (%d) in current charset (%s)",
953 FIXNULL(character),charnr,FIXNULL(font->getName()));
972 drawpath(tag, outline, &m2, 0);
977 static void endtext(swfoutput*obj)
983 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
984 swf_ObjectPlace(tag,textid,/*depth*/depth++,&obj->fontmatrix,NULL,NULL);
989 /* draw a curved polygon. */
990 void swfoutput_drawpath(swfoutput*output, SWF_OUTLINE*outline,
996 /* Multiple polygons in one shape don't overlap correctly,
997 so we better start a new shape here if the polygon is filled
999 if(shapeid>=0 && fill && !ignoredraworder) {
1011 drawpath(output, outline,m, 0);
1014 void swfoutput_drawpath2poly(struct swfoutput*output, SWF_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
1024 drawpath2poly(output, outline, m, 0, line_join, line_cap, line_width, miter_limit);
1027 int getCharID(SWFFONT *font, int charnr, char *charname, int u)
1031 for(t=0;t<font->numchars;t++) {
1032 if(font->glyphnames[t] && !strcmp(font->glyphnames[t],charname)) {
1036 /* if we didn't find the character, maybe
1037 we can find the capitalized version */
1038 for(t=0;t<font->numchars;t++) {
1039 if(font->glyphnames[t] && !strcasecmp(font->glyphnames[t],charname)) {
1046 /* try to use the unicode id */
1047 if(u>=0 && u<font->maxascii && font->ascii2glyph[u]>=0) {
1048 return font->ascii2glyph[u];
1052 if(charnr>=0 && charnr<font->numchars) {
1056 /* the following is technically wrong, and only works if the font encoding
1057 is US-ASCII based. It's needed for fonts which return broken unicode
1059 /* if(charnr>=0 && charnr<font->maxascii && font->ascii2glyph[charnr]>=0) {
1060 return font->ascii2glyph[charnr];
1067 /* set's the t1 font index of the font to use for swfoutput_drawchar(). */
1068 void swfoutput_setfont(struct swfoutput*obj, char*fontid, char*filename)
1070 fontlist_t*last=0,*iterator;
1072 msg("<error> No fontid");
1076 if(obj->swffont && obj->swffont->name && !strcmp((char*)obj->swffont->name,fontid))
1079 iterator = fontlist;
1081 if(!strcmp((char*)iterator->swffont->name,fontid)) {
1082 obj->swffont = iterator->swffont;
1086 iterator = iterator->next;
1090 msg("<error> No filename given for font- internal error?");
1094 swf_SetLoadFontParameters(0,/*skip unused*/0,/*full unicode*/1);
1095 SWFFONT*swffont = swf_LoadFont(filename);
1098 msg("<warning> Couldn't load font %s (%s)", fontid, filename);
1099 swffont = swf_LoadFont(0);
1102 swf_FontSetID(swffont, ++currentswfid);
1104 if(screenloglevel >= LOGLEVEL_DEBUG) {
1105 // print font information
1106 msg("<debug> Font %s (%s)",swffont->name, filename);
1107 msg("<debug> | ID: %d", swffont->id);
1108 msg("<debug> | Version: %d", swffont->version);
1109 msg("<debug> | Name: %s", fontid);
1110 msg("<debug> | Numchars: %d", swffont->numchars);
1111 msg("<debug> | Maxascii: %d", swffont->maxascii);
1112 msg("<debug> | Style: %d", swffont->style);
1113 msg("<debug> | Encoding: %d", swffont->encoding);
1114 for(int iii=0; iii<swffont->numchars;iii++) {
1115 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,
1116 swffont->layout->bounds[iii].xmin/20.0,
1117 swffont->layout->bounds[iii].ymin/20.0,
1118 swffont->layout->bounds[iii].xmax/20.0,
1119 swffont->layout->bounds[iii].ymax/20.0
1124 /* set the font name to the ID we use here */
1125 if(swffont->name) free(swffont->name);
1126 swffont->name = (U8*)strdup(fontid);
1128 iterator = new fontlist_t;
1129 iterator->swffont = swffont;
1133 last->next = iterator;
1135 fontlist = iterator;
1137 obj->swffont = swffont;
1140 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1142 fontlist_t *iterator = fontlist;
1144 if(!strcmp((char*)iterator->swffont->name,fontid))
1146 iterator = iterator->next;
1151 /* set's the matrix which is to be applied to characters drawn by
1152 swfoutput_drawchar() */
1153 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1154 double m21,double m22)
1156 if(obj->fontm11 == m11 &&
1157 obj->fontm12 == m12 &&
1158 obj->fontm21 == m21 &&
1159 obj->fontm22 == m22)
1169 m.sx = (U32)((obj->fontm11)*65536); m.r1 = (U32)((obj->fontm12)*65536);
1170 m.r0 = (U32)((obj->fontm21)*65536); m.sy = (U32)((obj->fontm22)*65536);
1173 obj->fontmatrix = m;
1176 /* draws a character at x,y. */
1177 int swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr, int u)
1180 m.m11 = obj->fontm11;
1181 m.m12 = obj->fontm12;
1182 m.m21 = obj->fontm21;
1183 m.m22 = obj->fontm22;
1186 return drawchar(obj, obj->swffont, character, charnr, u, &m);
1189 /* initialize the swf writer */
1190 void swfoutput_init(struct swfoutput* obj, char*_filename, int x1, int y1, int x2, int y2)
1194 memset(obj, 0, sizeof(struct swfoutput));
1195 filename = _filename;
1199 msg("<verbose> initializing swf output for size %d*%d\n", sizex,sizey);
1204 memset(&swf,0x00,sizeof(SWF));
1206 swf.fileVersion = flashversion;
1207 swf.frameRate = 0x0040; // 1 frame per 4 seconds
1208 swf.movieSize.xmin = 20*x1;
1209 swf.movieSize.ymin = 20*y1;
1210 swf.movieSize.xmax = 20*x2;
1211 swf.movieSize.ymax = 20*y2;
1215 swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1217 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1218 swf_SetRGB(tag,&rgb);
1220 if(1)/* add white rectangle */
1225 int shapeid = ++currentswfid;
1230 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
1232 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1233 swf_SetU16(tag,shapeid);
1234 swf_SetRect(tag,&r);
1235 swf_SetShapeHeader(tag,s);
1236 swf_ShapeSetAll(tag,s,x1*20,y1*20,ls1,fs1,0);
1237 swf_ShapeSetLine(tag,s,20*(x2-x1),0);
1238 swf_ShapeSetLine(tag,s,0,20*(y2-y1));
1239 swf_ShapeSetLine(tag,s,20*(x1-x2),0);
1240 swf_ShapeSetLine(tag,s,0,20*(y1-y2));
1241 swf_ShapeSetEnd(tag);
1243 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1244 swf_ObjectPlace(tag,shapeid,depth++,0,0,0);
1245 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1246 swf_ObjectPlaceClip(tag,shapeid,depth++,0,0,0,65535);
1250 tag = swf_InsertTag(tag, ST_PROTECT);
1255 void swfoutput_setprotected() //write PROTECT tag
1260 static void startshape(struct swfoutput*obj)
1268 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1270 swf_ShapeNew(&shape);
1271 linestyleid = swf_ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1272 rgb.r = obj->fillrgb.r;
1273 rgb.g = obj->fillrgb.g;
1274 rgb.b = obj->fillrgb.b;
1275 fillstyleid = swf_ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1277 shapeid = ++currentswfid;
1278 swf_SetU16(tag,shapeid); // ID
1280 /* TODO: patch back */
1286 swf_SetRect(tag,&r);
1288 swf_SetShapeStyles(tag,shape);
1289 swf_ShapeCountBits(shape,NULL,NULL);
1290 swf_SetShapeBits(tag,shape);
1292 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,linestyleid,0,0);
1293 swflastx=swflasty=0;
1298 static void starttext(struct swfoutput*obj)
1305 tag = swf_InsertTag(tag,ST_DEFINETEXT);
1306 textid = ++currentswfid;
1307 swf_SetU16(tag, textid);
1309 /* TODO: patch back */
1315 swf_SetRect(tag,&r);
1317 swf_GetMatrix(0, &m);
1318 swf_SetMatrix(tag,&m);
1319 swflastx=swflasty=0;
1322 static void endshape()
1326 swf_ShapeSetEnd(tag);
1329 // delete the tag again, we didn't do anything
1332 swf_DeleteTag(todel);
1334 /* TODO: fix bounding box */
1335 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1336 swf_ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL);
1341 static void endpage(struct swfoutput*obj)
1348 swfoutput_endclip(obj);
1352 atag = action_Stop(atag);
1353 atag = action_End(atag);
1354 tag = swf_InsertTag(tag,ST_DOACTION);
1355 swf_ActionSet(tag,atag);
1357 tag = swf_InsertTag(tag,ST_SHOWFRAME);
1360 void swfoutput_newpage(struct swfoutput*obj)
1364 for(depth--;depth>=startdepth;depth--) {
1365 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1366 swf_SetU16(tag,depth);
1372 /* Perform cleaning up, complete the swf, and write it out. */
1373 void swfoutput_destroy(struct swfoutput* obj)
1376 fontlist_t *tmp,*iterator = fontlist;
1378 TAG*mtag = swf.firstTag;
1379 if(iterator->swffont) {
1380 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1381 /*if(!storeallcharacters)
1382 swf_FontReduce(iterator->swffont);*/
1383 swf_FontSetDefine2(mtag, iterator->swffont);
1384 swf_FontFree(iterator->swffont);
1388 iterator = iterator->next;
1395 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1400 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1404 tag = swf_InsertTag(tag,ST_END);
1406 if(enablezlib || flashversion>=6) {
1407 if FAILED(swf_WriteSWC(fi,&swf))
1408 msg("<error> WriteSWC() failed.\n");
1410 if FAILED(swf_WriteSWF(fi,&swf))
1411 msg("<error> WriteSWF() failed.\n");
1416 msg("<notice> SWF written\n");
1419 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1421 obj->drawmode = mode;
1422 if(mode == DRAWMODE_FILL)
1424 else if(mode == DRAWMODE_EOFILL)
1426 else if(mode == DRAWMODE_STROKE)
1428 else if(mode == DRAWMODE_CLIP)
1430 else if(mode == DRAWMODE_EOCLIP)
1434 void swfoutput_setfillcolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1436 if(obj->fillrgb.r == r &&
1437 obj->fillrgb.g == g &&
1438 obj->fillrgb.b == b &&
1439 obj->fillrgb.a == a) return;
1449 void swfoutput_setstrokecolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1451 if(obj->strokergb.r == r &&
1452 obj->strokergb.g == g &&
1453 obj->strokergb.b == b &&
1454 obj->strokergb.a == a) return;
1458 obj->strokergb.r = r;
1459 obj->strokergb.g = g;
1460 obj->strokergb.b = b;
1461 obj->strokergb.a = a;
1464 void swfoutput_setlinewidth(struct swfoutput*obj, double linewidth)
1466 if(obj->linewidth == (u16)(linewidth*20))
1471 obj->linewidth = (u16)(linewidth*20);
1475 void swfoutput_startclip(swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m)
1484 msg("<warning> Too many clip levels.");
1489 int olddrawmode = obj->drawmode;
1490 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1491 swfoutput_drawpath(obj, outline, m);
1492 swf_ShapeSetEnd(tag);
1493 swfoutput_setdrawmode(obj, olddrawmode);
1495 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1496 cliptags[clippos] = tag;
1497 clipshapes[clippos] = shapeid;
1498 clipdepths[clippos] = depth++;
1503 void swfoutput_endclip(swfoutput*obj)
1511 msg("<error> Invalid end of clipping region");
1515 swf_ObjectPlaceClip(cliptags[clippos],clipshapes[clippos],clipdepths[clippos],NULL,NULL,NULL,depth++);
1518 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1520 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1523 if(!strncmp("http://pdf2swf:", url, 15)) {
1524 char*tmp = strdup(url);
1525 int l = strlen(tmp);
1528 swfoutput_namedlink(obj, tmp+15, points);
1539 actions = action_GetUrl(0, url, "_parent");
1541 actions = action_GetUrl(0, url, "_this");
1542 actions = action_End(actions);
1544 drawlink(obj, actions, 0, points,0);
1546 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1555 actions = action_GotoFrame(0, page);
1556 actions = action_End(actions);
1558 drawlink(obj, actions, 0, points,0);
1561 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
1562 of the viewer objects, like subtitles, index elements etc.
1564 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
1566 ActionTAG *actions1,*actions2;
1567 char*tmp = strdup(name);
1575 if(!strncmp(tmp, "call:", 5))
1577 char*x = strchr(&tmp[5], ':');
1579 actions1 = action_PushInt(0, 0); //number of parameters (0)
1580 actions1 = action_PushString(actions1, &tmp[5]); //function name
1581 actions1 = action_CallFunction(actions1);
1584 actions1 = action_PushString(0, x+1); //parameter
1585 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
1586 actions1 = action_PushString(actions1, &tmp[5]); //function name
1587 actions1 = action_CallFunction(actions1);
1589 actions2 = action_End(0);
1594 actions1 = action_PushString(0, "/:subtitle");
1595 actions1 = action_PushString(actions1, name);
1596 actions1 = action_SetVariable(actions1);
1597 actions1 = action_End(actions1);
1599 actions2 = action_PushString(0, "/:subtitle");
1600 actions2 = action_PushString(actions2, "");
1601 actions2 = action_SetVariable(actions2);
1602 actions2 = action_End(actions2);
1605 drawlink(obj, actions1, actions2, points,mouseover);
1607 swf_ActionFree(actions1);
1608 swf_ActionFree(actions2);
1612 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
1618 struct plotxy p1,p2,p3,p4;
1622 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
1626 int buttonid = ++currentswfid;
1629 if(points[t].x>xmax) xmax=points[t].x;
1630 if(points[t].y>ymax) ymax=points[t].y;
1631 if(points[t].x<xmin) xmin=points[t].x;
1632 if(points[t].y<ymin) ymin=points[t].y;
1635 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
1636 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
1638 /* the following code subtracts the upper left edge from all coordinates,
1639 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
1640 Necessary for preprocessing with swfcombine. */
1641 posx = xmin; posy = ymin;
1642 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
1643 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
1644 xmin -= posx; ymin -= posy;
1645 xmax -= posx; ymax -= posy;
1648 myshapeid = ++currentswfid;
1649 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1650 swf_ShapeNew(&shape);
1651 rgb.r = rgb.b = rgb.a = rgb.g = 0;
1652 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1653 swf_SetU16(tag, myshapeid);
1654 r.xmin = (int)(xmin*20);
1655 r.ymin = (int)(ymin*20);
1656 r.xmax = (int)(xmax*20);
1657 r.ymax = (int)(ymax*20);
1658 swf_SetRect(tag,&r);
1659 swf_SetShapeStyles(tag,shape);
1660 swf_ShapeCountBits(shape,NULL,NULL);
1661 swf_SetShapeBits(tag,shape);
1662 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1663 swflastx = swflasty = 0;
1669 swf_ShapeSetEnd(tag);
1672 myshapeid2 = ++currentswfid;
1673 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1674 swf_ShapeNew(&shape);
1675 rgb.r = rgb.b = rgb.a = rgb.g = 255;
1677 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1678 swf_SetU16(tag, myshapeid2);
1679 r.xmin = (int)(xmin*20);
1680 r.ymin = (int)(ymin*20);
1681 r.xmax = (int)(xmax*20);
1682 r.ymax = (int)(ymax*20);
1683 swf_SetRect(tag,&r);
1684 swf_SetShapeStyles(tag,shape);
1685 swf_ShapeCountBits(shape,NULL,NULL);
1686 swf_SetShapeBits(tag,shape);
1687 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1688 swflastx = swflasty = 0;
1694 swf_ShapeSetEnd(tag);
1698 tag = swf_InsertTag(tag,ST_DEFINEBUTTON);
1699 swf_SetU16(tag,buttonid); //id
1700 swf_ButtonSetFlags(tag, 0); //menu=no
1701 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1702 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1703 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1704 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1706 swf_ActionSet(tag,actions1);
1711 tag = swf_InsertTag(tag,ST_DEFINEBUTTON2);
1712 swf_SetU16(tag,buttonid); //id
1713 swf_ButtonSetFlags(tag, 0); //menu=no
1714 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1715 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1716 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1717 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1718 swf_SetU8(tag,0); // end of button records
1719 swf_ButtonSetCondition(tag, BC_IDLE_OVERUP);
1720 swf_ActionSet(tag,actions1);
1722 swf_ButtonSetCondition(tag, BC_OVERUP_IDLE);
1723 swf_ActionSet(tag,actions2);
1725 swf_ButtonPostProcess(tag, 2);
1728 swf_ButtonPostProcess(tag, 1);
1732 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1734 if(posx!=0 || posy!=0) {
1736 swf_GetMatrix(0,&m);
1737 m.tx = (int)(posx*20);
1738 m.ty = (int)(posy*20);
1739 swf_ObjectPlace(tag, buttonid, depth++,&m,0,0);
1742 swf_ObjectPlace(tag, buttonid, depth++,0,0,0);
1746 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
1747 double x1,double y1,
1748 double x2,double y2,
1749 double x3,double y3,
1750 double x4,double y4)
1756 struct plotxy p1,p2,p3,p4;
1758 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
1759 if(x2>xmax) xmax=x2;
1760 if(y2>ymax) ymax=y2;
1761 if(x2<xmin) xmin=x2;
1762 if(y2<ymin) ymin=y2;
1763 if(x3>xmax) xmax=x3;
1764 if(y3>ymax) ymax=y3;
1765 if(x3<xmin) xmin=x3;
1766 if(y3<ymin) ymin=y3;
1767 if(x4>xmax) xmax=x4;
1768 if(y4>ymax) ymax=y4;
1769 if(x4<xmin) xmin=x4;
1770 if(y4<ymin) ymin=y4;
1776 {p1.x = (int)(p1.x*20)/20.0;
1777 p1.y = (int)(p1.y*20)/20.0;
1778 p2.x = (int)(p2.x*20)/20.0;
1779 p2.y = (int)(p2.y*20)/20.0;
1780 p3.x = (int)(p3.x*20)/20.0;
1781 p3.y = (int)(p3.y*20)/20.0;
1782 p4.x = (int)(p4.x*20)/20.0;
1783 p4.y = (int)(p4.y*20)/20.0;}
1786 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
1787 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
1788 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
1789 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
1791 m.tx = (int)(p1.x*20);
1792 m.ty = (int)(p1.y*20);
1795 myshapeid = ++currentswfid;
1796 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1797 swf_ShapeNew(&shape);
1798 //lsid = ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1799 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1800 fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
1801 swf_SetU16(tag, myshapeid);
1802 r.xmin = (int)(xmin*20);
1803 r.ymin = (int)(ymin*20);
1804 r.xmax = (int)(xmax*20);
1805 r.ymax = (int)(ymax*20);
1806 swf_SetRect(tag,&r);
1807 swf_SetShapeStyles(tag,shape);
1808 swf_ShapeCountBits(shape,NULL,NULL);
1809 swf_SetShapeBits(tag,shape);
1810 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,lsid,fsid,0);
1811 swflastx = swflasty = 0;
1818 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
1819 ShapeSetLine (tag, shape, (int)(x1*20);
1820 ShapeSetLine (tag, shape, x*20,0);
1821 ShapeSetLine (tag, shape, 0,-y*20);
1822 ShapeSetLine (tag, shape, -x*20,0);*/
1823 swf_ShapeSetEnd(tag);
1826 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1827 swf_ObjectPlace(tag,myshapeid,/*depth*/depth++,NULL,NULL,NULL);
1830 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
1831 double x1,double y1,
1832 double x2,double y2,
1833 double x3,double y3,
1834 double x4,double y4)
1842 int bitid = ++currentswfid;
1844 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
1845 swf_SetU16(tag, bitid);
1846 if(swf_SetJPEGBits(tag, filename, jpegquality)<0) {
1852 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1856 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
1857 double x1,double y1,
1858 double x2,double y2,
1859 double x3,double y3,
1860 double x4,double y4)
1870 int bitid = ++currentswfid;
1872 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
1873 swf_SetU16(tag, bitid);
1874 swf_SetJPEGBits2(tag,sizex,sizey,mem,jpegquality);
1875 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1879 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
1880 double x1,double y1,
1881 double x2,double y2,
1882 double x3,double y3,
1883 double x4,double y4)
1891 int bitid = ++currentswfid;
1893 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS);
1894 swf_SetU16(tag, bitid);
1895 if(swf_SetLosslessBits(tag,sizex,sizey,mem, BMF_32BIT)<0) {
1901 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1905 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
1906 double x1,double y1,
1907 double x2,double y2,
1908 double x3,double y3,
1909 double x4,double y4, int n)
1920 /* SWF expects scanlines to be 4 byte aligned */
1923 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
1925 for(y=0;y<sizey;y++)
1927 for(x=0;x<sizex;x++)
1928 *ptr++ = mem[y*sizex+x];
1929 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
1934 int bitid = ++currentswfid;
1936 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS2);
1937 swf_SetU16(tag, bitid);
1938 if(swf_SetLosslessBitsIndexed(tag,sizex,sizey,mem, pal, n)<0) {
1946 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1950 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
1951 double x1,double y1,
1952 double x2,double y2,
1953 double x3,double y3,
1954 double x4,double y4)
1962 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);