mirror of https://github.com/Chlumsky/msdfgen.git
Version 1.7
This commit is contained in:
parent
fd50406d67
commit
5427fe8f5a
11
CHANGELOG.md
11
CHANGELOG.md
|
|
@ -1,4 +1,15 @@
|
||||||
|
|
||||||
|
## Version 1.7 (2020-03-07)
|
||||||
|
|
||||||
|
- Added `mtsdf` mode - a combination of `msdf` with `sdf` in the alpha channel
|
||||||
|
- Distance fields can now be stored as uncompressed TIFF image files with floating point precision
|
||||||
|
- Bitmap class refactor - template argument split into data type and number of channels, bitmap reference classes introduced
|
||||||
|
- Added a secondary "ink trap" edge coloring heuristic, can be selected using `-coloringstrategy inktrap`
|
||||||
|
- Added computation of estimated rendering error for a given SDF
|
||||||
|
- Added computation of bounding box that includes sharp mitered corners
|
||||||
|
- The API for bounds computation of the `Shape` class changed for clarity
|
||||||
|
- Fixed several edge case bugs
|
||||||
|
|
||||||
## Version 1.6 (2019-04-08)
|
## Version 1.6 (2019-04-08)
|
||||||
|
|
||||||
- Core algorithm rewritten to split up advanced edge selection logic into modular template arguments.
|
- Core algorithm rewritten to split up advanced edge selection logic into modular template arguments.
|
||||||
|
|
|
||||||
|
|
@ -124,29 +124,35 @@
|
||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<TargetName>msdfgen</TargetName>
|
<TargetName>msdfgen</TargetName>
|
||||||
|
<OutDir>$(Configuration)\</OutDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|Win32'">
|
||||||
<TargetName>msdfgen</TargetName>
|
<TargetName>msdfgen</TargetName>
|
||||||
|
<OutDir>$(Configuration)\</OutDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<TargetName>msdfgen</TargetName>
|
<TargetName>msdfgen</TargetName>
|
||||||
<OutDir>$(SolutionDir)\bin\</OutDir>
|
<OutDir>bin\</OutDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release Library|Win32'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release Library|Win32'">
|
||||||
<TargetName>msdfgen</TargetName>
|
<TargetName>msdfgen</TargetName>
|
||||||
<OutDir>$(SolutionDir)\bin\</OutDir>
|
<OutDir>bin\</OutDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release Library|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release Library|x64'">
|
||||||
<TargetName>msdfgen</TargetName>
|
<TargetName>msdfgen</TargetName>
|
||||||
|
<OutDir>$(Platform)\$(Configuration)\</OutDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
<TargetName>msdfgen</TargetName>
|
<TargetName>msdfgen</TargetName>
|
||||||
|
<OutDir>$(Platform)\$(Configuration)\</OutDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<TargetName>msdfgen</TargetName>
|
<TargetName>msdfgen</TargetName>
|
||||||
|
<OutDir>$(Platform)\$(Configuration)\</OutDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'">
|
||||||
<TargetName>msdfgen</TargetName>
|
<TargetName>msdfgen</TargetName>
|
||||||
|
<OutDir>$(Platform)\$(Configuration)\</OutDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,13 @@ public:
|
||||||
int height() const;
|
int height() const;
|
||||||
T * operator()(int x, int y);
|
T * operator()(int x, int y);
|
||||||
const T * operator()(int x, int y) const;
|
const T * operator()(int x, int y) const;
|
||||||
|
#ifdef MSDFGEN_USE_CPP11
|
||||||
explicit operator T *();
|
explicit operator T *();
|
||||||
explicit operator const T *() const;
|
explicit operator const T *() const;
|
||||||
|
#else
|
||||||
|
operator T *();
|
||||||
|
operator const T *() const;
|
||||||
|
#endif
|
||||||
operator BitmapRef<T, N>();
|
operator BitmapRef<T, N>();
|
||||||
operator BitmapConstRef<T, N>() const;
|
operator BitmapConstRef<T, N>() const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -220,9 +220,18 @@ bool readShapeDescription(const char *input, Shape &output, bool *colorsSpecifie
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isColored(const Shape &shape) {
|
||||||
|
for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour)
|
||||||
|
for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge)
|
||||||
|
if ((*edge)->color != WHITE)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool writeShapeDescription(FILE *output, const Shape &shape) {
|
bool writeShapeDescription(FILE *output, const Shape &shape) {
|
||||||
if (!shape.validate())
|
if (!shape.validate())
|
||||||
return false;
|
return false;
|
||||||
|
bool writeColors = isColored(shape);
|
||||||
if (shape.inverseYAxis)
|
if (shape.inverseYAxis)
|
||||||
fprintf(output, "@invert-y\n");
|
fprintf(output, "@invert-y\n");
|
||||||
for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
|
for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
|
||||||
|
|
@ -230,6 +239,7 @@ bool writeShapeDescription(FILE *output, const Shape &shape) {
|
||||||
if (!contour->edges.empty()) {
|
if (!contour->edges.empty()) {
|
||||||
for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
|
for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
|
||||||
char colorCode = '\0';
|
char colorCode = '\0';
|
||||||
|
if (writeColors) {
|
||||||
switch ((*edge)->color) {
|
switch ((*edge)->color) {
|
||||||
case YELLOW: colorCode = 'y'; break;
|
case YELLOW: colorCode = 'y'; break;
|
||||||
case MAGENTA: colorCode = 'm'; break;
|
case MAGENTA: colorCode = 'm'; break;
|
||||||
|
|
@ -237,6 +247,7 @@ bool writeShapeDescription(FILE *output, const Shape &shape) {
|
||||||
case WHITE: colorCode = 'w'; break;
|
case WHITE: colorCode = 'w'; break;
|
||||||
default:;
|
default:;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
{
|
{
|
||||||
const LinearSegment *e = dynamic_cast<const LinearSegment *>(&**edge);
|
const LinearSegment *e = dynamic_cast<const LinearSegment *>(&**edge);
|
||||||
if (e) {
|
if (e) {
|
||||||
|
|
|
||||||
18
main.cpp
18
main.cpp
|
|
@ -1,8 +1,8 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR v1.6 (2019-04-08) - standalone console program
|
* MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR v1.7 (2020-03-07) - standalone console program
|
||||||
* --------------------------------------------------------------------------------------------
|
* --------------------------------------------------------------------------------------------
|
||||||
* A utility by Viktor Chlumsky, (c) 2014 - 2019
|
* A utility by Viktor Chlumsky, (c) 2014 - 2020
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -33,7 +33,7 @@ enum Format {
|
||||||
TEXT_FLOAT,
|
TEXT_FLOAT,
|
||||||
BINARY,
|
BINARY,
|
||||||
BINARY_FLOAT,
|
BINARY_FLOAT,
|
||||||
BINART_FLOAT_BE
|
BINARY_FLOAT_BE
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool is8bitFormat(Format format) {
|
static bool is8bitFormat(Format format) {
|
||||||
|
|
@ -228,14 +228,14 @@ static const char * writeOutput(const BitmapConstRef<float, N> &bitmap, const ch
|
||||||
fclose(file);
|
fclose(file);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
case BINARY: case BINARY_FLOAT: case BINART_FLOAT_BE: {
|
case BINARY: case BINARY_FLOAT: case BINARY_FLOAT_BE: {
|
||||||
FILE *file = fopen(filename, "wb");
|
FILE *file = fopen(filename, "wb");
|
||||||
if (!file) return "Failed to write output binary file.";
|
if (!file) return "Failed to write output binary file.";
|
||||||
if (format == BINARY)
|
if (format == BINARY)
|
||||||
writeBinBitmap(file, bitmap.pixels, N*bitmap.width*bitmap.height);
|
writeBinBitmap(file, bitmap.pixels, N*bitmap.width*bitmap.height);
|
||||||
else if (format == BINARY_FLOAT)
|
else if (format == BINARY_FLOAT)
|
||||||
writeBinBitmapFloat(file, bitmap.pixels, N*bitmap.width*bitmap.height);
|
writeBinBitmapFloat(file, bitmap.pixels, N*bitmap.width*bitmap.height);
|
||||||
else if (format == BINART_FLOAT_BE)
|
else if (format == BINARY_FLOAT_BE)
|
||||||
writeBinBitmapFloatBE(file, bitmap.pixels, N*bitmap.width*bitmap.height);
|
writeBinBitmapFloatBE(file, bitmap.pixels, N*bitmap.width*bitmap.height);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -498,7 +498,7 @@ int main(int argc, const char * const *argv) {
|
||||||
else if (!strcmp(argv[argPos+1], "textfloat") || !strcmp(argv[argPos+1], "txtfloat")) SET_FORMAT(TEXT_FLOAT, "txt");
|
else if (!strcmp(argv[argPos+1], "textfloat") || !strcmp(argv[argPos+1], "txtfloat")) SET_FORMAT(TEXT_FLOAT, "txt");
|
||||||
else if (!strcmp(argv[argPos+1], "bin") || !strcmp(argv[argPos+1], "binary")) SET_FORMAT(BINARY, "bin");
|
else if (!strcmp(argv[argPos+1], "bin") || !strcmp(argv[argPos+1], "binary")) SET_FORMAT(BINARY, "bin");
|
||||||
else if (!strcmp(argv[argPos+1], "binfloat") || !strcmp(argv[argPos+1], "binfloatle")) SET_FORMAT(BINARY_FLOAT, "bin");
|
else if (!strcmp(argv[argPos+1], "binfloat") || !strcmp(argv[argPos+1], "binfloatle")) SET_FORMAT(BINARY_FLOAT, "bin");
|
||||||
else if (!strcmp(argv[argPos+1], "binfloatbe")) SET_FORMAT(BINART_FLOAT_BE, "bin");
|
else if (!strcmp(argv[argPos+1], "binfloatbe")) SET_FORMAT(BINARY_FLOAT_BE, "bin");
|
||||||
else
|
else
|
||||||
puts("Unknown format specified.");
|
puts("Unknown format specified.");
|
||||||
argPos += 2;
|
argPos += 2;
|
||||||
|
|
@ -657,8 +657,10 @@ int main(int argc, const char * const *argv) {
|
||||||
argPos += 2;
|
argPos += 2;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ARG_CASE("-help", 0)
|
ARG_CASE("-help", 0) {
|
||||||
ABORT(helpText);
|
puts(helpText);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
printf("Unknown setting or insufficient parameters: %s\n", arg);
|
printf("Unknown setting or insufficient parameters: %s\n", arg);
|
||||||
suggestHelp = true;
|
suggestHelp = true;
|
||||||
++argPos;
|
++argPos;
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR v1.6 (2019-04-08) - extensions
|
* MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR v1.7 (2020-03-07) - extensions
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
* A utility by Viktor Chlumsky, (c) 2014 - 2019
|
* A utility by Viktor Chlumsky, (c) 2014 - 2020
|
||||||
*
|
*
|
||||||
* The extension module provides ways to easily load input and save output using popular formats.
|
* The extension module provides ways to easily load input and save output using popular formats.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
10
msdfgen.h
10
msdfgen.h
|
|
@ -2,16 +2,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR v1.6 (2019-04-08)
|
* MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR v1.7 (2020-03-07)
|
||||||
* ---------------------------------------------------------------
|
* ---------------------------------------------------------------
|
||||||
* A utility by Viktor Chlumsky, (c) 2014 - 2019
|
* A utility by Viktor Chlumsky, (c) 2014 - 2020
|
||||||
*
|
*
|
||||||
* The technique used to generate multi-channel distance fields in this code
|
* The technique used to generate multi-channel distance fields in this code
|
||||||
* has been developed by Viktor Chlumsky in 2014 for his master's thesis,
|
* has been developed by Viktor Chlumsky in 2014 for his master's thesis,
|
||||||
* "Shape Decomposition for Multi-Channel Distance Fields". It provides improved
|
* "Shape Decomposition for Multi-Channel Distance Fields". It provides improved
|
||||||
* quality of sharp corners in glyphs and other 2D shapes in comparison to monochrome
|
* quality of sharp corners in glyphs and other 2D shapes compared to monochrome
|
||||||
* distance fields. To reconstruct an image of the shape, apply the median of three
|
* distance fields. To reconstruct an image of the shape, apply the median of three
|
||||||
* operation on the triplet of sampled distance field values.
|
* operation on the triplet of sampled signed distance values.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
#include "core/save-tiff.h"
|
#include "core/save-tiff.h"
|
||||||
#include "core/shape-description.h"
|
#include "core/shape-description.h"
|
||||||
|
|
||||||
#define MSDFGEN_VERSION "1.6"
|
#define MSDFGEN_VERSION "1.7"
|
||||||
#define MSDFGEN_DEFAULT_ERROR_CORRECTION_THRESHOLD 1.001
|
#define MSDFGEN_DEFAULT_ERROR_CORRECTION_THRESHOLD 1.001
|
||||||
|
|
||||||
namespace msdfgen {
|
namespace msdfgen {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue