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"
38 #include "../lib/gfxdevice.h"
41 #define CHARDATAMAX 8192
45 typedef struct _chardata {
47 int fontid; /* TODO: use a SWFFONT instead */
60 double config_ppmsubpixels=0;
61 double config_jpegsubpixels=0;
62 int config_opennewwindow=0;
63 int config_ignoredraworder=0;
64 int config_drawonlyshapes=0;
65 int config_jpegquality=85;
66 int config_storeallcharacters=0;
67 int config_enablezlib=0;
68 int config_insertstoptag=0;
69 int config_flashversion=5;
70 int config_splinemaxerror=1;
71 int config_fontsplinemaxerror=1;
72 int config_filloverlap=0;
74 float config_minlinewidth=0.05;
76 typedef struct _swfoutput_internal
78 swfoutput*obj; // the swfoutput object where this internal struct resides
117 int pic_height[1024];
123 char fillstylechanged;
125 int jpeg; //next image type
132 chardata_t chardata[CHARDATAMAX];
137 /* during the transition to the gfxdevice interface:
138 a device which uses this swfoutput as target */
141 } swfoutput_internal;
143 void swf_fillbitmap(struct _gfxdevice*driver, gfxline_t*line, gfximage_t*img, gfxmatrix_t*move, gfxcxform_t*cxform);
144 int swf_setparameter(struct _gfxdevice*driver, const char*key, const char*value);
146 static swfoutput_internal* init_internal_struct()
148 swfoutput_internal*i = (swfoutput_internal*)malloc(sizeof(swfoutput_internal));
149 memset(i, 0, sizeof(swfoutput_internal));
170 i->fillstylechanged = 0;
177 i->device.internal = (void*)i;
178 i->device.fillbitmap = swf_fillbitmap;
179 i->device.setparameter = swf_setparameter;
184 static void startshape(struct swfoutput* obj);
185 static void starttext(struct swfoutput* obj);
186 static void endshape(struct swfoutput* obj,int clip);
187 static void endtext(struct swfoutput* obj);
189 // matrix multiplication. changes p0
190 static void transform (plotxy*p0,struct swfmatrix*m)
193 x = m->m11*p0->x+m->m12*p0->y;
194 y = m->m21*p0->x+m->m22*p0->y;
199 // write a move-to command into the swf
200 static int moveto(struct swfoutput*obj, TAG*tag, plotxy p0)
202 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
203 int rx = (int)(p0.x*20);
204 int ry = (int)(p0.y*20);
205 if(rx!=i->swflastx || ry!=i->swflasty || i->fillstylechanged) {
206 swf_ShapeSetMove (tag, i->shape, rx,ry);
207 i->fillstylechanged = 0;
214 static int moveto(struct swfoutput*obj, TAG*tag, float x, float y)
216 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
220 return moveto(obj, tag, p);
222 static void addPointToBBox(struct swfoutput*obj, int px, int py)
224 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
230 swf_ExpandRect(&i->bboxrect, p);
232 swf_ExpandRect3(&i->bboxrect, p, i->linewidth*3/2);
236 // write a line-to command into the swf
237 static void lineto(struct swfoutput*obj, TAG*tag, plotxy p0)
239 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
240 int px = (int)(p0.x*20);
241 int py = (int)(p0.y*20);
242 int rx = (px-i->swflastx);
243 int ry = (py-i->swflasty);
244 /* we can't skip this for rx=0,ry=0, those
246 swf_ShapeSetLine (tag, i->shape, rx,ry);
248 addPointToBBox(obj, i->swflastx,i->swflasty);
249 addPointToBBox(obj, px,py);
255 static void lineto(struct swfoutput*obj, TAG*tag, double x, double y)
263 // write a spline-to command into the swf
264 static void splineto(struct swfoutput*obj, TAG*tag, plotxy control,plotxy end)
266 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
267 int lastlastx = i->swflastx;
268 int lastlasty = i->swflasty;
270 int cx = ((int)(control.x*20)-i->swflastx);
271 int cy = ((int)(control.y*20)-i->swflasty);
274 int ex = ((int)(end.x*20)-i->swflastx);
275 int ey = ((int)(end.y*20)-i->swflasty);
279 if(cx || cy || ex || ey) {
280 swf_ShapeSetCurve(tag, i->shape, cx,cy,ex,ey);
281 addPointToBBox(obj, lastlastx ,lastlasty );
282 addPointToBBox(obj, lastlastx+cx,lastlasty+cy);
283 addPointToBBox(obj, lastlastx+cx+ex,lastlasty+cy+ey);
288 /* write a line, given two points and the transformation
290 static void line(struct swfoutput*obj, TAG*tag, plotxy p0, plotxy p1, struct swfmatrix*m)
294 moveto(obj, tag, p0);
295 lineto(obj, tag, p1);
298 /* write a cubic (!) spline. This involves calling the approximate()
299 function out of spline.cc to convert it to a quadratic spline. */
300 static void spline(struct swfoutput*obj, TAG*tag,plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m)
302 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
304 struct qspline q[128];
318 /* fonts use a different approximation than shapes */
319 num = cspline_approximate(&c, q, config_fontsplinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
320 //num = cspline_approximate(&c, q, 10.0, APPROXIMATE_INFLECTION);
322 num = cspline_approximate(&c, q, config_splinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
326 moveto(obj, tag,q[t].start);
327 splineto(obj, tag,q[t].control, q[t].end);
331 void resetdrawer(struct swfoutput*obj)
333 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
338 static void stopFill(struct swfoutput*obj)
340 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
343 swf_ShapeSetStyle(i->tag,i->shape,i->linestyleid,0x8000,0);
344 i->fillstylechanged = 1;
348 static void startFill(struct swfoutput*obj)
350 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
353 swf_ShapeSetStyle(i->tag,i->shape,0x8000,i->fillstyleid,0);
354 i->fillstylechanged = 1;
359 /* draw an outline. These are generated by pdf2swf and by t1lib
360 (representing characters). */
361 void drawpath(struct swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m, int log)
363 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
364 if( i->tag->id != ST_DEFINESHAPE &&
365 i->tag->id != ST_DEFINESHAPE2 &&
366 i->tag->id != ST_DEFINESHAPE3)
368 msg("<error> internal error: drawpath needs a shape tag, not %d\n",i->tag->id);
372 double lastx=0,lasty=0;
373 double firstx=0,firsty=0;
378 x += (outline->dest.x/(float)0xffff);
379 y += (outline->dest.y/(float)0xffff);
380 if(outline->type == SWF_PATHTYPE_MOVE)
382 //if(!init && fill && obj->drawmode != DRAWMODE_EOFILL && !ignoredraworder) {
383 if(config_filloverlap && !init && i->fill && obj->drawmode != DRAWMODE_EOFILL) {
384 /* drawmode=FILL (not EOFILL) means that
385 seperate shapes do not cancel each other out.
386 On SWF side, we need to start a new shape for each
387 closed polygon, because SWF only knows EOFILL.
394 if(((int)(lastx*20) != (int)(firstx*20) ||
395 (int)(lasty*20) != (int)(firsty*20)) &&
404 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
405 line(obj,i->tag, p0, p1, m);
411 else if(outline->type == SWF_PATHTYPE_LINE)
419 if(log) printf("line: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
420 line(obj,i->tag, p0,p1,m);
422 else if(outline->type == SWF_PATHTYPE_BEZIER)
428 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
431 p1.x=o2->C.x/(float)0xffff+lastx;
432 p1.y=o2->C.y/(float)0xffff+lasty;
433 p2.x=o2->B.x/(float)0xffff+lastx;
434 p2.y=o2->B.y/(float)0xffff+lasty;
437 if(log) printf("spline: %f,%f -> %f,%f\n",p3.x,p3.y,p0.x,p0.y);
438 spline(obj,i->tag,p0,p1,p2,p3,m);
441 msg("<error> drawpath: unknown outline type:%d\n", outline->type);
445 outline = outline->link;
447 if(((int)(lastx*20) != (int)(firstx*20) ||
448 (int)(lasty*20) != (int)(firsty*20)) &&
457 if(log) printf("fix: %f,%f -> %f,%f\n",p0.x,p0.y,p1.x,p1.y);
458 line(obj, i->tag, p0, p1, m);
462 plotxy getPivot(struct swfoutput*obj, SWF_OUTLINE*outline, int dir, double line_width, int end, int trytwo)
464 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
465 SWF_PATHPOINT next, next2;
466 double xv=0,yv=0, xv2=0, yv2=0;
471 if(outline->type == SWF_PATHTYPE_LINE) {
472 next = outline->dest;
474 next = ((SWF_BEZIERSEGMENT*)outline)->B;
475 if(next.x==0 && next.y==0) {
476 next = ((SWF_BEZIERSEGMENT*)outline)->C;
478 if(next.x==0 && next.y==0) {
479 next = ((SWF_BEZIERSEGMENT*)outline)->dest;
483 if(trytwo && outline->last && outline->last->type != SWF_PATHTYPE_MOVE) {
484 if(outline->type == SWF_PATHTYPE_LINE) {
485 next2 = outline->last->dest;
487 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)(outline->last))->C;
488 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)(outline->last))->B;
489 next2.x = outline->last->dest.x - c.x;
490 next2.y = outline->last->dest.y - c.y;
491 if(next2.x==0 && next2.y==0) {
492 next2.x = outline->last->dest.x - b.x;
493 next2.y = outline->last->dest.y - b.y;
495 if(next2.x==0 && next2.y==0) {
496 next2.x = outline->last->dest.x;
497 next2.y = outline->last->dest.y;
503 if(outline->type == SWF_PATHTYPE_LINE) {
504 next = outline->dest;
506 SWF_PATHPOINT c = ((SWF_BEZIERSEGMENT*)outline)->C;
507 SWF_PATHPOINT b = ((SWF_BEZIERSEGMENT*)outline)->B;
508 next.x = outline->dest.x - c.x;
509 next.y = outline->dest.y - c.y;
510 if(next.x==0 && next.y==0) {
511 next.x = outline->dest.x - b.x;
512 next.y = outline->dest.y - b.y;
514 if(next.x==0 && next.y==0) {
515 next.x = outline->dest.x;
516 next.y = outline->dest.y;
520 if(trytwo && outline->link && outline->link->type != SWF_PATHTYPE_MOVE) {
521 if(outline->type == SWF_PATHTYPE_LINE) {
522 next2 = outline->link->dest;
524 next2 = ((SWF_BEZIERSEGMENT*)(outline->link))->B;
525 if(next2.x==0 && next2.y==0) {
526 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->C;
528 if(next2.x==0 && next2.y==0) {
529 next2 = ((SWF_BEZIERSEGMENT*)outline->link)->dest;
537 xv = next.y/(float)0xffff;
538 yv = -next.x/(float)0xffff;
540 xv = -next.y/(float)0xffff;
541 yv = next.x/(float)0xffff;
544 double r = (line_width/2)/sqrt(xv*xv+yv*yv);
550 xv2 = next2.y/(float)0xffff;
551 yv2 = -next2.x/(float)0xffff;
553 xv2 = -next2.y/(float)0xffff;
554 yv2 = next2.x/(float)0xffff;
557 double r2 = (line_width/2)/sqrt(xv2*xv2+yv2*yv2);
562 double r3 = (line_width/2)/sqrt(xv*xv+yv*yv);
572 void drawShortPath(struct swfoutput*obj, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline)
574 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
575 double lastx=x, lasty=y;
576 while (outline && outline->type != SWF_PATHTYPE_MOVE)
578 x += (outline->dest.x/(float)0xffff);
579 y += (outline->dest.y/(float)0xffff);
581 if(outline->type == SWF_PATHTYPE_LINE)
588 line(obj, i->tag, p0, p1, m);
590 else if(outline->type == SWF_PATHTYPE_BEZIER)
593 SWF_BEZIERSEGMENT*o2 = (SWF_BEZIERSEGMENT*)outline;
596 p1.x=o2->C.x/(float)0xffff+lastx;
597 p1.y=o2->C.y/(float)0xffff+lasty;
598 p2.x=o2->B.x/(float)0xffff+lastx;
599 p2.y=o2->B.y/(float)0xffff+lasty;
602 spline(obj, i->tag,p0,p1,p2,p3,m);
606 outline = outline->link;
610 void drawShortPathWithEnds(struct swfoutput*obj, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline, int num, int line_cap, int line_join, double line_width)
612 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
616 if(line_cap == LINE_CAP_BUTT || line_cap == LINE_CAP_SQUARE) {
619 SWF_OUTLINE *last, *tmp=outline;
620 plotxy s,e,p0,p1,p2,p3,m0,m1,m2,m3;
626 while(tmp && tmp->type != SWF_PATHTYPE_MOVE) {
628 lx += (tmp->dest.x/(float)0xffff);
629 ly += (tmp->dest.y/(float)0xffff);
632 s = getPivot(obj, outline, 0, line_width, 0, 0);
633 e = getPivot(obj, last, 0, line_width, 1, 0);
635 if(line_cap == LINE_CAP_BUTT) {
636 /* make the clipping rectangle slighly bigger
637 than the line ending, so that it get's clipped
647 p2.x = x2 - s.y - s.x*ee;
648 p2.y = y2 + s.x - s.y*ee;
649 p3.x = x2 - s.y + s.x*ee;
650 p3.y = y2 + s.x + s.y*ee;
655 m2.x = lx + e.y - e.x*ee;
656 m2.y = ly - e.x - e.y*ee;
657 m3.x = lx + e.y + e.x*ee;
658 m3.y = ly - e.x + e.y*ee;
660 for(nr=0;nr<2;nr++) {
662 struct plotxy q0,q1,q2,q3,q4,q5;
665 if(line_cap == LINE_CAP_BUTT) {
667 /* FIXME: box should be smaller */
669 q1.x = i->max_x; q1.y = 0;
670 q2.x = i->max_x; q2.y = i->max_y;
671 q3.x = 0; q3.y = i->max_y;
673 /* FIXME: box should be smaller */
674 q0.x = i->max_x; q0.y = i->max_y;
675 q1.x = 0; q1.y = i->max_y;
677 q3.x = i->max_x; q3.y = 0;
681 moveto(obj, i->tag, q0);
682 lineto(obj, i->tag, q1);
683 lineto(obj, i->tag, q2);
684 lineto(obj, i->tag, q3);
685 lineto(obj, i->tag, q0);
688 lineto(obj, i->tag, q4);
691 line(obj, i->tag, p0, p1, m);
692 line(obj, i->tag, p1, p2, m);
693 line(obj, i->tag, p2, p3, m);
694 line(obj, i->tag, p3, p0, m);
696 if(line_cap == LINE_CAP_BUTT) {
697 lineto(obj, i->tag, q0);
698 endshape(obj, i->depth+2-nr);
710 drawShortPath(obj,x,y,m,outline);
712 if(line_cap == LINE_CAP_BUTT) {
718 void drawT1toRect(struct swfoutput*obj, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline, int num, int line_cap, int line_join, double line_width)
720 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
721 plotxy d1,d2,p1,p2,p3,p4;
723 d1.x = (outline->dest.x/(float)0xffff);
724 d1.y = (outline->dest.y/(float)0xffff);
725 d2 = getPivot(obj, outline, 0, line_width, 0, 0);
727 assert(line_cap != LINE_CAP_ROUND);
728 if(line_cap == LINE_CAP_SQUARE) {
737 p2.x = x + d2.x + d1.x;
738 p2.y = y + d2.y + d1.y;
739 p3.x = x - d2.x + d1.x;
740 p3.y = y - d2.y + d1.y;
744 line(obj, i->tag, p1,p2, m);
745 line(obj, i->tag, p2,p3, m);
746 line(obj, i->tag, p3,p4, m);
747 line(obj, i->tag, p4,p1, m);
750 void drawShortPathWithStraightEnds(struct swfoutput*obj, double x, double y, struct swfmatrix* m, SWF_OUTLINE*outline, int num, int line_cap, int line_join, double line_width)
752 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
753 SWF_OUTLINE*tmp=outline;
756 assert(i->shapeid>=0);
759 drawT1toRect(obj, x, y, m,outline, num, line_cap, line_join, line_width);
761 while(tmp->link && tmp->link->type!=SWF_PATHTYPE_MOVE) {
762 xx += (tmp->dest.x/(float)0xffff);
763 yy += (tmp->dest.y/(float)0xffff);
767 assert(tmp->type == SWF_PATHTYPE_LINE);
768 assert(outline->type == SWF_PATHTYPE_LINE);
772 if(outline->link == tmp) {
773 /* the two straight line segments (which are everything we
774 need to draw) are very likely to overlap. To avoid that
775 they cancel each other out at the end points, start a new
776 shape for the second one */
777 endshape(obj,0);startshape(obj);
781 drawT1toRect(obj, xx, yy, m, tmp, num, line_cap, line_join, line_width);
783 if(outline->link != tmp)
785 stopFill(obj);stop=1;
787 tmp->type = SWF_PATHTYPE_MOVE;
788 x += (outline->dest.x/(float)0xffff);
789 y += (outline->dest.y/(float)0xffff);
790 outline = outline->link;
791 drawShortPath(obj, x, y, m, outline);
799 static int t1len(struct swfoutput*obj, SWF_OUTLINE*line)
801 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
803 while(line && line->type != SWF_PATHTYPE_MOVE) {
810 static float t1linelen(struct swfoutput*obj, SWF_OUTLINE*line)
812 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
814 x = (line->dest.x/(float)0xffff);
815 y = (line->dest.y/(float)0xffff);
816 return sqrt(x*x+y*y);
819 void drawpath2poly(struct swfoutput *obj, SWF_OUTLINE*outline, struct swfmatrix*m, int log, int line_join, int line_cap, double line_width, double miter_limit)
821 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
822 if( i->tag->id != ST_DEFINESHAPE &&
823 i->tag->id != ST_DEFINESHAPE2 &&
824 i->tag->id != ST_DEFINESHAPE3) {
825 msg("<error> internal error: drawpath needs a shape tag, not %d\n",i->tag->id);
828 assert(i->shapeid>=0);
830 double lastx=0,lasty=0;
833 SWF_OUTLINE*tmp = outline, *last = 0;
837 double previousx = x, previousy = y;
839 x += (tmp->dest.x/(float)0xffff);
840 y += (tmp->dest.y/(float)0xffff);
842 if(!tmp || tmp->type == SWF_PATHTYPE_MOVE) {
844 if(fabs(lastx-previousx)<0.001 && fabs(lasty-previousy)<0.001) {
845 /* endpoints match- the path is closed.
846 Don't bother to draw endings */
847 drawShortPath(obj, lastx, lasty, m, last);
849 if(last->type == SWF_PATHTYPE_LINE && t1linelen(obj,last)>line_width*2 &&
850 lastwasline && line_cap != LINE_CAP_ROUND)
851 drawShortPathWithStraightEnds(obj, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
853 drawShortPathWithEnds(obj, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
863 last = tmp; //remember last stroke start (first segment after moveto)
867 if(tmp && tmp->type == SWF_PATHTYPE_LINE && t1linelen(obj,tmp)>line_width*2)
873 tmp->link->last = tmp; // make sure list is properly linked in both directions
878 static inline int colorcompare(struct swfoutput*obj, RGBA*a,RGBA*b)
890 static SRECT getcharacterbbox(struct swfoutput*obj, SWFFONT*font)
892 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
895 memset(&r, 0, sizeof(r));
898 if(debug) printf("\n");
899 for(t=0;t<i->chardatapos;t++)
901 if(i->chardata[t].fontid != font->id) {
902 msg("<error> Internal error: fontid %d != fontid %d", i->chardata[t].fontid, font->id);
905 SRECT b = font->layout->bounds[i->chardata[t].charid];
906 b.xmin *= i->chardata[t].size;
907 b.ymin *= i->chardata[t].size;
908 b.xmax *= i->chardata[t].size;
909 b.ymax *= i->chardata[t].size;
914 b.xmin += i->chardata[t].x;
915 b.ymin += i->chardata[t].y;
916 b.xmax += i->chardata[t].x;
917 b.ymax += i->chardata[t].y;
919 /* until we solve the INTERNAL_SCALING problem (see below)
920 make sure the bounding box is big enough */
926 if(debug) printf("(%f,%f,%f,%f) -> (%f,%f,%f,%f) [font %d/%d, char %d]\n",
927 font->layout->bounds[i->chardata[t].charid].xmin/20.0,
928 font->layout->bounds[i->chardata[t].charid].ymin/20.0,
929 font->layout->bounds[i->chardata[t].charid].xmax/20.0,
930 font->layout->bounds[i->chardata[t].charid].ymax/20.0,
935 i->chardata[t].fontid,
937 i->chardata[t].charid
939 swf_ExpandRect2(&r, &b);
941 if(debug) printf("-----> (%f,%f,%f,%f)\n",
949 static void putcharacters(struct swfoutput*obj, TAG*tag)
951 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
955 color.r = i->chardata[0].color.r^255;
964 int charadvance[128];
967 int glyphbits=1; //TODO: can this be zero?
970 if(tag->id != ST_DEFINETEXT &&
971 tag->id != ST_DEFINETEXT2) {
972 msg("<error> internal error: putcharacters needs an text tag, not %d\n",tag->id);
975 if(!i->chardatapos) {
976 msg("<warning> putcharacters called with zero characters");
979 for(pass = 0; pass < 2; pass++)
989 advancebits++; // add sign bit
990 swf_SetU8(tag, glyphbits);
991 swf_SetU8(tag, advancebits);
994 for(t=0;t<=i->chardatapos;t++)
996 if(lastfontid != i->chardata[t].fontid ||
997 lastx!=i->chardata[t].x ||
998 lasty!=i->chardata[t].y ||
999 !colorcompare(obj,&color, &i->chardata[t].color) ||
1000 charstorepos==127 ||
1001 lastsize != i->chardata[t].size ||
1002 t == i->chardatapos)
1004 if(charstorepos && pass==0)
1007 for(s=0;s<charstorepos;s++)
1009 while(charids[s]>=(1<<glyphbits))
1011 while(charadvance[s]>=(1<<advancebits))
1015 if(charstorepos && pass==1)
1017 tag->writeBit = 0; // Q&D
1018 swf_SetBits(tag, 0, 1); // GLYPH Record
1019 swf_SetBits(tag, charstorepos, 7); // number of glyphs
1021 for(s=0;s<charstorepos;s++)
1023 swf_SetBits(tag, charids[s], glyphbits);
1024 swf_SetBits(tag, charadvance[s], advancebits);
1029 if(pass == 1 && t<i->chardatapos)
1035 if(lastx != i->chardata[t].x ||
1036 lasty != i->chardata[t].y)
1038 newx = i->chardata[t].x;
1039 newy = i->chardata[t].y;
1045 if(!colorcompare(obj,&color, &i->chardata[t].color))
1047 color = i->chardata[t].color;
1050 font.id = i->chardata[t].fontid;
1051 if(lastfontid != i->chardata[t].fontid || lastsize != i->chardata[t].size)
1054 tag->writeBit = 0; // Q&D
1055 swf_TextSetInfoRecord(tag, newfont, i->chardata[t].size, newcolor, newx,newy);
1058 lastfontid = i->chardata[t].fontid;
1059 lastx = i->chardata[t].x;
1060 lasty = i->chardata[t].y;
1061 lastsize = i->chardata[t].size;
1064 if(t==i->chardatapos)
1068 int nextt = t==i->chardatapos-1?t:t+1;
1069 int rel = i->chardata[nextt].x-i->chardata[t].x;
1070 if(rel>=0 && (rel<(1<<(advancebits-1)) || pass==0)) {
1072 lastx=i->chardata[nextt].x;
1076 lastx=i->chardata[t].x;
1078 charids[charstorepos] = i->chardata[t].charid;
1079 charadvance[charstorepos] = advance;
1086 static void putcharacter(struct swfoutput*obj, int fontid, int charid,
1087 int x,int y, int size)
1089 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1090 if(i->chardatapos == CHARDATAMAX)
1092 msg("<warning> Character buffer too small. SWF will be slightly bigger");
1096 i->chardata[i->chardatapos].fontid = fontid;
1097 i->chardata[i->chardatapos].charid = charid;
1098 i->chardata[i->chardatapos].x = x;
1099 i->chardata[i->chardatapos].y = y;
1100 i->chardata[i->chardatapos].color = obj->fillrgb;
1101 i->chardata[i->chardatapos].size = size;
1105 /* Notice: we can only put chars in the range -1639,1638 (-32768/20,32768/20).
1106 So if we set this value to high, the char coordinates will overflow.
1107 If we set it to low, however, the char positions will be inaccurate */
1108 #define FONT_INTERNAL_SIZE 4
1110 /* process a character. */
1111 static int drawchar(struct swfoutput*obj, SWFFONT *swffont, char*character, int charnr, int u, swfmatrix*m)
1113 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1115 msg("<warning> Font is NULL");
1119 int charid = getCharID(swffont, charnr, character, u);
1122 msg("<warning> Didn't find character '%s' (c=%d,u=%d) in current charset (%s, %d characters)",
1123 FIXNULL(character),charnr, u, FIXNULL((char*)swffont->name), swffont->numchars);
1134 float det = ((m->m11*m->m22)-(m->m21*m->m12));
1135 if(fabs(det) < 0.0005) {
1136 /* x direction equals y direction- the text is invisible */
1139 det = 20*FONT_INTERNAL_SIZE / det;
1142 p.x = (SCOORD)(( x * m->m22 - y * m->m12)*det);
1143 p.y = (SCOORD)((- x * m->m21 + y * m->m11)*det);
1145 putcharacter(obj, swffont->id, charid,p.x,p.y,FONT_INTERNAL_SIZE);
1146 swf_FontUseGlyph(swffont, charid);
1151 SWF_OUTLINE*outline = font->getOutline(character, charnr);
1152 char* charname = character;
1155 msg("<warning> Didn't find character '%s' (%d) in current charset (%s)",
1156 FIXNULL(character),charnr,FIXNULL(font->getName()));
1175 drawpath(tag, outline, &m2, 0);
1180 static void endtext(swfoutput*obj)
1182 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1186 i->tag = swf_InsertTag(i->tag,ST_DEFINETEXT);
1187 swf_SetU16(i->tag, i->textid);
1190 r = getcharacterbbox(obj, obj->swffont);
1192 swf_SetRect(i->tag,&r);
1195 swf_GetMatrix(0, &m); /* set unit matrix- the real matrix is in the placeobject */
1196 swf_SetMatrix(i->tag,&m);
1198 putcharacters(obj, i->tag);
1199 swf_SetU8(i->tag,0);
1200 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
1201 //swf_ObjectPlace(i->tag,i->textid,/*depth*/i->depth++,&i->page_matrix,NULL,NULL);
1203 swf_MatrixJoin(&m2,&obj->fontmatrix, &i->page_matrix);
1205 swf_ObjectPlace(i->tag,i->textid,/*depth*/i->depth++,&m2,NULL,NULL);
1210 /* draw a curved polygon. */
1211 void swfoutput_drawpath(swfoutput*obj, SWF_OUTLINE*outline,
1214 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1218 /* Multiple polygons in one shape don't overlap correctly,
1219 so we better start a new shape here if the polygon is filled
1221 if(i->shapeid>=0 && i->fill && !config_ignoredraworder) {
1234 drawpath(obj, outline,m, 0);
1237 void swfoutput_drawpath2poly(struct swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
1239 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1244 assert(i->shapeid<0);
1248 drawpath2poly(obj, outline, m, 0, line_join, line_cap, line_width, miter_limit);
1251 int getCharID(SWFFONT *font, int charnr, char *charname, int u)
1254 if(charname && font->glyphnames) {
1255 for(t=0;t<font->numchars;t++) {
1256 if(font->glyphnames[t] && !strcmp(font->glyphnames[t],charname)) {
1257 msg("<debug> Char [%d,>%s<,%d] maps to %d\n", charnr, charname, u, t);
1261 /* if we didn't find the character, maybe
1262 we can find the capitalized version */
1263 for(t=0;t<font->numchars;t++) {
1264 if(font->glyphnames[t] && !strcasecmp(font->glyphnames[t],charname)) {
1265 msg("<debug> Char [%d,>>%s<<,%d] maps to %d\n", charnr, charname, u, t);
1271 if(u>0 && font->encoding != 255) {
1272 /* try to use the unicode id */
1273 if(u>=0 && u<font->maxascii && font->ascii2glyph[u]>=0) {
1274 msg("<debug> Char [%d,%s,>%d<] maps to %d\n", charnr, charname, u, font->ascii2glyph[u]);
1275 return font->ascii2glyph[u];
1279 if(font->encoding != FONT_ENCODING_UNICODE) {
1280 /* the following only works if the font encoding
1281 is US-ASCII based. It's needed for fonts which return broken unicode
1283 if(charnr>=0 && charnr<font->maxascii && font->ascii2glyph[charnr]>=0) {
1284 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, font->ascii2glyph[charnr]);
1285 return font->ascii2glyph[charnr];
1289 if(charnr>=0 && charnr<font->numchars) {
1290 msg("<debug> Char [>%d<,%s,%d] maps to %d\n", charnr, charname, u, charnr);
1298 /* set's the t1 font index of the font to use for swfoutput_drawchar(). */
1299 void swfoutput_setfont(struct swfoutput*obj, char*fontid, char*filename)
1301 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1302 fontlist_t*last=0,*iterator;
1304 msg("<error> No fontid");
1308 if(obj->swffont && obj->swffont->name && !strcmp((char*)obj->swffont->name,fontid))
1311 /* TODO: remove the need for this (enhance getcharacterbbox so that it can cope
1312 with multiple fonts */
1315 iterator = i->fontlist;
1317 if(!strcmp((char*)iterator->swffont->name,fontid)) {
1318 obj->swffont = iterator->swffont;
1322 iterator = iterator->next;
1326 msg("<error> No filename given for font- internal error?");
1330 swf_SetLoadFontParameters(64,/*skip unused*/0,/*full unicode*/1);
1331 SWFFONT*swffont = swf_LoadFont(filename);
1334 msg("<warning> Couldn't load font %s (%s)", fontid, filename);
1335 swffont = swf_LoadFont(0);
1338 if(swffont->glyph2ascii) {
1341 /* check whether the Unicode indices look o.k.
1342 If they don't, disable the unicode lookup by setting
1343 the encoding to 255 */
1344 for(t=0;t<swffont->numchars;t++) {
1345 int c = swffont->glyph2ascii[t];
1346 if(c && c < 32 && swffont->glyph[t].shape->bitlen > 16) {
1347 // the character maps into the unicode control character range
1348 // between 0001-001f. Yet it is not empty. Treat the one
1349 // mapping as broken, and look how many of those we find.
1354 msg("<warning> Font %s has bad unicode mapping", fontid);
1355 swffont->encoding = 255;
1359 swf_FontSetID(swffont, ++i->currentswfid);
1361 if(getScreenLogLevel() >= LOGLEVEL_DEBUG) {
1362 // print font information
1363 msg("<debug> Font %s (%s)",swffont->name, filename);
1364 msg("<debug> | ID: %d", swffont->id);
1365 msg("<debug> | Version: %d", swffont->version);
1366 msg("<debug> | Name: %s", fontid);
1367 msg("<debug> | Numchars: %d", swffont->numchars);
1368 msg("<debug> | Maxascii: %d", swffont->maxascii);
1369 msg("<debug> | Style: %d", swffont->style);
1370 msg("<debug> | Encoding: %d", swffont->encoding);
1371 for(int iii=0; iii<swffont->numchars;iii++) {
1372 msg("<debug> | Glyph %d) name=%s, unicode=%d size=%d bbox=(%.2f,%.2f,%.2f,%.2f)\n", iii, swffont->glyphnames?swffont->glyphnames[iii]:"<nonames>", swffont->glyph2ascii[iii], swffont->glyph[iii].shape->bitlen,
1373 swffont->layout->bounds[iii].xmin/20.0,
1374 swffont->layout->bounds[iii].ymin/20.0,
1375 swffont->layout->bounds[iii].xmax/20.0,
1376 swffont->layout->bounds[iii].ymax/20.0
1379 for(t=0;t<swffont->maxascii;t++) {
1380 if(swffont->ascii2glyph[t] == iii)
1381 msg("<debug> | - maps to %d",t);
1386 /* set the font name to the ID we use here */
1387 if(swffont->name) free(swffont->name);
1388 swffont->name = (U8*)strdup(fontid);
1390 iterator = new fontlist_t;
1391 iterator->swffont = swffont;
1395 last->next = iterator;
1397 i->fontlist = iterator;
1399 obj->swffont = swffont;
1402 int swfoutput_queryfont(struct swfoutput*obj, char*fontid)
1404 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1405 fontlist_t *iterator = i->fontlist;
1407 if(!strcmp((char*)iterator->swffont->name,fontid))
1409 iterator = iterator->next;
1414 /* set's the matrix which is to be applied to characters drawn by
1415 swfoutput_drawchar() */
1416 void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12,
1417 double m21,double m22)
1419 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1420 if(obj->fontm11 == m11 &&
1421 obj->fontm12 == m12 &&
1422 obj->fontm21 == m21 &&
1423 obj->fontm22 == m22)
1433 m.sx = (U32)(((obj->fontm11)*65536)/FONT_INTERNAL_SIZE); m.r1 = (U32)(((obj->fontm12)*65536)/FONT_INTERNAL_SIZE);
1434 m.r0 = (U32)(((obj->fontm21)*65536)/FONT_INTERNAL_SIZE); m.sy = (U32)(((obj->fontm22)*65536)/FONT_INTERNAL_SIZE);
1437 obj->fontmatrix = m;
1440 /* draws a character at x,y. */
1441 int swfoutput_drawchar(struct swfoutput* obj,double x,double y,char*character, int charnr, int u)
1443 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1445 m.m11 = obj->fontm11;
1446 m.m12 = obj->fontm12;
1447 m.m21 = obj->fontm21;
1448 m.m22 = obj->fontm22;
1451 return drawchar(obj, obj->swffont, character, charnr, u, &m);
1454 static void endpage(struct swfoutput*obj)
1456 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1462 swfoutput_endclip(obj);
1463 i->pagefinished = 1;
1466 void swfoutput_pagefeed(struct swfoutput*obj)
1468 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1470 if(!i->pagefinished)
1473 if(config_insertstoptag) {
1475 atag = action_Stop(atag);
1476 atag = action_End(atag);
1477 i->tag = swf_InsertTag(i->tag,ST_DOACTION);
1478 swf_ActionSet(i->tag,atag);
1480 i->tag = swf_InsertTag(i->tag,ST_SHOWFRAME);
1483 for(i->depth--;i->depth>=i->startdepth;i->depth--) {
1484 i->tag = swf_InsertTag(i->tag,ST_REMOVEOBJECT2);
1485 swf_SetU16(i->tag,i->depth);
1487 i->depth = i->startdepth;
1490 static void setBackground(struct swfoutput*obj, int x1, int y1, int x2, int y2)
1492 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1494 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1498 int shapeid = ++i->currentswfid;
1503 i->tag = swf_InsertTag(i->tag, ST_DEFINESHAPE);
1505 fs1 = swf_ShapeAddSolidFillStyle(s, &rgb);
1506 swf_SetU16(i->tag,shapeid);
1507 swf_SetRect(i->tag,&r);
1508 swf_SetShapeHeader(i->tag,s);
1509 swf_ShapeSetAll(i->tag,s,x1,y1,ls1,fs1,0);
1510 swf_ShapeSetLine(i->tag,s,(x2-x1),0);
1511 swf_ShapeSetLine(i->tag,s,0,(y2-y1));
1512 swf_ShapeSetLine(i->tag,s,(x1-x2),0);
1513 swf_ShapeSetLine(i->tag,s,0,(y1-y2));
1514 swf_ShapeSetEnd(i->tag);
1516 i->tag = swf_InsertTag(i->tag, ST_PLACEOBJECT2);
1517 swf_ObjectPlace(i->tag,shapeid,i->depth++,0,0,0);
1518 i->tag = swf_InsertTag(i->tag, ST_PLACEOBJECT2);
1519 swf_ObjectPlaceClip(i->tag,shapeid,i->depth++,0,0,0,65535);
1520 i->cliptag = i->tag;
1523 void swfoutput_newpage(struct swfoutput*obj, int pageNum, int movex, int movey, int x1, int y1, int x2, int y2)
1525 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1526 if(!i->firstpage && !i->pagefinished)
1529 swf_GetMatrix(0, &i->page_matrix);
1530 i->page_matrix.tx = movex*20;
1531 i->page_matrix.ty = movey*20;
1533 if(i->cliptag && i->frameno == i->lastframeno) {
1535 swf_GetPlaceObject(i->cliptag, &obj);
1536 obj.clipdepth = i->depth++;
1537 swf_ResetTag(i->cliptag, i->cliptag->id);
1538 swf_SetPlaceObject(i->cliptag, &obj);
1539 swf_PlaceObjectFree(&obj);
1547 msg("<notice> processing page %d (%dx%d:%d:%d)", pageNum,x2-x1,y2-y1, x1, y1);
1549 x1*=20;y1*=20;x2*=20;y2*=20;
1551 /* set clipping/background rectangle */
1552 /* TODO: this should all be done in SWFOutputDev */
1553 setBackground(obj, x1, y1, x2, y2);
1555 /* increase SWF's bounding box */
1561 swf_ExpandRect2(&i->swf.movieSize, &r);
1563 i->lastframeno = i->frameno;
1565 i->pagefinished = 0;
1568 /* initialize the swf writer */
1569 void swfoutput_init(struct swfoutput* obj)
1571 memset(obj, 0, sizeof(struct swfoutput));
1572 obj->internal = init_internal_struct();
1573 ((swfoutput_internal*)obj->internal)->obj = obj;
1575 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1580 msg("<verbose> initializing swf output for size %d*%d\n", i->max_x,i->max_y);
1585 memset(&i->swf,0x00,sizeof(SWF));
1587 i->swf.fileVersion = config_flashversion;
1588 i->swf.frameRate = 0x0040; // 1 frame per 4 seconds
1589 i->swf.movieSize.xmin = 0;
1590 i->swf.movieSize.ymin = 0;
1591 i->swf.movieSize.xmax = 0;
1592 i->swf.movieSize.ymax = 0;
1594 i->swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1595 i->tag = i->swf.firstTag;
1596 rgb.a = rgb.r = rgb.g = rgb.b = 0xff;
1597 swf_SetRGB(i->tag,&rgb);
1599 i->startdepth = i->depth = 3; /* leave room for clip and background rectangle */
1602 i->tag = swf_InsertTag(i->tag, ST_PROTECT);
1605 static void startshape(struct swfoutput*obj)
1607 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1613 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE);
1615 swf_ShapeNew(&i->shape);
1616 i->linestyleid = swf_ShapeAddLineStyle(i->shape,i->linewidth,&obj->strokergb);
1617 i->fillstyleid = swf_ShapeAddSolidFillStyle(i->shape,&obj->fillrgb);
1619 i->shapeid = ++i->currentswfid;
1620 swf_SetU16(i->tag,i->shapeid); // ID
1622 i->bboxrectpos = i->tag->len;
1626 r.xmax = 20*i->max_x;
1627 r.ymax = 20*i->max_y;
1628 swf_SetRect(i->tag,&r);
1630 memset(&i->bboxrect, 0, sizeof(i->bboxrect));
1632 swf_SetShapeStyles(i->tag,i->shape);
1633 swf_ShapeCountBits(i->shape,NULL,NULL);
1634 swf_SetShapeBits(i->tag,i->shape);
1636 /* TODO: do we really need this? */
1637 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,i->linestyleid,0,0);
1638 i->swflastx=i->swflasty=0;
1640 i->shapeisempty = 1;
1643 static void starttext(struct swfoutput*obj)
1645 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1649 i->textid = ++i->currentswfid;
1651 i->swflastx=i->swflasty=0;
1655 /* TODO: move to ../lib/rfxswf */
1656 void changeRect(struct swfoutput*obj, TAG*tag, int pos, SRECT*newrect)
1658 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1659 /* determine length of old rect */
1663 swf_GetRect(tag, &old);
1664 swf_ResetReadBits(tag);
1665 int pos_end = tag->pos;
1667 int len = tag->len - pos_end;
1668 U8*data = (U8*)malloc(len);
1669 memcpy(data, &tag->data[pos_end], len);
1672 swf_SetRect(tag, newrect);
1673 swf_SetBlock(tag, data, len);
1675 tag->pos = tag->readBit = 0;
1678 void cancelshape(swfoutput*obj)
1680 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1681 /* delete old shape tag */
1683 i->tag = i->tag->prev;
1684 swf_DeleteTag(todel);
1685 if(i->shape) {swf_ShapeFree(i->shape);i->shape=0;}
1687 i->bboxrectpos = -1;
1690 void fixAreas(swfoutput*obj)
1692 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1693 if(!i->shapeisempty && i->fill &&
1694 (i->bboxrect.xmin == i->bboxrect.xmax ||
1695 i->bboxrect.ymin == i->bboxrect.ymax) &&
1696 config_minlinewidth >= 0.001
1698 msg("<debug> Shape has size 0: width=%.2f height=%.2f",
1699 (i->bboxrect.xmax-i->bboxrect.xmin)/20.0,
1700 (i->bboxrect.ymax-i->bboxrect.ymin)/20.0
1703 SRECT r = i->bboxrect;
1705 if(r.xmin == r.xmax && r.ymin == r.ymax) {
1706 /* this thing comes down to a single dot- nothing to fix here */
1712 RGBA save_col = obj->strokergb;
1713 int save_width = i->linewidth;
1715 obj->strokergb = obj->fillrgb;
1716 i->linewidth = (int)(config_minlinewidth*20);
1717 if(i->linewidth==0) i->linewidth = 1;
1721 moveto(obj, i->tag, r.xmin/20.0,r.ymin/20.0);
1722 lineto(obj, i->tag, r.xmax/20.0,r.ymax/20.0);
1724 obj->strokergb = save_col;
1725 i->linewidth = save_width;
1730 static void endshape_noput(swfoutput*obj)
1732 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1735 //changeRect(obj, i->tag, i->bboxrectpos, &i->bboxrect);
1738 swf_ShapeFree(i->shape);
1743 static void endshape(swfoutput*obj, int clipdepth)
1745 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1752 if(i->shapeisempty ||
1754 (i->bboxrect.xmin == i->bboxrect.xmax &&
1755 i->bboxrect.ymin == i->bboxrect.ymax))
1757 // delete the shape again, we didn't do anything
1762 swf_ShapeSetEnd(i->tag);
1764 changeRect(obj, i->tag, i->bboxrectpos, &i->bboxrect);
1766 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
1769 swf_ObjectPlaceClip(i->tag,i->shapeid,i->depth++,&i->page_matrix,NULL,NULL,clipdepth);
1771 swf_ObjectPlace(i->tag,i->shapeid,/*depth*/i->depth++,&i->page_matrix,NULL,NULL);
1773 swf_ShapeFree(i->shape);
1776 i->bboxrectpos = -1;
1779 void swfoutput_finalize(struct swfoutput*obj)
1781 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1783 if(i->tag && i->tag->id == ST_END)
1784 return; //already done
1786 if(i->frameno == i->lastframeno) // fix: add missing pagefeed
1787 swfoutput_pagefeed(obj);
1790 fontlist_t *tmp,*iterator = i->fontlist;
1792 TAG*mtag = i->swf.firstTag;
1793 if(iterator->swffont) {
1794 mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
1795 /*if(!storeallcharacters)
1796 swf_FontReduce(iterator->swffont);*/
1797 swf_FontSetDefine2(mtag, iterator->swffont);
1800 iterator = iterator->next;
1802 i->tag = swf_InsertTag(i->tag,ST_END);
1803 TAG* tag = i->tag->prev;
1805 /* remove the removeobject2 tags between the last ST_SHOWFRAME
1806 and the ST_END- they confuse the flash player */
1807 while(tag->id == ST_REMOVEOBJECT2) {
1808 TAG* prev = tag->prev;
1814 SWF* swfoutput_get(struct swfoutput*obj)
1816 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1818 swfoutput_finalize(obj);
1820 return swf_CopySWF(&i->swf);
1823 void swfoutput_getdimensions(struct swfoutput*obj, int*x1, int*y1, int*x2, int*y2)
1825 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1826 if(x1) *x1 = i->swf.movieSize.xmin/20;
1827 if(y1) *y1 = i->swf.movieSize.ymin/20;
1828 if(x2) *x2 = i->swf.movieSize.xmax/20;
1829 if(y2) *y2 = i->swf.movieSize.ymax/20;
1832 int swfoutput_save(struct swfoutput* obj, char*filename)
1834 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1835 swfoutput_finalize(obj);
1839 fi = open(filename, O_BINARY|O_CREAT|O_TRUNC|O_WRONLY, 0777);
1844 msg("<fatal> Could not create \"%s\". ", FIXNULL(filename));
1848 if(config_enablezlib || config_flashversion>=6) {
1849 if FAILED(swf_WriteSWC(fi,&i->swf))
1850 msg("<error> WriteSWC() failed.\n");
1852 if FAILED(swf_WriteSWF(fi,&i->swf))
1853 msg("<error> WriteSWF() failed.\n");
1858 msg("<notice> SWF written\n");
1862 /* Perform cleaning up, complete the swf, and write it out. */
1863 void swfoutput_destroy(struct swfoutput* obj)
1865 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1867 /* not initialized yet- nothing to destroy */
1871 fontlist_t *tmp,*iterator = i->fontlist;
1873 if(iterator->swffont) {
1874 swf_FontFree(iterator->swffont);iterator->swffont=0;
1877 iterator = iterator->next;
1880 swf_FreeTags(&i->swf);
1883 memset(obj, 0, sizeof(swfoutput));
1886 void swfoutput_setdrawmode(swfoutput* obj, int mode)
1888 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1889 obj->drawmode = mode;
1890 if(mode == DRAWMODE_FILL)
1892 else if(mode == DRAWMODE_EOFILL)
1894 else if(mode == DRAWMODE_STROKE)
1896 else if(mode == DRAWMODE_CLIP)
1898 else if(mode == DRAWMODE_EOCLIP)
1902 void swfoutput_setfillcolor(swfoutput* obj, U8 r, U8 g, U8 b, U8 a)
1904 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1905 if(obj->fillrgb.r == r &&
1906 obj->fillrgb.g == g &&
1907 obj->fillrgb.b == b &&
1908 obj->fillrgb.a == a) return;
1918 void swfoutput_setstrokecolor(swfoutput* obj, U8 r, U8 g, U8 b, U8 a)
1920 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1921 if(obj->strokergb.r == r &&
1922 obj->strokergb.g == g &&
1923 obj->strokergb.b == b &&
1924 obj->strokergb.a == a) return;
1928 obj->strokergb.r = r;
1929 obj->strokergb.g = g;
1930 obj->strokergb.b = b;
1931 obj->strokergb.a = a;
1934 void swfoutput_setlinewidth(struct swfoutput*obj, double _linewidth)
1936 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1937 if(i->linewidth == (U16)(_linewidth*20))
1942 i->linewidth = (U16)(_linewidth*20);
1946 void swfoutput_startclip(swfoutput*obj, SWF_OUTLINE*outline, struct swfmatrix*m)
1948 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1954 if(i->clippos >= 127)
1956 msg("<warning> Too many clip levels.");
1961 int olddrawmode = obj->drawmode;
1962 swfoutput_setdrawmode(obj, DRAWMODE_CLIP);
1963 swfoutput_drawpath(obj, outline, m);
1964 swf_ShapeSetEnd(i->tag);
1965 swfoutput_setdrawmode(obj, olddrawmode);
1967 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
1968 i->cliptags[i->clippos] = i->tag;
1969 i->clipshapes[i->clippos] = i->shapeid;
1970 i->clipdepths[i->clippos] = i->depth++;
1973 endshape_noput(obj);
1976 void swfoutput_endclip(swfoutput*obj)
1978 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1985 msg("<error> Invalid end of clipping region");
1989 swf_ObjectPlaceClip(i->cliptags[i->clippos],i->clipshapes[i->clippos],i->clipdepths[i->clippos],&i->page_matrix,NULL,NULL,i->depth++);
1992 static void drawlink(struct swfoutput*obj, ActionTAG*,ActionTAG*, swfcoord*points, char mouseover);
1994 void swfoutput_linktourl(struct swfoutput*obj, char*url, swfcoord*points)
1996 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
1998 if(!strncmp("http://pdf2swf:", url, 15)) {
1999 char*tmp = strdup(url);
2000 int l = strlen(tmp);
2003 swfoutput_namedlink(obj, tmp+15, points);
2013 if(config_opennewwindow)
2014 actions = action_GetUrl(0, url, "_parent");
2016 actions = action_GetUrl(0, url, "_this");
2017 actions = action_End(actions);
2019 drawlink(obj, actions, 0, points,0);
2021 void swfoutput_linktopage(struct swfoutput*obj, int page, swfcoord*points)
2023 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2031 actions = action_GotoFrame(0, page);
2032 actions = action_End(actions);
2034 drawlink(obj, actions, 0, points,0);
2037 /* Named Links (a.k.a. Acrobatmenu) are used to implement various gadgets
2038 of the viewer objects, like subtitles, index elements etc.
2040 void swfoutput_namedlink(struct swfoutput*obj, char*name, swfcoord*points)
2042 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2043 ActionTAG *actions1,*actions2;
2044 char*tmp = strdup(name);
2052 if(!strncmp(tmp, "call:", 5))
2054 char*x = strchr(&tmp[5], ':');
2056 actions1 = action_PushInt(0, 0); //number of parameters (0)
2057 actions1 = action_PushString(actions1, &tmp[5]); //function name
2058 actions1 = action_CallFunction(actions1);
2061 actions1 = action_PushString(0, x+1); //parameter
2062 actions1 = action_PushInt(actions1, 1); //number of parameters (1)
2063 actions1 = action_PushString(actions1, &tmp[5]); //function name
2064 actions1 = action_CallFunction(actions1);
2066 actions2 = action_End(0);
2071 actions1 = action_PushString(0, "/:subtitle");
2072 actions1 = action_PushString(actions1, name);
2073 actions1 = action_SetVariable(actions1);
2074 actions1 = action_End(actions1);
2076 actions2 = action_PushString(0, "/:subtitle");
2077 actions2 = action_PushString(actions2, "");
2078 actions2 = action_SetVariable(actions2);
2079 actions2 = action_End(actions2);
2082 drawlink(obj, actions1, actions2, points,mouseover);
2084 swf_ActionFree(actions1);
2085 swf_ActionFree(actions2);
2089 static void drawlink(struct swfoutput*obj, ActionTAG*actions1, ActionTAG*actions2, swfcoord*points, char mouseover)
2091 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2096 struct plotxy p1,p2,p3,p4;
2100 double xmax=xmin=points[0].x,ymax=ymin=points[0].y;
2104 int buttonid = ++i->currentswfid;
2107 if(points[t].x>xmax) xmax=points[t].x;
2108 if(points[t].y>ymax) ymax=points[t].y;
2109 if(points[t].x<xmin) xmin=points[t].x;
2110 if(points[t].y<ymin) ymin=points[t].y;
2113 p1.x=points[0].x; p1.y=points[0].y; p2.x=points[1].x; p2.y=points[1].y;
2114 p3.x=points[2].x; p3.y=points[2].y; p4.x=points[3].x; p4.y=points[3].y;
2116 /* the following code subtracts the upper left edge from all coordinates,
2117 and set's posx,posy so that ST_PLACEOBJECT is used with a matrix.
2118 Necessary for preprocessing with swfcombine. */
2119 posx = xmin; posy = ymin;
2120 p1.x-=posx;p2.x-=posx;p3.x-=posx;p4.x-=posx;
2121 p1.y-=posy;p2.y-=posy;p3.y-=posy;p4.y-=posy;
2122 xmin -= posx; ymin -= posy;
2123 xmax -= posx; ymax -= posy;
2126 myshapeid = ++i->currentswfid;
2127 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE3);
2128 swf_ShapeNew(&i->shape);
2129 rgb.r = rgb.b = rgb.a = rgb.g = 0;
2130 fsid = swf_ShapeAddSolidFillStyle(i->shape,&rgb);
2131 swf_SetU16(i->tag, myshapeid);
2132 r.xmin = (int)(xmin*20);
2133 r.ymin = (int)(ymin*20);
2134 r.xmax = (int)(xmax*20);
2135 r.ymax = (int)(ymax*20);
2136 swf_SetRect(i->tag,&r);
2137 swf_SetShapeStyles(i->tag,i->shape);
2138 swf_ShapeCountBits(i->shape,NULL,NULL);
2139 swf_SetShapeBits(i->tag,i->shape);
2140 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,0,fsid,0);
2141 i->swflastx = i->swflasty = 0;
2142 moveto(obj, i->tag, p1);
2143 lineto(obj, i->tag, p2);
2144 lineto(obj, i->tag, p3);
2145 lineto(obj, i->tag, p4);
2146 lineto(obj, i->tag, p1);
2147 swf_ShapeSetEnd(i->tag);
2150 myshapeid2 = ++i->currentswfid;
2151 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE3);
2152 swf_ShapeNew(&i->shape);
2153 rgb.r = rgb.b = rgb.a = rgb.g = 255;
2155 fsid = swf_ShapeAddSolidFillStyle(i->shape,&rgb);
2156 swf_SetU16(i->tag, myshapeid2);
2157 r.xmin = (int)(xmin*20);
2158 r.ymin = (int)(ymin*20);
2159 r.xmax = (int)(xmax*20);
2160 r.ymax = (int)(ymax*20);
2161 swf_SetRect(i->tag,&r);
2162 swf_SetShapeStyles(i->tag,i->shape);
2163 swf_ShapeCountBits(i->shape,NULL,NULL);
2164 swf_SetShapeBits(i->tag,i->shape);
2165 swf_ShapeSetAll(i->tag,i->shape,/*x*/0,/*y*/0,0,fsid,0);
2166 i->swflastx = i->swflasty = 0;
2167 moveto(obj, i->tag, p1);
2168 lineto(obj, i->tag, p2);
2169 lineto(obj, i->tag, p3);
2170 lineto(obj, i->tag, p4);
2171 lineto(obj, i->tag, p1);
2172 swf_ShapeSetEnd(i->tag);
2176 i->tag = swf_InsertTag(i->tag,ST_DEFINEBUTTON);
2177 swf_SetU16(i->tag,buttonid); //id
2178 swf_ButtonSetFlags(i->tag, 0); //menu=no
2179 swf_ButtonSetRecord(i->tag,0x01,myshapeid,i->depth,0,0);
2180 swf_ButtonSetRecord(i->tag,0x02,myshapeid2,i->depth,0,0);
2181 swf_ButtonSetRecord(i->tag,0x04,myshapeid2,i->depth,0,0);
2182 swf_ButtonSetRecord(i->tag,0x08,myshapeid,i->depth,0,0);
2183 swf_SetU8(i->tag,0);
2184 swf_ActionSet(i->tag,actions1);
2185 swf_SetU8(i->tag,0);
2189 i->tag = swf_InsertTag(i->tag,ST_DEFINEBUTTON2);
2190 swf_SetU16(i->tag,buttonid); //id
2191 swf_ButtonSetFlags(i->tag, 0); //menu=no
2192 swf_ButtonSetRecord(i->tag,0x01,myshapeid,i->depth,0,0);
2193 swf_ButtonSetRecord(i->tag,0x02,myshapeid2,i->depth,0,0);
2194 swf_ButtonSetRecord(i->tag,0x04,myshapeid2,i->depth,0,0);
2195 swf_ButtonSetRecord(i->tag,0x08,myshapeid,i->depth,0,0);
2196 swf_SetU8(i->tag,0); // end of button records
2197 swf_ButtonSetCondition(i->tag, BC_IDLE_OVERUP);
2198 swf_ActionSet(i->tag,actions1);
2200 swf_ButtonSetCondition(i->tag, BC_OVERUP_IDLE);
2201 swf_ActionSet(i->tag,actions2);
2202 swf_SetU8(i->tag,0);
2203 swf_ButtonPostProcess(i->tag, 2);
2205 swf_SetU8(i->tag,0);
2206 swf_ButtonPostProcess(i->tag, 1);
2210 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
2212 if(posx!=0 || posy!=0) {
2214 p.x = (int)(posx*20);
2215 p.y = (int)(posy*20);
2216 p = swf_TurnPoint(p, &i->page_matrix);
2221 swf_ObjectPlace(i->tag, buttonid, i->depth++,&m,0,0);
2224 swf_ObjectPlace(i->tag, buttonid, i->depth++,&i->page_matrix,0,0);
2231 for(t=0;t<picpos;t++)
2233 if(pic_xids[t] == xid &&
2234 pic_yids[t] == yid) {
2235 width = pic_width[t];
2236 height = pic_height[t];
2240 pic_ids[picpos] = swfoutput_drawimagelosslessN(&output, pic, pal, width, height, x1,y1,x2,y2,x3,y3,x4,y4, numpalette);
2241 pic_xids[picpos] = xid;
2242 pic_yids[picpos] = yid;
2243 pic_width[picpos] = width;
2244 pic_height[picpos] = height;
2247 pic[width*y+x] = buf[0];
2251 xid += pal[1].r*3 + pal[1].g*11 + pal[1].b*17;
2252 yid += pal[1].r*7 + pal[1].g*5 + pal[1].b*23;
2256 xid += x*r+x*b*3+x*g*7+x*a*11;
2257 yid += y*r*3+y*b*17+y*g*19+y*a*11;
2259 for(t=0;t<picpos;t++)
2261 if(pic_xids[t] == xid &&
2262 pic_yids[t] == yid) {
2272 gfxbbox_t gfxbbox_expand_to_point(gfxbbox_t box, gfxcoord_t x, gfxcoord_t y)
2274 if(box.xmin==0 || box.ymin==0 || box.xmax==0 || box.ymax==0) {
2279 if(x==0 && y==0) box.xmax = 0.0000001;
2293 gfxbbox_t gfxline_getbbox(gfxline_t*line)
2296 gfxbbox_t bbox = {0,0,0,0};
2299 if(line->type == gfx_moveTo) {
2301 } else if(line->type == gfx_lineTo) {
2302 if(last) bbox = gfxbbox_expand_to_point(bbox, x, y);
2303 bbox = gfxbbox_expand_to_point(bbox, line->x, line->y);
2305 } else if(line->type == gfx_splineTo) {
2306 if(last) bbox = gfxbbox_expand_to_point(bbox, x, y);
2307 bbox = gfxbbox_expand_to_point(bbox, line->sx, line->sy);
2308 bbox = gfxbbox_expand_to_point(bbox, line->x, line->y);
2319 static void drawgfxline(struct swfoutput*obj, gfxline_t*line)
2321 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2323 if(line->type == gfx_moveTo) {
2324 moveto(obj, i->tag, line->x, line->y);
2325 } if(line->type == gfx_lineTo) {
2326 lineto(obj, i->tag, line->x, line->y);
2327 } else if(line->type == gfx_splineTo) {
2329 s.x = line->sx;p.x = line->x;
2330 s.y = line->sy;p.y = line->y;
2331 splineto(obj, i->tag, s, p);
2336 static CXFORM gfxcxform_to_cxform(gfxcxform_t* c)
2339 swf_GetCXForm(0, &cx, 1);
2342 if(c->rg!=0 || c->rb!=0 || c->ra!=0 ||
2343 c->gr!=0 || c->gb!=0 || c->ga!=0 ||
2344 c->br!=0 || c->bg!=0 || c->ba!=0 ||
2345 c->ar!=0 || c->ag!=0 || c->ab!=0)
2346 msg("<warning> CXForm not SWF-compatible");
2348 cx.a0 = (S16)(c->aa*256);
2349 cx.r0 = (S16)(c->rr*256);
2350 cx.g0 = (S16)(c->gg*256);
2351 cx.b0 = (S16)(c->bb*256);
2359 static int add_image(swfoutput_internal*i, gfximage_t*img, int targetwidth, int targetheight, int* newwidth, int* newheight)
2362 RGBA*mem = (RGBA*)img->data;
2363 int bitid = ++i->currentswfid;
2365 int sizex = img->width;
2366 int sizey = img->height;
2367 int num_colors = swf_ImageGetNumberOfPaletteEntries(mem,sizex,sizey,0);
2368 int has_alpha = swf_ImageHasAlpha(mem,sizex,sizey);
2369 int is_jpeg = i->jpeg;
2372 int newsizex=sizex, newsizey=sizey;
2375 if(is_jpeg && config_jpegsubpixels) {
2376 newsizex = (int)(targetwidth*config_jpegsubpixels+0.5);
2377 newsizey = (int)(targetheight*config_jpegsubpixels+0.5);
2378 } else if(!is_jpeg && config_ppmsubpixels) {
2379 newsizex = (int)(targetwidth*config_ppmsubpixels+0.5);
2380 newsizey = (int)(targetheight*config_ppmsubpixels+0.5);
2384 *newwidth = newsizex;
2385 *newheight = newsizey;
2388 /* TODO: cache images */
2390 msg("<verbose> Drawing %dx%d %s%simage at size %dx%d (%dx%d), %s%d colors",
2392 has_alpha?(has_alpha==2?"semi-transparent ":"transparent "):"",
2395 targetwidth, targetheight,
2396 /*newsizex, newsizey,*/
2397 num_colors>256?">":"", num_colors>256?256:num_colors);
2399 if(newsizex!=sizex || newsizey!=sizey) {
2400 newpic = swf_ImageScale(mem, sizex, sizey, newsizex, newsizey);
2407 if(num_colors<=256 || sizex<8 || sizey<8) {
2408 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSLOSSLESS2);
2409 swf_SetU16(i->tag, bitid);
2410 swf_SetLosslessImage(i->tag,mem,sizex,sizey);
2412 /*TODO: check what is smaller */
2413 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSJPEG3);
2414 swf_SetU16(i->tag, bitid);
2415 swf_SetJPEGBits3(i->tag,sizex,sizey,mem,config_jpegquality);
2416 //swf_SetLosslessImage(i->tag,mem,sizex,sizey);
2419 if(num_colors<=256 || sizex<8) {
2420 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSLOSSLESS);
2421 swf_SetU16(i->tag, bitid);
2422 swf_SetLosslessImage(i->tag,mem,sizex,sizey);
2424 /*TODO: check what is smaller */
2425 i->tag = swf_InsertTag(i->tag,ST_DEFINEBITSJPEG2);
2426 swf_SetU16(i->tag, bitid);
2427 swf_SetJPEGBits2(i->tag,sizex,sizey,mem,config_jpegquality);
2428 //swf_SetLosslessImage(i->tag,mem,sizex,sizey);
2438 void swf_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform)
2440 swfoutput_internal*i = (swfoutput_internal*)dev->internal;
2441 swfoutput*obj = i->obj;
2448 gfxbbox_t bbox = gfxline_getbbox(line);
2450 int targetx = (int)(sqrt(matrix->m00*matrix->m00 + matrix->m01*matrix->m01)*img->width);
2451 int targety = (int)(sqrt(matrix->m10*matrix->m10 + matrix->m11*matrix->m11)*img->height);
2453 int newwidth=0,newheight=0;
2454 int bitid = add_image(i, img, targetx, targety, &newwidth, &newheight);
2455 double fx = (double)img->width / (double)newwidth;
2456 double fy = (double)img->height / (double)newheight;
2461 m.sx = (int)(65536*20*matrix->m00*fx);
2462 m.r0 = (int)(65536*20*matrix->m01*fx);
2463 m.r1 = (int)(65536*20*matrix->m10*fy);
2464 m.sy = (int)(65536*20*matrix->m11*fy);
2465 m.tx = (int)(matrix->tx*20);
2466 m.ty = (int)(matrix->ty*20);
2469 int myshapeid = ++i->currentswfid;
2470 i->tag = swf_InsertTag(i->tag,ST_DEFINESHAPE);
2472 swf_ShapeNew(&shape);
2473 int fsid = swf_ShapeAddBitmapFillStyle(shape,&m,bitid,1);
2475 swf_SetU16(i->tag, myshapeid);
2476 r.xmin = (int)(bbox.xmin*20);
2477 r.ymin = (int)(bbox.ymin*20);
2478 r.xmax = (int)(bbox.xmax*20);
2479 r.ymax = (int)(bbox.ymax*20);
2480 swf_SetRect(i->tag,&r);
2481 swf_SetShapeStyles(i->tag,shape);
2482 swf_ShapeCountBits(shape,NULL,NULL);
2483 swf_SetShapeBits(i->tag,shape);
2484 swf_ShapeSetAll(i->tag,shape,/*x*/0,/*y*/0,/*ls*/0,fsid,0);
2485 i->swflastx = i->swflasty = 0;
2486 drawgfxline(obj, line);
2487 swf_ShapeSetEnd(i->tag);
2488 swf_ShapeFree(shape);
2490 i->tag = swf_InsertTag(i->tag,ST_PLACEOBJECT2);
2491 CXFORM cxform2 = gfxcxform_to_cxform(cxform);
2492 swf_ObjectPlace(i->tag,myshapeid,/*depth*/i->depth++,&i->page_matrix,&cxform2,NULL);
2495 #define IMAGE_TYPE_JPEG 0
2496 #define IMAGE_TYPE_LOSSLESS 1
2498 static void swfoutput_drawimage(struct swfoutput*obj, RGBA* data, int sizex,int sizey,
2499 double x1,double y1,
2500 double x2,double y2,
2501 double x3,double y3,
2502 double x4,double y4, int type)
2504 swfoutput_internal*i = (swfoutput_internal*)obj->internal;
2508 double l1 = sqrt((x4-x1)*(x4-x1) + (y4-y1)*(y4-y1));
2509 double l2 = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
2511 gfxline_t p1,p2,p3,p4,p5;
2512 p1.type=gfx_moveTo;p1.x=x1; p1.y=y1;p1.next=&p2;
2513 p2.type=gfx_lineTo;p2.x=x2; p2.y=y2;p2.next=&p3;
2514 p3.type=gfx_lineTo;p3.x=x3; p3.y=y3;p3.next=&p4;
2515 p4.type=gfx_lineTo;p4.x=x4; p4.y=y4;p4.next=&p5;
2516 p5.type=gfx_lineTo;p5.x=x1; p5.y=y1;p5.next=0;
2518 {p1.x = (int)(p1.x*20)/20.0;
2519 p1.y = (int)(p1.y*20)/20.0;
2520 p2.x = (int)(p2.x*20)/20.0;
2521 p2.y = (int)(p2.y*20)/20.0;
2522 p3.x = (int)(p3.x*20)/20.0;
2523 p3.y = (int)(p3.y*20)/20.0;
2524 p4.x = (int)(p4.x*20)/20.0;
2525 p4.y = (int)(p4.y*20)/20.0;
2526 p5.x = (int)(p5.x*20)/20.0;
2527 p5.y = (int)(p5.y*20)/20.0;
2534 m.m00 = (p4.x-p1.x)/sizex;
2535 m.m01 = (p1.x-p2.x)/sizey;
2536 m.m10 = -(p4.y-p1.y)/sizex;
2537 m.m11 = -(p1.y-p2.y)/sizey;
2542 img.data = (gfxcolor_t*)data;
2546 if(type == IMAGE_TYPE_JPEG)
2547 /* TODO: pass image_dpi to device instead */
2548 i->device.setparameter(&i->device, "next_bitmap_is_jpeg", "1");
2550 i->device.fillbitmap(&i->device, &p1, &img, &m, 0);
2553 void swfoutput_drawimagejpeg(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2554 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2556 swfoutput_drawimage(obj,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_JPEG);
2559 void swfoutput_drawimagelossless(struct swfoutput*obj, RGBA*mem, int sizex,int sizey,
2560 double x1,double y1, double x2,double y2, double x3,double y3, double x4,double y4)
2562 swfoutput_drawimage(obj,mem,sizex,sizey,x1,y1,x2,y2,x3,y3,x4,y4, IMAGE_TYPE_LOSSLESS);
2565 int swf_setparameter(gfxdevice_t*dev, const char*key, const char*value)
2567 if(!strcmp(key, "next_bitmap_is_jpeg")) {
2568 ((swfoutput_internal*)dev->internal)->jpeg = 1;
2574 void swfoutput_setparameter(char*name, char*value)
2576 if(!strcmp(name, "jpegsubpixels")) {
2577 config_jpegsubpixels = atof(value);
2578 } else if(!strcmp(name, "ppmsubpixels")) {
2579 config_ppmsubpixels = atof(value);
2580 } else if(!strcmp(name, "drawonlyshapes")) {
2581 config_drawonlyshapes = atoi(value);
2582 } else if(!strcmp(name, "ignoredraworder")) {
2583 config_ignoredraworder = atoi(value);
2584 } else if(!strcmp(name, "filloverlap")) {
2585 config_filloverlap = atoi(value);
2586 } else if(!strcmp(name, "linksopennewwindow")) {
2587 config_opennewwindow = atoi(value);
2588 } else if(!strcmp(name, "opennewwindow")) {
2589 config_opennewwindow = atoi(value);
2590 } else if(!strcmp(name, "storeallcharacters")) {
2591 config_storeallcharacters = atoi(value);
2592 } else if(!strcmp(name, "enablezlib")) {
2593 config_enablezlib = atoi(value);
2594 } else if(!strcmp(name, "insertstop")) {
2595 config_insertstoptag = atoi(value);
2596 } else if(!strcmp(name, "protected")) {
2597 config_protect = atoi(value);
2598 } else if(!strcmp(name, "flashversion")) {
2599 config_flashversion = atoi(value);
2600 } else if(!strcmp(name, "minlinewidth")) {
2601 config_minlinewidth = atof(value);
2602 } else if(!strcmp(name, "jpegquality")) {
2603 int val = atoi(value);
2605 if(val>100) val=100;
2606 config_jpegquality = val;
2607 } else if(!strcmp(name, "splinequality")) {
2608 int v = atoi(value);
2609 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2611 config_splinemaxerror = v;
2612 } else if(!strcmp(name, "fontquality")) {
2613 int v = atoi(value);
2614 v = 500-(v*5); // 100% = 0.25 pixel, 0% = 25 pixel
2616 config_fontsplinemaxerror = v;
2618 fprintf(stderr, "unknown parameter: %s (=%s)\n", name, value);