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 SRECT getcharacterbbox(SWFFONT*font)
752 memset(&r, 0, sizeof(r));
755 if(debug) printf("\n");
756 for(t=0;t<chardatapos;t++)
758 if(chardata[t].fontid != font->id) {
759 msg("<error> Internal error: fontid %d != fontid %d", chardata[t].fontid, font->id);
762 SRECT b = font->layout->bounds[chardata[t].charid];
763 b.xmin *= chardata[t].size;
764 b.ymin *= chardata[t].size;
765 b.xmax *= chardata[t].size;
766 b.ymax *= chardata[t].size;
771 b.xmin += chardata[t].x;
772 b.ymin += chardata[t].y;
773 b.xmax += chardata[t].x;
774 b.ymax += chardata[t].y;
776 /* until we solve the INTERNAL_SCALING problem (see below)
777 make sure the bounding box is big enough */
783 if(debug) printf("(%f,%f,%f,%f) -> (%f,%f,%f,%f) [font %d/%d, char %d]\n",
784 font->layout->bounds[chardata[t].charid].xmin/20.0,
785 font->layout->bounds[chardata[t].charid].ymin/20.0,
786 font->layout->bounds[chardata[t].charid].xmax/20.0,
787 font->layout->bounds[chardata[t].charid].ymax/20.0,
796 swf_ExpandRect2(&r, &b);
798 if(debug) printf("-----> (%f,%f,%f,%f)\n",
806 static void putcharacters(TAG*tag)
811 color.r = chardata[0].color.r^255;
820 int charadvance[128];
823 int glyphbits=1; //TODO: can this be zero?
826 if(tag->id != ST_DEFINETEXT &&
827 tag->id != ST_DEFINETEXT2) {
828 msg("<error> internal error: putcharacters needs an text tag, not %d\n",tag->id);
832 msg("<warning> putcharacters called with zero characters");
835 for(pass = 0; pass < 2; pass++)
845 advancebits++; // add sign bit
846 swf_SetU8(tag, glyphbits);
847 swf_SetU8(tag, advancebits);
850 for(t=0;t<=chardatapos;t++)
852 if(lastfontid != chardata[t].fontid ||
853 lastx!=chardata[t].x ||
854 lasty!=chardata[t].y ||
855 !colorcompare(&color, &chardata[t].color) ||
857 lastsize != chardata[t].size ||
860 if(charstorepos && pass==0)
863 for(s=0;s<charstorepos;s++)
865 while(charids[s]>=(1<<glyphbits))
867 while(charadvance[s]>=(1<<advancebits))
871 if(charstorepos && pass==1)
873 tag->writeBit = 0; // Q&D
874 swf_SetBits(tag, 0, 1); // GLYPH Record
875 swf_SetBits(tag, charstorepos, 7); // number of glyphs
877 for(s=0;s<charstorepos;s++)
879 swf_SetBits(tag, charids[s], glyphbits);
880 swf_SetBits(tag, charadvance[s], advancebits);
885 if(pass == 1 && t<chardatapos)
891 if(lastx != chardata[t].x ||
892 lasty != chardata[t].y)
894 newx = chardata[t].x;
895 newy = chardata[t].y;
901 if(!colorcompare(&color, &chardata[t].color))
903 color = chardata[t].color;
906 font.id = chardata[t].fontid;
907 if(lastfontid != chardata[t].fontid || lastsize != chardata[t].size)
910 tag->writeBit = 0; // Q&D
911 swf_TextSetInfoRecord(tag, newfont, chardata[t].size, newcolor, newx,newy);
914 lastfontid = chardata[t].fontid;
915 lastx = chardata[t].x;
916 lasty = chardata[t].y;
917 lastsize = chardata[t].size;
924 int nextt = t==chardatapos-1?t:t+1;
925 int rel = chardata[nextt].x-chardata[t].x;
926 if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) {
928 lastx=chardata[nextt].x;
934 charids[charstorepos] = chardata[t].charid;
935 charadvance[charstorepos] = advance;
942 static void putcharacter(struct swfoutput*obj, int fontid, int charid,
943 int x,int y, int size)
945 if(chardatapos == CHARDATAMAX)
947 msg("<warning> Character buffer too small. SWF will be slightly bigger");
951 chardata[chardatapos].fontid = fontid;
952 chardata[chardatapos].charid = charid;
953 chardata[chardatapos].x = x;
954 chardata[chardatapos].y = y;
955 chardata[chardatapos].color = obj->fillrgb;
956 chardata[chardatapos].size = size;
966 /* todo: why don't higher values (64, 1024) work here? */
967 #define FONT_INTERNAL_SIZE 1
969 /* process a character. */
970 static int drawchar(struct swfoutput*obj, SWFFONT *swffont, char*character, int charnr, int u, swfmatrix*m)
973 msg("<warning> Font is NULL");
977 int charid = getCharID(swffont, charnr, character, u);
980 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
981 FIXNULL(character),charnr, u, FIXNULL((char*)swffont->name), swffont->numchars);
992 float det = ((m->m11*m->m22)-(m->m21*m->m12));
993 if(fabs(det) < 0.0005) {
994 /* x direction equals y direction- the text is invisible */
997 det = 20*FONT_INTERNAL_SIZE / det;
1000 p.x = (SCOORD)(( x * m->m22 - y * m->m12)*det);
1001 p.y = (SCOORD)((- x * m->m21 + y * m->m11)*det);
1003 putcharacter(obj, swffont->id, charid,p.x,p.y,FONT_INTERNAL_SIZE);
1004 swf_FontUseGlyph(swffont, charid);
1009 SWF_OUTLINE*outline = font->getOutline(character, charnr);
1010 char* charname = character;
1013 msg("<warning> Didn't find character '%s' (%d) in current charset (%s)",
1014 FIXNULL(character),charnr,FIXNULL(font->getName()));
1033 drawpath(tag, outline, &m2, 0);
1038 static void endtext(swfoutput*obj)
1043 tag = swf_InsertTag(tag,ST_DEFINETEXT);
1044 swf_SetU16(tag, textid);
1047 r = getcharacterbbox(obj->swffont);
1049 swf_SetRect(tag,&r);
1052 swf_GetMatrix(0, &m);
1053 swf_SetMatrix(tag,&m);
1057 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1058 swf_ObjectPlace(tag,textid,/*depth*/depth++,&obj->fontmatrix,NULL,NULL);
1063 /* draw a curved polygon. */
1064 void swfoutput_drawpath(swfoutput*output, SWF_OUTLINE*outline,
1070 /* Multiple polygons in one shape don't overlap correctly,
1071 so we better start a new shape here if the polygon is filled
1073 if(shapeid>=0 && fill && !ignoredraworder) {
1085 drawpath(output, outline,m, 0);
1088 void swfoutput_drawpath2poly(struct swfoutput*output, SWF_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
1098 drawpath2poly(output, outline, m, 0, line_join, line_cap, line_width, miter_limit);
1101 int getCharID(SWFFONT *font, int charnr, char *charname, int u)
1105 for(t=0;t<font->numchars;t++) {
1106 if(font->glyphnames[t] && !strcmp(font->glyphnames[t],charname)) {
1110 /* if we didn't find the character, maybe
1111 we can find the capitalized version */
1112 for(t=0;t<font->numchars;t++) {
1113 if(font->glyphnames[t] && !strcasecmp(font->glyphnames[t],charname)) {
1120 /* try to use the unicode id */
1121 if(u>=0 && u<font->maxascii && font->ascii2glyph[u]>=0) {
1122 return font->ascii2glyph[u];
1126 if(charnr>=0 && charnr<font->numchars) {
1130 /* the following is technically wrong, and only works if the font encoding
1131 is US-ASCII based. It's needed for fonts which return broken unicode
1133 /* if(charnr>=0 && charnr<font->maxascii && font->ascii2glyph[charnr]>=0) {
1134 return font->ascii2glyph[charnr];
1141 /* set's the t1 font index of the font to use for swfoutput_drawchar(). */
1142 void swfoutput_setfont(struct swfoutput*obj, char*fontid, char*filename)
1144 fontlist_t*last=0,*iterator;
1146 msg("<error> No fontid");
1150 if(obj->swffont && obj->swffont->name && !strcmp((char*)obj->swffont->name,fontid))
1153 /* TODO: remove the need for this (enhance getcharacterbbox so that it can cope
1154 with multiple fonts */
1157 iterator = fontlist;
1159 if(!strcmp((char*)iterator->swffont->name,fontid)) {
1160 obj->swffont = iterator->swffont;
1164 iterator = iterator->next;
1168 msg("<error> No filename given for font- internal error?");
1172 swf_SetLoadFontParameters(64,/*skip unused*/0,/*full unicode*/1);
1173 SWFFONT*swffont = swf_LoadFont(filename);
1176 msg("<warning> Couldn't load font %s (%s)", fontid, filename);
1177 swffont = swf_LoadFont(0);
1180 swf_FontSetID(swffont, ++currentswfid);
1182 if(screenloglevel >= LOGLEVEL_DEBUG) {
1183 // print font information
1184 msg("<debug> Font %s (%s)",swffont->name, filename);
1185 msg("<debug> | ID: %d", swffont->id);
1186 msg("<debug> | Version: %d", swffont->version);
1187 msg("<debug> | Name: %s", fontid);
1188 msg("<debug> | Numchars: %d", swffont->numchars);
1189 msg("<debug> | Maxascii: %d", swffont->maxascii);
1190 msg("<debug> | Style: %d", swffont->style);
1191 msg("<debug> | Encoding: %d", swffont->encoding);
1192 for(int iii=0; iii<swffont->numchars;iii++) {
1193 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,
1194 swffont->layout->bounds[iii].xmin/20.0,
1195 swffont->layout->bounds[iii].ymin/20.0,
1196 swffont->layout->bounds[iii].xmax/20.0,
1197 swffont->layout->bounds[iii].ymax/20.0
1202 /* set the font name to the ID we use here */
1203 if(swffont->name) free(swffont->name);
1204 swffont->name = (U8*)strdup(fontid);
1206 iterator = new fontlist_t;
1207 iterator->swffont = swffont;
1211 last->next = iterator;
1213 fontlist = iterator;
1215 obj->swffont = swffont;
1218 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1220 fontlist_t *iterator = fontlist;
1222 if(!strcmp((char*)iterator->swffont->name,fontid))
1224 iterator = iterator->next;
1229 /* set's the matrix which is to be applied to characters drawn by
1230 swfoutput_drawchar() */
1231 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1232 double m21,double m22)
1234 if(obj->fontm11 == m11 &&
1235 obj->fontm12 == m12 &&
1236 obj->fontm21 == m21 &&
1237 obj->fontm22 == m22)
1247 m.sx = (U32)(((obj->fontm11)*65536)/FONT_INTERNAL_SIZE); m.r1 = (U32)(((obj->fontm12)*65536)/FONT_INTERNAL_SIZE);
1248 m.r0 = (U32)(((obj->fontm21)*65536)/FONT_INTERNAL_SIZE); m.sy = (U32)(((obj->fontm22)*65536)/FONT_INTERNAL_SIZE);
1251 obj->fontmatrix = m;
1254 /* draws a character at x,y. */
1255 int swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr, int u)
1258 m.m11 = obj->fontm11;
1259 m.m12 = obj->fontm12;
1260 m.m21 = obj->fontm21;
1261 m.m22 = obj->fontm22;
1264 return drawchar(obj, obj->swffont, character, charnr, u, &m);
1267 /* initialize the swf writer */
1268 void swfoutput_init(struct swfoutput* obj, char*_filename, int x1, int y1, int x2, int y2)
1272 memset(obj, 0, sizeof(struct swfoutput));
1273 filename = _filename;
1277 msg("<verbose> initializing swf output for size %d*%d\n", sizex,sizey);
1282 memset(&swf,0x00,sizeof(SWF));
1284 swf.fileVersion = flashversion;
1285 swf.frameRate = 0x0040; // 1 frame per 4 seconds
1286 swf.movieSize.xmin = 20*x1;
1287 swf.movieSize.ymin = 20*y1;
1288 swf.movieSize.xmax = 20*x2;
1289 swf.movieSize.ymax = 20*y2;
1293 swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1295 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1296 swf_SetRGB(tag,&rgb);
1298 if(1)/* add white rectangle */
1303 int shapeid = ++currentswfid;
1308 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
1310 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1311 swf_SetU16(tag,shapeid);
1312 swf_SetRect(tag,&r);
1313 swf_SetShapeHeader(tag,s);
1314 swf_ShapeSetAll(tag,s,x1*20,y1*20,ls1,fs1,0);
1315 swf_ShapeSetLine(tag,s,20*(x2-x1),0);
1316 swf_ShapeSetLine(tag,s,0,20*(y2-y1));
1317 swf_ShapeSetLine(tag,s,20*(x1-x2),0);
1318 swf_ShapeSetLine(tag,s,0,20*(y1-y2));
1319 swf_ShapeSetEnd(tag);
1321 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1322 swf_ObjectPlace(tag,shapeid,depth++,0,0,0);
1323 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1324 swf_ObjectPlaceClip(tag,shapeid,depth++,0,0,0,65535);
1328 tag = swf_InsertTag(tag, ST_PROTECT);
1333 void swfoutput_setprotected() //write PROTECT tag
1338 static void startshape(struct swfoutput*obj)
1346 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1348 swf_ShapeNew(&shape);
1349 linestyleid = swf_ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1350 rgb.r = obj->fillrgb.r;
1351 rgb.g = obj->fillrgb.g;
1352 rgb.b = obj->fillrgb.b;
1353 fillstyleid = swf_ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1355 shapeid = ++currentswfid;
1356 swf_SetU16(tag,shapeid); // ID
1358 /* TODO: patch back */
1364 swf_SetRect(tag,&r);
1366 swf_SetShapeStyles(tag,shape);
1367 swf_ShapeCountBits(shape,NULL,NULL);
1368 swf_SetShapeBits(tag,shape);
1370 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,linestyleid,0,0);
1371 swflastx=swflasty=0;
1376 static void starttext(struct swfoutput*obj)
1381 textid = ++currentswfid;
1383 swflastx=swflasty=0;
1386 static void endshape()
1390 swf_ShapeSetEnd(tag);
1393 // delete the tag again, we didn't do anything
1396 swf_DeleteTag(todel);
1398 /* TODO: fix bounding box */
1399 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1400 swf_ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL);
1405 static void endpage(struct swfoutput*obj)
1412 swfoutput_endclip(obj);
1416 atag = action_Stop(atag);
1417 atag = action_End(atag);
1418 tag = swf_InsertTag(tag,ST_DOACTION);
1419 swf_ActionSet(tag,atag);
1421 tag = swf_InsertTag(tag,ST_SHOWFRAME);
1424 void swfoutput_newpage(struct swfoutput*obj)
1428 for(depth--;depth>=startdepth;depth--) {
1429 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1430 swf_SetU16(tag,depth);
1436 /* Perform cleaning up, complete the swf, and write it out. */
1437 void swfoutput_destroy(struct swfoutput* obj)
1440 fontlist_t *tmp,*iterator = fontlist;
1442 TAG*mtag = swf.firstTag;
1443 if(iterator->swffont) {
1444 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1445 /*if(!storeallcharacters)
1446 swf_FontReduce(iterator->swffont);*/
1447 swf_FontSetDefine2(mtag, iterator->swffont);
1448 swf_FontFree(iterator->swffont);
1452 iterator = iterator->next;
1459 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1464 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1468 tag = swf_InsertTag(tag,ST_END);
1470 if(enablezlib || flashversion>=6) {
1471 if FAILED(swf_WriteSWC(fi,&swf))
1472 msg("<error> WriteSWC() failed.\n");
1474 if FAILED(swf_WriteSWF(fi,&swf))
1475 msg("<error> WriteSWF() failed.\n");
1480 msg("<notice> SWF written\n");
1483 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1485 obj->drawmode = mode;
1486 if(mode == DRAWMODE_FILL)
1488 else if(mode == DRAWMODE_EOFILL)
1490 else if(mode == DRAWMODE_STROKE)
1492 else if(mode == DRAWMODE_CLIP)
1494 else if(mode == DRAWMODE_EOCLIP)
1498 void swfoutput_setfillcolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1500 if(obj->fillrgb.r == r &&
1501 obj->fillrgb.g == g &&
1502 obj->fillrgb.b == b &&
1503 obj->fillrgb.a == a) return;
1513 void swfoutput_setstrokecolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1515 if(obj->strokergb.r == r &&
1516 obj->strokergb.g == g &&
1517 obj->strokergb.b == b &&
1518 obj->strokergb.a == a) return;
1522 obj->strokergb.r = r;
1523 obj->strokergb.g = g;
1524 obj->strokergb.b = b;
1525 obj->strokergb.a = a;
1528 void swfoutput_setlinewidth(struct swfoutput*obj, double linewidth)
1530 if(obj->linewidth == (u16)(linewidth*20))
1535 obj->linewidth = (u16)(linewidth*20);
1539 void swfoutput_startclip(swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m)
1548 msg("<warning> Too many clip levels.");
1553 int olddrawmode = obj->drawmode;
1554 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1555 swfoutput_drawpath(obj, outline, m);
1556 swf_ShapeSetEnd(tag);
1557 swfoutput_setdrawmode(obj, olddrawmode);
1559 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1560 cliptags[clippos] = tag;
1561 clipshapes[clippos] = shapeid;
1562 clipdepths[clippos] = depth++;
1567 void swfoutput_endclip(swfoutput*obj)
1575 msg("<error> Invalid end of clipping region");
1579 swf_ObjectPlaceClip(cliptags[clippos],clipshapes[clippos],clipdepths[clippos],NULL,NULL,NULL,depth++);
1582 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1584 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1587 if(!strncmp("http://pdf2swf:", url, 15)) {
1588 char*tmp = strdup(url);
1589 int l = strlen(tmp);
1592 swfoutput_namedlink(obj, tmp+15, points);
1603 actions = action_GetUrl(0, url, "_parent");
1605 actions = action_GetUrl(0, url, "_this");
1606 actions = action_End(actions);
1608 drawlink(obj, actions, 0, points,0);
1610 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1619 actions = action_GotoFrame(0, page);
1620 actions = action_End(actions);
1622 drawlink(obj, actions, 0, points,0);
1625 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
1626 of the viewer objects, like subtitles, index elements etc.
1628 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
1630 ActionTAG *actions1,*actions2;
1631 char*tmp = strdup(name);
1639 if(!strncmp(tmp, "call:", 5))
1641 char*x = strchr(&tmp[5], ':');
1643 actions1 = action_PushInt(0, 0); //number of parameters (0)
1644 actions1 = action_PushString(actions1, &tmp[5]); //function name
1645 actions1 = action_CallFunction(actions1);
1648 actions1 = action_PushString(0, x+1); //parameter
1649 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
1650 actions1 = action_PushString(actions1, &tmp[5]); //function name
1651 actions1 = action_CallFunction(actions1);
1653 actions2 = action_End(0);
1658 actions1 = action_PushString(0, "/:subtitle");
1659 actions1 = action_PushString(actions1, name);
1660 actions1 = action_SetVariable(actions1);
1661 actions1 = action_End(actions1);
1663 actions2 = action_PushString(0, "/:subtitle");
1664 actions2 = action_PushString(actions2, "");
1665 actions2 = action_SetVariable(actions2);
1666 actions2 = action_End(actions2);
1669 drawlink(obj, actions1, actions2, points,mouseover);
1671 swf_ActionFree(actions1);
1672 swf_ActionFree(actions2);
1676 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
1682 struct plotxy p1,p2,p3,p4;
1686 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
1690 int buttonid = ++currentswfid;
1693 if(points[t].x>xmax) xmax=points[t].x;
1694 if(points[t].y>ymax) ymax=points[t].y;
1695 if(points[t].x<xmin) xmin=points[t].x;
1696 if(points[t].y<ymin) ymin=points[t].y;
1699 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
1700 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
1702 /* the following code subtracts the upper left edge from all coordinates,
1703 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
1704 Necessary for preprocessing with swfcombine. */
1705 posx = xmin; posy = ymin;
1706 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
1707 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
1708 xmin -= posx; ymin -= posy;
1709 xmax -= posx; ymax -= posy;
1712 myshapeid = ++currentswfid;
1713 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1714 swf_ShapeNew(&shape);
1715 rgb.r = rgb.b = rgb.a = rgb.g = 0;
1716 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1717 swf_SetU16(tag, myshapeid);
1718 r.xmin = (int)(xmin*20);
1719 r.ymin = (int)(ymin*20);
1720 r.xmax = (int)(xmax*20);
1721 r.ymax = (int)(ymax*20);
1722 swf_SetRect(tag,&r);
1723 swf_SetShapeStyles(tag,shape);
1724 swf_ShapeCountBits(shape,NULL,NULL);
1725 swf_SetShapeBits(tag,shape);
1726 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1727 swflastx = swflasty = 0;
1733 swf_ShapeSetEnd(tag);
1736 myshapeid2 = ++currentswfid;
1737 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1738 swf_ShapeNew(&shape);
1739 rgb.r = rgb.b = rgb.a = rgb.g = 255;
1741 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1742 swf_SetU16(tag, myshapeid2);
1743 r.xmin = (int)(xmin*20);
1744 r.ymin = (int)(ymin*20);
1745 r.xmax = (int)(xmax*20);
1746 r.ymax = (int)(ymax*20);
1747 swf_SetRect(tag,&r);
1748 swf_SetShapeStyles(tag,shape);
1749 swf_ShapeCountBits(shape,NULL,NULL);
1750 swf_SetShapeBits(tag,shape);
1751 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1752 swflastx = swflasty = 0;
1758 swf_ShapeSetEnd(tag);
1762 tag = swf_InsertTag(tag,ST_DEFINEBUTTON);
1763 swf_SetU16(tag,buttonid); //id
1764 swf_ButtonSetFlags(tag, 0); //menu=no
1765 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1766 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1767 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1768 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1770 swf_ActionSet(tag,actions1);
1775 tag = swf_InsertTag(tag,ST_DEFINEBUTTON2);
1776 swf_SetU16(tag,buttonid); //id
1777 swf_ButtonSetFlags(tag, 0); //menu=no
1778 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1779 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1780 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1781 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1782 swf_SetU8(tag,0); // end of button records
1783 swf_ButtonSetCondition(tag, BC_IDLE_OVERUP);
1784 swf_ActionSet(tag,actions1);
1786 swf_ButtonSetCondition(tag, BC_OVERUP_IDLE);
1787 swf_ActionSet(tag,actions2);
1789 swf_ButtonPostProcess(tag, 2);
1792 swf_ButtonPostProcess(tag, 1);
1796 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1798 if(posx!=0 || posy!=0) {
1800 swf_GetMatrix(0,&m);
1801 m.tx = (int)(posx*20);
1802 m.ty = (int)(posy*20);
1803 swf_ObjectPlace(tag, buttonid, depth++,&m,0,0);
1806 swf_ObjectPlace(tag, buttonid, depth++,0,0,0);
1810 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
1811 double x1,double y1,
1812 double x2,double y2,
1813 double x3,double y3,
1814 double x4,double y4)
1820 struct plotxy p1,p2,p3,p4;
1822 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
1823 if(x2>xmax) xmax=x2;
1824 if(y2>ymax) ymax=y2;
1825 if(x2<xmin) xmin=x2;
1826 if(y2<ymin) ymin=y2;
1827 if(x3>xmax) xmax=x3;
1828 if(y3>ymax) ymax=y3;
1829 if(x3<xmin) xmin=x3;
1830 if(y3<ymin) ymin=y3;
1831 if(x4>xmax) xmax=x4;
1832 if(y4>ymax) ymax=y4;
1833 if(x4<xmin) xmin=x4;
1834 if(y4<ymin) ymin=y4;
1840 {p1.x = (int)(p1.x*20)/20.0;
1841 p1.y = (int)(p1.y*20)/20.0;
1842 p2.x = (int)(p2.x*20)/20.0;
1843 p2.y = (int)(p2.y*20)/20.0;
1844 p3.x = (int)(p3.x*20)/20.0;
1845 p3.y = (int)(p3.y*20)/20.0;
1846 p4.x = (int)(p4.x*20)/20.0;
1847 p4.y = (int)(p4.y*20)/20.0;}
1850 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
1851 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
1852 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
1853 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
1855 m.tx = (int)(p1.x*20);
1856 m.ty = (int)(p1.y*20);
1859 myshapeid = ++currentswfid;
1860 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1861 swf_ShapeNew(&shape);
1862 //lsid = ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1863 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1864 fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
1865 swf_SetU16(tag, myshapeid);
1866 r.xmin = (int)(xmin*20);
1867 r.ymin = (int)(ymin*20);
1868 r.xmax = (int)(xmax*20);
1869 r.ymax = (int)(ymax*20);
1870 swf_SetRect(tag,&r);
1871 swf_SetShapeStyles(tag,shape);
1872 swf_ShapeCountBits(shape,NULL,NULL);
1873 swf_SetShapeBits(tag,shape);
1874 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,lsid,fsid,0);
1875 swflastx = swflasty = 0;
1882 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
1883 ShapeSetLine (tag, shape, (int)(x1*20);
1884 ShapeSetLine (tag, shape, x*20,0);
1885 ShapeSetLine (tag, shape, 0,-y*20);
1886 ShapeSetLine (tag, shape, -x*20,0);*/
1887 swf_ShapeSetEnd(tag);
1890 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1891 swf_ObjectPlace(tag,myshapeid,/*depth*/depth++,NULL,NULL,NULL);
1894 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
1895 double x1,double y1,
1896 double x2,double y2,
1897 double x3,double y3,
1898 double x4,double y4)
1906 int bitid = ++currentswfid;
1908 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
1909 swf_SetU16(tag, bitid);
1910 if(swf_SetJPEGBits(tag, filename, jpegquality)<0) {
1916 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1920 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
1921 double x1,double y1,
1922 double x2,double y2,
1923 double x3,double y3,
1924 double x4,double y4)
1934 int bitid = ++currentswfid;
1936 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
1937 swf_SetU16(tag, bitid);
1938 swf_SetJPEGBits2(tag,sizex,sizey,mem,jpegquality);
1939 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1943 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
1944 double x1,double y1,
1945 double x2,double y2,
1946 double x3,double y3,
1947 double x4,double y4)
1955 int bitid = ++currentswfid;
1957 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS);
1958 swf_SetU16(tag, bitid);
1959 if(swf_SetLosslessBits(tag,sizex,sizey,mem, BMF_32BIT)<0) {
1965 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1969 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
1970 double x1,double y1,
1971 double x2,double y2,
1972 double x3,double y3,
1973 double x4,double y4, int n)
1984 /* SWF expects scanlines to be 4 byte aligned */
1987 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
1989 for(y=0;y<sizey;y++)
1991 for(x=0;x<sizex;x++)
1992 *ptr++ = mem[y*sizex+x];
1993 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
1998 int bitid = ++currentswfid;
2000 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS2);
2001 swf_SetU16(tag, bitid);
2002 if(swf_SetLosslessBitsIndexed(tag,sizex,sizey,mem, pal, n)<0) {
2010 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
2014 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
2015 double x1,double y1,
2016 double x2,double y2,
2017 double x3,double y3,
2018 double x4,double y4)
2026 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);