32 typedef struct NSVGrasterizer NSVGrasterizer;
47 NSVGrasterizer* nsvgCreateRasterizer();
58 void nsvgRasterize(NSVGrasterizer* r,
59 NSVGimage* image,
float tx,
float ty,
float scale,
60 unsigned char* dst,
int w,
int h,
int stride);
63 void nsvgDeleteRasterizer(NSVGrasterizer*);
70 #endif // NANOSVGRAST_H
72 #ifdef NANOSVGRAST_IMPLEMENTATION
76 #define NSVG__SUBSAMPLES 5
77 #define NSVG__FIXSHIFT 10
78 #define NSVG__FIX (1 << NSVG__FIXSHIFT)
79 #define NSVG__FIXMASK (NSVG__FIX-1)
80 #define NSVG__MEMPAGE_SIZE 1024
82 typedef struct NSVGedge {
85 struct NSVGedge* next;
88 typedef struct NSVGpoint {
96 typedef struct NSVGactiveEdge {
100 struct NSVGactiveEdge *next;
103 typedef struct NSVGmemPage {
104 unsigned char mem[NSVG__MEMPAGE_SIZE];
106 struct NSVGmemPage* next;
109 typedef struct NSVGcachedPaint {
113 unsigned int colors[256];
116 struct NSVGrasterizer
131 NSVGactiveEdge* freelist;
133 NSVGmemPage* curpage;
135 unsigned char* scanline;
138 unsigned char* bitmap;
139 int width, height, stride;
142 NSVGrasterizer* nsvgCreateRasterizer()
144 NSVGrasterizer* r = (NSVGrasterizer*)malloc(
sizeof(NSVGrasterizer));
145 if (r == NULL)
goto error;
146 memset(r, 0,
sizeof(NSVGrasterizer));
154 nsvgDeleteRasterizer(r);
158 void nsvgDeleteRasterizer(NSVGrasterizer* r)
162 if (r == NULL)
return;
166 NSVGmemPage* next = p->next;
171 if (r->edges) free(r->edges);
172 if (r->points) free(r->points);
173 if (r->scanline) free(r->scanline);
178 static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur)
183 if (cur != NULL && cur->next != NULL) {
188 newp = (NSVGmemPage*)malloc(
sizeof(NSVGmemPage));
189 if (newp == NULL)
return NULL;
190 memset(newp, 0,
sizeof(NSVGmemPage));
201 static void nsvg__resetPool(NSVGrasterizer* r)
203 NSVGmemPage* p = r->pages;
208 r->curpage = r->pages;
211 static unsigned char* nsvg__alloc(NSVGrasterizer* r,
int size)
214 if (size > NSVG__MEMPAGE_SIZE)
return NULL;
215 if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) {
216 r->curpage = nsvg__nextPage(r, r->curpage);
218 buf = &r->curpage->mem[r->curpage->size];
219 r->curpage->size += size;
223 static int nsvg__ptEquals(
float x1,
float y1,
float x2,
float y2,
float tol)
227 return dx*dx + dy*dy < tol*tol;
230 static void nsvg__addPathPoint(NSVGrasterizer* r,
float x,
float y,
int flags)
234 if (r->npoints > 0) {
235 pt = &r->points[r->npoints-1];
236 if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) {
242 if (r->npoints+1 > r->cpoints) {
243 r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
244 r->points = (NSVGpoint*)realloc(r->points,
sizeof(NSVGpoint) * r->cpoints);
245 if (r->points == NULL)
return;
248 pt = &r->points[r->npoints];
255 static void nsvg__addEdge(NSVGrasterizer* r,
float x0,
float y0,
float x1,
float y1)
263 if (r->nedges+1 > r->cedges) {
264 r->cedges = r->cedges > 0 ? r->cedges * 2 : 64;
265 r->edges = (NSVGedge*)realloc(r->edges,
sizeof(NSVGedge) * r->cedges);
266 if (r->edges == NULL)
return;
269 e = &r->edges[r->nedges];
287 static float nsvg__normalize(
float *x,
float* y)
289 float d = sqrtf((*x)*(*x) + (*y)*(*y));
298 static float nsvg__absf(
float x) {
return x < 0 ? -x : x; }
300 static void nsvg__flattenCubicBez(NSVGrasterizer* r,
301 float x1,
float y1,
float x2,
float y2,
302 float x3,
float y3,
float x4,
float y4,
305 float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;
308 if (level > 10)
return;
316 x123 = (x12+x23)*0.5f;
317 y123 = (y12+y23)*0.5f;
321 d2 = nsvg__absf(((x2 - x4) * dy - (y2 - y4) * dx));
322 d3 = nsvg__absf(((x3 - x4) * dy - (y3 - y4) * dx));
324 if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) {
325 nsvg__addPathPoint(r, x4, y4, type);
329 x234 = (x23+x34)*0.5f;
330 y234 = (y23+y34)*0.5f;
331 x1234 = (x123+x234)*0.5f;
332 y1234 = (y123+y234)*0.5f;
334 nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0);
335 nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type);
338 static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape,
float scale)
343 for (path = shape->paths; path != NULL; path = path->next) {
346 nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0);
347 for (i = 0; i < path->npts-1; i += 3) {
348 float* p = &path->pts[i*2];
349 nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, 0);
352 nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0);
354 for (i = 0, j = r->npoints-1; i < r->npoints; j = i++)
355 nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y);
361 NSVG_PT_CORNER = 0x01,
362 NSVG_PT_BEVEL = 0x02,
366 static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1,
float lineWidth)
368 float w = lineWidth * 0.5f;
369 float dx = p1->x - p0->x;
370 float dy = p1->y - p0->y;
371 float len = nsvg__normalize(&dx, &dy);
372 float px = p0->x + dx*len*0.5f, py = p0->y + dy*len*0.5f;
373 float dlx = dy, dly = -dx;
374 float lx = px - dlx*w, ly = py - dly*w;
375 float rx = px + dlx*w, ry = py + dly*w;
376 left->x = lx; left->y = ly;
377 right->x = rx; right->y = ry;
380 static void nsvg__buttCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p,
float dx,
float dy,
float lineWidth,
int connect)
382 float w = lineWidth * 0.5f;
383 float px = p->x, py = p->y;
384 float dlx = dy, dly = -dx;
385 float lx = px - dlx*w, ly = py - dly*w;
386 float rx = px + dlx*w, ry = py + dly*w;
388 nsvg__addEdge(r, lx, ly, rx, ry);
391 nsvg__addEdge(r, left->x, left->y, lx, ly);
392 nsvg__addEdge(r, rx, ry, right->x, right->y);
394 left->x = lx; left->y = ly;
395 right->x = rx; right->y = ry;
398 static void nsvg__squareCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p,
float dx,
float dy,
float lineWidth,
int connect)
400 float w = lineWidth * 0.5f;
401 float px = p->x - dx*w, py = p->y - dy*w;
402 float dlx = dy, dly = -dx;
403 float lx = px - dlx*w, ly = py - dly*w;
404 float rx = px + dlx*w, ry = py + dly*w;
406 nsvg__addEdge(r, lx, ly, rx, ry);
409 nsvg__addEdge(r, left->x, left->y, lx, ly);
410 nsvg__addEdge(r, rx, ry, right->x, right->y);
412 left->x = lx; left->y = ly;
413 right->x = rx; right->y = ry;
417 #define NSVG_PI (3.14159265358979323846264338327f)
420 static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p,
float dx,
float dy,
float lineWidth,
int ncap,
int connect)
423 float w = lineWidth * 0.5f;
424 float px = p->x, py = p->y;
425 float dlx = dy, dly = -dx;
426 float lx, ly, rx, ry, prevx, prevy;
428 for (i = 0; i < ncap; i++) {
429 float a = i/(float)(ncap-1)*NSVG_PI;
430 float ax = cosf(a) * w, ay = sinf(a) * w;
431 float x = px - dlx*ax - dx*ay;
432 float y = py - dly*ax - dy*ay;
435 nsvg__addEdge(r, prevx, prevy, x, y);
442 }
else if (i == ncap-1) {
448 nsvg__addEdge(r, left->x, left->y, lx, ly);
449 nsvg__addEdge(r, rx, ry, right->x, right->y);
452 left->x = lx; left->y = ly;
453 right->x = rx; right->y = ry;
456 static void nsvg__bevelJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1,
float lineWidth)
458 float w = lineWidth * 0.5f;
459 float dlx0 = p0->dy, dly0 = -p0->dx;
460 float dlx1 = p1->dy, dly1 = -p1->dx;
461 float lx0 = p1->x - (dlx0 * w), ly0 = p1->y - (dly0 * w);
462 float rx0 = p1->x + (dlx0 * w), ry0 = p1->y + (dly0 * w);
463 float lx1 = p1->x - (dlx1 * w), ly1 = p1->y - (dly1 * w);
464 float rx1 = p1->x + (dlx1 * w), ry1 = p1->y + (dly1 * w);
466 nsvg__addEdge(r, lx0, ly0, left->x, left->y);
467 nsvg__addEdge(r, lx1, ly1, lx0, ly0);
469 nsvg__addEdge(r, right->x, right->y, rx0, ry0);
470 nsvg__addEdge(r, rx0, ry0, rx1, ry1);
472 left->x = lx1; left->y = ly1;
473 right->x = rx1; right->y = ry1;
476 static void nsvg__miterJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1,
float lineWidth)
478 float w = lineWidth * 0.5f;
479 float dlx0 = p0->dy, dly0 = -p0->dx;
480 float dlx1 = p1->dy, dly1 = -p1->dx;
481 float lx0, rx0, lx1, rx1;
482 float ly0, ry0, ly1, ry1;
484 if (p1->flags & NSVG_PT_LEFT) {
485 lx0 = lx1 = p1->x - p1->dmx * w;
486 ly0 = ly1 = p1->y - p1->dmy * w;
487 nsvg__addEdge(r, lx1, ly1, left->x, left->y);
489 rx0 = p1->x + (dlx0 * w);
490 ry0 = p1->y + (dly0 * w);
491 rx1 = p1->x + (dlx1 * w);
492 ry1 = p1->y + (dly1 * w);
493 nsvg__addEdge(r, right->x, right->y, rx0, ry0);
494 nsvg__addEdge(r, rx0, ry0, rx1, ry1);
496 lx0 = p1->x - (dlx0 * w);
497 ly0 = p1->y - (dly0 * w);
498 lx1 = p1->x - (dlx1 * w);
499 ly1 = p1->y - (dly1 * w);
500 nsvg__addEdge(r, lx0, ly0, left->x, left->y);
501 nsvg__addEdge(r, lx1, ly1, lx0, ly0);
503 rx0 = rx1 = p1->x + p1->dmx * w;
504 ry0 = ry1 = p1->y + p1->dmy * w;
505 nsvg__addEdge(r, right->x, right->y, rx1, ry1);
508 left->x = lx1; left->y = ly1;
509 right->x = rx1; right->y = ry1;
512 static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1,
float lineWidth,
int ncap)
515 float w = lineWidth * 0.5f;
516 float dlx0 = p0->dy, dly0 = -p0->dx;
517 float dlx1 = p1->dy, dly1 = -p1->dx;
518 float a0 = atan2f(dly0, dlx0);
519 float a1 = atan2f(dly1, dlx1);
521 float lx, ly, rx, ry;
523 if (da < NSVG_PI) da += NSVG_PI*2;
524 if (da > NSVG_PI) da -= NSVG_PI*2;
526 n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * ncap);
528 if (n > ncap) n = ncap;
535 for (i = 0; i < n; i++) {
536 float u = i/(float)(n-1);
538 float ax = cosf(a) * w, ay = sinf(a) * w;
539 float lx1 = p1->x - ax, ly1 = p1->y - ay;
540 float rx1 = p1->x + ax, ry1 = p1->y + ay;
542 nsvg__addEdge(r, lx1, ly1, lx, ly);
543 nsvg__addEdge(r, rx, ry, rx1, ry1);
549 left->x = lx; left->y = ly;
550 right->x = rx; right->y = ry;
553 static void nsvg__straightJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p1,
float lineWidth)
555 float w = lineWidth * 0.5f;
556 float lx = p1->x - (p1->dmx * w), ly = p1->y - (p1->dmy * w);
557 float rx = p1->x + (p1->dmx * w), ry = p1->y + (p1->dmy * w);
559 nsvg__addEdge(r, lx, ly, left->x, left->y);
560 nsvg__addEdge(r, right->x, right->y, rx, ry);
562 left->x = lx; left->y = ly;
563 right->x = rx; right->y = ry;
566 static int nsvg__curveDivs(
float r,
float arc,
float tol)
568 float da = acosf(r / (r + tol)) * 2.0f;
569 int divs = (int)ceilf(arc / da);
570 if (divs < 2) divs = 2;
574 static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape,
float scale)
580 float miterLimit = 4;
581 int lineJoin = shape->strokeLineJoin;
582 int lineCap = shape->strokeLineCap;
583 float lineWidth = shape->strokeWidth * scale;
584 int ncap = nsvg__curveDivs(lineWidth*0.5f, NSVG_PI, r->tessTol);
585 NSVGpoint left, right, firstLeft, firstRight;
587 for (path = shape->paths; path != NULL; path = path->next) {
590 nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, NSVG_PT_CORNER);
591 for (i = 0; i < path->npts-1; i += 3) {
592 float* p = &path->pts[i*2];
593 nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, NSVG_PT_CORNER);
598 closed = path->closed;
601 p0 = &r->points[r->npoints-1];
603 if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) {
605 p0 = &r->points[r->npoints-1];
609 for (i = 0; i < r->npoints; i++) {
611 p0->dx = p1->x - p0->x;
612 p0->dy = p1->y - p0->y;
613 p0->len = nsvg__normalize(&p0->dx, &p0->dy);
619 p0 = &r->points[r->npoints-1];
621 for (j = 0; j < r->npoints; j++) {
622 float dlx0, dly0, dlx1, dly1, dmr2, cross;
628 p1->dmx = (dlx0 + dlx1) * 0.5f;
629 p1->dmy = (dly0 + dly1) * 0.5f;
630 dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy;
631 if (dmr2 > 0.000001f) {
632 float s = 1.0f / dmr2;
641 p1->flags = (p1->flags & NSVG_PT_CORNER) ? NSVG_PT_CORNER : 0;
644 cross = p1->dx * p0->dy - p0->dx * p1->dy;
646 p1->flags |= NSVG_PT_LEFT;
649 if (p1->flags & NSVG_PT_CORNER) {
650 if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NSVG_JOIN_BEVEL || lineJoin == NSVG_JOIN_ROUND) {
651 p1->flags |= NSVG_PT_BEVEL;
661 p0 = &r->points[r->npoints-1];
674 nsvg__initClosed(&left, &right, p0, p1, lineWidth);
679 float dx = p1->x - p0->x;
680 float dy = p1->y - p0->y;
681 nsvg__normalize(&dx, &dy);
682 if (lineCap == NSVG_CAP_BUTT)
683 nsvg__buttCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
684 else if (lineCap == NSVG_CAP_SQUARE)
685 nsvg__squareCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
686 else if (lineCap == NSVG_CAP_ROUND)
687 nsvg__roundCap(r, &left, &right, p0, dx, dy, lineWidth, ncap, 0);
690 for (j = s; j < e; ++j) {
692 if (p1->flags & NSVG_PT_CORNER) {
693 if (lineJoin == NSVG_JOIN_ROUND)
694 nsvg__roundJoin(r, &left, &right, p0, p1, lineWidth, ncap);
695 else if (lineJoin == NSVG_JOIN_BEVEL || (p1->flags & NSVG_PT_BEVEL))
696 nsvg__bevelJoin(r, &left, &right, p0, p1, lineWidth);
698 nsvg__miterJoin(r, &left, &right, p0, p1, lineWidth);
700 nsvg__straightJoin(r, &left, &right, p1, lineWidth);
707 nsvg__addEdge(r, firstLeft.x, firstLeft.y, left.x, left.y);
708 nsvg__addEdge(r, right.x, right.y, firstRight.x, firstRight.y);
711 float dx = p1->x - p0->x;
712 float dy = p1->y - p0->y;
713 nsvg__normalize(&dx, &dy);
714 if (lineCap == NSVG_CAP_BUTT)
715 nsvg__buttCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
716 else if (lineCap == NSVG_CAP_SQUARE)
717 nsvg__squareCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
718 else if (lineCap == NSVG_CAP_ROUND)
719 nsvg__roundCap(r, &right, &left, p1, -dx, -dy, lineWidth, ncap, 1);
724 static int nsvg__cmpEdge(
const void *p,
const void *q)
726 NSVGedge* a = (NSVGedge*)p;
727 NSVGedge* b = (NSVGedge*)q;
729 if (a->y0 < b->y0)
return -1;
730 if (a->y0 > b->y0)
return 1;
735 static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e,
float startPoint)
739 if (r->freelist != NULL) {
742 r->freelist = z->next;
745 z = (NSVGactiveEdge*)nsvg__alloc(r,
sizeof(NSVGactiveEdge));
746 if (z == NULL)
return NULL;
749 float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
753 z->dx = -floorf(NSVG__FIX * -dxdy);
755 z->dx = floorf(NSVG__FIX * dxdy);
756 z->x = floorf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0)));
765 static void nsvg__freeActive(NSVGrasterizer* r, NSVGactiveEdge* z)
767 z->next = r->freelist;
774 static void nsvg__fillActiveEdges(
unsigned char* scanline,
int len, NSVGactiveEdge* e,
int maxWeight,
int* xmin,
int* xmax)
782 x0 = e->x; w += e->dir;
784 int x1 = e->x; w += e->dir;
787 int i = x0 >> NSVG__FIXSHIFT;
788 int j = x1 >> NSVG__FIXSHIFT;
789 if (i < *xmin) *xmin = i;
790 if (j > *xmax) *xmax = j;
791 if (i < len && j >= 0) {
794 scanline[i] += (
unsigned char)((x1 - x0) * maxWeight >> NSVG__FIXSHIFT);
797 scanline[i] += (
unsigned char)(((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT);
802 scanline[j] += (
unsigned char)(((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT);
806 for (++i; i < j; ++i)
807 scanline[i] += (
unsigned char)maxWeight;
816 static float nsvg__clampf(
float a,
float mn,
float mx) {
return a < mn ? mn : (a > mx ? mx : a); }
818 static unsigned int nsvg__RGBA(
unsigned char r,
unsigned char g,
unsigned char b,
unsigned char a)
820 return (r) | (g << 8) | (b << 16) | (a << 24);
823 static unsigned int nsvg__lerpRGBA(
unsigned int c0,
unsigned int c1,
float u)
825 int iu = (float)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
826 int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8;
827 int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8;
828 int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8;
829 int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8;
830 return nsvg__RGBA(r,g,b,a);
833 static unsigned int nsvg__applyOpacity(
unsigned int c,
float u)
835 int iu = (float)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
837 int g = (c>>8) & 0xff;
838 int b = (c>>16) & 0xff;
839 int a = (((c>>24) & 0xff)*iu) >> 8;
840 return nsvg__RGBA(r,g,b,a);
843 static void nsvg__scanlineSolid(
unsigned char* dst,
int count,
unsigned char* cover,
int x,
int y,
844 float tx,
float ty,
float scale, NSVGcachedPaint* cache)
847 if (cache->type == NSVG_PAINT_COLOR) {
848 int i, cr, cg, cb, ca;
849 cr = cache->colors[0] & 0xff;
850 cg = (cache->colors[0] >> 8) & 0xff;
851 cb = (cache->colors[0] >> 16) & 0xff;
852 ca = (cache->colors[0] >> 24) & 0xff;
854 for (i = 0; i < count; i++) {
856 int a = ((int)cover[0] * ca) >> 8;
864 r += ((ia * (int)dst[0]) >> 8);
865 g += ((ia * (int)dst[1]) >> 8);
866 b += ((ia * (int)dst[2]) >> 8);
867 a += ((ia * (int)dst[3]) >> 8);
869 dst[0] = (
unsigned char)r;
870 dst[1] = (
unsigned char)g;
871 dst[2] = (
unsigned char)b;
872 dst[3] = (
unsigned char)a;
877 }
else if (cache->type == NSVG_PAINT_LINEAR_GRADIENT) {
880 float fx, fy, dx, gy;
881 float* t = cache->xform;
882 int i, cr, cg, cb, ca;
885 fx = (x - tx) / scale;
886 fy = (y - ty) / scale;
889 for (i = 0; i < count; i++) {
891 gy = fx*t[1] + fy*t[3] + t[5];
892 c = cache->colors[(int)nsvg__clampf(gy*255.0f, 0, 255.0f)];
894 cg = (c >> 8) & 0xff;
895 cb = (c >> 16) & 0xff;
896 ca = (c >> 24) & 0xff;
898 a = ((int)cover[0] * ca) >> 8;
907 r += ((ia * (int)dst[0]) >> 8);
908 g += ((ia * (int)dst[1]) >> 8);
909 b += ((ia * (int)dst[2]) >> 8);
910 a += ((ia * (int)dst[3]) >> 8);
912 dst[0] = (
unsigned char)r;
913 dst[1] = (
unsigned char)g;
914 dst[2] = (
unsigned char)b;
915 dst[3] = (
unsigned char)a;
921 }
else if (cache->type == NSVG_PAINT_RADIAL_GRADIENT) {
925 float fx, fy, dx, gx, gy, gd;
926 float* t = cache->xform;
927 int i, cr, cg, cb, ca;
930 fx = (x - tx) / scale;
931 fy = (y - ty) / scale;
934 for (i = 0; i < count; i++) {
936 gx = fx*t[0] + fy*t[2] + t[4];
937 gy = fx*t[1] + fy*t[3] + t[5];
938 gd = sqrtf(gx*gx + gy*gy);
939 c = cache->colors[(int)nsvg__clampf(gd*255.0f, 0, 255.0f)];
941 cg = (c >> 8) & 0xff;
942 cb = (c >> 16) & 0xff;
943 ca = (c >> 24) & 0xff;
945 a = ((int)cover[0] * ca) >> 8;
954 r += ((ia * (int)dst[0]) >> 8);
955 g += ((ia * (int)dst[1]) >> 8);
956 b += ((ia * (int)dst[2]) >> 8);
957 a += ((ia * (int)dst[3]) >> 8);
959 dst[0] = (
unsigned char)r;
960 dst[1] = (
unsigned char)g;
961 dst[2] = (
unsigned char)b;
962 dst[3] = (
unsigned char)a;
971 static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r,
float tx,
float ty,
float scale, NSVGcachedPaint* cache)
973 NSVGactiveEdge *active = NULL;
976 int maxWeight = (255 / NSVG__SUBSAMPLES);
979 for (y = 0; y < r->height; y++) {
980 memset(r->scanline, 0, r->width);
983 for (s = 0; s < NSVG__SUBSAMPLES; ++s) {
985 float scany = y*NSVG__SUBSAMPLES + s + 0.5f;
986 NSVGactiveEdge **step = &active;
991 NSVGactiveEdge *z = *step;
992 if (z->ey <= scany) {
995 nsvg__freeActive(r, z);
998 step = &((*step)->next);
1006 while (*step && (*step)->next) {
1007 if ((*step)->x > (*step)->next->x) {
1008 NSVGactiveEdge* t = *step;
1009 NSVGactiveEdge* q = t->next;
1015 step = &(*step)->next;
1017 if (!changed)
break;
1021 while (e < r->nedges && r->edges[e].y0 <= scany) {
1022 if (r->edges[e].y1 > scany) {
1023 NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany);
1024 if (z == NULL)
break;
1026 if (active == NULL) {
1028 }
else if (z->x < active->x) {
1034 NSVGactiveEdge* p = active;
1035 while (p->next && p->next->x < z->x)
1047 nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, &xmin, &xmax);
1050 if (xmin < 0) xmin = 0;
1051 if (xmax > r->width-1) xmax = r->width-1;
1053 nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty,scale,cache);
1059 static void nsvg__unpremultiplyAlpha(
unsigned char* image,
int w,
int h,
int stride)
1064 for (y = 0; y < h; y++) {
1065 unsigned char *row = &image[y*stride];
1066 for (x = 0; x < w; x++) {
1067 int r = row[0], g = row[1], b = row[2], a = row[3];
1069 row[0] = (int)(r*255/a);
1070 row[1] = (int)(g*255/a);
1071 row[2] = (int)(b*255/a);
1078 for (y = 0; y < h; y++) {
1079 unsigned char *row = &image[y*stride];
1080 for (x = 0; x < w; x++) {
1081 int r = 0, g = 0, b = 0, a = row[3], n = 0;
1083 if (x-1 > 0 && row[-1] != 0) {
1089 if (x+1 < w && row[7] != 0) {
1095 if (y-1 > 0 && row[-stride+3] != 0) {
1097 g += row[-stride+1];
1098 b += row[-stride+2];
1101 if (y+1 < h && row[stride+3] != 0) {
1119 static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint,
float opacity)
1124 cache->type = paint->type;
1126 if (paint->type == NSVG_PAINT_COLOR) {
1127 cache->colors[0] = nsvg__applyOpacity(paint->color, opacity);
1131 grad = paint->gradient;
1133 cache->spread = grad->spread;
1134 memcpy(cache->xform, grad->xform,
sizeof(
float)*6);
1136 if (grad->nstops == 0) {
1137 for (i = 0; i < 256; i++)
1138 cache->colors[i] = 0;
1139 }
if (grad->nstops == 1) {
1140 for (i = 0; i < 256; i++)
1141 cache->colors[i] = nsvg__applyOpacity(grad->stops[i].color, opacity);
1143 unsigned int ca, cb;
1144 float ua, ub, du, u;
1147 ca = nsvg__applyOpacity(grad->stops[0].color, opacity);
1148 ua = nsvg__clampf(grad->stops[0].offset, 0, 1);
1149 ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1);
1152 for (i = 0; i < ia; i++) {
1153 cache->colors[i] = ca;
1156 for (i = 0; i < grad->nstops-1; i++) {
1157 ca = nsvg__applyOpacity(grad->stops[i].color, opacity);
1158 cb = nsvg__applyOpacity(grad->stops[i+1].color, opacity);
1159 ua = nsvg__clampf(grad->stops[i].offset, 0, 1);
1160 ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1);
1164 if (count <= 0)
continue;
1166 du = 1.0f / (float)count;
1167 for (j = 0; j < count; j++) {
1168 cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u);
1173 for (i = ib; i < 256; i++)
1174 cache->colors[i] = cb;
1221 void nsvgRasterize(NSVGrasterizer* r,
1222 NSVGimage* image,
float tx,
float ty,
float scale,
1223 unsigned char* dst,
int w,
int h,
int stride)
1225 NSVGshape *shape = NULL;
1227 NSVGcachedPaint cache;
1235 if (w > r->cscanline) {
1237 r->scanline = (
unsigned char*)realloc(r->scanline, w);
1238 if (r->scanline == NULL)
return;
1241 for (i = 0; i < h; i++)
1242 memset(&dst[i*stride], 0, w*4);
1244 for (shape = image->shapes; shape != NULL; shape = shape->next) {
1245 if (shape->fill.type != NSVG_PAINT_NONE) {
1250 nsvg__flattenShape(r, shape, scale);
1253 for (i = 0; i < r->nedges; i++) {
1256 e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
1258 e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
1262 qsort(r->edges, r->nedges,
sizeof(NSVGedge), nsvg__cmpEdge);
1265 nsvg__initPaint(&cache, &shape->fill, shape->opacity);
1267 nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache);
1269 if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) {
1274 nsvg__flattenShapeStroke(r, shape, scale);
1279 for (i = 0; i < r->nedges; i++) {
1282 e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
1284 e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
1288 qsort(r->edges, r->nedges,
sizeof(NSVGedge), nsvg__cmpEdge);
1291 nsvg__initPaint(&cache, &shape->stroke, shape->opacity);
1293 nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache);
1297 nsvg__unpremultiplyAlpha(dst, w, h, stride);