Ver código fonte

Add the exposure time metadata

Martijn Braam 1 ano atrás
pai
commit
680b260882
6 arquivos alterados com 58 adições e 1 exclusões
  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;
 		struct tm datetime;
 		uint16_t exposure_program;
+		float exposure_time;
 
 		// Raw image data
 		uint16_t bayer_pattern_dimensions[2];
@@ -124,6 +125,9 @@ libdng_load_calibration_file(libdng_info *dng, const char *path);
 EXPORT int
 libdng_set_exposure_program(libdng_info *dng, uint16_t mode);
 
+EXPORT int
+libdng_set_exposure_time(libdng_info *dng, float seconds);
+
 EXPORT int
 libdng_write(libdng_info *dng, const char *path, unsigned int width, unsigned int height, const uint8_t *data,
 	size_t length);

+ 3 - 0
man/makedng.1.scd

@@ -46,6 +46,9 @@ metadata to correctly render the file.
 *-e program*
 	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
 
 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[1] = 1.0f;
 	dng->analogbalance[2] = 1.0f;
+
+	dng->exposure_time = 0.0f;
 }
 
 int
@@ -197,6 +199,20 @@ libdng_set_exposure_program(libdng_info *dng, uint16_t mode)
 	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
 libdng_write(libdng_info *dng, const char *path, unsigned int width, unsigned int height, const uint8_t *data,
 	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);
 
+	if (dng->exposure_time > 0) {
+		TIFFSetField(tif, EXIFTAG_EXPOSURETIME, dng->exposure_time);
+	}
+
 	uint64_t exif_offset = 0;
 	if (!TIFFWriteCustomDirectory(tif, &exif_offset)) {
 		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();
 }
 
+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)
 {
@@ -34,6 +45,7 @@ TEST generate_simple_dng(void)
 		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 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);
 		ASSERT_EQm("Write DNG", 1, libdng_write(&info, "test.dng", 1280, 720, data, 1280 * 720));
 	free(data);
@@ -45,6 +57,11 @@ TEST generate_simple_dng(void)
 			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_CALL(check_int_tag(im, TIFFTAG_ORIENTATION, "ORIENTATION", 4));
 		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_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();
 }
 

+ 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 \
   -b 0.4,0.5,0.6 \
   -e 2 \
+  -t 0.01 \
   scratch/data.rgb scratch/fields.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, "  -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, "  -t seconds     Set the exposure time in seconds\n");
 }
 
 int
@@ -45,8 +46,9 @@ main(int argc, char *argv[])
 	float neutral[] = {1.0f, 1.0f, 1.0f};
 	float balance[] = {1.0f, 1.0f, 1.0f};
 	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) {
 			case 'w':
 				val = strtol(optarg, &end, 10);
@@ -94,6 +96,9 @@ main(int argc, char *argv[])
 				val = strtol(optarg, &end, 10);
 				exposure_program = (uint16_t) val;
 				break;
+			case 't':
+				exposure_time = strtof(optarg, &end);
+				break;
 			case '?':
 				if (optopt == 'd' || optopt == 'l') {
 					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_analog_balance(&info, balance[0], balance[1], balance[2]);
 	libdng_set_exposure_program(&info, exposure_program);
+	if (exposure_time > 0) {
+		libdng_set_exposure_time(&info, exposure_time);
+	}
 
 	printf("Reading %s...\n", argv[optind]);
 	FILE *src = fopen(argv[optind], "r");