diff --git a/Msdfgen.vcxproj b/Msdfgen.vcxproj
index 7c9e65a..63f58ee 100644
--- a/Msdfgen.vcxproj
+++ b/Msdfgen.vcxproj
@@ -305,6 +305,7 @@
+
@@ -328,6 +329,7 @@
+
diff --git a/Msdfgen.vcxproj.filters b/Msdfgen.vcxproj.filters
index 86d5a29..fe3e3bf 100644
--- a/Msdfgen.vcxproj.filters
+++ b/Msdfgen.vcxproj.filters
@@ -99,6 +99,9 @@
Core
+
+ Core
+
@@ -167,6 +170,9 @@
Core
+
+ Core
+
diff --git a/core/save-tiff.cpp b/core/save-tiff.cpp
new file mode 100644
index 0000000..441d069
--- /dev/null
+++ b/core/save-tiff.cpp
@@ -0,0 +1,192 @@
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#include "save-tiff.h"
+
+#include
+
+#ifdef MSDFGEN_USE_CPP11
+ #include
+#else
+ typedef int int32_t;
+ typedef unsigned uint32_t;
+ typedef unsigned short uint16_t;
+ typedef unsigned char uint8_t;
+#endif
+
+namespace msdfgen {
+
+template
+static bool writeValue(FILE *file, T value) {
+ return fwrite(&value, sizeof(T), 1, file) == 1;
+}
+
+static bool writeTiffHeader(FILE *file, int width, int height, int channels) {
+ #ifdef __BIG_ENDIAN__
+ writeValue(file, 0x4d4du);
+ #else
+ writeValue(file, 0x4949u);
+ #endif
+ writeValue(file, 42);
+ writeValue(file, 0x0008u); // Offset of first IFD
+ // Offset = 0x0008
+
+ writeValue(file, 15); // Number of IFD entries
+
+ // ImageWidth
+ writeValue(file, 0x0100u);
+ writeValue(file, 0x0004u);
+ writeValue(file, 1);
+ writeValue(file, width);
+ // ImageLength
+ writeValue(file, 0x0101u);
+ writeValue(file, 0x0004u);
+ writeValue(file, 1);
+ writeValue(file, height);
+ // BitsPerSample
+ writeValue(file, 0x0102u);
+ writeValue(file, 0x0003u);
+ writeValue(file, channels);
+ if (channels == 3)
+ writeValue(file, 0x00c2u); // Offset of 32, 32, 32
+ else {
+ writeValue(file, 32);
+ writeValue(file, 0);
+ }
+ // Compression
+ writeValue(file, 0x0103u);
+ writeValue(file, 0x0003u);
+ writeValue(file, 1);
+ writeValue(file, 1);
+ writeValue(file, 0);
+ // PhotometricInterpretation
+ writeValue(file, 0x0106u);
+ writeValue(file, 0x0003u);
+ writeValue(file, 1);
+ writeValue(file, channels == 3 ? 2 : 1);
+ writeValue(file, 0);
+ // StripOffsets
+ writeValue(file, 0x0111u);
+ writeValue(file, 0x0004u);
+ writeValue(file, 1);
+ writeValue(file, channels == 3 ? 0x00f6u : 0x00d2u); // Offset of pixel data
+ // SamplesPerPixel
+ writeValue(file, 0x0115u);
+ writeValue(file, 0x0003u);
+ writeValue(file, 1);
+ writeValue(file, channels);
+ writeValue(file, 0);
+ // RowsPerStrip
+ writeValue(file, 0x0116u);
+ writeValue(file, 0x0004u);
+ writeValue(file, 1);
+ writeValue(file, height);
+ // StripByteCounts
+ writeValue(file, 0x0117u);
+ writeValue(file, 0x0004u);
+ writeValue(file, 1);
+ writeValue(file, sizeof(float)*channels*width*height);
+ // XResolution
+ writeValue(file, 0x011au);
+ writeValue(file, 0x0005u);
+ writeValue(file, 1);
+ writeValue(file, channels == 3 ? 0x00c8u : 0x00c2u); // Offset of 300, 1
+ // YResolution
+ writeValue(file, 0x011bu);
+ writeValue(file, 0x0005u);
+ writeValue(file, 1);
+ writeValue(file, channels == 3 ? 0x00d0u : 0x00cau); // Offset of 300, 1
+ // ResolutionUnit
+ writeValue(file, 0x0128u);
+ writeValue(file, 0x0003u);
+ writeValue(file, 1);
+ writeValue(file, 2);
+ writeValue(file, 0);
+ // SampleFormat
+ writeValue(file, 0x0153u);
+ writeValue(file, 0x0003u);
+ writeValue(file, channels);
+ if (channels == 3)
+ writeValue(file, 0x00d8u); // Offset of 3, 3, 3
+ else {
+ writeValue(file, 3);
+ writeValue(file, 0);
+ }
+ // SMinSampleValue
+ writeValue(file, 0x0154u);
+ writeValue(file, 0x000bu);
+ writeValue(file, channels);
+ if (channels == 3)
+ writeValue(file, 0x00deu); // Offset of 0.f, 0.f, 0.f
+ else
+ writeValue(file, 0.f);
+ // SMaxSampleValue
+ writeValue(file, 0x0155u);
+ writeValue(file, 0x000bu);
+ writeValue(file, channels);
+ if (channels == 3)
+ writeValue(file, 0x00eau); // Offset of 1.f, 1.f, 1.f
+ else
+ writeValue(file, 1.f);
+ // Offset = 0x00be
+
+ writeValue(file, 0);
+
+ if (channels == 3) {
+ // 0x00c2 BitsPerSample data
+ writeValue(file, 32);
+ writeValue(file, 32);
+ writeValue(file, 32);
+ // 0x00c8 XResolution data
+ writeValue(file, 300);
+ writeValue(file, 1);
+ // 0x00d0 YResolution data
+ writeValue(file, 300);
+ writeValue(file, 1);
+ // 0x00d8 SampleFormat data
+ writeValue(file, 3);
+ writeValue(file, 3);
+ writeValue(file, 3);
+ // 0x00de SMinSampleValue data
+ writeValue(file, 0.f);
+ writeValue(file, 0.f);
+ writeValue(file, 0.f);
+ // 0x00ea SMaxSampleValue data
+ writeValue(file, 1.f);
+ writeValue(file, 1.f);
+ writeValue(file, 1.f);
+ // Offset = 0x00f6
+ } else {
+ // 0x00c2 XResolution data
+ writeValue(file, 300);
+ writeValue(file, 1);
+ // 0x00ca YResolution data
+ writeValue(file, 300);
+ writeValue(file, 1);
+ // Offset = 0x00d2
+ }
+
+ return true;
+}
+
+bool saveTiff(const BitmapConstRef &bitmap, const char *filename) {
+ FILE *file = fopen(filename, "wb");
+ if (!file)
+ return false;
+ writeTiffHeader(file, bitmap.width, bitmap.height, 1);
+ for (int y = bitmap.height-1; y >= 0; --y)
+ fwrite(bitmap(0, y), sizeof(float), bitmap.width, file);
+ return !fclose(file);
+}
+
+bool saveTiff(const BitmapConstRef &bitmap, const char *filename) {
+ FILE *file = fopen(filename, "wb");
+ if (!file)
+ return false;
+ writeTiffHeader(file, bitmap.width, bitmap.height, 3);
+ for (int y = bitmap.height-1; y >= 0; --y)
+ fwrite(bitmap(0, y), sizeof(float), 3*bitmap.width, file);
+ return !fclose(file);
+}
+
+}
diff --git a/core/save-tiff.h b/core/save-tiff.h
new file mode 100644
index 0000000..f3c7e27
--- /dev/null
+++ b/core/save-tiff.h
@@ -0,0 +1,12 @@
+
+#pragma once
+
+#include "BitmapRef.hpp"
+
+namespace msdfgen {
+
+/// Saves the bitmap as an uncompressed floating-point TIFF file.
+bool saveTiff(const BitmapConstRef &bitmap, const char *filename);
+bool saveTiff(const BitmapConstRef &bitmap, const char *filename);
+
+}
diff --git a/main.cpp b/main.cpp
index 5c4da3c..9f2aeed 100644
--- a/main.cpp
+++ b/main.cpp
@@ -28,6 +28,7 @@ enum Format {
AUTO,
PNG,
BMP,
+ TIFF,
TEXT,
TEXT_FLOAT,
BINARY,
@@ -203,6 +204,7 @@ static const char * writeOutput(const BitmapConstRef &bitmap, const ch
if (format == AUTO) {
if (cmpExtension(filename, ".png")) format = PNG;
else if (cmpExtension(filename, ".bmp")) format = BMP;
+ else if (cmpExtension(filename, ".tif") || cmpExtension(filename, ".tiff")) format = TIFF;
else if (cmpExtension(filename, ".txt")) format = TEXT;
else if (cmpExtension(filename, ".bin")) format = BINARY;
else
@@ -211,6 +213,7 @@ static const char * writeOutput(const BitmapConstRef &bitmap, const ch
switch (format) {
case PNG: return savePng(bitmap, filename) ? NULL : "Failed to write output PNG image.";
case BMP: return saveBmp(bitmap, filename) ? NULL : "Failed to write output BMP image.";
+ case TIFF: return saveTiff(bitmap, filename) ? NULL : "Failed to write output BMP image.";
case TEXT: case TEXT_FLOAT: {
FILE *file = fopen(filename, "w");
if (!file) return "Failed to write output text file.";
@@ -289,7 +292,7 @@ static const char *helpText =
"\tSaves the shape description into a text file that can be edited and loaded using -shapedesc.\n"
" -fillrule \n"
"\tSets the fill rule for the scanline pass. Default is nonzero.\n"
- " -format \n"
+ " -format \n"
"\tSpecifies the output format of the distance field. Otherwise it is chosen based on output file extension.\n"
" -guessorder\n"
"\tAttempts to detect if shape contours have the wrong winding and generates the SDF with the right one.\n"
@@ -477,6 +480,7 @@ int main(int argc, const char * const *argv) {
if (!strcmp(argv[argPos+1], "auto")) format = AUTO;
else if (!strcmp(argv[argPos+1], "png")) SET_FORMAT(PNG, "png");
else if (!strcmp(argv[argPos+1], "bmp")) SET_FORMAT(BMP, "bmp");
+ else if (!strcmp(argv[argPos+1], "tiff")) SET_FORMAT(TIFF, "tif");
else if (!strcmp(argv[argPos+1], "text") || !strcmp(argv[argPos+1], "txt")) SET_FORMAT(TEXT, "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");
diff --git a/msdfgen.h b/msdfgen.h
index f41fc16..8f201f8 100644
--- a/msdfgen.h
+++ b/msdfgen.h
@@ -24,6 +24,7 @@
#include "core/render-sdf.h"
#include "core/rasterization.h"
#include "core/save-bmp.h"
+#include "core/save-tiff.h"
#include "core/shape-description.h"
#define MSDFGEN_VERSION "1.6"