Fix for issue #4 and issue #5 added per shape opacity parameter

- added parsing for per shape opacity
- added support for per shape opacity in rasteriser
This commit is contained in:
Mikko Mononen 2014-04-04 21:58:50 +03:00
parent 1b894120be
commit 95caf10c0b
2 changed files with 28 additions and 13 deletions

View File

@ -112,6 +112,7 @@ struct NSVGshape
{ {
struct NSVGpaint fill; // Fill paint struct NSVGpaint fill; // Fill paint
struct NSVGpaint stroke; // Stroke paint struct NSVGpaint stroke; // Stroke paint
float opacity; // Opacity of the shape.
float strokeWidth; // Stroke width (scaled) float strokeWidth; // Stroke width (scaled)
float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy].
struct NSVGpath* paths; // Linked list of paths in the image. 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_MEET 1
#define NSVG_ALIGN_SLICE 2 #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 #ifdef _MSC_VER
#pragma warning (disable: 4996) // Switch off security warnings #pragma warning (disable: 4996) // Switch off security warnings
#pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings #pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings
@ -335,6 +338,7 @@ struct NSVGattrib
float xform[6]; float xform[6];
unsigned int fillColor; unsigned int fillColor;
unsigned int strokeColor; unsigned int strokeColor;
float opacity;
float fillOpacity; float fillOpacity;
float strokeOpacity; float strokeOpacity;
char fillGradient[64]; char fillGradient[64];
@ -536,13 +540,14 @@ static struct NSVGparser* nsvg__createParser()
// Init style // Init style
nsvg__xformIdentity(p->attr[0].xform); nsvg__xformIdentity(p->attr[0].xform);
p->attr[0].fillColor = 0; p->attr[0].fillColor = NSVG_RGB(0,0,0);
p->attr[0].strokeColor = 0; p->attr[0].strokeColor = NSVG_RGB(0,0,0);
p->attr[0].opacity = 1;
p->attr[0].fillOpacity = 1; p->attr[0].fillOpacity = 1;
p->attr[0].strokeOpacity = 1; p->attr[0].strokeOpacity = 1;
p->attr[0].stopOpacity = 1; p->attr[0].stopOpacity = 1;
p->attr[0].strokeWidth = 1; p->attr[0].strokeWidth = 1;
p->attr[0].hasFill = 0; p->attr[0].hasFill = 1;
p->attr[0].hasStroke = 0; p->attr[0].hasStroke = 0;
p->attr[0].visible = 1; 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])); scale = nsvg__maxf(fabsf(attr->xform[0]), fabsf(attr->xform[3]));
shape->strokeWidth = attr->strokeWidth * scale; shape->strokeWidth = attr->strokeWidth * scale;
shape->opacity = attr->opacity;
shape->paths = p->plist; shape->paths = p->plist;
p->plist = NULL; 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) static unsigned int nsvg__parseColorHex(const char* str)
{ {
unsigned int c = 0, r = 0, g = 0, b = 0; 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->hasFill = 1;
attr->fillColor = nsvg__parseColor(value); 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) { } else if (strcmp(name, "fill-opacity") == 0) {
attr->fillOpacity = nsvg__parseFloat(p, value, 2); attr->fillOpacity = nsvg__parseFloat(p, value, 2);
} else if (strcmp(name, "stroke") == 0) { } else if (strcmp(name, "stroke") == 0) {

View File

@ -394,6 +394,16 @@ static unsigned int nsvg__lerpRGBA(unsigned int c0, unsigned int c1, float u)
return nsvg__RGBA(r,g,b,a); 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, 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) 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; int i, j;
struct NSVGgradient* grad; struct NSVGgradient* grad;
@ -678,7 +688,7 @@ static void nsvg__initPaint(struct NSVGcachedPaint* cache, struct NSVGpaint* pai
cache->type = paint->type; cache->type = paint->type;
if (paint->type == NSVG_PAINT_COLOR) { if (paint->type == NSVG_PAINT_COLOR) {
cache->colors[0] = paint->color; cache->colors[0] = nsvg__applyOpacity(paint->color, opacity);
return; return;
} }
@ -692,14 +702,13 @@ static void nsvg__initPaint(struct NSVGcachedPaint* cache, struct NSVGpaint* pai
cache->colors[i] = 0; cache->colors[i] = 0;
} if (grad->nstops == 1) { } if (grad->nstops == 1) {
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
cache->colors[i] = grad->stops[i].color; cache->colors[i] = nsvg__applyOpacity(grad->stops[i].color, opacity);
} else { } else {
unsigned int ca, cb; unsigned int ca, cb;
float ua, ub, du, u; float ua, ub, du, u;
int ia, ib, count; int ia, ib, count;
ca = grad->stops[0].color; ca = nsvg__applyOpacity(grad->stops[0].color, opacity);
cb = grad->stops[grad->nstops-1].color;
ua = nsvg__clampf(grad->stops[0].offset, 0, 1); ua = nsvg__clampf(grad->stops[0].offset, 0, 1);
ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1); ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1);
ia = ua * 255.0f; 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++) { for (i = 0; i < grad->nstops-1; i++) {
ca = grad->stops[i].color; ca = nsvg__applyOpacity(grad->stops[i].color, opacity);
cb = grad->stops[i+1].color; cb = nsvg__applyOpacity(grad->stops[i+1].color, opacity);
ua = nsvg__clampf(grad->stops[i].offset, 0, 1); ua = nsvg__clampf(grad->stops[i].offset, 0, 1);
ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1); ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1);
ia = ua * 255.0f; ia = ua * 255.0f;
@ -778,7 +787,7 @@ void nsvgRasterize(struct NSVGrasterizer* r,
qsort(r->edges, r->nedges, sizeof(struct NSVGedge), nsvg__cmpEdge); 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 // 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); nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache);
} }