249 lines
9.4 KiB
Diff
249 lines
9.4 KiB
Diff
|
From abcd277ea45e9098bed752cf9c6875b533c0892f Mon Sep 17 00:00:00 2001
|
||
|
From: AlbrechtS <AlbrechtS.svn@fltk.example.org>
|
||
|
Date: Sun, 4 Feb 2018 23:47:38 +0100
|
||
|
Subject: [PATCH] Modify rasterizer to support non-square X,Y axes scaling.
|
||
|
|
||
|
Add new function nsvgRasterizeXY() similar to nsvgRasterize() but with
|
||
|
separate scaling factors for x-axis and y-axis.
|
||
|
---
|
||
|
src/nanosvgrast.h | 78 +++++++++++++++++++++++++++++++----------------
|
||
|
1 file changed, 51 insertions(+), 27 deletions(-)
|
||
|
|
||
|
diff --git a/src/nanosvgrast.h b/src/nanosvgrast.h
|
||
|
index 17ba3b0..a83db27 100644
|
||
|
--- a/src/nanosvgrast.h
|
||
|
+++ b/src/nanosvgrast.h
|
||
|
@@ -22,6 +22,12 @@
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
+/* Modified by FLTK to support non-square X,Y axes scaling.
|
||
|
+ *
|
||
|
+ * Added: nsvgRasterizeXY()
|
||
|
+*/
|
||
|
+
|
||
|
+
|
||
|
#ifndef NANOSVGRAST_H
|
||
|
#define NANOSVGRAST_H
|
||
|
|
||
|
@@ -46,6 +52,9 @@ typedef struct NSVGrasterizer NSVGrasterizer;
|
||
|
unsigned char* img = malloc(w*h*4);
|
||
|
// Rasterize
|
||
|
nsvgRasterize(rast, image, 0,0,1, img, w, h, w*4);
|
||
|
+
|
||
|
+ // For non-square X,Y scaling, use
|
||
|
+ nsvgRasterizeXY(rast, image, 0,0,1,1, img, w, h, w*4);
|
||
|
*/
|
||
|
|
||
|
// Allocated rasterizer context.
|
||
|
@@ -55,7 +64,7 @@ NSVGrasterizer* nsvgCreateRasterizer(void);
|
||
|
// r - pointer to rasterizer context
|
||
|
// image - pointer to image to rasterize
|
||
|
// tx,ty - image offset (applied after scaling)
|
||
|
-// scale - image scale
|
||
|
+// scale - image scale (assumes square aspect ratio)
|
||
|
// dst - pointer to destination image data, 4 bytes per pixel (RGBA)
|
||
|
// w - width of the image to render
|
||
|
// h - height of the image to render
|
||
|
@@ -64,6 +73,12 @@ void nsvgRasterize(NSVGrasterizer* r,
|
||
|
NSVGimage* image, float tx, float ty, float scale,
|
||
|
unsigned char* dst, int w, int h, int stride);
|
||
|
|
||
|
+// As above, but allow X and Y axes to scale independently for non-square aspects
|
||
|
+void nsvgRasterizeXY(NSVGrasterizer* r,
|
||
|
+ NSVGimage* image, float tx, float ty,
|
||
|
+ float sx, float sy,
|
||
|
+ unsigned char* dst, int w, int h, int stride);
|
||
|
+
|
||
|
// Deletes rasterizer context.
|
||
|
void nsvgDeleteRasterizer(NSVGrasterizer*);
|
||
|
|
||
|
@@ -370,7 +385,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 sx, float sy)
|
||
|
{
|
||
|
int i, j;
|
||
|
NSVGpath* path;
|
||
|
@@ -378,13 +393,13 @@ static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, float scale)
|
||
|
for (path = shape->paths; path != NULL; path = path->next) {
|
||
|
r->npoints = 0;
|
||
|
// Flatten path
|
||
|
- nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0);
|
||
|
+ nsvg__addPathPoint(r, path->pts[0]*sx, path->pts[1]*sy, 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]*sx,p[1]*sy, p[2]*sx,p[3]*sy, p[4]*sx,p[5]*sy, p[6]*sx,p[7]*sy, 0, 0);
|
||
|
}
|
||
|
// Close path
|
||
|
- nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0);
|
||
|
+ nsvg__addPathPoint(r, path->pts[0]*sx, path->pts[1]*sy, 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);
|
||
|
@@ -734,7 +749,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 sx, float sy)
|
||
|
{
|
||
|
int i, j, closed;
|
||
|
NSVGpath* path;
|
||
|
@@ -742,15 +757,16 @@ 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;
|
||
|
+ const float sw = (sx + sy) / 2; // average scaling factor
|
||
|
+ const float lineWidth = shape->strokeWidth * sw; // FIXME (?)
|
||
|
|
||
|
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]*sx, path->pts[1]*sy, 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]*sx,p[1]*sy, p[2]*sx,p[3]*sy, p[4]*sx,p[5]*sy, p[6]*sx,p[7]*sy, 0, NSVG_PT_CORNER);
|
||
|
}
|
||
|
if (r->npoints < 2)
|
||
|
continue;
|
||
|
@@ -796,7 +812,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) * sw;
|
||
|
|
||
|
for (j = 1; j < r->npoints2; ) {
|
||
|
float dx = r->points2[j].x - cur.x;
|
||
|
@@ -818,7 +834,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] * sw;
|
||
|
// Restart
|
||
|
cur.x = x;
|
||
|
cur.y = y;
|
||
|
@@ -987,7 +1003,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 sx, float sy, NSVGcachedPaint* cache)
|
||
|
{
|
||
|
|
||
|
if (cache->type == NSVG_PAINT_COLOR) {
|
||
|
@@ -1028,9 +1044,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) / sx;
|
||
|
+ fy = ((float)y - ty) / sy;
|
||
|
+ dx = 1.0f / sx;
|
||
|
|
||
|
for (i = 0; i < count; i++) {
|
||
|
int r,g,b,a,ia;
|
||
|
@@ -1073,9 +1089,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) / sx;
|
||
|
+ fy = ((float)y - ty) / sy;
|
||
|
+ dx = 1.0f / sx;
|
||
|
|
||
|
for (i = 0; i < count; i++) {
|
||
|
int r,g,b,a,ia;
|
||
|
@@ -1114,7 +1130,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 sx, float sy, NSVGcachedPaint* cache, char fillRule)
|
||
|
{
|
||
|
NSVGactiveEdge *active = NULL;
|
||
|
int y, s;
|
||
|
@@ -1196,7 +1212,7 @@ static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, fl
|
||
|
if (xmin < 0) xmin = 0;
|
||
|
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, sx, sy, cache);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@@ -1364,8 +1380,9 @@ static void dumpEdges(NSVGrasterizer* r, const char* name)
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
-void nsvgRasterize(NSVGrasterizer* r,
|
||
|
- NSVGimage* image, float tx, float ty, float scale,
|
||
|
+void nsvgRasterizeXY(NSVGrasterizer* r,
|
||
|
+ NSVGimage* image, float tx, float ty,
|
||
|
+ float sx, float sy,
|
||
|
unsigned char* dst, int w, int h, int stride)
|
||
|
{
|
||
|
NSVGshape *shape = NULL;
|
||
|
@@ -1396,7 +1413,7 @@ void nsvgRasterize(NSVGrasterizer* r,
|
||
|
r->freelist = NULL;
|
||
|
r->nedges = 0;
|
||
|
|
||
|
- nsvg__flattenShape(r, shape, scale);
|
||
|
+ nsvg__flattenShape(r, shape, sx, sy);
|
||
|
|
||
|
// Scale and translate edges
|
||
|
for (i = 0; i < r->nedges; i++) {
|
||
|
@@ -1414,14 +1431,14 @@ 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, sx, sy, &cache, shape->fillRule);
|
||
|
}
|
||
|
- if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) {
|
||
|
+ if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * sx) > 0.01f) {
|
||
|
nsvg__resetPool(r);
|
||
|
r->freelist = NULL;
|
||
|
r->nedges = 0;
|
||
|
|
||
|
- nsvg__flattenShapeStroke(r, shape, scale);
|
||
|
+ nsvg__flattenShapeStroke(r, shape, sx, sy);
|
||
|
|
||
|
// dumpEdges(r, "edge.svg");
|
||
|
|
||
|
@@ -1441,7 +1458,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,sx, sy, &cache, NSVG_FILLRULE_NONZERO);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@@ -1453,6 +1470,13 @@ 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)
|
||
|
+{
|
||
|
+ nsvgRasterizeXY(r,image, tx, ty, scale, scale, dst, w, h, stride);
|
||
|
+}
|
||
|
+
|
||
|
#endif // NANOSVGRAST_IMPLEMENTATION
|
||
|
|
||
|
#endif // NANOSVGRAST_H
|