/src/LibRaw/src/metadata/exif_gps.cpp
Line | Count | Source |
1 | | /* -*- C++ -*- |
2 | | * Copyright 2019-2025 LibRaw LLC (info@libraw.org) |
3 | | * |
4 | | LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder, |
5 | | dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net. |
6 | | LibRaw do not use RESTRICTED code from dcraw.c |
7 | | |
8 | | LibRaw is free software; you can redistribute it and/or modify |
9 | | it under the terms of the one of two licenses as you choose: |
10 | | |
11 | | 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 |
12 | | (See file LICENSE.LGPL provided in LibRaw distribution archive for details). |
13 | | |
14 | | 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 |
15 | | (See file LICENSE.CDDL provided in LibRaw distribution archive for details). |
16 | | |
17 | | */ |
18 | | |
19 | | #include "../../internal/dcraw_defs.h" |
20 | | #include "../../internal/libraw_cameraids.h" |
21 | | |
22 | | void LibRaw::parse_exif_interop(INT64 base) |
23 | 2.74k | { |
24 | 2.74k | unsigned entries, tag, type, len; |
25 | 2.74k | INT64 save; |
26 | 2.74k | char value[4] = { 0,0,0,0 }; |
27 | 2.74k | entries = get2(); |
28 | 2.74k | INT64 fsize = ifp->size(); |
29 | 4.02M | while (entries--) |
30 | 4.01M | { |
31 | 4.01M | tiff_get(base, &tag, &type, &len, &save); |
32 | | |
33 | 4.01M | INT64 savepos = ftell(ifp); |
34 | 4.01M | if (len > 8 && savepos + len > fsize * 2) |
35 | 2.87M | { |
36 | 2.87M | fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! |
37 | 2.87M | continue; |
38 | 2.87M | } |
39 | 1.14M | if (callbacks.exif_cb) |
40 | 0 | { |
41 | 0 | callbacks.exif_cb(callbacks.exifparser_data, tag | 0x40000, type, len, order, ifp, base); |
42 | 0 | fseek(ifp, savepos, SEEK_SET); |
43 | 0 | } |
44 | | |
45 | 1.14M | switch (tag) |
46 | 1.14M | { |
47 | 68.7k | case 0x0001: // InteropIndex |
48 | 68.7k | fread(value, 1, MIN(4, len), ifp); |
49 | 68.7k | if (strncmp(value, "R98", 3) == 0 && |
50 | | // Canon bug, when [Canon].ColorSpace = AdobeRGB, |
51 | | // but [ExifIFD].ColorSpace = Uncalibrated and |
52 | | // [InteropIFD].InteropIndex = "R98" |
53 | 540 | imgdata.color.ExifColorSpace == LIBRAW_COLORSPACE_Unknown) |
54 | 26 | imgdata.color.ExifColorSpace = LIBRAW_COLORSPACE_sRGB; |
55 | 68.6k | else if (strncmp(value, "R03", 3) == 0) |
56 | 254 | imgdata.color.ExifColorSpace = LIBRAW_COLORSPACE_AdobeRGB; |
57 | 68.7k | break; |
58 | 1.14M | } |
59 | 1.14M | fseek(ifp, save, SEEK_SET); |
60 | 1.14M | } |
61 | 2.74k | } |
62 | | |
63 | | void LibRaw::parse_exif(INT64 base) |
64 | 147k | { |
65 | 147k | unsigned entries, tag, type, len, c; |
66 | 147k | double expo, ape; |
67 | 147k | INT64 save; |
68 | | |
69 | 147k | unsigned kodak = !strncmp(make, "EASTMAN", 7) && tiff_nifds < 3; |
70 | | |
71 | 147k | if (!libraw_internal_data.unpacker_data.exif_subdir_offset) |
72 | 16.9k | { |
73 | 16.9k | libraw_internal_data.unpacker_data.exif_offset = base; |
74 | 16.9k | libraw_internal_data.unpacker_data.exif_subdir_offset = ftell(ifp); |
75 | 16.9k | } |
76 | | |
77 | 147k | entries = get2(); |
78 | 147k | if (!strncmp(make, "Hasselblad", 10) && (tiff_nifds > 3) && (entries > 512)) |
79 | 486 | return; |
80 | 147k | INT64 fsize = ifp->size(); |
81 | 39.5M | while (entries--) |
82 | 39.3M | { |
83 | 39.3M | tiff_get(base, &tag, &type, &len, &save); |
84 | | |
85 | 39.3M | INT64 savepos = ftell(ifp); |
86 | 39.3M | if (len > 8 && savepos + INT64(len) > fsize * 2LL) |
87 | 28.9M | { |
88 | 28.9M | fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! |
89 | 28.9M | continue; |
90 | 28.9M | } |
91 | 10.4M | if (callbacks.exif_cb) |
92 | 0 | { |
93 | 0 | callbacks.exif_cb(callbacks.exifparser_data, tag, type, len, order, ifp, |
94 | 0 | base); |
95 | 0 | fseek(ifp, savepos, SEEK_SET); |
96 | 0 | } |
97 | | |
98 | 10.4M | switch (tag) |
99 | 10.4M | { |
100 | 2.74k | case 0xA005: // Interoperability IFD |
101 | 2.74k | fseek(ifp, get4() + base, SEEK_SET); |
102 | 2.74k | parse_exif_interop(base); |
103 | 2.74k | break; |
104 | 12.8k | case 0xA001: // ExifIFD.ColorSpace |
105 | 12.8k | c = get2(); |
106 | 12.8k | if (c == 1 && imgdata.color.ExifColorSpace == LIBRAW_COLORSPACE_Unknown) |
107 | 932 | imgdata.color.ExifColorSpace = LIBRAW_COLORSPACE_sRGB; |
108 | 11.9k | else if (c == 2) |
109 | 196 | imgdata.color.ExifColorSpace = LIBRAW_COLORSPACE_AdobeRGB; |
110 | 12.8k | break; |
111 | 4.67k | case 0x9400: |
112 | 4.67k | imCommon.exifAmbientTemperature = getrealf(type); |
113 | 4.67k | if ((imCommon.CameraTemperature > -273.15f) && |
114 | 1.64k | ((OlyID == OlyID_TG_5) || |
115 | 1.64k | (OlyID == OlyID_TG_6)) |
116 | 4.67k | ) |
117 | 0 | imCommon.CameraTemperature += imCommon.exifAmbientTemperature; |
118 | 4.67k | break; |
119 | 1.45k | case 0x9401: |
120 | 1.45k | imCommon.exifHumidity = getrealf(type); |
121 | 1.45k | break; |
122 | 2.03k | case 0x9402: |
123 | 2.03k | imCommon.exifPressure = getrealf(type); |
124 | 2.03k | break; |
125 | 2.39k | case 0x9403: |
126 | 2.39k | imCommon.exifWaterDepth = getrealf(type); |
127 | 2.39k | break; |
128 | 1.27k | case 0x9404: |
129 | 1.27k | imCommon.exifAcceleration = getrealf(type); |
130 | 1.27k | break; |
131 | 1.25k | case 0x9405: |
132 | 1.25k | imCommon.exifCameraElevationAngle = getrealf(type); |
133 | 1.25k | break; |
134 | | |
135 | 342 | case 0xa405: // FocalLengthIn35mmFormat |
136 | 342 | imgdata.lens.FocalLengthIn35mmFormat = get2(); |
137 | 342 | break; |
138 | 480 | case 0xa431: // BodySerialNumber |
139 | 480 | stmread(imgdata.shootinginfo.BodySerial, len, ifp); |
140 | 480 | break; |
141 | 420 | case 0xa432: // LensInfo, 42034dec, Lens Specification per EXIF standard |
142 | 420 | imgdata.lens.MinFocal = getrealf(type); |
143 | 420 | imgdata.lens.MaxFocal = getrealf(type); |
144 | 420 | imgdata.lens.MaxAp4MinFocal = getrealf(type); |
145 | 420 | imgdata.lens.MaxAp4MaxFocal = getrealf(type); |
146 | 420 | break; |
147 | 1.59k | case 0xa435: // LensSerialNumber |
148 | 1.59k | stmread(imgdata.lens.LensSerial, len, ifp); |
149 | 1.59k | if (!strncmp(imgdata.lens.LensSerial, "----", 4)) |
150 | 238 | imgdata.lens.LensSerial[0] = '\0'; |
151 | 1.59k | break; |
152 | 990 | case 0xa420: /* 42016, ImageUniqueID */ |
153 | 990 | stmread(imgdata.color.ImageUniqueID, len, ifp); |
154 | 990 | break; |
155 | 354 | case 0xc65d: /* 50781, RawDataUniqueID */ |
156 | 354 | imgdata.color.RawDataUniqueID[16] = 0; |
157 | 354 | fread(imgdata.color.RawDataUniqueID, 1, 16, ifp); |
158 | 354 | break; |
159 | 750 | case 0xc630: // DNG LensInfo, Lens Specification per EXIF standard |
160 | 750 | imgdata.lens.dng.MinFocal = getrealf(type); |
161 | 750 | imgdata.lens.dng.MaxFocal = getrealf(type); |
162 | 750 | imgdata.lens.dng.MaxAp4MinFocal = getrealf(type); |
163 | 750 | imgdata.lens.dng.MaxAp4MaxFocal = getrealf(type); |
164 | 750 | break; |
165 | 854 | case 0xc68b: /* 50827, OriginalRawFileName */ |
166 | 854 | stmread(imgdata.color.OriginalRawFileName, len, ifp); |
167 | 854 | break; |
168 | 1.41k | case 0xa433: // LensMake |
169 | 1.41k | stmread(imgdata.lens.LensMake, len, ifp); |
170 | 1.41k | break; |
171 | 1.79k | case 0xa434: // LensModel |
172 | 1.79k | stmread(imgdata.lens.Lens, len, ifp); |
173 | 1.79k | if (!strncmp(imgdata.lens.Lens, "----", 4)) |
174 | 1.21k | imgdata.lens.Lens[0] = '\0'; |
175 | 1.79k | break; |
176 | 4.56k | case 0x9205: |
177 | 4.56k | imgdata.lens.EXIF_MaxAp = libraw_powf64l(2.0f, getrealf(type) / 2.0f); |
178 | 4.56k | break; |
179 | 7.14k | case 0x829a: // 33434 |
180 | 7.14k | shutter = getrealf(type); |
181 | 7.14k | if (tiff_nifds > 0 && tiff_nifds <= LIBRAW_IFD_MAXCOUNT) |
182 | 7.14k | tiff_ifd[tiff_nifds - 1].t_shutter = shutter; |
183 | 7.14k | break; |
184 | 6.92k | case 0x829d: // 33437, FNumber |
185 | 6.92k | aperture = getrealf(type); |
186 | 6.92k | break; |
187 | 5.47k | case 0x8827: // 34855 |
188 | 5.47k | iso_speed = get2(); |
189 | 5.47k | break; |
190 | 412 | case 0x8831: // 34865 |
191 | 412 | if (iso_speed == 0xffff && !strncasecmp(make, "FUJI", 4)) |
192 | 36 | iso_speed = getrealf(type); |
193 | 412 | break; |
194 | 518 | case 0x8832: // 34866 |
195 | 518 | if (iso_speed == 0xffff && |
196 | 180 | (!strncasecmp(make, "SONY", 4) || !strncasecmp(make, "CANON", 5))) |
197 | 108 | iso_speed = getrealf(type); |
198 | 518 | break; |
199 | 7.85k | case 0x9003: // 36867 |
200 | 13.0k | case 0x9004: // 36868 |
201 | 13.0k | get_timestamp(0); |
202 | 13.0k | break; |
203 | 4.76k | case 0x9201: // 37377 |
204 | 4.76k | if ((expo = -getreal(type)) < 128 && shutter == 0.) |
205 | 1.78k | { |
206 | 1.78k | shutter = libraw_powf64l(2.0f, float(expo)); |
207 | 1.78k | if (tiff_nifds > 0 && tiff_nifds <= LIBRAW_IFD_MAXCOUNT) |
208 | 1.78k | tiff_ifd[tiff_nifds - 1].t_shutter = shutter; |
209 | 1.78k | } |
210 | 4.76k | break; |
211 | 4.99k | case 0x9202: // 37378 ApertureValue |
212 | 4.99k | if ((fabs(ape = getreal(type)) < 256.0) && (!aperture)) |
213 | 1.25k | aperture = libraw_powf64l(2.0f, float(ape / 2.0)); |
214 | 4.99k | break; |
215 | 14.5k | case 0x9209: // 37385 |
216 | 14.5k | flash_used = getrealf(type); |
217 | 14.5k | break; |
218 | 15.9k | case 0x920a: // 37386 |
219 | 15.9k | focal_len = getrealf(type); |
220 | 15.9k | break; |
221 | 490k | case 0x927c: // 37500 |
222 | 490k | #ifndef USE_6BY9RPI |
223 | 490k | if (((make[0] == '\0') && !strncmp(model, "ov5647", 6)) || |
224 | 490k | (!strncmp(make, "RaspberryPi", 11) && |
225 | 2.06k | (!strncmp(model, "RP_OV5647", 9) || |
226 | 504 | !strncmp(model, "RP_imx219", 9)))) |
227 | | #else |
228 | | if (((make[0] == '\0') && !strncmp(model, "ov5647", 6)) || |
229 | | (!strncmp(make, "RaspberryPi", 11) && |
230 | | (!strncmp(model, "RP_", 3) || !strncmp(model,"imx477",6)))) |
231 | | #endif |
232 | 2.14k | { |
233 | 2.14k | char mn_text[512]; |
234 | 2.14k | char *pos; |
235 | 2.14k | char ccms[512]; |
236 | 2.14k | ushort l; |
237 | 2.14k | float num; |
238 | | |
239 | 2.14k | memset(mn_text, 0, sizeof(mn_text)); |
240 | 2.14k | fgets(mn_text, MIN(len, 511), ifp); |
241 | 2.14k | mn_text[511] = 0; |
242 | | |
243 | 2.14k | pos = strstr(mn_text, "ev="); |
244 | 2.14k | if (pos) |
245 | 72 | imCommon.ExposureCalibrationShift = float(atof(pos + 3)); |
246 | | |
247 | 2.14k | pos = strstr(mn_text, "gain_r="); |
248 | 2.14k | if (pos) |
249 | 180 | cam_mul[0] = float(atof(pos + 7)); |
250 | 2.14k | pos = strstr(mn_text, "gain_b="); |
251 | 2.14k | if (pos) |
252 | 74 | cam_mul[2] = float(atof(pos + 7)); |
253 | 2.14k | if ((cam_mul[0] > 0.001f) && (cam_mul[2] > 0.001f)) |
254 | 372 | cam_mul[1] = cam_mul[3] = 1.0f; |
255 | 1.77k | else |
256 | 1.77k | cam_mul[0] = cam_mul[2] = 0.0f; |
257 | | |
258 | 2.14k | pos = strstr(mn_text, "ccm="); |
259 | 2.14k | if (pos) |
260 | 924 | { |
261 | 924 | pos += 4; |
262 | 924 | char *pos2 = strstr(pos, " "); |
263 | 924 | if (pos2) |
264 | 782 | { |
265 | 782 | l = LIM(ushort(pos2 - pos), 0, 511); |
266 | 782 | memcpy(ccms, pos, l); |
267 | 782 | ccms[l] = '\0'; |
268 | | #ifdef LIBRAW_WIN32_CALLS |
269 | | // Win32 strtok is already thread-safe |
270 | | pos = strtok(ccms, ","); |
271 | | #else |
272 | 782 | char *last = 0; |
273 | 782 | pos = strtok_r(ccms, ",", &last); |
274 | 782 | #endif |
275 | 782 | if (pos) |
276 | 742 | { |
277 | 1.68k | for (l = 0; l < 3; l++) // skip last row |
278 | 1.61k | { |
279 | 1.61k | num = 0.0; |
280 | 4.99k | for (c = 0; c < 3; c++) |
281 | 4.05k | { |
282 | 4.05k | cmatrix[l][c] = (float)atoi(pos); |
283 | 4.05k | num += cmatrix[c][l]; |
284 | | #ifdef LIBRAW_WIN32_CALLS |
285 | | pos = strtok(NULL, ","); |
286 | | #else |
287 | 4.05k | pos = strtok_r(NULL, ",", &last); |
288 | 4.05k | #endif |
289 | 4.05k | if (!pos) |
290 | 668 | goto end; // broken |
291 | 4.05k | } |
292 | 942 | if (num > 0.01) |
293 | 1.20k | FORC3 cmatrix[l][c] = cmatrix[l][c] / num; |
294 | 942 | } |
295 | 742 | } |
296 | 782 | } |
297 | 924 | } |
298 | 2.14k | end:; |
299 | 2.14k | } |
300 | 488k | else if (!strncmp(make, "SONY", 4) && |
301 | 86.1k | (!strncmp(model, "DSC-V3", 6) || !strncmp(model, "DSC-F828", 8))) |
302 | 12.7k | { |
303 | 12.7k | parseSonySRF(len); |
304 | 12.7k | break; |
305 | 12.7k | } |
306 | 475k | else if ((len == 1) && !strncmp(make, "NIKON", 5)) |
307 | 4.16k | { |
308 | 4.16k | c = get4(); |
309 | 4.16k | if (c) |
310 | 3.86k | fseek(ifp, c, SEEK_SET); |
311 | 4.16k | is_NikonTransfer = 1; |
312 | 4.16k | } |
313 | 478k | parse_makernote(base, 0); |
314 | 478k | break; |
315 | 3.53k | case 0xa002: // 40962 |
316 | 3.53k | if (kodak) |
317 | 72 | raw_width = get4(); |
318 | 3.53k | break; |
319 | 3.99k | case 0xa003: // 40963 |
320 | 3.99k | if (kodak) |
321 | 160 | raw_height = get4(); |
322 | 3.99k | break; |
323 | 1.53k | case 0xa302: // 41730 |
324 | 1.53k | if (get4() == 0x20002) |
325 | 1.17k | for (exif_cfa = c = 0; c < 8; c += 2) |
326 | 936 | exif_cfa |= fgetc(ifp) * 0x01010101U << c; |
327 | 10.4M | } |
328 | 10.4M | fseek(ifp, save, SEEK_SET); |
329 | 10.4M | } |
330 | 147k | } |
331 | | |
332 | | void LibRaw::parse_gps_libraw(INT64 base) |
333 | 3.53k | { |
334 | 3.53k | unsigned entries, tag, type, len, c; |
335 | 3.53k | INT64 save; |
336 | | |
337 | 3.53k | entries = get2(); |
338 | 3.53k | if (entries > 40) |
339 | 842 | return; |
340 | 2.68k | if (entries > 0) |
341 | 2.21k | imgdata.other.parsed_gps.gpsparsed = 1; |
342 | 2.68k | INT64 fsize = ifp->size(); |
343 | 39.9k | while (entries--) |
344 | 37.3k | { |
345 | 37.3k | tiff_get(base, &tag, &type, &len, &save); |
346 | 37.3k | if (len > 1024) |
347 | 27.3k | { |
348 | 27.3k | fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! |
349 | 27.3k | continue; // no GPS tags are 1k or larger |
350 | 27.3k | } |
351 | 9.97k | INT64 savepos = ftell(ifp); |
352 | 9.97k | if (len > 8 && savepos + len > fsize * 2) |
353 | 122 | { |
354 | 122 | fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! |
355 | 122 | continue; |
356 | 122 | } |
357 | | |
358 | 9.85k | if (callbacks.exif_cb) |
359 | 0 | { |
360 | 0 | callbacks.exif_cb(callbacks.exifparser_data, tag | 0x50000, type, len, order, ifp, base); |
361 | 0 | fseek(ifp, savepos, SEEK_SET); |
362 | 0 | } |
363 | | |
364 | 9.85k | switch (tag) |
365 | 9.85k | { |
366 | 1.32k | case 0x0001: |
367 | 1.32k | imgdata.other.parsed_gps.latref = getc(ifp); |
368 | 1.32k | break; |
369 | 174 | case 0x0003: |
370 | 174 | imgdata.other.parsed_gps.longref = getc(ifp); |
371 | 174 | break; |
372 | 84 | case 0x0005: |
373 | 84 | imgdata.other.parsed_gps.altref = getc(ifp); |
374 | 84 | break; |
375 | 702 | case 0x0002: |
376 | 702 | if (len == 3) |
377 | 1.63k | FORC(3) imgdata.other.parsed_gps.latitude[c] = getrealf(type); |
378 | 702 | break; |
379 | 186 | case 0x0004: |
380 | 186 | if (len == 3) |
381 | 294 | FORC(3) imgdata.other.parsed_gps.longitude[c] = getrealf(type); |
382 | 186 | break; |
383 | 506 | case 0x0007: |
384 | 506 | if (len == 3) |
385 | 618 | FORC(3) imgdata.other.parsed_gps.gpstimestamp[c] = getrealf(type); |
386 | 506 | break; |
387 | 216 | case 0x0006: |
388 | 216 | imgdata.other.parsed_gps.altitude = getrealf(type); |
389 | 216 | break; |
390 | 100 | case 0x0009: |
391 | 100 | imgdata.other.parsed_gps.gpsstatus = getc(ifp); |
392 | 100 | break; |
393 | 9.85k | } |
394 | 9.83k | fseek(ifp, save, SEEK_SET); |
395 | 9.83k | } |
396 | 2.68k | } |
397 | | |
398 | | void LibRaw::parse_gps(INT64 base) |
399 | 3.56k | { |
400 | 3.56k | unsigned entries, tag, type, len, c; |
401 | 3.56k | INT64 save; |
402 | | |
403 | 3.56k | entries = get2(); |
404 | 3.56k | if (entries > 40) |
405 | 1.24k | return; |
406 | 33.8k | while (entries--) |
407 | 31.5k | { |
408 | 31.5k | tiff_get(base, &tag, &type, &len, &save); |
409 | 31.5k | if (len > 1024) |
410 | 23.1k | { |
411 | 23.1k | fseek(ifp, save, SEEK_SET); // Recover tiff-read position!! |
412 | 23.1k | continue; // no GPS tags are 1k or larger |
413 | 23.1k | } |
414 | 8.44k | switch (tag) |
415 | 8.44k | { |
416 | 1.27k | case 0x0001: |
417 | 1.47k | case 0x0003: |
418 | 1.55k | case 0x0005: |
419 | 1.55k | gpsdata[29 + tag / 2] = getc(ifp); |
420 | 1.55k | break; |
421 | 682 | case 0x0002: |
422 | 764 | case 0x0004: |
423 | 1.12k | case 0x0007: |
424 | 6.75k | FORC(6) gpsdata[tag / 3 * 6 + c] = get4(); |
425 | 1.12k | break; |
426 | 84 | case 0x0006: |
427 | 168 | FORC(2) gpsdata[18 + c] = get4(); |
428 | 84 | break; |
429 | 102 | case 0x0012: // 18 |
430 | 236 | case 0x001d: // 29 |
431 | 236 | fgets((char *)(gpsdata + 14 + tag / 3), MIN(len, 12), ifp); |
432 | 8.44k | } |
433 | 8.41k | fseek(ifp, save, SEEK_SET); |
434 | 8.41k | } |
435 | 2.32k | } |