From da68a1c96af4a04bb139bb9a0628a1ec02e6f9a4 Mon Sep 17 00:00:00 2001 From: Martijn Braam Date: Thu, 23 Nov 2023 00:12:01 +0100 Subject: [PATCH] Write more metadata using libdng --- src/dcp.c | 146 ----------------------------------------- src/dcp.h | 11 ---- src/process_pipeline.c | 131 ++++++++++-------------------------- 3 files changed, 34 insertions(+), 254 deletions(-) diff --git a/src/dcp.c b/src/dcp.c index e4a35e5..d25417f 100644 --- a/src/dcp.c +++ b/src/dcp.c @@ -2,154 +2,8 @@ #include #include -#include -#include #include -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; -} - -struct MPCameraCalibration -parse_calibration_file(const char *path) -{ - FILE *fp; - size_t size; - unsigned char *buffer; - - struct MPCameraCalibration result = { 0 }; - - fp = fopen(path, "rb"); - if (fp == NULL) { - return result; - } - - 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 result; - } - fclose(fp); - - if (buffer[0] != 'I' || buffer[1] != 'I') { - fprintf(stderr, "Magic for DCP file incorrect\n"); - return result; - } - if (buffer[2] != 0x52 || buffer[3] != 0x43) { - fprintf(stderr, "Invalid DCP version\n"); - return result; - } - - 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 DCPTAG_COLOR_MATRIX_1: - for (int j = 0; j < 9; j++) { - float point = - get_srational(buffer, offset + (j * 8)); - result.color_matrix_1[j] = point; - } - break; - case DCPTAG_COLOR_MATRIX_2: - for (int j = 0; j < 9; j++) { - float point = - get_srational(buffer, offset + (j * 8)); - result.color_matrix_2[j] = point; - } - break; - case DCPTAG_FORWARD_MATRIX_1: - for (int j = 0; j < 9; j++) { - float point = - get_srational(buffer, offset + (j * 8)); - result.forward_matrix_1[j] = point; - } - break; - case DCPTAG_FORWARD_MATRIX_2: - for (int j = 0; j < 9; j++) { - float point = - get_srational(buffer, offset + (j * 8)); - result.forward_matrix_2[j] = point; - } - break; - case DCPTAG_CALIBRATION_ILLUMINANT_1: - result.illuminant_1 = offset; - break; - case DCPTAG_CALIBRATION_ILLUMINANT_2: - result.illuminant_2 = offset; - break; - case DCPTAG_PROFILE_TONE_CURVE: - result.tone_curve = malloc(count * sizeof(float)); - result.tone_curve_length = count; - for (int j = 0; j < count; j++) { - result.tone_curve[j] = - get_float(buffer, offset + (j * 4)); - } - break; - case DCPTAG_PROFILE_HUE_SAT_MAP_DIMS: - result.hue_sat_map_dims[0] = get_int32(buffer, offset); - result.hue_sat_map_dims[1] = get_int32(buffer, offset + 4); - result.hue_sat_map_dims[2] = get_int32(buffer, offset + 8); - break; - case DCPTAG_PROFILE_HUE_SAT_MAP_DATA_1: - result.hue_sat_map_data_1 = malloc(count * sizeof(float)); - for (int j = 0; j < count; j++) { - result.hue_sat_map_data_1[j] = - get_float(buffer, offset + (j * 4)); - } - break; - case DCPTAG_PROFILE_HUE_SAT_MAP_DATA_2: - result.hue_sat_map_data_2 = malloc(count * sizeof(float)); - for (int j = 0; j < count; j++) { - result.hue_sat_map_data_2[j] = - get_float(buffer, offset + (j * 4)); - } - break; - } - } - - return result; -} - bool find_calibration_by_model(char *conffile, char *model, const char *sensor) { diff --git a/src/dcp.h b/src/dcp.h index ca8902f..4c0d87d 100644 --- a/src/dcp.h +++ b/src/dcp.h @@ -17,17 +17,6 @@ struct MPCameraCalibration { float *hue_sat_map_data_2; }; -#define DCPTAG_COLOR_MATRIX_1 50721 -#define DCPTAG_COLOR_MATRIX_2 50722 -#define DCPTAG_PROFILE_HUE_SAT_MAP_DIMS 50937 -#define DCPTAG_PROFILE_HUE_SAT_MAP_DATA_1 50938 -#define DCPTAG_PROFILE_HUE_SAT_MAP_DATA_2 50939 -#define DCPTAG_PROFILE_TONE_CURVE 50940 -#define DCPTAG_CALIBRATION_ILLUMINANT_1 50778 -#define DCPTAG_CALIBRATION_ILLUMINANT_2 50779 -#define DCPTAG_FORWARD_MATRIX_1 50964 -#define DCPTAG_FORWARD_MATRIX_2 50965 - struct MPCameraCalibration parse_calibration_file(const char *path); bool find_calibration(char *conffile, const char *sensor); diff --git a/src/process_pipeline.c b/src/process_pipeline.c index e8721a7..d78e6fa 100644 --- a/src/process_pipeline.c +++ b/src/process_pipeline.c @@ -481,24 +481,51 @@ process_image_for_preview(const uint8_t *image) static void process_image_for_capture(const uint8_t *image, int count) { - time_t rawtime; - time(&rawtime); - struct tm tim = *(localtime(&rawtime)); - - char datetime[20] = { 0 }; - strftime(datetime, 20, "%Y:%m:%d %H:%M:%S", &tim); - char fname[255]; sprintf(fname, "%s/%d.dng", burst_dir, count); + uint16_t orientation; + if (state_proc.device_rotation == 0) { + orientation = state_proc.mode->mirrored ? + LIBDNG_ORIENTATION_TOPRIGHT : + LIBDNG_ORIENTATION_TOPLEFT; + } else if (state_proc.device_rotation == 90) { + orientation = state_proc.mode->mirrored ? + LIBDNG_ORIENTATION_RIGHTBOT : + LIBDNG_ORIENTATION_LEFTBOT; + } else if (state_proc.device_rotation == 180) { + orientation = state_proc.mode->mirrored ? + LIBDNG_ORIENTATION_BOTLEFT : + LIBDNG_ORIENTATION_BOTRIGHT; + } else { + orientation = state_proc.mode->mirrored ? + LIBDNG_ORIENTATION_LEFTTOP : + LIBDNG_ORIENTATION_RIGHTTOP; + } + libdng_info dng = { 0 }; libdng_new(&dng); + libdng_set_datetime_now(&dng); libdng_set_mode_from_pixfmt(&dng, state_proc.mode->v4l_pixfmt); libdng_set_make_model(&dng, state_proc.configuration->make, state_proc.configuration->model); + libdng_set_orientation(&dng, orientation); + libdng_set_software(&dng, "Megapixels"); + libdng_set_neutral(&dng, state_proc.red, 1.0f, state_proc.blue); + libdng_set_analog_balance(&dng, + state_proc.balance[0], + state_proc.balance[1], + state_proc.balance[2]); + if (!state_proc.exposure.manual) { + libdng_set_exposure_program(&dng, LIBDNG_EXPOSUREPROGRAM_NORMAL); + } else { + libdng_set_exposure_program(&dng, LIBDNG_EXPOSUREPROGRAM_MANUAL); + } + + printf("Writing frame to %s\n", fname); libdng_write(&dng, fname, state_proc.mode->width, @@ -507,84 +534,6 @@ process_image_for_capture(const uint8_t *image, int count) count); libdng_free(&dng); - uint16_t orientation; - if (state_proc.device_rotation == 0) { - orientation = state_proc.mode->mirrored ? ORIENTATION_TOPRIGHT : - ORIENTATION_TOPLEFT; - } else if (state_proc.device_rotation == 90) { - orientation = state_proc.mode->mirrored ? ORIENTATION_RIGHTBOT : - ORIENTATION_LEFTBOT; - } else if (state_proc.device_rotation == 180) { - orientation = state_proc.mode->mirrored ? ORIENTATION_BOTLEFT : - ORIENTATION_BOTRIGHT; - } else { - orientation = state_proc.mode->mirrored ? ORIENTATION_LEFTTOP : - ORIENTATION_RIGHTTOP; - } - TIFFSetField(tif, TIFFTAG_ORIENTATION, orientation); - TIFFSetField(tif, TIFFTAG_DATETIME, datetime); - TIFFSetField(tif, TIFFTAG_SOFTWARE, "Megapixels"); - - static float neutral[] = { 1.0f, 1.0f, 1.0f }; - neutral[0] = state_proc.red; - neutral[2] = state_proc.blue; - TIFFSetField(tif, TIFFTAG_ASSHOTNEUTRAL, 3, neutral); - TIFFSetField(tif, TIFFTAG_ANALOGBALANCE, 3, state_proc.balance); - - // Write black thumbnail, only windows uses this - { - unsigned char *buf = (unsigned char *)calloc( - 1, (state_proc.mode->width >> 4) * 3); - for (int row = 0; row < (state_proc.mode->height >> 4); row++) { - TIFFWriteScanline(tif, buf, row, 0); - } - free(buf); - } - TIFFWriteDirectory(tif); - - printf("TIFF version %d\n", TIFFLIB_VERSION); - int whitelevel = - (1 << libmegapixels_format_bits_per_pixel(state_proc.mode->format)) - - 1; - TIFFSetField(tif, TIFFTAG_WHITELEVEL, 1, &whitelevel); - TIFFCheckpointDirectory(tif); - printf("Writing frame to %s\n", fname); - - uint8_t *output_image = (uint8_t *)image; - - // Repack 10-bit image from sensor format into a sequencial format - if (libmegapixels_format_bits_per_pixel(state_proc.mode->format) == 10) { - output_image = malloc( - libmegapixels_mode_width_to_bytes(state_proc.mode->format, - state_proc.mode->width) * - state_proc.mode->height); - - repack_image_sequencial(image, output_image, state_proc.mode); - } - - for (int row = 0; row < state_proc.mode->height; row++) { - TIFFWriteScanline(tif, - (void *)output_image + - (row * libmegapixels_mode_width_to_bytes( - state_proc.mode->format, - state_proc.mode->width)), - row, - 0); - } - TIFFWriteDirectory(tif); - - if (output_image != image) - free(output_image); - - // Add an EXIF block to the tiff - TIFFCreateEXIFDirectory(tif); - // 1 = manual, 2 = full auto, 3 = aperture priority, 4 = shutter priority - if (!state_proc.exposure.manual) { - TIFFSetField(tif, EXIFTAG_EXPOSUREPROGRAM, 2); - } else { - TIFFSetField(tif, EXIFTAG_EXPOSUREPROGRAM, 1); - } - /* TIFFSetField(tif, EXIFTAG_EXPOSURETIME, @@ -610,8 +559,6 @@ process_image_for_capture(const uint8_t *image, int count) } */ - TIFFSetField(tif, EXIFTAG_DATETIMEORIGINAL, datetime); - TIFFSetField(tif, EXIFTAG_DATETIMEDIGITIZED, datetime); /* if (pr_camera->fnumber) { TIFFSetField(tif, EXIFTAG_FNUMBER, pr_camera->fnumber); @@ -626,16 +573,6 @@ process_image_for_capture(const uint8_t *image, int count) pr_camera->cropfactor)); } */ - uint64_t exif_offset = 0; - TIFFWriteCustomDirectory(tif, &exif_offset); - TIFFFreeDirectory(tif); - - // Update exif pointer - TIFFSetDirectory(tif, 0); - TIFFSetField(tif, TIFFTAG_EXIFIFD, exif_offset); - TIFFRewriteDirectory(tif); - - TIFFClose(tif); } static void