mirror of
				https://github.com/godotengine/godot.git
				synced 2025-10-31 13:41:03 +00:00 
			
		
		
		
	
		
			
	
	
		
			191 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			191 lines
		
	
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|   | 
 | ||
|  | #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; | ||
|  | } | ||
|  | template <typename T> | ||
|  | static void writeValueRepeated(FILE *file, T value, int times) { | ||
|  |     for (int i = 0; i < times; ++i) | ||
|  |         writeValue(file, value); | ||
|  | } | ||
|  | 
 | ||
|  | 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 > 1) | ||
|  |         writeValue<uint32_t>(file, 0x00c2u); // Offset of 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, 0x00d2u+(channels > 1)*channels*12); // 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, 0x00c2u+(channels > 1)*channels*2); // Offset of 300, 1
 | ||
|  |     // YResolution
 | ||
|  |     writeValue<uint16_t>(file, 0x011bu); | ||
|  |     writeValue<uint16_t>(file, 0x0005u); | ||
|  |     writeValue<uint32_t>(file, 1); | ||
|  |     writeValue<uint32_t>(file, 0x00cau+(channels > 1)*channels*2); // 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 > 1) | ||
|  |         writeValue<uint32_t>(file, 0x00d2u+channels*2); // Offset of 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 > 1) | ||
|  |         writeValue<uint32_t>(file, 0x00d2u+channels*4); // Offset of 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 > 1) | ||
|  |         writeValue<uint32_t>(file, 0x00d2u+channels*8); // Offset of 1.f, 1.f, ...
 | ||
|  |     else | ||
|  |         writeValue<float>(file, 1.f); | ||
|  |     // Offset = 0x00be
 | ||
|  | 
 | ||
|  |     writeValue<uint32_t>(file, 0); | ||
|  | 
 | ||
|  |     if (channels > 1) { | ||
|  |         // 0x00c2 BitsPerSample data
 | ||
|  |         writeValueRepeated<uint16_t>(file, 32, channels); | ||
|  |         // 0x00c2 + 2*N XResolution data
 | ||
|  |         writeValue<uint32_t>(file, 300); | ||
|  |         writeValue<uint32_t>(file, 1); | ||
|  |         // 0x00ca + 2*N YResolution data
 | ||
|  |         writeValue<uint32_t>(file, 300); | ||
|  |         writeValue<uint32_t>(file, 1); | ||
|  |         // 0x00d2 + 2*N SampleFormat data
 | ||
|  |         writeValueRepeated<uint16_t>(file, 3, channels); | ||
|  |         // 0x00d2 + 4*N SMinSampleValue data
 | ||
|  |         writeValueRepeated<float>(file, 0.f, channels); | ||
|  |         // 0x00d2 + 8*N SMaxSampleValue data
 | ||
|  |         writeValueRepeated<float>(file, 1.f, channels); | ||
|  |         // Offset = 0x00d2 + 12*N
 | ||
|  |     } 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; | ||
|  | } | ||
|  | 
 | ||
|  | template <int N> | ||
|  | bool saveTiffFloat(const BitmapConstRef<float, N> &bitmap, const char *filename) { | ||
|  |     FILE *file = fopen(filename, "wb"); | ||
|  |     if (!file) | ||
|  |         return false; | ||
|  |     writeTiffHeader(file, bitmap.width, bitmap.height, N); | ||
|  |     for (int y = bitmap.height-1; y >= 0; --y) | ||
|  |         fwrite(bitmap(0, y), sizeof(float), N*bitmap.width, file); | ||
|  |     return !fclose(file); | ||
|  | } | ||
|  | 
 | ||
|  | bool saveTiff(const BitmapConstRef<float, 1> &bitmap, const char *filename) { | ||
|  |     return saveTiffFloat(bitmap, filename); | ||
|  | } | ||
|  | bool saveTiff(const BitmapConstRef<float, 3> &bitmap, const char *filename) { | ||
|  |     return saveTiffFloat(bitmap, filename); | ||
|  | } | ||
|  | bool saveTiff(const BitmapConstRef<float, 4> &bitmap, const char *filename) { | ||
|  |     return saveTiffFloat(bitmap, filename); | ||
|  | } | ||
|  | 
 | ||
|  | } |