4
* Copyright (C) 2008 The Geeqie Team
7
* Support for Exif file format, originally written by Eric Swalens.
8
* Modified by Quy Tonthat
10
* Reimplemented with generic data storage by John Ellis (Nov 2003)
12
* The tags were added with information from the FREE document:
13
* http://www.ba.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html
15
* For the official Exif Format, please refer to:
17
* http://www.exif.org/specifications.html (PDF spec sheets)
20
* Additional tag formats should be added to the proper
21
* location in ExifKnownMarkersList[].
23
* Human readable ouput (that needs additional processing of data to
24
* be useable) can be defined by adding a key to ExifFormattedList[],
25
* then handling that tag in the function exif_get_formatted_by_key().
26
* The human readable formatted keys must begin with the character 'f'.
28
* Unsupported at this time:
34
* Convert data to useable form in the ??_as_text function for:
35
* ComponentsConfiguration
36
* UserComment (convert this to UTF-8?)
39
This program is free software; you can redistribute it and/or modify
40
it under the terms of the GNU General Public License as published by
41
the Free Software Foundation; either version 2 of the License, or
42
(at your option) any later version.
44
This program is distributed in the hope that it will be useful,
45
but WITHOUT ANY WARRANTY; without even the implied warranty of
46
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
47
GNU General Public License for more details.
49
You should have received a copy of the GNU General Public License
50
along with this program; if not, write to the Free Software
51
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
64
#include <sys/types.h>
76
#include "format_raw.h"
77
#include "ui_fileops.h"
81
*-----------------------------------------------------------------------------
83
*-----------------------------------------------------------------------------
86
ExifFormatAttrib ExifFormatList[] = {
87
{ EXIF_FORMAT_UNKNOWN, 1, "unknown", "unknown" },
88
{ EXIF_FORMAT_BYTE_UNSIGNED, 1, "ubyte", "unsigned byte" },
89
{ EXIF_FORMAT_STRING, 1, "string", "string" },
90
{ EXIF_FORMAT_SHORT_UNSIGNED, 2, "ushort", "unsigned short" },
91
{ EXIF_FORMAT_LONG_UNSIGNED, 4, "ulong", "unsigned long" },
92
{ EXIF_FORMAT_RATIONAL_UNSIGNED,8, "urational", "unsigned rational" },
93
{ EXIF_FORMAT_BYTE, 1, "byte", "byte" },
94
{ EXIF_FORMAT_UNDEFINED, 1, "undefined", "undefined" },
95
{ EXIF_FORMAT_SHORT, 2, "sshort", "signed short" },
96
{ EXIF_FORMAT_LONG, 4, "slong", "signed long" },
97
{ EXIF_FORMAT_RATIONAL, 8, "srational", "signed rational" },
98
{ EXIF_FORMAT_FLOAT, 4, "float", "float" },
99
{ EXIF_FORMAT_DOUBLE, 8, "double", "double" },
103
/* tags that are special, or need special treatment */
104
#define TAG_EXIFOFFSET 0x8769
105
#define TAG_EXIFMAKERNOTE 0x927c
109
*-----------------------------------------------------------------------------
111
*-----------------------------------------------------------------------------
113
static ExifTextList ExifCompressionList[] = {
114
{ 1, "Uncompressed" },
116
{ 3, "T4/Group 3 Fax" },
117
{ 4, "T6/Group 4 Fax" },
119
{ 6, "JPEG (old style)" },
121
{ 8, "Adobe Deflate" },
123
{ 10, "JBIG Color" },
125
{ 32771, "CCIRLEW" },
126
{ 32773, "PackBits" },
127
{ 32809, "ThunderScan" },
128
{ 32895, "IT8CTPAD" },
132
{ 32908, "PixasFilm" },
133
{ 32909, "PixasLog" },
134
{ 32946, "Deflate" },
138
{ 34677, "SGILog24" },
139
{ 34712, "JPEF 2000" },
140
{ 34713, "Nikon NEF Compressed" },
144
static ExifTextList ExifOrientationList[] = {
145
{ EXIF_ORIENTATION_UNKNOWN, N_("unknown") },
146
{ EXIF_ORIENTATION_TOP_LEFT, N_("top left") },
147
{ EXIF_ORIENTATION_TOP_RIGHT, N_("top right") },
148
{ EXIF_ORIENTATION_BOTTOM_RIGHT,N_("bottom right") },
149
{ EXIF_ORIENTATION_BOTTOM_LEFT, N_("bottom left") },
150
{ EXIF_ORIENTATION_LEFT_TOP, N_("left top") },
151
{ EXIF_ORIENTATION_RIGHT_TOP, N_("right top") },
152
{ EXIF_ORIENTATION_RIGHT_BOTTOM,N_("right bottom") },
153
{ EXIF_ORIENTATION_LEFT_BOTTOM, N_("left bottom") },
157
static ExifTextList ExifUnitList[] = {
158
{ EXIF_UNIT_UNKNOWN, N_("unknown") },
159
{ EXIF_UNIT_NOUNIT, "" },
160
{ EXIF_UNIT_INCH, N_("inch") },
161
{ EXIF_UNIT_CENTIMETER, N_("centimeter") },
165
static ExifTextList ExifYCbCrPosList[] = {
171
static ExifTextList ExifMeteringModeList[] = {
172
{ 0, N_("unknown") },
173
{ 1, N_("average") },
174
{ 2, N_("center weighted") },
176
{ 4, N_("multi-spot") },
177
{ 5, N_("multi-segment") },
178
{ 6, N_("partial") },
179
{ 255, N_("other") },
183
static ExifTextList ExifExposureProgramList[] = {
184
{ 0, N_("not defined") },
187
{ 3, N_("aperture") },
188
{ 4, N_("shutter") },
189
{ 5, N_("creative") },
191
{ 7, N_("portrait") },
192
{ 8, N_("landscape") },
196
static ExifTextList ExifLightSourceList[] = {
197
{ 0, N_("unknown") },
198
{ 1, N_("daylight") },
199
{ 2, N_("fluorescent") },
200
{ 3, N_("tungsten (incandescent)") },
202
{ 9, N_("fine weather") },
203
{ 10, N_("cloudy weather") },
205
{ 12, N_("daylight fluorescent") },
206
{ 13, N_("day white fluorescent") },
207
{ 14, N_("cool white fluorescent") },
208
{ 15, N_("white fluorescent") },
209
{ 17, N_("standard light A") },
210
{ 18, N_("standard light B") },
211
{ 19, N_("standard light C") },
216
{ 24, N_("ISO studio tungsten") },
217
{ 255, N_("other") },
221
static ExifTextList ExifFlashList[] = {
224
{ 5, N_("yes, not detected by strobe") },
225
{ 7, N_("yes, detected by strobe") },
229
static ExifTextList ExifColorSpaceList[] = {
231
{ 65535,N_("uncalibrated") },
235
static ExifTextList ExifSensorList[] = {
236
{ 1, N_("not defined") },
237
{ 2, N_("1 chip color area") },
238
{ 2, N_("2 chip color area") },
239
{ 4, N_("3 chip color area") },
240
{ 5, N_("color sequential area") },
241
{ 7, N_("trilinear") },
242
{ 8, N_("color sequential linear") },
246
static ExifTextList ExifSourceList[] = {
247
{ 3, N_("digital still camera") },
251
static ExifTextList ExifSceneList[] = {
252
{ 1, N_("direct photo") },
256
static ExifTextList ExifCustRenderList[] = {
262
static ExifTextList ExifExposureModeList[] = {
265
{ 2, N_("auto bracket") },
269
static ExifTextList ExifWhiteBalanceList[] = {
275
static ExifTextList ExifSceneCaptureList[] = {
276
{ 0, N_("standard") },
277
{ 1, N_("landscape") },
278
{ 2, N_("portrait") },
279
{ 3, N_("night scene") },
283
static ExifTextList ExifGainControlList[] = {
285
{ 1, N_("low gain up") },
286
{ 2, N_("high gain up") },
287
{ 3, N_("low gain down") },
288
{ 4, N_("high gain down") },
292
static ExifTextList ExifContrastList[] = {
299
static ExifTextList ExifSaturationList[] = {
306
static ExifTextList ExifSharpnessList[] = {
313
static ExifTextList ExifSubjectRangeList[] = {
314
{ 0, N_("unknown") },
317
{ 3, N_("distant") },
322
Tag names should match to exiv2 keys, http://www.exiv2.org/metadata.html
323
Tags that don't match are not supported by exiv2 and should not be used anywhere in the code
326
ExifMarker ExifKnownMarkersList[] = {
327
{ 0x0100, EXIF_FORMAT_LONG_UNSIGNED, 1, "Exif.Image.ImageWidth", N_("Image Width"), NULL },
328
{ 0x0101, EXIF_FORMAT_LONG_UNSIGNED, 1, "Exif.Image.ImageLength", N_("Image Height"), NULL },
329
{ 0x0102, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Image.BitsPerSample", N_("Bits per Sample/Pixel"), NULL },
330
{ 0x0103, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Image.Compression", N_("Compression"), ExifCompressionList },
331
{ 0x010e, EXIF_FORMAT_STRING, -1, "Exif.Image.ImageDescription", N_("Image description"), NULL },
332
{ 0x010f, EXIF_FORMAT_STRING, -1, "Exif.Image.Make", N_("Camera make"), NULL },
333
{ 0x0110, EXIF_FORMAT_STRING, -1, "Exif.Image.Model", N_("Camera model"), NULL },
334
{ 0x0112, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Image.Orientation", N_("Orientation"), ExifOrientationList },
335
{ 0x011a, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Exif.Image.XResolution", N_("X resolution"), NULL },
336
{ 0x011b, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Exif.Image.YResolution", N_("Y Resolution"), NULL },
337
{ 0x0128, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Image.ResolutionUnit", N_("Resolution units"), ExifUnitList },
338
{ 0x0131, EXIF_FORMAT_STRING, -1, "Exif.Image.Software", N_("Firmware"), NULL },
339
{ 0x0132, EXIF_FORMAT_STRING, 20, "Exif.Image.DateTime", N_("Date"), NULL },
340
{ 0x013e, EXIF_FORMAT_RATIONAL_UNSIGNED, 2, "Exif.Image.WhitePoint", N_("White point"), NULL },
341
{ 0x013f, EXIF_FORMAT_RATIONAL_UNSIGNED, 6, "Exif.Image.PrimaryChromaticities",N_("Primary chromaticities"), NULL },
342
{ 0x0211, EXIF_FORMAT_RATIONAL_UNSIGNED, 3, "Exif.Image.YCbCrCoefficients", N_("YCbCy coefficients"), NULL },
343
{ 0x0213, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Image.YCbCrPositioning", N_("YCbCr positioning"), ExifYCbCrPosList },
344
{ 0x0214, EXIF_FORMAT_RATIONAL_UNSIGNED, 6, "Exif.Image.ReferenceBlackWhite",N_("Black white reference"), NULL },
345
{ 0x8298, EXIF_FORMAT_STRING, -1, "Exif.Image.Copyright", N_("Copyright"), NULL },
346
{ 0x8769, EXIF_FORMAT_LONG_UNSIGNED, 1, "Exif.Image.ExifTag", N_("SubIFD Exif offset"), NULL },
348
{ 0x829a, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Exif.Photo.ExposureTime", N_("Exposure time (seconds)"), NULL },
349
{ 0x829d, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Exif.Photo.FNumber", N_("FNumber"), NULL },
350
{ 0x8822, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Photo.ExposureProgram", N_("Exposure program"), ExifExposureProgramList },
351
{ 0x8824, EXIF_FORMAT_STRING, -1, "Exif.Photo.SpectralSensitivity",N_("Spectral Sensitivity"), NULL },
352
{ 0x8827, EXIF_FORMAT_SHORT_UNSIGNED, -1, "Exif.Photo.ISOSpeedRatings", N_("ISO sensitivity"), NULL },
353
{ 0x8828, EXIF_FORMAT_UNDEFINED, -1, "Exif.Photo.OECF", N_("Optoelectric conversion factor"), NULL },
354
{ 0x9000, EXIF_FORMAT_UNDEFINED, 4, "Exif.Photo.ExifVersion", N_("Exif version"), NULL },
355
{ 0x9003, EXIF_FORMAT_STRING, 20, "Exif.Photo.DateTimeOriginal", N_("Date original"), NULL },
356
{ 0x9004, EXIF_FORMAT_STRING, 20, "Exif.Photo.DateTimeDigitized", N_("Date digitized"), NULL },
357
{ 0x9101, EXIF_FORMAT_UNDEFINED, -1, "Exif.Photo.ComponentsConfiguration",N_("Pixel format"), NULL },
358
{ 0x9102, EXIF_FORMAT_RATIONAL_UNSIGNED,1, "Exif.Photo.CompressedBitsPerPixel",N_("Compression ratio"), NULL },
359
{ 0x9201, EXIF_FORMAT_RATIONAL, 1, "Exif.Photo.ShutterSpeedValue", N_("Shutter speed"), NULL },
360
{ 0x9202, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Exif.Photo.ApertureValue", N_("Aperture"), NULL },
361
{ 0x9203, EXIF_FORMAT_RATIONAL, 1, "Exif.Photo.BrightnessValue", N_("Brightness"), NULL },
362
{ 0x9204, EXIF_FORMAT_RATIONAL, 1, "Exif.Photo.ExposureBiasValue", N_("Exposure bias"), NULL },
363
{ 0x9205, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Exif.Photo.MaxApertureValue", N_("Maximum aperture"), NULL },
364
{ 0x9206, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Exif.Photo.SubjectDistance", N_("Subject distance"), NULL },
365
{ 0x9207, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Photo.MeteringMode", N_("Metering mode"), ExifMeteringModeList },
366
{ 0x9208, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Photo.LightSource", N_("Light source"), ExifLightSourceList },
367
{ 0x9209, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Photo.Flash", N_("Flash"), ExifFlashList },
368
{ 0x920a, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Exif.Photo.FocalLength", N_("Focal length"), NULL },
369
{ 0x9214, EXIF_FORMAT_SHORT_UNSIGNED, -1, "Exif.Photo.SubjectArea", N_("Subject area"), NULL },
370
{ 0x927c, EXIF_FORMAT_UNDEFINED, -1, "Exif.Photo.MakerNote", N_("MakerNote"), NULL },
371
{ 0x9286, EXIF_FORMAT_UNDEFINED, -1, "Exif.Photo.UserComment", N_("UserComment"), NULL },
372
{ 0x9290, EXIF_FORMAT_STRING, -1, "Exif.Photo.SubSecTime", N_("Subsecond time"), NULL },
373
{ 0x9291, EXIF_FORMAT_STRING, -1, "Exif.Photo.SubSecTimeOriginal",N_("Subsecond time original"), NULL },
374
{ 0x9292, EXIF_FORMAT_STRING, -1, "Exif.Photo.SubSecTimeDigitized",N_("Subsecond time digitized"), NULL },
375
{ 0xa000, EXIF_FORMAT_UNDEFINED, 4, "Exif.Photo.FlashpixVersion", N_("FlashPix version"), NULL },
376
{ 0xa001, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Photo.ColorSpace", N_("Colorspace"), ExifColorSpaceList },
377
/* ExifImageWidth, ExifImageHeight can also be unsigned short */
378
{ 0xa002, EXIF_FORMAT_LONG_UNSIGNED, 1, "Exif.Photo.PixelXDimension", N_("Width"), NULL },
379
{ 0xa003, EXIF_FORMAT_LONG_UNSIGNED, 1, "Exif.Photo.PixelYDimension", N_("Height"), NULL },
380
{ 0xa004, EXIF_FORMAT_STRING, -1, "Exif.Photo.RelatedSoundFile", N_("Audio data"), NULL },
381
{ 0xa005, EXIF_FORMAT_LONG_UNSIGNED, 1, "ExifInteroperabilityOffset", N_("ExifR98 extension"), NULL },
382
{ 0xa20b, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Exif.Photo.FlashEnergy", N_("Flash strength"), NULL },
383
{ 0xa20c, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Photo.SpatialFrequencyResponse",N_("Spatial frequency response"), NULL },
384
{ 0xa20e, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Exif.Photo.FocalPlaneXResolution", N_("X Pixel density"), NULL },
385
{ 0xa20f, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Exif.Photo.FocalPlaneYResolution", N_("Y Pixel density"), NULL },
386
{ 0xa210, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Photo.FocalPlaneResolutionUnit", N_("Pixel density units"), ExifUnitList },
387
{ 0x0214, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Exif.Photo.SubjectLocation", N_("Subject location"), NULL },
388
{ 0xa215, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Exif.Photo.ExposureIndex", N_("ISO sensitivity"), NULL },
389
{ 0xa217, EXIF_FORMAT_SHORT_UNSIGNED, -1, "Exif.Photo.SensingMethod", N_("Sensor type"), ExifSensorList },
390
{ 0xa300, EXIF_FORMAT_UNDEFINED, 1, "Exif.Photo.FileSource", N_("Source type"), ExifSourceList },
391
{ 0xa301, EXIF_FORMAT_UNDEFINED, 1, "Exif.Photo.SceneType", N_("Scene type"), ExifSceneList },
392
{ 0xa302, EXIF_FORMAT_UNDEFINED, -1, "Exif.Image.CFAPattern", N_("Color filter array pattern"), NULL },
393
/* tags a4xx were added for Exif 2.2 (not just these - some above, as well) */
394
{ 0xa401, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Photo.CustomRendered", N_("Render process"), ExifCustRenderList },
395
{ 0xa402, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Photo.ExposureMode", N_("Exposure mode"), ExifExposureModeList },
396
{ 0xa403, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Photo.WhiteBalance", N_("White balance"), ExifWhiteBalanceList },
397
{ 0xa404, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Exif.Photo.DigitalZoomRatio", N_("Digital zoom ratio"), NULL },
398
{ 0xa405, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Photo.FocalLengthIn35mmFilm",N_("Focal length (35mm)"), NULL },
399
{ 0xa406, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Photo.SceneCaptureType", N_("Scene capture type"), ExifSceneCaptureList },
400
{ 0xa407, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Photo.GainControl", N_("Gain control"), ExifGainControlList },
401
{ 0xa408, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Photo.Contrast", N_("Contrast"), ExifContrastList },
402
{ 0xa409, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Photo.Saturation", N_("Saturation"), ExifSaturationList },
403
{ 0xa40a, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Photo.Sharpness", N_("Sharpness"), ExifSharpnessList },
404
{ 0xa40b, EXIF_FORMAT_UNDEFINED, -1, "Exif.Photo.DeviceSettingDescription",N_("Device setting"), NULL },
405
{ 0xa40c, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Exif.Photo.SubjectDistanceRange",N_("Subject range"), ExifSubjectRangeList },
406
{ 0xa420, EXIF_FORMAT_STRING, -1, "Exif.Photo.ImageUniqueID", N_("Image serial number"), NULL },
407
/* place known, but undocumented or lesser used tags here */
408
{ 0x00fe, EXIF_FORMAT_LONG_UNSIGNED, 1, "Exif.Image.NewSubfileType", NULL, NULL },
409
{ 0x00ff, EXIF_FORMAT_SHORT_UNSIGNED, 1, "SubfileType", NULL, NULL },
410
{ 0x012d, EXIF_FORMAT_SHORT_UNSIGNED, 3, "Exif.Image.TransferFunction", NULL, NULL },
411
{ 0x013b, EXIF_FORMAT_STRING, -1, "Exif.Image.Artist", "Artist", NULL },
412
{ 0x013d, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Predictor", NULL, NULL },
413
{ 0x0142, EXIF_FORMAT_SHORT_UNSIGNED, 1, "TileWidth", NULL, NULL },
414
{ 0x0143, EXIF_FORMAT_SHORT_UNSIGNED, 1, "TileLength", NULL, NULL },
415
{ 0x0144, EXIF_FORMAT_LONG_UNSIGNED, -1, "TileOffsets", NULL, NULL },
416
{ 0x0145, EXIF_FORMAT_SHORT_UNSIGNED, -1, "TileByteCounts", NULL, NULL },
417
{ 0x014a, EXIF_FORMAT_LONG_UNSIGNED, -1, "Exif.Image.SubIFDs", NULL, NULL },
418
{ 0x015b, EXIF_FORMAT_UNDEFINED, -1, "JPEGTables", NULL, NULL },
419
{ 0x828d, EXIF_FORMAT_SHORT_UNSIGNED, 2, "Exif.Image.CFARepeatPatternDim", NULL, NULL },
420
{ 0x828e, EXIF_FORMAT_BYTE_UNSIGNED, -1, "Exif.Image.CFAPattern", NULL, NULL },
421
{ 0x828f, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Exif.Image.BatteryLevel", NULL, NULL },
422
{ 0x83bb, EXIF_FORMAT_LONG_UNSIGNED, -1, "IPTC/NAA", NULL, NULL },
423
{ 0x8773, EXIF_FORMAT_UNDEFINED, -1, "Exif.Image.InterColorProfile", NULL, NULL },
424
{ 0x8825, EXIF_FORMAT_LONG_UNSIGNED, 1, "GPSInfo", "SubIFD GPS offset", NULL },
425
{ 0x8829, EXIF_FORMAT_SHORT_UNSIGNED, 1, "Interlace", NULL, NULL },
426
{ 0x882a, EXIF_FORMAT_SHORT, 1, "TimeZoneOffset", NULL, NULL },
427
{ 0x882b, EXIF_FORMAT_SHORT_UNSIGNED, 1, "SelfTimerMode", NULL, NULL },
428
{ 0x920b, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Exif.Photo.FlashEnergy", NULL, NULL },
429
{ 0x920c, EXIF_FORMAT_UNDEFINED, -1, "Exif.Photo.SpatialFrequencyResponse", NULL, NULL },
430
{ 0x920d, EXIF_FORMAT_UNDEFINED, -1, "Noise", NULL, NULL },
431
{ 0x9211, EXIF_FORMAT_LONG_UNSIGNED, 1, "ImageNumber", NULL, NULL },
432
{ 0x9212, EXIF_FORMAT_STRING, 1, "SecurityClassification", NULL, NULL },
433
{ 0x9213, EXIF_FORMAT_STRING, -1, "ImageHistory", NULL, NULL },
434
{ 0x9215, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Exif.Photo.ExposureIndex", NULL, NULL },
435
{ 0x9216, EXIF_FORMAT_BYTE_UNSIGNED, 4, "TIFF/EPStandardID", NULL, NULL },
440
ExifMarker ExifUnknownMarkersList[] = {
441
{ 0x0000, EXIF_FORMAT_UNKNOWN, 0, "unknown", NULL, NULL },
442
{ 0x0000, EXIF_FORMAT_BYTE_UNSIGNED, -1, "unknown", NULL, NULL },
443
{ 0x0000, EXIF_FORMAT_STRING, -1, "unknown", NULL, NULL },
444
{ 0x0000, EXIF_FORMAT_SHORT_UNSIGNED, -1, "unknown", NULL, NULL },
445
{ 0x0000, EXIF_FORMAT_LONG_UNSIGNED, -1, "unknown", NULL, NULL },
446
{ 0x0000, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "unknown", NULL, NULL },
447
{ 0x0000, EXIF_FORMAT_BYTE, -1, "unknown", NULL, NULL },
448
{ 0x0000, EXIF_FORMAT_UNDEFINED, -1, "unknown", NULL, NULL },
449
{ 0x0000, EXIF_FORMAT_SHORT, -1, "unknown", NULL, NULL },
450
{ 0x0000, EXIF_FORMAT_LONG, -1, "unknown", NULL, NULL },
451
{ 0x0000, EXIF_FORMAT_RATIONAL, -1, "unknown", NULL, NULL },
452
{ 0x0000, EXIF_FORMAT_FLOAT, -1, "unknown", NULL, NULL },
453
{ 0x0000, EXIF_FORMAT_DOUBLE, -1, "unknown", NULL, NULL },
456
static const ExifMarker *exif_marker_from_tag(guint16 tag, const ExifMarker *list);
459
*-----------------------------------------------------------------------------
461
*-----------------------------------------------------------------------------
464
ExifItem *exif_item_new(ExifFormatType format, guint tag,
465
guint elements, const ExifMarker *marker)
469
item = g_new0(ExifItem, 1);
470
item->format = format;
472
item->marker = marker;
473
item->elements = elements;
479
case EXIF_FORMAT_UNKNOWN:
480
/* unknown, data is NULL */
483
case EXIF_FORMAT_BYTE_UNSIGNED:
484
item->data_len = sizeof(char) * elements;
486
case EXIF_FORMAT_STRING:
487
item->data_len = sizeof(char) * elements;
489
case EXIF_FORMAT_SHORT_UNSIGNED:
490
item->data_len = sizeof(guint16) * elements;
492
case EXIF_FORMAT_LONG_UNSIGNED:
493
item->data_len = sizeof(guint32) * elements;
495
case EXIF_FORMAT_RATIONAL_UNSIGNED:
496
item->data_len = sizeof(ExifRational) * elements;
498
case EXIF_FORMAT_BYTE:
499
item->data_len = sizeof(char) * elements;
501
case EXIF_FORMAT_UNDEFINED:
502
item->data_len = sizeof(char) * elements;
504
case EXIF_FORMAT_SHORT:
505
item->data_len = sizeof(gint16) * elements;
507
case EXIF_FORMAT_LONG:
508
item->data_len = sizeof(gint32) * elements;
510
case EXIF_FORMAT_RATIONAL:
511
item->data_len = sizeof(ExifRational) * elements;
513
case EXIF_FORMAT_FLOAT:
514
item->data_len = sizeof(float) * elements;
516
case EXIF_FORMAT_DOUBLE:
517
item->data_len = sizeof(double) * elements;
521
item->data = g_malloc0(item->data_len);
526
static void exif_item_free(ExifItem *item)
534
char *exif_item_get_tag_name(ExifItem *item)
536
if (!item || !item->marker) return NULL;
537
return g_strdup(item->marker->key);
540
guint exif_item_get_tag_id(ExifItem *item)
546
guint exif_item_get_elements(ExifItem *item)
549
return item->elements;
552
char *exif_item_get_data(ExifItem *item, guint *data_len)
555
*data_len = item->data_len;
556
return g_memdup(item->data, item->data_len);
559
guint exif_item_get_format_id(ExifItem *item)
561
if (!item) return EXIF_FORMAT_UNKNOWN;
566
char *exif_item_get_description(ExifItem *item)
568
if (!item || !item->marker) return NULL;
569
return g_strdup(_(item->marker->description));
572
const char *exif_item_get_format_name(ExifItem *item, gint brief)
574
if (!item || !item->marker) return NULL;
575
return (brief) ? ExifFormatList[item->format].short_name : ExifFormatList[item->format].description;
578
static GString *string_append_raw_bytes(GString *string, gpointer data, gint ne)
582
for (i = 0 ; i < ne; i++)
584
unsigned char c = ((char *)data)[i];
585
if (c < 32 || c > 127) c = '.';
586
g_string_append_printf(string, "%c", c);
588
string = g_string_append(string, " : ");
589
for (i = 0 ; i < ne; i++)
607
g_string_append_printf(string, "%s%02x", spacer, ((char *)data)[i]);
614
gchar *exif_text_list_find_value(ExifTextList *list, guint value)
616
gchar *result = NULL;
620
while (!result && list[i].value >= 0)
622
if (value == list[i].value) result = g_strdup(_(list[i].description));
625
if (!result) result = g_strdup_printf("%d (%s)", value, _("unknown"));
632
*-------------------------------------------------------------------
634
*-------------------------------------------------------------------
637
/* note: the align_buf is used to avoid alignment issues (on sparc) */
639
guint16 exif_byte_get_int16(unsigned char *f, ExifByteOrder bo)
643
memcpy(&align_buf, f, sizeof(guint16));
645
if (bo == EXIF_BYTE_ORDER_INTEL)
646
return GUINT16_FROM_LE(align_buf);
648
return GUINT16_FROM_BE(align_buf);
651
guint32 exif_byte_get_int32(unsigned char *f, ExifByteOrder bo)
655
memcpy(&align_buf, f, sizeof(guint32));
657
if (bo == EXIF_BYTE_ORDER_INTEL)
658
return GUINT32_FROM_LE(align_buf);
660
return GUINT32_FROM_BE(align_buf);
663
void exif_byte_put_int16(unsigned char *f, guint16 n, ExifByteOrder bo)
667
if (bo == EXIF_BYTE_ORDER_INTEL)
669
align_buf = GUINT16_TO_LE(n);
673
align_buf = GUINT16_TO_BE(n);
676
memcpy(f, &align_buf, sizeof(guint16));
679
void exif_byte_put_int32(unsigned char *f, guint32 n, ExifByteOrder bo)
683
if (bo == EXIF_BYTE_ORDER_INTEL)
685
align_buf = GUINT32_TO_LE(n);
689
align_buf = GUINT32_TO_BE(n);
692
memcpy(f, &align_buf, sizeof(guint32));
697
*-------------------------------------------------------------------
699
*-------------------------------------------------------------------
702
static const ExifMarker *exif_marker_from_tag(guint16 tag, const ExifMarker *list)
706
if (!list) return NULL;
708
while (list[i].tag != 0 && list[i].tag != tag)
713
return (list[i].tag == 0 ? NULL : &list[i]);
716
static void rational_from_data(ExifRational *r, void *src, ExifByteOrder bo)
718
r->num = exif_byte_get_int32(src, bo);
719
r->den = exif_byte_get_int32(src + sizeof(guint32), bo);
722
/* src_format and item->format must be compatible
723
* and not overrun src or item->data.
725
void exif_item_copy_data(ExifItem *item, void *src, guint len,
726
ExifFormatType src_format, ExifByteOrder bo)
733
bs = ExifFormatList[item->format].size;
738
ExifFormatList[src_format].size * ne > len)
740
gchar *tag = exif_item_get_tag_name(item);
741
printf("exif tag %s data size mismatch\n", tag);
746
switch (item->format)
748
case EXIF_FORMAT_UNKNOWN:
750
case EXIF_FORMAT_BYTE_UNSIGNED:
751
case EXIF_FORMAT_BYTE:
752
case EXIF_FORMAT_UNDEFINED:
753
memcpy(dest, src, len);
755
case EXIF_FORMAT_STRING:
756
memcpy(dest, src, len);
757
/* string is NULL terminated, make sure this is true */
758
if (((char *)dest)[len - 1] != '\0') ((char *)dest)[len - 1] = '\0';
760
case EXIF_FORMAT_SHORT_UNSIGNED:
761
case EXIF_FORMAT_SHORT:
762
for (i = 0; i < ne; i++)
764
((guint16 *)dest)[i] = exif_byte_get_int16(src + i * bs, bo);
767
case EXIF_FORMAT_LONG_UNSIGNED:
768
case EXIF_FORMAT_LONG:
769
if (src_format == EXIF_FORMAT_SHORT_UNSIGNED ||
770
src_format == EXIF_FORMAT_SHORT)
772
/* a short fits into a long, so allow it */
775
ss = ExifFormatList[src_format].size;
776
for (i = 0; i < ne; i++)
778
((gint32 *)dest)[i] =
779
(gint32)exif_byte_get_int16(src + i * ss, bo);
784
for (i = 0; i < ne; i++)
786
((gint32 *)dest)[i] =
787
exif_byte_get_int32(src + i * bs, bo);
791
case EXIF_FORMAT_RATIONAL_UNSIGNED:
792
case EXIF_FORMAT_RATIONAL:
793
for (i = 0; i < ne; i++)
795
rational_from_data(&((ExifRational *)dest)[i], src + i * bs, bo);
798
case EXIF_FORMAT_FLOAT:
799
for (i = 0; i < ne; i++)
801
((float *)dest)[i] = exif_byte_get_int32(src + i * bs, bo);
804
case EXIF_FORMAT_DOUBLE:
805
for (i = 0; i < ne; i++)
809
rational_from_data(&r, src + i * bs, bo);
810
if (r.den) ((double *)dest)[i] = (double)r.num / r.den;
816
static gint exif_parse_IFD_entry(ExifData *exif, unsigned char *tiff, guint offset,
817
guint size, ExifByteOrder bo,
819
const ExifMarker *list)
827
const ExifMarker *marker;
830
tag = exif_byte_get_int16(tiff + offset + EXIF_TIFD_OFFSET_TAG, bo);
831
format = exif_byte_get_int16(tiff + offset + EXIF_TIFD_OFFSET_FORMAT, bo);
832
count = exif_byte_get_int32(tiff + offset + EXIF_TIFD_OFFSET_COUNT, bo);
833
data_val = exif_byte_get_int32(tiff + offset + EXIF_TIFD_OFFSET_DATA, bo);
835
/* Check tag type. If it does not match, either the format is wrong,
836
* either it is a unknown tag; so it is not really an error.
838
marker = exif_marker_from_tag(tag, list);
841
if (format >= EXIF_FORMAT_COUNT)
843
printf("warning: exif tag 0x%4x has invalid format %d\n", tag, format);
846
/* allow non recognized tags to be displayed */
847
marker = &ExifUnknownMarkersList[format];
849
if (marker->format != format)
851
/* Some cameras got mixed up signed/unsigned_rational
852
* eg KODAK DC4800 on object_distance tag
854
* FIXME: what exactly is this test trying to do?
855
* ok, so this test is to allow the case of swapped signed/unsigned mismatch to leak through?
857
if (!(marker->format == EXIF_FORMAT_RATIONAL_UNSIGNED && format == EXIF_FORMAT_RATIONAL) &&
858
!(marker->format == EXIF_FORMAT_RATIONAL && format == EXIF_FORMAT_RATIONAL_UNSIGNED) &&
859
/* short fits into a long so allow this mismatch
860
* as well (some tags allowed to be unsigned short _or_ unsigned long)
862
!(marker->format == EXIF_FORMAT_LONG_UNSIGNED && format == EXIF_FORMAT_SHORT_UNSIGNED) )
864
if (format < EXIF_FORMAT_COUNT)
866
printf("warning: exif tag %s format mismatch, found %s exif spec requests %s\n",
867
marker->key, ExifFormatList[format].short_name,
868
ExifFormatList[marker->format].short_name);
872
printf("warning: exif tag %s format mismatch, found unknown id %d exif spec requests %d (%s)\n",
873
marker->key, format, marker->format,
874
ExifFormatList[marker->format].short_name);
880
/* Where is the data, is it available?
882
if (marker->components > 0 && marker->components != count)
884
printf("warning: exif tag %s has %d elements, exif spec requests %d\n",
885
marker->key, count, marker->components);
888
data_length = ExifFormatList[marker->format].size * count;
891
data_offset = data_val;
892
if (size < data_offset + data_length)
894
printf("warning: exif tag %s data will overrun end of file, ignored.\n", marker->key);
900
data_offset = offset + EXIF_TIFD_OFFSET_DATA;
903
item = exif_item_new(marker->format, tag, count, marker);
904
exif_item_copy_data(item, tiff + data_offset, data_length, format, bo);
905
exif->items = g_list_prepend(exif->items, item);
907
if (list == ExifKnownMarkersList)
912
exif_parse_IFD_table(exif, tiff, data_val, size, bo, level + 1, list);
914
case TAG_EXIFMAKERNOTE:
915
format_exif_makernote_parse(exif, tiff, data_val, size, bo);
923
gint exif_parse_IFD_table(ExifData *exif,
924
unsigned char *tiff, guint offset,
925
guint size, ExifByteOrder bo,
927
const ExifMarker *list)
932
/* limit damage from infinite loops */
933
if (level > EXIF_TIFF_MAX_LEVELS) return -1;
935
/* We should be able to read number of entries in IFD0) */
936
if (size < offset + 2) return -1;
938
count = exif_byte_get_int16(tiff + offset, bo);
941
/* Entries and next IFD offset must be readable */
942
if (size < offset + count * EXIF_TIFD_SIZE + 4) return -1;
944
for (i = 0; i < count; i++)
946
exif_parse_IFD_entry(exif, tiff, offset + i * EXIF_TIFD_SIZE, size, bo, level, list);
953
*-------------------------------------------------------------------
955
*-------------------------------------------------------------------
958
gint exif_tiff_directory_offset(unsigned char *data, const guint len,
959
guint *offset, ExifByteOrder *bo)
961
if (len < 8) return FALSE;
963
if (memcmp(data, "II", 2) == 0)
965
*bo = EXIF_BYTE_ORDER_INTEL;
967
else if (memcmp(data, "MM", 2) == 0)
969
*bo = EXIF_BYTE_ORDER_MOTOROLA;
976
if (exif_byte_get_int16(data + 2, *bo) != 0x002A)
981
*offset = exif_byte_get_int32(data + 4, *bo);
983
return (*offset < len);
986
gint exif_tiff_parse(ExifData *exif, unsigned char *tiff, guint size, ExifMarker *list)
991
if (!exif_tiff_directory_offset(tiff, size, &offset, &bo)) return -1;
993
return exif_parse_IFD_table(exif, tiff, offset, size, bo, 0, list);
998
*-------------------------------------------------------------------
1000
*-------------------------------------------------------------------
1003
#define JPEG_MARKER 0xFF
1004
#define JPEG_MARKER_SOI 0xD8
1005
#define JPEG_MARKER_EOI 0xD9
1006
#define JPEG_MARKER_APP1 0xE1
1007
#define JPEG_MARKER_APP2 0xE2
1009
/* jpeg container format:
1010
all data markers start with 0XFF
1011
2 byte long file start and end markers: 0xFFD8(SOI) and 0XFFD9(EOI)
1012
4 byte long data segment markers in format: 0xFFTTSSSSNNN...
1013
FF: 1 byte standard marker identifier
1014
TT: 1 byte data type
1015
SSSS: 2 bytes in Motorola byte alignment for length of the data.
1016
This value includes these 2 bytes in the count, making actual
1017
length of NN... == SSSS - 2.
1018
NNN.: the data in this segment
1020
static ExifMarker jpeg_color_marker = { 0x8773, EXIF_FORMAT_UNDEFINED, -1, "Exif.Image.InterColorProfile", NULL, NULL };
1022
void exif_add_jpeg_color_profile(ExifData *exif, unsigned char *cp_data, guint cp_length)
1024
ExifItem *item = exif_item_new(jpeg_color_marker.format, jpeg_color_marker.tag, 1,
1025
&jpeg_color_marker);
1027
item->data = cp_data;
1028
item->elements = cp_length;
1029
item->data_len = cp_length;
1030
exif->items = g_list_prepend(exif->items, item);
1034
static gint exif_jpeg_parse(ExifData *exif,
1035
unsigned char *data, guint size,
1038
guint seg_offset = 0;
1039
guint seg_length = 0;
1043
memcmp(data, "\xFF\xD8", 2) != 0)
1048
if (exif_jpeg_segment_find(data, size, JPEG_MARKER_APP1,
1050
&seg_offset, &seg_length))
1052
res = exif_tiff_parse(exif, data + seg_offset + 6, seg_length - 6, list);
1055
if (exif_jpeg_parse_color(exif, data, size))
1063
unsigned char *exif_get_color_profile(ExifData *exif, guint *data_len)
1065
ExifItem *prof_item = exif_get_item(exif, "Exif.Image.InterColorProfile");
1066
if (prof_item && exif_item_get_format_id(prof_item) == EXIF_FORMAT_UNDEFINED)
1067
return (unsigned char*) exif_item_get_data(prof_item, data_len);
1073
*-------------------------------------------------------------------
1075
*-------------------------------------------------------------------
1079
ExifItem *exif_get_first_item(ExifData *exif)
1083
ExifItem *ret = (ExifItem *)exif->items->data;
1084
exif->current = exif->items->next;
1087
exif->current = NULL;
1091
ExifItem *exif_get_next_item(ExifData *exif)
1095
ExifItem *ret = (ExifItem *)exif->current->data;
1096
exif->current = exif->current->next;
1102
static gint map_file(const gchar *path, void **mapping, int *size)
1107
if ((fd = open(path, O_RDONLY)) == -1)
1113
if (fstat(fd, &fs) == -1)
1122
if ((*mapping = mmap(0, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0)) == MAP_FAILED)
1133
static gint unmap_file(void *mapping, int size)
1135
if (munmap(mapping, size) == -1)
1144
void exif_free(ExifData *exif)
1153
ExifItem *item = work->data;
1155
exif_item_free(item);
1158
g_list_free(exif->items);
1162
ExifData *exif_read(gchar *path, gchar *sidecar_path)
1169
if (!path) return NULL;
1171
pathl = path_from_utf8(path);
1172
if (map_file(pathl, &f, &size) == -1)
1179
exif = g_new0(ExifData, 1);
1181
exif->current = NULL;
1183
if ((res = exif_jpeg_parse(exif, (unsigned char *)f, size,
1184
ExifKnownMarkersList)) == -2)
1186
res = exif_tiff_parse(exif, (unsigned char *)f, size, ExifKnownMarkersList);
1191
FormatRawExifType exif_type;
1192
FormatRawExifParseFunc exif_parse_func;
1195
exif_type = format_raw_exif_offset(f, size, &offset, &exif_parse_func);
1198
case FORMAT_RAW_EXIF_NONE:
1201
case FORMAT_RAW_EXIF_TIFF:
1202
res = exif_tiff_parse(exif, (unsigned char*)f + offset, size - offset,
1203
ExifKnownMarkersList);
1205
case FORMAT_RAW_EXIF_JPEG:
1206
res = exif_jpeg_parse(exif, (unsigned char*)f + offset, size - offset,
1207
ExifKnownMarkersList);
1209
case FORMAT_RAW_EXIF_IFD_II:
1210
case FORMAT_RAW_EXIF_IFD_MM:
1211
res = exif_parse_IFD_table(exif, (unsigned char*)f, offset, size - offset,
1212
(exif_type == FORMAT_RAW_EXIF_IFD_II) ?
1213
EXIF_BYTE_ORDER_INTEL : EXIF_BYTE_ORDER_MOTOROLA,
1214
0, ExifKnownMarkersList);
1216
case FORMAT_RAW_EXIF_PROPRIETARY:
1217
if (exif_parse_func)
1219
res = exif_parse_func((unsigned char*)f + offset, size - offset, exif);
1231
unmap_file(f, size);
1233
if (exif) exif->items = g_list_reverse(exif->items);
1236
exif_write_data_list(exif, stdout, TRUE);
1237
exif_write_data_list(exif, stdout, FALSE);
1243
ExifItem *exif_get_item(ExifData *exif, const gchar *key)
1247
if (!key) return NULL;
1256
if (item->marker->key && strcmp(key, item->marker->key) == 0) return item;
1261
#define EXIF_DATA_AS_TEXT_MAX_COUNT 16
1263
gchar *exif_item_get_string(ExifItem *item, int idx)
1265
return exif_item_get_data_as_text(item);
1269
gchar *exif_item_get_data_as_text(ExifItem *item)
1271
const ExifMarker *marker;
1278
if (!item) return NULL;
1280
marker = item->marker;
1281
if (!marker) return NULL;
1284
ne = item->elements;
1285
if (ne > EXIF_DATA_AS_TEXT_MAX_COUNT) ne = EXIF_DATA_AS_TEXT_MAX_COUNT;
1286
string = g_string_new("");
1287
switch (item->format)
1289
case EXIF_FORMAT_UNKNOWN:
1291
case EXIF_FORMAT_BYTE_UNSIGNED:
1292
case EXIF_FORMAT_BYTE:
1293
case EXIF_FORMAT_UNDEFINED:
1294
if (ne == 1 && marker->list)
1299
if (item->format == EXIF_FORMAT_BYTE_UNSIGNED ||
1300
item->format == EXIF_FORMAT_UNDEFINED)
1302
val = ((unsigned char *)data)[0];
1306
val = (unsigned char)(((signed char *)data)[0]);
1309
result = exif_text_list_find_value(marker->list, (guint)val);
1310
string = g_string_append(string, result);
1315
string = string_append_raw_bytes(string, data, ne);
1318
case EXIF_FORMAT_STRING:
1319
string = g_string_append(string, (gchar *)(item->data));
1321
case EXIF_FORMAT_SHORT_UNSIGNED:
1322
if (ne == 1 && marker->list)
1326
result = exif_text_list_find_value(marker->list, ((guint16 *)data)[0]);
1327
string = g_string_append(string, result);
1330
else for (i = 0; i < ne; i++)
1332
g_string_append_printf(string, "%s%hd", (i > 0) ? ", " : "",
1333
((guint16 *)data)[i]);
1336
case EXIF_FORMAT_LONG_UNSIGNED:
1337
for (i = 0; i < ne; i++)
1339
g_string_append_printf(string, "%s%ld", (i > 0) ? ", " : "",
1340
(unsigned long int)((guint32 *)data)[i]);
1343
case EXIF_FORMAT_RATIONAL_UNSIGNED:
1344
for (i = 0; i < ne; i++)
1348
r = &((ExifRational *)data)[i];
1349
g_string_append_printf(string, "%s%ld/%ld", (i > 0) ? ", " : "",
1350
(unsigned long)r->num, (unsigned long)r->den);
1353
case EXIF_FORMAT_SHORT:
1354
for (i = 0; i < ne; i++)
1356
g_string_append_printf(string, "%s%hd", (i > 0) ? ", " : "",
1357
((gint16 *)data)[i]);
1360
case EXIF_FORMAT_LONG:
1361
for (i = 0; i < ne; i++)
1363
g_string_append_printf(string, "%s%ld", (i > 0) ? ", " : "",
1364
(long int)((gint32 *)data)[i]);
1367
case EXIF_FORMAT_RATIONAL:
1368
for (i = 0; i < ne; i++)
1372
r = &((ExifRational *)data)[i];
1373
g_string_append_printf(string, "%s%ld/%ld", (i > 0) ? ", " : "",
1374
(long)r->num, (long)r->den);
1377
case EXIF_FORMAT_FLOAT:
1378
for (i = 0; i < ne; i++)
1380
g_string_append_printf(string, "%s%f", (i > 0) ? ", " : "",
1381
((float *)data)[i]);
1384
case EXIF_FORMAT_DOUBLE:
1385
for (i = 0; i < ne; i++)
1387
g_string_append_printf(string, "%s%f", (i > 0) ? ", " : "",
1388
((double *)data)[i]);
1393
if (item->elements > EXIF_DATA_AS_TEXT_MAX_COUNT &&
1394
item->format != EXIF_FORMAT_STRING)
1396
g_string_append(string, " ...");
1400
g_string_free(string, FALSE);
1405
gint exif_item_get_integer(ExifItem *item, gint *value)
1407
if (!item) return FALSE;
1409
switch (item->format)
1411
case EXIF_FORMAT_SHORT:
1412
*value = (gint)(((gint16 *)(item->data))[0]);
1415
case EXIF_FORMAT_SHORT_UNSIGNED:
1416
*value = (gint)(((guint16 *)(item->data))[0]);
1419
case EXIF_FORMAT_LONG:
1420
*value = (gint)(((gint32 *)(item->data))[0]);
1423
case EXIF_FORMAT_LONG_UNSIGNED:
1424
/* FIXME: overflow possible */
1425
*value = (gint)(((guint32 *)(item->data))[0]);
1428
/* all other type return FALSE */
1435
ExifRational *exif_item_get_rational(ExifItem *item, gint *sign)
1437
if (!item) return NULL;
1439
if (item->format == EXIF_FORMAT_RATIONAL ||
1440
item->format == EXIF_FORMAT_RATIONAL_UNSIGNED)
1442
if (sign) *sign = (item->format == EXIF_FORMAT_RATIONAL);
1443
return &((ExifRational *)(item->data))[0];
1449
const gchar *exif_get_tag_description_by_key(const gchar *key)
1453
if (!key) return NULL;
1456
while (ExifKnownMarkersList[i].tag > 0)
1458
if (strcmp(key, ExifKnownMarkersList[i].key) == 0) return _(ExifKnownMarkersList[i].description);
1465
static void exif_write_item(FILE *f, ExifItem *item)
1469
text = exif_item_get_data_as_text(item);
1472
gchar *tag = exif_item_get_tag_name(item);
1473
fprintf(f, "%4x %9s %30s %s\n", item->tag, ExifFormatList[item->format].short_name,
1480
void exif_write_data_list(ExifData *exif, FILE *f, gint human_readable_list)
1482
if (!f || !exif) return;
1484
fprintf(f, " tag format key value\n");
1485
fprintf(f, "----------------------------------------------------\n");
1487
if (human_readable_list)
1492
while (ExifFormattedList[i].key)
1496
text = exif_get_formatted_by_key(exif, ExifFormattedList[i].key, NULL);
1499
fprintf(f, " %9s %30s %s\n", "string", ExifFormattedList[i].key, text);
1516
exif_write_item(f, item);
1519
fprintf(f, "----------------------------------------------------\n");
1522
int exif_write(ExifData *exif)
1524
printf("Not compiled with EXIF write support");
1528
ExifItem *exif_add_item(ExifData *exif, const gchar *key)
1533
int exif_item_delete(ExifData *exif, ExifItem *item)
1538
int exif_item_set_string(ExifItem *item, const char *str)
1546
/* not HAVE_EXIV2 */