msdfgen: Update to 1.13

Remove unused `export-svg` and `save-*` files.
This commit is contained in:
Rémi Verschelde
2025-12-12 22:39:53 +01:00
parent 08e6cd181f
commit 76dda1f2c8
43 changed files with 807 additions and 1041 deletions
+63 -63
View File
@@ -87,17 +87,15 @@ public:
Point2 shapeCoord, sdfCoord;
const float *msd;
bool protectedFlag;
inline ShapeDistanceChecker(const BitmapConstRef<float, N> &sdf, const Shape &shape, const Projection &projection, DistanceMapping distanceMapping, double minImproveRatio) : distanceFinder(shape), sdf(sdf), distanceMapping(distanceMapping), minImproveRatio(minImproveRatio) {
inline ShapeDistanceChecker(const BitmapConstSection<float, N> &sdf, const Shape &shape, const Projection &projection, DistanceMapping distanceMapping, double minImproveRatio) : distanceFinder(shape), sdf(sdf), distanceMapping(distanceMapping), minImproveRatio(minImproveRatio) {
texelSize = projection.unprojectVector(Vector2(1));
if (shape.inverseYAxis)
texelSize.y = -texelSize.y;
}
inline ArtifactClassifier classifier(const Vector2 &direction, double span) {
return ArtifactClassifier(this, direction, span);
}
private:
ShapeDistanceFinder<ContourCombiner<PerpendicularDistanceSelector> > distanceFinder;
BitmapConstRef<float, N> sdf;
BitmapConstSection<float, N> sdf;
DistanceMapping distanceMapping;
Vector2 texelSize;
double minImproveRatio;
@@ -105,10 +103,11 @@ private:
MSDFErrorCorrection::MSDFErrorCorrection() { }
MSDFErrorCorrection::MSDFErrorCorrection(const BitmapRef<byte, 1> &stencil, const SDFTransformation &transformation) : stencil(stencil), transformation(transformation) {
MSDFErrorCorrection::MSDFErrorCorrection(const BitmapSection<byte, 1> &stencil, const SDFTransformation &transformation) : stencil(stencil), transformation(transformation) {
minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio;
minImproveRatio = ErrorCorrectionConfig::defaultMinImproveRatio;
memset(stencil.pixels, 0, sizeof(byte)*stencil.width*stencil.height);
for (int y = 0; y < stencil.height; ++y)
memset(stencil(0, y), 0, sizeof(byte)*stencil.width);
}
void MSDFErrorCorrection::setMinDeviationRatio(double minDeviationRatio) {
@@ -120,6 +119,7 @@ void MSDFErrorCorrection::setMinImproveRatio(double minImproveRatio) {
}
void MSDFErrorCorrection::protectCorners(const Shape &shape) {
stencil.reorient(shape.getYAxisOrientation());
for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour)
if (!contour->edges.empty()) {
const EdgeSegment *prevEdge = contour->edges.back();
@@ -131,8 +131,6 @@ void MSDFErrorCorrection::protectCorners(const Shape &shape) {
Point2 p = transformation.project((*edge)->point(0));
int l = (int) floor(p.x-.5);
int b = (int) floor(p.y-.5);
if (shape.inverseYAxis)
b = stencil.height-b-2;
int r = l+1;
int t = b+1;
// Check that the positions are within bounds.
@@ -189,8 +187,9 @@ static void protectExtremeChannels(byte *stencil, const float *msd, float m, int
}
template <int N>
void MSDFErrorCorrection::protectEdges(const BitmapConstRef<float, N> &sdf) {
void MSDFErrorCorrection::protectEdges(const BitmapConstSection<float, N> &sdf) {
float radius;
stencil.reorient(sdf.yOrientation);
// Horizontal texel pairs
radius = float(PROTECTION_RADIUS_TOLERANCE*transformation.unprojectVector(Vector2(transformation.distanceMapping(DistanceMapping::Delta(1)), 0)).length());
for (int y = 0; y < sdf.height; ++y) {
@@ -251,9 +250,11 @@ void MSDFErrorCorrection::protectEdges(const BitmapConstRef<float, N> &sdf) {
}
void MSDFErrorCorrection::protectAll() {
byte *end = stencil.pixels+stencil.width*stencil.height;
for (byte *mask = stencil.pixels; mask < end; ++mask)
*mask |= (byte) PROTECTED;
for (int y = 0; y < stencil.height; ++y) {
byte *mask = stencil(0, y);
for (int x = 0; x < stencil.width; ++x)
*mask++ |= (byte) PROTECTED;
}
}
/// Returns the median of the linear interpolation of texels a, b at t.
@@ -273,16 +274,6 @@ static float interpolatedMedian(const float *a, const float *l, const float *q,
));
}
/// Determines if the interpolated median xm is an artifact.
static bool isArtifact(bool isProtected, double axSpan, double bxSpan, float am, float bm, float xm) {
return (
// For protected texels, only report an artifact if it would cause fill inversion (change between positive and negative distance).
(!isProtected || (am > .5f && bm > .5f && xm <= .5f) || (am < .5f && bm < .5f && xm >= .5f)) &&
// This is an artifact if the interpolated median is outside the range of possible values based on its distance from a, b.
!(xm >= am-axSpan && xm <= am+axSpan && xm >= bm-bxSpan && xm <= bm+bxSpan)
);
}
/// Checks if a linear interpolation artifact will occur at a point where two specific color channels are equal - such points have extreme median values.
template <class ArtifactClassifier>
static bool hasLinearArtifactInner(const ArtifactClassifier &artifactClassifier, float am, float bm, const float *a, const float *b, float dA, float dB) {
@@ -390,7 +381,8 @@ static bool hasDiagonalArtifact(const ArtifactClassifier &artifactClassifier, fl
}
template <int N>
void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, N> &sdf) {
void MSDFErrorCorrection::findErrors(const BitmapConstSection<float, N> &sdf) {
stencil.reorient(sdf.yOrientation);
// Compute the expected deltas between values of horizontally, vertically, and diagonally adjacent texels.
double hSpan = minDeviationRatio*transformation.unprojectVector(Vector2(transformation.distanceMapping(DistanceMapping::Delta(1)), 0)).length();
double vSpan = minDeviationRatio*transformation.unprojectVector(Vector2(0, transformation.distanceMapping(DistanceMapping::Delta(1)))).length();
@@ -418,7 +410,9 @@ void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, N> &sdf) {
}
template <template <typename> class ContourCombiner, int N>
void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, N> &sdf, const Shape &shape) {
void MSDFErrorCorrection::findErrors(BitmapConstSection<float, N> sdf, const Shape &shape) {
sdf.reorient(shape.getYAxisOrientation());
stencil.reorient(sdf.yOrientation);
// Compute the expected deltas between values of horizontally, vertically, and diagonally adjacent texels.
double hSpan = minDeviationRatio*transformation.unprojectVector(Vector2(transformation.distanceMapping(DistanceMapping::Delta(1)), 0)).length();
double vSpan = minDeviationRatio*transformation.unprojectVector(Vector2(0, transformation.distanceMapping(DistanceMapping::Delta(1)))).length();
@@ -428,69 +422,75 @@ void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, N> &sdf, const
#endif
{
ShapeDistanceChecker<ContourCombiner, N> shapeDistanceChecker(sdf, shape, transformation, transformation.distanceMapping, minImproveRatio);
bool rightToLeft = false;
int xDirection = 1;
// Inspect all texels.
#ifdef MSDFGEN_USE_OPENMP
#pragma omp for
#endif
for (int y = 0; y < sdf.height; ++y) {
int row = shape.inverseYAxis ? sdf.height-y-1 : y;
for (int col = 0; col < sdf.width; ++col) {
int x = rightToLeft ? sdf.width-col-1 : col;
if ((*stencil(x, row)&ERROR))
int x = xDirection < 0 ? sdf.width-1 : 0;
for (int col = 0; col < sdf.width; ++col, x += xDirection) {
if ((*stencil(x, y)&ERROR))
continue;
const float *c = sdf(x, row);
const float *c = sdf(x, y);
shapeDistanceChecker.shapeCoord = transformation.unproject(Point2(x+.5, y+.5));
shapeDistanceChecker.sdfCoord = Point2(x+.5, row+.5);
shapeDistanceChecker.sdfCoord = Point2(x+.5, y+.5);
shapeDistanceChecker.msd = c;
shapeDistanceChecker.protectedFlag = (*stencil(x, row)&PROTECTED) != 0;
shapeDistanceChecker.protectedFlag = (*stencil(x, y)&PROTECTED) != 0;
float cm = median(c[0], c[1], c[2]);
const float *l = NULL, *b = NULL, *r = NULL, *t = NULL;
// Mark current texel c with the error flag if an artifact occurs when it's interpolated with any of its 8 neighbors.
*stencil(x, row) |= (byte) (ERROR*(
(x > 0 && ((l = sdf(x-1, row)), hasLinearArtifact(shapeDistanceChecker.classifier(Vector2(-1, 0), hSpan), cm, c, l))) ||
(row > 0 && ((b = sdf(x, row-1)), hasLinearArtifact(shapeDistanceChecker.classifier(Vector2(0, -1), vSpan), cm, c, b))) ||
(x < sdf.width-1 && ((r = sdf(x+1, row)), hasLinearArtifact(shapeDistanceChecker.classifier(Vector2(+1, 0), hSpan), cm, c, r))) ||
(row < sdf.height-1 && ((t = sdf(x, row+1)), hasLinearArtifact(shapeDistanceChecker.classifier(Vector2(0, +1), vSpan), cm, c, t))) ||
(x > 0 && row > 0 && hasDiagonalArtifact(shapeDistanceChecker.classifier(Vector2(-1, -1), dSpan), cm, c, l, b, sdf(x-1, row-1))) ||
(x < sdf.width-1 && row > 0 && hasDiagonalArtifact(shapeDistanceChecker.classifier(Vector2(+1, -1), dSpan), cm, c, r, b, sdf(x+1, row-1))) ||
(x > 0 && row < sdf.height-1 && hasDiagonalArtifact(shapeDistanceChecker.classifier(Vector2(-1, +1), dSpan), cm, c, l, t, sdf(x-1, row+1))) ||
(x < sdf.width-1 && row < sdf.height-1 && hasDiagonalArtifact(shapeDistanceChecker.classifier(Vector2(+1, +1), dSpan), cm, c, r, t, sdf(x+1, row+1)))
*stencil(x, y) |= (byte) (ERROR*(
(x > 0 && ((l = sdf(x-1, y)), hasLinearArtifact(shapeDistanceChecker.classifier(Vector2(-1, 0), hSpan), cm, c, l))) ||
(y > 0 && ((b = sdf(x, y-1)), hasLinearArtifact(shapeDistanceChecker.classifier(Vector2(0, -1), vSpan), cm, c, b))) ||
(x < sdf.width-1 && ((r = sdf(x+1, y)), hasLinearArtifact(shapeDistanceChecker.classifier(Vector2(+1, 0), hSpan), cm, c, r))) ||
(y < sdf.height-1 && ((t = sdf(x, y+1)), hasLinearArtifact(shapeDistanceChecker.classifier(Vector2(0, +1), vSpan), cm, c, t))) ||
(x > 0 && y > 0 && hasDiagonalArtifact(shapeDistanceChecker.classifier(Vector2(-1, -1), dSpan), cm, c, l, b, sdf(x-1, y-1))) ||
(x < sdf.width-1 && y > 0 && hasDiagonalArtifact(shapeDistanceChecker.classifier(Vector2(+1, -1), dSpan), cm, c, r, b, sdf(x+1, y-1))) ||
(x > 0 && y < sdf.height-1 && hasDiagonalArtifact(shapeDistanceChecker.classifier(Vector2(-1, +1), dSpan), cm, c, l, t, sdf(x-1, y+1))) ||
(x < sdf.width-1 && y < sdf.height-1 && hasDiagonalArtifact(shapeDistanceChecker.classifier(Vector2(+1, +1), dSpan), cm, c, r, t, sdf(x+1, y+1)))
));
}
xDirection = -xDirection;
}
}
}
template <int N>
void MSDFErrorCorrection::apply(const BitmapRef<float, N> &sdf) const {
int texelCount = sdf.width*sdf.height;
const byte *mask = stencil.pixels;
float *texel = sdf.pixels;
for (int i = 0; i < texelCount; ++i) {
if (*mask&ERROR) {
// Set all color channels to the median.
float m = median(texel[0], texel[1], texel[2]);
texel[0] = m, texel[1] = m, texel[2] = m;
void MSDFErrorCorrection::apply(BitmapSection<float, N> sdf) const {
sdf.reorient(stencil.yOrientation);
const byte *stencilRow = stencil.pixels;
float *rowStart = sdf.pixels;
for (int y = 0; y < sdf.height; ++y) {
const byte *mask = stencilRow;
float *pixel = rowStart;
for (int x = 0; x < sdf.width; ++x) {
if (*mask&ERROR) {
// Set all color channels to the median.
float m = median(pixel[0], pixel[1], pixel[2]);
pixel[0] = m, pixel[1] = m, pixel[2] = m;
}
++mask;
pixel += N;
}
++mask;
texel += N;
stencilRow += stencil.rowStride;
rowStart += sdf.rowStride;
}
}
BitmapConstRef<byte, 1> MSDFErrorCorrection::getStencil() const {
BitmapConstSection<byte, 1> MSDFErrorCorrection::getStencil() const {
return stencil;
}
template void MSDFErrorCorrection::protectEdges(const BitmapConstRef<float, 3> &sdf);
template void MSDFErrorCorrection::protectEdges(const BitmapConstRef<float, 4> &sdf);
template void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, 3> &sdf);
template void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, 4> &sdf);
template void MSDFErrorCorrection::findErrors<SimpleContourCombiner>(const BitmapConstRef<float, 3> &sdf, const Shape &shape);
template void MSDFErrorCorrection::findErrors<SimpleContourCombiner>(const BitmapConstRef<float, 4> &sdf, const Shape &shape);
template void MSDFErrorCorrection::findErrors<OverlappingContourCombiner>(const BitmapConstRef<float, 3> &sdf, const Shape &shape);
template void MSDFErrorCorrection::findErrors<OverlappingContourCombiner>(const BitmapConstRef<float, 4> &sdf, const Shape &shape);
template void MSDFErrorCorrection::apply(const BitmapRef<float, 3> &sdf) const;
template void MSDFErrorCorrection::apply(const BitmapRef<float, 4> &sdf) const;
template void MSDFErrorCorrection::protectEdges(const BitmapConstSection<float, 3> &sdf);
template void MSDFErrorCorrection::protectEdges(const BitmapConstSection<float, 4> &sdf);
template void MSDFErrorCorrection::findErrors(const BitmapConstSection<float, 3> &sdf);
template void MSDFErrorCorrection::findErrors(const BitmapConstSection<float, 4> &sdf);
template void MSDFErrorCorrection::findErrors<SimpleContourCombiner>(BitmapConstSection<float, 3> sdf, const Shape &shape);
template void MSDFErrorCorrection::findErrors<SimpleContourCombiner>(BitmapConstSection<float, 4> sdf, const Shape &shape);
template void MSDFErrorCorrection::findErrors<OverlappingContourCombiner>(BitmapConstSection<float, 3> sdf, const Shape &shape);
template void MSDFErrorCorrection::findErrors<OverlappingContourCombiner>(BitmapConstSection<float, 4> sdf, const Shape &shape);
template void MSDFErrorCorrection::apply(BitmapSection<float, 3> sdf) const;
template void MSDFErrorCorrection::apply(BitmapSection<float, 4> sdf) const;
}