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"