summaryrefslogtreecommitdiff
path: root/pdf2swf/swfoutput.cc
diff options
context:
space:
mode:
Diffstat (limited to 'pdf2swf/swfoutput.cc')
-rw-r--r--pdf2swf/swfoutput.cc594
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);
+}
+