X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=blobdiff_plain;f=lib%2Fgfxtools.c;h=e79e6fefd672f78c7a7c71a3213fd8d6f1a2df2e;hp=76525ea502ed72578aa21390bbd6c6c234334aa7;hb=bf04757cd94e94c1f67fa3d2a4e3e59fa5bce0c0;hpb=a5c6cfc6f6b4ffdcee8e63116b0c507b0388cac0 diff --git a/lib/gfxtools.c b/lib/gfxtools.c index 76525ea..e79e6fe 100644 --- a/lib/gfxtools.c +++ b/lib/gfxtools.c @@ -1,10 +1,10 @@ -/* gfxtools.c +/* gfxtools.c Various utility functions for dealing with gfxdevices. Part of the swftools package. - Copyright (c) 2005 Matthias Kramm + Copyright (c) 2005 Matthias Kramm This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,10 +21,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include +#include #include #include +#include #include #include "gfxtools.h" +#include "gfxfont.h" typedef struct _linedraw_internal { @@ -35,7 +38,7 @@ typedef struct _linedraw_internal static void linedraw_moveTo(gfxdrawer_t*d, gfxcoord_t x, gfxcoord_t y) { linedraw_internal_t*i = (linedraw_internal_t*)d->internal; - gfxline_t*l = rfx_alloc(sizeof(gfxline_t)); + gfxline_t*l = (gfxline_t*)rfx_alloc(sizeof(gfxline_t)); l->type = gfx_moveTo; if((int)((d->x * 5120) == (int)(x * 5120)) && (int)((d->y * 5120) == (int)(y * 5120))) { @@ -43,6 +46,7 @@ static void linedraw_moveTo(gfxdrawer_t*d, gfxcoord_t x, gfxcoord_t y) return; } + l->sx = l->sy = 0; d->x = l->x = x; d->y = l->y = y; l->next = 0; @@ -55,7 +59,7 @@ static void linedraw_moveTo(gfxdrawer_t*d, gfxcoord_t x, gfxcoord_t y) static void linedraw_lineTo(gfxdrawer_t*d, gfxcoord_t x, gfxcoord_t y) { linedraw_internal_t*i = (linedraw_internal_t*)d->internal; - gfxline_t*l = rfx_alloc(sizeof(gfxline_t)); + gfxline_t*l = (gfxline_t*)rfx_alloc(sizeof(gfxline_t)); if(!i->start) { /* starts with a line, not with a moveto. That needs we first @@ -77,7 +81,7 @@ static void linedraw_lineTo(gfxdrawer_t*d, gfxcoord_t x, gfxcoord_t y) static void linedraw_splineTo(gfxdrawer_t*d, gfxcoord_t sx, gfxcoord_t sy, gfxcoord_t x, gfxcoord_t y) { linedraw_internal_t*i = (linedraw_internal_t*)d->internal; - gfxline_t*l = rfx_alloc(sizeof(gfxline_t)); + gfxline_t*l = (gfxline_t*)rfx_alloc(sizeof(gfxline_t)); if(!i->start) { /* starts with a line, not with a moveto. That needs we first @@ -86,9 +90,9 @@ static void linedraw_splineTo(gfxdrawer_t*d, gfxcoord_t sx, gfxcoord_t sy, gfxco } l->type = gfx_splineTo; - d->x = l->x = x; + d->x = l->x = x; d->y = l->y = y; - l->sx = sx; + l->sx = sx; l->sy = sy; l->next = 0; if(i->next) @@ -141,7 +145,7 @@ typedef struct cspline_t static void mkspline(qspline_abc_t*s, double x, double y, gfxline_t*l) { - /* + /* Form 1: x = t*t*l->x + 2*t*(1-t)*l->sx + (1-t)*(1-t)*x; Form 2: x = a*t*t + b*t + c */ @@ -178,7 +182,7 @@ static double get_spline_len(qspline_abc_t*s) double dy = s->ay*(2*i+1)*r2 + s->by*r; len += sqrt(dx*dx+dy*dy); } - /*printf("Spline from %f,%f to %f,%f has len %f (%f)\n", s->cx, s->cy, + /*printf("Spline from %f,%f to %f,%f has len %f (%f)\n", s->cx, s->cy, s->cx + s->bx + s->ax, s->cy + s->by + s->ay, len, sqrt((s->bx + s->ax)*(s->bx + s->ax) + (s->by + s->ay)*(s->by + s->ay)) @@ -193,14 +197,34 @@ void gfxtool_draw_dashed_line(gfxdrawer_t*d, gfxline_t*line, float*r, float phas double x=0,y=0; double linepos,nextpos; char on; - int apos; + int apos=0; if(line && line->type != gfx_moveTo) { fprintf(stderr, "gfxtool: outline doesn't start with a moveTo"); return; } - if(!r || r[0]<0 || phase<0) { - fprintf(stderr, "gfxtool: invalid dashes"); + + int i; + double dashlen=0; + for(i=0;r[i]>=0;i++) { + dashlen+=r[i]; + } + if(!r || (r[0]<=0 && r[0]>-0.01) || dashlen<0.001) { + // no dashing. just draw the thing + while(line) { + if(line->type == gfx_moveTo) { + d->moveTo(d, line->x, line->y); + } else if(line->type == gfx_lineTo) { + d->lineTo(d, line->x, line->y); + } else if(line->type == gfx_splineTo) { + d->splineTo(d, line->sx, line->sy, line->x, line->y); + } + line = line->next; + } + return; + } + if(r[0]<0 || phase<0) { + fprintf(stderr, "gfxtool: invalid (negative) dashes: %f, phase=%f", r[0], phase); return; } @@ -302,7 +326,7 @@ gfxline_t * gfxline_clone(gfxline_t*line) gfxline_t*dest = 0; gfxline_t*pos = 0; while(line) { - gfxline_t*n = rfx_calloc(sizeof(gfxline_t)); + gfxline_t*n = (gfxline_t*)rfx_calloc(sizeof(gfxline_t)); *n = *line; n->next = 0; if(!pos) { @@ -315,20 +339,31 @@ gfxline_t * gfxline_clone(gfxline_t*line) } return dest; } + +static char splineIsStraight(double x, double y, gfxline_t*l) +{ + if(l->type == gfx_moveTo) + return 0; + if(l->type == gfx_lineTo) + return 1; + double dx = l->x-x; + double dy = l->y-y; + double sx = l->sx-x; + double sy = l->sy-y; + if(fabs(dx*sy - dy*sx) < 0.000001 && (dx*sx + dy*sy) >= 0) { + return 1; + } + return 0; +} + void gfxline_optimize(gfxline_t*line) { gfxline_t*l = line; /* step 1: convert splines to lines, where possible */ double x=0,y=0; while(l) { - if(l->type == gfx_splineTo) { - double dx = l->x-x; - double dy = l->y-y; - double sx = l->sx-x; - double sy = l->sy-y; - if(fabs(dx*sy - dy*sx) < 0.000001 && (dx*sx + dy*sy) >= 0) { - l->type = gfx_lineTo; - } + if(l->type == gfx_splineTo && splineIsStraight(x,y,l)) { + l->type = gfx_lineTo; } x = l->x; y = l->y; @@ -343,8 +378,8 @@ void gfxline_optimize(gfxline_t*line) if(l->type == gfx_lineTo && next->type == gfx_lineTo) { double dx = l->x-x; double dy = l->y-y; - double nx = next->x-x; - double ny = next->y-y; + double nx = next->x-l->x; + double ny = next->y-l->y; if(fabs(dx*ny - dy*nx) < 0.000001 && (dx*nx + dy*ny) >= 0) { combine = 1; } @@ -438,7 +473,7 @@ static int approximate3(const cspline_t*s, qspline_t*q, int size, double quality unsigned int istart = 0; int num = 0; int level = 0; - + while(istart<0x80000000) { unsigned int iend = istart + istep; @@ -463,14 +498,14 @@ static int approximate3(const cspline_t*s, qspline_t*q, int size, double quality /* depending on where we are in the spline, we either try to match the left or right tangent */ - if(start<0.5) + if(start<0.5) left=1; /* get derivative */ pos = left?start:end; qpos = pos*pos; - test.control.x = s->end.x*(3*qpos) + 3*s->control2.x*(2*pos-3*qpos) + + test.control.x = s->end.x*(3*qpos) + 3*s->control2.x*(2*pos-3*qpos) + 3*s->control1.x*(1-4*pos+3*qpos) + s->start.x*(-3+6*pos-3*qpos); - test.control.y = s->end.y*(3*qpos) + 3*s->control2.y*(2*pos-3*qpos) + + test.control.y = s->end.y*(3*qpos) + 3*s->control2.y*(2*pos-3*qpos) + 3*s->control1.y*(1-4*pos+3*qpos) + s->start.y*(-3+6*pos-3*qpos); if(left) { test.control.x *= (end-start)/2; @@ -515,12 +550,12 @@ static int approximate3(const cspline_t*s, qspline_t*q, int size, double quality } #else // quadratic error: *much* faster! - /* convert control point representation to + /* convert control point representation to d*x^3 + c*x^2 + b*x + a */ dx= s->end.x - s->control2.x*3 + s->control1.x*3 - s->start.x; dy= s->end.y - s->control2.y*3 + s->control1.y*3 - s->start.y; - - /* we need to do this for the subspline between [start,end], not [0,1] + + /* we need to do this for the subspline between [start,end], not [0,1] as a transformation of t->a*t+b does nothing to highest coefficient of the spline except multiply it with a^3, we just need to modify d here. */ @@ -528,9 +563,9 @@ static int approximate3(const cspline_t*s, qspline_t*q, int size, double quality dx*=m*m*m; dy*=m*m*m; } - + /* use the integral over (f(x)-g(x))^2 between 0 and 1 - to measure the approximation quality. + to measure the approximation quality. (it boils down to const*d^2) */ recurse = (dx*dx + dy*dy > quality2); #endif @@ -576,7 +611,7 @@ void gfxdraw_cubicTo(gfxdrawer_t*draw, double c1x, double c1y, double c2x, doubl c.control2.y = c2y; c.end.x = x; c.end.y = y; - + num = approximate3(&c, q, 128, maxerror); for(t=0;txmin > box1->xmin) + box1->xmin = box2->xmin; + if(box2->ymin > box1->ymin) + box1->ymin = box2->ymin; + if(box2->xmax < box1->xmax) + box1->xmax = box2->xmax; + if(box2->ymax > box1->ymax) + box1->ymax = box2->ymax; + if(box1->xmin > box1->xmax) + box1->xmax = box1->xmin; + if(box1->ymin > box1->ymax) + box1->ymax = box1->ymin; +} + gfxbbox_t gfxline_getbbox(gfxline_t*line) { gfxcoord_t x=0,y=0; @@ -636,20 +687,6 @@ gfxbbox_t gfxline_getbbox(gfxline_t*line) return bbox; } -void gfxline_dump(gfxline_t*line, FILE*fi, char*prefix) -{ - while(line) { - if(line->type == gfx_moveTo) { - fprintf(fi, "%smoveTo %.2f %.2f\n", prefix, line->x, line->y); - } else if(line->type == gfx_lineTo) { - fprintf(fi, "%slineTo %.2f %.2f\n", prefix, line->x, line->y); - } else if(line->type == gfx_splineTo) { - fprintf(fi, "%ssplineTo (%.2f %.2f) %.2f %.2f\n", prefix, line->sx, line->sy, line->x, line->y); - } - line = line->next; - } -} - gfxline_t* gfxline_append(gfxline_t*line1, gfxline_t*line2) { gfxline_t*l = line1;; @@ -705,6 +742,21 @@ void gfxmatrix_invert(gfxmatrix_t*m, gfxmatrix_t*dest) dest->tx = -(dest->m00 * m->tx + dest->m10 * m->ty); dest->ty = -(dest->m01 * m->tx + dest->m11 * m->ty); } +void gfxmatrix_unit(gfxmatrix_t*m) +{ + memset(m, 0, sizeof(gfxmatrix_t)); + m->m00 = 1.0; + m->m11 = 1.0; +} +void gfxmatrix_multiply(gfxmatrix_t*m1, gfxmatrix_t*m2, gfxmatrix_t*dest) +{ + dest->m00 = m1->m00*m2->m00 + m1->m10*m2->m01; + dest->m01 = m1->m01*m2->m00 + m1->m11*m2->m01; + dest->m10 = m1->m00*m2->m10 + m1->m10*m2->m11; + dest->m11 = m1->m01*m2->m10 + m1->m11*m2->m11; + dest->tx = m1->m00*m2->tx + m1->m10*m2->ty + m1->tx; + dest->ty = m1->m01*m2->tx + m1->m11*m2->ty + m1->ty; +} gfxfontlist_t* gfxfontlist_create() { @@ -739,7 +791,7 @@ gfxfontlist_t*gfxfontlist_addfont(gfxfontlist_t*list, gfxfont_t*font) gfxfontlist_t*last=0,*l = list; while(l) { last = l; - if(!strcmp((char*)l->font->id, font->id)) { + if(l->font == font) { return list; // we already know this font } l = l->next; @@ -757,6 +809,19 @@ gfxfontlist_t*gfxfontlist_addfont(gfxfontlist_t*list, gfxfont_t*font) return l; } } +void gfxfontlist_free(gfxfontlist_t*list, char deletefonts) +{ + gfxfontlist_t*l = list; + while(l) { + gfxfontlist_t*next = l->next; + if(deletefonts && l->font) { + gfxfont_free(l->font);l->font=0; + } + l->next = 0; + free(l); + l = next; + } +} gfxline_t*gfxline_makerectangle(int x1,int y1,int x2, int y2) { @@ -768,3 +833,113 @@ gfxline_t*gfxline_makerectangle(int x1,int y1,int x2, int y2) line[4].x = x1;line[4].y = y1;line[4].type = gfx_lineTo; return line; } + +gfxbbox_t* gfxline_isrectangle(gfxline_t*_l) +{ + if(!_l) + return 0; + + gfxline_t*l = gfxline_clone(_l); + gfxline_optimize(l); + + double x1,x2,y1,y2; + int xc=0,yc=0; + char corners=0; + + char prev=0; + char fail=0; + for(;l; l=l->next) { + double x = l->x; + double y = l->y; + + char top=0,left=0; + + if(xc==2 && x!=x1 && x!=x2) {fail=1;break;} + else if(xc>=1 && x==x1) {left=0;} + else if(xc==2 && x==x2) {left=1;} + else if(xc==1 && x!=x1) {x2 = x; xc=2; left=1;} + else if(xc==0) {x1 = x; xc=1;left=0;} + else {fprintf(stderr, "Internal error in rectangle detection\n");} + + if(yc==2 && y!=y1 && y!=y2) {fail=1;break;} + else if(yc>=1 && y==y1) {top=0;} + else if(yc==2 && y==y2) {top=1;} + else if(yc==1 && y!=y1) {y2 = y; yc=2; top=1;} + else if(yc==0) {y1 = y; yc=1;top=0;} + else {fprintf(stderr, "Internal error in rectangle detection\n");} + + char pos=top<<1|left; + + if((pos^prev)==3) { + /* diagonal lines not allowed */ + fail=1;break; + } + prev = pos; + + /* no corner except the first one may be touched twice */ + if(pos && (corners & 1<xmin = x1; r->ymin = y1; + r->xmax = x2; r->ymax = y2; + return r; +} + +void gfximage_transform(gfximage_t*img, gfxcxform_t*cxform) +{ + int t; + int size = img->width*img->height; + + int rr,rg,rb,ra, tr; + int gr,gg,gb,ga, tg; + int br,bg,bb,ba, tb; + int ar,ag,ab,aa, ta; + rr = (int)(cxform->rr*256);gr = (int)(cxform->gr*256); + rg = (int)(cxform->rg*256);gg = (int)(cxform->gg*256); + rb = (int)(cxform->rb*256);gb = (int)(cxform->gb*256); + ra = (int)(cxform->ra*256);ga = (int)(cxform->ga*256); + br = (int)(cxform->br*256);ar = (int)(cxform->ar*256);tr = (int)(cxform->tr*256); + bg = (int)(cxform->bg*256);ag = (int)(cxform->ag*256);tg = (int)(cxform->tg*256); + bb = (int)(cxform->bb*256);ab = (int)(cxform->ab*256);tb = (int)(cxform->tb*256); + ba = (int)(cxform->ba*256);aa = (int)(cxform->aa*256);ta = (int)(cxform->ta*256); + + for(t=0;tdata[t]; + unsigned char r = (pixel->r * rr + pixel->g * rg + pixel->b * rb + pixel->a * ra + tr) / 256; + unsigned char g = (pixel->r * gr + pixel->g * gg + pixel->b * gb + pixel->a * ga + tg) / 256; + unsigned char b = (pixel->r * br + pixel->g * bg + pixel->b * bb + pixel->a * ba + tb) / 256; + unsigned char a = (pixel->r * ar + pixel->g * ag + pixel->b * ab + pixel->a * aa + ta) / 256; + pixel->r = r; + pixel->g = g; + pixel->b = b; + pixel->a = a; + } +} +void gfxline_dump(gfxline_t*line, FILE*fi, char*prefix) +{ + while(line) { + if(line->type == gfx_moveTo) { + fprintf(fi, "%smoveTo %.2f %.2f\n", prefix, line->x, line->y); + } else if(line->type == gfx_lineTo) { + fprintf(fi, "%slineTo %.2f %.2f\n", prefix, line->x, line->y); + } else if(line->type == gfx_splineTo) { + fprintf(fi, "%ssplineTo (%.2f %.2f) %.2f %.2f\n", prefix, line->sx, line->sy, line->x, line->y); + } + line = line->next; + } +} +