check_dng.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. #include <stdbool.h>
  2. #include <tiffio.h>
  3. #include "greatest.h"
  4. #include "libdng.h"
  5. static enum greatest_test_res
  6. check_str_tag(TIFF *im, uint32_t tag, const char *name, const char *expected)
  7. {
  8. char *temp;
  9. if (TIFFGetField(im, tag, &temp) != 1) {
  10. FAILm(name);
  11. }
  12. ASSERT_STR_EQm(name, expected, temp);
  13. PASS();
  14. }
  15. static enum greatest_test_res
  16. check_int_tag(TIFF *im, uint32_t tag, const char *name, int expected)
  17. {
  18. uint32_t temp = 0;
  19. if (TIFFGetField(im, tag, &temp) != 1) {
  20. FAILm(name);
  21. }
  22. ASSERT_EQ_FMTm(name, expected, temp, "%d");
  23. PASS();
  24. }
  25. static enum greatest_test_res
  26. check_float_tag(TIFF *im, uint32_t tag, const char *name, float expected)
  27. {
  28. float temp;
  29. if (TIFFGetField(im, tag, &temp) != 1) {
  30. FAILm(name);
  31. }
  32. ASSERT_EQ_FMTm(name, expected, temp, "%f");
  33. PASS();
  34. }
  35. TEST generate_simple_dng(void)
  36. {
  37. libdng_info info = {0};
  38. libdng_new(&info);
  39. ASSERT_EQm("Set mode", 1, libdng_set_mode_from_name(&info, "RGGB"));
  40. ASSERT_EQm("Set make", 1, libdng_set_make_model(&info, "Make", "Model"));
  41. ASSERT_EQm("Set software", 1, libdng_set_software(&info, "Software"));
  42. ASSERT_EQm("Set orientation", 1, libdng_set_orientation(&info, 4));
  43. ASSERT_EQm("Set exposuretime", 1, libdng_set_exposure_time(&info, 0.04f));
  44. ASSERT_EQm("Set fnumber", 1, libdng_set_fnumber(&info, 2.8f));
  45. ASSERT_EQm("Set fnumber", 1, libdng_set_focal_length(&info, 50.0f, 1.5f));
  46. ASSERT_EQm("Set framerate", 1, libdng_set_frame_rate(&info, 30.0f));
  47. ASSERT_EQm("Set distortion", 1, libdng_set_distortion(&info, 1.0f, 2.0f, 3.0f));
  48. ASSERT_EQm("Set vignette", 1, libdng_set_vignette(&info, 1.0f, -1.0f, 6.0f));
  49. ASSERT_EQm("Set color matrix 1", 1, libdng_set_color_matrix_1(&info, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f));
  50. ASSERT_EQm("Set color matrix 2", 1, libdng_set_color_matrix_2(&info, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f));
  51. ASSERT_EQm("Set forward matrix 1", 1, libdng_set_forward_matrix_1(&info, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f));
  52. ASSERT_EQm("Set forward matrix 2", 1, libdng_set_forward_matrix_2(&info, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f));
  53. uint8_t *data = malloc(1280 * 720);
  54. ASSERT_EQm("Write DNG", 1, libdng_write(&info, "test.dng", 1280, 720, data, 1280 * 720));
  55. free(data);
  56. libdng_free(&info);
  57. // Use LibTIFF directly to verify results
  58. TIFF *im = TIFFOpen("test.dng", "r");
  59. if (im == NULL) {
  60. FAILm("Could not open result");
  61. }
  62. toff_t exif_offset;
  63. if (TIFFGetField(im, TIFFTAG_EXIFIFD, &exif_offset) != 1) {
  64. FAILm("Could not find EXIF data");
  65. }
  66. // Check IFD0 with most metadata and the thumbnail image
  67. CHECK_CALL(check_int_tag(im, TIFFTAG_ORIENTATION, "ORIENTATION", 4));
  68. CHECK_CALL(check_int_tag(im, TIFFTAG_BITSPERSAMPLE, "THUMB_BPS", 8));
  69. CHECK_CALL(check_int_tag(im, TIFFTAG_SAMPLESPERPIXEL, "THUMB_CHANNELS", 3));
  70. CHECK_CALL(check_int_tag(im, TIFFTAG_PHOTOMETRIC, "THUMB_PHOTOMETRIC", PHOTOMETRIC_RGB));
  71. CHECK_CALL(check_str_tag(im, TIFFTAG_MAKE, "MAKE", "Make"));
  72. CHECK_CALL(check_str_tag(im, TIFFTAG_MODEL, "MODEL", "Model"));
  73. CHECK_CALL(check_str_tag(im, TIFFTAG_UNIQUECAMERAMODEL, "UCM", "Make Model"));
  74. CHECK_CALL(check_str_tag(im, TIFFTAG_SOFTWARE, "SOFTWARE", "Software"));
  75. CHECK_CALL(check_int_tag(im, TIFFTAG_ORIENTATION, "ORIENTATION", 4));
  76. // Check the custom tags
  77. #define MPTAG_VERSION 49982
  78. #define MPTAG_DISTORTION 49983
  79. #define MPTAG_VIGNETTE 49984
  80. unsigned short count;
  81. float *fvalues;
  82. uint8_t *u8values;
  83. if (TIFFGetField(im, MPTAG_VERSION, &count, &u8values) != 1) {
  84. FAILm("Could not read MPTAG_VERSION");
  85. }
  86. ASSERT_EQ_FMTm("MPTAG_VERSION count", 4, count, "%d");
  87. ASSERT_EQ_FMTm("MPTAG_VERSION[0]", 1, u8values[0], "%d");
  88. ASSERT_EQ_FMTm("MPTAG_VERSION[1]", 0, u8values[1], "%d");
  89. ASSERT_EQ_FMTm("MPTAG_VERSION[2]", 0, u8values[2], "%d");
  90. ASSERT_EQ_FMTm("MPTAG_VERSION[3]", 0, u8values[3], "%d");
  91. if (TIFFGetField(im, MPTAG_DISTORTION, &fvalues) != 1) {
  92. FAILm("Could not read MPTAG_DISTORTION");
  93. }
  94. ASSERT_EQ_FMTm("MPTAG_DISTORTION[0]", 1.0f, fvalues[0], "%f");
  95. ASSERT_EQ_FMTm("MPTAG_DISTORTION[1]", 2.0f, fvalues[1], "%f");
  96. ASSERT_EQ_FMTm("MPTAG_DISTORTION[2]", 3.0f, fvalues[2], "%f");
  97. if (TIFFGetField(im, MPTAG_VIGNETTE, &fvalues) != 1) {
  98. FAILm("Could not read MPTAG_VIGNETTE");
  99. }
  100. ASSERT_EQ_FMTm("MPTAG_VIGNETTE[0]", 1.0f, fvalues[0], "%f");
  101. ASSERT_EQ_FMTm("MPTAG_VIGNETTE[1]", -1.0f, fvalues[1], "%f");
  102. ASSERT_EQ_FMTm("MPTAG_VIGNETTE[2]", 6.0f, fvalues[2], "%f");
  103. // Switch to IFD1 which has the raw data
  104. int subifd_count = 0;
  105. void *ptr;
  106. toff_t subifd_offsets[2];
  107. TIFFGetField(im, TIFFTAG_SUBIFD, &subifd_count, &ptr);
  108. memcpy(subifd_offsets, ptr, subifd_count * sizeof(subifd_offsets[0]));
  109. TIFFSetSubDirectory(im, subifd_offsets[0]);
  110. // Check IFD1 metadata
  111. CHECK_CALL(check_int_tag(im, TIFFTAG_IMAGEWIDTH, "RAW_WIDTH", 1280));
  112. CHECK_CALL(check_int_tag(im, TIFFTAG_IMAGELENGTH, "RAW_HEIGHT", 720));
  113. CHECK_CALL(check_int_tag(im, TIFFTAG_BITSPERSAMPLE, "RAW_BPS", 8));
  114. CHECK_CALL(check_int_tag(im, TIFFTAG_SAMPLESPERPIXEL, "RAW_CHANNELS", 1));
  115. CHECK_CALL(check_int_tag(im, TIFFTAG_PHOTOMETRIC, "RAW_PHOTOMETRIC", PHOTOMETRIC_CFA));
  116. // Switch to the EXIF block with the generic picture metadata
  117. TIFFReadEXIFDirectory(im, exif_offset);
  118. CHECK_CALL(check_float_tag(im, EXIFTAG_EXPOSURETIME, "EXPOSURETIME", 0.04f));
  119. CHECK_CALL(check_float_tag(im, EXIFTAG_FNUMBER, "FNUMBER", 2.8f));
  120. CHECK_CALL(check_float_tag(im, EXIFTAG_FOCALLENGTH, "FOCALLENGTH", 50.0f));
  121. CHECK_CALL(check_int_tag(im, EXIFTAG_FOCALLENGTHIN35MMFILM, "FOCALLENGTHIN35MMFILM", 75));
  122. PASS();
  123. }
  124. TEST read_dng(void)
  125. {
  126. // Generate test timestamp
  127. struct tm testtime;
  128. strptime("2024-08-27 01:02:03", "%Y-%m-%d %H:%M:%S", &testtime);
  129. // Generate a file to read
  130. libdng_info info = {0};
  131. libdng_new(&info);
  132. libdng_set_datetime(&info, testtime);
  133. libdng_set_mode_from_name(&info, "RGGB");
  134. libdng_set_make_model(&info, "Make", "Model");
  135. libdng_set_software(&info, "Software");
  136. libdng_set_orientation(&info, LIBDNG_ORIENTATION_RIGHTBOT);
  137. libdng_set_exposure_time(&info, 1.4f);
  138. libdng_set_exposure_program(&info, LIBDNG_EXPOSUREPROGRAM_PORTRAIT);
  139. libdng_set_fnumber(&info, 1.8f);
  140. libdng_set_focal_length(&info, 75.0f, 1.6f);
  141. uint8_t *data = malloc(1280 * 720);
  142. libdng_write(&info, "test.dng", 1280, 720, data, 1280 * 720);
  143. free(data);
  144. libdng_free(&info);
  145. // Read the file again
  146. libdng_info dng = {0};
  147. libdng_read(&dng, "test.dng");
  148. ASSERT_EQm("Bit depth", 8, dng.bit_depth);
  149. ASSERT_EQm("CFFA[0]", 0, dng.cfapattern[0]);
  150. ASSERT_EQm("CFFA[1]", 1, dng.cfapattern[1]);
  151. ASSERT_EQm("CFFA[2]", 1, dng.cfapattern[2]);
  152. ASSERT_EQm("CFFA[3]", 2, dng.cfapattern[3]);
  153. ASSERT_STR_EQm("Make", "Make", dng.camera_make);
  154. ASSERT_STR_EQm("Model", "Model", dng.camera_model);
  155. ASSERT_STR_EQm("Software", "Software", dng.software);
  156. ASSERT_EQm("Orientation", LIBDNG_ORIENTATION_RIGHTBOT, dng.orientation);
  157. ASSERT_EQ_FMTm("Exposure time", 1.4f, dng.exposure_time, "%f");
  158. ASSERT_EQm("Exposure program", LIBDNG_EXPOSUREPROGRAM_PORTRAIT, dng.exposure_program);
  159. ASSERT_EQ_FMTm("FNumber", 1.8f, dng.fnumber, "%f");
  160. ASSERT_EQ_FMTm("Focal length", 75.0f, dng.focal_length, "%f");
  161. ASSERT_EQ_FMTm("Crop factor", 1.6f, dng.crop_factor, "%f");
  162. char orig[sizeof "2011-10-08T07:07:09Z"];
  163. char parsed[sizeof "2011-10-08T07:07:09Z"];
  164. strftime(orig, sizeof orig, "%FT%TZ", &testtime);
  165. strftime(parsed, sizeof parsed, "%FT%TZ", &dng.datetime);
  166. ASSERT_STR_EQm("DateTime", orig, parsed);
  167. ASSERT_EQm("Year", testtime.tm_year, dng.datetime.tm_year);
  168. ASSERT_EQm("Month", testtime.tm_mon, dng.datetime.tm_mon);
  169. ASSERT_EQm("Day", testtime.tm_yday, dng.datetime.tm_yday);
  170. ASSERT_EQ_FMTm("Hour", testtime.tm_hour, dng.datetime.tm_hour, "%d");
  171. ASSERT_EQm("Minute", testtime.tm_min, dng.datetime.tm_min);
  172. ASSERT_EQm("Second", testtime.tm_sec, dng.datetime.tm_sec);
  173. PASS();
  174. }
  175. SUITE (test_suite)
  176. {
  177. RUN_TEST(generate_simple_dng);
  178. RUN_TEST(read_dng);
  179. }
  180. GREATEST_MAIN_DEFS();
  181. int
  182. main(int argc, char **argv)
  183. {
  184. GREATEST_MAIN_BEGIN();
  185. libdng_init();
  186. RUN_SUITE(test_suite);
  187. GREATEST_MAIN_END();
  188. }