Browse Source

TIFF file support

Viktor Chlumský 6 years ago
parent
commit
f0b8f556d2
6 changed files with 218 additions and 1 deletions
  1. 2 0
      Msdfgen.vcxproj
  2. 6 0
      Msdfgen.vcxproj.filters
  3. 192 0
      core/save-tiff.cpp
  4. 12 0
      core/save-tiff.h
  5. 5 1
      main.cpp
  6. 1 0
      msdfgen.h

+ 2 - 0
Msdfgen.vcxproj

@@ -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" />

+ 6 - 0
Msdfgen.vcxproj.filters

@@ -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 - 0
core/save-tiff.cpp

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

+ 5 - 1
main.cpp

@@ -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");

+ 1 - 0
msdfgen.h

@@ -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"