Sfoglia il codice sorgente

Implement loading DCP files

Martijn Braam 1 anno fa
parent
commit
05612542e7
7 ha cambiato i file con 250 aggiunte e 11 eliminazioni
  1. 1 1
      CMakeLists.txt
  2. 3 0
      doc/makedng.1.scd
  3. 16 2
      include/libdng.h
  4. 3 0
      meson.build
  5. 210 0
      src/dcp.c
  6. 6 6
      src/libdng.c
  7. 11 2
      util/makedng.c

+ 1 - 1
CMakeLists.txt

@@ -6,7 +6,7 @@ set(LIBRARY_VERSION_MAJOR 0)
 set(LIBRARY_VERSION_STRING 0.1)
 set(CMAKE_C_VISIBILITY_PRESET hidden)
 
-add_library(libdng SHARED include/libdng.h src/libdng.c src/dng.h src/mode.c src/repack.c src/repack.h)
+add_library(libdng SHARED include/libdng.h src/libdng.c src/dng.h src/mode.c src/repack.c src/repack.h src/dcp.c)
 
 set_target_properties(libdng PROPERTIES
         VERSION ${LIBRARY_VERSION_STRING}

+ 3 - 0
doc/makedng.1.scd

@@ -34,6 +34,9 @@ metadata to correctly render the file.
 	Set the orientation of the image data as a number from 1-8 from the DNG
 	specification.
 
+*-c dcp-file*
+	Load a DCP calibration file and append the color profile to the final DNG.
+
 # PIXEL FORMATS
 
 The pixel format argument accepts the following values:

+ 16 - 2
include/libdng.h

@@ -17,11 +17,22 @@ typedef struct {
 
 		// Raw image data
 		uint16_t bayer_pattern_dimensions[2];
-		float colormatrix1[9];
-		float colormatrix2[9];
 		float neutral[3];
 		uint8_t cfapattern[4];
 
+		// Calibration data
+		float color_matrix_1[9];
+		float color_matrix_2[9];
+		float forward_matrix_1[9];
+		float forward_matrix_2[9];
+		unsigned short illuminant_1;
+		unsigned short illuminant_2;
+		unsigned int hue_sat_map_dims[3];
+		size_t tone_curve_length;
+		float *tone_curve;
+		float *hue_sat_map_data_1;
+		float *hue_sat_map_data_2;
+
 		uint16_t bit_depth;
 		bool needs_repack;
 } libdng_info;
@@ -65,6 +76,9 @@ libdng_set_datetime_now(libdng_info *dng);
 EXPORT int
 libdng_set_orientation(libdng_info *dng, uint16_t orientation);
 
+EXPORT int
+libdng_load_calibration_file(libdng_info *dng, const char *path);
+
 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
meson.build

@@ -30,6 +30,9 @@ lib_src = [
     'src/dng.h',
     'src/mode.c',
     'src/mode.h',
+    'src/dcp.c',
+    'src/repack.c',
+    'src/repack.h',
 ]
 
 add_project_arguments(['-Wno-multichar'], language: 'c')

+ 210 - 0
src/dcp.c

@@ -0,0 +1,210 @@
+#include "dng.h"
+#include "libdng.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+unsigned int
+get_int32(const unsigned char *buffer, size_t offset)
+{
+	return (buffer[offset + 3] << 24) | (buffer[offset + 2] << 16) |
+		(buffer[offset + 1] << 8) | (buffer[offset]);
+}
+
+unsigned int
+get_int16(const unsigned char *buffer, size_t offset)
+{
+	return (buffer[offset + 1] << 8) | (buffer[offset]);
+}
+
+float
+get_float(unsigned char *buffer, size_t offset)
+{
+	float f;
+	unsigned char b[] = {buffer[offset + 0],
+		buffer[offset + 1],
+		buffer[offset + 2],
+		buffer[offset + 3]};
+	memcpy(&f, &b, sizeof(f));
+	return f;
+}
+
+float
+get_srational(unsigned char *buffer, size_t offset)
+{
+	int a = (int) get_int32(buffer, offset);
+	int b = (int) get_int32(buffer, offset + 4);
+	return (float) a / (float) b;
+}
+
+int
+libdng_load_calibration_file(libdng_info *dng, const char *path)
+{
+	FILE *fp;
+	size_t size;
+	unsigned char *buffer;
+
+	fp = fopen(path, "rb");
+	if (fp == NULL) {
+		return 0;
+	}
+
+	fseek(fp, 0, SEEK_END);
+	size = ftell(fp);
+	fseek(fp, 0, SEEK_SET);
+	buffer = malloc(sizeof(char) * size);
+	size_t ret = fread(buffer, 1, size, fp);
+	if (ret != size) {
+		return 0;
+	}
+	fclose(fp);
+
+	if (buffer[0] != 'I' || buffer[1] != 'I') {
+		fprintf(stderr, "Magic for DCP file incorrect\n");
+		return 0;
+	}
+	if (buffer[2] != 0x52 || buffer[3] != 0x43) {
+		fprintf(stderr, "Invalid DCP version\n");
+		return 0;
+	}
+
+	unsigned int ifd0 = get_int32(buffer, 4);
+	unsigned int tag_count = get_int16(buffer, ifd0);
+
+	for (int i = 0; i < tag_count; i++) {
+		int tag_offset = ifd0 + 2 + (i * 12);
+		unsigned int tag = get_int16(buffer, tag_offset + 0);
+		unsigned int type = get_int16(buffer, tag_offset + 2);
+		unsigned int count = get_int32(buffer, tag_offset + 4);
+		unsigned int offset = get_int32(buffer, tag_offset + 8);
+
+		switch (tag) {
+			case DNGTAG_COLOR_MATRIX_1:
+				for (int j = 0; j < 9; j++) {
+					float point =
+						get_srational(buffer, offset + (j * 8));
+					dng->color_matrix_1[j] = point;
+				}
+				break;
+			case DNGTAG_COLOR_MATRIX_2:
+				for (int j = 0; j < 9; j++) {
+					float point =
+						get_srational(buffer, offset + (j * 8));
+					dng->color_matrix_2[j] = point;
+				}
+				break;
+			case DNGTAG_FORWARD_MATRIX_1:
+				for (int j = 0; j < 9; j++) {
+					float point =
+						get_srational(buffer, offset + (j * 8));
+					dng->forward_matrix_1[j] = point;
+				}
+				break;
+			case DNGTAG_FORWARD_MATRIX_2:
+				for (int j = 0; j < 9; j++) {
+					float point =
+						get_srational(buffer, offset + (j * 8));
+					dng->forward_matrix_2[j] = point;
+				}
+				break;
+			case DNGTAG_CALIBRATION_ILLUMINANT_1:
+				dng->illuminant_1 = offset;
+				break;
+			case DNGTAG_CALIBRATION_ILLUMINANT_2:
+				dng->illuminant_2 = offset;
+				break;
+			case DNGTAG_PROFILE_TONE_CURVE:
+				dng->tone_curve = malloc(count * sizeof(float));
+				dng->tone_curve_length = count;
+				for (int j = 0; j < count; j++) {
+					dng->tone_curve[j] =
+						get_float(buffer, offset + (j * 4));
+				}
+				break;
+			case DNGTAG_PROFILE_HUE_SAT_MAP_DIMS:
+				dng->hue_sat_map_dims[0] = get_int32(buffer, offset);
+				dng->hue_sat_map_dims[1] = get_int32(buffer, offset + 4);
+				dng->hue_sat_map_dims[2] = get_int32(buffer, offset + 8);
+				break;
+			case DNGTAG_PROFILE_HUE_SAT_MAP_DATA_1:
+				dng->hue_sat_map_data_1 = malloc(count * sizeof(float));
+				for (int j = 0; j < count; j++) {
+					dng->hue_sat_map_data_1[j] =
+						get_float(buffer, offset + (j * 4));
+				}
+				break;
+			case DNGTAG_PROFILE_HUE_SAT_MAP_DATA_2:
+				dng->hue_sat_map_data_2 = malloc(count * sizeof(float));
+				for (int j = 0; j < count; j++) {
+					dng->hue_sat_map_data_2[j] =
+						get_float(buffer, offset + (j * 4));
+				}
+				break;
+		}
+	}
+
+	return 1;
+}
+
+bool
+find_calibration_by_model(char *conffile, char *model, const char *sensor)
+{
+	// Check config/%model,%sensor.dcp in the current working directory
+	sprintf(conffile, "config/%s,%s.dcp", model, sensor);
+	if (access(conffile, F_OK) != -1) {
+		printf("Found calibration file at %s\n", conffile);
+		return true;
+	}
+
+	// Check user overridden /etc/megapixels/config/%model,%sensor.dcp
+	sprintf(conffile,
+		"%s/megapixels/config/%s,%s.dcp",
+		"/etc",
+		model,
+		sensor);
+	if (access(conffile, F_OK) != -1) {
+		printf("Found calibration file at %s\n", conffile);
+		return true;
+	}
+
+	// Check packaged /usr/share/megapixels/config/%model,%sensor.ini
+	sprintf(conffile, "%s/megapixels/config/%s,%s.dcp", "/usr/share", model, sensor);
+	if (access(conffile, F_OK) != -1) {
+		printf("Found calibration file at %s\n", conffile);
+		return true;
+	}
+	printf("No calibration found for %s,%s\n", model, sensor);
+	return false;
+}
+
+bool
+find_calibration(char *conffile, const char *sensor)
+{
+	char model[512];
+	FILE *fp;
+
+	if (access("/proc/device-tree/compatible", F_OK) == -1) {
+		return false;
+	}
+	fp = fopen("/proc/device-tree/compatible", "r");
+	char *modelptr = model;
+	while (1) {
+		int c = fgetc(fp);
+		if (c == EOF) {
+			*(modelptr) = '\0';
+			return find_calibration_by_model(conffile, model, sensor);
+		}
+		*(modelptr++) = (char) c;
+		if (c == 0) {
+			bool res =
+				find_calibration_by_model(conffile, model, sensor);
+			if (res) {
+				return true;
+			}
+			modelptr = model;
+		}
+	}
+}

+ 6 - 6
src/libdng.c

@@ -38,12 +38,12 @@ libdng_new(libdng_info *dng)
 	dng->bayer_pattern_dimensions[1] = 2;
 
 	for (size_t i = 0; i < 9; i++) {
-		dng->colormatrix1[i] = 0.0f;
-		dng->colormatrix2[i] = 0.0f;
+		dng->color_matrix_1[i] = 0.0f;
+		dng->color_matrix_2[i] = 0.0f;
 	}
-	dng->colormatrix1[0] = 1.0f;
-	dng->colormatrix1[4] = 1.0f;
-	dng->colormatrix1[8] = 1.0f;
+	dng->color_matrix_1[0] = 1.0f;
+	dng->color_matrix_1[4] = 1.0f;
+	dng->color_matrix_1[8] = 1.0f;
 
 	dng->cfapattern[0] = 0;
 	dng->cfapattern[1] = 1;
@@ -186,7 +186,7 @@ libdng_write(libdng_info *dng, const char *path, unsigned int width, unsigned in
 	TIFFSetField(tif, TIFFTAG_ORIENTATION, dng->orientation);
 	TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
 	TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
-	TIFFSetField(tif, DNGTAG_COLOR_MATRIX_1, 9, dng->colormatrix1);
+	TIFFSetField(tif, DNGTAG_COLOR_MATRIX_1, 9, dng->color_matrix_1);
 	TIFFSetField(tif, DNGTAG_ASSHOTNEUTRAL, 3, dng->neutral);
 
 	if (dng->camera_make != NULL)

+ 11 - 2
util/makedng.c

@@ -9,7 +9,7 @@
 void
 usage(char *name)
 {
-	fprintf(stderr, "Usage: %s -w width -h height srcfile dstfile\n", name);
+	fprintf(stderr, "Usage: %s -w width -h height -p fmt srcfile dstfile\n", name);
 	fprintf(stderr, "Convert raw sensor data to DNG\n\n");
 	fprintf(stderr, "Arguments:\n");
 	fprintf(stderr, "  -w width       Source data width\n");
@@ -18,6 +18,7 @@ usage(char *name)
 	fprintf(stderr, "  -m make,model  Make and model, comma seperated\n");
 	fprintf(stderr, "  -s software    Software name\n");
 	fprintf(stderr, "  -o orientation Orientation number [0-9]\n");
+	fprintf(stderr, "  -c dcp         Append calibration data from .dcp file\n");
 }
 
 int
@@ -36,9 +37,10 @@ main(int argc, char *argv[])
 	char *pixelfmt = NULL;
 	char *model = NULL;
 	char *software = NULL;
+	char *calibration = NULL;
 	uint16_t orientation = 0;
 
-	while ((c = getopt(argc, argv, "w:h:p:o:m:s:")) != -1) {
+	while ((c = getopt(argc, argv, "w:h:p:o:m:s:c:")) != -1) {
 		switch (c) {
 			case 'w':
 				val = strtol(optarg, &end, 10);
@@ -65,6 +67,9 @@ main(int argc, char *argv[])
 			case 's':
 				software = optarg;
 				break;
+			case 'c':
+				calibration = optarg;
+				break;
 			case '?':
 				if (optopt == 'd' || optopt == 'l') {
 					fprintf(stderr, "Option -%c requires an argument.\n", optopt);
@@ -123,6 +128,10 @@ main(int argc, char *argv[])
 		libdng_set_orientation(&info, orientation);
 	}
 
+	if (calibration != NULL) {
+		libdng_load_calibration_file(&info, calibration);
+	}
+
 	printf("Reading %s...\n", argv[optind]);
 	FILE *src = fopen(argv[optind], "r");
 	if (src == NULL) {