diff --git a/src/nanosvg.h b/src/nanosvg.h index 76c4b4b..ad2ee52 100644 --- a/src/nanosvg.h +++ b/src/nanosvg.h @@ -112,6 +112,7 @@ struct NSVGshape { struct NSVGpaint fill; // Fill paint struct NSVGpaint stroke; // Stroke paint + float opacity; // Opacity of the shape. float strokeWidth; // Stroke width (scaled) float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. struct NSVGpath* paths; // Linked list of paths in the image. @@ -156,6 +157,8 @@ void nsvgDelete(struct NSVGimage* image); #define NSVG_ALIGN_MEET 1 #define NSVG_ALIGN_SLICE 2 +#define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16)) + #ifdef _MSC_VER #pragma warning (disable: 4996) // Switch off security warnings #pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings @@ -335,6 +338,7 @@ struct NSVGattrib float xform[6]; unsigned int fillColor; unsigned int strokeColor; + float opacity; float fillOpacity; float strokeOpacity; char fillGradient[64]; @@ -536,13 +540,14 @@ static struct NSVGparser* nsvg__createParser() // Init style nsvg__xformIdentity(p->attr[0].xform); - p->attr[0].fillColor = 0; - p->attr[0].strokeColor = 0; + p->attr[0].fillColor = NSVG_RGB(0,0,0); + p->attr[0].strokeColor = NSVG_RGB(0,0,0); + p->attr[0].opacity = 1; p->attr[0].fillOpacity = 1; p->attr[0].strokeOpacity = 1; p->attr[0].stopOpacity = 1; p->attr[0].strokeWidth = 1; - p->attr[0].hasFill = 0; + p->attr[0].hasFill = 1; p->attr[0].hasStroke = 0; p->attr[0].visible = 1; @@ -743,6 +748,7 @@ static void nsvg__addShape(struct NSVGparser* p) scale = nsvg__maxf(fabsf(attr->xform[0]), fabsf(attr->xform[3])); shape->strokeWidth = attr->strokeWidth * scale; + shape->opacity = attr->opacity; shape->paths = p->plist; p->plist = NULL; @@ -929,8 +935,6 @@ static float nsvg__actualLength(struct NSVGparser* p) } -#define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16)) - static unsigned int nsvg__parseColorHex(const char* str) { unsigned int c = 0, r = 0, g = 0, b = 0; @@ -1389,6 +1393,8 @@ static int nsvg__parseAttr(struct NSVGparser* p, const char* name, const char* v attr->hasFill = 1; attr->fillColor = nsvg__parseColor(value); } + } else if (strcmp(name, "opacity") == 0) { + attr->opacity = nsvg__parseFloat(p, value, 2); } else if (strcmp(name, "fill-opacity") == 0) { attr->fillOpacity = nsvg__parseFloat(p, value, 2); } else if (strcmp(name, "stroke") == 0) { diff --git a/src/nanosvgrast.h b/src/nanosvgrast.h index c489f30..60eac66 100644 --- a/src/nanosvgrast.h +++ b/src/nanosvgrast.h @@ -394,6 +394,16 @@ static unsigned int nsvg__lerpRGBA(unsigned int c0, unsigned int c1, float u) return nsvg__RGBA(r,g,b,a); } +static unsigned int nsvg__applyOpacity(unsigned int c, float u) +{ + int iu = (float)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f); + int r = (c) & 0xff; + int g = (c>>8) & 0xff; + int b = (c>>16) & 0xff; + int a = (((c>>24) & 0xff)*iu) >> 8; + return nsvg__RGBA(r,g,b,a); +} + static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* cover, int x, int y, float tx, float ty, float scale, struct NSVGcachedPaint* cache) { @@ -670,7 +680,7 @@ static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int str } -static void nsvg__initPaint(struct NSVGcachedPaint* cache, struct NSVGpaint* paint) +static void nsvg__initPaint(struct NSVGcachedPaint* cache, struct NSVGpaint* paint, float opacity) { int i, j; struct NSVGgradient* grad; @@ -678,7 +688,7 @@ static void nsvg__initPaint(struct NSVGcachedPaint* cache, struct NSVGpaint* pai cache->type = paint->type; if (paint->type == NSVG_PAINT_COLOR) { - cache->colors[0] = paint->color; + cache->colors[0] = nsvg__applyOpacity(paint->color, opacity); return; } @@ -692,14 +702,13 @@ static void nsvg__initPaint(struct NSVGcachedPaint* cache, struct NSVGpaint* pai cache->colors[i] = 0; } if (grad->nstops == 1) { for (i = 0; i < 256; i++) - cache->colors[i] = grad->stops[i].color; + cache->colors[i] = nsvg__applyOpacity(grad->stops[i].color, opacity); } else { unsigned int ca, cb; float ua, ub, du, u; int ia, ib, count; - ca = grad->stops[0].color; - cb = grad->stops[grad->nstops-1].color; + ca = nsvg__applyOpacity(grad->stops[0].color, opacity); ua = nsvg__clampf(grad->stops[0].offset, 0, 1); ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1); ia = ua * 255.0f; @@ -709,8 +718,8 @@ static void nsvg__initPaint(struct NSVGcachedPaint* cache, struct NSVGpaint* pai } for (i = 0; i < grad->nstops-1; i++) { - ca = grad->stops[i].color; - cb = grad->stops[i+1].color; + ca = nsvg__applyOpacity(grad->stops[i].color, opacity); + cb = nsvg__applyOpacity(grad->stops[i+1].color, opacity); ua = nsvg__clampf(grad->stops[i].offset, 0, 1); ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1); ia = ua * 255.0f; @@ -778,7 +787,7 @@ void nsvgRasterize(struct NSVGrasterizer* r, qsort(r->edges, r->nedges, sizeof(struct NSVGedge), nsvg__cmpEdge); // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule - nsvg__initPaint(&cache, &shape->fill); + nsvg__initPaint(&cache, &shape->fill, shape->opacity); nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache); }