added support for line caps.
authorkramm <kramm>
Wed, 30 Apr 2003 14:35:48 +0000 (14:35 +0000)
committerkramm <kramm>
Wed, 30 Apr 2003 14:35:48 +0000 (14:35 +0000)
pdf2swf/swfoutput.cc
pdf2swf/swfoutput.h

index 75f8bda..47ec619 100644 (file)
@@ -30,6 +30,8 @@ extern "C" {
 #define standardEncodingSize 335
 extern char *standardEncodingNames[standardEncodingSize];
 
+#define assert(a) 
+
 int opennewwindow=0;
 int ignoredraworder=0;
 int drawonlyshapes=0;
@@ -38,6 +40,8 @@ int storeallcharacters=0;
 int enablezlib=0;
 int insertstoptag=0;
 int flashversion=4;
+int splinemaxerror=1;
+int fontsplinemaxerror=1;
 static int flag_protected = 0;
 
 typedef unsigned char u8;
@@ -163,10 +167,10 @@ static void spline(TAG*tag,plotxy p0,plotxy p1,plotxy p2,plotxy p3,struct swfmat
 
     if(storefont) {
        /* fonts use a different approximation than shapes */
-       num = cspline_approximate(&c, q, 0.05, APPROXIMATE_RECURSIVE_BINARY);
+       num = cspline_approximate(&c, q, fontsplinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
        //num = cspline_approximate(&c, q, 10.0, APPROXIMATE_INFLECTION);
     } else {
-       num = cspline_approximate(&c, q, 0.05, APPROXIMATE_RECURSIVE_BINARY);
+       num = cspline_approximate(&c, q,     splinemaxerror/20.0, APPROXIMATE_RECURSIVE_BINARY);
     }
     for(t=0;t<num;t++) {
        if(!t) 
@@ -181,8 +185,27 @@ void resetdrawer()
     swflasty = 0;
 }
 
-/* draw a T1 outline. These are generated by pdf2swf and by t1lib.
-   (representing characters) */
+static void stopFill()
+{
+    if(lastwasfill)
+    {
+     swf_ShapeSetStyle(tag,shape,linestyleid,0x8000,0);
+     fillstylechanged = 1;
+     lastwasfill = 0;
+    }
+}
+static void startFill()
+{
+    if(!lastwasfill)
+    {
+     swf_ShapeSetStyle(tag,shape,0x8000,fillstyleid,0);
+     fillstylechanged = 1;
+     lastwasfill = 1;
+    }
+}
+
+/* draw a T1 outline. These are generated by pdf2swf and by t1lib
+   (representing characters). */
 void drawpath(TAG*tag, T1_OUTLINE*outline, struct swfmatrix*m, int log)
 {
     if(tag->id != ST_DEFINEFONT &&
@@ -272,6 +295,289 @@ void drawpath(TAG*tag, T1_OUTLINE*outline, struct swfmatrix*m, int log)
     }
 }
 
+plotxy getPivot(T1_OUTLINE*outline, int dir, double line_width, int end)
+{
+    T1_PATHPOINT next, next2;
+    double xv=0,yv=0, xv2=0, yv2=0;
+    plotxy p;
+    int two = 0;
+
+    if(!end) {
+       if(outline->type == T1_PATHTYPE_LINE) {
+           next = outline->dest;
+       } else {
+           next = ((T1_BEZIERSEGMENT*)outline)->B;
+           if(next.x==0 && next.y==0) {
+               next = ((T1_BEZIERSEGMENT*)outline)->C;
+           }
+           if(next.x==0 && next.y==0) {
+               next = ((T1_BEZIERSEGMENT*)outline)->dest;
+           }
+       }
+       next2 = next;
+       if(outline->last && outline->last->type != T1_PATHTYPE_MOVE) {
+           if(outline->type == T1_PATHTYPE_LINE) {
+               next2 = outline->last->dest;
+           } else {
+               T1_PATHPOINT c = ((T1_BEZIERSEGMENT*)(outline->last))->C;
+               T1_PATHPOINT b = ((T1_BEZIERSEGMENT*)(outline->last))->B;
+               next2.x = outline->last->dest.x - c.x;
+               next2.y = outline->last->dest.y - c.y;
+               if(next2.x==0 && next2.y==0) {
+                   next2.x = outline->last->dest.x - b.x;
+                   next2.y = outline->last->dest.y - b.y;
+               }
+               if(next2.x==0 && next2.y==0) {
+                   next2.x = outline->last->dest.x;
+                   next2.y = outline->last->dest.y;
+               }
+           }
+           two = 1;
+       }
+    } else {
+       if(outline->type == T1_PATHTYPE_LINE) {
+           next = outline->dest;
+       } else {
+           T1_PATHPOINT c = ((T1_BEZIERSEGMENT*)outline)->C;
+           T1_PATHPOINT b = ((T1_BEZIERSEGMENT*)outline)->B;
+           next.x = outline->dest.x - c.x;
+           next.y = outline->dest.y - c.y;
+           if(next.x==0 && next.y==0) {
+               next.x = outline->dest.x - b.x;
+               next.y = outline->dest.y - b.y;
+           }
+           if(next.x==0 && next.y==0) {
+               next.x = outline->dest.x;
+               next.y = outline->dest.y;
+           }
+       }
+       next2 = next;
+       if(outline->link && outline->link->type != T1_PATHTYPE_MOVE) {
+           if(outline->type == T1_PATHTYPE_LINE) {
+               next2 = outline->link->dest;
+           } else {
+               next2 = ((T1_BEZIERSEGMENT*)(outline->link))->B;
+               if(next2.x==0 && next2.y==0) {
+                   next2 = ((T1_BEZIERSEGMENT*)outline->link)->C;
+               }
+               if(next2.x==0 && next2.y==0) {
+                   next2 = ((T1_BEZIERSEGMENT*)outline->link)->dest;
+               }
+           }
+           two = 1;
+       }
+    }
+
+    if(dir) {
+       xv =  next.y/(float)0xffff;
+       yv = -next.x/(float)0xffff;
+    } else {
+       xv = -next.y/(float)0xffff;
+       yv =  next.x/(float)0xffff;
+    }
+
+    double r = line_width/sqrt(xv*xv+yv*yv);
+    xv*=r;
+    yv*=r;
+
+    if(two) {
+       if(dir) {
+           xv2 =  next2.y/(float)0xffff;
+           yv2 = -next2.x/(float)0xffff;
+       } else {
+           xv2 = -next2.y/(float)0xffff;
+           yv2 =  next2.x/(float)0xffff;
+       }
+
+       double r2 = line_width/sqrt(xv2*xv2+yv2*yv2);
+       xv2*=r2;
+       yv2*=r2;
+       xv = (xv+xv2)/2;
+       yv = (yv+yv2)/2;
+       double r3 = line_width/sqrt(xv*xv+yv*yv);
+       xv *= r3;
+       yv *= r3;
+    }
+
+    p.x = xv;
+    p.y = yv;
+    return p;
+}
+
+void drawShortPath(struct swfoutput*output, double x, double y, struct swfmatrix* m, T1_OUTLINE*outline, int num, int line_cap, int line_join, double line_width)
+{
+    double lastx=x, lasty=y;
+    plotxy d,d2;
+    int back = 0;
+
+    if(line_cap == LINE_CAP_BUTT || line_cap == LINE_CAP_SQUARE) {
+       endshape();
+       startshape(output);
+       T1_OUTLINE *last, *tmp=outline;
+       plotxy s,e,p0,p1,p2,p3,m0,m1,m2,m3;
+       double x2 = x;
+       double y2 = y;
+       double lx=x,ly=y;
+       int nr;
+       while(tmp && tmp->type != T1_PATHTYPE_MOVE) {
+           last = tmp;
+           lx += (tmp->dest.x/(float)0xffff);
+           ly += (tmp->dest.y/(float)0xffff);
+           tmp = tmp->link;
+       }
+       s = getPivot(outline, 0, line_width, 0);
+       e = getPivot(last, 0, line_width, 1);
+
+       s.x/=2;
+       s.y/=2;
+       e.x/=2;
+       e.y/=2;
+
+       p0.x = x2 + s.x; 
+       p0.y = y2 + s.y;
+       p1.x = x2 - s.x; 
+       p1.y = y2 - s.y;
+       p2.x = x2 - s.y - s.x; 
+       p2.y = y2 + s.x - s.y;
+       p3.x = x2 - s.y + s.x; 
+       p3.y = y2 + s.x + s.y;
+       m0.x = lx + e.x; 
+       m0.y = ly + e.y;
+       m1.x = lx - e.x; 
+       m1.y = ly - e.y;
+       m2.x = lx + e.y - e.x; 
+       m2.y = ly - e.x - e.y;
+       m3.x = lx + e.y + e.x; 
+       m3.y = ly - e.x + e.y;
+
+       for(nr=0;nr<2;nr++) {
+           int dir=0;
+           struct plotxy q0,q1,q2,q3,q4,q5;
+           startFill();
+           if(line_cap == LINE_CAP_BUTT) {
+               if(dir) {
+                   q0.x = 0; q0.y = 0;
+                   q1.x = sizex; q1.y = 0;
+                   q2.x = sizex; q2.y = sizey;
+                   q3.x = 0; q3.y = sizey;
+               } else {
+                   q0.x = sizex; q0.y = sizey;
+                   q1.x = 0; q1.y = sizey;
+                   q2.x = 0; q2.y = 0;
+                   q3.x = sizex; q3.y = 0;
+               }
+               q4.x = p0.x; 
+               q4.y = p0.y;
+               moveto(tag, q0);
+               lineto(tag, q1);
+               lineto(tag, q2);
+               lineto(tag, q3);
+               lineto(tag, q0);
+
+               transform(&q4,m);
+               lineto(tag, q4);
+           }
+
+           line(tag, p0, p1, m);
+           line(tag, p1, p2, m);
+           line(tag, p2, p3, m);
+           line(tag, p3, p0, m);
+
+           if(line_cap == LINE_CAP_BUTT) {
+               lineto(tag, q0);
+               swf_ShapeSetEnd(tag);
+               tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
+               swf_ObjectPlaceClip(tag,shapeid,depth,NULL,NULL,NULL,depth+2-nr);
+               depth++;
+               shapeid = -1;
+               startshape(output);
+           }
+           p0 = m0;
+           p1 = m1;
+           p2 = m2;
+           p3 = m3;
+       }
+
+       stopFill();
+    }
+
+    while (outline && outline->type != T1_PATHTYPE_MOVE)
+    {
+        x += (outline->dest.x/(float)0xffff);
+        y += (outline->dest.y/(float)0xffff);
+
+        if(outline->type == T1_PATHTYPE_LINE)
+        {
+            plotxy p0, p1;
+            p0.x=lastx;
+           p0.y=lasty;
+            p1.x= x; 
+           p1.y= y;
+            line(tag, p0, p1, m);
+        }
+        else if(outline->type == T1_PATHTYPE_BEZIER)
+        {
+            plotxy p0,p1,p2,p3;
+            T1_BEZIERSEGMENT*o2 = (T1_BEZIERSEGMENT*)outline;
+            p3.x=lastx;
+           p3.y=lasty;
+            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;
+            p0.x=x; 
+           p0.y=y;
+            spline(tag,p0,p1,p2,p3,m);
+        } 
+        lastx=x;
+        lasty=y;
+        outline = outline->link;
+    }
+    if(line_cap == LINE_CAP_BUTT) {
+       endshape();
+    }
+}
+
+void drawpath2poly(struct swfoutput *output, T1_OUTLINE*outline, struct swfmatrix*m, int log, int line_join, int line_cap, double line_width, double miter_limit)
+{
+    if(tag->id != ST_DEFINEFONT &&
+        tag->id != ST_DEFINESHAPE &&
+        tag->id != ST_DEFINESHAPE2 &&
+        tag->id != ST_DEFINESHAPE3) {
+        logf("<error> internal error: drawpath needs a shape tag, not %d\n",tag->id);
+        exit(1);
+    }
+    double x=0,y=0;
+    double lastx=0,lasty=0;
+    int valid = 0;
+    T1_OUTLINE*tmp = outline, *last = 0;
+    tmp->last = 0;
+
+    while(tmp) {
+        x += (tmp->dest.x/(float)0xffff);
+        y += (tmp->dest.y/(float)0xffff);
+        if(tmp->type == T1_PATHTYPE_MOVE) {
+           if(valid && last) {
+               drawShortPath(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
+           }
+           valid = 0;
+           last = 0;
+           lastx = x;
+           lasty = y;
+       } else {
+           if(!last)
+               last = tmp;
+           valid++;
+       }
+       if(tmp->link)
+           tmp->link->last = tmp; // make sure list is properly linked in both directions
+       tmp = tmp->link;
+    }
+    if(valid && last) {
+       drawShortPath(output, lastx, lasty, m, last, valid, line_cap, line_join, line_width);
+    }
+}
+
 static inline int colorcompare(RGBA*a,RGBA*b)
 {
 
@@ -486,11 +792,7 @@ static void drawchar(struct swfoutput*obj, SWFFont*font, char*character, int cha
         if(shapeid<0)
             startshape(obj);
 
-        if(!lastwasfill) {
-         swf_ShapeSetStyle(tag,shape,0x8000,fillstyleid,0);
-        fillstylechanged = 1;
-       }
-        lastwasfill = 1;
+       startFill();
 
         int lf = fill;
         fill = 1;
@@ -516,22 +818,27 @@ void swfoutput_drawpath(swfoutput*output, T1_OUTLINE*outline,
     if(shapeid<0)
         startshape(output);
 
-    if(lastwasfill && !fill)
-    {
-     swf_ShapeSetStyle(tag,shape,linestyleid,0x8000,0);
-     fillstylechanged = 1;
-     lastwasfill = 0;
-    }
-    if(!lastwasfill && fill)
-    {
-     swf_ShapeSetStyle(tag,shape,0x8000,fillstyleid,0);
-     fillstylechanged = 1;
-     lastwasfill = 1;
-    }
+    if(!fill)
+       stopFill();
+    else
+       startFill();
 
     drawpath(tag, outline,m, 0); 
 }
 
+void swfoutput_drawpath2poly(struct swfoutput*output, T1_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit)
+{
+    if(textid>=0)
+        endtext();
+    if(shapeid>=0)
+       endshape();
+    assert(shapeid<0);
+    startshape(output);
+    stopFill();
+
+    drawpath2poly(output, outline, m, 0, line_join, line_cap, line_width, miter_limit); 
+}
+
 /* SWFFont: copy all t1 font outlines to a local 
    array. */
 SWFFont::SWFFont(char*name, int id, char*filename)
index 5bd8ee0..fa5b174 100644 (file)
@@ -27,6 +27,8 @@ extern int jpegquality; //default:100;
 extern int storeallcharacters; // default:0
 extern int insertstoptag; //default:0
 extern int flashversion; //default:4
+extern int splinemaxerror; //default:1
+extern int fontsplinemaxerror; //default:1
 
 typedef long int twip;
 
@@ -103,6 +105,13 @@ void swfoutput_setlinewidth(struct swfoutput*, double linewidth);
 
 void swfoutput_drawchar(struct swfoutput*,double x,double y,char*a, int charnr);
 void swfoutput_drawpath(struct swfoutput*, T1_OUTLINE*outline, struct swfmatrix*m);
+#define LINE_CAP_BUTT 0
+#define LINE_CAP_ROUND 1 
+#define LINE_CAP_SQUARE 2
+#define LINE_JOIN_MITER 0 
+#define LINE_JOIN_ROUND 1
+#define LINE_JOIN_BEVEL 2
+void swfoutput_drawpath2poly(struct swfoutput*, T1_OUTLINE*outline, struct swfmatrix*m, int line_join, int line_cap, double line_width, double miter_limit);
 void swfoutput_startclip(struct swfoutput*, T1_OUTLINE*outline, struct swfmatrix*m);
 void swfoutput_endclip(struct swfoutput*);
 int swfoutput_drawimagejpeg(struct swfoutput*, RGBA*pic, int sizex,int sizey,