浏览代码

Add private MP_* fields for extra data not in the DNG spec

There is no generic way to specify lens distortion and vignetting values. This defines the MP_VERSION, MP_DISTORTION and MP_VIGNETTE tiff tags in the private tag area for that data.
Martijn Braam 3 月之前
父节点
当前提交
bd4372559f
共有 4 个文件被更改,包括 120 次插入2 次删除
  1. 13 0
      include/libdng.h
  2. 10 1
      src/dng.h
  3. 63 0
      src/libdng.c
  4. 34 1
      tests/check_dng.c

+ 13 - 0
include/libdng.h

@@ -47,6 +47,13 @@ typedef struct {
 		bool needs_repack;
 		uint32_t width;
 		uint32_t height;
+
+		float distortion_a;
+		float distortion_b;
+		float distortion_c;
+		float vignette_k1;
+		float vignette_k2;
+		float vignette_k3;
 } libdng_info;
 
 #define LIBDNG_ORIENTATION_TOPLEFT 1
@@ -147,6 +154,12 @@ libdng_set_focal_length(libdng_info *dng, float focal_length, float crop_factor)
 EXPORT int
 libdng_set_frame_rate(libdng_info *dng, float framerate);
 
+EXPORT int
+libdng_set_distortion(libdng_info *dng, float a, float b, float c);
+
+EXPORT int
+libdng_set_vignette(libdng_info *dng, float k1, float k2, float k3);
+
 EXPORT int
 libdng_write(libdng_info *dng, const char *path, unsigned int width, unsigned int height, const uint8_t *data,
 	size_t length);

+ 10 - 1
src/dng.h

@@ -136,6 +136,12 @@
 #define DNGTAG_FRAMERATE 51044
 #define DNGTAG_TSTOP 51058
 
+// Custom tags
+
+#define MPTAG_VERSION 49982
+#define MPTAG_DISTORTION 49983
+#define MPTAG_VIGNETTE 49984
+
 /*
  * Field definitions for the tags in the DNG spec
  */
@@ -151,5 +157,8 @@ static const TIFFFieldInfo custom_dng_fields[] = {
 	{DNGTAG_CFAREPEATPATTERNDIM,        -1, -1, TIFF_SHORT,     FIELD_CUSTOM, 1, 1, "CFARepeatPatternDim"},
 	{DNGTAG_CFAPATTERN,                 -1, -1, TIFF_BYTE,      FIELD_CUSTOM, 1, 1, "CFAPattern"},
 	{DNGTAG_LINEARIZATIONTABLE,         -1, -1, TIFF_SHORT,     FIELD_CUSTOM, 1, 1, "LinearizationTable"},
-	{DNGTAG_FRAMERATE,                  -1,  -1,  TIFF_SRATIONAL, FIELD_CUSTOM, 1, 1, "FrameRate"},
+	{DNGTAG_FRAMERATE,                  -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, 1, 1, "FrameRate"},
+	{MPTAG_VERSION,                  -1,  -1,  TIFF_BYTE,     FIELD_CUSTOM, 1, 1, "MPVersion"},
+	{MPTAG_DISTORTION,                  3,  3,  TIFF_FLOAT,     FIELD_CUSTOM, 1, 0, "MPDistortion"},
+	{MPTAG_VIGNETTE,                    3,  3,  TIFF_FLOAT,     FIELD_CUSTOM, 1, 0, "MPVignette"},
 };

+ 63 - 0
src/libdng.c

@@ -9,6 +9,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <float.h>
 
 #define DNG_SUBFILETYPE_ORIGINAL 0
 #define DNG_SUBFILETYPE_THUMBNAIL 1
@@ -65,6 +66,13 @@ libdng_new(libdng_info *dng)
 	dng->crop_factor = 1.0f;
 	dng->focal_length = 0.0f;
 	dng->frame_rate = 0.0f;
+
+	dng->distortion_a = 0.0f;
+	dng->distortion_b = 0.0f;
+	dng->distortion_c = 0.0f;
+	dng->vignette_k1 = 0.0f;
+	dng->vignette_k2 = 0.0f;
+	dng->vignette_k3 = 0.0f;
 }
 
 int
@@ -268,6 +276,30 @@ libdng_set_frame_rate(libdng_info *dng, float framerate)
 	return 1;
 }
 
+int
+libdng_set_distortion(libdng_info *dng, float a, float b, float c)
+{
+	if (dng == NULL)
+		return 0;
+
+	dng->distortion_a = a;
+	dng->distortion_b = b;
+	dng->distortion_c = c;
+	return 1;
+}
+
+int
+libdng_set_vignette(libdng_info *dng, float k1, float k2, float k3)
+{
+	if (dng == NULL)
+		return 0;
+
+	dng->vignette_k1 = k1;
+	dng->vignette_k2 = k2;
+	dng->vignette_k3 = k3;
+	return 1;
+}
+
 int
 libdng_write(libdng_info *dng, const char *path, unsigned int width, unsigned int height, const uint8_t *data,
 	size_t length)
@@ -332,6 +364,18 @@ libdng_write_with_thumbnail(libdng_info *dng, const char *path, unsigned int wid
 		TIFFSetField(tif, TIFFTAG_DATETIME, datetime);
 	}
 
+	TIFFSetField(tif, MPTAG_VERSION, 4, "\1\0\0\0");
+
+	if (dng->distortion_a != 0.0f) {
+		float dist[] = {dng->distortion_a, dng->distortion_b, dng->distortion_c};
+		TIFFSetField(tif, MPTAG_DISTORTION, dist);
+	}
+
+	if (dng->vignette_k1 != 0.0f) {
+		float vign[] = {dng->vignette_k1, dng->vignette_k2, dng->vignette_k3};
+		TIFFSetField(tif, MPTAG_VIGNETTE, vign);
+	}
+
 	TIFFSetField(tif, DNGTAG_DNGVERSION, "\001\004\0\0");
 
 	char ucm[255];
@@ -508,6 +552,25 @@ libdng_read(libdng_info *dng, const char *path)
 			dng->forward_matrix_2[i] = fvalues[i];
 		}
 	}
+	uint8_t mptag_version = 0;
+	if (TIFFGetField(tif, MPTAG_VERSION, &count, &u8values) == 1) {
+		if (count == 4) {
+			mptag_version = u8values[0];
+		}
+	}
+	if (mptag_version == 1) {
+		if (TIFFGetField(tif, MPTAG_DISTORTION, &count, &fvalues) == 1) {
+			dng->distortion_a = fvalues[0];
+			dng->distortion_b = fvalues[1];
+			dng->distortion_c = fvalues[2];
+		}
+
+		if (TIFFGetField(tif, MPTAG_VIGNETTE, &count, &fvalues) == 1) {
+			dng->vignette_k1 = fvalues[0];
+			dng->vignette_k2 = fvalues[1];
+			dng->vignette_k3 = fvalues[2];
+		}
+	}
 
 	int subifd_count = 0;
 	void *ptr;

+ 34 - 1
tests/check_dng.c

@@ -49,6 +49,8 @@ TEST generate_simple_dng(void)
 		ASSERT_EQm("Set fnumber", 1, libdng_set_fnumber(&info, 2.8f));
 		ASSERT_EQm("Set fnumber", 1, libdng_set_focal_length(&info, 50.0f, 1.5f));
 		ASSERT_EQm("Set framerate", 1, libdng_set_frame_rate(&info, 30.0f));
+		ASSERT_EQm("Set distortion", 1, libdng_set_distortion(&info, 1.0f, 2.0f, 3.0f));
+		ASSERT_EQm("Set vignette", 1, libdng_set_vignette(&info, 1.0f, -1.0f, 6.0f));
 	uint8_t *data = malloc(1280 * 720);
 		ASSERT_EQm("Write DNG", 1, libdng_write(&info, "test.dng", 1280, 720, data, 1280 * 720));
 	free(data);
@@ -77,6 +79,37 @@ TEST generate_simple_dng(void)
 		CHECK_CALL(check_str_tag(im, TIFFTAG_SOFTWARE, "SOFTWARE", "Software"));
 		CHECK_CALL(check_int_tag(im, TIFFTAG_ORIENTATION, "ORIENTATION", 4));
 
+	// Check the custom tags
+#define MPTAG_VERSION 49982
+#define MPTAG_DISTORTION 49983
+#define MPTAG_VIGNETTE 49984
+	unsigned short count;
+	float *fvalues;
+	uint8_t *u8values;
+
+	if (TIFFGetField(im, MPTAG_VERSION, &count, &u8values) != 1) {
+			FAILm("Could not read MPTAG_VERSION");
+	}
+		ASSERT_EQ_FMTm("MPTAG_VERSION count", 4, count, "%d");
+		ASSERT_EQ_FMTm("MPTAG_VERSION[0]", 1, u8values[0], "%d");
+		ASSERT_EQ_FMTm("MPTAG_VERSION[1]", 0, u8values[1], "%d");
+		ASSERT_EQ_FMTm("MPTAG_VERSION[2]", 0, u8values[2], "%d");
+		ASSERT_EQ_FMTm("MPTAG_VERSION[3]", 0, u8values[3], "%d");
+
+	if (TIFFGetField(im, MPTAG_DISTORTION, &fvalues) != 1) {
+			FAILm("Could not read MPTAG_DISTORTION");
+	}
+		ASSERT_EQ_FMTm("MPTAG_DISTORTION[0]", 1.0f, fvalues[0], "%f");
+		ASSERT_EQ_FMTm("MPTAG_DISTORTION[1]", 2.0f, fvalues[1], "%f");
+		ASSERT_EQ_FMTm("MPTAG_DISTORTION[2]", 3.0f, fvalues[2], "%f");
+
+	if (TIFFGetField(im, MPTAG_VIGNETTE, &fvalues) != 1) {
+			FAILm("Could not read MPTAG_VIGNETTE");
+	}
+		ASSERT_EQ_FMTm("MPTAG_VIGNETTE[0]", 1.0f, fvalues[0], "%f");
+		ASSERT_EQ_FMTm("MPTAG_VIGNETTE[1]", -1.0f, fvalues[1], "%f");
+		ASSERT_EQ_FMTm("MPTAG_VIGNETTE[2]", 6.0f, fvalues[2], "%f");
+
 	// Switch to IFD1 which has the raw data
 	int subifd_count = 0;
 	void *ptr;
@@ -147,7 +180,7 @@ TEST read_dng(void)
 	char parsed[sizeof "2011-10-08T07:07:09Z"];
 	strftime(orig, sizeof orig, "%FT%TZ", &testtime);
 	strftime(parsed, sizeof parsed, "%FT%TZ", &dng.datetime);
-	ASSERT_STR_EQm("DateTime", orig, parsed);
+		ASSERT_STR_EQm("DateTime", orig, parsed);
 
 		ASSERT_EQm("Year", testtime.tm_year, dng.datetime.tm_year);
 		ASSERT_EQm("Month", testtime.tm_mon, dng.datetime.tm_mon);