From 70bb2497c61f257438e2a463cf4c7804a2c9de7a Mon Sep 17 00:00:00 2001 From: TangoCash Date: Wed, 27 Oct 2021 21:30:09 +0200 Subject: [PATCH] add svg alphalevel, add full resize Origin commit data ------------------ Branch: ni/coolstream Commit: https://github.com/neutrino-images/ni-neutrino/commit/6de84a4caf0ea3a2cd6ef5df591d7f5e5d038fbb Author: TangoCash Date: 2021-10-27 (Wed, 27 Oct 2021) ------------------ No further description and justification available within origin commit message! ------------------ This commit was generated by Migit --- src/driver/pictureviewer/nanosvg.h | 47 ++++++++++++++++-- src/driver/pictureviewer/nanosvgrast.h | 67 +++++++++++++++----------- src/driver/pictureviewer/svg.cpp | 10 ++-- 3 files changed, 85 insertions(+), 39 deletions(-) diff --git a/src/driver/pictureviewer/nanosvg.h b/src/driver/pictureviewer/nanosvg.h index 2e12eff19..c02a8a0fc 100644 --- a/src/driver/pictureviewer/nanosvg.h +++ b/src/driver/pictureviewer/nanosvg.h @@ -195,6 +195,7 @@ void nsvgDelete(NSVGimage* image); #ifdef NANOSVG_IMPLEMENTATION +#include #include #include #include @@ -211,6 +212,7 @@ void nsvgDelete(NSVGimage* image); #define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0) #define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16)) +#define NSVG_RGBA(r, g, b, a) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16) | ((unsigned int)a << 24)) #ifdef _MSC_VER #pragma warning (disable: 4996) // Switch off security warnings @@ -304,7 +306,7 @@ static void nsvg__parseElement(char* s, // Get attribs while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) { - char* name = NULL; + char* aname = NULL; char* value = NULL; // Skip white space before the attrib name @@ -315,7 +317,7 @@ static void nsvg__parseElement(char* s, end = 1; break; } - name = s; + aname = s; // Find end of the attrib name. while (*s && !nsvg__isspace(*s) && *s != '=') s++; if (*s) @@ -336,9 +338,9 @@ static void nsvg__parseElement(char* s, } // Store only well formed attributes - if (name && value) + if (aname && value) { - attr[nattr++] = name; + attr[nattr++] = aname; attr[nattr++] = value; } } @@ -1364,7 +1366,9 @@ static const char* nsvg__getNextPathItem(const char* s, char* it) static unsigned int nsvg__parseColorHex(const char* str) { - unsigned int r=0, g=0, b=0; + unsigned int r=0, g=0, b=0, a=0; + if (sscanf(str, "#%2x%2x%2x%2x", &r, &g, &b, &a) == 4 ) // 2 digit hex with alpha + return NSVG_RGBA(r, g, b, a); if (sscanf(str, "#%2x%2x%2x", &r, &g, &b) == 3 ) // 2 digit hex return NSVG_RGB(r, g, b); if (sscanf(str, "#%1x%1x%1x", &r, &g, &b) == 3 ) // 1 digit hex, e.g. #abc -> 0xccbbaa @@ -1382,6 +1386,21 @@ static unsigned int nsvg__parseColorRGB(const char* str) return NSVG_RGB(128, 128, 128); } +static unsigned int nsvg__parseColorRGBA(const char* str) +{ + unsigned int r=0, g=0, b=0; + float a = 1.0; + if (sscanf(str, "rgba(%u, %u, %u, %f)", &r, &g, &b, &a) == 4) // decimal integers + { + float alpha = a * 255; + if (alpha < 1.0) alpha = 1.0; + return NSVG_RGBA(r, g, b, alpha); + } + if (sscanf(str, "rgba(%u%%, %u%%, %u%%, %f)", &r, &g, &b, &a) == 4) // decimal integer percentage + return NSVG_RGBA((r*255)/100, (g*255)/100, (b*255)/100, (a*255)/100); + return NSVG_RGBA(128, 128, 128, 1.0); +} + typedef struct NSVGNamedColor { const char* name; @@ -1567,6 +1586,8 @@ static unsigned int nsvg__parseColor(const char* str) return nsvg__parseColorHex(str); else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(') return nsvg__parseColorRGB(str); + else if (len >= 5 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == 'a' && str[4] == '(') + return nsvg__parseColorRGBA(str); return nsvg__parseColorName(str); } @@ -1923,6 +1944,14 @@ static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value) { attr->hasFill = 1; attr->fillColor = nsvg__parseColor(value); + // if the fillColor has an alpha value then use it to + // set the fillOpacity + if (attr->fillColor & 0xFF000000) + { + attr->fillOpacity = ((attr->fillColor >> 24) & 0xFF) / 255.0; + // remove the alpha value from the color + attr->fillColor &= 0x00FFFFFF; + } } } else if (strcmp(name, "opacity") == 0) @@ -1948,6 +1977,14 @@ static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value) { attr->hasStroke = 1; attr->strokeColor = nsvg__parseColor(value); + // if the strokeColor has an alpha value then use it to + // set the strokeOpacity + if (attr->strokeColor & 0xFF000000) + { + attr->strokeOpacity = ((attr->strokeColor >> 24) & 0xFF) / 255.0; + // remove the alpha value from the color + attr->strokeColor &= 0x00FFFFFF; + } } } else if (strcmp(name, "stroke-width") == 0) diff --git a/src/driver/pictureviewer/nanosvgrast.h b/src/driver/pictureviewer/nanosvgrast.h index fd6bec86e..6ed4b78ab 100644 --- a/src/driver/pictureviewer/nanosvgrast.h +++ b/src/driver/pictureviewer/nanosvgrast.h @@ -62,6 +62,10 @@ void nsvgRasterize(NSVGrasterizer* r, NSVGimage* image, float tx, float ty, float scale, unsigned char* dst, int w, int h, int stride); +void nsvgRasterizeFull(NSVGrasterizer* r, NSVGimage* image, + float tx, float ty, float scalex, float scaley, + unsigned char* dst, int w, int h, int stride); + // Deletes rasterizer context. void nsvgDeleteRasterizer(NSVGrasterizer*); @@ -391,7 +395,7 @@ static void nsvg__flattenCubicBez(NSVGrasterizer* r, nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type); } -static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, float scale) +static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, float scalex, float scaley) { int i, j; NSVGpath* path; @@ -400,14 +404,14 @@ static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, float scale) { r->npoints = 0; // Flatten path - nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0); + nsvg__addPathPoint(r, path->pts[0]*scalex, path->pts[1]*scaley, 0); for (i = 0; i < path->npts-1; i += 3) { float* p = &path->pts[i*2]; - 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); + 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); } // Close path - nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0); + nsvg__addPathPoint(r, path->pts[0]*scalex, path->pts[1]*scaley, 0); // Build edges for (i = 0, j = r->npoints-1; i < r->npoints; j = i++) nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y); @@ -807,7 +811,7 @@ static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int lineJoi } } -static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float scale) +static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float scalex, float scaley) { int i, j, closed; NSVGpath* path; @@ -815,17 +819,17 @@ static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float float miterLimit = shape->miterLimit; int lineJoin = shape->strokeLineJoin; int lineCap = shape->strokeLineCap; - float lineWidth = shape->strokeWidth * scale; + float lineWidth = shape->strokeWidth * (scalex+scaley)*0.5; for (path = shape->paths; path != NULL; path = path->next) { // Flatten path r->npoints = 0; - nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, NSVG_PT_CORNER); + nsvg__addPathPoint(r, path->pts[0]*scalex, path->pts[1]*scaley, NSVG_PT_CORNER); for (i = 0; i < path->npts-1; i += 3) { float* p = &path->pts[i*2]; - 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); + 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); } if (r->npoints < 2) continue; @@ -874,7 +878,7 @@ static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float dashOffset -= shape->strokeDashArray[idash]; idash = (idash + 1) % shape->strokeDashCount; } - dashLen = (shape->strokeDashArray[idash] - dashOffset) * scale; + dashLen = (shape->strokeDashArray[idash] - dashOffset) * (scalex+scaley)*0.5; for (j = 1; j < r->npoints2; ) { @@ -899,7 +903,7 @@ static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float // Advance dash pattern dashState = !dashState; idash = (idash+1) % shape->strokeDashCount; - dashLen = shape->strokeDashArray[idash] * scale; + dashLen = shape->strokeDashArray[idash] * (scalex+scaley)*0.5; // Restart cur.x = x; cur.y = y; @@ -1097,7 +1101,7 @@ static inline int nsvg__div255(int x) } static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* cover, int x, int y, - float tx, float ty, float scale, NSVGcachedPaint* cache) + float tx, float ty, float scalex, float scaley, NSVGcachedPaint* cache) { if (cache->type == NSVG_PAINT_COLOR) @@ -1142,9 +1146,9 @@ static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* co int i, cr, cg, cb, ca; unsigned int c; - fx = ((float)x - tx) / scale; - fy = ((float)y - ty) / scale; - dx = 1.0f / scale; + fx = ((float)x - tx) / scalex; + fy = ((float)y - ty) / scaley; + dx = 1.0f / scalex; for (i = 0; i < count; i++) { @@ -1190,9 +1194,9 @@ static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* co int i, cr, cg, cb, ca; unsigned int c; - fx = ((float)x - tx) / scale; - fy = ((float)y - ty) / scale; - dx = 1.0f / scale; + fx = ((float)x - tx) / scalex; + fy = ((float)y - ty) / scaley; + dx = 1.0f / scalex; for (i = 0; i < count; i++) { @@ -1232,7 +1236,7 @@ static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* co } } -static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, float scale, NSVGcachedPaint* cache, char fillRule) +static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, float scalex, float scaley, NSVGcachedPaint* cache, char fillRule) { NSVGactiveEdge *active = NULL; int y, s; @@ -1331,7 +1335,7 @@ static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, fl if (xmax > r->width-1) xmax = r->width-1; if (xmin <= xmax) { - nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty, scale, cache); + nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty, scalex, scaley, cache); } } @@ -1519,8 +1523,8 @@ static void dumpEdges(NSVGrasterizer* r, const char* name) } */ -void nsvgRasterize(NSVGrasterizer* r, - NSVGimage* image, float tx, float ty, float scale, +void nsvgRasterizeFull(NSVGrasterizer* r, + NSVGimage* image, float tx, float ty, float scalex, float scaley, unsigned char* dst, int w, int h, int stride) { NSVGshape *shape = NULL; @@ -1540,8 +1544,8 @@ void nsvgRasterize(NSVGrasterizer* r, if (r->scanline == NULL) return; } - for (i = 0; i < h; i++) - memset(&dst[i*stride], 0, w*4); + // for (i = 0; i < h; i++) + // memset(&dst[i*stride], 0, w*4); for (shape = image->shapes; shape != NULL; shape = shape->next) { @@ -1554,7 +1558,7 @@ void nsvgRasterize(NSVGrasterizer* r, r->freelist = NULL; r->nedges = 0; - nsvg__flattenShape(r, shape, scale); + nsvg__flattenShape(r, shape, scalex, scaley); // Scale and translate edges for (i = 0; i < r->nedges; i++) @@ -1572,15 +1576,15 @@ void nsvgRasterize(NSVGrasterizer* r, // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule nsvg__initPaint(&cache, &shape->fill, shape->opacity); - nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, shape->fillRule); + nsvg__rasterizeSortedEdges(r, tx,ty, scalex, scaley, &cache, shape->fillRule); } - if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) + if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * (scalex+scaley)*0.5) > 0.01f) { nsvg__resetPool(r); r->freelist = NULL; r->nedges = 0; - nsvg__flattenShapeStroke(r, shape, scale); + nsvg__flattenShapeStroke(r, shape, scalex, scaley); // dumpEdges(r, "edge.svg"); @@ -1600,7 +1604,7 @@ void nsvgRasterize(NSVGrasterizer* r, // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule nsvg__initPaint(&cache, &shape->stroke, shape->opacity); - nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO); + nsvg__rasterizeSortedEdges(r, tx,ty, scalex, scaley, &cache, NSVG_FILLRULE_NONZERO); } } @@ -1612,4 +1616,11 @@ void nsvgRasterize(NSVGrasterizer* r, r->stride = 0; } +void nsvgRasterize(NSVGrasterizer* r, + NSVGimage* image, float tx, float ty, float scale, + unsigned char* dst, int w, int h, int stride) +{ + return nsvgRasterizeFull(r, image, tx, ty, scale, scale, dst, w, h, stride); +} + #endif diff --git a/src/driver/pictureviewer/svg.cpp b/src/driver/pictureviewer/svg.cpp index 264dae6e3..bf74fa1c5 100644 --- a/src/driver/pictureviewer/svg.cpp +++ b/src/driver/pictureviewer/svg.cpp @@ -133,14 +133,12 @@ int svg_load_resize(const char *name, unsigned char **buffer, int* ox, int* oy, goto error; } - float scale,scale_w,scale_h; + float scale_w,scale_h; scale_w = *dx/w; scale_h = *dy/h; - scale = std::max(scale_w,scale_h); - - w = (int)(w*scale); - h = (int)(h*scale); + w = (int)(w*scale_w); + h = (int)(h*scale_h); free(*buffer); *buffer = (unsigned char*) malloc(w*h*4); @@ -155,7 +153,7 @@ int svg_load_resize(const char *name, unsigned char **buffer, int* ox, int* oy, } //printf("[SVG] rasterizing image %d x %d\n", w, h); - nsvgRasterize(rast, image, 0, 0, scale, *buffer, w, h, w*4); + nsvgRasterizeFull(rast, image, 0, 0, scale_w, scale_h, *buffer, w, h, w*4); error: nsvgDeleteRasterizer(rast);