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
135 NSVGactiveEdge* freelist;
137 NSVGmemPage* curpage;
139 unsigned char* scanline;
142 unsigned char* bitmap;
143 int width, height, stride;
146 NSVGrasterizer* nsvgCreateRasterizer()
148 NSVGrasterizer* r = (NSVGrasterizer*)malloc(
sizeof(NSVGrasterizer));
149 if (r == NULL)
goto error;
150 memset(r, 0,
sizeof(NSVGrasterizer));
158 nsvgDeleteRasterizer(r);
162 void nsvgDeleteRasterizer(NSVGrasterizer* r)
166 if (r == NULL)
return;
170 NSVGmemPage* next = p->next;
175 if (r->edges) free(r->edges);
176 if (r->points) free(r->points);
177 if (r->points2) free(r->points2);
178 if (r->scanline) free(r->scanline);
183 static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur)
188 if (cur != NULL && cur->next != NULL) {
193 newp = (NSVGmemPage*)malloc(
sizeof(NSVGmemPage));
194 if (newp == NULL)
return NULL;
195 memset(newp, 0,
sizeof(NSVGmemPage));
206 static void nsvg__resetPool(NSVGrasterizer* r)
208 NSVGmemPage* p = r->pages;
213 r->curpage = r->pages;
216 static unsigned char* nsvg__alloc(NSVGrasterizer* r,
int size)
219 if (size > NSVG__MEMPAGE_SIZE)
return NULL;
220 if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) {
221 r->curpage = nsvg__nextPage(r, r->curpage);
223 buf = &r->curpage->mem[r->curpage->size];
224 r->curpage->size += size;
228 static int nsvg__ptEquals(
float x1,
float y1,
float x2,
float y2,
float tol)
232 return dx*dx + dy*dy < tol*tol;
235 static void nsvg__addPathPoint(NSVGrasterizer* r,
float x,
float y,
int flags)
239 if (r->npoints > 0) {
240 pt = &r->points[r->npoints-1];
241 if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) {
242 pt->flags = (
unsigned char)(pt->flags | flags);
247 if (r->npoints+1 > r->cpoints) {
248 r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
249 r->points = (NSVGpoint*)realloc(r->points,
sizeof(NSVGpoint) * r->cpoints);
250 if (r->points == NULL)
return;
253 pt = &r->points[r->npoints];
256 pt->flags = (
unsigned char)flags;
260 static void nsvg__appendPathPoint(NSVGrasterizer* r, NSVGpoint pt)
262 if (r->npoints+1 > r->cpoints) {
263 r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
264 r->points = (NSVGpoint*)realloc(r->points,
sizeof(NSVGpoint) * r->cpoints);
265 if (r->points == NULL)
return;
267 r->points[r->npoints] = pt;
271 static void nsvg__duplicatePoints(NSVGrasterizer* r)
273 if (r->npoints > r->cpoints2) {
274 r->cpoints2 = r->npoints;
275 r->points2 = (NSVGpoint*)realloc(r->points2,
sizeof(NSVGpoint) * r->cpoints2);
276 if (r->points2 == NULL)
return;
279 memcpy(r->points2, r->points,
sizeof(NSVGpoint) * r->npoints);
280 r->npoints2 = r->npoints;
283 static void nsvg__addEdge(NSVGrasterizer* r,
float x0,
float y0,
float x1,
float y1)
291 if (r->nedges+1 > r->cedges) {
292 r->cedges = r->cedges > 0 ? r->cedges * 2 : 64;
293 r->edges = (NSVGedge*)realloc(r->edges,
sizeof(NSVGedge) * r->cedges);
294 if (r->edges == NULL)
return;
297 e = &r->edges[r->nedges];
315 static float nsvg__normalize(
float *x,
float* y)
317 float d = sqrtf((*x)*(*x) + (*y)*(*y));
326 static float nsvg__absf(
float x) {
return x < 0 ? -x : x; }
328 static void nsvg__flattenCubicBez(NSVGrasterizer* r,
329 float x1,
float y1,
float x2,
float y2,
330 float x3,
float y3,
float x4,
float y4,
333 float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;
336 if (level > 10)
return;
344 x123 = (x12+x23)*0.5f;
345 y123 = (y12+y23)*0.5f;
349 d2 = nsvg__absf(((x2 - x4) * dy - (y2 - y4) * dx));
350 d3 = nsvg__absf(((x3 - x4) * dy - (y3 - y4) * dx));
352 if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) {
353 nsvg__addPathPoint(r, x4, y4, type);
357 x234 = (x23+x34)*0.5f;
358 y234 = (y23+y34)*0.5f;
359 x1234 = (x123+x234)*0.5f;
360 y1234 = (y123+y234)*0.5f;
362 nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0);
363 nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type);
366 static void nsvg__flattenShape(NSVGrasterizer* r,
NSVGshape* shape,
float scale)
371 for (path = shape->paths; path != NULL; path = path->next) {
374 nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0);
375 for (i = 0; i < path->npts-1; i += 3) {
376 float* p = &path->pts[i*2];
377 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);
380 nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0);
382 for (i = 0, j = r->npoints-1; i < r->npoints; j = i++)
383 nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y);
389 NSVG_PT_CORNER = 0x01,
390 NSVG_PT_BEVEL = 0x02,
394 static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1,
float lineWidth)
396 float w = lineWidth * 0.5f;
397 float dx = p1->x - p0->x;
398 float dy = p1->y - p0->y;
399 float len = nsvg__normalize(&dx, &dy);
400 float px = p0->x + dx*len*0.5f, py = p0->y + dy*len*0.5f;
401 float dlx = dy, dly = -dx;
402 float lx = px - dlx*w, ly = py - dly*w;
403 float rx = px + dlx*w, ry = py + dly*w;
404 left->x = lx; left->y = ly;
405 right->x = rx; right->y = ry;
408 static void nsvg__buttCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p,
float dx,
float dy,
float lineWidth,
int connect)
410 float w = lineWidth * 0.5f;
411 float px = p->x, py = p->y;
412 float dlx = dy, dly = -dx;
413 float lx = px - dlx*w, ly = py - dly*w;
414 float rx = px + dlx*w, ry = py + dly*w;
416 nsvg__addEdge(r, lx, ly, rx, ry);
419 nsvg__addEdge(r, left->x, left->y, lx, ly);
420 nsvg__addEdge(r, rx, ry, right->x, right->y);
422 left->x = lx; left->y = ly;
423 right->x = rx; right->y = ry;
426 static void nsvg__squareCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p,
float dx,
float dy,
float lineWidth,
int connect)
428 float w = lineWidth * 0.5f;
429 float px = p->x - dx*w, py = p->y - dy*w;
430 float dlx = dy, dly = -dx;
431 float lx = px - dlx*w, ly = py - dly*w;
432 float rx = px + dlx*w, ry = py + dly*w;
434 nsvg__addEdge(r, lx, ly, rx, ry);
437 nsvg__addEdge(r, left->x, left->y, lx, ly);
438 nsvg__addEdge(r, rx, ry, right->x, right->y);
440 left->x = lx; left->y = ly;
441 right->x = rx; right->y = ry;
445 #define NSVG_PI (3.14159265358979323846264338327f)
448 static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p,
float dx,
float dy,
float lineWidth,
int ncap,
int connect)
451 float w = lineWidth * 0.5f;
452 float px = p->x, py = p->y;
453 float dlx = dy, dly = -dx;
454 float lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0;
456 for (i = 0; i < ncap; i++) {
457 float a = (float)i/(
float)(ncap-1)*NSVG_PI;
458 float ax = cosf(a) * w, ay = sinf(a) * w;
459 float x = px - dlx*ax - dx*ay;
460 float y = py - dly*ax - dy*ay;
463 nsvg__addEdge(r, prevx, prevy, x, y);
470 }
else if (i == ncap-1) {
476 nsvg__addEdge(r, left->x, left->y, lx, ly);
477 nsvg__addEdge(r, rx, ry, right->x, right->y);
480 left->x = lx; left->y = ly;
481 right->x = rx; right->y = ry;
484 static void nsvg__bevelJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1,
float lineWidth)
486 float w = lineWidth * 0.5f;
487 float dlx0 = p0->dy, dly0 = -p0->dx;
488 float dlx1 = p1->dy, dly1 = -p1->dx;
489 float lx0 = p1->x - (dlx0 * w), ly0 = p1->y - (dly0 * w);
490 float rx0 = p1->x + (dlx0 * w), ry0 = p1->y + (dly0 * w);
491 float lx1 = p1->x - (dlx1 * w), ly1 = p1->y - (dly1 * w);
492 float rx1 = p1->x + (dlx1 * w), ry1 = p1->y + (dly1 * w);
494 nsvg__addEdge(r, lx0, ly0, left->x, left->y);
495 nsvg__addEdge(r, lx1, ly1, lx0, ly0);
497 nsvg__addEdge(r, right->x, right->y, rx0, ry0);
498 nsvg__addEdge(r, rx0, ry0, rx1, ry1);
500 left->x = lx1; left->y = ly1;
501 right->x = rx1; right->y = ry1;
504 static void nsvg__miterJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1,
float lineWidth)
506 float w = lineWidth * 0.5f;
507 float dlx0 = p0->dy, dly0 = -p0->dx;
508 float dlx1 = p1->dy, dly1 = -p1->dx;
509 float lx0, rx0, lx1, rx1;
510 float ly0, ry0, ly1, ry1;
512 if (p1->flags & NSVG_PT_LEFT) {
513 lx0 = lx1 = p1->x - p1->dmx * w;
514 ly0 = ly1 = p1->y - p1->dmy * w;
515 nsvg__addEdge(r, lx1, ly1, left->x, left->y);
517 rx0 = p1->x + (dlx0 * w);
518 ry0 = p1->y + (dly0 * w);
519 rx1 = p1->x + (dlx1 * w);
520 ry1 = p1->y + (dly1 * w);
521 nsvg__addEdge(r, right->x, right->y, rx0, ry0);
522 nsvg__addEdge(r, rx0, ry0, rx1, ry1);
524 lx0 = p1->x - (dlx0 * w);
525 ly0 = p1->y - (dly0 * w);
526 lx1 = p1->x - (dlx1 * w);
527 ly1 = p1->y - (dly1 * w);
528 nsvg__addEdge(r, lx0, ly0, left->x, left->y);
529 nsvg__addEdge(r, lx1, ly1, lx0, ly0);
531 rx0 = rx1 = p1->x + p1->dmx * w;
532 ry0 = ry1 = p1->y + p1->dmy * w;
533 nsvg__addEdge(r, right->x, right->y, rx1, ry1);
536 left->x = lx1; left->y = ly1;
537 right->x = rx1; right->y = ry1;
540 static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1,
float lineWidth,
int ncap)
543 float w = lineWidth * 0.5f;
544 float dlx0 = p0->dy, dly0 = -p0->dx;
545 float dlx1 = p1->dy, dly1 = -p1->dx;
546 float a0 = atan2f(dly0, dlx0);
547 float a1 = atan2f(dly1, dlx1);
549 float lx, ly, rx, ry;
551 if (da < NSVG_PI) da += NSVG_PI*2;
552 if (da > NSVG_PI) da -= NSVG_PI*2;
554 n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * (float)ncap);
556 if (n > ncap) n = ncap;
563 for (i = 0; i < n; i++) {
564 float u = (float)i/(
float)(n-1);
566 float ax = cosf(a) * w, ay = sinf(a) * w;
567 float lx1 = p1->x - ax, ly1 = p1->y - ay;
568 float rx1 = p1->x + ax, ry1 = p1->y + ay;
570 nsvg__addEdge(r, lx1, ly1, lx, ly);
571 nsvg__addEdge(r, rx, ry, rx1, ry1);
577 left->x = lx; left->y = ly;
578 right->x = rx; right->y = ry;
581 static void nsvg__straightJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p1,
float lineWidth)
583 float w = lineWidth * 0.5f;
584 float lx = p1->x - (p1->dmx * w), ly = p1->y - (p1->dmy * w);
585 float rx = p1->x + (p1->dmx * w), ry = p1->y + (p1->dmy * w);
587 nsvg__addEdge(r, lx, ly, left->x, left->y);
588 nsvg__addEdge(r, right->x, right->y, rx, ry);
590 left->x = lx; left->y = ly;
591 right->x = rx; right->y = ry;
594 static int nsvg__curveDivs(
float r,
float arc,
float tol)
596 float da = acosf(r / (r + tol)) * 2.0f;
597 int divs = (int)ceilf(arc / da);
598 if (divs < 2) divs = 2;
602 static void nsvg__expandStroke(NSVGrasterizer* r, NSVGpoint* points,
int npoints,
int closed,
int lineJoin,
int lineCap,
float lineWidth)
604 int ncap = nsvg__curveDivs(lineWidth*0.5f, NSVG_PI, r->tessTol);
605 NSVGpoint left = {0,0,0,0,0,0,0,0}, right = {0,0,0,0,0,0,0,0}, firstLeft = {0,0,0,0,0,0,0,0}, firstRight = {0,0,0,0,0,0,0,0};
612 p0 = &points[npoints-1];
625 nsvg__initClosed(&left, &right, p0, p1, lineWidth);
630 float dx = p1->x - p0->x;
631 float dy = p1->y - p0->y;
632 nsvg__normalize(&dx, &dy);
633 if (lineCap == NSVG_CAP_BUTT)
634 nsvg__buttCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
635 else if (lineCap == NSVG_CAP_SQUARE)
636 nsvg__squareCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
637 else if (lineCap == NSVG_CAP_ROUND)
638 nsvg__roundCap(r, &left, &right, p0, dx, dy, lineWidth, ncap, 0);
641 for (j = s; j < e; ++j) {
642 if (p1->flags & NSVG_PT_CORNER) {
643 if (lineJoin == NSVG_JOIN_ROUND)
644 nsvg__roundJoin(r, &left, &right, p0, p1, lineWidth, ncap);
645 else if (lineJoin == NSVG_JOIN_BEVEL || (p1->flags & NSVG_PT_BEVEL))
646 nsvg__bevelJoin(r, &left, &right, p0, p1, lineWidth);
648 nsvg__miterJoin(r, &left, &right, p0, p1, lineWidth);
650 nsvg__straightJoin(r, &left, &right, p1, lineWidth);
657 nsvg__addEdge(r, firstLeft.x, firstLeft.y, left.x, left.y);
658 nsvg__addEdge(r, right.x, right.y, firstRight.x, firstRight.y);
661 float dx = p1->x - p0->x;
662 float dy = p1->y - p0->y;
663 nsvg__normalize(&dx, &dy);
664 if (lineCap == NSVG_CAP_BUTT)
665 nsvg__buttCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
666 else if (lineCap == NSVG_CAP_SQUARE)
667 nsvg__squareCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
668 else if (lineCap == NSVG_CAP_ROUND)
669 nsvg__roundCap(r, &right, &left, p1, -dx, -dy, lineWidth, ncap, 1);
673 static void nsvg__prepareStroke(NSVGrasterizer* r,
float miterLimit,
int lineJoin)
678 p0 = &r->points[r->npoints-1];
680 for (i = 0; i < r->npoints; i++) {
682 p0->dx = p1->x - p0->x;
683 p0->dy = p1->y - p0->y;
684 p0->len = nsvg__normalize(&p0->dx, &p0->dy);
690 p0 = &r->points[r->npoints-1];
692 for (j = 0; j < r->npoints; j++) {
693 float dlx0, dly0, dlx1, dly1, dmr2, cross;
699 p1->dmx = (dlx0 + dlx1) * 0.5f;
700 p1->dmy = (dly0 + dly1) * 0.5f;
701 dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy;
702 if (dmr2 > 0.000001f) {
703 float s2 = 1.0f / dmr2;
712 p1->flags = (p1->flags & NSVG_PT_CORNER) ? NSVG_PT_CORNER : 0;
715 cross = p1->dx * p0->dy - p0->dx * p1->dy;
717 p1->flags |= NSVG_PT_LEFT;
720 if (p1->flags & NSVG_PT_CORNER) {
721 if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NSVG_JOIN_BEVEL || lineJoin == NSVG_JOIN_ROUND) {
722 p1->flags |= NSVG_PT_BEVEL;
730 static void nsvg__flattenShapeStroke(NSVGrasterizer* r,
NSVGshape* shape,
float scale)
735 float miterLimit = shape->miterLimit;
736 int lineJoin = shape->strokeLineJoin;
737 int lineCap = shape->strokeLineCap;
738 float lineWidth = shape->strokeWidth * scale;
740 for (path = shape->paths; path != NULL; path = path->next) {
743 nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, NSVG_PT_CORNER);
744 for (i = 0; i < path->npts-1; i += 3) {
745 float* p = &path->pts[i*2];
746 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);
751 closed = path->closed;
754 p0 = &r->points[r->npoints-1];
756 if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) {
758 p0 = &r->points[r->npoints-1];
762 if (shape->strokeDashCount > 0) {
763 int idash = 0, dashState = 1;
764 float totalDist = 0, dashLen, allDashLen, dashOffset;
768 nsvg__appendPathPoint(r, r->points[0]);
771 nsvg__duplicatePoints(r);
775 nsvg__appendPathPoint(r, cur);
779 for (j = 0; j < shape->strokeDashCount; j++)
780 allDashLen += shape->strokeDashArray[j];
781 if (shape->strokeDashCount & 1)
784 dashOffset = fmodf(shape->strokeDashOffset, allDashLen);
785 if (dashOffset < 0.0f)
786 dashOffset += allDashLen;
788 while (dashOffset > shape->strokeDashArray[idash]) {
789 dashOffset -= shape->strokeDashArray[idash];
790 idash = (idash + 1) % shape->strokeDashCount;
792 dashLen = (shape->strokeDashArray[idash] - dashOffset) * scale;
794 for (j = 1; j < r->npoints2; ) {
795 float dx = r->points2[j].x - cur.x;
796 float dy = r->points2[j].y - cur.y;
797 float dist = sqrtf(dx*dx + dy*dy);
799 if ((totalDist + dist) > dashLen) {
801 float d = (dashLen - totalDist) / dist;
802 float x = cur.x + dx * d;
803 float y = cur.y + dy * d;
804 nsvg__addPathPoint(r, x, y, NSVG_PT_CORNER);
807 if (r->npoints > 1 && dashState) {
808 nsvg__prepareStroke(r, miterLimit, lineJoin);
809 nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);
812 dashState = !dashState;
813 idash = (idash+1) % shape->strokeDashCount;
814 dashLen = shape->strokeDashArray[idash] * scale;
818 cur.flags = NSVG_PT_CORNER;
821 nsvg__appendPathPoint(r, cur);
825 nsvg__appendPathPoint(r, cur);
830 if (r->npoints > 1 && dashState)
831 nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);
833 nsvg__prepareStroke(r, miterLimit, lineJoin);
834 nsvg__expandStroke(r, r->points, r->npoints, closed, lineJoin, lineCap, lineWidth);
839 static int nsvg__cmpEdge(
const void *p,
const void *q)
841 const NSVGedge* a = (
const NSVGedge*)p;
842 const NSVGedge* b = (
const NSVGedge*)q;
844 if (a->y0 < b->y0)
return -1;
845 if (a->y0 > b->y0)
return 1;
850 static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e,
float startPoint)
854 if (r->freelist != NULL) {
857 r->freelist = z->next;
860 z = (NSVGactiveEdge*)nsvg__alloc(r,
sizeof(NSVGactiveEdge));
861 if (z == NULL)
return NULL;
864 float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
868 z->dx = (int)(-floorf(NSVG__FIX * -dxdy));
870 z->dx = (int)floorf(NSVG__FIX * dxdy);
871 z->x = (int)floorf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0)));
880 static void nsvg__freeActive(NSVGrasterizer* r, NSVGactiveEdge* z)
882 z->next = r->freelist;
886 static void nsvg__fillScanline(
unsigned char* scanline,
int len,
int x0,
int x1,
int maxWeight,
int* xmin,
int* xmax)
888 int i = x0 >> NSVG__FIXSHIFT;
889 int j = x1 >> NSVG__FIXSHIFT;
890 if (i < *xmin) *xmin = i;
891 if (j > *xmax) *xmax = j;
892 if (i < len && j >= 0) {
895 scanline[i] = (
unsigned char)(scanline[i] + ((x1 - x0) * maxWeight >> NSVG__FIXSHIFT));
898 scanline[i] = (
unsigned char)(scanline[i] + (((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT));
903 scanline[j] = (
unsigned char)(scanline[j] + (((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT));
907 for (++i; i < j; ++i)
908 scanline[i] = (
unsigned char)(scanline[i] + maxWeight);
916 static void nsvg__fillActiveEdges(
unsigned char* scanline,
int len, NSVGactiveEdge* e,
int maxWeight,
int* xmin,
int* xmax,
char fillRule)
921 if (fillRule == NSVG_FILLRULE_NONZERO) {
926 x0 = e->x; w += e->dir;
928 int x1 = e->x; w += e->dir;
931 nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);
935 }
else if (fillRule == NSVG_FILLRULE_EVENODD) {
942 int x1 = e->x; w = 0;
943 nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);
950 static float nsvg__clampf(
float a,
float mn,
float mx) {
return a < mn ? mn : (a > mx ? mx : a); }
952 static unsigned int nsvg__RGBA(
unsigned char r,
unsigned char g,
unsigned char b,
unsigned char a)
954 return (r) | (g << 8) | (b << 16) | (a << 24);
957 static unsigned int nsvg__lerpRGBA(
unsigned int c0,
unsigned int c1,
float u)
959 int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
960 int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8;
961 int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8;
962 int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8;
963 int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8;
964 return nsvg__RGBA((
unsigned char)r, (
unsigned char)g, (
unsigned char)b, (
unsigned char)a);
967 static unsigned int nsvg__applyOpacity(
unsigned int c,
float u)
969 int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
971 int g = (c>>8) & 0xff;
972 int b = (c>>16) & 0xff;
973 int a = (((c>>24) & 0xff)*iu) >> 8;
974 return nsvg__RGBA((
unsigned char)r, (
unsigned char)g, (
unsigned char)b, (
unsigned char)a);
977 static inline int nsvg__div255(
int x)
979 return ((x+1) * 257) >> 16;
982 static void nsvg__scanlineSolid(
unsigned char* dst,
int count,
unsigned char* cover,
int x,
int y,
983 float tx,
float ty,
float scale, NSVGcachedPaint* cache)
986 if (cache->type == NSVG_PAINT_COLOR) {
987 int i, cr, cg, cb, ca;
988 cr = cache->colors[0] & 0xff;
989 cg = (cache->colors[0] >> 8) & 0xff;
990 cb = (cache->colors[0] >> 16) & 0xff;
991 ca = (cache->colors[0] >> 24) & 0xff;
993 for (i = 0; i < count; i++) {
995 int a = nsvg__div255((
int)cover[0] * ca);
998 r = nsvg__div255(cr * a);
999 g = nsvg__div255(cg * a);
1000 b = nsvg__div255(cb * a);
1003 r += nsvg__div255(ia * (
int)dst[0]);
1004 g += nsvg__div255(ia * (
int)dst[1]);
1005 b += nsvg__div255(ia * (
int)dst[2]);
1006 a += nsvg__div255(ia * (
int)dst[3]);
1008 dst[0] = (
unsigned char)r;
1009 dst[1] = (
unsigned char)g;
1010 dst[2] = (
unsigned char)b;
1011 dst[3] = (
unsigned char)a;
1016 }
else if (cache->type == NSVG_PAINT_LINEAR_GRADIENT) {
1019 float fx, fy, dx, gy;
1020 float* t = cache->xform;
1021 int i, cr, cg, cb, ca;
1024 fx = ((float)x - tx) / scale;
1025 fy = ((float)y - ty) / scale;
1028 for (i = 0; i < count; i++) {
1030 gy = fx*t[1] + fy*t[3] + t[5];
1031 c = cache->colors[(int)nsvg__clampf(gy*255.0f, 0, 255.0f)];
1033 cg = (c >> 8) & 0xff;
1034 cb = (c >> 16) & 0xff;
1035 ca = (c >> 24) & 0xff;
1037 a = nsvg__div255((
int)cover[0] * ca);
1041 r = nsvg__div255(cr * a);
1042 g = nsvg__div255(cg * a);
1043 b = nsvg__div255(cb * a);
1046 r += nsvg__div255(ia * (
int)dst[0]);
1047 g += nsvg__div255(ia * (
int)dst[1]);
1048 b += nsvg__div255(ia * (
int)dst[2]);
1049 a += nsvg__div255(ia * (
int)dst[3]);
1051 dst[0] = (
unsigned char)r;
1052 dst[1] = (
unsigned char)g;
1053 dst[2] = (
unsigned char)b;
1054 dst[3] = (
unsigned char)a;
1060 }
else if (cache->type == NSVG_PAINT_RADIAL_GRADIENT) {
1064 float fx, fy, dx, gx, gy, gd;
1065 float* t = cache->xform;
1066 int i, cr, cg, cb, ca;
1069 fx = ((float)x - tx) / scale;
1070 fy = ((float)y - ty) / scale;
1073 for (i = 0; i < count; i++) {
1075 gx = fx*t[0] + fy*t[2] + t[4];
1076 gy = fx*t[1] + fy*t[3] + t[5];
1077 gd = sqrtf(gx*gx + gy*gy);
1078 c = cache->colors[(int)nsvg__clampf(gd*255.0f, 0, 255.0f)];
1080 cg = (c >> 8) & 0xff;
1081 cb = (c >> 16) & 0xff;
1082 ca = (c >> 24) & 0xff;
1084 a = nsvg__div255((
int)cover[0] * ca);
1088 r = nsvg__div255(cr * a);
1089 g = nsvg__div255(cg * a);
1090 b = nsvg__div255(cb * a);
1093 r += nsvg__div255(ia * (
int)dst[0]);
1094 g += nsvg__div255(ia * (
int)dst[1]);
1095 b += nsvg__div255(ia * (
int)dst[2]);
1096 a += nsvg__div255(ia * (
int)dst[3]);
1098 dst[0] = (
unsigned char)r;
1099 dst[1] = (
unsigned char)g;
1100 dst[2] = (
unsigned char)b;
1101 dst[3] = (
unsigned char)a;
1110 static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r,
float tx,
float ty,
float scale, NSVGcachedPaint* cache,
char fillRule)
1112 NSVGactiveEdge *active = NULL;
1115 int maxWeight = (255 / NSVG__SUBSAMPLES);
1118 for (y = 0; y < r->height; y++) {
1119 memset(r->scanline, 0, r->width);
1122 for (s = 0; s < NSVG__SUBSAMPLES; ++s) {
1124 float scany = (float)(y*NSVG__SUBSAMPLES + s) + 0.5f;
1125 NSVGactiveEdge **step = &active;
1130 NSVGactiveEdge *z = *step;
1131 if (z->ey <= scany) {
1134 nsvg__freeActive(r, z);
1137 step = &((*step)->next);
1145 while (*step && (*step)->next) {
1146 if ((*step)->x > (*step)->next->x) {
1147 NSVGactiveEdge* t = *step;
1148 NSVGactiveEdge* q = t->next;
1154 step = &(*step)->next;
1156 if (!changed)
break;
1160 while (e < r->nedges && r->edges[e].y0 <= scany) {
1161 if (r->edges[e].y1 > scany) {
1162 NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany);
1163 if (z == NULL)
break;
1165 if (active == NULL) {
1167 }
else if (z->x < active->x) {
1173 NSVGactiveEdge* p = active;
1174 while (p->next && p->next->x < z->x)
1186 nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, &xmin, &xmax, fillRule);
1189 if (xmin < 0) xmin = 0;
1190 if (xmax > r->width-1) xmax = r->width-1;
1192 nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty, scale, cache);
1198 static void nsvg__unpremultiplyAlpha(
unsigned char* image,
int w,
int h,
int stride)
1203 for (y = 0; y < h; y++) {
1204 unsigned char *row = &image[y*stride];
1205 for (x = 0; x < w; x++) {
1206 int r = row[0], g = row[1], b = row[2], a = row[3];
1208 row[0] = (
unsigned char)(r*255/a);
1209 row[1] = (
unsigned char)(g*255/a);
1210 row[2] = (
unsigned char)(b*255/a);
1217 for (y = 0; y < h; y++) {
1218 unsigned char *row = &image[y*stride];
1219 for (x = 0; x < w; x++) {
1220 int r = 0, g = 0, b = 0, a = row[3], n = 0;
1222 if (x-1 > 0 && row[-1] != 0) {
1228 if (x+1 < w && row[7] != 0) {
1234 if (y-1 > 0 && row[-stride+3] != 0) {
1236 g += row[-stride+1];
1237 b += row[-stride+2];
1240 if (y+1 < h && row[stride+3] != 0) {
1247 row[0] = (
unsigned char)(r/n);
1248 row[1] = (
unsigned char)(g/n);
1249 row[2] = (
unsigned char)(b/n);
1258 static void nsvg__initPaint(NSVGcachedPaint* cache,
NSVGpaint* paint,
float opacity)
1263 cache->type = paint->type;
1265 if (paint->type == NSVG_PAINT_COLOR) {
1266 cache->colors[0] = nsvg__applyOpacity(paint->color, opacity);
1270 grad = paint->gradient;
1272 cache->spread = grad->spread;
1273 memcpy(cache->xform, grad->xform,
sizeof(
float)*6);
1275 if (grad->nstops == 0) {
1276 for (i = 0; i < 256; i++)
1277 cache->colors[i] = 0;
1278 }
if (grad->nstops == 1) {
1279 for (i = 0; i < 256; i++)
1280 cache->colors[i] = nsvg__applyOpacity(grad->stops[i].color, opacity);
1282 unsigned int ca, cb = 0;
1283 float ua, ub, du, u;
1286 ca = nsvg__applyOpacity(grad->stops[0].color, opacity);
1287 ua = nsvg__clampf(grad->stops[0].offset, 0, 1);
1288 ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1);
1289 ia = (int)(ua * 255.0f);
1290 ib = (int)(ub * 255.0f);
1291 for (i = 0; i < ia; i++) {
1292 cache->colors[i] = ca;
1295 for (i = 0; i < grad->nstops-1; i++) {
1296 ca = nsvg__applyOpacity(grad->stops[i].color, opacity);
1297 cb = nsvg__applyOpacity(grad->stops[i+1].color, opacity);
1298 ua = nsvg__clampf(grad->stops[i].offset, 0, 1);
1299 ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1);
1300 ia = (int)(ua * 255.0f);
1301 ib = (int)(ub * 255.0f);
1303 if (count <= 0)
continue;
1305 du = 1.0f / (float)count;
1306 for (j = 0; j < count; j++) {
1307 cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u);
1312 for (i = ib; i < 256; i++)
1313 cache->colors[i] = cb;
1360 void nsvgRasterize(NSVGrasterizer* r,
1361 NSVGimage* image,
float tx,
float ty,
float scale,
1362 unsigned char* dst,
int w,
int h,
int stride)
1366 NSVGcachedPaint cache;
1374 if (w > r->cscanline) {
1376 r->scanline = (
unsigned char*)realloc(r->scanline, w);
1377 if (r->scanline == NULL)
return;
1380 for (i = 0; i < h; i++)
1381 memset(&dst[i*stride], 0, w*4);
1383 for (shape = image->shapes; shape != NULL; shape = shape->next) {
1384 if (!(shape->flags & NSVG_FLAGS_VISIBLE))
1387 if (shape->fill.type != NSVG_PAINT_NONE) {
1392 nsvg__flattenShape(r, shape, scale);
1395 for (i = 0; i < r->nedges; i++) {
1398 e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
1400 e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
1404 qsort(r->edges, r->nedges,
sizeof(NSVGedge), nsvg__cmpEdge);
1407 nsvg__initPaint(&cache, &shape->fill, shape->opacity);
1409 nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, shape->fillRule);
1411 if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) {
1416 nsvg__flattenShapeStroke(r, shape, scale);
1421 for (i = 0; i < r->nedges; i++) {
1424 e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
1426 e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
1430 qsort(r->edges, r->nedges,
sizeof(NSVGedge), nsvg__cmpEdge);
1433 nsvg__initPaint(&cache, &shape->stroke, shape->opacity);
1435 nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO);
1439 nsvg__unpremultiplyAlpha(dst, w, h, stride);
Definition: nanosvg.h:156
Definition: nanosvg.h:127
Definition: nanosvg.h:136
Definition: nanosvg.h:111
Definition: nanosvg.h:119