X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fdevices%2Frender.c;h=1d6e80ec37cd0637abd28ea018030b496180007d;hb=a6c987152623f74912763bb88b323445ba3bd4f8;hp=69cfae6e17f2bf78144b29ea3cbab6372cb176cf;hpb=dcdc00b2f13eae009af81e8b02caf87086913047;p=swftools.git diff --git a/lib/devices/render.c b/lib/devices/render.c index 69cfae6..1d6e80e 100644 --- a/lib/devices/render.c +++ b/lib/devices/render.c @@ -1,8 +1,8 @@ -/* gfxdevice_bitmap.cc +/* render.c Part of the swftools package. - Copyright (c) 2005 Matthias Kramm + Copyright (c) 2005/2006/2007 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 @@ -45,45 +45,29 @@ typedef struct _renderline } renderline_t; typedef struct _internal_result { - int width; - int height; - RGBA* img; + gfximage_t img; struct _internal_result*next; } internal_result_t; typedef struct _clipbuffer { U32*data; - int linesize; - struct _clipbuffer*prev; + struct _clipbuffer*next; } clipbuffer_t; -typedef struct _fontlist -{ - gfxfont_t*font; - char*id; - struct _fontlist*next; -} fontlist_t; - typedef struct _internal { int width; int height; int width2; int height2; + int bitwidth; int multiply; int antialize; + int zoom; int ymin, ymax; - - int depth; + int fillwhite; RGBA* img; - int* zbuf; - gfxfont_t*font; - char*fontid; - - fontlist_t* fontlist; - - clipbuffer_t*clipbufs; clipbuffer_t*clipbuf; renderline_t*lines; @@ -183,6 +167,8 @@ static void add_line(gfxdevice_t*dev , double x1, double y1, double x2, double y #define PI 3.14159265358979 static void add_solidline(gfxdevice_t*dev, double x1, double y1, double x2, double y2, double width) { + /* TODO: handle cap styles */ + internal_t*i = (internal_t*)dev->internal; double dx = x2-x1; @@ -320,27 +306,31 @@ 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) { + gfxcolor_t red = {255,255,0,0}; + fill_line_solid(line, z, y, x1, x2, red); + return; + } + double det = m->m00*m->m11 - m->m01*m->m10; if(fabs(det) < 0.0005) { /* x direction equals y direction- the image is invisible */ 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; - if(!b->width || !b->height) { - gfxcolor_t red = {255,255,0,0}; - fill_line_solid(line, z, y, x1, x2, red); - return; - } - U32 bit = 1<<(x1&31); int bitpos = (x1/32); do { if(z[bitpos]&bit) { RGBA col; - int xx = (int)(( (x - m->tx) * m->m11 - (y - m->ty) * m->m10)*det); - int yy = (int)((- (x - m->tx) * m->m01 + (y - m->ty) * m->m00)*det); + int xx = (int)(xx1 + x * xinc1); + int yy = (int)(yy1 - x * yinc1); int ainv; if(info->clip) { @@ -358,6 +348,7 @@ static void fill_line_bitmap(RGBA*line, U32*z, int y, int x1, int x2, fillinfo_t col = b->data[yy*b->width+xx]; 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; @@ -405,7 +396,8 @@ void fill(gfxdevice_t*dev, fillinfo_t*fill) for(y=i->ymin;y<=i->ymax;y++) { renderpoint_t*points = i->lines[y].points; RGBA*line = &i->img[i->width2*y]; - int*zline = &i->zbuf[i->width2*y]; + U32*zline = &i->clipbuf->data[i->bitwidth*y]; + int n; int num = i->lines[y].num; int lastx; @@ -430,6 +422,15 @@ void fill(gfxdevice_t*dev, fillinfo_t*fill) if(endx == i->width2) break; } + if(fill->type == filltype_clip) { + if(i->clipbuf->next) { + U32*line2 = &i->clipbuf->next->data[i->bitwidth*y]; + int x; + for(x=0;xbitwidth;x++) + zline[x] &= line2[x]; + } + } + i->lines[y].num = 0; } } @@ -445,10 +446,18 @@ 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; } return 0; } @@ -458,37 +467,29 @@ void newclip(struct _gfxdevice*dev) internal_t*i = (internal_t*)dev->internal; clipbuffer_t*c = rfx_calloc(sizeof(clipbuffer_t)); - c->linesize = ((i->width2+31) / 32); - c->data = rfx_calloc(c->linesize * i->height2); - - if(!i->clipbufs) { - i->clipbufs = i->clipbuf = c; - } else { - clipbuffer_t*old = i->clipbuf; - i->clipbuf = c; - i->clipbuf->prev = old; - } + c->data = rfx_calloc(sizeof(U32) * i->bitwidth * i->height2); + c->next = i->clipbuf; + i->clipbuf = c; + if(c->next) + memcpy(c->data, c->next->data, i->bitwidth*i->height2); + else + memset(c->data, 0, sizeof(U32)*i->bitwidth*i->height2); } void endclip(struct _gfxdevice*dev) { internal_t*i = (internal_t*)dev->internal; - if(!i->clipbufs) { + if(!i->clipbuf) { fprintf(stderr, "endclip without any active clip buffers"); return; } - - clipbuffer_t*old = i->clipbuf; - - if(i->clipbuf == i->clipbufs) - i->clipbufs = 0; - - i->clipbuf = i->clipbuf->prev; - old->prev = 0; - free(old->data);old->data = 0; - free(old); + clipbuffer_t*c = i->clipbuf; + i->clipbuf = i->clipbuf->next; + c->next = 0; + free(c->data);c->data = 0; + free(c); } void render_stroke(struct _gfxdevice*dev, gfxline_t*line, gfxcoord_t width, gfxcolor_t*color, gfx_capType cap_style, gfx_joinType joint_style, gfxcoord_t miterLimit) @@ -496,26 +497,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,y1=y; - double x3=line->x,y3=line->y; + 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); fill_solid(dev, color); } else if(line->type == gfx_splineTo) { int c,t,parts,qparts; double xx,yy; - double x1=x,y1=y; - double x2=line->sx,y2=line->sy; - double x3=line->x,y3=line->y; + 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); xx=x1; @@ -551,17 +552,17 @@ static void draw_line(gfxdevice_t*dev, gfxline_t*line) if(line->type == gfx_moveTo) { } else if(line->type == gfx_lineTo) { - double x1=x,y1=y; - double x3=line->x,y3=line->y; + double x1=x*i->zoom,y1=y*i->zoom; + double x3=line->x*i->zoom,y3=line->y*i->zoom; add_line(dev, x1, y1, x3, y3); } else if(line->type == gfx_splineTo) { int c,t,parts,qparts; double xx,yy; - double x1=x,y1=y; - double x2=line->sx,y2=line->sy; - double x3=line->x,y3=line->y; + 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); xx=x1; @@ -615,13 +616,19 @@ void render_fillbitmap(struct _gfxdevice*dev, gfxline_t*line, gfximage_t*img, gf gfxcolor_t black = {255,0,0,0}; + gfxmatrix_t m2 = *matrix; + draw_line(dev, line); fillinfo_t info; info.type = filltype_bitmap; info.image = img; - info.matrix = matrix; + info.matrix = &m2; info.cxform = cxform; + + m2.m00 *= i->zoom; m2.m01 *= i->zoom; m2.tx *= i->zoom; + m2.m10 *= i->zoom; m2.m11 *= i->zoom; m2.ty *= i->zoom; + fill(dev, &info); } @@ -635,55 +642,19 @@ void render_fillgradient(struct _gfxdevice*dev, gfxline_t*line, gfxgradient_t*gr fill_solid(dev, &black); } -void render_addfont(struct _gfxdevice*dev, char*fontid, gfxfont_t*font) +void render_addfont(struct _gfxdevice*dev, gfxfont_t*font) { - internal_t*i = (internal_t*)dev->internal; - - fontlist_t*last=0,*l = i->fontlist; - while(l) { - last = l; - if(!strcmp((char*)l->id, fontid)) { - return; // we already know this font - } - l = l->next; - } - l = (fontlist_t*)rfx_calloc(sizeof(fontlist_t)); - l->font = font; - l->id = strdup(fontid); - l->next = 0; - if(last) { - last->next = l; - } else { - i->fontlist = l; - } } -void render_drawchar(struct _gfxdevice*dev, char*fontid, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix) +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(i->font && i->fontid && !strcmp(fontid, i->fontid)) { - // current font is correct - } else { - fontlist_t*l = i->fontlist; - i->font = 0; - i->fontid = 0; - while(l) { - if(!strcmp((char*)l->id, fontid)) { - i->font = l->font; - i->fontid = l->id; - break; - } - l = l->next; - } - if(i->font == 0) { - fprintf(stderr, "Unknown font id: %s", fontid); - 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 = &i->font->glyphs[glyphnr]; - + gfxglyph_t*glyph = &font->glyphs[glyphnr]; gfxline_t*line2 = gfxline_clone(glyph->line); gfxline_transform(line2, matrix); draw_line(dev, line2); @@ -697,29 +668,93 @@ 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, 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, i->width, i->height); + sprintf(filenamebuf, "%s.%d.png", origname, nr); + writePNG(filename, (unsigned char*)i->img.data, i->img.width, i->img.height); nr++; } + free(origname); } else { - writePNG(filename, (unsigned char*)i->img, i->width, i->height); + writePNG(filename, (unsigned char*)i->img.data, i->img.width, i->img.height); } return 1; } +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"); + 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, char*name) { internal_result_t*i= (internal_result_t*)r->internal; + 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; + } + return gfximage_asXPM(&i->img, 64); + } else if(!strncmp(name,"page",4)) { + int pagenr = atoi(&name[4]); + if(pagenr<0) + pagenr=0; + while(pagenr>0) { + i = i->next; + if(!i) + return 0; + } + return &i->img; + } return 0; } void render_result_destroy(gfxresult_t*r) { internal_result_t*i= (internal_result_t*)r->internal; - free(i); r->internal = 0; + r->internal = 0; + while(i) { + internal_result_t*next = i->next; + free(i->img.data);i->img.data = 0; + free(i); + i = next; + } free(r); } @@ -737,8 +772,6 @@ gfxresult_t* render_finish(struct _gfxdevice*dev) free(dev->internal); dev->internal = 0; i = 0; - /* TODO: free fonts */ - return res; } @@ -752,10 +785,11 @@ void render_startpage(struct _gfxdevice*dev, int width, int height) exit(1); } - i->width = width; - i->height = height; - i->width2 = width*i->antialize*i->multiply; - i->height2 = height*i->antialize*i->multiply; + i->width = width*i->multiply; + i->height = height*i->multiply; + i->width2 = width*i->zoom; + i->height2 = height*i->zoom; + i->bitwidth = (i->width2+31)/32; i->lines = (renderline_t*)rfx_alloc(i->height2*sizeof(renderline_t)); for(y=0;yheight2;y++) { @@ -763,12 +797,72 @@ void render_startpage(struct _gfxdevice*dev, int width, int height) i->lines[y].points = 0; i->lines[y].num = 0; } - i->zbuf = (int*)rfx_calloc(sizeof(int)*i->width2*i->height2); 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; + + /* initialize initial clipping field, which doesn't clip anything yet */ newclip(dev); + memset(i->clipbuf->data, 255, sizeof(U32)*i->bitwidth*i->height2); +} + +static void store_image(internal_t*i, internal_result_t*ir) +{ + ir->img.data = malloc(i->width*i->height*sizeof(RGBA)); + ir->img.width = i->width; + ir->img.height = i->height; + + gfxcolor_t*dest = ir->img.data; + + if(i->antialize <= 1) /* no antializing */ { + int y; + for(y=0;yheight;y++) { + RGBA*line = &i->img[y*i->width]; + memcpy(&dest[y*i->width], line, sizeof(RGBA)*i->width); + } + } else { + RGBA**lines = (RGBA**)rfx_calloc(sizeof(RGBA*)*i->antialize); + int q = i->antialize*i->antialize; + int ypos = 0; + int y; + int y2=0; + for(y=0;yheight2;y++) { + int n; + ypos = y % i->antialize; + lines[ypos] = &i->img[y*i->width2]; + if(ypos == i->antialize-1) { + RGBA*out = &dest[(y2++)*i->width]; + int x; + int r,g,b,a; + for(x=0;xwidth;x++) { + int xpos = x*i->antialize; + int yp; + U32 r=0,g=0,b=0,a=0; + for(yp=0;ypantialize;yp++) { + RGBA*lp = &lines[yp][xpos]; + int xp; + for(xp=0;xpantialize;xp++) { + RGBA*p = &lp[xp]; + r += p->r; + g += p->g; + b += p->b; + a += p->a; + } + } + out[x].r = r / q; + out[x].g = g / q; + out[x].b = b / q; + out[x].a = a / q; + } + } + } + rfx_free(lines); + } } void render_endpage(struct _gfxdevice*dev) @@ -781,15 +875,17 @@ void render_endpage(struct _gfxdevice*dev) } endclip(dev); - while(i->clipbufs) { + while(i->clipbuf) { fprintf(stderr, "Warning: unclosed clip while processing endpage()\n"); endclip(dev); } internal_result_t*ir= (internal_result_t*)rfx_calloc(sizeof(internal_result_t)); - ir->width = i->width; - ir->height = i->height; - ir->img = i->img; i->img = 0; + + int y,x; + + store_image(i, ir); + ir->next = 0; if(i->result_next) { i->result_next->next = ir; @@ -799,8 +895,11 @@ void render_endpage(struct _gfxdevice*dev) } i->result_next = ir; - rfx_free(i->lines);i->lines=0; //FIXME - rfx_free(i->zbuf);i->zbuf = 0; + for(y=0;yheight2;y++) { + rfx_free(i->lines[y].points); i->lines[y].points = 0; + } + rfx_free(i->lines);i->lines=0; + if(i->img) {rfx_free(i->img);i->img = 0;} i->width2 = 0; @@ -817,6 +916,9 @@ 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"; + dev->internal = i; i->width = 0; @@ -825,6 +927,7 @@ void gfxdevice_render_init(gfxdevice_t*dev) i->height2 = 0; i->antialize = 1; i->multiply = 1; + i->zoom = 1; dev->setparameter = render_setparameter; dev->startpage = render_startpage;