~vanvugt/ubuntu/oneiric/geeqie/fix-788321

« back to all changes in this revision

Viewing changes to src/exif.c

  • Committer: Bazaar Package Importer
  • Author(s): Michal Čihař
  • Date: 2008-06-10 08:42:37 UTC
  • Revision ID: james.westby@ubuntu.com-20080610084237-foorlvywoxj92o04
Tags: upstream-1.0~alpha1
Import upstream version 1.0~alpha1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  GQView
 
3
 *  (C) 2006 John Ellis
 
4
 *  Copyright (C) 2008 The Geeqie Team
 
5
 *
 
6
 *  Authors:
 
7
 *    Support for Exif file format, originally written by Eric Swalens.
 
8
 *    Modified by Quy Tonthat
 
9
 *
 
10
 *    Reimplemented with generic data storage by John Ellis (Nov 2003)
 
11
 *
 
12
 *  The tags were added with information from the FREE document:
 
13
 *     http://www.ba.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html
 
14
 *
 
15
 *  For the official Exif Format, please refer to:
 
16
 *     http://www.exif.org
 
17
 *     http://www.exif.org/specifications.html (PDF spec sheets)
 
18
 *
 
19
 *  Notes:
 
20
 *     Additional tag formats should be added to the proper
 
21
 *     location in ExifKnownMarkersList[].
 
22
 *
 
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'.
 
27
 *
 
28
 *  Unsupported at this time:
 
29
 *     IFD1 (thumbnail)
 
30
 *     MakerNote
 
31
 *     GPSInfo
 
32
 *
 
33
 *  TODO:
 
34
 *     Convert data to useable form in the ??_as_text function for:
 
35
 *        ComponentsConfiguration
 
36
 *        UserComment (convert this to UTF-8?)
 
37
 *
 
38
 
 
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.
 
43
 
 
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.
 
48
 
 
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.
 
52
*/
 
53
 
 
54
#ifdef HAVE_CONFIG_H
 
55
#  include "config.h"
 
56
#endif
 
57
 
 
58
#ifndef HAVE_EXIV2
 
59
 
 
60
#include <stdio.h>
 
61
#include <string.h>
 
62
#include <fcntl.h>
 
63
#include <unistd.h>
 
64
#include <sys/types.h>
 
65
#include <sys/stat.h>
 
66
#include <sys/mman.h>
 
67
#include <math.h>
 
68
 
 
69
#include <glib.h>
 
70
 
 
71
#include "intl.h"
 
72
 
 
73
#include "main.h"
 
74
#include "exif-int.h"
 
75
 
 
76
#include "format_raw.h"
 
77
#include "ui_fileops.h"
 
78
 
 
79
 
 
80
/*
 
81
 *-----------------------------------------------------------------------------
 
82
 * Tag formats
 
83
 *-----------------------------------------------------------------------------
 
84
 */
 
85
 
 
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" },
 
100
        { -1, 0, NULL }
 
101
};
 
102
 
 
103
/* tags that are special, or need special treatment */
 
104
#define TAG_EXIFOFFSET          0x8769
 
105
#define TAG_EXIFMAKERNOTE       0x927c
 
106
 
 
107
 
 
108
/*
 
109
 *-----------------------------------------------------------------------------
 
110
 * Data
 
111
 *-----------------------------------------------------------------------------
 
112
 */
 
113
static ExifTextList ExifCompressionList[] = {
 
114
        { 1, "Uncompressed" },
 
115
        { 2, "CCITT 1D" },
 
116
        { 3, "T4/Group 3 Fax" },
 
117
        { 4, "T6/Group 4 Fax" },
 
118
        { 5, "LZW" },
 
119
        { 6, "JPEG (old style)" },
 
120
        { 7, "JPEG" },
 
121
        { 8, "Adobe Deflate" },
 
122
        { 9, "JBIG B&W" },
 
123
        { 10, "JBIG Color" },
 
124
        { 32766, "Next" },
 
125
        { 32771, "CCIRLEW" },
 
126
        { 32773, "PackBits" },
 
127
        { 32809, "ThunderScan" },
 
128
        { 32895, "IT8CTPAD" },
 
129
        { 32896, "IT8LW" },
 
130
        { 32897, "IT8MP" },
 
131
        { 32898, "IT8BL" },
 
132
        { 32908, "PixasFilm" },
 
133
        { 32909, "PixasLog" },
 
134
        { 32946, "Deflate" },
 
135
        { 32947, "DCS" },
 
136
        { 34661, "JBIG" },
 
137
        { 34676, "SGILog" },
 
138
        { 34677, "SGILog24" },
 
139
        { 34712, "JPEF 2000" },
 
140
        { 34713, "Nikon NEF Compressed" },
 
141
        EXIF_TEXT_LIST_END
 
142
};
 
143
 
 
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") },
 
154
        EXIF_TEXT_LIST_END
 
155
};
 
156
 
 
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") },
 
162
        EXIF_TEXT_LIST_END
 
163
};
 
164
 
 
165
static ExifTextList ExifYCbCrPosList[] = {
 
166
        { 1,    "center" },
 
167
        { 2,    "datum" },
 
168
        EXIF_TEXT_LIST_END
 
169
};
 
170
 
 
171
static ExifTextList ExifMeteringModeList[] = {
 
172
        { 0,    N_("unknown") },
 
173
        { 1,    N_("average") },
 
174
        { 2,    N_("center weighted") },
 
175
        { 3,    N_("spot") },
 
176
        { 4,    N_("multi-spot") },
 
177
        { 5,    N_("multi-segment") },
 
178
        { 6,    N_("partial") },
 
179
        { 255,  N_("other") },
 
180
        EXIF_TEXT_LIST_END
 
181
};
 
182
 
 
183
static ExifTextList ExifExposureProgramList[] = {
 
184
        { 0,    N_("not defined") },
 
185
        { 1,    N_("manual") },
 
186
        { 2,    N_("normal") },
 
187
        { 3,    N_("aperture") },
 
188
        { 4,    N_("shutter") },
 
189
        { 5,    N_("creative") },
 
190
        { 6,    N_("action") },
 
191
        { 7,    N_("portrait") },
 
192
        { 8,    N_("landscape") },
 
193
        EXIF_TEXT_LIST_END
 
194
};
 
195
 
 
196
static ExifTextList ExifLightSourceList[] = {
 
197
        { 0,    N_("unknown") },
 
198
        { 1,    N_("daylight") },
 
199
        { 2,    N_("fluorescent") },
 
200
        { 3,    N_("tungsten (incandescent)") },
 
201
        { 4,    N_("flash") },
 
202
        { 9,    N_("fine weather") },
 
203
        { 10,   N_("cloudy weather") },
 
204
        { 11,   N_("shade") },
 
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") },
 
212
        { 20,   N_("D55") },
 
213
        { 21,   N_("D65") },
 
214
        { 22,   N_("D75") },
 
215
        { 23,   N_("D50") },
 
216
        { 24,   N_("ISO studio tungsten") },
 
217
        { 255,  N_("other") },
 
218
        EXIF_TEXT_LIST_END
 
219
};
 
220
 
 
221
static ExifTextList ExifFlashList[] = {
 
222
        { 0,    N_("no") },
 
223
        { 1,    N_("yes") },
 
224
        { 5,    N_("yes, not detected by strobe") },
 
225
        { 7,    N_("yes, detected by strobe") },
 
226
        EXIF_TEXT_LIST_END
 
227
};
 
228
 
 
229
static ExifTextList ExifColorSpaceList[] = {
 
230
        { 1,    N_("sRGB") },
 
231
        { 65535,N_("uncalibrated") },
 
232
        EXIF_TEXT_LIST_END
 
233
};
 
234
 
 
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") },
 
243
        EXIF_TEXT_LIST_END
 
244
};
 
245
 
 
246
static ExifTextList ExifSourceList[] = {
 
247
        { 3,    N_("digital still camera") },
 
248
        EXIF_TEXT_LIST_END
 
249
};
 
250
 
 
251
static ExifTextList ExifSceneList[] = {
 
252
        { 1,    N_("direct photo") },
 
253
        EXIF_TEXT_LIST_END
 
254
};
 
255
 
 
256
static ExifTextList ExifCustRenderList[] = {
 
257
        { 0,    N_("normal") },
 
258
        { 1,    N_("custom") },
 
259
        EXIF_TEXT_LIST_END
 
260
};
 
261
 
 
262
static ExifTextList ExifExposureModeList[] = {
 
263
        { 0,    N_("auto") },
 
264
        { 1,    N_("manual") },
 
265
        { 2,    N_("auto bracket") },
 
266
        EXIF_TEXT_LIST_END
 
267
};
 
268
 
 
269
static ExifTextList ExifWhiteBalanceList[] = {
 
270
        { 0,    N_("auto") },
 
271
        { 1,    N_("manual") },
 
272
        EXIF_TEXT_LIST_END
 
273
};
 
274
 
 
275
static ExifTextList ExifSceneCaptureList[] = {
 
276
        { 0,    N_("standard") },
 
277
        { 1,    N_("landscape") },
 
278
        { 2,    N_("portrait") },
 
279
        { 3,    N_("night scene") },
 
280
        EXIF_TEXT_LIST_END
 
281
};
 
282
 
 
283
static ExifTextList ExifGainControlList[] = {
 
284
        { 0,    N_("none") },
 
285
        { 1,    N_("low gain up") },
 
286
        { 2,    N_("high gain up") },
 
287
        { 3,    N_("low gain down") },
 
288
        { 4,    N_("high gain down") },
 
289
        EXIF_TEXT_LIST_END
 
290
};
 
291
 
 
292
static ExifTextList ExifContrastList[] = {
 
293
        { 0,    N_("normal") },
 
294
        { 1,    N_("soft") },
 
295
        { 2,    N_("hard") },
 
296
        EXIF_TEXT_LIST_END
 
297
};
 
298
 
 
299
static ExifTextList ExifSaturationList[] = {
 
300
        { 0,    N_("normal") },
 
301
        { 1,    N_("low") },
 
302
        { 2,    N_("high") },
 
303
        EXIF_TEXT_LIST_END
 
304
};
 
305
 
 
306
static ExifTextList ExifSharpnessList[] = {
 
307
        { 0,    N_("normal") },
 
308
        { 1,    N_("soft") },
 
309
        { 2,    N_("hard") },
 
310
        EXIF_TEXT_LIST_END
 
311
};
 
312
 
 
313
static ExifTextList ExifSubjectRangeList[] = {
 
314
        { 0,    N_("unknown") },
 
315
        { 1,    N_("macro") },
 
316
        { 2,    N_("close") },
 
317
        { 3,    N_("distant") },
 
318
        EXIF_TEXT_LIST_END
 
319
};
 
320
 
 
321
/*
 
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
 
324
*/
 
325
 
 
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 },
 
347
        /* subIFD follows */
 
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 },
 
436
 
 
437
EXIF_MARKER_LIST_END
 
438
};
 
439
 
 
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 },
 
454
};
 
455
 
 
456
static const ExifMarker *exif_marker_from_tag(guint16 tag, const ExifMarker *list);
 
457
 
 
458
/*
 
459
 *-----------------------------------------------------------------------------
 
460
 * ExifItem
 
461
 *-----------------------------------------------------------------------------
 
462
 */
 
463
 
 
464
ExifItem *exif_item_new(ExifFormatType format, guint tag,
 
465
                        guint elements, const ExifMarker *marker)
 
466
{
 
467
        ExifItem *item;
 
468
 
 
469
        item = g_new0(ExifItem, 1);
 
470
        item->format = format;
 
471
        item->tag = tag;
 
472
        item->marker = marker;
 
473
        item->elements = elements;
 
474
        item->data = NULL;
 
475
        item->data_len = 0;
 
476
 
 
477
        switch (format)
 
478
                {
 
479
                case EXIF_FORMAT_UNKNOWN:
 
480
                        /* unknown, data is NULL */
 
481
                        return item;
 
482
                        break;
 
483
                case EXIF_FORMAT_BYTE_UNSIGNED:
 
484
                        item->data_len = sizeof(char) * elements;
 
485
                        break;
 
486
                case EXIF_FORMAT_STRING:
 
487
                        item->data_len = sizeof(char) * elements;
 
488
                        break;
 
489
                case EXIF_FORMAT_SHORT_UNSIGNED:
 
490
                        item->data_len = sizeof(guint16) * elements;
 
491
                        break;
 
492
                case EXIF_FORMAT_LONG_UNSIGNED:
 
493
                        item->data_len = sizeof(guint32) * elements;
 
494
                        break;
 
495
                case EXIF_FORMAT_RATIONAL_UNSIGNED:
 
496
                        item->data_len = sizeof(ExifRational) * elements;
 
497
                        break;
 
498
                case EXIF_FORMAT_BYTE:
 
499
                        item->data_len = sizeof(char) * elements;
 
500
                        break;
 
501
                case EXIF_FORMAT_UNDEFINED:
 
502
                        item->data_len = sizeof(char) * elements;
 
503
                        break;
 
504
                case EXIF_FORMAT_SHORT:
 
505
                        item->data_len = sizeof(gint16) * elements;
 
506
                        break;
 
507
                case EXIF_FORMAT_LONG:
 
508
                        item->data_len = sizeof(gint32) * elements;
 
509
                        break;
 
510
                case EXIF_FORMAT_RATIONAL:
 
511
                        item->data_len = sizeof(ExifRational) * elements;
 
512
                        break;
 
513
                case EXIF_FORMAT_FLOAT:
 
514
                        item->data_len = sizeof(float) * elements;
 
515
                        break;
 
516
                case EXIF_FORMAT_DOUBLE:
 
517
                        item->data_len = sizeof(double) * elements;
 
518
                        break;
 
519
                }
 
520
 
 
521
        item->data = g_malloc0(item->data_len);
 
522
 
 
523
        return item;
 
524
}
 
525
 
 
526
static void exif_item_free(ExifItem *item)
 
527
{
 
528
        if (!item) return;
 
529
 
 
530
        g_free(item->data);
 
531
        g_free(item);
 
532
}
 
533
 
 
534
char *exif_item_get_tag_name(ExifItem *item)
 
535
{
 
536
        if (!item || !item->marker) return NULL;
 
537
        return g_strdup(item->marker->key);
 
538
}
 
539
 
 
540
guint exif_item_get_tag_id(ExifItem *item)
 
541
{
 
542
        if (!item) return 0;
 
543
        return item->tag;
 
544
}
 
545
 
 
546
guint exif_item_get_elements(ExifItem *item)
 
547
{
 
548
        if (!item) return 0;
 
549
        return item->elements;
 
550
}
 
551
 
 
552
char *exif_item_get_data(ExifItem *item, guint *data_len)
 
553
{
 
554
        if (data_len)
 
555
                *data_len = item->data_len;
 
556
        return g_memdup(item->data, item->data_len);
 
557
}
 
558
 
 
559
guint exif_item_get_format_id(ExifItem *item)
 
560
{
 
561
        if (!item) return EXIF_FORMAT_UNKNOWN;
 
562
        return item->format;
 
563
}
 
564
 
 
565
 
 
566
char *exif_item_get_description(ExifItem *item)
 
567
{
 
568
        if (!item || !item->marker) return NULL;
 
569
        return g_strdup(_(item->marker->description));
 
570
}
 
571
 
 
572
const char *exif_item_get_format_name(ExifItem *item, gint brief)
 
573
{
 
574
        if (!item || !item->marker) return NULL;
 
575
        return (brief) ? ExifFormatList[item->format].short_name : ExifFormatList[item->format].description;
 
576
}
 
577
 
 
578
static GString *string_append_raw_bytes(GString *string, gpointer data, gint ne)
 
579
{
 
580
        gint i;
 
581
 
 
582
        for (i = 0 ; i < ne; i++)
 
583
                {
 
584
                unsigned char c = ((char *)data)[i];
 
585
                if (c < 32 || c > 127) c = '.';
 
586
                g_string_append_printf(string, "%c", c);
 
587
                }
 
588
        string = g_string_append(string, " : ");
 
589
        for (i = 0 ; i < ne; i++)
 
590
                {
 
591
                const gchar *spacer;
 
592
                if (i > 0)
 
593
                        {
 
594
                        if (i%8 == 0)
 
595
                                {
 
596
                                spacer = " - ";
 
597
                                }
 
598
                        else
 
599
                                {
 
600
                                spacer = " ";
 
601
                                }
 
602
                        }
 
603
                else
 
604
                        {
 
605
                        spacer = "";
 
606
                        }
 
607
                g_string_append_printf(string, "%s%02x", spacer, ((char *)data)[i]);
 
608
                }
 
609
 
 
610
        return string;
 
611
}
 
612
 
 
613
 
 
614
gchar *exif_text_list_find_value(ExifTextList *list, guint value)
 
615
{
 
616
        gchar *result = NULL;
 
617
        gint i;
 
618
 
 
619
        i = 0;
 
620
        while (!result && list[i].value >= 0)
 
621
                {
 
622
                if (value == list[i].value) result = g_strdup(_(list[i].description));
 
623
                i++;
 
624
                }
 
625
        if (!result) result = g_strdup_printf("%d (%s)", value, _("unknown"));
 
626
 
 
627
        return result;
 
628
}
 
629
 
 
630
 
 
631
/*
 
632
 *-------------------------------------------------------------------
 
633
 * byte order utils
 
634
 *-------------------------------------------------------------------
 
635
 */
 
636
 
 
637
/* note: the align_buf is used to avoid alignment issues (on sparc) */
 
638
 
 
639
guint16 exif_byte_get_int16(unsigned char *f, ExifByteOrder bo)
 
640
{
 
641
        guint16 align_buf;
 
642
 
 
643
        memcpy(&align_buf, f, sizeof(guint16));
 
644
 
 
645
        if (bo == EXIF_BYTE_ORDER_INTEL)
 
646
                return GUINT16_FROM_LE(align_buf);
 
647
        else
 
648
                return GUINT16_FROM_BE(align_buf);
 
649
}
 
650
 
 
651
guint32 exif_byte_get_int32(unsigned char *f, ExifByteOrder bo)
 
652
{
 
653
        guint32 align_buf;
 
654
 
 
655
        memcpy(&align_buf, f, sizeof(guint32));
 
656
 
 
657
        if (bo == EXIF_BYTE_ORDER_INTEL)
 
658
                return GUINT32_FROM_LE(align_buf);
 
659
        else
 
660
                return GUINT32_FROM_BE(align_buf);
 
661
}
 
662
 
 
663
void exif_byte_put_int16(unsigned char *f, guint16 n, ExifByteOrder bo)
 
664
{
 
665
        guint16 align_buf;
 
666
 
 
667
        if (bo == EXIF_BYTE_ORDER_INTEL)
 
668
                {
 
669
                align_buf = GUINT16_TO_LE(n);
 
670
                }
 
671
        else
 
672
                {
 
673
                align_buf = GUINT16_TO_BE(n);
 
674
                }
 
675
 
 
676
        memcpy(f, &align_buf, sizeof(guint16));
 
677
}
 
678
 
 
679
void exif_byte_put_int32(unsigned char *f, guint32 n, ExifByteOrder bo)
 
680
{
 
681
        guint32 align_buf;
 
682
 
 
683
        if (bo == EXIF_BYTE_ORDER_INTEL)
 
684
                {
 
685
                align_buf = GUINT32_TO_LE(n);
 
686
                }
 
687
        else
 
688
                {
 
689
                align_buf = GUINT32_TO_BE(n);
 
690
                }
 
691
 
 
692
        memcpy(f, &align_buf, sizeof(guint32));
 
693
}
 
694
 
 
695
 
 
696
/*
 
697
 *-------------------------------------------------------------------
 
698
 * IFD utils
 
699
 *-------------------------------------------------------------------
 
700
 */
 
701
 
 
702
static const ExifMarker *exif_marker_from_tag(guint16 tag, const ExifMarker *list)
 
703
{
 
704
        gint i = 0;
 
705
 
 
706
        if (!list) return NULL;
 
707
 
 
708
        while (list[i].tag != 0 && list[i].tag != tag)
 
709
                {
 
710
                i++;
 
711
                }
 
712
 
 
713
        return (list[i].tag == 0 ? NULL : &list[i]);
 
714
}
 
715
 
 
716
static void rational_from_data(ExifRational *r, void *src, ExifByteOrder bo)
 
717
{
 
718
        r->num = exif_byte_get_int32(src, bo);
 
719
        r->den = exif_byte_get_int32(src + sizeof(guint32), bo);
 
720
}
 
721
 
 
722
/* src_format and item->format must be compatible
 
723
 * and not overrun src or item->data.
 
724
 */
 
725
void exif_item_copy_data(ExifItem *item, void *src, guint len,
 
726
                         ExifFormatType src_format, ExifByteOrder bo)
 
727
{
 
728
        gint bs;
 
729
        gint ne;
 
730
        gpointer dest;
 
731
        gint i;
 
732
 
 
733
        bs = ExifFormatList[item->format].size;
 
734
        ne = item->elements;
 
735
        dest = item->data;
 
736
 
 
737
        if (!dest ||
 
738
            ExifFormatList[src_format].size * ne > len)
 
739
                {
 
740
                gchar *tag = exif_item_get_tag_name(item);
 
741
                printf("exif tag %s data size mismatch\n", tag);
 
742
                g_free(tag);
 
743
                return;
 
744
                }
 
745
 
 
746
        switch (item->format)
 
747
                {
 
748
                case EXIF_FORMAT_UNKNOWN:
 
749
                        break;
 
750
                case EXIF_FORMAT_BYTE_UNSIGNED:
 
751
                case EXIF_FORMAT_BYTE:
 
752
                case EXIF_FORMAT_UNDEFINED:
 
753
                        memcpy(dest, src, len);
 
754
                        break;
 
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';
 
759
                        break;
 
760
                case EXIF_FORMAT_SHORT_UNSIGNED:
 
761
                case EXIF_FORMAT_SHORT:
 
762
                        for (i = 0; i < ne; i++)
 
763
                                {
 
764
                                ((guint16 *)dest)[i] = exif_byte_get_int16(src + i * bs, bo);
 
765
                                }
 
766
                        break;
 
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)
 
771
                                {
 
772
                                /* a short fits into a long, so allow it */
 
773
                                gint ss;
 
774
 
 
775
                                ss = ExifFormatList[src_format].size;
 
776
                                for (i = 0; i < ne; i++)
 
777
                                        {
 
778
                                        ((gint32 *)dest)[i] =
 
779
                                                (gint32)exif_byte_get_int16(src + i * ss, bo);
 
780
                                        }
 
781
                                }
 
782
                        else
 
783
                                {
 
784
                                for (i = 0; i < ne; i++)
 
785
                                        {
 
786
                                        ((gint32 *)dest)[i] =
 
787
                                                exif_byte_get_int32(src + i * bs, bo);
 
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, bo);
 
796
                                }
 
797
                        break;
 
798
                case EXIF_FORMAT_FLOAT:
 
799
                        for (i = 0; i < ne; i++)
 
800
                                {
 
801
                                ((float *)dest)[i] = exif_byte_get_int32(src + i * bs, bo);
 
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, bo);
 
810
                                if (r.den) ((double *)dest)[i] = (double)r.num / r.den;
 
811
                                }
 
812
                        break;
 
813
                }
 
814
}
 
815
 
 
816
static gint exif_parse_IFD_entry(ExifData *exif, unsigned char *tiff, guint offset,
 
817
                                 guint size, ExifByteOrder bo,
 
818
                                 gint level,
 
819
                                 const ExifMarker *list)
 
820
{
 
821
        guint tag;
 
822
        guint format;
 
823
        guint count;
 
824
        guint data_val;
 
825
        guint data_offset;
 
826
        guint data_length;
 
827
        const ExifMarker *marker;
 
828
        ExifItem *item;
 
829
 
 
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);
 
834
 
 
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.
 
837
         */
 
838
        marker = exif_marker_from_tag(tag, list);
 
839
        if (!marker)
 
840
                {
 
841
                if (format >= EXIF_FORMAT_COUNT)
 
842
                        {
 
843
                        printf("warning: exif tag 0x%4x has invalid format %d\n", tag, format);
 
844
                        return 0;
 
845
                        }
 
846
                /* allow non recognized tags to be displayed */
 
847
                marker = &ExifUnknownMarkersList[format];
 
848
                }
 
849
        if (marker->format != format)
 
850
                {
 
851
                /* Some cameras got mixed up signed/unsigned_rational
 
852
                 * eg KODAK DC4800 on object_distance tag
 
853
                 *
 
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?
 
856
                 */
 
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)
 
861
                         */
 
862
                    !(marker->format == EXIF_FORMAT_LONG_UNSIGNED && format == EXIF_FORMAT_SHORT_UNSIGNED) )
 
863
                        {
 
864
                        if (format < EXIF_FORMAT_COUNT)
 
865
                                {
 
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);
 
869
                                }
 
870
                        else
 
871
                                {
 
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);
 
875
                                }
 
876
                        return 0;
 
877
                        }
 
878
                }
 
879
 
 
880
        /* Where is the data, is it available?
 
881
         */
 
882
        if (marker->components > 0 && marker->components != count)
 
883
                {
 
884
                printf("warning: exif tag %s has %d elements, exif spec requests %d\n",
 
885
                        marker->key, count, marker->components);
 
886
                }
 
887
 
 
888
        data_length = ExifFormatList[marker->format].size * count;
 
889
        if (data_length > 4)
 
890
                {
 
891
                data_offset = data_val;
 
892
                if (size < data_offset + data_length)
 
893
                        {
 
894
                        printf("warning: exif tag %s data will overrun end of file, ignored.\n", marker->key);
 
895
                        return -1;
 
896
                        }
 
897
                }
 
898
        else
 
899
                {
 
900
                data_offset = offset + EXIF_TIFD_OFFSET_DATA;
 
901
                }
 
902
 
 
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);
 
906
 
 
907
        if (list == ExifKnownMarkersList)
 
908
                {
 
909
                switch (item->tag)
 
910
                        {
 
911
                        case TAG_EXIFOFFSET:
 
912
                                exif_parse_IFD_table(exif, tiff, data_val, size, bo, level + 1, list);
 
913
                                break;
 
914
                        case TAG_EXIFMAKERNOTE:
 
915
                                format_exif_makernote_parse(exif, tiff, data_val, size, bo);
 
916
                                break;
 
917
                        }
 
918
                }
 
919
 
 
920
        return 0;
 
921
}
 
922
 
 
923
gint exif_parse_IFD_table(ExifData *exif,
 
924
                          unsigned char *tiff, guint offset,
 
925
                          guint size, ExifByteOrder bo,
 
926
                          gint level,
 
927
                          const ExifMarker *list)
 
928
{
 
929
        guint count;
 
930
        guint i;
 
931
 
 
932
        /* limit damage from infinite loops */
 
933
        if (level > EXIF_TIFF_MAX_LEVELS) return -1;
 
934
 
 
935
        /* We should be able to read number of entries in IFD0) */
 
936
        if (size < offset + 2) return -1;
 
937
 
 
938
        count = exif_byte_get_int16(tiff + offset, bo);
 
939
        offset += 2;
 
940
 
 
941
        /* Entries and next IFD offset must be readable */
 
942
        if (size < offset + count * EXIF_TIFD_SIZE + 4) return -1;
 
943
 
 
944
        for (i = 0; i < count; i++)
 
945
                {
 
946
                exif_parse_IFD_entry(exif, tiff, offset + i * EXIF_TIFD_SIZE, size, bo, level, list);
 
947
                }
 
948
 
 
949
        return 0;
 
950
}
 
951
 
 
952
/*
 
953
 *-------------------------------------------------------------------
 
954
 * file formats
 
955
 *-------------------------------------------------------------------
 
956
 */
 
957
 
 
958
gint exif_tiff_directory_offset(unsigned char *data, const guint len,
 
959
                                guint *offset, ExifByteOrder *bo)
 
960
{
 
961
        if (len < 8) return FALSE;
 
962
 
 
963
        if (memcmp(data, "II", 2) == 0)
 
964
                {
 
965
                *bo = EXIF_BYTE_ORDER_INTEL;
 
966
                }
 
967
        else if (memcmp(data, "MM", 2) == 0)
 
968
                {
 
969
                *bo = EXIF_BYTE_ORDER_MOTOROLA;
 
970
                }
 
971
        else
 
972
                {
 
973
                return FALSE;
 
974
                }
 
975
 
 
976
        if (exif_byte_get_int16(data + 2, *bo) != 0x002A)
 
977
                {
 
978
                return FALSE;
 
979
                }
 
980
 
 
981
        *offset = exif_byte_get_int32(data + 4, *bo);
 
982
 
 
983
        return (*offset < len);
 
984
}
 
985
 
 
986
gint exif_tiff_parse(ExifData *exif, unsigned char *tiff, guint size, ExifMarker *list)
 
987
{
 
988
        ExifByteOrder bo;
 
989
        guint offset;
 
990
 
 
991
        if (!exif_tiff_directory_offset(tiff, size, &offset, &bo)) return -1;
 
992
 
 
993
        return exif_parse_IFD_table(exif, tiff, offset, size, bo, 0, list);
 
994
}
 
995
 
 
996
 
 
997
/*
 
998
 *-------------------------------------------------------------------
 
999
 * jpeg marker utils
 
1000
 *-------------------------------------------------------------------
 
1001
 */
 
1002
 
 
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
 
1008
 
 
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
 
1019
 */
 
1020
static ExifMarker jpeg_color_marker = { 0x8773, EXIF_FORMAT_UNDEFINED, -1, "Exif.Image.InterColorProfile", NULL, NULL };
 
1021
 
 
1022
void exif_add_jpeg_color_profile(ExifData *exif, unsigned char *cp_data, guint cp_length)
 
1023
{
 
1024
        ExifItem *item = exif_item_new(jpeg_color_marker.format, jpeg_color_marker.tag, 1,
 
1025
                                     &jpeg_color_marker);
 
1026
        g_free(item->data);
 
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);
 
1031
 
 
1032
}
 
1033
 
 
1034
static gint exif_jpeg_parse(ExifData *exif,
 
1035
                            unsigned char *data, guint size,
 
1036
                            ExifMarker *list)
 
1037
{
 
1038
        guint seg_offset = 0;
 
1039
        guint seg_length = 0;
 
1040
        gint res = -1;
 
1041
 
 
1042
        if (size < 4 ||
 
1043
            memcmp(data, "\xFF\xD8", 2) != 0)
 
1044
                {
 
1045
                return -2;
 
1046
                }
 
1047
 
 
1048
        if (exif_jpeg_segment_find(data, size, JPEG_MARKER_APP1,
 
1049
                                   "Exif\x00\x00", 6,
 
1050
                                   &seg_offset, &seg_length))
 
1051
                {
 
1052
                res = exif_tiff_parse(exif, data + seg_offset + 6, seg_length - 6, list);
 
1053
                }
 
1054
 
 
1055
        if (exif_jpeg_parse_color(exif, data, size))
 
1056
                {
 
1057
                res = 0;
 
1058
                }
 
1059
 
 
1060
        return res;
 
1061
}
 
1062
 
 
1063
unsigned char *exif_get_color_profile(ExifData *exif, guint *data_len)
 
1064
{
 
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);
 
1068
        return NULL;
 
1069
}
 
1070
 
 
1071
 
 
1072
/*
 
1073
 *-------------------------------------------------------------------
 
1074
 * misc
 
1075
 *-------------------------------------------------------------------
 
1076
 */
 
1077
 
 
1078
 
 
1079
ExifItem *exif_get_first_item(ExifData *exif)
 
1080
{
 
1081
        if (exif->items)
 
1082
                {
 
1083
                ExifItem *ret = (ExifItem *)exif->items->data;
 
1084
                exif->current = exif->items->next;
 
1085
                return ret;
 
1086
                }
 
1087
        exif->current = NULL;
 
1088
        return NULL;
 
1089
}
 
1090
 
 
1091
ExifItem *exif_get_next_item(ExifData *exif)
 
1092
{
 
1093
        if (exif->current)
 
1094
                {
 
1095
                ExifItem *ret = (ExifItem *)exif->current->data;
 
1096
                exif->current = exif->current->next;
 
1097
                return ret;
 
1098
                }
 
1099
        return NULL;
 
1100
}
 
1101
 
 
1102
static gint map_file(const gchar *path, void **mapping, int *size)
 
1103
{
 
1104
        int fd;
 
1105
        struct stat fs;
 
1106
 
 
1107
        if ((fd = open(path, O_RDONLY)) == -1)
 
1108
                {
 
1109
                perror(path);
 
1110
                return -1;
 
1111
                }
 
1112
 
 
1113
        if (fstat(fd, &fs) == -1)
 
1114
                {
 
1115
                perror(path);
 
1116
                close(fd);
 
1117
                return -1;
 
1118
                }
 
1119
 
 
1120
        *size = fs.st_size;
 
1121
 
 
1122
        if ((*mapping = mmap(0, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0)) == MAP_FAILED)
 
1123
                {
 
1124
                perror(path);
 
1125
                close(fd);
 
1126
                return -1;
 
1127
                }
 
1128
 
 
1129
        close(fd);
 
1130
        return 0;
 
1131
}
 
1132
 
 
1133
static gint unmap_file(void *mapping, int size)
 
1134
{
 
1135
        if (munmap(mapping, size) == -1)
 
1136
                {
 
1137
                perror("munmap");
 
1138
                return -1;
 
1139
                }
 
1140
 
 
1141
        return 0;
 
1142
}
 
1143
 
 
1144
void exif_free(ExifData *exif)
 
1145
{
 
1146
        GList *work;
 
1147
 
 
1148
        if (!exif) return;
 
1149
 
 
1150
        work = exif->items;
 
1151
        while (work)
 
1152
                {
 
1153
                ExifItem *item = work->data;
 
1154
                work = work->next;
 
1155
                exif_item_free(item);
 
1156
                }
 
1157
 
 
1158
        g_list_free(exif->items);
 
1159
        g_free(exif);
 
1160
}
 
1161
 
 
1162
ExifData *exif_read(gchar *path, gchar *sidecar_path)
 
1163
{
 
1164
        ExifData *exif;
 
1165
        void *f;
 
1166
        int size, res;
 
1167
        gchar *pathl;
 
1168
 
 
1169
        if (!path) return NULL;
 
1170
 
 
1171
        pathl = path_from_utf8(path);
 
1172
        if (map_file(pathl, &f, &size) == -1)
 
1173
                {
 
1174
                g_free(pathl);
 
1175
                return NULL;
 
1176
                }
 
1177
        g_free(pathl);
 
1178
 
 
1179
        exif = g_new0(ExifData, 1);
 
1180
        exif->items = NULL;
 
1181
        exif->current = NULL;
 
1182
 
 
1183
        if ((res = exif_jpeg_parse(exif, (unsigned char *)f, size,
 
1184
                                   ExifKnownMarkersList)) == -2)
 
1185
                {
 
1186
                res = exif_tiff_parse(exif, (unsigned char *)f, size, ExifKnownMarkersList);
 
1187
                }
 
1188
 
 
1189
        if (res != 0)
 
1190
                {
 
1191
                FormatRawExifType exif_type;
 
1192
                FormatRawExifParseFunc exif_parse_func;
 
1193
                guint32 offset = 0;
 
1194
 
 
1195
                exif_type = format_raw_exif_offset(f, size, &offset, &exif_parse_func);
 
1196
                switch (exif_type)
 
1197
                        {
 
1198
                        case FORMAT_RAW_EXIF_NONE:
 
1199
                        default:
 
1200
                                break;
 
1201
                        case FORMAT_RAW_EXIF_TIFF:
 
1202
                                res = exif_tiff_parse(exif, (unsigned char*)f + offset, size - offset,
 
1203
                                                      ExifKnownMarkersList);
 
1204
                                break;
 
1205
                        case FORMAT_RAW_EXIF_JPEG:
 
1206
                                res = exif_jpeg_parse(exif, (unsigned char*)f + offset, size - offset,
 
1207
                                                      ExifKnownMarkersList);
 
1208
                                break;
 
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);
 
1215
                                break;
 
1216
                        case FORMAT_RAW_EXIF_PROPRIETARY:
 
1217
                                if (exif_parse_func)
 
1218
                                        {
 
1219
                                        res = exif_parse_func((unsigned char*)f + offset, size - offset, exif);
 
1220
                                        }
 
1221
                                break;
 
1222
                        }
 
1223
                }
 
1224
 
 
1225
        if (res != 0)
 
1226
                {
 
1227
                exif_free(exif);
 
1228
                exif = NULL;
 
1229
                }
 
1230
 
 
1231
        unmap_file(f, size);
 
1232
 
 
1233
        if (exif) exif->items = g_list_reverse(exif->items);
 
1234
 
 
1235
#if 0
 
1236
        exif_write_data_list(exif, stdout, TRUE);
 
1237
        exif_write_data_list(exif, stdout, FALSE);
 
1238
#endif
 
1239
 
 
1240
        return exif;
 
1241
}
 
1242
 
 
1243
ExifItem *exif_get_item(ExifData *exif, const gchar *key)
 
1244
{
 
1245
        GList *work;
 
1246
 
 
1247
        if (!key) return NULL;
 
1248
 
 
1249
        work = exif->items;
 
1250
        while (work)
 
1251
                {
 
1252
                ExifItem *item;
 
1253
 
 
1254
                item = work->data;
 
1255
                work = work->next;
 
1256
                if (item->marker->key && strcmp(key, item->marker->key) == 0) return item;
 
1257
                }
 
1258
        return NULL;
 
1259
}
 
1260
 
 
1261
#define EXIF_DATA_AS_TEXT_MAX_COUNT 16
 
1262
 
 
1263
gchar *exif_item_get_string(ExifItem *item, int idx)
 
1264
{
 
1265
        return exif_item_get_data_as_text(item);
 
1266
}
 
1267
 
 
1268
 
 
1269
gchar *exif_item_get_data_as_text(ExifItem *item)
 
1270
{
 
1271
        const ExifMarker *marker;
 
1272
        gpointer data;
 
1273
        GString *string;
 
1274
        gchar *text;
 
1275
        gint ne;
 
1276
        gint i;
 
1277
 
 
1278
        if (!item) return NULL;
 
1279
 
 
1280
        marker = item->marker;
 
1281
        if (!marker) return NULL;
 
1282
 
 
1283
        data = item->data;
 
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)
 
1288
                {
 
1289
                case EXIF_FORMAT_UNKNOWN:
 
1290
                        break;
 
1291
                case EXIF_FORMAT_BYTE_UNSIGNED:
 
1292
                case EXIF_FORMAT_BYTE:
 
1293
                case EXIF_FORMAT_UNDEFINED:
 
1294
                        if (ne == 1 && marker->list)
 
1295
                                {
 
1296
                                gchar *result;
 
1297
                                unsigned char val;
 
1298
 
 
1299
                                if (item->format == EXIF_FORMAT_BYTE_UNSIGNED ||
 
1300
                                    item->format == EXIF_FORMAT_UNDEFINED)
 
1301
                                        {
 
1302
                                        val = ((unsigned char *)data)[0];
 
1303
                                        }
 
1304
                                else
 
1305
                                        {
 
1306
                                        val = (unsigned char)(((signed char *)data)[0]);
 
1307
                                        }
 
1308
 
 
1309
                                result = exif_text_list_find_value(marker->list, (guint)val);
 
1310
                                string = g_string_append(string, result);
 
1311
                                g_free(result);
 
1312
                                }
 
1313
                        else
 
1314
                                {
 
1315
                                string = string_append_raw_bytes(string, data, ne);
 
1316
                                }
 
1317
                        break;
 
1318
                case EXIF_FORMAT_STRING:
 
1319
                        string = g_string_append(string, (gchar *)(item->data));
 
1320
                        break;
 
1321
                case EXIF_FORMAT_SHORT_UNSIGNED:
 
1322
                        if (ne == 1 && marker->list)
 
1323
                                {
 
1324
                                gchar *result;
 
1325
 
 
1326
                                result = exif_text_list_find_value(marker->list, ((guint16 *)data)[0]);
 
1327
                                string = g_string_append(string, result);
 
1328
                                g_free(result);
 
1329
                                }
 
1330
                        else for (i = 0; i < ne; i++)
 
1331
                                {
 
1332
                                g_string_append_printf(string, "%s%hd", (i > 0) ? ", " : "",
 
1333
                                                        ((guint16 *)data)[i]);
 
1334
                                }
 
1335
                        break;
 
1336
                case EXIF_FORMAT_LONG_UNSIGNED:
 
1337
                        for (i = 0; i < ne; i++)
 
1338
                                {
 
1339
                                g_string_append_printf(string, "%s%ld", (i > 0) ? ", " : "",
 
1340
                                                        (unsigned long int)((guint32 *)data)[i]);
 
1341
                                }
 
1342
                        break;
 
1343
                case EXIF_FORMAT_RATIONAL_UNSIGNED:
 
1344
                        for (i = 0; i < ne; i++)
 
1345
                                {
 
1346
                                ExifRational *r;
 
1347
 
 
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);
 
1351
                                }
 
1352
                        break;
 
1353
                case EXIF_FORMAT_SHORT:
 
1354
                        for (i = 0; i < ne; i++)
 
1355
                                {
 
1356
                                g_string_append_printf(string, "%s%hd", (i > 0) ? ", " : "",
 
1357
                                                        ((gint16 *)data)[i]);
 
1358
                                }
 
1359
                        break;
 
1360
                case EXIF_FORMAT_LONG:
 
1361
                        for (i = 0; i < ne; i++)
 
1362
                                {
 
1363
                                g_string_append_printf(string, "%s%ld", (i > 0) ? ", " : "",
 
1364
                                                        (long int)((gint32 *)data)[i]);
 
1365
                                }
 
1366
                        break;
 
1367
                case EXIF_FORMAT_RATIONAL:
 
1368
                        for (i = 0; i < ne; i++)
 
1369
                                {
 
1370
                                ExifRational *r;
 
1371
 
 
1372
                                r = &((ExifRational *)data)[i];
 
1373
                                g_string_append_printf(string, "%s%ld/%ld", (i > 0) ? ", " : "",
 
1374
                                                        (long)r->num, (long)r->den);
 
1375
                                }
 
1376
                        break;
 
1377
                case EXIF_FORMAT_FLOAT:
 
1378
                        for (i = 0; i < ne; i++)
 
1379
                                {
 
1380
                                g_string_append_printf(string, "%s%f", (i > 0) ? ", " : "",
 
1381
                                                        ((float *)data)[i]);
 
1382
                                }
 
1383
                        break;
 
1384
                case EXIF_FORMAT_DOUBLE:
 
1385
                        for (i = 0; i < ne; i++)
 
1386
                                {
 
1387
                                g_string_append_printf(string, "%s%f", (i > 0) ? ", " : "",
 
1388
                                                        ((double *)data)[i]);
 
1389
                                }
 
1390
                        break;
 
1391
                }
 
1392
 
 
1393
        if (item->elements > EXIF_DATA_AS_TEXT_MAX_COUNT &&
 
1394
            item->format != EXIF_FORMAT_STRING)
 
1395
                {
 
1396
                g_string_append(string, " ...");
 
1397
                }
 
1398
 
 
1399
        text = string->str;
 
1400
        g_string_free(string, FALSE);
 
1401
 
 
1402
        return text;
 
1403
}
 
1404
 
 
1405
gint exif_item_get_integer(ExifItem *item, gint *value)
 
1406
{
 
1407
        if (!item) return FALSE;
 
1408
 
 
1409
        switch (item->format)
 
1410
                {
 
1411
                case EXIF_FORMAT_SHORT:
 
1412
                        *value = (gint)(((gint16 *)(item->data))[0]);
 
1413
                        return TRUE;
 
1414
                        break;
 
1415
                case EXIF_FORMAT_SHORT_UNSIGNED:
 
1416
                        *value = (gint)(((guint16 *)(item->data))[0]);
 
1417
                        return TRUE;
 
1418
                        break;
 
1419
                case EXIF_FORMAT_LONG:
 
1420
                        *value = (gint)(((gint32 *)(item->data))[0]);
 
1421
                        return TRUE;
 
1422
                        break;
 
1423
                case EXIF_FORMAT_LONG_UNSIGNED:
 
1424
                        /* FIXME: overflow possible */
 
1425
                        *value = (gint)(((guint32 *)(item->data))[0]);
 
1426
                        return TRUE;
 
1427
                default:
 
1428
                        /* all other type return FALSE */
 
1429
                        break;
 
1430
                }
 
1431
        return FALSE;
 
1432
}
 
1433
 
 
1434
 
 
1435
ExifRational *exif_item_get_rational(ExifItem *item, gint *sign)
 
1436
{
 
1437
        if (!item) return NULL;
 
1438
 
 
1439
        if (item->format == EXIF_FORMAT_RATIONAL ||
 
1440
            item->format == EXIF_FORMAT_RATIONAL_UNSIGNED)
 
1441
                {
 
1442
                if (sign) *sign = (item->format == EXIF_FORMAT_RATIONAL);
 
1443
                return &((ExifRational *)(item->data))[0];
 
1444
                }
 
1445
 
 
1446
        return NULL;
 
1447
}
 
1448
 
 
1449
const gchar *exif_get_tag_description_by_key(const gchar *key)
 
1450
{
 
1451
        gint i;
 
1452
 
 
1453
        if (!key) return NULL;
 
1454
 
 
1455
        i = 0;
 
1456
        while (ExifKnownMarkersList[i].tag > 0)
 
1457
                {
 
1458
                if (strcmp(key, ExifKnownMarkersList[i].key) == 0) return _(ExifKnownMarkersList[i].description);
 
1459
                i++;
 
1460
                }
 
1461
 
 
1462
        return NULL;
 
1463
}
 
1464
 
 
1465
static void exif_write_item(FILE *f, ExifItem *item)
 
1466
{
 
1467
        gchar *text;
 
1468
 
 
1469
        text = exif_item_get_data_as_text(item);
 
1470
        if (text)
 
1471
                {
 
1472
                gchar *tag = exif_item_get_tag_name(item);
 
1473
                fprintf(f, "%4x %9s %30s %s\n", item->tag, ExifFormatList[item->format].short_name,
 
1474
                        tag, text);
 
1475
                g_free(tag);
 
1476
                }
 
1477
        g_free(text);
 
1478
}
 
1479
 
 
1480
void exif_write_data_list(ExifData *exif, FILE *f, gint human_readable_list)
 
1481
{
 
1482
        if (!f || !exif) return;
 
1483
 
 
1484
        fprintf(f, " tag   format                             key value\n");
 
1485
        fprintf(f, "----------------------------------------------------\n");
 
1486
 
 
1487
        if (human_readable_list)
 
1488
                {
 
1489
                gint i;
 
1490
 
 
1491
                i = 0;
 
1492
                while (ExifFormattedList[i].key)
 
1493
                        {
 
1494
                        gchar *text;
 
1495
 
 
1496
                        text = exif_get_formatted_by_key(exif, ExifFormattedList[i].key, NULL);
 
1497
                        if (text)
 
1498
                                {
 
1499
                                fprintf(f, "     %9s %30s %s\n", "string", ExifFormattedList[i].key, text);
 
1500
                                }
 
1501
                        i++;
 
1502
                        }
 
1503
                }
 
1504
        else
 
1505
                {
 
1506
                GList *work;
 
1507
 
 
1508
                work = exif->items;
 
1509
                while (work)
 
1510
                        {
 
1511
                        ExifItem *item;
 
1512
 
 
1513
                        item = work->data;
 
1514
                        work = work->next;
 
1515
 
 
1516
                        exif_write_item(f, item);
 
1517
                        }
 
1518
                }
 
1519
        fprintf(f, "----------------------------------------------------\n");
 
1520
}
 
1521
 
 
1522
int exif_write(ExifData *exif)
 
1523
{
 
1524
        printf("Not compiled with EXIF write support");
 
1525
        return 0;
 
1526
}
 
1527
 
 
1528
ExifItem *exif_add_item(ExifData *exif, const gchar *key)
 
1529
{
 
1530
        return NULL;
 
1531
}
 
1532
 
 
1533
int exif_item_delete(ExifData *exif, ExifItem *item)
 
1534
{
 
1535
        return 0;
 
1536
}
 
1537
 
 
1538
int exif_item_set_string(ExifItem *item, const char *str)
 
1539
{
 
1540
        return 0;
 
1541
}
 
1542
 
 
1543
 
 
1544
 
 
1545
#endif
 
1546
/* not HAVE_EXIV2 */