瀏覽代碼

Add the exposure time metadata

Martijn Braam 1 年之前
父節點
當前提交
680b260882
共有 6 個文件被更改,包括 58 次插入1 次删除
  1. 4 0
      include/libdng.h
  2. 3 0
      man/makedng.1.scd
  3. 20 0
      src/libdng.c
  4. 21 0
      tests/check_dng.c
  5. 1 0
      tests/test_dng_validate.sh
  6. 9 1
      util/makedng.c

+ 4 - 0
include/libdng.h

@@ -16,6 +16,7 @@ typedef struct {
 		uint16_t orientation;
 		uint16_t orientation;
 		struct tm datetime;
 		struct tm datetime;
 		uint16_t exposure_program;
 		uint16_t exposure_program;
+		float exposure_time;
 
 
 		// Raw image data
 		// Raw image data
 		uint16_t bayer_pattern_dimensions[2];
 		uint16_t bayer_pattern_dimensions[2];
@@ -124,6 +125,9 @@ libdng_load_calibration_file(libdng_info *dng, const char *path);
 EXPORT int
 EXPORT int
 libdng_set_exposure_program(libdng_info *dng, uint16_t mode);
 libdng_set_exposure_program(libdng_info *dng, uint16_t mode);
 
 
+EXPORT int
+libdng_set_exposure_time(libdng_info *dng, float seconds);
+
 EXPORT int
 EXPORT int
 libdng_write(libdng_info *dng, const char *path, unsigned int width, unsigned int height, const uint8_t *data,
 libdng_write(libdng_info *dng, const char *path, unsigned int width, unsigned int height, const uint8_t *data,
 	size_t length);
 	size_t length);

+ 3 - 0
man/makedng.1.scd

@@ -46,6 +46,9 @@ metadata to correctly render the file.
 *-e program*
 *-e program*
 	Set the exposure program in the EXIF data using one of the program numbers from the DNG spec.
 	Set the exposure program in the EXIF data using one of the program numbers from the DNG spec.
 
 
+*-t seconds*
+	Set the exposure time for the picture in seconds (eg. 0.01 for 1/100)
+
 # PIXEL FORMATS
 # PIXEL FORMATS
 
 
 The pixel format argument accepts the following values:
 The pixel format argument accepts the following values:

+ 20 - 0
src/libdng.c

@@ -57,6 +57,8 @@ libdng_new(libdng_info *dng)
 	dng->analogbalance[0] = 1.0f;
 	dng->analogbalance[0] = 1.0f;
 	dng->analogbalance[1] = 1.0f;
 	dng->analogbalance[1] = 1.0f;
 	dng->analogbalance[2] = 1.0f;
 	dng->analogbalance[2] = 1.0f;
+
+	dng->exposure_time = 0.0f;
 }
 }
 
 
 int
 int
@@ -197,6 +199,20 @@ libdng_set_exposure_program(libdng_info *dng, uint16_t mode)
 	return 1;
 	return 1;
 }
 }
 
 
+int
+libdng_set_exposure_time(libdng_info *dng, float seconds)
+{
+	if (dng == NULL)
+		return 0;
+
+	if (seconds < 0.0f)
+		return 0;
+
+	dng->exposure_time = seconds;
+	return 1;
+}
+
+
 int
 int
 libdng_write(libdng_info *dng, const char *path, unsigned int width, unsigned int height, const uint8_t *data,
 libdng_write(libdng_info *dng, const char *path, unsigned int width, unsigned int height, const uint8_t *data,
 	size_t length)
 	size_t length)
@@ -329,6 +345,10 @@ libdng_write_with_thumbnail(libdng_info *dng, const char *path, unsigned int wid
 
 
 	TIFFSetField(tif, EXIFTAG_EXPOSUREPROGRAM, dng->exposure_program);
 	TIFFSetField(tif, EXIFTAG_EXPOSUREPROGRAM, dng->exposure_program);
 
 
+	if (dng->exposure_time > 0) {
+		TIFFSetField(tif, EXIFTAG_EXPOSURETIME, dng->exposure_time);
+	}
+
 	uint64_t exif_offset = 0;
 	uint64_t exif_offset = 0;
 	if (!TIFFWriteCustomDirectory(tif, &exif_offset)) {
 	if (!TIFFWriteCustomDirectory(tif, &exif_offset)) {
 		fprintf(stderr, "Can't write EXIF\n");
 		fprintf(stderr, "Can't write EXIF\n");

+ 21 - 0
tests/check_dng.c

@@ -25,6 +25,17 @@ check_int_tag(TIFF *im, uint32_t tag, const char *name, int expected)
 		PASS();
 		PASS();
 }
 }
 
 
+static enum greatest_test_res
+check_float_tag(TIFF *im, uint32_t tag, const char *name, float expected)
+{
+	float temp;
+	if (TIFFGetField(im, tag, &temp) != 1) {
+			FAILm(name);
+	}
+		ASSERT_EQ_FMTm(name, expected, temp, "%f");
+		PASS();
+}
+
 
 
 TEST generate_simple_dng(void)
 TEST generate_simple_dng(void)
 {
 {
@@ -34,6 +45,7 @@ TEST generate_simple_dng(void)
 		ASSERT_EQm("Set make", 1, libdng_set_make_model(&info, "Make", "Model"));
 		ASSERT_EQm("Set make", 1, libdng_set_make_model(&info, "Make", "Model"));
 		ASSERT_EQm("Set software", 1, libdng_set_software(&info, "Software"));
 		ASSERT_EQm("Set software", 1, libdng_set_software(&info, "Software"));
 		ASSERT_EQm("Set orientation", 1, libdng_set_orientation(&info, 4));
 		ASSERT_EQm("Set orientation", 1, libdng_set_orientation(&info, 4));
+		ASSERT_EQm("Set exposuretime", 1, libdng_set_exposure_time(&info, 0.04f));
 	uint8_t *data = malloc(1280 * 720);
 	uint8_t *data = malloc(1280 * 720);
 		ASSERT_EQm("Write DNG", 1, libdng_write(&info, "test.dng", 1280, 720, data, 1280 * 720));
 		ASSERT_EQm("Write DNG", 1, libdng_write(&info, "test.dng", 1280, 720, data, 1280 * 720));
 	free(data);
 	free(data);
@@ -45,6 +57,11 @@ TEST generate_simple_dng(void)
 			FAILm("Could not open result");
 			FAILm("Could not open result");
 	}
 	}
 
 
+	toff_t exif_offset;
+	if (TIFFGetField(im, TIFFTAG_EXIFIFD, &exif_offset) != 1) {
+			FAILm("Could not find EXIF data");
+	}
+
 	// Check IFD0 with most metadata and the thumbnail image
 	// Check IFD0 with most metadata and the thumbnail image
 		CHECK_CALL(check_int_tag(im, TIFFTAG_ORIENTATION, "ORIENTATION", 4));
 		CHECK_CALL(check_int_tag(im, TIFFTAG_ORIENTATION, "ORIENTATION", 4));
 		CHECK_CALL(check_int_tag(im, TIFFTAG_BITSPERSAMPLE, "THUMB_BPS", 8));
 		CHECK_CALL(check_int_tag(im, TIFFTAG_BITSPERSAMPLE, "THUMB_BPS", 8));
@@ -72,6 +89,10 @@ TEST generate_simple_dng(void)
 		CHECK_CALL(check_int_tag(im, TIFFTAG_SAMPLESPERPIXEL, "RAW_CHANNELS", 1));
 		CHECK_CALL(check_int_tag(im, TIFFTAG_SAMPLESPERPIXEL, "RAW_CHANNELS", 1));
 		CHECK_CALL(check_int_tag(im, TIFFTAG_PHOTOMETRIC, "RAW_PHOTOMETRIC", PHOTOMETRIC_CFA));
 		CHECK_CALL(check_int_tag(im, TIFFTAG_PHOTOMETRIC, "RAW_PHOTOMETRIC", PHOTOMETRIC_CFA));
 
 
+	// Switch to the EXIF block with the generic picture metadata
+	TIFFReadEXIFDirectory(im, exif_offset);
+		CHECK_CALL(check_float_tag(im, EXIFTAG_EXPOSURETIME, "EXPOSURETIME", 0.04f));
+
 		PASS();
 		PASS();
 }
 }
 
 

+ 1 - 0
tests/test_dng_validate.sh

@@ -32,6 +32,7 @@ $makedng -w 1280 -h 720 -p RGGB \
   -n 0.1,0.2,0.3 \
   -n 0.1,0.2,0.3 \
   -b 0.4,0.5,0.6 \
   -b 0.4,0.5,0.6 \
   -e 2 \
   -e 2 \
+  -t 0.01 \
   scratch/data.rgb scratch/fields.dng
   scratch/data.rgb scratch/fields.dng
 
 
 # Validate DNG
 # Validate DNG

+ 9 - 1
util/makedng.c

@@ -22,6 +22,7 @@ usage(char *name)
 	fprintf(stderr, "  -n r,g,b       Set the whitepoint as 3 comma seperated floats\n");
 	fprintf(stderr, "  -n r,g,b       Set the whitepoint as 3 comma seperated floats\n");
 	fprintf(stderr, "  -b r,g,b       Set sensor analog gain as 3 comma seperated floats\n");
 	fprintf(stderr, "  -b r,g,b       Set sensor analog gain as 3 comma seperated floats\n");
 	fprintf(stderr, "  -e program     Set the exposure program in EXIF, 0-8\n");
 	fprintf(stderr, "  -e program     Set the exposure program in EXIF, 0-8\n");
+	fprintf(stderr, "  -t seconds     Set the exposure time in seconds\n");
 }
 }
 
 
 int
 int
@@ -45,8 +46,9 @@ main(int argc, char *argv[])
 	float neutral[] = {1.0f, 1.0f, 1.0f};
 	float neutral[] = {1.0f, 1.0f, 1.0f};
 	float balance[] = {1.0f, 1.0f, 1.0f};
 	float balance[] = {1.0f, 1.0f, 1.0f};
 	uint16_t exposure_program = 0;
 	uint16_t exposure_program = 0;
+	float exposure_time = 0;
 
 
-	while ((c = getopt(argc, argv, "w:h:p:o:m:s:c:n:b:e:")) != -1) {
+	while ((c = getopt(argc, argv, "w:h:p:o:m:s:c:n:b:e:t:")) != -1) {
 		switch (c) {
 		switch (c) {
 			case 'w':
 			case 'w':
 				val = strtol(optarg, &end, 10);
 				val = strtol(optarg, &end, 10);
@@ -94,6 +96,9 @@ main(int argc, char *argv[])
 				val = strtol(optarg, &end, 10);
 				val = strtol(optarg, &end, 10);
 				exposure_program = (uint16_t) val;
 				exposure_program = (uint16_t) val;
 				break;
 				break;
+			case 't':
+				exposure_time = strtof(optarg, &end);
+				break;
 			case '?':
 			case '?':
 				if (optopt == 'd' || optopt == 'l') {
 				if (optopt == 'd' || optopt == 'l') {
 					fprintf(stderr, "Option -%c requires an argument.\n", optopt);
 					fprintf(stderr, "Option -%c requires an argument.\n", optopt);
@@ -159,6 +164,9 @@ main(int argc, char *argv[])
 	libdng_set_neutral(&info, neutral[0], neutral[1], neutral[2]);
 	libdng_set_neutral(&info, neutral[0], neutral[1], neutral[2]);
 	libdng_set_analog_balance(&info, balance[0], balance[1], balance[2]);
 	libdng_set_analog_balance(&info, balance[0], balance[1], balance[2]);
 	libdng_set_exposure_program(&info, exposure_program);
 	libdng_set_exposure_program(&info, exposure_program);
+	if (exposure_time > 0) {
+		libdng_set_exposure_time(&info, exposure_time);
+	}
 
 
 	printf("Reading %s...\n", argv[optind]);
 	printf("Reading %s...\n", argv[optind]);
 	FILE *src = fopen(argv[optind], "r");
 	FILE *src = fopen(argv[optind], "r");