TIFF file support

This commit is contained in:
Viktor Chlumský 2019-04-21 00:27:28 +02:00
parent 997e42f734
commit f0b8f556d2
6 changed files with 218 additions and 1 deletions

View File

@ -305,6 +305,7 @@
<ClInclude Include="core\rasterization.h" /> <ClInclude Include="core\rasterization.h" />
<ClInclude Include="core\render-sdf.h" /> <ClInclude Include="core\render-sdf.h" />
<ClInclude Include="core\save-bmp.h" /> <ClInclude Include="core\save-bmp.h" />
<ClInclude Include="core\save-tiff.h" />
<ClInclude Include="core\Scanline.h" /> <ClInclude Include="core\Scanline.h" />
<ClInclude Include="core\shape-description.h" /> <ClInclude Include="core\shape-description.h" />
<ClInclude Include="core\Shape.h" /> <ClInclude Include="core\Shape.h" />
@ -328,6 +329,7 @@
<ClCompile Include="core\rasterization.cpp" /> <ClCompile Include="core\rasterization.cpp" />
<ClCompile Include="core\render-sdf.cpp" /> <ClCompile Include="core\render-sdf.cpp" />
<ClCompile Include="core\save-bmp.cpp" /> <ClCompile Include="core\save-bmp.cpp" />
<ClCompile Include="core\save-tiff.cpp" />
<ClCompile Include="core\Scanline.cpp" /> <ClCompile Include="core\Scanline.cpp" />
<ClCompile Include="core\shape-description.cpp" /> <ClCompile Include="core\shape-description.cpp" />
<ClCompile Include="core\Shape.cpp" /> <ClCompile Include="core\Shape.cpp" />

View File

@ -99,6 +99,9 @@
<ClInclude Include="core\pixel-conversion.hpp"> <ClInclude Include="core\pixel-conversion.hpp">
<Filter>Core</Filter> <Filter>Core</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="core\save-tiff.h">
<Filter>Core</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="main.cpp"> <ClCompile Include="main.cpp">
@ -167,6 +170,9 @@
<ClCompile Include="core\rasterization.cpp"> <ClCompile Include="core\rasterization.cpp">
<Filter>Core</Filter> <Filter>Core</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="core\save-tiff.cpp">
<Filter>Core</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="Msdfgen.rc"> <ResourceCompile Include="Msdfgen.rc">

192
core/save-tiff.cpp Normal file
View File

@ -0,0 +1,192 @@
#define _CRT_SECURE_NO_WARNINGS
#include "save-tiff.h"
#include <cstdio>
#ifdef MSDFGEN_USE_CPP11
#include <cstdint>
#else
typedef int int32_t;
typedef unsigned uint32_t;
typedef unsigned short uint16_t;
typedef unsigned char uint8_t;
#endif
namespace msdfgen {
template <typename T>
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<uint16_t>(file, 0x4d4du);
#else
writeValue<uint16_t>(file, 0x4949u);
#endif
writeValue<uint16_t>(file, 42);
writeValue<uint32_t>(file, 0x0008u); // Offset of first IFD
// Offset = 0x0008
writeValue<uint16_t>(file, 15); // Number of IFD entries
// ImageWidth
writeValue<uint16_t>(file, 0x0100u);
writeValue<uint16_t>(file, 0x0004u);
writeValue<uint32_t>(file, 1);
writeValue<int32_t>(file, width);
// ImageLength
writeValue<uint16_t>(file, 0x0101u);
writeValue<uint16_t>(file, 0x0004u);
writeValue<uint32_t>(file, 1);
writeValue<int32_t>(file, height);
// BitsPerSample
writeValue<uint16_t>(file, 0x0102u);
writeValue<uint16_t>(file, 0x0003u);
writeValue<uint32_t>(file, channels);
if (channels == 3)
writeValue<uint32_t>(file, 0x00c2u); // Offset of 32, 32, 32
else {
writeValue<uint16_t>(file, 32);
writeValue<uint16_t>(file, 0);
}
// Compression
writeValue<uint16_t>(file, 0x0103u);
writeValue<uint16_t>(file, 0x0003u);
writeValue<uint32_t>(file, 1);
writeValue<uint16_t>(file, 1);
writeValue<uint16_t>(file, 0);
// PhotometricInterpretation
writeValue<uint16_t>(file, 0x0106u);
writeValue<uint16_t>(file, 0x0003u);
writeValue<uint32_t>(file, 1);
writeValue<uint16_t>(file, channels == 3 ? 2 : 1);
writeValue<uint16_t>(file, 0);
// StripOffsets
writeValue<uint16_t>(file, 0x0111u);
writeValue<uint16_t>(file, 0x0004u);
writeValue<uint32_t>(file, 1);
writeValue<uint32_t>(file, channels == 3 ? 0x00f6u : 0x00d2u); // Offset of pixel data
// SamplesPerPixel
writeValue<uint16_t>(file, 0x0115u);
writeValue<uint16_t>(file, 0x0003u);
writeValue<uint32_t>(file, 1);
writeValue<uint16_t>(file, channels);
writeValue<uint16_t>(file, 0);
// RowsPerStrip
writeValue<uint16_t>(file, 0x0116u);
writeValue<uint16_t>(file, 0x0004u);
writeValue<uint32_t>(file, 1);
writeValue<int32_t>(file, height);
// StripByteCounts
writeValue<uint16_t>(file, 0x0117u);
writeValue<uint16_t>(file, 0x0004u);
writeValue<uint32_t>(file, 1);
writeValue<int32_t>(file, sizeof(float)*channels*width*height);
// XResolution
writeValue<uint16_t>(file, 0x011au);
writeValue<uint16_t>(file, 0x0005u);
writeValue<uint32_t>(file, 1);
writeValue<uint32_t>(file, channels == 3 ? 0x00c8u : 0x00c2u); // Offset of 300, 1
// YResolution
writeValue<uint16_t>(file, 0x011bu);
writeValue<uint16_t>(file, 0x0005u);
writeValue<uint32_t>(file, 1);
writeValue<uint32_t>(file, channels == 3 ? 0x00d0u : 0x00cau); // Offset of 300, 1
// ResolutionUnit
writeValue<uint16_t>(file, 0x0128u);
writeValue<uint16_t>(file, 0x0003u);
writeValue<uint32_t>(file, 1);
writeValue<uint16_t>(file, 2);
writeValue<uint16_t>(file, 0);
// SampleFormat
writeValue<uint16_t>(file, 0x0153u);
writeValue<uint16_t>(file, 0x0003u);
writeValue<uint32_t>(file, channels);
if (channels == 3)
writeValue<uint32_t>(file, 0x00d8u); // Offset of 3, 3, 3
else {
writeValue<uint16_t>(file, 3);
writeValue<uint16_t>(file, 0);
}
// SMinSampleValue
writeValue<uint16_t>(file, 0x0154u);
writeValue<uint16_t>(file, 0x000bu);
writeValue<uint32_t>(file, channels);
if (channels == 3)
writeValue<uint32_t>(file, 0x00deu); // Offset of 0.f, 0.f, 0.f
else
writeValue<float>(file, 0.f);
// SMaxSampleValue
writeValue<uint16_t>(file, 0x0155u);
writeValue<uint16_t>(file, 0x000bu);
writeValue<uint32_t>(file, channels);
if (channels == 3)
writeValue<uint32_t>(file, 0x00eau); // Offset of 1.f, 1.f, 1.f
else
writeValue<float>(file, 1.f);
// Offset = 0x00be
writeValue<uint32_t>(file, 0);
if (channels == 3) {
// 0x00c2 BitsPerSample data
writeValue<uint16_t>(file, 32);
writeValue<uint16_t>(file, 32);
writeValue<uint16_t>(file, 32);
// 0x00c8 XResolution data
writeValue<uint32_t>(file, 300);
writeValue<uint32_t>(file, 1);
// 0x00d0 YResolution data
writeValue<uint32_t>(file, 300);
writeValue<uint32_t>(file, 1);
// 0x00d8 SampleFormat data
writeValue<uint16_t>(file, 3);
writeValue<uint16_t>(file, 3);
writeValue<uint16_t>(file, 3);
// 0x00de SMinSampleValue data
writeValue<float>(file, 0.f);
writeValue<float>(file, 0.f);
writeValue<float>(file, 0.f);
// 0x00ea SMaxSampleValue data
writeValue<float>(file, 1.f);
writeValue<float>(file, 1.f);
writeValue<float>(file, 1.f);
// Offset = 0x00f6
} else {
// 0x00c2 XResolution data
writeValue<uint32_t>(file, 300);
writeValue<uint32_t>(file, 1);
// 0x00ca YResolution data
writeValue<uint32_t>(file, 300);
writeValue<uint32_t>(file, 1);
// Offset = 0x00d2
}
return true;
}
bool saveTiff(const BitmapConstRef<float, 1> &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<float, 3> &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);
}
}

12
core/save-tiff.h Normal file
View File

@ -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<float, 1> &bitmap, const char *filename);
bool saveTiff(const BitmapConstRef<float, 3> &bitmap, const char *filename);
}

View File

@ -28,6 +28,7 @@ enum Format {
AUTO, AUTO,
PNG, PNG,
BMP, BMP,
TIFF,
TEXT, TEXT,
TEXT_FLOAT, TEXT_FLOAT,
BINARY, BINARY,
@ -203,6 +204,7 @@ static const char * writeOutput(const BitmapConstRef<float, N> &bitmap, const ch
if (format == AUTO) { if (format == AUTO) {
if (cmpExtension(filename, ".png")) format = PNG; if (cmpExtension(filename, ".png")) format = PNG;
else if (cmpExtension(filename, ".bmp")) format = BMP; 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, ".txt")) format = TEXT;
else if (cmpExtension(filename, ".bin")) format = BINARY; else if (cmpExtension(filename, ".bin")) format = BINARY;
else else
@ -211,6 +213,7 @@ static const char * writeOutput(const BitmapConstRef<float, N> &bitmap, const ch
switch (format) { switch (format) {
case PNG: return savePng(bitmap, filename) ? NULL : "Failed to write output PNG image."; 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 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: { case TEXT: case TEXT_FLOAT: {
FILE *file = fopen(filename, "w"); FILE *file = fopen(filename, "w");
if (!file) return "Failed to write output text file."; 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" "\tSaves the shape description into a text file that can be edited and loaded using -shapedesc.\n"
" -fillrule <nonzero / evenodd / positive / negative>\n" " -fillrule <nonzero / evenodd / positive / negative>\n"
"\tSets the fill rule for the scanline pass. Default is nonzero.\n" "\tSets the fill rule for the scanline pass. Default is nonzero.\n"
" -format <png / bmp / text / textfloat / bin / binfloat / binfloatbe>\n" " -format <png / bmp / tiff / text / textfloat / bin / binfloat / binfloatbe>\n"
"\tSpecifies the output format of the distance field. Otherwise it is chosen based on output file extension.\n" "\tSpecifies the output format of the distance field. Otherwise it is chosen based on output file extension.\n"
" -guessorder\n" " -guessorder\n"
"\tAttempts to detect if shape contours have the wrong winding and generates the SDF with the right one.\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; 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], "png")) SET_FORMAT(PNG, "png");
else if (!strcmp(argv[argPos+1], "bmp")) SET_FORMAT(BMP, "bmp"); 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], "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], "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");

View File

@ -24,6 +24,7 @@
#include "core/render-sdf.h" #include "core/render-sdf.h"
#include "core/rasterization.h" #include "core/rasterization.h"
#include "core/save-bmp.h" #include "core/save-bmp.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.6"