Skip to content

Commit

Permalink
Added -exportsvg, RGBA & FL32 image output
Browse files Browse the repository at this point in the history
  • Loading branch information
Chlumsky committed May 7, 2024
1 parent d7ac1e0 commit aa9478e
Show file tree
Hide file tree
Showing 12 changed files with 328 additions and 13 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ The input can be specified as one of:
The complete list of available options can be printed with **-help**.
Some of the important ones are:
- **-o \<filename\>** &ndash; specifies the output file name. The desired format will be deduced from the extension
(png, bmp, tif, txt, bin). Otherwise, use -format.
(png, bmp, tiff, rgba, fl32, txt, bin). Otherwise, use -format.
- **-dimensions \<width\> \<height\>** &ndash; specifies the dimensions of the output distance field (in pixels).
- **-range \<range\>**, **-pxrange \<range\>** &ndash; specifies the width of the range around the shape
between the minimum and maximum representable signed distance in shape units or distance field pixels, respectivelly.
Expand Down Expand Up @@ -107,7 +107,7 @@ in order to generate a distance field. Please note that all classes and function
This can be performed automatically using the `edgeColoringSimple` (or other) heuristic, or manually by setting each edge's
`color` member. Keep in mind that at least two color channels must be turned on in each edge.
- Call `generateSDF`, `generatePSDF`, `generateMSDF`, or `generateMTSDF` to generate a distance field into a floating point
`Bitmap` object. This can then be worked with further or saved to a file using `saveBmp`, `savePng`, or `saveTiff`.
`Bitmap` object. This can then be worked with further or saved to a file using `saveBmp`, `savePng`, `saveTiff`, etc.
- You may also render an image from the distance field using `renderSDF`. Consider calling `simulate8bit`
on the distance field beforehand to simulate the standard 8 bits/channel image format.

Expand Down
79 changes: 79 additions & 0 deletions core/export-svg.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@

#include "export-svg.h"

#include <cstdio>
#include "edge-segments.h"

namespace msdfgen {

static void writeSvgCoord(FILE *f, Point2 coord) {
fprintf(f, "%.17g %.17g", coord.x, coord.y);
}

static void writeSvgPathDef(FILE *f, const Shape &shape) {
bool beginning = true;
for (const Contour &c : shape.contours) {
if (c.edges.empty())
continue;
if (beginning)
beginning = false;
else
fputc(' ', f);
fputs("M ", f);
writeSvgCoord(f, c.edges[0]->controlPoints()[0]);
for (const EdgeHolder &e : c.edges) {
const Point2 *cp = e->controlPoints();
switch (e->type()) {
case (int) LinearSegment::EDGE_TYPE:
fputs(" L ", f);
writeSvgCoord(f, cp[1]);
break;
case (int) QuadraticSegment::EDGE_TYPE:
fputs(" Q ", f);
writeSvgCoord(f, cp[1]);
fputc(' ', f);
writeSvgCoord(f, cp[2]);
break;
case (int) CubicSegment::EDGE_TYPE:
fputs(" C ", f);
writeSvgCoord(f, cp[1]);
fputc(' ', f);
writeSvgCoord(f, cp[2]);
fputc(' ', f);
writeSvgCoord(f, cp[3]);
break;
}
}
fputs(" Z", f);
}
}

bool saveSvgShape(const Shape &shape, const char *filename) {
if (FILE *f = fopen(filename, "w")) {
fputs("<svg xmlns=\"http://www.w3.org/2000/svg\"><path", f);
if (!shape.inverseYAxis)
fputs(" transform=\"scale(1 -1)\"", f);
fputs(" d=\"", f);
writeSvgPathDef(f, shape);
fputs("\"/></svg>\n", f);
fclose(f);
return true;
}
return false;
}

bool saveSvgShape(const Shape &shape, const Shape::Bounds &bounds, const char *filename) {
if (FILE *f = fopen(filename, "w")) {
fprintf(f, "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"%.17g %.17g %.17g %.17g\"><path", bounds.l, bounds.b, bounds.r-bounds.l, bounds.t-bounds.b);
if (!shape.inverseYAxis)
fprintf(f, " transform=\"translate(0 %.17g) scale(1 -1)\"", bounds.b+bounds.t);
fputs(" d=\"", f);
writeSvgPathDef(f, shape);
fputs("\"/></svg>\n", f);
fclose(f);
return true;
}
return false;
}

}
11 changes: 11 additions & 0 deletions core/export-svg.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

#pragma once

#include "Shape.h"

namespace msdfgen {

bool saveSvgShape(const Shape &shape, const char *filename);
bool saveSvgShape(const Shape &shape, const Shape::Bounds &bounds, const char *filename);

}
2 changes: 2 additions & 0 deletions core/save-bmp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
#ifdef MSDFGEN_USE_CPP11
#include <cstdint>
#else
namespace msdfgen {
typedef int int32_t;
typedef unsigned uint32_t;
typedef unsigned short uint16_t;
typedef unsigned char uint8_t;
}
#endif

#include "pixel-conversion.hpp"
Expand Down
39 changes: 39 additions & 0 deletions core/save-fl32.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

#include "save-fl32.h"

#include <cstdio>

namespace msdfgen {

// Requires byte reversal for floats on big-endian platform
#ifndef __BIG_ENDIAN__

template <int N>
bool saveFl32(const BitmapConstRef<float, N> &bitmap, const char *filename) {
if (FILE *f = fopen(filename, "wb")) {
byte header[16] = { byte('F'), byte('L'), byte('3'), byte('2') };
header[4] = byte(bitmap.height);
header[5] = byte(bitmap.height>>8);
header[6] = byte(bitmap.height>>16);
header[7] = byte(bitmap.height>>24);
header[8] = byte(bitmap.width);
header[9] = byte(bitmap.width>>8);
header[10] = byte(bitmap.width>>16);
header[11] = byte(bitmap.width>>24);
header[12] = byte(N);
fwrite(header, 1, 16, f);
fwrite(bitmap.pixels, sizeof(float), N*bitmap.width*bitmap.height, f);
fclose(f);
return true;
}
return false;
}

template bool saveFl32(const BitmapConstRef<float, 1> &bitmap, const char *filename);
template bool saveFl32(const BitmapConstRef<float, 2> &bitmap, const char *filename);
template bool saveFl32(const BitmapConstRef<float, 3> &bitmap, const char *filename);
template bool saveFl32(const BitmapConstRef<float, 4> &bitmap, const char *filename);

#endif

}
12 changes: 12 additions & 0 deletions core/save-fl32.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

#pragma once

#include "BitmapRef.hpp"

namespace msdfgen {

/// Saves the bitmap as an uncompressed floating-point FL32 file, which can be decoded trivially.
template <int N>
bool saveFl32(const BitmapConstRef<float, N> &bitmap, const char *filename);

}
133 changes: 133 additions & 0 deletions core/save-rgba.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@

#include "save-rgba.h"

#include <cstdio>
#include "pixel-conversion.hpp"

namespace msdfgen {

class RgbaFileOutput {
FILE *file;

public:
RgbaFileOutput(const char *filename, unsigned width, unsigned height) {
if ((file = fopen(filename, "wb"))) {
byte header[12] = { byte('R'), byte('G'), byte('B'), byte('A') };
header[4] = byte(width>>24);
header[5] = byte(width>>16);
header[6] = byte(width>>8);
header[7] = byte(width);
header[8] = byte(height>>24);
header[9] = byte(height>>16);
header[10] = byte(height>>8);
header[11] = byte(height);
fwrite(header, 1, 12, file);
}
}

~RgbaFileOutput() {
if (file)
fclose(file);
}

void writePixel(const byte rgba[4]) {
fwrite(rgba, 1, 4, file);
}

operator FILE *() {
return file;
}

};

bool saveRgba(const BitmapConstRef<byte, 1> &bitmap, const char *filename) {
RgbaFileOutput output(filename, bitmap.width, bitmap.height);
if (output) {
byte rgba[4] = { byte(0), byte(0), byte(0), byte(0xff) };
for (int y = bitmap.height; y--;) {
for (const byte *p = bitmap(0, y), *end = p+bitmap.width; p < end; ++p) {
rgba[0] = rgba[1] = rgba[2] = *p;
output.writePixel(rgba);
}
}
return true;
}
return false;
}

bool saveRgba(const BitmapConstRef<byte, 3> &bitmap, const char *filename) {
RgbaFileOutput output(filename, bitmap.width, bitmap.height);
if (output) {
byte rgba[4] = { byte(0), byte(0), byte(0), byte(0xff) };
for (int y = bitmap.height; y--;) {
for (const byte *p = bitmap(0, y), *end = p+3*bitmap.width; p < end; p += 3) {
rgba[0] = p[0], rgba[1] = p[1], rgba[2] = p[2];
output.writePixel(rgba);
}
}
return true;
}
return false;
}

bool saveRgba(const BitmapConstRef<byte, 4> &bitmap, const char *filename) {
RgbaFileOutput output(filename, bitmap.width, bitmap.height);
if (output) {
for (int y = bitmap.height; y--;)
fwrite(bitmap(0, y), 1, 4*bitmap.width, output);
return true;
}
return false;
}

bool saveRgba(const BitmapConstRef<float, 1> &bitmap, const char *filename) {
RgbaFileOutput output(filename, bitmap.width, bitmap.height);
if (output) {
byte rgba[4] = { byte(0), byte(0), byte(0), byte(0xff) };
for (int y = bitmap.height; y--;) {
for (const float *p = bitmap(0, y), *end = p+bitmap.width; p < end; ++p) {
rgba[0] = rgba[1] = rgba[2] = pixelFloatToByte(*p);
output.writePixel(rgba);
}
}
return true;
}
return false;
}

bool saveRgba(const BitmapConstRef<float, 3> &bitmap, const char *filename) {
RgbaFileOutput output(filename, bitmap.width, bitmap.height);
if (output) {
byte rgba[4] = { byte(0), byte(0), byte(0), byte(0xff) };
for (int y = bitmap.height; y--;) {
for (const float *p = bitmap(0, y), *end = p+3*bitmap.width; p < end; p += 3) {
rgba[0] = pixelFloatToByte(p[0]);
rgba[1] = pixelFloatToByte(p[1]);
rgba[2] = pixelFloatToByte(p[2]);
output.writePixel(rgba);
}
}
return true;
}
return false;
}

bool saveRgba(const BitmapConstRef<float, 4> &bitmap, const char *filename) {
RgbaFileOutput output(filename, bitmap.width, bitmap.height);
if (output) {
byte rgba[4];
for (int y = bitmap.height; y--;) {
for (const float *p = bitmap(0, y), *end = p+4*bitmap.width; p < end; p += 4) {
rgba[0] = pixelFloatToByte(p[0]);
rgba[1] = pixelFloatToByte(p[1]);
rgba[2] = pixelFloatToByte(p[2]);
rgba[3] = pixelFloatToByte(p[3]);
output.writePixel(rgba);
}
}
return true;
}
return false;
}

}
16 changes: 16 additions & 0 deletions core/save-rgba.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

#pragma once

#include "BitmapRef.hpp"

namespace msdfgen {

/// Saves the bitmap as a simple RGBA file, which can be decoded trivially.
bool saveRgba(const BitmapConstRef<byte, 1> &bitmap, const char *filename);
bool saveRgba(const BitmapConstRef<byte, 3> &bitmap, const char *filename);
bool saveRgba(const BitmapConstRef<byte, 4> &bitmap, const char *filename);
bool saveRgba(const BitmapConstRef<float, 1> &bitmap, const char *filename);
bool saveRgba(const BitmapConstRef<float, 3> &bitmap, const char *filename);
bool saveRgba(const BitmapConstRef<float, 4> &bitmap, const char *filename);

}
2 changes: 2 additions & 0 deletions core/save-tiff.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
#ifdef MSDFGEN_USE_CPP11
#include <cstdint>
#else
namespace msdfgen {
typedef int int32_t;
typedef unsigned uint32_t;
typedef unsigned short uint16_t;
typedef unsigned char uint8_t;
}
#endif

namespace msdfgen {
Expand Down
Loading

0 comments on commit aa9478e

Please sign in to comment.