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();
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 rx = ((int)(p0.x*20)-swflastx);
123 int ry = ((int)(p0.y*20)-swflasty);
124 /* we can't skip this for rx=0,ry=0, those
126 swf_ShapeSetLine (tag, shape, rx,ry);
132 // write a spline-to command into the swf
133 static void splineto(TAG*tag, plotxy control,plotxy end)
135 int cx = ((int)(control.x*20)-swflastx);
136 int cy = ((int)(control.y*20)-swflasty);
139 int ex = ((int)(end.x*20)-swflastx);
140 int ey = ((int)(end.y*20)-swflasty);
143 if(cx || cy || ex || ey)
144 swf_ShapeSetCurve(tag, shape, cx,cy,ex,ey);
148 /* write a line, given two points and the transformation
150 static void line(TAG*tag, plotxy p0, plotxy p1, struct swfmatrix*m)
158 /* write a cubic (!) spline. This involves calling the approximate()
159 function out of spline.cc to convert it to a quadratic spline. */
160 static void spline(TAG*tag,plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m)
163 struct qspline q[128];
177 /* fonts use a different approximation than shapes */
178 num = cspline_approximate(&c, q, fontsplinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
179 //num = cspline_approximate(&c, q, 10.0, APPROXIMATE_INFLECTION);
181 num = cspline_approximate(&c, q, splinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
185 moveto(tag,q[t].start);
186 splineto(tag,q[t].control, q[t].end);
196 static void stopFill()
200 swf_ShapeSetStyle(tag,shape,linestyleid,0x8000,0);
201 fillstylechanged = 1;
205 static void startFill()
209 swf_ShapeSetStyle(tag,shape,0x8000,fillstyleid,0);
210 fillstylechanged = 1;
215 /* draw an outline. These are generated by pdf2swf and by t1lib
216 (representing characters). */
217 void drawpath(struct swfoutput*output, SWF_OUTLINE*outline, struct swfmatrix*m, int log)
219 if( tag->id != ST_DEFINESHAPE &&
220 tag->id != ST_DEFINESHAPE2 &&
221 tag->id != ST_DEFINESHAPE3)
223 msg("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
227 double lastx=0,lasty=0;
228 double firstx=0,firsty=0;
233 x += (outline->dest.x/(float)0xffff);
234 y += (outline->dest.y/(float)0xffff);
235 if(outline->type == SWF_PATHTYPE_MOVE)
237 if(!init && fill && output->drawmode != DRAWMODE_EOFILL && !ignoredraworder) {
238 /* drawmode=FILL (not EOFILL) means that
239 seperate shapes do not cancel each other out.
240 On SWF side, we need to start a new shape for each
241 closed polygon, because SWF only knows EOFILL.
248 if(((int)(lastx*20) != (int)(firstx*20) ||
249 (int)(lasty*20) != (int)(firsty*20)) &&
258 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
259 line(tag, p0, p1, m);
265 else if(outline->type == SWF_PATHTYPE_LINE)
273 if(log) printf("line: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
276 else if(outline->type == SWF_PATHTYPE_BEZIER)
282 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
285 p1.x=o2->C.x/(float)0xffff+lastx;
286 p1.y=o2->C.y/(float)0xffff+lasty;
287 p2.x=o2->B.x/(float)0xffff+lastx;
288 p2.y=o2->B.y/(float)0xffff+lasty;
291 if(log) printf("spline: %f,%f -> %f,%f\n",p3.x,p3.y,p0.x,p0.y);
292 spline(tag,p0,p1,p2,p3,m);
295 msg("<error> drawpath: unknown outline type:%d\n", outline->type);
299 outline = outline->link;
301 if(((int)(lastx*20) != (int)(firstx*20) ||
302 (int)(lasty*20) != (int)(firsty*20)) &&
311 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
312 line(tag, p0, p1, m);
316 plotxy getPivot(SWF_OUTLINE*outline, int dir, double line_width, int end, int trytwo)
318 SWF_PATHPOINT next, next2;
319 double xv=0,yv=0, xv2=0, yv2=0;
324 if(outline->type == SWF_PATHTYPE_LINE) {
325 next = outline->dest;
327 next = ((SWF_BEZIERSEGMENT*)outline)->B;
328 if(next.x==0 && next.y==0) {
329 next = ((SWF_BEZIERSEGMENT*)outline)->C;
331 if(next.x==0 && next.y==0) {
332 next = ((SWF_BEZIERSEGMENT*)outline)->dest;
336 if(trytwo && outline->last && outline->last->type != SWF_PATHTYPE_MOVE) {
337 if(outline->type == SWF_PATHTYPE_LINE) {
338 next2 = outline->last->dest;
340 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)(outline->last))->C;
341 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)(outline->last))->B;
342 next2.x = outline->last->dest.x - c.x;
343 next2.y = outline->last->dest.y - c.y;
344 if(next2.x==0 && next2.y==0) {
345 next2.x = outline->last->dest.x - b.x;
346 next2.y = outline->last->dest.y - b.y;
348 if(next2.x==0 && next2.y==0) {
349 next2.x = outline->last->dest.x;
350 next2.y = outline->last->dest.y;
356 if(outline->type == SWF_PATHTYPE_LINE) {
357 next = outline->dest;
359 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)outline)->C;
360 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)outline)->B;
361 next.x = outline->dest.x - c.x;
362 next.y = outline->dest.y - c.y;
363 if(next.x==0 && next.y==0) {
364 next.x = outline->dest.x - b.x;
365 next.y = outline->dest.y - b.y;
367 if(next.x==0 && next.y==0) {
368 next.x = outline->dest.x;
369 next.y = outline->dest.y;
373 if(trytwo && outline->link && outline->link->type != SWF_PATHTYPE_MOVE) {
374 if(outline->type == SWF_PATHTYPE_LINE) {
375 next2 = outline->link->dest;
377 next2 = ((SWF_BEZIERSEGMENT*)(outline->link))->B;
378 if(next2.x==0 && next2.y==0) {
379 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->C;
381 if(next2.x==0 && next2.y==0) {
382 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->dest;
390 xv = next.y/(float)0xffff;
391 yv = -next.x/(float)0xffff;
393 xv = -next.y/(float)0xffff;
394 yv = next.x/(float)0xffff;
397 double r = (line_width/2)/sqrt(xv*xv+yv*yv);
403 xv2 = next2.y/(float)0xffff;
404 yv2 = -next2.x/(float)0xffff;
406 xv2 = -next2.y/(float)0xffff;
407 yv2 = next2.x/(float)0xffff;
410 double r2 = (line_width/2)/sqrt(xv2*xv2+yv2*yv2);
415 double r3 = (line_width/2)/sqrt(xv*xv+yv*yv);
425 void drawShortPath(struct swfoutput*output, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline)
427 double lastx=x, lasty=y;
428 while (outline && outline->type != SWF_PATHTYPE_MOVE)
430 x += (outline->dest.x/(float)0xffff);
431 y += (outline->dest.y/(float)0xffff);
433 if(outline->type == SWF_PATHTYPE_LINE)
440 line(tag, p0, p1, m);
442 else if(outline->type == SWF_PATHTYPE_BEZIER)
445 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
448 p1.x=o2->C.x/(float)0xffff+lastx;
449 p1.y=o2->C.y/(float)0xffff+lasty;
450 p2.x=o2->B.x/(float)0xffff+lastx;
451 p2.y=o2->B.y/(float)0xffff+lasty;
454 spline(tag,p0,p1,p2,p3,m);
458 outline = outline->link;
462 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)
467 if(line_cap == LINE_CAP_BUTT || line_cap == LINE_CAP_SQUARE) {
470 SWF_OUTLINE *last, *tmp=outline;
471 plotxy s,e,p0,p1,p2,p3,m0,m1,m2,m3;
477 while(tmp && tmp->type != SWF_PATHTYPE_MOVE) {
479 lx += (tmp->dest.x/(float)0xffff);
480 ly += (tmp->dest.y/(float)0xffff);
483 s = getPivot(outline, 0, line_width, 0, 0);
484 e = getPivot(last, 0, line_width, 1, 0);
486 if(line_cap == LINE_CAP_BUTT) {
487 /* make the clipping rectangle slighly bigger
488 than the line ending, so that it get's clipped
498 p2.x = x2 - s.y - s.x*ee;
499 p2.y = y2 + s.x - s.y*ee;
500 p3.x = x2 - s.y + s.x*ee;
501 p3.y = y2 + s.x + s.y*ee;
506 m2.x = lx + e.y - e.x*ee;
507 m2.y = ly - e.x - e.y*ee;
508 m3.x = lx + e.y + e.x*ee;
509 m3.y = ly - e.x + e.y*ee;
511 for(nr=0;nr<2;nr++) {
513 struct plotxy q0,q1,q2,q3,q4,q5;
515 if(line_cap == LINE_CAP_BUTT) {
518 q1.x = sizex; q1.y = 0;
519 q2.x = sizex; q2.y = sizey;
520 q3.x = 0; q3.y = sizey;
522 q0.x = sizex; q0.y = sizey;
523 q1.x = 0; q1.y = sizey;
525 q3.x = sizex; q3.y = 0;
539 line(tag, p0, p1, m);
540 line(tag, p1, p2, m);
541 line(tag, p2, p3, m);
542 line(tag, p3, p0, m);
544 if(line_cap == LINE_CAP_BUTT) {
546 swf_ShapeSetEnd(tag);
547 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
548 swf_ObjectPlaceClip(tag,shapeid,depth,NULL,NULL,NULL,depth+2-nr);
562 drawShortPath(output,x,y,m,outline);
564 if(line_cap == LINE_CAP_BUTT) {
570 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)
572 plotxy d1,d2,p1,p2,p3,p4;
574 d1.x = (outline->dest.x/(float)0xffff);
575 d1.y = (outline->dest.y/(float)0xffff);
576 d2 = getPivot(outline, 0, line_width, 0, 0);
578 assert(line_cap != LINE_CAP_ROUND);
579 if(line_cap == LINE_CAP_SQUARE) {
588 p2.x = x + d2.x + d1.x;
589 p2.y = y + d2.y + d1.y;
590 p3.x = x - d2.x + d1.x;
591 p3.y = y - d2.y + d1.y;
601 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)
603 SWF_OUTLINE*tmp=outline;
609 drawT1toRect(output, x, y, m,outline, num, line_cap, line_join, line_width);
611 while(tmp->link && tmp->link->type!=SWF_PATHTYPE_MOVE) {
612 xx += (tmp->dest.x/(float)0xffff);
613 yy += (tmp->dest.y/(float)0xffff);
617 assert(tmp->type == SWF_PATHTYPE_LINE);
618 assert(outline->type == SWF_PATHTYPE_LINE);
622 if(outline->link == tmp) {
623 /* the two straight line segments (which are everything we
624 need to draw) are very likely to overlap. To avoid that
625 they cancel each other out at the end points, start a new
626 shape for the second one */
627 endshape();startshape(output);
631 drawT1toRect(output, xx, yy, m, tmp, num, line_cap, line_join, line_width);
633 if(outline->link != tmp)
637 tmp->type = SWF_PATHTYPE_MOVE;
638 x += (outline->dest.x/(float)0xffff);
639 y += (outline->dest.y/(float)0xffff);
640 outline = outline->link;
641 drawShortPath(output, x, y, m, outline);
649 static int t1len(SWF_OUTLINE*line)
652 while(line && line->type != SWF_PATHTYPE_MOVE) {
659 static float t1linelen(SWF_OUTLINE*line)
662 x = (line->dest.x/(float)0xffff);
663 y = (line->dest.y/(float)0xffff);
664 return sqrt(x*x+y*y);
667 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)
669 if( tag->id != ST_DEFINESHAPE &&
670 tag->id != ST_DEFINESHAPE2 &&
671 tag->id != ST_DEFINESHAPE3) {
672 msg("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
677 double lastx=0,lasty=0;
680 SWF_OUTLINE*tmp = outline, *last = 0;
685 x += (tmp->dest.x/(float)0xffff);
686 y += (tmp->dest.y/(float)0xffff);
688 if(!tmp || tmp->type == SWF_PATHTYPE_MOVE) {
690 if(last->type == SWF_PATHTYPE_LINE && t1linelen(last)>line_width*2 &&
691 lastwasline && line_cap != LINE_CAP_ROUND)
692 drawShortPathWithStraightEnds(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
694 drawShortPathWithEnds(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
708 if(tmp && tmp->type == SWF_PATHTYPE_LINE && t1linelen(tmp)>line_width*2)
714 tmp->link->last = tmp; // make sure list is properly linked in both directions
719 static inline int colorcompare(RGBA*a,RGBA*b)
731 static const int CHARDATAMAX = 8192;
739 } chardata[CHARDATAMAX];
742 static void putcharacters(TAG*tag)
747 color.r = chardata[0].color.r^255;
756 int charadvance[128];
759 int glyphbits=1; //TODO: can this be zero?
762 if(tag->id != ST_DEFINETEXT &&
763 tag->id != ST_DEFINETEXT2) {
764 msg("<error> internal error: putcharacters needs an text tag, not %d\n",tag->id);
768 msg("<warning> putcharacters called with zero characters");
771 for(pass = 0; pass < 2; pass++)
781 advancebits++; // add sign bit
782 swf_SetU8(tag, glyphbits);
783 swf_SetU8(tag, advancebits);
786 for(t=0;t<=chardatapos;t++)
788 if(lastfontid != chardata[t].fontid ||
789 lastx!=chardata[t].x ||
790 lasty!=chardata[t].y ||
791 !colorcompare(&color, &chardata[t].color) ||
793 lastsize != chardata[t].size ||
796 if(charstorepos && pass==0)
799 for(s=0;s<charstorepos;s++)
801 while(charids[s]>=(1<<glyphbits))
803 while(charadvance[s]>=(1<<advancebits))
807 if(charstorepos && pass==1)
809 tag->writeBit = 0; // Q&D
810 swf_SetBits(tag, 0, 1); // GLYPH Record
811 swf_SetBits(tag, charstorepos, 7); // number of glyphs
813 for(s=0;s<charstorepos;s++)
815 swf_SetBits(tag, charids[s], glyphbits);
816 swf_SetBits(tag, charadvance[s], advancebits);
821 if(pass == 1 && t<chardatapos)
827 if(lastx != chardata[t].x ||
828 lasty != chardata[t].y)
830 newx = chardata[t].x;
831 newy = chardata[t].y;
837 if(!colorcompare(&color, &chardata[t].color))
839 color = chardata[t].color;
842 font.id = chardata[t].fontid;
843 if(lastfontid != chardata[t].fontid || lastsize != chardata[t].size)
846 tag->writeBit = 0; // Q&D
847 swf_TextSetInfoRecord(tag, newfont, chardata[t].size, newcolor, newx,newy);
850 lastfontid = chardata[t].fontid;
851 lastx = chardata[t].x;
852 lasty = chardata[t].y;
853 lastsize = chardata[t].size;
860 int nextt = t==chardatapos-1?t:t+1;
861 int rel = chardata[nextt].x-chardata[t].x;
862 if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) {
864 lastx=chardata[nextt].x;
870 charids[charstorepos] = chardata[t].charid;
871 charadvance[charstorepos] = advance;
878 static void putcharacter(struct swfoutput*obj, int fontid, int charid,
879 int x,int y, int size)
881 if(chardatapos == CHARDATAMAX)
883 msg("<warning> Character buffer too small. SWF will be slightly bigger");
887 chardata[chardatapos].fontid = fontid;
888 chardata[chardatapos].charid = charid;
889 chardata[chardatapos].x = x;
890 chardata[chardatapos].y = y;
891 chardata[chardatapos].color = obj->fillrgb;
892 chardata[chardatapos].size = size;
902 /* process a character. */
903 static int drawchar(struct swfoutput*obj, SWFFONT *swffont, char*character, int charnr, int u, swfmatrix*m)
906 if(m->m12!=0 || m->m21!=0)
912 msg("<warning> Font is NULL");
917 msg("<verbose> Non diagonal font matrix: %f %f", m->m11, m->m21);
918 msg("<verbose> | %f %f", m->m12, m->m22);
921 //if(usefonts && ! drawonlyshapes)
924 int charid = getCharID(swffont, charnr, character, u);
927 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
928 FIXNULL(character),charnr, u, FIXNULL((char*)swffont->name), swffont->numchars);
929 /*fontlist_t*it = fontlist;
931 msg("<warning> Font history: %s [%d]", it->swffont->name, getCharID(it->swffont, charnr, character, u));
942 putcharacter(obj, swffont->id, charid,(int)(m->m13*20),(int)(m->m23*20),
944 swf_FontUseGlyph(swffont, charid);
949 SWF_OUTLINE*outline = font->getOutline(character, charnr);
950 char* charname = character;
953 msg("<warning> Didn't find character '%s' (%d) in current charset (%s)",
954 FIXNULL(character),charnr,FIXNULL(font->getName()));
973 drawpath(tag, outline, &m2, 0);
978 /* draw a curved polygon. */
979 void swfoutput_drawpath(swfoutput*output, SWF_OUTLINE*outline,
985 /* Multiple polygons in one shape don't overlap correctly,
986 so we better start a new shape here if the polygon is filled
988 if(shapeid>=0 && fill && !ignoredraworder) {
1000 drawpath(output, outline,m, 0);
1003 void swfoutput_drawpath2poly(struct swfoutput*output, SWF_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
1013 drawpath2poly(output, outline, m, 0, line_join, line_cap, line_width, miter_limit);
1016 int getCharID(SWFFONT *font, int charnr, char *charname, int u)
1020 for(t=0;t<font->numchars;t++) {
1021 if(font->glyphnames[t] && !strcmp(font->glyphnames[t],charname)) {
1025 /* if we didn't find the character, maybe
1026 we can find the capitalized version */
1027 for(t=0;t<font->numchars;t++) {
1028 if(font->glyphnames[t] && !strcasecmp(font->glyphnames[t],charname)) {
1035 if(u>=font->maxascii)
1036 msg("<debug> u=%d, font->maxascii=%d",u,font->maxascii);
1038 msg("<debug> u=%d, font->maxascii=%d ascci2glyph[%d]=%d",u,font->maxascii,u,font->ascii2glyph[u]);
1040 /* try to use the unicode id */
1041 if(u>=0 && u<font->maxascii && font->ascii2glyph[u]>=0) {
1042 return font->ascii2glyph[u];
1046 if(charnr>=0 && charnr<font->numchars) {
1050 /* the following is technically wrong, and only works if the font encoding
1051 is US-ASCII based. It's needed for fonts which return broken unicode
1053 /* if(charnr>=0 && charnr<font->maxascii && font->ascii2glyph[charnr]>=0) {
1054 return font->ascii2glyph[charnr];
1061 /* set's the t1 font index of the font to use for swfoutput_drawchar(). */
1062 void swfoutput_setfont(struct swfoutput*obj, char*fontid, char*filename)
1064 fontlist_t*last=0,*iterator;
1066 msg("<error> No fontid");
1070 if(obj->swffont && obj->swffont->name && !strcmp((char*)obj->swffont->name,fontid))
1073 iterator = fontlist;
1075 if(!strcmp((char*)iterator->swffont->name,fontid)) {
1076 obj->swffont = iterator->swffont;
1080 iterator = iterator->next;
1084 msg("<error> No filename given for font- internal error?");
1088 swf_SetLoadFontParameters(0,/*skip unused*/0,/*full unicode*/1);
1089 SWFFONT*swffont = swf_LoadFont(filename);
1092 msg("<warning> Couldn't load font %s (%s)", fontid, filename);
1093 swffont = swf_LoadFont(0);
1096 swf_FontSetID(swffont, ++currentswfid);
1098 if(screenloglevel >= LOGLEVEL_DEBUG) {
1099 // print font information
1100 msg("<debug> Font %s (%s)",swffont->name, filename);
1101 msg("<debug> | ID: %d", swffont->id);
1102 msg("<debug> | Version: %d", swffont->version);
1103 msg("<debug> | Name: %s", fontid);
1104 msg("<debug> | Numchars: %d", swffont->numchars);
1105 msg("<debug> | Maxascii: %d", swffont->maxascii);
1106 msg("<debug> | Style: %d", swffont->style);
1107 msg("<debug> | Encoding: %d", swffont->encoding);
1108 for(int iii=0; iii<swffont->numchars;iii++) {
1109 msg("<debug> | Glyph %d) name=%s, unicode=%d\n", iii, swffont->glyphnames[iii], swffont->glyph2ascii[iii]);
1113 /* set the font name to the ID we use here */
1114 if(swffont->name) free(swffont->name);
1115 swffont->name = (U8*)strdup(fontid);
1117 iterator = new fontlist_t;
1118 iterator->swffont = swffont;
1122 last->next = iterator;
1124 fontlist = iterator;
1126 obj->swffont = swffont;
1129 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1131 fontlist_t *iterator = fontlist;
1133 if(!strcmp((char*)iterator->swffont->name,fontid))
1135 iterator = iterator->next;
1140 /* set's the matrix which is to be applied to characters drawn by
1141 swfoutput_drawchar() */
1142 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1143 double m21,double m22)
1145 if(obj->fontm11 == m11 &&
1146 obj->fontm12 == m12 &&
1147 obj->fontm21 == m21 &&
1148 obj->fontm22 == m22)
1158 /* draws a character at x,y. */
1159 int swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr, int u)
1162 m.m11 = obj->fontm11;
1163 m.m12 = obj->fontm12;
1164 m.m21 = obj->fontm21;
1165 m.m22 = obj->fontm22;
1168 return drawchar(obj, obj->swffont, character, charnr, u, &m);
1171 /* initialize the swf writer */
1172 void swfoutput_init(struct swfoutput* obj, char*_filename, int x1, int y1, int x2, int y2)
1176 memset(obj, 0, sizeof(struct swfoutput));
1177 filename = _filename;
1181 msg("<verbose> initializing swf output for size %d*%d\n", sizex,sizey);
1186 memset(&swf,0x00,sizeof(SWF));
1188 swf.fileVersion = flashversion;
1189 swf.frameRate = 0x0040; // 1 frame per 4 seconds
1190 swf.movieSize.xmin = 20*x1;
1191 swf.movieSize.ymin = 20*y1;
1192 swf.movieSize.xmax = 20*x2;
1193 swf.movieSize.ymax = 20*y2;
1197 swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1199 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1200 swf_SetRGB(tag,&rgb);
1202 if(1)/* add white rectangle */
1207 int shapeid = ++currentswfid;
1212 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
1214 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1215 swf_SetU16(tag,shapeid);
1216 swf_SetRect(tag,&r);
1217 swf_SetShapeHeader(tag,s);
1218 swf_ShapeSetAll(tag,s,x1*20,y1*20,ls1,fs1,0);
1219 swf_ShapeSetLine(tag,s,20*(x2-x1),0);
1220 swf_ShapeSetLine(tag,s,0,20*(y2-y1));
1221 swf_ShapeSetLine(tag,s,20*(x1-x2),0);
1222 swf_ShapeSetLine(tag,s,0,20*(y1-y2));
1223 swf_ShapeSetEnd(tag);
1225 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1226 swf_ObjectPlace(tag,shapeid,depth++,0,0,0);
1227 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1228 swf_ObjectPlaceClip(tag,shapeid,depth++,0,0,0,65535);
1232 tag = swf_InsertTag(tag, ST_PROTECT);
1237 void swfoutput_setprotected() //write PROTECT tag
1242 static void startshape(struct swfoutput*obj)
1250 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1252 swf_ShapeNew(&shape);
1253 linestyleid = swf_ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1254 rgb.r = obj->fillrgb.r;
1255 rgb.g = obj->fillrgb.g;
1256 rgb.b = obj->fillrgb.b;
1257 fillstyleid = swf_ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1259 shapeid = ++currentswfid;
1260 swf_SetU16(tag,shapeid); // ID
1267 swf_SetRect(tag,&r);
1269 swf_SetShapeStyles(tag,shape);
1270 swf_ShapeCountBits(shape,NULL,NULL);
1271 swf_SetShapeBits(tag,shape);
1273 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,linestyleid,0,0);
1274 swflastx=swflasty=0;
1279 static void starttext(struct swfoutput*obj)
1285 tag = swf_InsertTag(tag,ST_DEFINETEXT);
1286 textid = ++currentswfid;
1287 swf_SetU16(tag, textid);
1294 swf_SetRect(tag,&r);
1303 swf_SetMatrix(tag,&m);
1304 swflastx=swflasty=0;
1307 static void endshape()
1311 swf_ShapeSetEnd(tag);
1314 // delete the tag again, we didn't do anything
1317 swf_DeleteTag(todel);
1319 /* TODO: fix bounding box */
1320 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1321 swf_ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL);
1326 static void endtext()
1332 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1333 swf_ObjectPlace(tag,textid,/*depth*/depth++,NULL,NULL,NULL);
1337 static void endpage(struct swfoutput*obj)
1344 swfoutput_endclip(obj);
1348 atag = action_Stop(atag);
1349 atag = action_End(atag);
1350 tag = swf_InsertTag(tag,ST_DOACTION);
1351 swf_ActionSet(tag,atag);
1353 tag = swf_InsertTag(tag,ST_SHOWFRAME);
1356 void swfoutput_newpage(struct swfoutput*obj)
1360 for(depth--;depth>=startdepth;depth--) {
1361 tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1362 swf_SetU16(tag,depth);
1368 /* Perform cleaning up, complete the swf, and write it out. */
1369 void swfoutput_destroy(struct swfoutput* obj)
1372 fontlist_t *tmp,*iterator = fontlist;
1374 TAG*mtag = swf.firstTag;
1375 if(iterator->swffont) {
1376 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1377 /*if(!storeallcharacters)
1378 swf_FontReduce(iterator->swffont);*/
1379 swf_FontSetDefine2(mtag, iterator->swffont);
1380 swf_FontFree(iterator->swffont);
1384 iterator = iterator->next;
1391 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1396 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1400 tag = swf_InsertTag(tag,ST_END);
1402 if(enablezlib || flashversion>=6) {
1403 if FAILED(swf_WriteSWC(fi,&swf))
1404 msg("<error> WriteSWC() failed.\n");
1406 if FAILED(swf_WriteSWF(fi,&swf))
1407 msg("<error> WriteSWF() failed.\n");
1412 msg("<notice> SWF written\n");
1415 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1417 obj->drawmode = mode;
1418 if(mode == DRAWMODE_FILL)
1420 else if(mode == DRAWMODE_EOFILL)
1422 else if(mode == DRAWMODE_STROKE)
1424 else if(mode == DRAWMODE_CLIP)
1426 else if(mode == DRAWMODE_EOCLIP)
1430 void swfoutput_setfillcolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1432 if(obj->fillrgb.r == r &&
1433 obj->fillrgb.g == g &&
1434 obj->fillrgb.b == b &&
1435 obj->fillrgb.a == a) return;
1445 void swfoutput_setstrokecolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a)
1447 if(obj->strokergb.r == r &&
1448 obj->strokergb.g == g &&
1449 obj->strokergb.b == b &&
1450 obj->strokergb.a == a) return;
1454 obj->strokergb.r = r;
1455 obj->strokergb.g = g;
1456 obj->strokergb.b = b;
1457 obj->strokergb.a = a;
1460 void swfoutput_setlinewidth(struct swfoutput*obj, double linewidth)
1462 if(obj->linewidth == (u16)(linewidth*20))
1467 obj->linewidth = (u16)(linewidth*20);
1471 void swfoutput_startclip(swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m)
1480 msg("<warning> Too many clip levels.");
1485 int olddrawmode = obj->drawmode;
1486 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1487 swfoutput_drawpath(obj, outline, m);
1488 swf_ShapeSetEnd(tag);
1489 swfoutput_setdrawmode(obj, olddrawmode);
1491 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1492 cliptags[clippos] = tag;
1493 clipshapes[clippos] = shapeid;
1494 clipdepths[clippos] = depth++;
1499 void swfoutput_endclip(swfoutput*obj)
1507 msg("<error> Invalid end of clipping region");
1511 swf_ObjectPlaceClip(cliptags[clippos],clipshapes[clippos],clipdepths[clippos],NULL,NULL,NULL,depth++);
1514 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1516 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1519 if(!strncmp("http://pdf2swf:", url, 15)) {
1520 char*tmp = strdup(url);
1521 int l = strlen(tmp);
1524 swfoutput_namedlink(obj, tmp+15, points);
1535 actions = action_GetUrl(0, url, "_parent");
1537 actions = action_GetUrl(0, url, "_this");
1538 actions = action_End(actions);
1540 drawlink(obj, actions, 0, points,0);
1542 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
1551 actions = action_GotoFrame(0, page);
1552 actions = action_End(actions);
1554 drawlink(obj, actions, 0, points,0);
1557 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
1558 of the viewer objects, like subtitles, index elements etc.
1560 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
1562 ActionTAG *actions1,*actions2;
1563 char*tmp = strdup(name);
1571 if(!strncmp(tmp, "call:", 5))
1573 char*x = strchr(&tmp[5], ':');
1575 actions1 = action_PushInt(0, 0); //number of parameters (0)
1576 actions1 = action_PushString(actions1, &tmp[5]); //function name
1577 actions1 = action_CallFunction(actions1);
1580 actions1 = action_PushString(0, x+1); //parameter
1581 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
1582 actions1 = action_PushString(actions1, &tmp[5]); //function name
1583 actions1 = action_CallFunction(actions1);
1585 actions2 = action_End(0);
1590 actions1 = action_PushString(0, "/:subtitle");
1591 actions1 = action_PushString(actions1, name);
1592 actions1 = action_SetVariable(actions1);
1593 actions1 = action_End(actions1);
1595 actions2 = action_PushString(0, "/:subtitle");
1596 actions2 = action_PushString(actions2, "");
1597 actions2 = action_SetVariable(actions2);
1598 actions2 = action_End(actions2);
1601 drawlink(obj, actions1, actions2, points,mouseover);
1603 swf_ActionFree(actions1);
1604 swf_ActionFree(actions2);
1608 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
1614 struct plotxy p1,p2,p3,p4;
1618 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
1622 int buttonid = ++currentswfid;
1625 if(points[t].x>xmax) xmax=points[t].x;
1626 if(points[t].y>ymax) ymax=points[t].y;
1627 if(points[t].x<xmin) xmin=points[t].x;
1628 if(points[t].y<ymin) ymin=points[t].y;
1631 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
1632 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
1634 /* the following code subtracts the upper left edge from all coordinates,
1635 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
1636 Necessary for preprocessing with swfcombine. */
1637 posx = xmin; posy = ymin;
1638 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
1639 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
1640 xmin -= posx; ymin -= posy;
1641 xmax -= posx; ymax -= posy;
1644 myshapeid = ++currentswfid;
1645 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1646 swf_ShapeNew(&shape);
1647 rgb.r = rgb.b = rgb.a = rgb.g = 0;
1648 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1649 swf_SetU16(tag, myshapeid);
1650 r.xmin = (int)(xmin*20);
1651 r.ymin = (int)(ymin*20);
1652 r.xmax = (int)(xmax*20);
1653 r.ymax = (int)(ymax*20);
1654 swf_SetRect(tag,&r);
1655 swf_SetShapeStyles(tag,shape);
1656 swf_ShapeCountBits(shape,NULL,NULL);
1657 swf_SetShapeBits(tag,shape);
1658 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1659 swflastx = swflasty = 0;
1665 swf_ShapeSetEnd(tag);
1668 myshapeid2 = ++currentswfid;
1669 tag = swf_InsertTag(tag,ST_DEFINESHAPE3);
1670 swf_ShapeNew(&shape);
1671 rgb.r = rgb.b = rgb.a = rgb.g = 255;
1673 fsid = swf_ShapeAddSolidFillStyle(shape,&rgb);
1674 swf_SetU16(tag, myshapeid2);
1675 r.xmin = (int)(xmin*20);
1676 r.ymin = (int)(ymin*20);
1677 r.xmax = (int)(xmax*20);
1678 r.ymax = (int)(ymax*20);
1679 swf_SetRect(tag,&r);
1680 swf_SetShapeStyles(tag,shape);
1681 swf_ShapeCountBits(shape,NULL,NULL);
1682 swf_SetShapeBits(tag,shape);
1683 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,0,fsid,0);
1684 swflastx = swflasty = 0;
1690 swf_ShapeSetEnd(tag);
1694 tag = swf_InsertTag(tag,ST_DEFINEBUTTON);
1695 swf_SetU16(tag,buttonid); //id
1696 swf_ButtonSetFlags(tag, 0); //menu=no
1697 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1698 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1699 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1700 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1702 swf_ActionSet(tag,actions1);
1707 tag = swf_InsertTag(tag,ST_DEFINEBUTTON2);
1708 swf_SetU16(tag,buttonid); //id
1709 swf_ButtonSetFlags(tag, 0); //menu=no
1710 swf_ButtonSetRecord(tag,0x01,myshapeid,depth,0,0);
1711 swf_ButtonSetRecord(tag,0x02,myshapeid2,depth,0,0);
1712 swf_ButtonSetRecord(tag,0x04,myshapeid2,depth,0,0);
1713 swf_ButtonSetRecord(tag,0x08,myshapeid,depth,0,0);
1714 swf_SetU8(tag,0); // end of button records
1715 swf_ButtonSetCondition(tag, BC_IDLE_OVERUP);
1716 swf_ActionSet(tag,actions1);
1718 swf_ButtonSetCondition(tag, BC_OVERUP_IDLE);
1719 swf_ActionSet(tag,actions2);
1721 swf_ButtonPostProcess(tag, 2);
1724 swf_ButtonPostProcess(tag, 1);
1728 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1730 if(posx!=0 || posy!=0) {
1732 swf_GetMatrix(0,&m);
1733 m.tx = (int)(posx*20);
1734 m.ty = (int)(posy*20);
1735 swf_ObjectPlace(tag, buttonid, depth++,&m,0,0);
1738 swf_ObjectPlace(tag, buttonid, depth++,0,0,0);
1742 static void drawimage(struct swfoutput*obj, int bitid, int sizex,int sizey,
1743 double x1,double y1,
1744 double x2,double y2,
1745 double x3,double y3,
1746 double x4,double y4)
1752 struct plotxy p1,p2,p3,p4;
1754 double xmax=x1,ymax=y1,xmin=x1,ymin=y1;
1755 if(x2>xmax) xmax=x2;
1756 if(y2>ymax) ymax=y2;
1757 if(x2<xmin) xmin=x2;
1758 if(y2<ymin) ymin=y2;
1759 if(x3>xmax) xmax=x3;
1760 if(y3>ymax) ymax=y3;
1761 if(x3<xmin) xmin=x3;
1762 if(y3<ymin) ymin=y3;
1763 if(x4>xmax) xmax=x4;
1764 if(y4>ymax) ymax=y4;
1765 if(x4<xmin) xmin=x4;
1766 if(y4<ymin) ymin=y4;
1772 {p1.x = (int)(p1.x*20)/20.0;
1773 p1.y = (int)(p1.y*20)/20.0;
1774 p2.x = (int)(p2.x*20)/20.0;
1775 p2.y = (int)(p2.y*20)/20.0;
1776 p3.x = (int)(p3.x*20)/20.0;
1777 p3.y = (int)(p3.y*20)/20.0;
1778 p4.x = (int)(p4.x*20)/20.0;
1779 p4.y = (int)(p4.y*20)/20.0;}
1782 m.sx = (int)(65536*20*(p4.x-p1.x)/sizex);
1783 m.r1 = -(int)(65536*20*(p4.y-p1.y)/sizex);
1784 m.r0 = (int)(65536*20*(p1.x-p2.x)/sizey);
1785 m.sy = -(int)(65536*20*(p1.y-p2.y)/sizey);
1787 m.tx = (int)(p1.x*20);
1788 m.ty = (int)(p1.y*20);
1791 myshapeid = ++currentswfid;
1792 tag = swf_InsertTag(tag,ST_DEFINESHAPE);
1793 swf_ShapeNew(&shape);
1794 //lsid = ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb);
1795 //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb);
1796 fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
1797 swf_SetU16(tag, myshapeid);
1798 r.xmin = (int)(xmin*20);
1799 r.ymin = (int)(ymin*20);
1800 r.xmax = (int)(xmax*20);
1801 r.ymax = (int)(ymax*20);
1802 swf_SetRect(tag,&r);
1803 swf_SetShapeStyles(tag,shape);
1804 swf_ShapeCountBits(shape,NULL,NULL);
1805 swf_SetShapeBits(tag,shape);
1806 swf_ShapeSetAll(tag,shape,/*x*/0,/*y*/0,lsid,fsid,0);
1807 swflastx = swflasty = 0;
1814 ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20));
1815 ShapeSetLine (tag, shape, (int)(x1*20);
1816 ShapeSetLine (tag, shape, x*20,0);
1817 ShapeSetLine (tag, shape, 0,-y*20);
1818 ShapeSetLine (tag, shape, -x*20,0);*/
1819 swf_ShapeSetEnd(tag);
1822 tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1823 swf_ObjectPlace(tag,myshapeid,/*depth*/depth++,NULL,NULL,NULL);
1826 int swfoutput_drawimagejpeg_old(struct swfoutput*obj, char*filename, int sizex,int sizey,
1827 double x1,double y1,
1828 double x2,double y2,
1829 double x3,double y3,
1830 double x4,double y4)
1838 int bitid = ++currentswfid;
1840 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
1841 swf_SetU16(tag, bitid);
1842 if(swf_SetJPEGBits(tag, filename, jpegquality)<0) {
1848 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1852 int swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
1853 double x1,double y1,
1854 double x2,double y2,
1855 double x3,double y3,
1856 double x4,double y4)
1866 int bitid = ++currentswfid;
1868 tag = swf_InsertTag(tag,ST_DEFINEBITSJPEG2);
1869 swf_SetU16(tag, bitid);
1870 swf_SetJPEGBits2(tag,sizex,sizey,mem,jpegquality);
1871 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1875 int swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
1876 double x1,double y1,
1877 double x2,double y2,
1878 double x3,double y3,
1879 double x4,double y4)
1887 int bitid = ++currentswfid;
1889 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS);
1890 swf_SetU16(tag, bitid);
1891 if(swf_SetLosslessBits(tag,sizex,sizey,mem, BMF_32BIT)<0) {
1897 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1901 int swfoutput_drawimagelosslessN(struct swfoutput*obj, U8*mem, RGBA*pal, int sizex,int sizey,
1902 double x1,double y1,
1903 double x2,double y2,
1904 double x3,double y3,
1905 double x4,double y4, int n)
1916 /* SWF expects scanlines to be 4 byte aligned */
1919 mem2 = (U8*)malloc(BYTES_PER_SCANLINE(sizex)*sizey);
1921 for(y=0;y<sizey;y++)
1923 for(x=0;x<sizex;x++)
1924 *ptr++ = mem[y*sizex+x];
1925 ptr+= BYTES_PER_SCANLINE(sizex)-sizex;
1930 int bitid = ++currentswfid;
1932 tag = swf_InsertTag(tag,ST_DEFINEBITSLOSSLESS2);
1933 swf_SetU16(tag, bitid);
1934 if(swf_SetLosslessBitsIndexed(tag,sizex,sizey,mem, pal, n)<0) {
1942 drawimage(obj, bitid, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);
1946 void swfoutput_drawimageagain(struct swfoutput*obj, int id, int sizex,int sizey,
1947 double x1,double y1,
1948 double x2,double y2,
1949 double x3,double y3,
1950 double x4,double y4)
1958 drawimage(obj, id, sizex, sizey, x1,y1,x2,y2,x3,y3,x4,y4);