X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=blobdiff_plain;f=lib%2Fdevices%2Frender.c;h=250356a271cabbf8f6a266dad21cfe578aa81544;hp=20c4dd800bc7d834bf21eb06f67aec4c85984a9c;hb=e321a0df2c56ff61602b13c1440465911b231f89;hpb=9ccf6217181fcc891d198ae75ebbd5d05b198b89 diff --git a/lib/devices/render.c b/lib/devices/render.c index 20c4dd8..250356a 100644 --- a/lib/devices/render.c +++ b/lib/devices/render.c @@ -24,11 +24,11 @@ #include #include "../gfxdevice.h" #include "../gfxtools.h" -#include "../png.h" #include "../mem.h" - -typedef unsigned int U32; -typedef unsigned char U8; +#include "../types.h" +#include "../png.h" +#include "../log.h" +#include "render.h" typedef gfxcolor_t RGBA; @@ -47,6 +47,7 @@ typedef struct _renderline typedef struct _internal_result { gfximage_t img; struct _internal_result*next; + char palette; } internal_result_t; typedef struct _clipbuffer { @@ -64,6 +65,9 @@ typedef struct _internal { int antialize; int zoom; int ymin, ymax; + int fillwhite; + + char palette; RGBA* img; @@ -75,15 +79,16 @@ typedef struct _internal { internal_result_t*result_next; } internal_t; -typedef enum {filltype_solid,filltype_clip,filltype_bitmap} filltype_t; +typedef enum {filltype_solid,filltype_clip,filltype_bitmap,filltype_gradient} filltype_t; typedef struct _fillinfo { - filltype_t type; //0=solid,1=clip + filltype_t type; gfxcolor_t*color; gfximage_t*image; gfxmatrix_t*matrix; gfxcxform_t*cxform; - char clip; + RGBA*gradient; + char linear_or_radial; } fillinfo_t; @@ -269,16 +274,16 @@ static void fill_line_solid(RGBA*line, U32*z, int y, int x1, int x2, RGBA col) if(col.a!=255) { int ainv = 255-col.a; - col.r = (col.r*col.a)>>8; - col.g = (col.g*col.a)>>8; - col.b = (col.b*col.a)>>8; - col.a = 255; + col.r = (col.r*col.a)/255; + col.g = (col.g*col.a)/255; + col.b = (col.b*col.a)/255; do { if(z[bitpos]&bit) { - line[x].r = ((line[x].r*ainv)>>8)+col.r; - line[x].g = ((line[x].g*ainv)>>8)+col.g; - line[x].b = ((line[x].b*ainv)>>8)+col.b; - line[x].a = 255; + line[x].r = ((line[x].r*ainv)/255)+col.r; + line[x].g = ((line[x].g*ainv)/255)+col.g; + line[x].b = ((line[x].b*ainv)/255)+col.b; + //line[x].a = 255; + line[x].a = ((line[x].a*ainv)/255)+col.a; } bit <<= 1; if(!bit) { @@ -305,7 +310,7 @@ static void fill_line_bitmap(RGBA*line, U32*z, int y, int x1, int x2, fillinfo_t gfxmatrix_t*m = info->matrix; gfximage_t*b = info->image; - if(!b->width || !b->height) { + if(!b || !b->width || !b->height) { gfxcolor_t red = {255,255,0,0}; fill_line_solid(line, z, y, x1, x2, red); return; @@ -332,7 +337,7 @@ static void fill_line_bitmap(RGBA*line, U32*z, int y, int x1, int x2, fillinfo_t int yy = (int)(yy1 - x * yinc1); int ainv; - if(info->clip) { + if(info->linear_or_radial) { if(xx<0) xx=0; if(xx>=b->width) xx = b->width-1; if(yy<0) yy=0; @@ -348,9 +353,65 @@ static void fill_line_bitmap(RGBA*line, U32*z, int y, int x1, int x2, fillinfo_t ainv = 255-col.a; /* needs bitmap with premultiplied alpha */ - line[x].r = ((line[x].r*ainv)>>8)+col.r; - line[x].g = ((line[x].g*ainv)>>8)+col.g; - line[x].b = ((line[x].b*ainv)>>8)+col.b; + line[x].r = ((line[x].r*ainv)/255)+col.r; + line[x].g = ((line[x].g*ainv)/255)+col.g; + line[x].b = ((line[x].b*ainv)/255)+col.b; + line[x].a = 255; + } + bit <<= 1; + if(!bit) { + bit = 1;bitpos++; + } + } while(++xmatrix; + RGBA*g= info->gradient; + + double det = m->m00*m->m11 - m->m01*m->m10; + if(fabs(det) < 0.0005) { + /* x direction equals y direction */ + return; + } + + det = 1.0/det; + double xx1 = ( (-m->tx) * m->m11 - (y - m->ty) * m->m10) * det; + double yy1 = (- (-m->tx) * m->m01 + (y - m->ty) * m->m00) * det; + double xinc1 = m->m11 * det; + double yinc1 = m->m01 * det; + + U32 bit = 1<<(x1&31); + int bitpos = (x1/32); + + do { + if(z[bitpos]&bit) { + RGBA col; + int ainv; + + int pos = 0; + if(info->linear_or_radial) { + double xx = xx1 + x * xinc1; + double yy = yy1 + y * yinc1; + double r = sqrt(xx*xx + yy*yy); + if(r>1) r = 1; + pos = (int)(r*255.999); + } else { + double r = xx1 + x * xinc1; + if(r>1) r = 1; + if(r<-1) r = -1; + pos = (int)((r+1)*127.999); + } + col = g[pos]; + ainv = 255-col.a; + + /* needs bitmap with premultiplied alpha */ + line[x].r = ((line[x].r*ainv)/255)+col.r; + line[x].g = ((line[x].g*ainv)/255)+col.g; + line[x].b = ((line[x].b*ainv)/255)+col.b; line[x].a = 255; } bit <<= 1; @@ -384,7 +445,8 @@ void fill_line(gfxdevice_t*dev, RGBA*line, U32*zline, int y, int startx, int end fill_line_clip(line, zline, y, startx, endx); else if(fill->type == filltype_bitmap) fill_line_bitmap(line, zline, y, startx, endx, fill); - // etc. + else if(fill->type == filltype_gradient) + fill_line_gradient(line, zline, y, startx, endx, fill); } void fill(gfxdevice_t*dev, fillinfo_t*fill) @@ -437,6 +499,7 @@ void fill(gfxdevice_t*dev, fillinfo_t*fill) void fill_solid(gfxdevice_t*dev, gfxcolor_t* color) { fillinfo_t info; + memset(&info, 0, sizeof(info)); info.type = filltype_solid; info.color = color; fill(dev, &info); @@ -445,13 +508,21 @@ void fill_solid(gfxdevice_t*dev, gfxcolor_t* color) int render_setparameter(struct _gfxdevice*dev, const char*key, const char*value) { internal_t*i = (internal_t*)dev->internal; - if(!strcmp(key, "antialize")) { + if(!strcmp(key, "antialize") || !strcmp(key, "antialise")) { i->antialize = atoi(value); i->zoom = i->antialize * i->multiply; + return 1; } else if(!strcmp(key, "multiply")) { i->multiply = atoi(value); i->zoom = i->antialize * i->multiply; fprintf(stderr, "Warning: multiply not implemented yet\n"); + return 1; + } else if(!strcmp(key, "fillwhite")) { + i->fillwhite = atoi(value); + return 1; + } else if(!strcmp(key, "palette")) { + i->palette = atoi(value); + return 1; } return 0; } @@ -460,8 +531,8 @@ void newclip(struct _gfxdevice*dev) { internal_t*i = (internal_t*)dev->internal; - clipbuffer_t*c = rfx_calloc(sizeof(clipbuffer_t)); - c->data = rfx_calloc(sizeof(U32) * i->bitwidth * i->height2); + clipbuffer_t*c = (clipbuffer_t*)rfx_calloc(sizeof(clipbuffer_t)); + c->data = (U32*)rfx_calloc(sizeof(U32) * i->bitwidth * i->height2); c->next = i->clipbuf; i->clipbuf = c; if(c->next) @@ -470,12 +541,13 @@ void newclip(struct _gfxdevice*dev) memset(c->data, 0, sizeof(U32)*i->bitwidth*i->height2); } -void endclip(struct _gfxdevice*dev) +void endclip(struct _gfxdevice*dev, char removelast) { internal_t*i = (internal_t*)dev->internal; - - if(!i->clipbuf) { - fprintf(stderr, "endclip without any active clip buffers"); + + /* test for at least one cliplevel (the one we created ourselves) */ + if(!i->clipbuf || (!i->clipbuf->next && !removelast)) { + fprintf(stderr, "endclip without any active clip buffers\n"); return; } @@ -491,28 +563,26 @@ void render_stroke(struct _gfxdevice*dev, gfxline_t*line, gfxcoord_t width, gfxc internal_t*i = (internal_t*)dev->internal; double x,y; - if(cap_style != gfx_capRound || joint_style != gfx_joinRound) { + /*if(cap_style != gfx_capRound || joint_style != gfx_joinRound) { fprintf(stderr, "Warning: cap/joint style != round not yet supported\n"); - } + }*/ while(line) { - int x1,y1,x2,y2,x3,y3; - if(line->type == gfx_moveTo) { } else if(line->type == gfx_lineTo) { double x1=x*i->zoom,y1=y*i->zoom; double x3=line->x*i->zoom,y3=line->y*i->zoom; - add_solidline(dev, x1, y1, x3, y3, width * i->multiply); + add_solidline(dev, x1, y1, x3, y3, width * i->zoom); fill_solid(dev, color); } else if(line->type == gfx_splineTo) { - int c,t,parts,qparts; + int t,parts; double xx,yy; double x1=x*i->zoom,y1=y*i->zoom; double x2=line->sx*i->zoom,y2=line->sy*i->zoom; double x3=line->x*i->zoom,y3=line->y*i->zoom; - c = abs(x3-2*x2+x1) + abs(y3-2*y2+y1); + double c = abs(x3-2*x2+x1) + abs(y3-2*y2+y1); xx=x1; yy=y1; @@ -523,7 +593,7 @@ void render_stroke(struct _gfxdevice*dev, gfxline_t*line, gfxcoord_t width, gfxc double nx = (double)(t*t*x3 + 2*t*(parts-t)*x2 + (parts-t)*(parts-t)*x1)/(double)(parts*parts); double ny = (double)(t*t*y3 + 2*t*(parts-t)*y2 + (parts-t)*(parts-t)*y1)/(double)(parts*parts); - add_solidline(dev, xx, yy, nx, ny, width * i->multiply); + add_solidline(dev, xx, yy, nx, ny, width * i->zoom); fill_solid(dev, color); xx = nx; yy = ny; @@ -562,7 +632,7 @@ static void draw_line(gfxdevice_t*dev, gfxline_t*line) xx=x1; yy=y1; - parts = (int)(sqrt(c)/3); + parts = (int)(sqrt(c)); if(!parts) parts = 1; for(t=1;t<=parts;t++) { @@ -584,6 +654,7 @@ void render_startclip(struct _gfxdevice*dev, gfxline_t*line) { internal_t*i = (internal_t*)dev->internal; fillinfo_t info; + memset(&info, 0, sizeof(info)); newclip(dev); info.type = filltype_clip; draw_line(dev, line); @@ -593,7 +664,7 @@ void render_startclip(struct _gfxdevice*dev, gfxline_t*line) void render_endclip(struct _gfxdevice*dev) { internal_t*i = (internal_t*)dev->internal; - endclip(dev); + endclip(dev, 0); } void render_fill(struct _gfxdevice*dev, gfxline_t*line, gfxcolor_t*color) @@ -608,13 +679,12 @@ void render_fillbitmap(struct _gfxdevice*dev, gfxline_t*line, gfximage_t*img, gf { internal_t*i = (internal_t*)dev->internal; - gfxcolor_t black = {255,0,0,0}; - gfxmatrix_t m2 = *matrix; draw_line(dev, line); fillinfo_t info; + memset(&info, 0, sizeof(info)); info.type = filltype_bitmap; info.image = img; info.matrix = &m2; @@ -630,10 +700,58 @@ void render_fillgradient(struct _gfxdevice*dev, gfxline_t*line, gfxgradient_t*gr { internal_t*i = (internal_t*)dev->internal; - gfxcolor_t black = {255,0,0,0}; + gfxmatrix_t m2 = *matrix; draw_line(dev, line); - fill_solid(dev, &black); + + RGBA g[256]; + fillinfo_t info; + memset(&info, 0, sizeof(info)); + info.type = filltype_gradient; + info.gradient = g; + info.matrix = &m2; + + m2.m00 *= i->zoom; m2.m01 *= i->zoom; m2.tx *= i->zoom; + m2.m10 *= i->zoom; m2.m11 *= i->zoom; m2.ty *= i->zoom; + + info.linear_or_radial = type == gfxgradient_radial; + + int pos = 0; + gfxcolor_t color = {0,0,0,0}; + pos=0; + while(gradient) { + int nextpos = gradient->pos*256; + int t; + if(nextpos>256) { + msg(" Invalid gradient- contains values > 1.0"); + return; + } + + gfxcolor_t nextcolor = gradient->color; + if(nextpos!=pos) { + double p0 = 1.0; + double p1 = 0.0; + double step = 1.0/(nextpos-pos); + int t; + for(t=pos;tnext; + } + if(pos!=256) { + msg(" Invalid gradient- doesn't end with 1.0"); + } + + fill(dev, &info); } void render_addfont(struct _gfxdevice*dev, gfxfont_t*font) @@ -643,6 +761,12 @@ void render_addfont(struct _gfxdevice*dev, gfxfont_t*font) void render_drawchar(struct _gfxdevice*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix) { internal_t*i = (internal_t*)dev->internal; + if(!font) + return; + + /* align characters to whole pixels */ + matrix->tx = (int)(matrix->tx * i->antialize) / i->antialize; + matrix->ty = (int)(matrix->ty * i->antialize) / i->antialize; gfxglyph_t*glyph = &font->glyphs[glyphnr]; gfxline_t*line2 = gfxline_clone(glyph->line); @@ -658,31 +782,88 @@ void render_result_write(gfxresult_t*r, int filedesc) { internal_result_t*i= (internal_result_t*)r->internal; } -int render_result_save(gfxresult_t*r, char*filename) +int render_result_save(gfxresult_t*r, const char*filename) { internal_result_t*i= (internal_result_t*)r->internal; + if(!i) { + return 0; // no pages drawn + } if(i->next) { int nr=0; + char filenamebuf[256]; + char*origname = strdup(filename); + int l = strlen(origname); + if(l>3 && strchr("gG",origname[l-1]) && strchr("nN",filename[l-2]) && + strchr("pP",origname[l-3]) && filename[l-4]=='.') { + origname[l-4] = 0; + } while(i->next) { - writePNG(filename, (unsigned char*)i->img.data, i->img.width, i->img.height); + sprintf(filenamebuf, "%s.%d.png", origname, nr); + if(!i->palette) { + writePNG(filename, (unsigned char*)i->img.data, i->img.width, i->img.height); + } else { + writePalettePNG(filename, (unsigned char*)i->img.data, i->img.width, i->img.height); + } nr++; } + free(origname); } else { - writePNG(filename, (unsigned char*)i->img.data, i->img.width, i->img.height); + if(!i->palette) { + writePNG(filename, (unsigned char*)i->img.data, i->img.width, i->img.height); + } else { + writePalettePNG(filename, (unsigned char*)i->img.data, i->img.width, i->img.height); + } } return 1; } -void*render_result_get(gfxresult_t*r, char*name) +char*gfximage_asXPM(gfximage_t*img, int depth) +{ + int d= 256/depth; + char*str = (char*)malloc(img->width*img->height*4 + 500 + 16*depth*depth*depth); + char*p = str; + p+= sprintf(p, "static char *noname[] = {\n\"%d %d 262144 3\",\n", img->width, img->height); + int r,g,b; + for(r=0;rheight;y++) { + p+=sprintf(p, "\""); + gfxcolor_t*col = &img->data[y*img->height]; + int x; + for(x=0;xwidth;x++) { + p+=sprintf(p, "%c%c%c", 32+(col->r/d), 32+(col->g/d), 32+(col->b/d)); + } + p+=sprintf(p, "\",\n"); + } + *p = 0; + return p; +} +void*render_result_get(gfxresult_t*r, const char*name) { internal_result_t*i= (internal_result_t*)r->internal; - if(!strncmp(name,"page",4)) { + if(!strncmp(name,"xpm",3)) { + int pagenr = atoi(&name[3]); + if(pagenr<0) + pagenr=0; + while(pagenr>0) { + i = i->next; + if(!i) + return 0; + pagenr--; + } + return gfximage_asXPM(&i->img, 64); + } else if(!strncmp(name,"page",4)) { int pagenr = atoi(&name[4]); if(pagenr<0) - return 0; + pagenr=0; while(pagenr>0) { i = i->next; if(!i) return 0; + pagenr--; } return &i->img; } @@ -695,10 +876,15 @@ void render_result_destroy(gfxresult_t*r) while(i) { internal_result_t*next = i->next; free(i->img.data);i->img.data = 0; - free(i); + + /* FIXME memleak + the following rfx_free causes a segfault on WIN32 machines, + if executed */ + //rfx_free(i); + i = next; } - free(r); + rfx_free(r); } gfxresult_t* render_finish(struct _gfxdevice*dev) @@ -741,6 +927,10 @@ void render_startpage(struct _gfxdevice*dev, int width, int height) i->lines[y].num = 0; } i->img = (RGBA*)rfx_calloc(sizeof(RGBA)*i->width2*i->height2); + if(i->fillwhite) { + memset(i->img, 0xff, sizeof(RGBA)*i->width2*i->height2); + } + i->ymin = 0x7fffffff; i->ymax = -0x80000000; @@ -752,7 +942,7 @@ void render_startpage(struct _gfxdevice*dev, int width, int height) static void store_image(internal_t*i, internal_result_t*ir) { - ir->img.data = malloc(i->width*i->height*sizeof(RGBA)); + ir->img.data = (gfxcolor_t*)malloc(i->width*i->height*sizeof(gfxcolor_t)); ir->img.width = i->width; ir->img.height = i->height; @@ -813,13 +1003,19 @@ void render_endpage(struct _gfxdevice*dev) exit(1); } - endclip(dev); + endclip(dev, 1); + int unclosed = 0; while(i->clipbuf) { - fprintf(stderr, "Warning: unclosed clip while processing endpage()\n"); - endclip(dev); + endclip(dev, 1); + unclosed++; + } + + if(unclosed) { + fprintf(stderr, "Warning: %d unclosed clip(s) while processing endpage()\n", unclosed); } internal_result_t*ir= (internal_result_t*)rfx_calloc(sizeof(internal_result_t)); + ir->palette = i->palette; int y,x; @@ -845,7 +1041,7 @@ void render_endpage(struct _gfxdevice*dev) i->height2 = 0; } -void render_drawlink(struct _gfxdevice*dev, gfxline_t*line, char*action) +void render_drawlink(struct _gfxdevice*dev, gfxline_t*line, const char*action) { /* not supported for this output device */ } @@ -853,7 +1049,6 @@ void render_drawlink(struct _gfxdevice*dev, gfxline_t*line, char*action) void gfxdevice_render_init(gfxdevice_t*dev) { internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t)); - int y; memset(dev, 0, sizeof(gfxdevice_t)); dev->name = "render"; @@ -883,3 +1078,10 @@ void gfxdevice_render_init(gfxdevice_t*dev) dev->finish = render_finish; } + +gfxdevice_t* gfxdevice_render_new() +{ + gfxdevice_t* d = (gfxdevice_t*)malloc(sizeof(gfxdevice_t)); + gfxdevice_render_init(d); + return d; +}