33 #ifndef NANOSVGRAST_CPLUSPLUS
67 unsigned char* dst,
int w,
int h,
int stride);
70 double tx,
double ty,
double scalex,
double scaley,
71 unsigned char* dst,
int w,
int h,
int stride,
int bgr);
77 #ifndef NANOSVGRAST_CPLUSPLUS
85 #ifdef NANOSVGRAST_IMPLEMENTATION
89 #define NSVG__SUBSAMPLES 5
90 #define NSVG__FIXSHIFT 10
91 #define NSVG__FIX (1 << NSVG__FIXSHIFT)
92 #define NSVG__FIXMASK (NSVG__FIX-1)
93 #define NSVG__MEMPAGE_SIZE 1024
95 typedef struct NSVGedge {
98 struct NSVGedge* next;
101 typedef struct NSVGpoint {
109 typedef struct NSVGactiveEdge {
113 struct NSVGactiveEdge *next;
116 typedef struct NSVGmemPage {
117 unsigned char mem[NSVG__MEMPAGE_SIZE];
119 struct NSVGmemPage* next;
122 typedef struct NSVGcachedPaint {
148 NSVGactiveEdge* freelist;
150 NSVGmemPage* curpage;
152 unsigned char* scanline;
155 unsigned char* bitmap;
162 if (r ==
nullptr)
goto error;
179 if (r ==
nullptr)
return;
182 while (
p !=
nullptr) {
183 NSVGmemPage* next =
p->next;
188 if (r->edges) free(r->edges);
189 if (r->points) free(r->points);
190 if (r->points2) free(r->points2);
191 if (r->scanline) free(r->scanline);
196 static NSVGmemPage* nsvg__nextPage(
NSVGrasterizer* r, NSVGmemPage* cur)
201 if (cur !=
nullptr && cur->next !=
nullptr) {
206 newp =
static_cast<NSVGmemPage*
>(malloc(
sizeof(NSVGmemPage)));
207 if (newp ==
nullptr)
return nullptr;
208 memset(newp, 0,
sizeof(NSVGmemPage));
221 NSVGmemPage*
p = r->pages;
222 while (
p !=
nullptr) {
226 r->curpage = r->pages;
232 if (
size > NSVG__MEMPAGE_SIZE)
return nullptr;
233 if (r->curpage ==
nullptr || r->curpage->size+
size > NSVG__MEMPAGE_SIZE) {
234 r->curpage = nsvg__nextPage(r, r->curpage);
236 buf = &r->curpage->mem[r->curpage->size];
237 r->curpage->size +=
size;
241 static int nsvg__ptEquals(
double x1,
double y1,
double x2,
double y2,
double tol)
245 return dx*dx + dy*dy < tol*tol;
248 static void nsvg__addPathPoint(
NSVGrasterizer* r,
double x,
double y,
int flags)
252 if (r->npoints > 0) {
253 pt = &r->points[r->npoints-1];
254 if (nsvg__ptEquals(pt->x,pt->y,
x,
y, r->distTol)) {
255 pt->flags =
static_cast<unsigned char>(pt->flags | flags);
260 if (r->npoints+1 > r->cpoints) {
261 r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
262 r->points =
static_cast<NSVGpoint*
>(realloc(r->points,
sizeof(NSVGpoint) * r->cpoints));
263 if (r->points ==
nullptr)
return;
266 pt = &r->points[r->npoints];
269 pt->flags =
static_cast<unsigned char>(flags);
273 static void nsvg__appendPathPoint(
NSVGrasterizer* r, NSVGpoint pt)
275 if (r->npoints+1 > r->cpoints) {
276 r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
277 r->points =
static_cast<NSVGpoint*
>(realloc(r->points,
sizeof(NSVGpoint) * r->cpoints));
278 if (r->points ==
nullptr)
return;
280 r->points[r->npoints] = pt;
286 if (r->npoints > r->cpoints2) {
287 r->cpoints2 = r->npoints;
288 r->points2 =
static_cast<NSVGpoint*
>(realloc(r->points2,
sizeof(NSVGpoint) * r->cpoints2));
289 if (r->points2 ==
nullptr)
return;
292 memcpy(r->points2, r->points,
sizeof(NSVGpoint) * r->npoints);
293 r->npoints2 = r->npoints;
296 static void nsvg__addEdge(
NSVGrasterizer* r,
double x0,
double y0,
double x1,
double y1)
300 #pragma GCC diagnostic push
301 #pragma GCC diagnostic ignored "-Wfloat-equal"
304 #pragma GCC diagnostic pop
307 if (r->nedges+1 > r->cedges) {
308 r->cedges = r->cedges > 0 ? r->cedges * 2 : 64;
309 r->edges =
static_cast<NSVGedge*
>(realloc(r->edges,
sizeof(NSVGedge) * r->cedges));
310 if (r->edges ==
nullptr)
return;
313 e = &r->edges[r->nedges];
331 static double nsvg__normalize(
double *
x,
double*
y)
333 double d = sqrt((*
x)*(*
x) + (*
y)*(*
y));
342 static double nsvg__absf(
double x) {
return x < 0 ? -
x :
x; }
345 double x1,
double y1,
double x2,
double y2,
346 double x3,
double y3,
double x4,
double y4,
349 double x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;
352 if (level > 10)
return;
360 x123 = (x12+x23)*0.5;
361 y123 = (y12+y23)*0.5;
365 d2 = nsvg__absf(((x2 - x4) * dy - (y2 - y4) * dx));
366 d3 = nsvg__absf(((x3 - x4) * dy - (y3 - y4) * dx));
368 if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) {
369 nsvg__addPathPoint(r, x4, y4, type);
373 x234 = (x23+x34)*0.5;
374 y234 = (y23+y34)*0.5;
375 x1234 = (x123+x234)*0.5;
376 y1234 = (y123+y234)*0.5;
378 nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0);
379 nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type);
390 nsvg__addPathPoint(r,
path->pts[0]*scalex,
path->pts[1]*scaley, 0);
391 for (i = 0; i <
path->npts-1; i += 3) {
392 double*
p = &
path->pts[i*2];
393 nsvg__flattenCubicBez(r,
p[0]*scalex,
p[1]*scaley,
p[2]*scalex,
p[3]*scaley,
p[4]*scalex,
p[5]*scaley,
p[6]*scalex,
p[7]*scaley, 0, 0);
396 nsvg__addPathPoint(r,
path->pts[0]*scalex,
path->pts[1]*scaley, 0);
398 for (i = 0, j = r->npoints-1; i < r->npoints; j = i++)
399 nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y);
405 NSVG_PT_CORNER = 0x01,
406 NSVG_PT_BEVEL = 0x02,
410 static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1,
double lineWidth)
412 double w = lineWidth * 0.5;
413 double dx = p1->x - p0->x;
414 double dy = p1->y - p0->y;
415 double len = nsvg__normalize(&dx, &dy);
416 double px = p0->x + dx*len*0.5, py = p0->y + dy*len*0.5;
417 double dlx = dy, dly = -dx;
418 double lx =
px - dlx*w, ly = py - dly*w;
419 double rx =
px + dlx*w, ry = py + dly*w;
420 left->x = lx; left->y = ly;
421 right->x = rx; right->y = ry;
424 static void nsvg__buttCap(
NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint*
p,
double dx,
double dy,
double lineWidth,
int connect)
426 double w = lineWidth * 0.5;
427 double px =
p->x, py =
p->y;
428 double dlx = dy, dly = -dx;
429 double lx =
px - dlx*w, ly = py - dly*w;
430 double rx =
px + dlx*w, ry = py + dly*w;
432 nsvg__addEdge(r, lx, ly, rx, ry);
435 nsvg__addEdge(r, left->x, left->y, lx, ly);
436 nsvg__addEdge(r, rx, ry, right->x, right->y);
438 left->x = lx; left->y = ly;
439 right->x = rx; right->y = ry;
442 static void nsvg__squareCap(
NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint*
p,
double dx,
double dy,
double lineWidth,
int connect)
444 double w = lineWidth * 0.5;
445 double px =
p->x - dx*w, py =
p->y - dy*w;
446 double dlx = dy, dly = -dx;
447 double lx =
px - dlx*w, ly = py - dly*w;
448 double rx =
px + dlx*w, ry = py + dly*w;
450 nsvg__addEdge(r, lx, ly, rx, ry);
453 nsvg__addEdge(r, left->x, left->y, lx, ly);
454 nsvg__addEdge(r, rx, ry, right->x, right->y);
456 left->x = lx; left->y = ly;
457 right->x = rx; right->y = ry;
461 #define NSVG_PI (3.14159265358979323846264338327)
464 static void nsvg__roundCap(
NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint*
p,
double dx,
double dy,
double lineWidth,
int ncap,
int connect)
467 double w = lineWidth * 0.5;
468 double px =
p->x, py =
p->y;
469 double dlx = dy, dly = -dx;
470 double lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0;
472 for (i = 0; i < ncap; i++) {
473 double a =
static_cast<double>(i)/
static_cast<double>(ncap-1)*NSVG_PI;
474 double ax = cos(a) * w, ay = sin(a) * w;
475 double x =
px - dlx*ax - dx*ay;
476 double y = py - dly*ax - dy*ay;
479 nsvg__addEdge(r, prevx, prevy,
x,
y);
486 }
else if (i == ncap-1) {
492 nsvg__addEdge(r, left->x, left->y, lx, ly);
493 nsvg__addEdge(r, rx, ry, right->x, right->y);
496 left->x = lx; left->y = ly;
497 right->x = rx; right->y = ry;
500 static void nsvg__bevelJoin(
NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1,
double lineWidth)
502 double w = lineWidth * 0.5;
503 double dlx0 = p0->dy, dly0 = -p0->dx;
504 double dlx1 = p1->dy, dly1 = -p1->dx;
505 double lx0 = p1->x - (dlx0 * w), ly0 = p1->y - (dly0 * w);
506 double rx0 = p1->x + (dlx0 * w), ry0 = p1->y + (dly0 * w);
507 double lx1 = p1->x - (dlx1 * w), ly1 = p1->y - (dly1 * w);
508 double rx1 = p1->x + (dlx1 * w), ry1 = p1->y + (dly1 * w);
510 nsvg__addEdge(r, lx0, ly0, left->x, left->y);
511 nsvg__addEdge(r, lx1, ly1, lx0, ly0);
513 nsvg__addEdge(r, right->x, right->y, rx0, ry0);
514 nsvg__addEdge(r, rx0, ry0, rx1, ry1);
516 left->x = lx1; left->y = ly1;
517 right->x = rx1; right->y = ry1;
520 static void nsvg__miterJoin(
NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1,
double lineWidth)
522 double w = lineWidth * 0.5;
523 double dlx0 = p0->dy, dly0 = -p0->dx;
524 double dlx1 = p1->dy, dly1 = -p1->dx;
525 double lx0, rx0, lx1, rx1;
526 double ly0, ry0, ly1, ry1;
528 if (p1->flags & NSVG_PT_LEFT) {
529 lx0 = lx1 = p1->x - p1->dmx * w;
530 ly0 = ly1 = p1->y - p1->dmy * w;
531 nsvg__addEdge(r, lx1, ly1, left->x, left->y);
533 rx0 = p1->x + (dlx0 * w);
534 ry0 = p1->y + (dly0 * w);
535 rx1 = p1->x + (dlx1 * w);
536 ry1 = p1->y + (dly1 * w);
537 nsvg__addEdge(r, right->x, right->y, rx0, ry0);
538 nsvg__addEdge(r, rx0, ry0, rx1, ry1);
540 lx0 = p1->x - (dlx0 * w);
541 ly0 = p1->y - (dly0 * w);
542 lx1 = p1->x - (dlx1 * w);
543 ly1 = p1->y - (dly1 * w);
544 nsvg__addEdge(r, lx0, ly0, left->x, left->y);
545 nsvg__addEdge(r, lx1, ly1, lx0, ly0);
547 rx0 = rx1 = p1->x + p1->dmx * w;
548 ry0 = ry1 = p1->y + p1->dmy * w;
549 nsvg__addEdge(r, right->x, right->y, rx1, ry1);
552 left->x = lx1; left->y = ly1;
553 right->x = rx1; right->y = ry1;
556 static void nsvg__roundJoin(
NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1,
double lineWidth,
int ncap)
559 double w = lineWidth * 0.5;
560 double dlx0 = p0->dy, dly0 = -p0->dx;
561 double dlx1 = p1->dy, dly1 = -p1->dx;
562 double a0 = atan2(dly0, dlx0);
563 double a1 = atan2(dly1, dlx1);
565 double lx, ly, rx, ry;
567 if (da < NSVG_PI) da += NSVG_PI*2;
568 if (da > NSVG_PI) da -= NSVG_PI*2;
570 n =
static_cast<int>(ceil((nsvg__absf(da) / NSVG_PI) *
static_cast<double>(ncap)));
572 if (
n > ncap)
n = ncap;
579 for (i = 0; i <
n; i++) {
580 double u =
static_cast<double>(i)/
static_cast<double>(
n-1);
581 double a =
a0 + u*da;
582 double ax = cos(a) * w, ay = sin(a) * w;
583 double lx1 = p1->x - ax, ly1 = p1->y - ay;
584 double rx1 = p1->x + ax, ry1 = p1->y + ay;
586 nsvg__addEdge(r, lx1, ly1, lx, ly);
587 nsvg__addEdge(r, rx, ry, rx1, ry1);
593 left->x = lx; left->y = ly;
594 right->x = rx; right->y = ry;
597 static void nsvg__straightJoin(
NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p1,
double lineWidth)
599 double w = lineWidth * 0.5;
600 double lx = p1->x - (p1->dmx * w), ly = p1->y - (p1->dmy * w);
601 double rx = p1->x + (p1->dmx * w), ry = p1->y + (p1->dmy * w);
603 nsvg__addEdge(r, lx, ly, left->x, left->y);
604 nsvg__addEdge(r, right->x, right->y, rx, ry);
606 left->x = lx; left->y = ly;
607 right->x = rx; right->y = ry;
610 static int nsvg__curveDivs(
double r,
double arc,
double tol)
612 double da = acos(r / (r + tol)) * 2.0;
613 int divs =
static_cast<int>(ceil(arc / da));
614 if (divs < 2) divs = 2;
618 static void nsvg__expandStroke(
NSVGrasterizer* r, NSVGpoint* points,
int npoints,
int closed,
int lineJoin,
int lineCap,
double lineWidth)
620 int ncap = nsvg__curveDivs(lineWidth*0.5, NSVG_PI, r->tessTol);
621 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};
628 p0 = &points[npoints-1];
641 nsvg__initClosed(&left, &right, p0, p1, lineWidth);
646 double dx = p1->x - p0->x;
647 double dy = p1->y - p0->y;
648 nsvg__normalize(&dx, &dy);
650 nsvg__buttCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
652 nsvg__squareCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
654 nsvg__roundCap(r, &left, &right, p0, dx, dy, lineWidth, ncap, 0);
657 for (j = s; j < e; ++j) {
658 if (p1->flags & NSVG_PT_CORNER) {
660 nsvg__roundJoin(r, &left, &right, p0, p1, lineWidth, ncap);
662 nsvg__bevelJoin(r, &left, &right, p0, p1, lineWidth);
664 nsvg__miterJoin(r, &left, &right, p0, p1, lineWidth);
666 nsvg__straightJoin(r, &left, &right, p1, lineWidth);
673 nsvg__addEdge(r, firstLeft.x, firstLeft.y, left.x, left.y);
674 nsvg__addEdge(r, right.x, right.y, firstRight.x, firstRight.y);
677 double dx = p1->x - p0->x;
678 double dy = p1->y - p0->y;
679 nsvg__normalize(&dx, &dy);
681 nsvg__buttCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
683 nsvg__squareCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
685 nsvg__roundCap(r, &right, &left, p1, -dx, -dy, lineWidth, ncap, 1);
689 static void nsvg__prepareStroke(
NSVGrasterizer* r,
double miterLimit,
int lineJoin)
694 p0 = &r->points[r->npoints-1];
696 for (i = 0; i < r->npoints; i++) {
698 p0->dx = p1->x - p0->x;
699 p0->dy = p1->y - p0->y;
700 p0->len = nsvg__normalize(&p0->dx, &p0->dy);
706 p0 = &r->points[r->npoints-1];
708 for (j = 0; j < r->npoints; j++) {
709 double dlx0, dly0, dlx1, dly1, dmr2, cross;
715 p1->dmx = (dlx0 + dlx1) * 0.5;
716 p1->dmy = (dly0 + dly1) * 0.5;
717 dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy;
718 if (dmr2 > 0.000001) {
719 double s2 = 1.0 / dmr2;
728 p1->flags = (p1->flags & NSVG_PT_CORNER) ? NSVG_PT_CORNER : 0;
731 cross = p1->dx * p0->dy - p0->dx * p1->dy;
733 p1->flags |= NSVG_PT_LEFT;
736 if (p1->flags & NSVG_PT_CORNER) {
738 p1->flags |= NSVG_PT_BEVEL;
751 double miterLimit =
shape->miterLimit;
752 int lineJoin =
shape->strokeLineJoin;
753 int lineCap =
shape->strokeLineCap;
754 double lineWidth =
shape->strokeWidth * (scalex+scaley)*0.5;
759 nsvg__addPathPoint(r,
path->pts[0]*scalex,
path->pts[1]*scaley, NSVG_PT_CORNER);
760 for (i = 0; i <
path->npts-1; i += 3) {
761 double*
p = &
path->pts[i*2];
762 nsvg__flattenCubicBez(r,
p[0]*scalex,
p[1]*scaley,
p[2]*scalex,
p[3]*scaley,
p[4]*scalex,
p[5]*scaley,
p[6]*scalex,
p[7]*scaley, 0, NSVG_PT_CORNER);
767 closed =
path->closed;
770 p0 = &r->points[r->npoints-1];
772 if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) {
774 p0 = &r->points[r->npoints-1];
778 if (
shape->strokeDashCount > 0) {
779 int idash = 0, dashState = 1;
780 double totalDist = 0, dashLen, allDashLen, dashOffset;
784 nsvg__appendPathPoint(r, r->points[0]);
787 nsvg__duplicatePoints(r);
791 nsvg__appendPathPoint(r, cur);
795 for (j = 0; j <
shape->strokeDashCount; j++)
796 allDashLen +=
shape->strokeDashArray[j];
797 if (
shape->strokeDashCount & 1)
800 dashOffset = fmod(
shape->strokeDashOffset, allDashLen);
801 if (dashOffset < 0.0)
802 dashOffset += allDashLen;
804 while (dashOffset >
shape->strokeDashArray[idash]) {
805 dashOffset -=
shape->strokeDashArray[idash];
806 idash = (idash + 1) %
shape->strokeDashCount;
808 dashLen = (
shape->strokeDashArray[idash] - dashOffset) * (scalex+scaley)*0.5;
810 for (j = 1; j < r->npoints2; ) {
811 double dx = r->points2[j].x - cur.x;
812 double dy = r->points2[j].y - cur.y;
813 double dist = sqrt(dx*dx + dy*dy);
815 if ((totalDist + dist) > dashLen) {
817 double d = (dashLen - totalDist) / dist;
818 double x = cur.x + dx * d;
819 double y = cur.y + dy * d;
820 nsvg__addPathPoint(r,
x,
y, NSVG_PT_CORNER);
823 if (r->npoints > 1 && dashState) {
824 nsvg__prepareStroke(r, miterLimit, lineJoin);
825 nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);
828 dashState = !dashState;
829 idash = (idash+1) %
shape->strokeDashCount;
830 dashLen =
shape->strokeDashArray[idash] * (scalex+scaley)*0.5;
834 cur.flags = NSVG_PT_CORNER;
837 nsvg__appendPathPoint(r, cur);
841 nsvg__appendPathPoint(r, cur);
846 if (r->npoints > 1 && dashState)
847 nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);
849 nsvg__prepareStroke(r, miterLimit, lineJoin);
850 nsvg__expandStroke(r, r->points, r->npoints, closed, lineJoin, lineCap, lineWidth);
855 static int nsvg__cmpEdge(
const void *
p,
const void *q)
857 const NSVGedge* a =
static_cast<const NSVGedge*
>(
p);
858 const NSVGedge* b =
static_cast<const NSVGedge*
>(q);
860 if (a->y0 < b->y0)
return -1;
861 if (a->y0 > b->y0)
return 1;
866 static NSVGactiveEdge* nsvg__addActive(
NSVGrasterizer* r, NSVGedge* e,
double startPoint)
870 if (r->freelist !=
nullptr) {
873 r->freelist = z->next;
876 z =
reinterpret_cast<NSVGactiveEdge*
>(nsvg__alloc(r,
sizeof(NSVGactiveEdge)));
877 if (z ==
nullptr)
return nullptr;
880 double dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
884 z->dx =
static_cast<int>(-floor(NSVG__FIX * -dxdy));
886 z->dx =
static_cast<int>(floor(NSVG__FIX * dxdy));
887 z->x =
static_cast<int>(floor(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0))));
896 static void nsvg__freeActive(
NSVGrasterizer* r, NSVGactiveEdge* z)
898 z->next = r->freelist;
902 static void nsvg__fillScanline(
unsigned char* scanline,
int len,
int x0,
int x1,
int maxWeight,
int* xmin,
int* xmax)
904 int i = x0 >> NSVG__FIXSHIFT;
905 int j = x1 >> NSVG__FIXSHIFT;
906 if (i < *xmin) *xmin = i;
907 if (j > *xmax) *xmax = j;
908 if (i < len && j >= 0) {
911 scanline[i] =
static_cast<unsigned char>(scanline[i] + ((x1 - x0) * maxWeight >> NSVG__FIXSHIFT));
914 scanline[i] =
static_cast<unsigned char>(scanline[i] + (((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT));
919 scanline[j] =
static_cast<unsigned char>(scanline[j] + (((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT));
923 for (++i; i < j; ++i)
924 scanline[i] =
static_cast<unsigned char>(scanline[i] + maxWeight);
932 static void nsvg__fillActiveEdges(
unsigned char* scanline,
int len, NSVGactiveEdge* e,
int maxWeight,
int* xmin,
int* xmax,
char fillRule)
939 while (e !=
nullptr) {
942 x0 = e->x; w += e->dir;
944 int x1 = e->x; w += e->dir;
947 nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);
953 while (e !=
nullptr) {
958 int x1 = e->x; w = 0;
959 nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);
966 static double nsvg__clampf(
double a,
double mn,
double mx) {
return a < mn ? mn : (a > mx ? mx : a); }
968 static unsigned int nsvg__RGBA(
unsigned char r,
unsigned char g,
unsigned char b,
unsigned char a)
970 return (r) | (g << 8) | (b << 16) | (a << 24);
973 static unsigned int nsvg__lerpRGBA(
unsigned int c0,
unsigned int c1,
double u)
975 int iu =
static_cast<int>(nsvg__clampf(u, 0.0, 1.0) * 256.0);
976 int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8;
977 int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8;
978 int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8;
979 int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8;
980 return nsvg__RGBA(
static_cast<unsigned char>(r),
static_cast<unsigned char>(g),
static_cast<unsigned char>(b),
static_cast<unsigned char>(a));
983 static unsigned int nsvg__applyOpacity(
unsigned int c,
double u)
985 int iu =
static_cast<int>(nsvg__clampf(u, 0.0, 1.0) * 256.0);
987 int g = (c>>8) & 0xff;
988 int b = (c>>16) & 0xff;
989 int a = (((c>>24) & 0xff)*iu) >> 8;
990 return nsvg__RGBA(
static_cast<unsigned char>(r),
static_cast<unsigned char>(g),
static_cast<unsigned char>(b),
static_cast<unsigned char>(a));
993 static inline int nsvg__div255(
int x)
995 return ((
x+1) * 257) >> 16;
998 static void nsvg__scanlineSolid(
unsigned char* dst,
int count,
unsigned char* cover,
int x,
int y,
999 double tx,
double ty,
double scalex,
double scaley, NSVGcachedPaint* cache)
1003 int i, cr, cg, cb, ca;
1004 cr = cache->colors[0] & 0xff;
1005 cg = (cache->colors[0] >> 8) & 0xff;
1006 cb = (cache->colors[0] >> 16) & 0xff;
1007 ca = (cache->colors[0] >> 24) & 0xff;
1009 for (i = 0; i <
count; i++) {
1011 int a = nsvg__div255(
static_cast<int>(cover[0]) * ca);
1014 r = nsvg__div255(cr * a);
1015 g = nsvg__div255(cg * a);
1016 b = nsvg__div255(cb * a);
1019 r += nsvg__div255(ia *
static_cast<int>(dst[0]));
1020 g += nsvg__div255(ia *
static_cast<int>(dst[1]));
1021 b += nsvg__div255(ia *
static_cast<int>(dst[2]));
1022 a += nsvg__div255(ia *
static_cast<int>(dst[3]));
1024 dst[0] =
static_cast<unsigned char>(r);
1025 dst[1] =
static_cast<unsigned char>(g);
1026 dst[2] =
static_cast<unsigned char>(b);
1027 dst[3] =
static_cast<unsigned char>(a);
1035 double fx, fy, dx, gy;
1036 double* t = cache->xform;
1037 int i, cr, cg, cb, ca;
1040 fx = (
static_cast<double>(
x) - tx) / scalex;
1041 fy = (
static_cast<double>(
y) - ty) / scaley;
1044 for (i = 0; i <
count; i++) {
1046 gy = fx*t[1] + fy*t[3] + t[5];
1047 c = cache->colors[
static_cast<int>(nsvg__clampf(gy*255.0, 0, 255.0))];
1049 cg = (c >> 8) & 0xff;
1050 cb = (c >> 16) & 0xff;
1051 ca = (c >> 24) & 0xff;
1053 a = nsvg__div255(
static_cast<int>(cover[0]) * ca);
1057 r = nsvg__div255(cr * a);
1058 g = nsvg__div255(cg * a);
1059 b = nsvg__div255(cb * a);
1062 r += nsvg__div255(ia *
static_cast<int>(dst[0]));
1063 g += nsvg__div255(ia *
static_cast<int>(dst[1]));
1064 b += nsvg__div255(ia *
static_cast<int>(dst[2]));
1065 a += nsvg__div255(ia *
static_cast<int>(dst[3]));
1067 dst[0] =
static_cast<unsigned char>(r);
1068 dst[1] =
static_cast<unsigned char>(g);
1069 dst[2] =
static_cast<unsigned char>(b);
1070 dst[3] =
static_cast<unsigned char>(a);
1080 double fx, fy, dx, gx, gy, gd;
1081 double* t = cache->xform;
1082 int i, cr, cg, cb, ca;
1085 fx = (
static_cast<double>(
x) - tx) / scalex;
1086 fy = (
static_cast<double>(
y) - ty) / scaley;
1089 for (i = 0; i <
count; i++) {
1091 gx = fx*t[0] + fy*t[2] + t[4];
1092 gy = fx*t[1] + fy*t[3] + t[5];
1093 gd = sqrt(gx*gx + gy*gy);
1094 c = cache->colors[
static_cast<int>(nsvg__clampf(gd*255.0, 0, 255.0))];
1096 cg = (c >> 8) & 0xff;
1097 cb = (c >> 16) & 0xff;
1098 ca = (c >> 24) & 0xff;
1100 a = nsvg__div255(
static_cast<int>(cover[0]) * ca);
1104 r = nsvg__div255(cr * a);
1105 g = nsvg__div255(cg * a);
1106 b = nsvg__div255(cb * a);
1109 r += nsvg__div255(ia *
static_cast<int>(dst[0]));
1110 g += nsvg__div255(ia *
static_cast<int>(dst[1]));
1111 b += nsvg__div255(ia *
static_cast<int>(dst[2]));
1112 a += nsvg__div255(ia *
static_cast<int>(dst[3]));
1114 dst[0] =
static_cast<unsigned char>(r);
1115 dst[1] =
static_cast<unsigned char>(g);
1116 dst[2] =
static_cast<unsigned char>(b);
1117 dst[3] =
static_cast<unsigned char>(a);
1126 static void nsvg__rasterizeSortedEdges(
NSVGrasterizer *r,
double tx,
double ty,
double scalex,
double scaley, NSVGcachedPaint* cache,
char fillRule)
1128 NSVGactiveEdge *active =
nullptr;
1131 int maxWeight = (255 / NSVG__SUBSAMPLES);
1134 for (
y = 0;
y < r->height;
y++) {
1135 memset(r->scanline, 0, r->width);
1138 for (s = 0; s < NSVG__SUBSAMPLES; ++s) {
1140 double scany =
static_cast<double>(
y*NSVG__SUBSAMPLES + s) + 0.5;
1141 NSVGactiveEdge **step = &active;
1146 NSVGactiveEdge *z = *step;
1147 if (z->ey <= scany) {
1150 nsvg__freeActive(r, z);
1153 step = &((*step)->next);
1161 while (*step && (*step)->next) {
1162 if ((*step)->x > (*step)->next->x) {
1163 NSVGactiveEdge* t = *step;
1164 NSVGactiveEdge* q = t->next;
1170 step = &(*step)->next;
1172 if (!changed)
break;
1176 while (e < r->nedges && r->edges[e].y0 <= scany) {
1177 if (r->edges[e].y1 > scany) {
1178 NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany);
1179 if (z ==
nullptr)
break;
1181 if (active ==
nullptr) {
1183 }
else if (z->x < active->x) {
1189 NSVGactiveEdge*
p = active;
1190 while (
p->next &&
p->next->x < z->x)
1201 if (active !=
nullptr)
1202 nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, &xmin, &xmax, fillRule);
1205 if (xmin < 0) xmin = 0;
1206 if (xmax > r->width-1) xmax = r->width-1;
1208 nsvg__scanlineSolid(&r->bitmap[
y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin,
y, tx,ty, scalex, scaley, cache);
1214 static void nsvg__unpremultiplyAlpha(
unsigned char* image,
int w,
int h,
int stride)
1219 for (
y = 0;
y < h;
y++) {
1220 unsigned char *row = &image[
y*stride];
1221 for (
x = 0;
x < w;
x++) {
1222 int r = row[0], g = row[1], b = row[2], a = row[3];
1224 row[0] =
static_cast<unsigned char>(r*255/a);
1225 row[1] =
static_cast<unsigned char>(g*255/a);
1226 row[2] =
static_cast<unsigned char>(b*255/a);
1233 for (
y = 0;
y < h;
y++) {
1234 unsigned char *row = &image[
y*stride];
1235 for (
x = 0;
x < w;
x++) {
1236 int r = 0, g = 0, b = 0, a = row[3],
n = 0;
1238 if (
x-1 > 0 && row[-1] != 0) {
1244 if (
x+1 < w && row[7] != 0) {
1250 if (
y-1 > 0 && row[-stride+3] != 0) {
1252 g += row[-stride+1];
1253 b += row[-stride+2];
1256 if (
y+1 < h && row[stride+3] != 0) {
1263 row[0] =
static_cast<unsigned char>(r/
n);
1264 row[1] =
static_cast<unsigned char>(g/
n);
1265 row[2] =
static_cast<unsigned char>(b/
n);
1274 static void nsvg__unpremultiplyBGRAlpha(
unsigned char* image,
int w,
int h,
int stride)
1279 for (
y = 0;
y < h;
y++) {
1280 unsigned char *row = &image[
y*stride];
1281 for (
x = 0;
x < w;
x++) {
1282 int b = row[0], g = row[1], r = row[2], a = row[3];
1284 row[0] =
static_cast<unsigned char>(r*255/a);
1285 row[1] =
static_cast<unsigned char>(g*255/a);
1286 row[2] =
static_cast<unsigned char>(b*255/a);
1293 for (
y = 0;
y < h;
y++) {
1294 unsigned char *row = &image[
y*stride];
1295 for (
x = 0;
x < w;
x++) {
1296 int r = 0, g = 0, b = 0, a = row[3],
n = 0;
1298 if (
x-1 > 0 && row[-1] != 0) {
1304 if (
x+1 < w && row[7] != 0) {
1310 if (
y-1 > 0 && row[-stride+3] != 0) {
1312 g += row[-stride+1];
1313 r += row[-stride+2];
1316 if (
y+1 < h && row[stride+3] != 0) {
1323 row[0] =
static_cast<unsigned char>(b/
n);
1324 row[1] =
static_cast<unsigned char>(g/
n);
1325 row[2] =
static_cast<unsigned char>(r/
n);
1334 static void nsvg__initPaint(NSVGcachedPaint* cache,
NSVGpaint* paint,
double opacity)
1339 cache->type = paint->
type;
1342 cache->colors[0] = nsvg__applyOpacity(paint->
color, opacity);
1349 memcpy(cache->xform, grad->
xform,
sizeof(
double)*6);
1352 for (i = 0; i < 256; i++)
1353 cache->colors[i] = 0;
1354 }
if (grad->
nstops == 1) {
1355 for (i = 0; i < 256; i++)
1356 cache->colors[i] = nsvg__applyOpacity(grad->
stops[i].
color, opacity);
1358 unsigned int ca, cb = 0;
1359 double ua, ub, du, u;
1362 ca = nsvg__applyOpacity(grad->
stops[0].
color, opacity);
1365 ia =
static_cast<int>(ua * 255.0);
1366 ib =
static_cast<int>(ub * 255.0);
1367 for (i = 0; i < ia; i++) {
1368 cache->colors[i] = ca;
1371 for (i = 0; i < grad->
nstops-1; i++) {
1372 ca = nsvg__applyOpacity(grad->
stops[i].
color, opacity);
1373 cb = nsvg__applyOpacity(grad->
stops[i+1].
color, opacity);
1376 ia =
static_cast<int>(ua * 255.0);
1377 ib =
static_cast<int>(ub * 255.0);
1379 if (
count <= 0)
continue;
1381 du = 1.0 /
static_cast<double>(
count);
1382 for (j = 0; j <
count; j++) {
1383 cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u);
1388 for (i = ib; i < 256; i++)
1389 cache->colors[i] = cb;
1396 NSVGimage* image,
double tx,
double ty,
double scalex,
double scaley,
1397 unsigned char* dst,
int w,
int h,
int stride,
int bgr)
1400 NSVGedge *e =
nullptr;
1401 NSVGcachedPaint cache;
1409 if (w > r->cscanline) {
1411 r->scanline =
static_cast<unsigned char*
>(realloc(r->scanline, w));
1412 if (r->scanline ==
nullptr)
return;
1415 for (i = 0; i < h; i++)
1416 memset(&dst[i*stride], 0, w*4);
1424 r->freelist =
nullptr;
1427 nsvg__flattenShape(r,
shape, scalex, scaley);
1430 for (i = 0; i < r->nedges; i++) {
1433 e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
1435 e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
1439 qsort(r->edges, r->nedges,
sizeof(NSVGedge), nsvg__cmpEdge);
1442 nsvg__initPaint(&cache, &
shape->fill,
shape->opacity);
1444 nsvg__rasterizeSortedEdges(r, tx,ty, scalex, scaley, &cache,
shape->fillRule);
1448 r->freelist =
nullptr;
1451 nsvg__flattenShapeStroke(r,
shape, scalex, scaley);
1456 for (i = 0; i < r->nedges; i++) {
1459 e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
1461 e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
1465 qsort(r->edges, r->nedges,
sizeof(NSVGedge), nsvg__cmpEdge);
1468 nsvg__initPaint(&cache, &
shape->stroke,
shape->opacity);
1475 nsvg__unpremultiplyBGRAlpha(dst, w, h, stride);
1477 nsvg__unpremultiplyAlpha(dst, w, h, stride);
1479 r->bitmap =
nullptr;
1487 unsigned char* dst,
int w,
int h,
int stride)
1489 return nsvgRasterizeFull(r, image, tx, ty,
scale,
scale, dst, w, h, stride, 0);
ucs4_t int n
Definition: big5.h:4148
const char int int int float scale
Definition: epng.h:39
const char int int int height
Definition: epng.h:39
const char int int width
Definition: epng.h:39
void shape(std::vector< unsigned long > &string, const std::vector< unsigned long > &text)
Definition: font_arabic.cpp:218
size
Definition: Plugins/SystemPlugins/PositionerSetup/log.py:16
int count
Definition: newplugin.py:14
dictionary colors
Definition: skin.py:29
def px(x)
Definition: svg2skin.py:36
p
Definition: upgrade.py:63
@ NSVG_FILLRULE_NONZERO
Definition: nanosvg.h:105
@ NSVG_FILLRULE_EVENODD
Definition: nanosvg.h:106
@ NSVG_CAP_SQUARE
Definition: nanosvg.h:101
@ NSVG_CAP_BUTT
Definition: nanosvg.h:99
@ NSVG_CAP_ROUND
Definition: nanosvg.h:100
@ NSVG_FLAGS_VISIBLE
Definition: nanosvg.h:110
@ NSVG_PAINT_NONE
Definition: nanosvg.h:80
@ NSVG_PAINT_COLOR
Definition: nanosvg.h:81
@ NSVG_PAINT_RADIAL_GRADIENT
Definition: nanosvg.h:83
@ NSVG_PAINT_LINEAR_GRADIENT
Definition: nanosvg.h:82
@ NSVG_JOIN_BEVEL
Definition: nanosvg.h:95
@ NSVG_JOIN_ROUND
Definition: nanosvg.h:94
NSVGrasterizer * nsvgCreateRasterizer()
void nsvgRasterize(NSVGrasterizer *r, NSVGimage *image, double tx, double ty, double scale, unsigned char *dst, int w, int h, int stride)
void nsvgRasterizeFull(NSVGrasterizer *r, NSVGimage *image, double tx, double ty, double scalex, double scaley, unsigned char *dst, int w, int h, int stride, int bgr)
void nsvgDeleteRasterizer(NSVGrasterizer *)
struct NSVGrasterizer NSVGrasterizer
Definition: nanosvgrast.h:39
if(background) PyTuple_SET_ITEM(tuple
std::string int int y
Definition: picload.cpp:1503
std::string int x
Definition: picload.cpp:1503
#define a0
Definition: rotor_calc.cpp:147
#define a1
Definition: rotor_calc.cpp:148
Definition: nanosvg.h:118
double xform[6]
Definition: nanosvg.h:119
int nstops
Definition: nanosvg.h:122
char spread
Definition: nanosvg.h:120
NSVGgradientStop stops[1]
Definition: nanosvg.h:123
unsigned int color
Definition: nanosvg.h:114
double offset
Definition: nanosvg.h:115
Definition: nanosvg.h:164
NSVGshape * shapes
Definition: nanosvg.h:167
Definition: nanosvg.h:126
char type
Definition: nanosvg.h:127
unsigned int color
Definition: nanosvg.h:129
NSVGgradient * gradient
Definition: nanosvg.h:130
Definition: nanosvg.h:135
Definition: nanosvg.h:144