1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18 #include "config.h"
19
20 #include <gexiv2/gexiv2.h>
21 #include <glib.h>
22 #include <gtk/gtk.h>
23
24 #include <libgimp/gimp.h>
25 #include "libgimp/stdplugins-intl.h"
26
27 #include "metadata-tags.h"
28
29
30 /* The meaning of "single" and "multi" here denotes whether it is used in a
31 * single line or a multi line edit field.
32 * Depending on it's xmp type multi line can be saved as either:
33 * - one tag of type text, possibly including newlines
34 * - an array of tags of the same type for seq and bag, where each line in
35 * the multi line edit will be one item in the array
36 */
37 const metadata_tag default_metadata_tags[] =
38 {
39 /* Description */
40 { "Xmp.dc.title", "single", 16, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 0
41 { "Xmp.dc.creator", "single", 13, TAG_TYPE_XMP, GIMP_XMP_SEQ }, // 1
42 { "Xmp.dc.description", "multi", 14, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 2
43 { "Xmp.dc.subject", "multi", 15, TAG_TYPE_XMP, GIMP_XMP_BAG }, // 3
44 { "Xmp.dc.rights", "single", 17, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 4
45 { "Xmp.photoshop.AuthorsPosition", "single", 19, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 5
46 { "Xmp.photoshop.CaptionWriter", "single", 21, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 6
47 { "Xmp.xmp.Rating", "combo", -1, TAG_TYPE_XMP, GIMP_XMP_NONE }, // 7
48 { "Xmp.xmpRights.Marked", "combo", -1, TAG_TYPE_XMP, GIMP_XMP_NONE }, // 8
49 { "Xmp.xmpRights.WebStatement", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 9
50
51 /* IPTC */
52 { "Xmp.photoshop.DateCreated", "single", 0, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 10
53 { "Xmp.photoshop.Headline", "multi", 3, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 11
54 { "Xmp.photoshop.TransmissionReference", "single", 1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 12
55 { "Xmp.photoshop.Instructions", "multi", 2, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 13
56 { "Xmp.iptc.IntellectualGenre", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 14
57 { "Xmp.iptc.Scene", "multi", -1, TAG_TYPE_XMP, GIMP_XMP_BAG }, // 15
58 { "Xmp.iptc.Location", "single", 18, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 16
59 { "Xmp.iptc.CountryCode", "single", 20, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 17
60 { "Xmp.iptc.SubjectCode", "multi", -1, TAG_TYPE_XMP, GIMP_XMP_BAG }, // 18
61 { "Xmp.xmpRights.UsageTerms", "multi", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 19
62 { "Xmp.photoshop.City", "single", 5, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 20
63 { "Xmp.photoshop.State", "single", 6, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 21
64 { "Xmp.photoshop.Country", "single", 7, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 22
65 /* Xmp.photoshop.CaptionWriter here is a duplicate of #6 above. We keep it here to not have
66 * to renumber the tag references. It seems it is not used on the IPTC tab. */
67 { "Xmp.photoshop.CaptionWriter", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 23
68 { "Xmp.photoshop.Credit", "single", 8, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 24
69 { "Xmp.photoshop.Source", "single", 9, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 25
70 { "Xmp.photoshop.Urgency", "combo", 11, TAG_TYPE_XMP, GIMP_XMP_NONE }, // 26
71
72 /* IPTC Extension */
73 { "Xmp.iptcExt.PersonInImage", "multi", -1, TAG_TYPE_XMP, GIMP_XMP_BAG }, // 27
74 { "Xmp.iptcExt.Sublocation", "single", 12, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 28
75 { "Xmp.iptcExt.City", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 29
76 { "Xmp.iptcExt.ProvinceState", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 30
77 { "Xmp.iptcExt.CountryName", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 31
78 { "Xmp.iptcExt.CountryCode", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 32
79 { "Xmp.iptcExt.WorldRegion", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 33
80 { "Xmp.iptcExt.LocationShown", "list", -1, TAG_TYPE_XMP, GIMP_XMP_NONE }, // 34
81 { "Xmp.iptcExt.OrganisationInImageName", "list", -1, TAG_TYPE_XMP, GIMP_XMP_NONE }, // 35
82 { "Xmp.iptcExt.OrganisationInImageCode", "list", -1, TAG_TYPE_XMP, GIMP_XMP_NONE }, // 36
83 { "Xmp.iptcExt.Event", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 37
84 { "Xmp.iptcExt.RegistryId", "list", -1, TAG_TYPE_XMP, GIMP_XMP_NONE }, // 38
85 { "Xmp.iptcExt.ArtworkOrObject", "list", -1, TAG_TYPE_XMP, GIMP_XMP_NONE }, // 39
86 { "Xmp.iptcExt.AddlModelInfo", "multi", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 40
87 { "Xmp.iptcExt.ModelAge", "single", -1, TAG_TYPE_XMP, GIMP_XMP_BAG }, // 41
88 { "Xmp.iptcExt.MaxAvailWidth", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 42
89 { "Xmp.iptcExt.MaxAvailHeight", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 43
90 { "Xmp.iptcExt.DigitalSourceType", "combo", -1, TAG_TYPE_XMP, GIMP_XMP_NONE }, // 44
91 { "Xmp.plus.MinorModelAgeDisclosure", "combo", -1, TAG_TYPE_XMP, GIMP_XMP_NONE }, // 45
92 { "Xmp.plus.ModelReleaseStatus", "combo", -1, TAG_TYPE_XMP, GIMP_XMP_NONE }, // 46
93 { "Xmp.plus.ModelReleaseID", "list", -1, TAG_TYPE_XMP, GIMP_XMP_NONE }, // 47
94 { "Xmp.plus.ImageSupplierName", "multi", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 48
95 { "Xmp.plus.ImageSupplierID", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 49
96 { "Xmp.plus.ImageSupplierImageID", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 50
97 { "Xmp.plus.ImageCreator", "list", -1, TAG_TYPE_XMP, GIMP_XMP_NONE }, // 51
98 { "Xmp.plus.CopyrightOwner", "list", -1, TAG_TYPE_XMP, GIMP_XMP_NONE }, // 52
99 { "Xmp.plus.Licensor", "list", -1, TAG_TYPE_XMP, GIMP_XMP_NONE }, // 53
100 { "Xmp.plus.PropertyReleaseStatus", "combo", -1, TAG_TYPE_XMP, GIMP_XMP_NONE }, // 54
101 { "Xmp.plus.PropertyReleaseID", "list", -1, TAG_TYPE_XMP, GIMP_XMP_NONE }, // 55
102
103 /* Categories */
104 { "Xmp.photoshop.Category", "single", 4, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 56
105 { "Xmp.photoshop.SupplementalCategories", "multi", 10, TAG_TYPE_XMP, GIMP_XMP_BAG }, // 57
106
107 /* GPS */
108 { "Exif.GPSInfo.GPSLongitude", "single", -1, TAG_TYPE_EXIF, GIMP_XMP_NONE }, // 58
109 { "Exif.GPSInfo.GPSLongitudeRef", "combo", -1, TAG_TYPE_EXIF, GIMP_XMP_NONE }, // 59
110 { "Exif.GPSInfo.GPSLatitude", "single", -1, TAG_TYPE_EXIF, GIMP_XMP_NONE }, // 60
111 { "Exif.GPSInfo.GPSLatitudeRef", "combo", -1, TAG_TYPE_EXIF, GIMP_XMP_NONE }, // 61
112 { "Exif.GPSInfo.GPSAltitude", "single", -1, TAG_TYPE_EXIF, GIMP_XMP_NONE }, // 62
113 { "Exif.GPSInfo.GPSAltitudeRef", "combo", -1, TAG_TYPE_EXIF, GIMP_XMP_NONE }, // 63
114
115 /* DICOM */
116 { "Xmp.DICOM.PatientName", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 64
117 { "Xmp.DICOM.PatientID", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 65
118 { "Xmp.DICOM.PatientDOB", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 66
119 { "Xmp.DICOM.PatientSex", "combo", -1, TAG_TYPE_XMP, GIMP_XMP_NONE }, // 67
120 { "Xmp.DICOM.StudyID", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 68
121 { "Xmp.DICOM.StudyPhysician", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 69
122 { "Xmp.DICOM.StudyDateTime", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 70
123 { "Xmp.DICOM.StudyDescription", "multi", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 71
124 { "Xmp.DICOM.SeriesNumber", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 72
125 { "Xmp.DICOM.SeriesModality", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 73
126 { "Xmp.DICOM.SeriesDateTime", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 74
127 { "Xmp.DICOM.SeriesDescription", "multi", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 75
128 { "Xmp.DICOM.EquipmentInstitution", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 76
129 { "Xmp.DICOM.EquipmentManufacturer", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 77
130
131 /* IPTC */
132 { "Xmp.iptc.CiAdrExtadr", "multi", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 78
133 { "Xmp.iptc.CiAdrCity", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 79
134 { "Xmp.iptc.CiAdrRegion", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 80
135 { "Xmp.iptc.CiAdrPcode", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 81
136 { "Xmp.iptc.CiAdrCtry", "single", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 82
137 { "Xmp.iptc.CiTelWork", "multi", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 83
138 { "Xmp.iptc.CiEmailWork", "multi", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT }, // 84
139 { "Xmp.iptc.CiUrlWork", "multi", -1, TAG_TYPE_XMP, GIMP_XMP_TEXT } // 85
140
141 };
142 const gint n_default_metadata_tags = G_N_ELEMENTS (default_metadata_tags);
143
144 /* Then meaning of "single" and "multi" below is a little different than above.
145 * "single" - for iptc tags that can appear only once,
146 * "multi" - for iptc tags that are repeatable, i.e. can appear multiple times.
147 */
148 const metadata_tag equivalent_metadata_tags[] =
149 {
150 { "Iptc.Application2.DateCreated", "single", 10, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 0
151 { "Iptc.Application2.TransmissionReference", "single", 12, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 1
152 { "Iptc.Application2.SpecialInstructions", "single", 13, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 2
153 { "Iptc.Application2.Headline", "single", 11, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 3
154 { "Iptc.Application2.Category", "single", 56, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 4
155 { "Iptc.Application2.City", "single", 20, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 5
156 { "Iptc.Application2.ProvinceState", "single", 21, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 6
157 { "Iptc.Application2.CountryName", "single", 22, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 7
158 { "Iptc.Application2.Credit", "single", 24, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 8
159 { "Iptc.Application2.Source", "single", 25, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 9
160 { "Iptc.Application2.SuppCategory", "multi", 57, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 10
161 { "Iptc.Application2.Urgency", "combo", 26, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 11
162 { "Iptc.Application2.SubLocation", "single", 28, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 12
163 { "Iptc.Application2.Byline", "single", 1, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 13
164 { "Iptc.Application2.Caption", "single", 2, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 14
165 { "Iptc.Application2.Keywords", "multi", 3, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 15
166 { "Iptc.Application2.ObjectName", "single", 0, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 16
167 { "Iptc.Application2.Copyright", "single", 4, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 17
168 { "Iptc.Application2.LocationName", "multi", 16, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 18
169 { "Iptc.Application2.BylineTitle", "multi", 5, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 19
170 { "Iptc.Application2.CountryCode", "single", 17, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 20
171 { "Iptc.Application2.Writer", "multi", 6, TAG_TYPE_IPTC, GIMP_XMP_NONE }, // 21
172 };
173 const gint n_equivalent_metadata_tags = G_N_ELEMENTS (equivalent_metadata_tags);
174
175 /* Digital Source Type Combobox Items
176 * http://cv.iptc.org/newscodes/digitalsourcetype/
177 */
178 const combobox_str_tag digitalsourcetype[] =
179 {
180 { "", N_("Select a value") },
181 { "http://cv.iptc.org/newscodes/digitalsourcetype/digitalCapture", N_("Original digital capture of a real life scene") },
182 { "http://cv.iptc.org/newscodes/digitalsourcetype/negativeFilm", N_("Digitized from a negative on film") },
183 { "http://cv.iptc.org/newscodes/digitalsourcetype/positiveFilm", N_("Digitized from a positive on film") },
184 { "http://cv.iptc.org/newscodes/digitalsourcetype/print", N_("Digitized from a print on non-transparent medium") },
185 { "http://cv.iptc.org/newscodes/digitalsourcetype/softwareImage", N_("Created by software") }
186 };
187 const gint n_digitalsourcetype = G_N_ELEMENTS (digitalsourcetype);
188
189 /* Model Release Status Combobox Items
190 * http://ns.useplus.org/LDF/ldf-XMPSpecification#ModelReleaseStatus
191 */
192 const combobox_str_tag modelreleasestatus[] =
193 {
194 { "", N_("Select a value") },
195 { "http://ns.useplus.org/ldf/vocab/MR-NON", N_("None") },
196 { "http://ns.useplus.org/ldf/vocab/MR-NAP", N_("Not Applicable") },
197 { "http://ns.useplus.org/ldf/vocab/MR-UMR", N_("Unlimited Model Releases") },
198 { "http://ns.useplus.org/ldf/vocab/MR-LMR", N_("Limited or Incomplete Model Releases") }
199 };
200 const gint n_modelreleasestatus = G_N_ELEMENTS (modelreleasestatus);
201
202 /* Property Release Status Combobox Items
203 * http://ns.useplus.org/LDF/ldf-XMPSpecification#PropertyReleaseStatus
204 */
205 const combobox_str_tag propertyreleasestatus[] =
206 {
207 { "http://ns.useplus.org/ldf/vocab/PR-NON", N_("None") },
208 { "http://ns.useplus.org/ldf/vocab/PR-NAP", N_("Not Applicable") },
209 { "http://ns.useplus.org/ldf/vocab/PR-UPR", N_("Unlimited Property Releases") },
210 { "http://ns.useplus.org/ldf/vocab/PR-LPR", N_("Limited or Incomplete Property Releases") }
211 };
212 const gint n_propertyreleasestatus = G_N_ELEMENTS (propertyreleasestatus);
213
214 /* Minor Model Age Disclosure Combobox Items
215 * http://ns.useplus.org/LDF/ldf-XMPSpecification#MinorModelAgeDisclosure
216 */
217 const combobox_str_tag minormodelagedisclosure[] =
218 {
219 { "http://ns.useplus.org/ldf/vocab/AG-UNK", N_("Age Unknown") },
220 { "http://ns.useplus.org/ldf/vocab/AG-A25", N_("Age 25 or Over") },
221 { "http://ns.useplus.org/ldf/vocab/AG-A24", N_("Age 24") },
222 { "http://ns.useplus.org/ldf/vocab/AG-A23", N_("Age 23") },
223 { "http://ns.useplus.org/ldf/vocab/AG-A22", N_("Age 22") },
224 { "http://ns.useplus.org/ldf/vocab/AG-A21", N_("Age 21") },
225 { "http://ns.useplus.org/ldf/vocab/AG-A20", N_("Age 20") },
226 { "http://ns.useplus.org/ldf/vocab/AG-A19", N_("Age 19") },
227 { "http://ns.useplus.org/ldf/vocab/AG-A18", N_("Age 18") },
228 { "http://ns.useplus.org/ldf/vocab/AG-A17", N_("Age 17") },
229 { "http://ns.useplus.org/ldf/vocab/AG-A16", N_("Age 16") },
230 { "http://ns.useplus.org/ldf/vocab/AG-A15", N_("Age 15") },
231 { "http://ns.useplus.org/ldf/vocab/AG-U14", N_("Age 14 or Under") }
232 };
233 const gint n_minormodelagedisclosure = G_N_ELEMENTS (minormodelagedisclosure);
234
235 /* Urgency */
236 const gchar *urgency[] =
237 {
238 N_("None"), N_("High"), N_("2"), N_("3"), N_("4"), N_("Normal"), N_("6"), N_("7"), N_("Low")
239 };
240 const gint n_urgency = G_N_ELEMENTS (urgency);
241
242 /* Marked */
243 const combobox_int_tag marked[] =
244 {
245 { -1, N_("Unknown") }, // DO NOT SAVE
246 { TRUE, N_("Copyrighted") }, // TRUE
247 { FALSE, N_("Public Domain") }, // FALSE
248 };
249 const gint n_marked = G_N_ELEMENTS (marked);
250
251 /* Phone Types */
252 const combobox_str_tag phone_types[] =
253 {
254 { "", N_("Select a value") },
255 { "http://ns.useplus.org/ldf/vocab/work", N_("Work") },
256 { "http://ns.useplus.org/ldf/vocab/cell", N_("Cell") },
257 { "http://ns.useplus.org/ldf/vocab/fax", N_("Fax") },
258 { "http://ns.useplus.org/ldf/vocab/home", N_("Home") },
259 { "http://ns.useplus.org/ldf/vocab/pager", N_("Pager") }
260 };
261 const gint n_phone_types = G_N_ELEMENTS (phone_types);
262
263 /* DICOM Patient Sex
264 * http://dicomlookup.com/lookup.asp?sw=Ttable&q=C.7-1
265 * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/XMP.html#DICOM
266 * https://dicomiseasy.blogspot.ca/2011/11/introduction-to-dicom-chapter-iii-dicom.html
267 * http://dicom.nema.org/standard.html
268 */
269 const combobox_str_tag dicom[] =
270 {
271 { "", N_("Select a value") },
272 { "male", N_("Male") },
273 { "female", N_("Female") },
274 { "other", N_("Other") },
275 };
276 const gint n_dicom = G_N_ELEMENTS (dicom);
277
278 /* GPS Altitude Ref */
279 const gchar *gpsaltref[] =
280 {
281 N_("Unknown"), N_("Above sea level"), N_("Below sea level")
282 };
283 const gint n_gpsaltref = G_N_ELEMENTS (gpsaltref);
284
285 /* GPS Latitude Ref */
286 const gchar *gpslatref[] =
287 {
288 N_("Unknown"), N_("North"), N_("South")
289 };
290 const gint n_gpslatref = G_N_ELEMENTS (gpslatref);
291
292 /* GPS Longitude Ref */
293 const gchar *gpslngref[] =
294 {
295 N_("Unknown"), N_("East"), N_("West")
296 };
297 const gint n_gpslngref = G_N_ELEMENTS (gpslngref);
298
299 /* GPS Measurement System */
300 const gchar *gpsaltsys[] =
301 {
302 "m", "ft"
303 };
304 const gint n_gpsaltsys = G_N_ELEMENTS (gpsaltsys);
305
306 const TranslateHeaderTag creatorContactInfoHeader =
307 {
308 "Xmp.iptc.CreatorContactInfo", "type=\"Struct\"", 8
309 };
310
311 const TranslateTag creatorContactInfoTags[] =
312 {
313 { "Xmp.iptc.CiAdrExtadr", "Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiAdrExtadr", "multi", -1, TAG_TYPE_XMP },
314 { "Xmp.iptc.CiAdrCity", "Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiAdrCity", "single", -1, TAG_TYPE_XMP },
315 { "Xmp.iptc.CiAdrRegion", "Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiAdrRegion", "single", -1, TAG_TYPE_XMP },
316 { "Xmp.iptc.CiAdrPcode", "Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiAdrPcode", "single", -1, TAG_TYPE_XMP },
317 { "Xmp.iptc.CiAdrCtry", "Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiAdrCtry", "single", -1, TAG_TYPE_XMP },
318 { "Xmp.iptc.CiTelWork", "Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiTelWork", "multi", -1, TAG_TYPE_XMP },
319 { "Xmp.iptc.CiEmailWork", "Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiEmailWork", "multi", -1, TAG_TYPE_XMP },
320 { "Xmp.iptc.CiUrlWork", "Xmp.iptc.CreatorContactInfo/Iptc4xmpCore:CiUrlWork", "multi", -1, TAG_TYPE_XMP }
321 };
322
323 const TranslateHeaderTag locationCreationInfoHeader =
324 {
325 "Xmp.iptcExt.LocationCreated", "type=\"Bag\"", 6
326 };
327
328 const TranslateTag locationCreationInfoTags[] =
329 {
330 { "Xmp.iptcExt.Sublocation", "Xmp.iptcExt.LocationCreated[1]/Iptc4xmpExt:Sublocation", "single", -1, TAG_TYPE_XMP },
331 { "Xmp.iptcExt.City", "Xmp.iptcExt.LocationCreated[1]/Iptc4xmpExt:City", "single", -1, TAG_TYPE_XMP },
332 { "Xmp.iptcExt.ProvinceState", "Xmp.iptcExt.LocationCreated[1]/Iptc4xmpExt:ProvinceState", "single", -1, TAG_TYPE_XMP },
333 { "Xmp.iptcExt.CountryName", "Xmp.iptcExt.LocationCreated[1]/Iptc4xmpExt:CountryName", "single", -1, TAG_TYPE_XMP },
334 { "Xmp.iptcExt.CountryCode", "Xmp.iptcExt.LocationCreated[1]/Iptc4xmpExt:CountryCode", "single", -1, TAG_TYPE_XMP },
335 { "Xmp.iptcExt.WorldRegion", "Xmp.iptcExt.LocationCreated[1]/Iptc4xmpExt:WorldRegion", "single", -1, TAG_TYPE_XMP }
336 };
337
338 const TranslateHeaderTag imageSupplierInfoHeader =
339 {
340 "Xmp.plus.ImageSupplier", "type=\"Seq\"", 2
341 };
342
343 const TranslateTag imageSupplierInfoTags[] =
344 {
345 { "Xmp.plus.ImageSupplierName", "Xmp.plus.ImageSupplier[1]/plus:ImageSupplierName", "multi", -1, TAG_TYPE_XMP },
346 { "Xmp.plus.ImageSupplierID", "Xmp.plus.ImageSupplier[1]/plus:ImageSupplierID", "single", -1, TAG_TYPE_XMP }
347 };
348
349 /* Plus and IPTC extension tags */
350
351 const gchar *licensor[] =
352 {
353 "/plus:LicensorName",
354 "/plus:LicensorID",
355 "/plus:LicensorTelephone1",
356 "/plus:LicensorTelephoneType1",
357 "/plus:LicensorTelephone2",
358 "/plus:LicensorTelephoneType2",
359 "/plus:LicensorEmail",
360 "/plus:LicensorURL"
361 };
362 const gint n_licensor = G_N_ELEMENTS (licensor);
363
364 const gint licensor_special_handling[] =
365 {
366 METADATA_NONE,
367 METADATA_NONE,
368 METADATA_NONE,
369 METADATA_PHONETYPE,
370 METADATA_NONE,
371 METADATA_PHONETYPE,
372 METADATA_NONE,
373 METADATA_NONE
374 };
375
376 #ifdef USE_TAGS
377 const gchar *imagesupplier[] =
378 {
379 "/plus:ImageSupplierName",
380 "/plus:ImageSupplierID"
381 };
382 const gint n_imagesupplier = G_N_ELEMENTS (imagesupplier);
383 #endif
384
385 const gchar *imagecreator[] =
386 {
387 "/plus:ImageCreatorName",
388 "/plus:ImageCreatorID"
389 };
390 const gint n_imagecreator = G_N_ELEMENTS (imagecreator);
391
392 const gchar *copyrightowner[] =
393 {
394 "/plus:CopyrightOwnerName",
395 "/plus:CopyrightOwnerID"
396 };
397 const gint n_copyrightowner = G_N_ELEMENTS (copyrightowner);
398
399 const gchar *registryid[] =
400 {
401 "/Iptc4xmpExt:RegOrgId",
402 "/Iptc4xmpExt:RegItemId"
403 };
404 const gint n_registryid = G_N_ELEMENTS (registryid);
405
406 const gchar *registryid_alternative[] =
407 {
408 "/iptcExt:RegOrgId",
409 "/iptcExt:RegItemId"
410 };
411
412 const gchar *artworkorobject[] =
413 {
414 "/Iptc4xmpExt:AOTitle",
415 "/Iptc4xmpExt:AODateCreated",
416 "/Iptc4xmpExt:AOCreator",
417 "/Iptc4xmpExt:AOSource",
418 "/Iptc4xmpExt:AOSourceInvNo",
419 "/Iptc4xmpExt:AOCopyrightNotice",
420 };
421 const gint n_artworkorobject = G_N_ELEMENTS (artworkorobject);
422
423 const gchar *artworkorobject_alternative[] =
424 {
425 "/iptcExt:AOTitle",
426 "/iptcExt:AODateCreated",
427 "/iptcExt:AOCreator",
428 "/iptcExt:AOSource",
429 "/iptcExt:AOSourceInvNo",
430 "/iptcExt:AOCopyrightNotice",
431 };
432
433 const gchar *locationshown[] =
434 {
435 "/Iptc4xmpExt:Sublocation",
436 "/Iptc4xmpExt:City",
437 "/Iptc4xmpExt:ProvinceState",
438 "/Iptc4xmpExt:CountryName",
439 "/Iptc4xmpExt:CountryCode",
440 "/Iptc4xmpExt:WorldRegion"
441 };
442 const gint n_locationshown = G_N_ELEMENTS (locationshown);
443
444 const gchar *locationshown_alternative[] =
445 {
446 "/iptcExt:Sublocation",
447 "/iptcExt:City",
448 "/iptcExt:ProvinceState",
449 "/iptcExt:CountryName",
450 "/iptcExt:CountryCode",
451 "/iptcExt:WorldRegion"
452 };
453
454
455 #ifdef USE_TAGS
456 const gchar *locationcreated[] =
457 {
458 "/Iptc4xmpExt:Sublocation",
459 "/Iptc4xmpExt:City",
460 "/Iptc4xmpExt:ProvinceState",
461 "/Iptc4xmpExt:CountryName",
462 "/Iptc4xmpExt:CountryCode",
463 "/Iptc4xmpExt:WorldRegion"
464 };
465 const gint n_locationcreated = G_N_ELEMENTS (locationcreated);
466 #endif
467
468
469 gchar *
metadata_format_gps_longitude_latitude(const gdouble value)470 metadata_format_gps_longitude_latitude (const gdouble value)
471 {
472 gint deg, min;
473 gdouble sec;
474 gdouble gps_value = value;
475
476 if (gps_value < 0.f)
477 gps_value *= -1.f;
478
479 deg = (gint) gps_value;
480 min = (gint) ((gps_value - (gdouble) deg) * 60.f);
481 sec = ((gps_value - (gdouble) deg - (gdouble) (min / 60.f)) * 60.f * 60.f);
482
483 return g_strdup_printf ("%ddeg %d' %.3f\"", deg, min, sec);
484 }
485
486 /*
487 * use_meter: True return meters, False return feet
488 * measurement_symbol: Should be "m", "ft", or empty string (not NULL)
489 */
490 gchar *
metadata_format_gps_altitude(const gdouble value,gboolean use_meter,gchar * measurement_symbol)491 metadata_format_gps_altitude (const gdouble value,
492 gboolean use_meter,
493 gchar *measurement_symbol)
494 {
495 gdouble gps_value = value;
496
497 if (gps_value < 0.f)
498 gps_value *= -1.f;
499
500 if (! use_meter)
501 {
502 gps_value *= 3.28;
503 }
504
505 return g_strdup_printf ("%.2f%s", gps_value, measurement_symbol);
506 }
507