diff options
Diffstat (limited to 'pdf2swf/swfoutput.cc')
-rw-r--r-- | pdf2swf/swfoutput.cc | 594 |
1 files changed, 594 insertions, 0 deletions
diff --git a/pdf2swf/swfoutput.cc b/pdf2swf/swfoutput.cc new file mode 100644 index 00000000..8636bba4 --- /dev/null +++ b/pdf2swf/swfoutput.cc @@ -0,0 +1,594 @@ +/* swfoutput.cc + Implements generation of swf files using the rfxswf lib. The routines + in this file are called from pdf2swf. + + This file is part of swftools. + + Swftools is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Swftools is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with swftools; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include "swfoutput.h" +#include "spline.h" +extern "C" { +#include "../lib/log.h" +#include "../lib/rfxswf.h" +} + +typedef unsigned char u8; +typedef unsigned short int u16; +typedef unsigned long int u32; + +static int fi; +static int flag_protected; +static SWF swf; +static TAG *tag; +static int shapeid = -1; +static int shapecount = 0; +static SHAPE* shape; +static int fillstyleid; +static int linestyleid; +static int swflastx=0; +static int swflasty=0; +static int lastwasfill = 0; +static char* filename = 0; +static int sizex; +static int sizey; +static char fill = 0; +static int depth = 1; +static int startdepth = 1; +TAG* cliptags[128]; +int clipshapes[128]; +u32 clipdepths[128]; +int clippos = 0; + +void startshape(struct swfoutput* obj); + +// matrix multiplication. changes p0 +void transform (plotxy*p0,struct swfmatrix*m) +{ + double x,y; + x = m->m11*p0->x+m->m12*p0->y; + y = m->m21*p0->x+m->m22*p0->y; + p0->x = x + m->m13; + p0->y = y + m->m23; +} + +// write a move-to command into the swf +void moveto(plotxy p0) +{ + int rx = (int)(p0.x*20); + int ry = (int)(p0.y*20); + if(rx!=swflastx || ry!=swflasty) { + ShapeSetMove (tag, shape, rx,ry); + } + swflastx=rx; + swflasty=ry; +} + +// write a line-to command into the swf +void lineto(plotxy p0) +{ + int rx = ((int)(p0.x*20)-swflastx); + int ry = ((int)(p0.y*20)-swflasty); + /* we can't skip this for rx=0,ry=0, those + are plots */ + ShapeSetLine (tag, shape, rx,ry); + swflastx+=rx; + swflasty+=ry; +} + +// write a spline-to command into the swf +void splineto(plotxy control,plotxy end) +{ + int cx = ((int)(control.x*20)-swflastx); + int cy = ((int)(control.y*20)-swflasty); + swflastx += cx; + swflasty += cy; + int ex = ((int)(end.x*20)-swflastx); + int ey = ((int)(end.y*20)-swflasty); + swflastx += ex; + swflasty += ey; + ShapeSetCurve(tag, shape, cx,cy,ex,ey); +} + +/* write a line, given two points and the transformation + matrix. */ +void line(plotxy p0, plotxy p1, struct swfmatrix*m) +{ + transform(&p0,m); + transform(&p1,m); + moveto(p0); + lineto(p1); +} + +/* write a cubic (!) spline. This involves calling the approximate() + function out of spline.cc to convert it to a quadratic spline. */ +void spline(plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmatrix*m) +{ + double d; + struct qspline q[16]; + int num; + int t; + transform(&p0,m); + transform(&p1,m); + transform(&p2,m); + transform(&p3,m); + + num = approximate(p0,p1,p2,p3,q); + for(t=0;t<num;t++) { + moveto(q[t].start); + splineto(q[t].control, q[t].end); + } +} + +/* Adds an outline to a font. Applies only the 2x2 component of the transformation matrix. + */ +void addtofont(T1_OUTLINE*outline, struct swfmatrix*m, char*namehint) +{ +} + +/* draw a T1 outline. These are generated by pdf2swf and by t1lib. + (representing characters) */ +void drawpath(T1_OUTLINE*outline, struct swfmatrix*m, char*namehint) +{ + double x=0,y=0; + double lastx=0,lasty=0; + + while (outline) + { + logf("<debug> Pathtype:%s",outline->type == T1_PATHTYPE_MOVE?"MOVE": + (outline->type == T1_PATHTYPE_LINE?"LINE" + :"BEZIER")); + logf("<debug> relative coordinates: %08x,%08x", outline->dest.x, outline->dest.y); + x += (outline->dest.x/(float)0xffff); + y += (outline->dest.y/(float)0xffff); + logf("<debug> coordinates: %f,%f", x, y); + if(outline->type == T1_PATHTYPE_MOVE) + { + } + else if(outline->type == T1_PATHTYPE_LINE) + { + plotxy p0; + plotxy p1; + p0.x=lastx; + p0.y=lasty; + p1.x=x; + p1.y=y; + line(p0,p1,m); + } + else if(outline->type == T1_PATHTYPE_BEZIER) + { + plotxy p0; + plotxy p1; + plotxy p2; + plotxy p3; + T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline; + p0.x=x; + p0.y=y; + p1.x=o2->C.x/(float)0xffff+lastx; + p1.y=o2->C.y/(float)0xffff+lasty; + p2.x=o2->B.x/(float)0xffff+lastx; + p2.y=o2->B.y/(float)0xffff+lasty; + p3.x=lastx; + p3.y=lasty; + spline(p0,p1,p2,p3,m); + } + else { + logf("<error> drawpath: unknown outline type:%d\n", outline->type); + } + lastx=x; + lasty=y; + outline = outline->link; + } +} + +/* process a character. */ +void drawchar(struct swfoutput*obj, int t1fontindex, char character, swfmatrix*m) +{ + + /* <T1 stuff> */ + T1_OUTLINE*outline; + int width = T1_GetCharWidth(t1fontindex, character); + BBox bbox = T1_GetCharBBox(t1fontindex, character); + char*charname= T1_GetCharName(t1fontindex, character); + logf("<debug> Font name is %s", T1_GetFontFileName(t1fontindex)); + logf("<debug> char 0x%02x is named %s\n",character,charname); + logf("<debug> bbox: %d %d %d %d\n",bbox.llx,bbox.lly,bbox.urx,bbox.ury); + if(!charname || charname[0] == '.') + { + /* for newline, we don't print an error. FIXME: We shouldn't get newlines here + in the first place + */ + if(character != '\n') { + logf("<error> Char to set is not defined!"); + logf("<error> - font file is %s\n", T1_GetFontFileName(t1fontindex)); + logf("<error> - char 0x%02x is named %s\n",character,charname); + } + return; + } + swfmatrix m2=*m; + m2.m11/=100; + m2.m21/=100; + m2.m12/=100; + m2.m22/=100; + outline = T1_GetCharOutline( t1fontindex, character, 100.0, 0); + + /** </T1 stuff> **/ + + if(shapeid<0) + startshape(obj); + + if(!lastwasfill) + ShapeSetStyle(tag,shape,0x8000,fillstyleid,0); + lastwasfill = 1; + + drawpath(outline, &m2, charname); +} + +/* draw a curved polygon. */ +void swfoutput_drawpath(swfoutput*output, T1_OUTLINE*outline, struct swfmatrix*m) +{ + if(shapeid<0) + startshape(output); + + if(lastwasfill && !fill) + { + ShapeSetStyle(tag,shape,linestyleid,0x8000,0); + lastwasfill = 0; + } + if(!lastwasfill && fill) + { + ShapeSetStyle(tag,shape,0x8000,fillstyleid,0); + lastwasfill = 1; + } + + drawpath(outline,m, 0); +} + + +/* set's the t1 font index of the font to use for swfoutput_drawchar(). */ +int swfoutput_setfont(struct swfoutput*obj, int t1id) +{ + obj->t1font = t1id; +} + +/* set's the matrix which is to be applied to characters drawn by + swfoutput_drawchar() */ +void swfoutput_setfontmatrix(struct swfoutput*obj,double m11,double m12, + double m21,double m22) +{ + obj->fontm11 = m11; + obj->fontm12 = m12; + obj->fontm21 = m21; + obj->fontm22 = m22; +} + +/* draws a character at x,y. */ +void swfoutput_drawchar(struct swfoutput* obj,double x,double y,char character) +{ + swfmatrix m; + m.m11 = obj->fontm11; + m.m12 = obj->fontm12; + m.m21 = obj->fontm21; + m.m22 = obj->fontm22; + m.m13 = x; + m.m23 = y; + drawchar(obj, obj->t1font, character, &m); +} + +/* initialize the swf writer */ +void swfoutput_init(struct swfoutput* obj, char*_filename, int _sizex, int _sizey) +{ + GLYPH *glyph; + RGBA rgb; + SRECT r; + memset(obj, 0, sizeof(struct swfoutput)); + filename = _filename; + sizex = _sizex; + sizey = _sizey; + + logf("<verbose> initializing swf output for size %d*%d\n", sizex,sizey); + + obj->t1font = 0; + + memset(&swf,0x00,sizeof(SWF)); + + swf.FileVersion = 4; +// swf.FrameRate = 0x1900; + swf.FrameRate = 0x0040; // 1 frame per 4 seconds + swf.MovieSize.xmax = 20*sizex; + swf.MovieSize.ymax = 20*sizey; + + swf.FirstTag = InsertTag(NULL,ST_SETBACKGROUNDCOLOR); + tag = swf.FirstTag; + rgb.r = 0xff; + rgb.g = 0xff; + rgb.b = 0xff; + SetRGB(tag,&rgb); + if(flag_protected) + tag = InsertTag(tag, ST_PROTECT); + depth = 1; + startdepth = depth; +} + +void swfoutput_setprotected() //write PROTECT tag +{ + flag_protected = 1; +} + +void startshape(struct swfoutput*obj) +{ + RGBA rgb; + SRECT r; + tag = InsertTag(tag,ST_DEFINESHAPE); + + NewShape(&shape); + linestyleid = ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb); + rgb.r = obj->fillrgb.r; + rgb.g = obj->fillrgb.g; + rgb.b = obj->fillrgb.b; + fillstyleid = ShapeAddSolidFillStyle(shape,&obj->fillrgb); + + shapeid = ++shapecount; + SetU16(tag,shapeid); // ID + + r.xmin = 0; + r.ymin = 0; + r.xmax = 20*sizex; + r.ymax = 20*sizey; + + SetRect(tag,&r); + + SetShapeStyles(tag,shape); + ShapeCountBits(shape,NULL,NULL); + SetShapeBits(tag,shape); + + ShapeSetAll(tag,shape,/*x*/0,/*y*/0,linestyleid,0,0); + swflastx=swflasty=0; + lastwasfill = 0; +} + +void endshape() +{ + if(shapeid<0) + return; + ShapeSetEnd(tag); + tag = InsertTag(tag,ST_PLACEOBJECT2); + ObjectPlace(tag,shapeid,/*depth*/depth++,NULL,NULL,NULL); + shapeid = -1; +} + +void endpage(struct swfoutput*obj) +{ + if(shapeid>=0) + endshape(); + while(clippos) + swfoutput_endclip(obj); + tag = InsertTag(tag,ST_SHOWFRAME); +} + +void swfoutput_newpage(struct swfoutput*obj) +{ + endpage(obj); + + for(depth--;depth>=startdepth;depth--) { + tag = InsertTag(tag,ST_REMOVEOBJECT2); + SetU16(tag,depth); + } + + depth = 1; + startdepth = depth; +} + +/* "destroy" like in (oo-terminology) "destructor". Perform cleaning + up, complete the swf, and write it out. */ +void swfoutput_destroy(struct swfoutput* obj) +{ + endpage(obj); + + T1_CloseLib(); + if(!filename) + return; + if(filename) + fi = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0777); + else + fi = 1; // stdout + + if(fi<=0) { + logf("<fatal> Could not create \"%s\". ", filename); + exit(1); + } + + tag = InsertTag(tag,ST_END); + + if FAILED(WriteSWF(fi,&swf)) + logf("<error> WriteSWF() failed.\n"); + if(filename) + close(fi); + printf("SWF written\n"); +} + +void swfoutput_setdrawmode(swfoutput* obj, int mode) +{ + if(mode == DRAWMODE_FILL) + fill = 1; + else if(mode == DRAWMODE_EOFILL) + fill = 1; + else if(mode == DRAWMODE_STROKE) + fill = 0; + else if(mode == DRAWMODE_CLIP) + fill = 1; + else if(mode == DRAWMODE_EOCLIP) + fill = 1; +} + +void swfoutput_setfillcolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a) +{ + if(shape>=0) + endshape(); + obj->fillrgb.r = r; + obj->fillrgb.g = g; + obj->fillrgb.b = b; + obj->fillrgb.a = a; +} + +void swfoutput_setstrokecolor(swfoutput* obj, u8 r, u8 g, u8 b, u8 a) +{ + if(shape>=0) + endshape(); + obj->strokergb.r = r; + obj->strokergb.g = g; + obj->strokergb.b = b; + obj->strokergb.a = a; +} + +void swfoutput_setlinewidth(struct swfoutput*obj, double linewidth) +{ + if(shape>=0) + endshape(); + obj->linewidth = (u16)(linewidth*20); +} + + +void swfoutput_startclip(swfoutput*obj, T1_OUTLINE*outline, struct swfmatrix*m) +{ + if(shape>=0) + endshape(); + + if(clippos >= 127) + { + logf("<warning> Too many clip levels."); + clippos --; + } + + startshape(obj); + + swfoutput_setdrawmode(obj, DRAWMODE_CLIP); + swfoutput_drawpath(obj, outline, m); + + ShapeSetEnd(tag); + tag = InsertTag(tag,ST_PLACEOBJECT2); + cliptags[clippos] = tag; + clipshapes[clippos] = shapeid; + clipdepths[clippos] = depth++; + clippos++; + shapeid = -1; +} + +void swfoutput_endclip(swfoutput*obj) +{ + if(shape>=0) + endshape(); + + if(!clippos) { + logf("<error> Invalid end of clipping region"); + return; + } + clippos--; + PlaceObject(cliptags[clippos],clipshapes[clippos],clipdepths[clippos],NULL,NULL,NULL,depth++); +} + +void swfoutput_drawimagefile(struct swfoutput*, char*filename, int sizex,int sizey, + double x1,double y1, + double x2,double y2, + double x3,double y3, + double x4,double y4) +{ + RGBA rgb; + SRECT r; + int lsid=0; + int fsid; + int bitid; + struct plotxy p1,p2,p3,p4; + int myshapeid; + double xmax=x1,ymax=y1,xmin=x1,ymin=y1; + if(x2>xmax) xmax=x2; + if(y2>ymax) ymax=y2; + if(x2<xmin) xmin=x2; + if(y2<ymin) ymin=y2; + if(x3>xmax) xmax=x3; + if(y3>ymax) ymax=y3; + if(x3<xmin) xmin=x3; + if(y3<ymin) ymin=y3; + if(x4>xmax) xmax=x4; + if(y4>ymax) ymax=y4; + if(x4<xmin) xmin=x4; + if(y4<ymin) ymin=y4; + p1.x=x1; + p1.y=y1; + p2.x=x2; + p2.y=y2; + p3.x=x3; + p3.y=y3; + p4.x=x4; + p4.y=y4; + + MATRIX m; + m.sx = (int)(65536*20*(x4-x1))/sizex; + m.r1 = -(int)(65536*20*(y4-y1))/sizex; + m.r0 = (int)(65536*20*(x1-x2))/sizey; + m.sy = -(int)(65536*20*(y1-y2))/sizey; + + m.tx = (int)(x1*20); + m.ty = (int)(y1*20); + + if(shape>=0) + endshape(); + + bitid = ++shapecount; + + /* bitmap */ + tag = InsertTag(tag,ST_DEFINEBITSJPEG2); + SetU16(tag, bitid); + SetJPEGBits(tag, filename, 85); + + /* shape */ + myshapeid = ++shapecount; + tag = InsertTag(tag,ST_DEFINESHAPE); + NewShape(&shape); + //lsid = ShapeAddLineStyle(shape,obj->linewidth,&obj->strokergb); + //fsid = ShapeAddSolidFillStyle(shape,&obj->fillrgb); + fsid = ShapeAddBitmapFillStyle(shape,&m,bitid,0); + SetU16(tag, myshapeid); + r.xmin = (int)(xmin*20); + r.ymin = (int)(ymin*20); + r.xmax = (int)(xmax*20); + r.ymax = (int)(ymax*20); + SetRect(tag,&r); + SetShapeStyles(tag,shape); + ShapeCountBits(shape,NULL,NULL); + SetShapeBits(tag,shape); + ShapeSetAll(tag,shape,/*x*/0,/*y*/0,lsid,fsid,0); + swflastx = swflasty = 0; + moveto(p1); + lineto(p2); + lineto(p3); + lineto(p4); + lineto(p1); + /* + ShapeMoveTo (tag, shape, (int)(x1*20),(int)(y1*20)); + ShapeSetLine (tag, shape, (int)(x1*20); + ShapeSetLine (tag, shape, x*20,0); + ShapeSetLine (tag, shape, 0,-y*20); + ShapeSetLine (tag, shape, -x*20,0);*/ + ShapeSetEnd(tag); + + /* instance */ + tag = InsertTag(tag,ST_PLACEOBJECT2); + ObjectPlace(tag,myshapeid,/*depth*/depth++,NULL,NULL,NULL); +} + |