Added pool alloc for active edges, improved tesselation algo, better guessing of image size

- added pool alloc for active edges
- improved tesselation algo
- better guessing of image size
- reverted tiger to default state
This commit is contained in:
Mikko Mononen 2014-01-09 23:05:52 +02:00
parent ad2841fccb
commit 8e47686015
3 changed files with 153 additions and 86 deletions

View File

@ -3,7 +3,7 @@
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="800" height="800">
height="800">
<g transform="translate(200,200)" style="fill-opacity:1; fill:none;">
<g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
<path d="M-122.304 84.285C-122.304 84.285 -122.203 86.179 -123.027 86.16C-123.851 86.141 -140.305 38.066 -160.833 40.309C-160.833 40.309 -143.05 32.956 -122.304 84.285z"/>

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 94 KiB

View File

@ -26,6 +26,39 @@
#define NANOSVGRAST_IMPLEMENTATION
#include "nanosvgrast.h"
static float minf(float a, float b) { return a < b ? a : b; }
static float maxf(float a, float b) { return a > b ? a : b; }
static void calcBounds(struct NSVGimage* image, float* bounds)
{
struct NSVGshape* shape;
struct NSVGpath* path;
int i;
bounds[0] = FLT_MAX;
bounds[1] = FLT_MAX;
bounds[2] = -FLT_MAX;
bounds[3] = -FLT_MAX;
for (shape = image->shapes; shape != NULL; shape = shape->next) {
for (path = shape->paths; path != NULL; path = path->next) {
for (i = 0; i < path->npts; i++) {
float* p = &path->pts[i*2];
bounds[0] = minf(bounds[0], p[0]);
bounds[1] = minf(bounds[1], p[1]);
bounds[2] = maxf(bounds[2], p[0]);
bounds[3] = maxf(bounds[3], p[1]);
}
}
}
}
static void getImageSize(struct NSVGimage *image, int* w, int* h)
{
float bounds[4];
if (image->width < 1 || image->height < 1)
calcBounds(image, bounds);
*w = image->width < 1 ? (bounds[2]+1) : image->width;
*h = image->height < 1 ? (bounds[3]+1) : image->height;
}
int main()
{
@ -39,8 +72,7 @@ int main()
printf("Could not open SVG image.\n");
goto error;
}
w = image->width;
h = image->height;
getImageSize(image, &w, &h);
if (w < 1 || h < 1) {
printf("Size of SVG not specified.\n");
goto error;
@ -63,9 +95,7 @@ int main()
stbi_write_png("svg.png", w, h, 4, img, w*4);
error:
printf("delete rast\n");
nsvgDeleteRasterizer(rast);
printf("delete image\n");
nsvgDelete(image);
return 0;

View File

@ -27,26 +27,30 @@ void nsvgDeleteRasterizer(struct NSVGrasterizer*);
// The polygon rasterization is heavily based on stb_truetype rasterizer by Sean Barrett - http://nothings.org/
#define NSVG__SUBSAMPLES 5
#define NSVG__FIXSHIFT 10
#define NSVG__FIX (1 << NSVG__FIXSHIFT)
#define NSVG__FIXMASK (NSVG__FIX-1)
#define NSVG__SUBSAMPLES 5
#define NSVG__FIXSHIFT 10
#define NSVG__FIX (1 << NSVG__FIXSHIFT)
#define NSVG__FIXMASK (NSVG__FIX-1)
#define NSVG__MEMPAGE_SIZE 1024
struct NSVGedge {
float x0,y0, x1,y1;
int dir;
// struct NSVGedge* next;
struct NSVGedge* next;
};
struct NSVGactedge {
struct NSVGactiveEdge {
int x,dx;
float ey;
int dir;
struct NSVGactedge *next;
struct NSVGactiveEdge *next;
};
struct NSVGmemPage {
unsigned char mem[NSVG__MEMPAGE_SIZE];
int size;
struct NSVGmemPage* next;
};
struct NSVGrasterizer
{
@ -56,10 +60,9 @@ struct NSVGrasterizer
int nedges;
int cedges;
struct NSVGactedge* actedges;
int nactedges;
int cactedges;
struct NSVGactedge* freelist;
struct NSVGactiveEdge* freelist;
struct NSVGmemPage* pages;
struct NSVGmemPage* curpage;
unsigned char* scanline;
int cscanline;
@ -73,6 +76,7 @@ struct NSVGrasterizer* nsvgCreateRasterizer()
struct NSVGrasterizer* r = (struct NSVGrasterizer*)malloc(sizeof(struct NSVGrasterizer));
if (r == NULL) goto error;
memset(r, 0, sizeof(struct NSVGrasterizer));
return r;
error:
@ -82,13 +86,67 @@ error:
void nsvgDeleteRasterizer(struct NSVGrasterizer* r)
{
struct NSVGmemPage* p;
if (r == NULL) return;
p = r->pages;
while (p != NULL) {
struct NSVGmemPage* next = p->next;
free(p);
p = next;
}
if (r->edges) free(r->edges);
if (r->actedges) free(r->actedges);
if (r->scanline) free(r->scanline);
free(r);
}
static struct NSVGmemPage* nsvg__nextPage(struct NSVGrasterizer* r, struct NSVGmemPage* cur)
{
struct NSVGmemPage *newp;
// If using existing chain, return the next page in chain
if (cur != NULL && cur->next != NULL) {
return cur->next;
}
// Alloc new page
newp = (struct NSVGmemPage*)malloc(sizeof(struct NSVGmemPage));
if (newp == NULL) return NULL;
memset(newp, 0, sizeof(struct NSVGmemPage));
// Add to linked list
if (cur != NULL)
cur->next = newp;
else
r->pages = newp;
return newp;
}
static void nsvg__resetPool(struct NSVGrasterizer* r)
{
struct NSVGmemPage* p = r->pages;
while (p != NULL) {
p->size = 0;
p = p->next;
}
r->curpage = r->pages;
}
static unsigned char* nsvg__alloc(struct NSVGrasterizer* r, int size)
{
unsigned char* buf;
if (size > NSVG__MEMPAGE_SIZE) return NULL;
if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) {
r->curpage = nsvg__nextPage(r, r->curpage);
}
buf = &r->curpage->mem[r->curpage->size];
r->curpage->size += size;
return buf;
}
static void nsvg__addEdge(struct NSVGrasterizer* r, float x0, float y0, float x1, float y1)
{
@ -122,22 +180,7 @@ static void nsvg__addEdge(struct NSVGrasterizer* r, float x0, float y0, float x1
}
}
static float nsvg__distPtSeg(float x, float y, float px, float py, float qx, float qy)
{
float pqx, pqy, dx, dy, d, t;
pqx = qx-px;
pqy = qy-py;
dx = x-px;
dy = y-py;
d = pqx*pqx + pqy*pqy;
t = pqx*dx + pqy*dy;
if (d > 0) t /= d;
if (t < 0) t = 0;
else if (t > 1) t = 1;
dx = px + t*pqx - x;
dy = py + t*pqy - y;
return dx*dx + dy*dy;
}
static float nsvg__absf(float x) { return x < 0 ? -x : x; }
static void nsvg__flattenCubicBez(struct NSVGrasterizer* r,
float x1, float y1, float x2, float y2,
@ -145,9 +188,15 @@ static void nsvg__flattenCubicBez(struct NSVGrasterizer* r,
float tol, int level)
{
float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;
float d;
if (level > 12) return;
if (level > 10) return;
if (nsvg__absf(x1+x3-x2-x2) + nsvg__absf(y1+y3-y2-y2) + nsvg__absf(x2+x4-x3-x3) + nsvg__absf(y2+y4-y3-y3) < tol) {
nsvg__addEdge(r, r->px, r->py, x4, y4);
r->px = x4;
r->py = y4;
return;
}
x12 = (x1+x2)*0.5f;
y12 = (y1+y2)*0.5f;
@ -162,14 +211,27 @@ static void nsvg__flattenCubicBez(struct NSVGrasterizer* r,
x1234 = (x123+x234)*0.5f;
y1234 = (y123+y234)*0.5f;
d = nsvg__distPtSeg(x1234, y1234, x1,y1, x4,y4);
if (d > tol*tol) {
nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, tol, level+1);
nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, tol, level+1);
} else {
nsvg__addEdge(r, r->px, r->py, x4, y4);
r->px = x4;
r->py = y4;
nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, tol, level+1);
nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, tol, level+1);
}
static void nsvg__flattenShape(struct NSVGrasterizer* r,
struct NSVGshape* shape, float tx, float ty, float scale)
{
struct NSVGpath* path;
float tol = 0.5f * 4.0f / scale;
int i;
for (path = shape->paths; path != NULL; path = path->next) {
// Flatten path
r->px = path->pts[0];
r->py = path->pts[1];
for (i = 0; i < path->npts-1; i += 3) {
float* p = &path->pts[i*2];
nsvg__flattenCubicBez(r, p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7], tol, 0);
}
// Close path
nsvg__addEdge(r, r->px,r->py, path->pts[0],path->pts[1]);
}
}
@ -184,9 +246,9 @@ static int nsvg__cmpEdge(const void *p, const void *q)
}
static struct NSVGactedge* nsvg__addActive(struct NSVGrasterizer* r, struct NSVGedge* e, float startPoint)
static struct NSVGactiveEdge* nsvg__addActive(struct NSVGrasterizer* r, struct NSVGedge* e, float startPoint)
{
struct NSVGactedge* z;
struct NSVGactiveEdge* z;
if (r->freelist != NULL) {
// Restore from freelist.
@ -194,13 +256,8 @@ static struct NSVGactedge* nsvg__addActive(struct NSVGrasterizer* r, struct NSVG
r->freelist = z->next;
} else {
// Alloc new edge.
if (r->nactedges+1 > r->cactedges) {
r->cactedges = r->cactedges > 0 ? r->cactedges * 2 : 64;
r->actedges = (struct NSVGactedge*)realloc(r->actedges, sizeof(struct NSVGactedge) * r->cactedges);
if (r->actedges == NULL) return NULL;
}
z = &r->actedges[r->nactedges];
r->nactedges++;
z = (struct NSVGactiveEdge*)nsvg__alloc(r, sizeof(struct NSVGactiveEdge));
if (z == NULL) return NULL;
}
float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
@ -219,7 +276,7 @@ static struct NSVGactedge* nsvg__addActive(struct NSVGrasterizer* r, struct NSVG
return z;
}
static void nsvg__freeActive(struct NSVGrasterizer* r, struct NSVGactedge* z)
static void nsvg__freeActive(struct NSVGrasterizer* r, struct NSVGactiveEdge* z)
{
z->next = r->freelist;
r->freelist = z;
@ -228,7 +285,7 @@ static void nsvg__freeActive(struct NSVGrasterizer* r, struct NSVGactedge* z)
// note: this routine clips fills that extend off the edges... ideally this
// wouldn't happen, but it could happen if the truetype glyph bounding boxes
// are wrong, or if the user supplies a too-small bitmap
static void nsvg__fillActiveEdges(unsigned char* scanline, int len, struct NSVGactedge* e, int maxWeight, int* xmin, int* xmax)
static void nsvg__fillActiveEdges(unsigned char* scanline, int len, struct NSVGactiveEdge* e, int maxWeight, int* xmin, int* xmax)
{
// non-zero winding fill
int x0 = 0, w = 0;
@ -306,7 +363,7 @@ static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* co
static void nsvg__rasterizeSortedEdges(struct NSVGrasterizer *r, unsigned int color)
{
struct NSVGactedge *active = NULL;
struct NSVGactiveEdge *active = NULL;
int y, s;
int e = 0;
int maxWeight = (255 / NSVG__SUBSAMPLES); // weight per vertical scanline
@ -319,12 +376,12 @@ static void nsvg__rasterizeSortedEdges(struct NSVGrasterizer *r, unsigned int co
for (s = 0; s < NSVG__SUBSAMPLES; ++s) {
// find center of pixel for this scanline
float scany = y*NSVG__SUBSAMPLES + s + 0.5f;
struct NSVGactedge **step = &active;
struct NSVGactiveEdge **step = &active;
// update all active edges;
// remove all active edges that terminate before the center of this scanline
while (*step) {
struct NSVGactedge *z = *step;
struct NSVGactiveEdge *z = *step;
if (z->ey <= scany) {
*step = z->next; // delete from list
// NSVG__assert(z->valid);
@ -341,8 +398,8 @@ static void nsvg__rasterizeSortedEdges(struct NSVGrasterizer *r, unsigned int co
step = &active;
while (*step && (*step)->next) {
if ((*step)->x > (*step)->next->x) {
struct NSVGactedge* t = *step;
struct NSVGactedge* q = t->next;
struct NSVGactiveEdge* t = *step;
struct NSVGactiveEdge* q = t->next;
t->next = q->next;
q->next = t;
*step = q;
@ -356,7 +413,7 @@ static void nsvg__rasterizeSortedEdges(struct NSVGrasterizer *r, unsigned int co
// insert all edges that start before the center of this scanline -- omit ones that also end on this scanline
while (e < r->nedges && r->edges[e].y0 <= scany) {
if (r->edges[e].y1 > scany) {
struct NSVGactedge* z = nsvg__addActive(r, &r->edges[e], scany);
struct NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany);
if (z == NULL) break;
// find insertion point
if (active == NULL) {
@ -367,7 +424,7 @@ static void nsvg__rasterizeSortedEdges(struct NSVGrasterizer *r, unsigned int co
active = z;
} else {
// find thing to insert AFTER
struct NSVGactedge* p = active;
struct NSVGactiveEdge* p = active;
while (p->next && p->next->x < z->x)
p = p->next;
// at this point, p->next->x is NOT < z->x
@ -390,26 +447,6 @@ static void nsvg__rasterizeSortedEdges(struct NSVGrasterizer *r, unsigned int co
}
static void nsvg__flattenShape(struct NSVGrasterizer* r,
struct NSVGshape* shape, float tx, float ty, float scale)
{
struct NSVGpath* path;
float tol = 0.5f * scale;
int i;
for (path = shape->paths; path != NULL; path = path->next) {
// Flatten path
r->px = path->pts[0];
r->py = path->pts[1];
for (i = 0; i < path->npts-1; i += 3) {
float* p = &path->pts[i*2];
nsvg__flattenCubicBez(r, p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7], tol, 0);
}
// Close path
nsvg__addEdge(r, r->px,r->py, path->pts[0],path->pts[1]);
}
}
static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int stride)
{
int x,y;
@ -496,9 +533,9 @@ void nsvgRasterize(struct NSVGrasterizer* r,
if (!shape->hasFill)
continue;
r->nedges = 0;
r->nactedges = 0;
nsvg__resetPool(r);
r->freelist = NULL;
r->nedges = 0;
nsvg__flattenShape(r, shape, tx,ty,scale);
@ -526,4 +563,4 @@ void nsvgRasterize(struct NSVGrasterizer* r,
r->stride = 0;
}
#endif
#endif