comparison src/exif.c @ 9:d907d608745f

Sync to GQview 1.5.9 release. ######## DO NOT BASE ENHANCEMENTS OR TRANSLATION UPDATES ON CODE IN THIS CVS! This CVS is never up to date with current development and is provided solely for reference purposes, please use the latest official release package when making any changes or translation updates. ########
author gqview
date Sat, 26 Feb 2005 00:13:35 +0000
parents
children ee03f36e9e4b
comparison
equal deleted inserted replaced
8:e0d0593d519e 9:d907d608745f
1 /*
2 * GQView
3 * (C) 2004 John Ellis
4 *
5 * Authors:
6 * Support for Exif file format, originally written by Eric Swalens.
7 * Modified by Quy Tonthat
8 *
9 * Reimplemented with generic data storage by John Ellis (Nov 2003)
10 *
11 * The tags were added with information from the FREE document:
12 * http://www.ba.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html
13 *
14 * For the official Exif Format, please refer to:
15 * http://www.exif.org
16 * http://www.exif.org/specifications.html (PDF spec sheets)
17 *
18 * Notes:
19 * Additional tag formats should be added to the proper
20 * location in ExifKnownMarkersList[].
21 *
22 * Human readable ouput (that needs additional processing of data to
23 * be useable) can be defined by adding a key to ExifFormattedList[],
24 * then handling that tag in the function exif_get_formatted_by_key().
25 * The human readable formatted keys must begin with the character 'f'.
26 *
27 * Unsupported at this time:
28 * IFD1 (thumbnail)
29 * MakerNote
30 * GPSInfo
31 *
32 * TODO:
33 * Convert data to useable form in the ??_as_text function for:
34 * ComponentsConfiguration
35 * UserComment (convert this to UTF-8?)
36 *
37
38 This program is free software; you can redistribute it and/or modify
39 it under the terms of the GNU General Public License as published by
40 the Free Software Foundation; either version 2 of the License, or
41 (at your option) any later version.
42
43 This program is distributed in the hope that it will be useful,
44 but WITHOUT ANY WARRANTY; without even the implied warranty of
45 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46 GNU General Public License for more details.
47
48 You should have received a copy of the GNU General Public License
49 along with this program; if not, write to the Free Software
50 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
51 */
52
53 #ifdef HAVE_CONFIG_H
54 # include "config.h"
55 #endif
56
57 #include <stdio.h>
58 #include <inttypes.h> /* stdint.h is not available on all systems... */
59 #include <string.h>
60 #include <fcntl.h>
61 #include <unistd.h>
62 #include <sys/types.h>
63 #include <sys/stat.h>
64 #include <sys/mman.h>
65 #include <math.h>
66
67 #include <glib.h>
68
69 #include "intl.h"
70
71 #include "exif.h"
72
73 #include "ui_fileops.h"
74
75
76 /*
77 *-----------------------------------------------------------------------------
78 * Tag formats
79 *-----------------------------------------------------------------------------
80 */
81
82 ExifFormatAttrib ExifFormatList[] = {
83 { EXIF_FORMAT_UNKNOWN, 1, "unknown", "unknown" },
84 { EXIF_FORMAT_BYTE_UNSIGNED, 1, "ubyte", "unsigned byte" },
85 { EXIF_FORMAT_STRING, 1, "string", "string" },
86 { EXIF_FORMAT_SHORT_UNSIGNED, 2, "ushort", "unsigned short" },
87 { EXIF_FORMAT_LONG_UNSIGNED, 4, "ulong", "unsigned long" },
88 { EXIF_FORMAT_RATIONAL_UNSIGNED,8, "urational", "unsigned rational" },
89 { EXIF_FORMAT_BYTE, 1, "byte", "byte" },
90 { EXIF_FORMAT_UNDEFINED, 1, "undefined", "undefined" },
91 { EXIF_FORMAT_SHORT, 2, "sshort", "signed short" },
92 { EXIF_FORMAT_LONG, 4, "slong", "signed long" },
93 { EXIF_FORMAT_RATIONAL, 8, "srational", "signed rational" },
94 { EXIF_FORMAT_FLOAT, 4, "float", "float" },
95 { EXIF_FORMAT_DOUBLE, 8, "double", "double" },
96 { -1, 0, NULL }
97 };
98
99 /* tags that are special, or need special treatment */
100 #define TAG_EXIFOFFSET 0x8769
101
102
103 /*
104 *-----------------------------------------------------------------------------
105 * Data
106 *-----------------------------------------------------------------------------
107 */
108
109 #define EXIF_TEXT_LIST_END { -1, NULL }
110
111 static ExifTextList ExifOrientationList[] = {
112 { EXIF_ORIENTATION_UNKNOWN, N_("unknown") },
113 { EXIF_ORIENTATION_TOP_LEFT, N_("top left") },
114 { EXIF_ORIENTATION_TOP_RIGHT, N_("top right") },
115 { EXIF_ORIENTATION_BOTTOM_RIGHT,N_("bottom right") },
116 { EXIF_ORIENTATION_BOTTOM_LEFT, N_("bottom left") },
117 { EXIF_ORIENTATION_LEFT_TOP, N_("left top") },
118 { EXIF_ORIENTATION_RIGHT_TOP, N_("right top") },
119 { EXIF_ORIENTATION_RIGHT_BOTTOM,N_("right bottom") },
120 { EXIF_ORIENTATION_LEFT_BOTTOM, N_("left bottom") },
121 EXIF_TEXT_LIST_END
122 };
123
124 static ExifTextList ExifUnitList[] = {
125 { EXIF_UNIT_UNKNOWN, N_("unknown") },
126 { EXIF_UNIT_NOUNIT, "" },
127 { EXIF_UNIT_INCH, N_("inch") },
128 { EXIF_UNIT_CENTIMETER, N_("centimeter") },
129 EXIF_TEXT_LIST_END
130 };
131
132 static ExifTextList ExifYCbCrPosList[] = {
133 { 1, "center" },
134 { 2, "datum" },
135 EXIF_TEXT_LIST_END
136 };
137
138 static ExifTextList ExifMeteringModeList[] = {
139 { 0, N_("unknown") },
140 { 1, N_("average") },
141 { 2, N_("center weighted") },
142 { 3, N_("spot") },
143 { 4, N_("multi-spot") },
144 { 5, N_("multi-segment") },
145 { 6, N_("partial") },
146 { 255, N_("other") },
147 EXIF_TEXT_LIST_END
148 };
149
150 static ExifTextList ExifExposureProgramList[] = {
151 { 0, N_("not defined") },
152 { 1, N_("manual") },
153 { 2, N_("normal") },
154 { 3, N_("aperture") },
155 { 4, N_("shutter") },
156 { 5, N_("creative") },
157 { 6, N_("action") },
158 { 7, N_("portrait") },
159 { 8, N_("landscape") },
160 EXIF_TEXT_LIST_END
161 };
162
163 static ExifTextList ExifLightSourceList[] = {
164 { 0, N_("unknown") },
165 { 1, N_("daylight") },
166 { 2, N_("fluorescent") },
167 { 3, N_("tungsten (incandescent)") },
168 { 4, N_("flash") },
169 { 9, "fine weather" },
170 { 10, "cloudy weather" },
171 { 11, "shade" },
172 { 12, "daylight fluorescent" },
173 { 13, "day white fluorescent" },
174 { 14, "cool white fluorescent" },
175 { 15, "while fluorescent" },
176 { 17, "standard light A" },
177 { 18, "standard light B" },
178 { 19, "standard light C" },
179 { 20, "D55" },
180 { 21, "D65" },
181 { 22, "D75" },
182 { 23, "D50" },
183 { 24, "ISO studio tungsten" },
184 { 255, N_("other") },
185 EXIF_TEXT_LIST_END
186 };
187
188 static ExifTextList ExifFlashList[] = {
189 { 0, N_("no") },
190 { 1, N_("yes") },
191 { 5, N_("yes, not detected by strobe") },
192 { 7, N_("yes, detected by strobe") },
193 EXIF_TEXT_LIST_END
194 };
195
196 static ExifTextList ExifColorSpaceList[] = {
197 { 1, "sRGB" },
198 { 65535,"uncalibrated" },
199 EXIF_TEXT_LIST_END
200 };
201
202 static ExifTextList ExifSensorList[] = {
203 { 1, "not defined" },
204 { 2, "1 chip color area" },
205 { 2, "2 chip color area" },
206 { 4, "3 chip color area" },
207 { 5, "color sequential area" },
208 { 7, "trilinear" },
209 { 8, "color sequential linear" },
210 EXIF_TEXT_LIST_END
211 };
212
213 static ExifTextList ExifSourceList[] = {
214 { 3, "digital still camera" },
215 EXIF_TEXT_LIST_END
216 };
217
218 static ExifTextList ExifSceneList[] = {
219 { 1, "direct photo" },
220 EXIF_TEXT_LIST_END
221 };
222
223 static ExifTextList ExifCustRenderList[] = {
224 { 0, "normal" },
225 { 1, "custom" },
226 EXIF_TEXT_LIST_END
227 };
228
229 static ExifTextList ExifExposureModeList[] = {
230 { 0, "auto" },
231 { 1, "manual" },
232 { 2, "auto bracket" },
233 EXIF_TEXT_LIST_END
234 };
235
236 static ExifTextList ExifWhiteBalanceList[] = {
237 { 0, "auto" },
238 { 1, "manual" },
239 EXIF_TEXT_LIST_END
240 };
241
242 static ExifTextList ExifSceneCaptureList[] = {
243 { 0, "standard" },
244 { 1, "landscape" },
245 { 2, "portrait" },
246 { 3, "night scene" },
247 EXIF_TEXT_LIST_END
248 };
249
250 static ExifTextList ExifGainControlList[] = {
251 { 0, "none" },
252 { 1, "low gain up" },
253 { 2, "high gain up" },
254 { 3, "low gain down" },
255 { 4, "high gain down" },
256 EXIF_TEXT_LIST_END
257 };
258
259 static ExifTextList ExifContrastList[] = {
260 { 0, "normal" },
261 { 1, "soft" },
262 { 2, "hard" },
263 EXIF_TEXT_LIST_END
264 };
265
266 static ExifTextList ExifSaturationList[] = {
267 { 0, "normal" },
268 { 1, "low" },
269 { 2, "high" },
270 EXIF_TEXT_LIST_END
271 };
272
273 static ExifTextList ExifSharpnessList[] = {
274 { 0, "normal" },
275 { 1, "soft" },
276 { 2, "hard" },
277 EXIF_TEXT_LIST_END
278 };
279
280 static ExifTextList ExifSubjectRangeList[] = {
281 { 0, "unknown" },
282 { 1, "macro" },
283 { 2, "close" },
284 { 3, "distant" },
285 EXIF_TEXT_LIST_END
286 };
287
288 ExifMarker ExifKnownMarkersList[] = {
289 { 0x010e, EXIF_FORMAT_STRING, -1, "ImageDescription", N_("Image description"), NULL },
290 { 0x010f, EXIF_FORMAT_STRING, -1, "Make", "Camera make", NULL },
291 { 0x0110, EXIF_FORMAT_STRING, -1, "Model", "Camera model", NULL },
292 { 0x0112, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Orientation", N_("Orientation"), ExifOrientationList },
293 { 0x011a, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "XResolution", "X resolution", NULL },
294 { 0x011b, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "YResolution", "Y Resolution", NULL },
295 { 0x0128, EXIF_FORMAT_SHORT_UNSIGNED, 1, "ResolutionUnit", "Resolution units", ExifUnitList },
296 { 0x0131, EXIF_FORMAT_STRING, -1, "Software", "Firmware", NULL },
297 { 0x0132, EXIF_FORMAT_STRING, 20, "DateTime", N_("Date"), NULL },
298 { 0x013e, EXIF_FORMAT_RATIONAL_UNSIGNED, 2, "WhitePoint", "White point", NULL },
299 { 0x013f, EXIF_FORMAT_RATIONAL_UNSIGNED, 6, "PrimaryChromaticities","Primary chromaticities", NULL },
300 { 0x0211, EXIF_FORMAT_RATIONAL_UNSIGNED, 3, "YCbCrCoefficients", "YCbCy coefficients", NULL },
301 { 0x0213, EXIF_FORMAT_SHORT_UNSIGNED, 1, "YCbCrPositioning", "YCbCr positioning", ExifYCbCrPosList },
302 { 0x0214, EXIF_FORMAT_RATIONAL_UNSIGNED, 6, "ReferenceBlackWhite", "Black white reference", NULL },
303 { 0x8298, EXIF_FORMAT_STRING, -1, "Copyright", N_("Copyright"), NULL },
304 { 0x8769, EXIF_FORMAT_LONG_UNSIGNED, 1, "ExifOffset", "SubIFD Exif offset", NULL },
305 /* subIFD follows */
306 { 0x829a, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "ExposureTime", "Exposure time (seconds)", NULL },
307 { 0x829d, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "FNumber", "FNumber", NULL },
308 { 0x8822, EXIF_FORMAT_SHORT_UNSIGNED, 1, "ExposureProgram", N_("Exposure program"), ExifExposureProgramList },
309 { 0x8824, EXIF_FORMAT_STRING, -1, "SpectralSensitivity", "Spectral Sensitivity", NULL },
310 { 0x8827, EXIF_FORMAT_SHORT_UNSIGNED, -1, "ISOSpeedRatings", N_("ISO sensitivity"), NULL },
311 { 0x8828, EXIF_FORMAT_UNDEFINED, -1, "OECF", "Optoelectric conversion factor", NULL },
312 { 0x9000, EXIF_FORMAT_UNDEFINED, 4, "ExifVersion", "Exif version", NULL },
313 { 0x9003, EXIF_FORMAT_STRING, 20, "DateTimeOriginal", N_("Date original"), NULL },
314 { 0x9004, EXIF_FORMAT_STRING, 20, "DateTimeDigitized", N_("Date digitized"), NULL },
315 { 0x9101, EXIF_FORMAT_UNDEFINED, -1, "ComponentsConfiguration","Pixel format", NULL },
316 { 0x9102, EXIF_FORMAT_RATIONAL_UNSIGNED,1, "CompressedBitsPerPixel","Compression ratio", NULL },
317 { 0x9201, EXIF_FORMAT_RATIONAL, 1, "ShutterSpeedValue", N_("Shutter speed"), NULL },
318 { 0x9202, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "ApertureValue", N_("Aperture"), NULL },
319 { 0x9203, EXIF_FORMAT_RATIONAL, 1, "BrightnessValue", "Brightness", NULL },
320 { 0x9204, EXIF_FORMAT_RATIONAL, 1, "ExposureBiasValue", N_("Exposure bias"), NULL },
321 { 0x9205, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "MaxApertureValue", "Maximum aperture", NULL },
322 { 0x9206, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "SubjectDistance", N_("Subject distance"), NULL },
323 { 0x9207, EXIF_FORMAT_SHORT_UNSIGNED, 1, "MeteringMode", N_("Metering mode"), ExifMeteringModeList },
324 { 0x9208, EXIF_FORMAT_SHORT_UNSIGNED, 1, "LightSource", N_("Light source"), ExifLightSourceList },
325 { 0x9209, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Flash", N_("Flash"), ExifFlashList },
326 { 0x920a, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "FocalLength", N_("Focal length"), NULL },
327 { 0x9214, EXIF_FORMAT_SHORT_UNSIGNED, -1, "SubjectArea", "Subject area", NULL },
328 { 0x927c, EXIF_FORMAT_UNDEFINED, -1, "MakerNote", "MakerNote", NULL },
329 { 0x9286, EXIF_FORMAT_UNDEFINED, -1, "UserComment", "UserComment", NULL },
330 { 0x9290, EXIF_FORMAT_STRING, -1, "SubsecTime", "Subsecond time", NULL },
331 { 0x9291, EXIF_FORMAT_STRING, -1, "SubsecTimeOriginal", "Subsecond time original", NULL },
332 { 0x9292, EXIF_FORMAT_STRING, -1, "SubsecTimeDigitized", "Subsecond time digitized", NULL },
333 { 0xa000, EXIF_FORMAT_UNDEFINED, 4, "FlashPixVersion", "FlashPix version", NULL },
334 { 0xa001, EXIF_FORMAT_SHORT_UNSIGNED, 1, "ColorSpace", "Colorspace", ExifColorSpaceList },
335 /* ExifImageWidth, ExifImageHeight can also be unsigned short */
336 { 0xa002, EXIF_FORMAT_LONG_UNSIGNED, 1, "ExifImageWidth", N_("Width"), NULL },
337 { 0xa003, EXIF_FORMAT_LONG_UNSIGNED, 1, "ExifImageHeight", N_("Height"), NULL },
338 { 0xa004, EXIF_FORMAT_STRING, -1, "RelatedSoundFile", "Audio data", NULL },
339 { 0xa005, EXIF_FORMAT_LONG_UNSIGNED, 1, "ExifInteroperabilityOffset", "ExifR98 extension", NULL },
340 { 0xa20b, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "FlashEnergy", "Flash strength", NULL },
341 { 0xa20c, EXIF_FORMAT_SHORT_UNSIGNED, 1, "SpatialFrequencyResponse","Spatial frequency response", NULL },
342 { 0xa20e, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "FocalPlaneXResolution", "X Pixel density", NULL },
343 { 0xa20f, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "FocalPlaneYResolution", "Y Pixel density", NULL },
344 { 0xa210, EXIF_FORMAT_SHORT_UNSIGNED, 1, "FocalPlaneResolutionUnit", "Pixel density units", ExifUnitList },
345 { 0x0214, EXIF_FORMAT_SHORT_UNSIGNED, 2, "SubjectLocation", "Subject location", NULL },
346 { 0xa215, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "ExposureIndex", N_("ISO sensitivity"), NULL },
347 { 0xa217, EXIF_FORMAT_SHORT_UNSIGNED, -1, "SensingMethod", "Sensor type", ExifSensorList },
348 { 0xa300, EXIF_FORMAT_UNDEFINED, 1, "FileSource", "Source type", ExifSourceList },
349 { 0xa301, EXIF_FORMAT_UNDEFINED, 1, "SceneType", "Scene type", ExifSceneList },
350 { 0xa302, EXIF_FORMAT_UNDEFINED, -1, "CFAPattern", "Color filter array pattern", NULL },
351 /* tags a4xx were added for Exif 2.2 (not just these - some above, as well) */
352 { 0xa401, EXIF_FORMAT_SHORT_UNSIGNED, 1, "CustomRendered", "Render process", ExifCustRenderList },
353 { 0xa402, EXIF_FORMAT_SHORT_UNSIGNED, 1, "ExposureMode", "Exposure mode", ExifExposureModeList },
354 { 0xa403, EXIF_FORMAT_SHORT_UNSIGNED, 1, "WhiteBalance", "White balance", ExifWhiteBalanceList },
355 { 0xa404, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "DigitalZoomRatio", "Digital zoom ratio", NULL },
356 { 0xa405, EXIF_FORMAT_SHORT_UNSIGNED, 1, "FocalLength35mmFilm", "Focal length (35mm)", NULL },
357 { 0xa406, EXIF_FORMAT_SHORT_UNSIGNED, 1, "SceneCapturetype", "Scene capture type", ExifSceneCaptureList },
358 { 0xa407, EXIF_FORMAT_SHORT_UNSIGNED, 1, "GainControl", "Gain control", ExifGainControlList },
359 { 0xa408, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Contrast", "Contrast", ExifContrastList },
360 { 0xa409, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Saturation", "Saturation", ExifSaturationList },
361 { 0xa40a, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Sharpness", "Sharpness", ExifSharpnessList },
362 { 0xa40b, EXIF_FORMAT_UNDEFINED, -1, "DeviceSettingDescription","Device setting", NULL },
363 { 0xa40c, EXIF_FORMAT_SHORT_UNSIGNED, 1, "SubjectDistanceRange", "Subject range", ExifSubjectRangeList },
364 { 0xa420, EXIF_FORMAT_STRING, -1, "ImageUniqueID", "Image serial number", NULL },
365 /* place known, but undocumented or lesser used tags here */
366 { 0x00fe, EXIF_FORMAT_LONG_UNSIGNED, 1, "NewSubfileType", NULL, NULL },
367 { 0x00ff, EXIF_FORMAT_SHORT_UNSIGNED, 1, "SubfileType", NULL, NULL },
368 { 0x012d, EXIF_FORMAT_SHORT_UNSIGNED, 3, "TransferFunction", NULL, NULL },
369 { 0x013b, EXIF_FORMAT_STRING, -1, "Artist", "Artist", NULL },
370 { 0x013d, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Predictor", NULL, NULL },
371 { 0x0142, EXIF_FORMAT_SHORT_UNSIGNED, 1, "TileWidth", NULL, NULL },
372 { 0x0143, EXIF_FORMAT_SHORT_UNSIGNED, 1, "TileLength", NULL, NULL },
373 { 0x0144, EXIF_FORMAT_LONG_UNSIGNED, -1, "TileOffsets", NULL, NULL },
374 { 0x0145, EXIF_FORMAT_SHORT_UNSIGNED, -1, "TileByteCounts", NULL, NULL },
375 { 0x014a, EXIF_FORMAT_LONG_UNSIGNED, -1, "SubIFDs", NULL, NULL },
376 { 0x015b, EXIF_FORMAT_UNDEFINED, -1, "JPEGTables", NULL, NULL },
377 { 0x828d, EXIF_FORMAT_SHORT_UNSIGNED, 2, "CFARepeatPatternDim", NULL, NULL },
378 { 0x828e, EXIF_FORMAT_BYTE_UNSIGNED, -1, "CFAPattern", NULL, NULL },
379 { 0x828f, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "BatteryLevel", NULL, NULL },
380 { 0x83bb, EXIF_FORMAT_LONG_UNSIGNED, -1, "IPTC/NAA", NULL, NULL },
381 { 0x8773, EXIF_FORMAT_UNDEFINED, -1, "InterColorProfile", NULL, NULL },
382 { 0x8825, EXIF_FORMAT_LONG_UNSIGNED, 1, "GPSInfo", "SubIFD GPS offset", NULL },
383 { 0x8829, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Interlace", NULL, NULL },
384 { 0x882a, EXIF_FORMAT_SHORT, 1, "TimeZoneOffset", NULL, NULL },
385 { 0x882b, EXIF_FORMAT_SHORT_UNSIGNED, 1, "SelfTimerMode", NULL, NULL },
386 { 0x920b, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "FlashEnergy", NULL, NULL },
387 { 0x920c, EXIF_FORMAT_UNDEFINED, -1, "SpatialFrequencyResponse", NULL, NULL },
388 { 0x920d, EXIF_FORMAT_UNDEFINED, -1, "Noise", NULL, NULL },
389 { 0x9211, EXIF_FORMAT_LONG_UNSIGNED, 1, "ImageNumber", NULL, NULL },
390 { 0x9212, EXIF_FORMAT_STRING, 1, "SecurityClassification", NULL, NULL },
391 { 0x9213, EXIF_FORMAT_STRING, -1, "ImageHistory", NULL, NULL },
392 { 0x9215, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "ExposureIndex", NULL, NULL },
393 { 0x9216, EXIF_FORMAT_BYTE_UNSIGNED, 4, "TIFF/EPStandardID", NULL, NULL },
394
395 /* end is marked by 0 tag */
396 { 0x0000, EXIF_FORMAT_UNKNOWN, 0, NULL, NULL, NULL }
397 };
398
399 ExifMarker ExifUnknownMarkersList[] = {
400 { 0x0000, EXIF_FORMAT_UNKNOWN, 0, "unknown", NULL, NULL },
401 { 0x0000, EXIF_FORMAT_BYTE_UNSIGNED, -1, "unknown", NULL, NULL },
402 { 0x0000, EXIF_FORMAT_STRING, -1, "unknown", NULL, NULL },
403 { 0x0000, EXIF_FORMAT_SHORT_UNSIGNED, -1, "unknown", NULL, NULL },
404 { 0x0000, EXIF_FORMAT_LONG_UNSIGNED, -1, "unknown", NULL, NULL },
405 { 0x0000, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "unknown", NULL, NULL },
406 { 0x0000, EXIF_FORMAT_BYTE, -1, "unknown", NULL, NULL },
407 { 0x0000, EXIF_FORMAT_UNDEFINED, -1, "unknown", NULL, NULL },
408 { 0x0000, EXIF_FORMAT_SHORT, -1, "unknown", NULL, NULL },
409 { 0x0000, EXIF_FORMAT_LONG, -1, "unknown", NULL, NULL },
410 { 0x0000, EXIF_FORMAT_RATIONAL, -1, "unknown", NULL, NULL },
411 { 0x0000, EXIF_FORMAT_FLOAT, -1, "unknown", NULL, NULL },
412 { 0x0000, EXIF_FORMAT_DOUBLE, -1, "unknown", NULL, NULL },
413 };
414
415 /* human readable key list */
416
417 ExifFormattedText ExifFormattedList[] = {
418 { "fCamera", N_("Camera") },
419 { "fDateTime", N_("Date") },
420 { "fShutterSpeed", N_("Shutter speed") },
421 { "fAperture", N_("Aperture") },
422 { "fExposureBias", N_("Exposure bias") },
423 { "fISOSpeedRating", N_("ISO sensitivity") },
424 { "fFocalLength", N_("Focal length") },
425 { "fSubjectDistance", N_("Subject distance") },
426 { "fFlash", N_("Flash") },
427 { "fResolution", N_("Resolution") },
428 { NULL, NULL }
429 };
430
431
432 /*
433 *-----------------------------------------------------------------------------
434 * misc
435 *-----------------------------------------------------------------------------
436 */
437
438 #define BYTE_ORDER_INTEL 1
439 #define BYTE_ORDER_MOTOROLA 2
440
441 #define MARKER_UNKNOWN 0x00
442 #define MARKER_SOI 0xD8
443 #define MARKER_APP1 0xE1
444
445 typedef struct {
446 char byte_order[2];
447 uint16_t magic;
448 uint32_t IFD_offset;
449 } TIFFHeader;
450
451 typedef struct {
452 uint16_t tag;
453 uint16_t format;
454 uint32_t nb;
455 uint32_t data;
456 } IFDEntry;
457
458
459 static ExifMarker *exif_marker_from_tag(uint16_t tag);
460 static int parse_IFD_table(ExifData *exif, unsigned char *tiff, int offset,
461 int size, int byte_order);
462
463 /*
464 *-----------------------------------------------------------------------------
465 * ExifItem
466 *-----------------------------------------------------------------------------
467 */
468
469 static ExifItem *exif_item_new(ExifFormatType format, unsigned int tag, unsigned int elements, ExifMarker *marker)
470 {
471 ExifItem *item;
472
473 item = g_new0(ExifItem, 1);
474 item->format = format;
475 item->tag = tag;
476 item->marker = marker;
477 item->elements = elements;
478 item->data = NULL;
479 item->data_len = 0;
480
481 switch (format)
482 {
483 case EXIF_FORMAT_UNKNOWN:
484 /* unknown, data is NULL */
485 return item;
486 break;
487 case EXIF_FORMAT_BYTE_UNSIGNED:
488 item->data_len = sizeof(char) * elements;
489 break;
490 case EXIF_FORMAT_STRING:
491 item->data_len = sizeof(char) * elements;
492 break;
493 case EXIF_FORMAT_SHORT_UNSIGNED:
494 item->data_len = sizeof(unsigned short int) * elements;
495 break;
496 case EXIF_FORMAT_LONG_UNSIGNED:
497 item->data_len = sizeof(unsigned long int) * elements;
498 break;
499 case EXIF_FORMAT_RATIONAL_UNSIGNED:
500 item->data_len = sizeof(ExifRational) * elements;
501 break;
502 case EXIF_FORMAT_BYTE:
503 item->data_len = sizeof(char) * elements;
504 break;
505 case EXIF_FORMAT_UNDEFINED:
506 item->data_len = sizeof(char) * elements;
507 break;
508 case EXIF_FORMAT_SHORT:
509 item->data_len = sizeof(short int) * elements;
510 break;
511 case EXIF_FORMAT_LONG:
512 item->data_len = sizeof(long int) * elements;
513 break;
514 case EXIF_FORMAT_RATIONAL:
515 item->data_len = sizeof(ExifRational) * elements;
516 break;
517 case EXIF_FORMAT_FLOAT:
518 item->data_len = sizeof(float) * elements;
519 break;
520 case EXIF_FORMAT_DOUBLE:
521 item->data_len = sizeof(double) * elements;
522 break;
523 }
524
525 item->data = g_malloc0(item->data_len);
526
527 return item;
528 }
529
530 static void exif_item_free(ExifItem *item)
531 {
532 if (!item) return;
533
534 g_free(item->data);
535 g_free(item);
536 }
537
538 const char *exif_item_get_tag_name(ExifItem *item)
539 {
540 if (!item || !item->marker) return NULL;
541 return item->marker->key;
542 }
543
544 const char *exif_item_get_description(ExifItem *item)
545 {
546 if (!item || !item->marker) return NULL;
547 return _(item->marker->description);
548 }
549
550 const char *exif_item_get_format_name(ExifItem *item, gint brief)
551 {
552 if (!item || !item->marker) return NULL;
553 return (brief) ? ExifFormatList[item->format].short_name : ExifFormatList[item->format].description;
554 }
555
556
557 #define UNDEFINED_TEXT_BYTE_COUNT 16
558
559 static GString *string_append_raw_bytes(GString *string, gpointer data, gint ne)
560 {
561 gint i;
562
563 for (i = 0 ; i < ne && i < UNDEFINED_TEXT_BYTE_COUNT; i++)
564 {
565 unsigned char c = ((char *)data)[i];
566 if (c < 32 || c > 127) c = '.';
567 g_string_append_printf(string, "%c", c);
568 }
569 string = g_string_append(string, " : ");
570 for (i = 0 ; i < ne && i < UNDEFINED_TEXT_BYTE_COUNT; i++)
571 {
572 const gchar *spacer;
573 if (i > 0)
574 {
575 if (i%8 == 0)
576 {
577 spacer = " - ";
578 }
579 else
580 {
581 spacer = " ";
582 }
583 }
584 else
585 {
586 spacer = "";
587 }
588 g_string_append_printf(string, "%s%02x", spacer, ((char *)data)[i]);
589 }
590 if (i >= UNDEFINED_TEXT_BYTE_COUNT) g_string_append_printf(string, " (%d bytes)", ne);
591
592 return string;
593 }
594
595 static gchar *text_list_find_value(ExifTextList *list, gint value)
596 {
597 gchar *result = NULL;
598 gint i;
599
600 i = 0;
601 while (!result && list[i].value >= 0)
602 {
603 if (value == list[i].value) result = g_strdup(_(list[i].description));
604 i++;
605 }
606 if (!result) result = g_strdup_printf("%d (%s)", value, _("unknown"));
607
608 return result;
609 }
610
611 /*
612 *-------------------------------------------------------------------
613 * byte size utils
614 *-------------------------------------------------------------------
615 */
616
617 static uint16_t get_int16(unsigned char *f, int bo)
618 {
619 if (bo == BYTE_ORDER_INTEL)
620 return *f + (*(f+1)<<8);
621 else
622 return ((*f)<<8) + *(f+1);
623 }
624
625 #if 0
626 /* not used ? */
627 static uint32_t get_int32(unsigned char *f, int bo)
628 {
629 if (bo == BYTE_ORDER_INTEL)
630 return get_int16(f, BYTE_ORDER_INTEL) + (get_int16(f+2, BYTE_ORDER_INTEL)<<16);
631 else
632 return (get_int16(f, BYTE_ORDER_MOTOROLA)<<16) + get_int16(f+2, BYTE_ORDER_MOTOROLA);
633 }
634 #endif
635
636 static uint16_t swab_int16(uint16_t n, int bo)
637 {
638 #if BYTE_ORDER == LITTLE_ENDIAN
639 if (bo == BYTE_ORDER_MOTOROLA)
640 #else
641 if (bo == BYTE_ORDER_INTEL)
642 #endif
643 return n>>8 | n<<8 ;
644 else
645 return n;
646 }
647
648 static uint32_t swab_int32(uint32_t n, int bo)
649 {
650 #if BYTE_ORDER == LITTLE_ENDIAN
651 if (bo == BYTE_ORDER_MOTOROLA)
652 #else
653 if (bo == BYTE_ORDER_INTEL)
654 #endif
655 return n<<24 | n>>24 | (n & 0xFF0000)>>8 | (n & 0xFF00)<<8;
656 else
657 return n;
658 }
659
660 /*
661 *-------------------------------------------------------------------
662 * marker utils
663 *-------------------------------------------------------------------
664 */
665
666 static int get_marker_size(unsigned char *f)
667 {
668 /* Size is always in Motorola byte order */
669 return get_int16(f+2, BYTE_ORDER_MOTOROLA);
670 }
671
672 static int goto_next_marker(unsigned char **f, int *size, int *marker)
673 {
674 int marker_size = 2;
675
676 *marker = MARKER_UNKNOWN;
677
678 /* It is safe to access the marker and its size since we have checked
679 * the SOI and this function guaranties the whole next marker is
680 * available
681 */
682 if (*(*f+1) != MARKER_SOI)
683 {
684 marker_size += get_marker_size(*f);
685 }
686
687 *size -= marker_size;
688
689 /* size should be at least 4, so we can read the marker and its size
690 * and check data are actually available
691 */
692 if (*size < 4) return -1;
693
694 /* Jump to the next marker and be sure it begins with 0xFF
695 */
696 *f += marker_size;
697 if (**f != 0xFF) return -1;
698
699 if (get_marker_size(*f)+2 > *size) return -1;
700
701 *marker = *(*f+1);
702
703 return 0;
704 }
705
706 /*
707 *-------------------------------------------------------------------
708 * IFD utils
709 *-------------------------------------------------------------------
710 */
711
712 static ExifMarker *exif_marker_from_tag(uint16_t tag)
713 {
714 static int len = sizeof(ExifKnownMarkersList)/sizeof(ExifMarker) - 1;
715 int i = 0;
716
717 while (i < len && ExifKnownMarkersList[i].tag != tag)
718 {
719 i++;
720 }
721
722 return (i >= len ? NULL : &ExifKnownMarkersList[i]);
723 }
724
725 static void rational_from_data(ExifRational *r, void *src, int byte_order)
726 {
727 r->num = swab_int32(*(uint32_t*)src, byte_order);
728 r->den = swab_int32(*(uint32_t*)(src + sizeof(uint32_t)), byte_order);
729 }
730
731 static void exif_item_copy_data(ExifItem *item, void *src, int len, ExifFormatType src_format, int byte_order)
732 {
733 int bs;
734 int ne;
735 gpointer dest;
736 int i;
737
738 bs = ExifFormatList[item->format].size;
739 ne = item->elements;
740 dest = item->data;
741
742 if (!dest || len > item->data_len)
743 {
744 printf("exif tag %s data size mismatch\n", exif_item_get_tag_name(item));
745 return;
746 }
747
748 switch (item->format)
749 {
750 case EXIF_FORMAT_UNKNOWN:
751 break;
752 case EXIF_FORMAT_BYTE_UNSIGNED:
753 case EXIF_FORMAT_BYTE:
754 case EXIF_FORMAT_UNDEFINED:
755 memcpy(dest, src, len);
756 break;
757 case EXIF_FORMAT_STRING:
758 memcpy(dest, src, len);
759 /* string is NULL terminated, make sure this is true */
760 if (((char *)dest)[len - 1] != '\0') ((char *)dest)[len - 1] = '\0';
761 break;
762 case EXIF_FORMAT_SHORT_UNSIGNED:
763 case EXIF_FORMAT_SHORT:
764 for (i = 0; i < ne; i++)
765 {
766 ((short *)dest)[i] = swab_int16(*(uint16_t*)(src + i * bs), byte_order);
767 }
768 break;
769 case EXIF_FORMAT_LONG_UNSIGNED:
770 case EXIF_FORMAT_LONG:
771 if (src_format == EXIF_FORMAT_SHORT_UNSIGNED ||
772 src_format == EXIF_FORMAT_SHORT)
773 {
774 /* a short fits into a long, so allow it */
775 int ss;
776
777 ss = ExifFormatList[src_format].size;
778 for (i = 0; i < ne; i++)
779 {
780 ((long *)dest)[i] = (long)swab_int16(*(uint16_t*)(src + i * ss), byte_order);
781 }
782 }
783 else
784 {
785 for (i = 0; i < ne; i++)
786 {
787 ((long *)dest)[i] = swab_int32(*(uint32_t*)(src + i * bs), byte_order);
788 }
789 }
790 break;
791 case EXIF_FORMAT_RATIONAL_UNSIGNED:
792 case EXIF_FORMAT_RATIONAL:
793 for (i = 0; i < ne; i++)
794 {
795 rational_from_data(&((ExifRational *)dest)[i], src + i * bs, byte_order);
796 }
797 break;
798 case EXIF_FORMAT_FLOAT:
799 for (i = 0; i < ne; i++)
800 {
801 ((float *)dest)[i] = swab_int32(*(uint32_t*)(src + i * bs), byte_order);
802 }
803 break;
804 case EXIF_FORMAT_DOUBLE:
805 for (i = 0; i < ne; i++)
806 {
807 ExifRational r;
808
809 rational_from_data(&r, src + i * bs, byte_order);
810 if (r.den) ((double *)dest)[i] = (double)r.num / r.den;
811 }
812 break;
813 }
814 }
815
816 static int parse_IFD_entry(ExifData *exif, unsigned char *tiff, int offset,
817 int size, int byte_order)
818 {
819 IFDEntry *ent = (IFDEntry*)(tiff+offset);
820 uint32_t swabed_data;
821 void *data;
822 int data_len;
823 ExifMarker *marker;
824 ExifItem *item;
825
826 ent->tag = swab_int16(ent->tag, byte_order);
827 ent->format = swab_int16(ent->format, byte_order);
828 ent->nb = swab_int32(ent->nb, byte_order);
829 swabed_data = swab_int32(ent->data, byte_order);
830
831 /* Check tag type. If it does not match, either the format is wrong,
832 * either it is a unknown tag; so it is not really an error.
833 */
834 marker = exif_marker_from_tag(ent->tag);
835 if (!marker)
836 {
837 if (ent->format > EXIF_FORMAT_DOUBLE)
838 {
839 printf("warning: exif tag 0x%4x has invalid format %d\n", ent->tag, ent->format);
840 return 0;
841 }
842 /* allow non recognized tags to be displayed */
843 marker = &ExifUnknownMarkersList[ent->format];
844 }
845 if (marker->format != ent->format)
846 {
847 /* Some cameras got mixed up signed/unsigned_rational
848 * eg KODAK DC4800 on object_distance tag
849 *
850 * FIXME: what exactly is this test trying to do?
851 * ok, so this test is to allow the case of swapped signed/unsigned mismatch to leak through?
852 */
853 if ( !(marker->format == EXIF_FORMAT_RATIONAL_UNSIGNED && ent->format == EXIF_FORMAT_RATIONAL) &&
854 !(marker->format == EXIF_FORMAT_RATIONAL && ent->format == EXIF_FORMAT_RATIONAL_UNSIGNED) &&
855 /* short fits into a long so allow this mismatch
856 * as well (some tags allowed to be unsigned short _or_ unsigned long)
857 */
858 !(marker->format == EXIF_FORMAT_LONG_UNSIGNED && ent->format == EXIF_FORMAT_SHORT_UNSIGNED) )
859 {
860 if (ent->format <= EXIF_FORMAT_DOUBLE)
861 {
862 printf("warning: exif tag %s format mismatch, found %s exif spec requests %s\n",
863 marker->key, ExifFormatList[ent->format].short_name, ExifFormatList[marker->format].short_name);
864 }
865 else
866 {
867 printf("warning: exif tag %s format mismatch, found unknown id %d exif spec requests %d (%s)\n",
868 marker->key, ent->format, marker->format, ExifFormatList[marker->format].short_name);
869 }
870 return 0;
871 }
872 }
873
874 /* Where is the data, is it available?
875 */
876 if (marker->components > 0 && marker->components != ent->nb)
877 {
878 printf("warning: exif tag %s has %d elements, exif spec requests %d\n", marker->key, ent->nb, marker->components);
879 }
880 data_len = ExifFormatList[marker->format].size * ent->nb;
881 if (data_len > sizeof(ent->data))
882 {
883 if (size < swabed_data+data_len)
884 {
885 printf("warning: exif tag %s will overrun IFD segment, ignored.\n", marker->key);
886 return -1;
887 }
888 data = (void*)tiff + swabed_data;
889 }
890 else
891 {
892 data = (void*)(&(ent->data));
893 }
894
895 item = exif_item_new(marker->format, ent->tag, ent->nb, marker);
896 exif_item_copy_data(item, data, data_len, ent->format, byte_order);
897 exif->items = g_list_prepend(exif->items, item);
898
899 if (item->tag == TAG_EXIFOFFSET)
900 {
901 parse_IFD_table(exif, tiff, swabed_data, size, byte_order);
902 }
903
904 return 0;
905 }
906
907 static int parse_IFD_table(ExifData *exif, unsigned char *tiff, int offset,
908 int size, int byte_order)
909 {
910 int i, nb_entries;
911
912 /* We should be able to read number of entries in IFD0) */
913 if (size < offset+2) return -1;
914
915 nb_entries = get_int16(tiff+offset, byte_order);
916
917 /* Entries and next IFD offset must be readable */
918 if (size < offset+nb_entries*12+4) return -1;
919
920 for (i=0; i<nb_entries; ++i)
921 {
922 parse_IFD_entry(exif, tiff, offset+2+i*sizeof(IFDEntry), size, byte_order);
923 }
924
925 return 0;
926 }
927
928 /*
929 *-------------------------------------------------------------------
930 * file formats
931 *-------------------------------------------------------------------
932 */
933
934 static int parse_TIFF(ExifData *exif, unsigned char *tiff, int size)
935 {
936 int byte_order, offset=0;
937
938 if (size < sizeof(TIFFHeader))
939 {
940 return -1;
941 }
942
943 if (strncmp(((TIFFHeader*)tiff)->byte_order, "II", 2) == 0)
944 {
945 byte_order = BYTE_ORDER_INTEL;
946 }
947 else if (strncmp(((TIFFHeader*)tiff)->byte_order, "MM", 2) == 0)
948 {
949 byte_order = BYTE_ORDER_MOTOROLA;
950 }
951 else
952 {
953 return -1;
954 }
955
956 if (swab_int16(((TIFFHeader*)tiff)->magic, byte_order) != 0x002A)
957 {
958 return -1;
959 }
960
961 offset = swab_int32(((TIFFHeader*)tiff)->IFD_offset, byte_order);
962
963 return parse_IFD_table(exif, tiff, offset, size, byte_order);
964 }
965
966 static int parse_JPEG(ExifData *exif, unsigned char *f, int size)
967 {
968 int marker, marker_size;
969
970 if (size<2 || *f!=0xFF || *(f+1)!=MARKER_SOI)
971 {
972 return -2;
973 }
974
975 do {
976 if (goto_next_marker(&f, &size, &marker) == -1)
977 {
978 break;
979 }
980 } while (marker != MARKER_APP1);
981
982 if (marker != MARKER_APP1)
983 {
984 return -2;
985 }
986
987 marker_size = get_marker_size(f)-2;
988
989 if (marker_size<6 || strncmp((char*)f+4, "Exif\0\0", 6)!=0)
990 {
991 return -2;
992 }
993
994 return parse_TIFF(exif, f+10, marker_size-6);
995 }
996
997 static gint map_file(const gchar *path, void **mapping, int *size)
998 {
999 int fd;
1000 struct stat fs;
1001
1002 if ((fd = open(path, O_RDONLY)) == -1)
1003 {
1004 perror(path);
1005 return -1;
1006 }
1007
1008 if (fstat(fd, &fs) == -1)
1009 {
1010 perror(path);
1011 close(fd);
1012 return -1;
1013 }
1014
1015 *size = fs.st_size;
1016
1017 if ((*mapping = mmap(0, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0)) == MAP_FAILED)
1018 {
1019 perror(path);
1020 close(fd);
1021 return -1;
1022 }
1023
1024 close(fd);
1025 return 0;
1026 }
1027
1028 static gint unmap_file(void *mapping, int size)
1029 {
1030 if (munmap(mapping, size) == -1)
1031 {
1032 perror("munmap");
1033 return -1;
1034 }
1035
1036 return 0;
1037 }
1038
1039 void exif_free(ExifData *exif)
1040 {
1041 GList *work;
1042
1043 if (!exif) return;
1044
1045 work = exif->items;
1046 while (work)
1047 {
1048 ExifItem *item = work->data;
1049 work = work->next;
1050 exif_item_free(item);
1051 }
1052
1053 g_list_free(exif->items);
1054 g_free(exif);
1055 }
1056
1057 ExifData *exif_read(const gchar *path)
1058 {
1059 ExifData *exif;
1060 void *f;
1061 int size, res;
1062 gchar *pathl;
1063
1064 if (!path) return NULL;
1065
1066 pathl = path_from_utf8(path);
1067 if (map_file(pathl, &f, &size) == -1)
1068 {
1069 g_free(pathl);
1070 return NULL;
1071 }
1072 g_free(pathl);
1073
1074 exif = g_new0(ExifData, 1);
1075 exif->items = NULL;
1076
1077 if ((res = parse_JPEG(exif, (unsigned char *)f, size)) == -2)
1078 {
1079 res = parse_TIFF(exif, (unsigned char *)f, size);
1080 }
1081
1082 if (res != 0)
1083 {
1084 exif_free(exif);
1085 exif = NULL;
1086 }
1087
1088 unmap_file(f, size);
1089
1090 if (exif) exif->items = g_list_reverse(exif->items);
1091
1092 #if 0
1093 exif_write_data_list(exif, stdout, TRUE);
1094 exif_write_data_list(exif, stdout, FALSE);
1095 #endif
1096
1097 return exif;
1098 }
1099
1100 ExifItem *exif_get_item(ExifData *exif, const gchar *key)
1101 {
1102 GList *work;
1103
1104 if (!key) return NULL;
1105
1106 work = exif->items;
1107 while (work)
1108 {
1109 ExifItem *item;
1110
1111 item = work->data;
1112 work = work->next;
1113 if (item->marker->key && strcmp(key, item->marker->key) == 0) return item;
1114 }
1115 return NULL;
1116 }
1117
1118 gchar *exif_item_get_data_as_text(ExifItem *item)
1119 {
1120 ExifMarker *marker;
1121 gpointer data;
1122 GString *string;
1123 gchar *text;
1124 gint ne;
1125 gint i;
1126
1127 if (!item) return NULL;
1128
1129 marker = item->marker;
1130 if (!marker) return NULL;
1131
1132 data = item->data;
1133 ne = item->elements;
1134 string = g_string_new("");
1135 switch (item->format)
1136 {
1137 case EXIF_FORMAT_UNKNOWN:
1138 break;
1139 case EXIF_FORMAT_BYTE_UNSIGNED:
1140 case EXIF_FORMAT_BYTE:
1141 case EXIF_FORMAT_UNDEFINED:
1142 if (ne == 1 && marker->list)
1143 {
1144 gchar *result;
1145 unsigned char val;
1146
1147 if (item->format == EXIF_FORMAT_BYTE_UNSIGNED ||
1148 item->format == EXIF_FORMAT_UNDEFINED)
1149 {
1150 val = ((unsigned char *)data)[0];
1151 }
1152 else
1153 {
1154 val = (unsigned char)(((signed char *)data)[0]);
1155 }
1156
1157 result = text_list_find_value(marker->list, (unsigned short)val);
1158 string = g_string_append(string, result);
1159 g_free(result);
1160 }
1161 else
1162 {
1163 string = string_append_raw_bytes(string, data, ne);
1164 }
1165 break;
1166 case EXIF_FORMAT_STRING:
1167 string = g_string_append(string, (gchar *)(item->data));
1168 break;
1169 case EXIF_FORMAT_SHORT_UNSIGNED:
1170 if (ne == 1 && marker->list)
1171 {
1172 gchar *result;
1173
1174 result = text_list_find_value(marker->list, ((unsigned short *)data)[0]);
1175 string = g_string_append(string, result);
1176 g_free(result);
1177 }
1178 else for (i = 0; i < ne; i++)
1179 {
1180 g_string_append_printf(string, "%s%hd", (i > 0) ? ", " : "",
1181 ((unsigned short *)data)[i]);
1182 }
1183 break;
1184 case EXIF_FORMAT_LONG_UNSIGNED:
1185 for (i = 0; i < ne; i++)
1186 {
1187 g_string_append_printf(string, "%s%ld", (i > 0) ? ", " : "",
1188 ((unsigned long *)data)[i]);
1189 }
1190 break;
1191 case EXIF_FORMAT_RATIONAL_UNSIGNED:
1192 for (i = 0; i < ne; i++)
1193 {
1194 ExifRational *r;
1195
1196 r = &((ExifRational *)data)[i];
1197 g_string_append_printf(string, "%s%ld/%ld", (i > 0) ? ", " : "",
1198 (unsigned long)r->num, (unsigned long)r->den);
1199 }
1200 break;
1201 case EXIF_FORMAT_SHORT:
1202 for (i = 0; i < ne; i++)
1203 {
1204 g_string_append_printf(string, "%s%hd", (i > 0) ? ", " : "",
1205 ((short *)data)[i]);
1206 }
1207 break;
1208 case EXIF_FORMAT_LONG:
1209 for (i = 0; i < ne; i++)
1210 {
1211 g_string_append_printf(string, "%s%ld", (i > 0) ? ", " : "",
1212 ((long *)data)[i]);
1213 }
1214 break;
1215 case EXIF_FORMAT_RATIONAL:
1216 for (i = 0; i < ne; i++)
1217 {
1218 ExifRational *r;
1219
1220 r = &((ExifRational *)data)[i];
1221 g_string_append_printf(string, "%s%ld/%ld", (i > 0) ? ", " : "",
1222 (long)r->num, (long)r->den);
1223 }
1224 break;
1225 case EXIF_FORMAT_FLOAT:
1226 for (i = 0; i < ne; i++)
1227 {
1228 g_string_append_printf(string, "%s%f", (i > 0) ? ", " : "",
1229 ((float *)data)[i]);
1230 }
1231 break;
1232 case EXIF_FORMAT_DOUBLE:
1233 for (i = 0; i < ne; i++)
1234 {
1235 g_string_append_printf(string, "%s%f", (i > 0) ? ", " : "",
1236 ((double *)data)[i]);
1237 }
1238 break;
1239 }
1240
1241 text = g_strdup(string->str);
1242 g_string_free(string, TRUE);
1243
1244 return text;
1245 }
1246
1247 gint exif_item_get_integer(ExifItem *item, gint *value)
1248 {
1249 if (!item) return FALSE;
1250
1251 switch (item->format)
1252 {
1253 case EXIF_FORMAT_SHORT:
1254 *value = (gint)(((short *)(item->data))[0]);
1255 return TRUE;
1256 break;
1257 case EXIF_FORMAT_SHORT_UNSIGNED:
1258 *value = (gint)(((unsigned short *)(item->data))[0]);
1259 return TRUE;
1260 break;
1261 case EXIF_FORMAT_LONG:
1262 *value = (gint)(((long *)(item->data))[0]);
1263 return TRUE;
1264 break;
1265 case EXIF_FORMAT_LONG_UNSIGNED:
1266 /* FIXME: overflow possible */
1267 *value = (gint)(((unsigned long *)(item->data))[0]);
1268 return TRUE;
1269 default:
1270 /* all other type return FALSE */
1271 break;
1272 }
1273 return FALSE;
1274 }
1275
1276 gint exif_get_integer(ExifData *exif, const gchar *key, gint *value)
1277 {
1278 ExifItem *item;
1279
1280 item = exif_get_item(exif, key);
1281 return exif_item_get_integer(item, value);
1282 }
1283
1284 ExifRational *exif_item_get_rational(ExifItem *item, gint *sign)
1285 {
1286 if (!item) return NULL;
1287
1288 if (item->format == EXIF_FORMAT_RATIONAL ||
1289 item->format == EXIF_FORMAT_RATIONAL_UNSIGNED)
1290 {
1291 if (sign) *sign = (item->format == EXIF_FORMAT_RATIONAL);
1292 return &((ExifRational *)(item->data))[0];
1293 }
1294
1295 return NULL;
1296 }
1297
1298 ExifRational *exif_get_rational(ExifData *exif, const gchar *key, gint *sign)
1299 {
1300 ExifItem *item;
1301
1302 item = exif_get_item(exif, key);
1303 return exif_item_get_rational(item, sign);
1304 }
1305
1306 double exif_rational_to_double(ExifRational *r, gint sign)
1307 {
1308 if (!r || r->den == 0.0) return 0.0;
1309
1310 if (sign) return (double)((int)r->num) / (double)((int)r->den);
1311 return (double)r->num / r->den;
1312 }
1313
1314 static double exif_get_rational_as_double(ExifData *exif, const gchar *key)
1315 {
1316 ExifRational *r;
1317 gint sign;
1318
1319 r = exif_get_rational(exif, key, &sign);
1320 return exif_rational_to_double(r, sign);
1321 }
1322
1323 static GString *append_comma_text(GString *string, const gchar *text)
1324 {
1325 string = g_string_append(string, ", ");
1326 string = g_string_append(string, text);
1327
1328 return string;
1329 }
1330
1331 static gchar *exif_get_formatted_by_key(ExifData *exif, const gchar *key, gint *key_valid)
1332 {
1333 /* must begin with f, else not formatted */
1334 if (key[0] != 'f')
1335 {
1336 if (key_valid) *key_valid = FALSE;
1337 return NULL;
1338 }
1339
1340 if (key_valid) *key_valid = TRUE;
1341
1342 if (strcmp(key, "fCamera") == 0)
1343 {
1344 gchar *text;
1345 gchar *make = exif_get_data_as_text(exif, "Make");
1346 gchar *model = exif_get_data_as_text(exif, "Model");
1347 gchar *software = exif_get_data_as_text(exif, "Software");
1348
1349 text = g_strdup_printf("%s%s%s%s%s%s", (make) ? make : "", ((make) && (model)) ? " " : "",
1350 (model) ? model : "",
1351 (software) ? " (" : "",
1352 (software) ? software : "",
1353 (software) ? ")" : "");
1354
1355 g_free(make);
1356 g_free(model);
1357 g_free(software);
1358 return text;
1359 }
1360 if (strcmp(key, "fDateTime") == 0)
1361 {
1362 gchar *text = exif_get_data_as_text(exif, "DateTimeOriginal");
1363 gchar *subsec = NULL;
1364 if (text) subsec = exif_get_data_as_text(exif, "SubsecTimeOriginal");
1365 if (!text)
1366 {
1367 text = exif_get_data_as_text(exif, "DateTime");
1368 if (text) subsec = exif_get_data_as_text(exif, "SubsecTime");
1369 }
1370 if (subsec)
1371 {
1372 gchar *tmp = text;
1373 text = g_strconcat(tmp, ".", subsec, NULL);
1374 g_free(tmp);
1375 g_free(subsec);
1376 }
1377 return text;
1378 }
1379 if (strcmp(key, "fShutterSpeed") == 0)
1380 {
1381 ExifRational *r;
1382
1383 r = exif_get_rational(exif, "ExposureTime", NULL);
1384 if (r && r->num && r->den)
1385 {
1386 double n = (double)r->den / (double)r->num;
1387 return g_strdup_printf("%s%.0fs", n > 1.0 ? "1/" : "",
1388 n > 1.0 ? n : 1.0 / n);
1389 }
1390 r = exif_get_rational(exif, "ShutterSpeedValue", NULL);
1391 if (r && r->num && r->den)
1392 {
1393 double n = pow(2.0, exif_rational_to_double(r, TRUE));
1394
1395 /* Correct exposure time to avoid values like 1/91s (seen on Minolta DImage 7) */
1396 if (n > 1.0 && (int)n - ((int)(n/10))*10 == 1) n--;
1397
1398 return g_strdup_printf("%s%.0fs", n > 1.0 ? "1/" : "",
1399 n > 1.0 ? floor(n) : 1.0 / n);
1400 }
1401 return NULL;
1402 }
1403 if (strcmp(key, "fAperture") == 0)
1404 {
1405 double n;
1406
1407 n = exif_get_rational_as_double(exif, "FNumber");
1408 if (n == 0.0) n = exif_get_rational_as_double(exif, "ApertureValue");
1409 if (n == 0.0) return NULL;
1410
1411 return g_strdup_printf("f/%.1f", n);
1412 }
1413 if (strcmp(key, "fExposureBias") == 0)
1414 {
1415 ExifRational *r;
1416 gint sign;
1417 double n;
1418
1419 r = exif_get_rational(exif, "ExposureBiasValue", &sign);
1420 if (!r) return NULL;
1421
1422 n = exif_rational_to_double(r, sign);
1423 return g_strdup_printf("%+.1f", n);
1424 }
1425 if (strcmp(key, "fFocalLength") == 0)
1426 {
1427 double n;
1428
1429 n = exif_get_rational_as_double(exif, "FocalLength");
1430 if (n == 0.0) return NULL;
1431 return g_strdup_printf("%.2f mm", n);
1432 }
1433 if (strcmp(key, "fISOSpeedRating") == 0)
1434 {
1435 gchar *text;
1436
1437 text = exif_get_data_as_text(exif, "ISOSpeedRatings");
1438 /* kodak may set this instead */
1439 if (!text) text = exif_get_data_as_text(exif, "ExposureIndex");
1440 return text;
1441 }
1442 if (strcmp(key, "fSubjectDistance") == 0)
1443 {
1444 ExifRational *r;
1445 gint sign;
1446 double n;
1447
1448 r = exif_get_rational(exif, "SubjectDistance", &sign);
1449 if (!r) return NULL;
1450
1451 if ((long)r->num == 0xffffffff) return g_strdup(_("infinity"));
1452 if ((long)r->num == 0) return g_strdup(_("unknown"));
1453
1454 n = exif_rational_to_double(r, sign);
1455 if (n == 0.0) return _("unknown");
1456 return g_strdup_printf("%.3f m", n);
1457 }
1458 if (strcmp(key, "fFlash") == 0)
1459 {
1460 /* grr, flash is a bitmask... */
1461 GString *string;
1462 gchar *text;
1463 gint n;
1464 gint v;
1465
1466 if (!exif_get_integer(exif, "Flash", &n)) return NULL;
1467
1468 /* Exif 2.1 only defines first 3 bits */
1469 if (n <= 0x07) return g_strdup(text_list_find_value(ExifFlashList, n));
1470
1471 /* must be Exif 2.2 */
1472 string = g_string_new("");
1473
1474 /* flash fired (bit 0) */
1475 string = g_string_append(string, (n & 0x01) ? _("yes") : _("no"));
1476
1477 /* flash mode (bits 3, 4) */
1478 v = (n >> 3) & 0x03;
1479 if (v) string = append_comma_text(string, _("mode:"));
1480 switch (v)
1481 {
1482 case 1:
1483 string = g_string_append(string, _("on"));
1484 break;
1485 case 2:
1486 string = g_string_append(string, _("off"));
1487 break;
1488 case 3:
1489 string = g_string_append(string, _("auto"));
1490 break;
1491 }
1492
1493 /* return light (bits 1, 2) */
1494 v = (n >> 1) & 0x03;
1495 if (v == 2) string = append_comma_text(string, _("not detected by strobe"));
1496 if (v == 3) string = append_comma_text(string, _("detected by strobe"));
1497
1498 /* we ignore flash function (bit 5) */
1499
1500 /* red-eye (bit 6) */
1501 if ((n >> 5) & 0x01) string = append_comma_text(string, _("red-eye reduction"));
1502
1503 text = string->str;
1504 g_string_free(string, FALSE);
1505 return text;
1506 }
1507 if (strcmp(key, "fResolution") == 0)
1508 {
1509 ExifRational *rx, *ry;
1510 gchar *units;
1511 gchar *text;
1512
1513 rx = exif_get_rational(exif, "XResolution", NULL);
1514 ry = exif_get_rational(exif, "YResolution", NULL);
1515 if (!rx || !ry) return NULL;
1516
1517 units = exif_get_data_as_text(exif, "ResolutionUnit");
1518 text = g_strdup_printf("%0.f x %0.f (%s/%s)", rx->den ? (double)rx->num / rx->den : 1.0,
1519 ry->den ? (double)ry->num / ry->den : 1.0,
1520 _("dot"), (units) ? units : _("unknown"));
1521
1522 g_free(units);
1523 return text;
1524 }
1525
1526 if (key_valid) *key_valid = FALSE;
1527 return NULL;
1528 }
1529
1530 gchar *exif_get_data_as_text(ExifData *exif, const gchar *key)
1531 {
1532 ExifItem *item;
1533 gchar *text;
1534 gint key_valid;
1535
1536 if (!key) return NULL;
1537
1538 text = exif_get_formatted_by_key(exif, key, &key_valid);
1539 if (key_valid) return text;
1540
1541 item = exif_get_item(exif, key);
1542 if (item) return exif_item_get_data_as_text(item);
1543
1544 return NULL;
1545 }
1546
1547 const gchar *exif_get_description_by_key(const gchar *key)
1548 {
1549 gint i;
1550
1551 if (!key) return NULL;
1552
1553 i = 0;
1554 while (ExifFormattedList[i].key != NULL)
1555 {
1556 if (strcmp(key, ExifFormattedList[i].key) == 0) return _(ExifFormattedList[i].description);
1557 i++;
1558 }
1559
1560 i = 0;
1561 while (ExifKnownMarkersList[i].tag > 0)
1562 {
1563 if (strcmp(key, ExifKnownMarkersList[i].key) == 0) return _(ExifKnownMarkersList[i].description);
1564 i++;
1565 }
1566
1567 return NULL;
1568 }
1569
1570 static void exif_write_item(FILE *f, ExifItem *item)
1571 {
1572 gchar *text;
1573
1574 text = exif_item_get_data_as_text(item);
1575 if (text)
1576 {
1577 fprintf(f, "%4x %9s %30s %s\n", item->tag, ExifFormatList[item->format].short_name,
1578 exif_item_get_tag_name(item), text);
1579 }
1580 g_free(text);
1581 }
1582
1583 void exif_write_data_list(ExifData *exif, FILE *f, gint human_readable_list)
1584 {
1585 if (!f || !exif) return;
1586
1587 fprintf(f, " tag format key value\n");
1588 fprintf(f, "----------------------------------------------------\n");
1589
1590 if (human_readable_list)
1591 {
1592 gint i;
1593
1594 i = 0;
1595 while (ExifFormattedList[i].key)
1596 {
1597 gchar *text;
1598
1599 text = exif_get_formatted_by_key(exif, ExifFormattedList[i].key, NULL);
1600 if (text)
1601 {
1602 fprintf(f, " %9s %30s %s\n", "string", ExifFormattedList[i].key, text);
1603 }
1604 i++;
1605 }
1606 }
1607 else
1608 {
1609 GList *work;
1610
1611 work = exif->items;
1612 while (work)
1613 {
1614 ExifItem *item;
1615
1616 item = work->data;
1617 work = work->next;
1618
1619 exif_write_item(f, item);
1620 }
1621 }
1622 fprintf(f, "----------------------------------------------------\n");
1623 }
1624