4750a9b60d65adee64b9b28a749a826c5ab37ab5
[vuplus_xbmc] / xbmc / pictures / PictureInfoTag.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "PictureInfoTag.h"
22 #include "XBDateTime.h"
23 #include "Util.h"
24 #include "utils/Variant.h"
25 #include "utils/CharsetConverter.h"
26 #include "utils/StringUtils.h"
27
28 using namespace std;
29
30 void CPictureInfoTag::Reset()
31 {
32   memset(&m_exifInfo, 0, sizeof(m_exifInfo));
33   memset(&m_iptcInfo, 0, sizeof(m_iptcInfo));
34   m_isLoaded = false;
35   m_isInfoSetExternally = false;
36   m_dateTimeTaken.Reset();
37 }
38
39 const CPictureInfoTag& CPictureInfoTag::operator=(const CPictureInfoTag& right)
40 {
41   if (this == &right) return * this;
42   memcpy(&m_exifInfo, &right.m_exifInfo, sizeof(m_exifInfo));
43   memcpy(&m_iptcInfo, &right.m_iptcInfo, sizeof(m_iptcInfo));
44   m_isLoaded = right.m_isLoaded;
45   m_isInfoSetExternally = right.m_isInfoSetExternally;
46   m_dateTimeTaken = right.m_dateTimeTaken;
47   return *this;
48 }
49
50 bool CPictureInfoTag::Load(const CStdString &path)
51 {
52   m_isLoaded = false;
53
54   DllLibExif exifDll;
55   if (path.IsEmpty() || !exifDll.Load())
56     return false;
57
58   if (exifDll.process_jpeg(path.c_str(), &m_exifInfo, &m_iptcInfo))
59     m_isLoaded = true;
60
61   ConvertDateTime();
62
63   return m_isLoaded;
64 }
65
66 void CPictureInfoTag::Archive(CArchive& ar)
67 {
68   if (ar.IsStoring())
69   {
70     ar << m_isLoaded;
71     ar << m_isInfoSetExternally;
72     ar << m_exifInfo.ApertureFNumber;
73     ar << CStdString(m_exifInfo.CameraMake);
74     ar << CStdString(m_exifInfo.CameraModel);
75     ar << m_exifInfo.CCDWidth;
76     ar << GetInfo(SLIDE_EXIF_COMMENT); // Store and restore the comment charset converted
77     ar << CStdString(m_exifInfo.Description);
78     ar << CStdString(m_exifInfo.DateTime);
79     for (int i = 0; i < 10; i++)
80       ar << m_exifInfo.DateTimeOffsets[i];
81     ar << m_exifInfo.DigitalZoomRatio;
82     ar << m_exifInfo.Distance;
83     ar << m_exifInfo.ExposureBias;
84     ar << m_exifInfo.ExposureMode;
85     ar << m_exifInfo.ExposureProgram;
86     ar << m_exifInfo.ExposureTime;
87     ar << m_exifInfo.FlashUsed;
88     ar << m_exifInfo.FocalLength;
89     ar << m_exifInfo.FocalLength35mmEquiv;
90     ar << m_exifInfo.GpsInfoPresent;
91     ar << CStdString(m_exifInfo.GpsAlt);
92     ar << CStdString(m_exifInfo.GpsLat);
93     ar << CStdString(m_exifInfo.GpsLong);
94     ar << m_exifInfo.Height;
95     ar << m_exifInfo.IsColor;
96     ar << m_exifInfo.ISOequivalent;
97     ar << m_exifInfo.LargestExifOffset;
98     ar << m_exifInfo.LightSource;
99     ar << m_exifInfo.MeteringMode;
100     ar << m_exifInfo.numDateTimeTags;
101     ar << m_exifInfo.Orientation;
102     ar << m_exifInfo.Process;
103     ar << m_exifInfo.ThumbnailAtEnd;
104     ar << m_exifInfo.ThumbnailOffset;
105     ar << m_exifInfo.ThumbnailSize;
106     ar << m_exifInfo.ThumbnailSizeOffset;
107     ar << m_exifInfo.Whitebalance;
108     ar << m_exifInfo.Width;
109     ar << m_dateTimeTaken;
110
111     ar << CStdString(m_iptcInfo.Author);
112     ar << CStdString(m_iptcInfo.Byline);
113     ar << CStdString(m_iptcInfo.BylineTitle);
114     ar << CStdString(m_iptcInfo.Caption);
115     ar << CStdString(m_iptcInfo.Category);
116     ar << CStdString(m_iptcInfo.City);
117     ar << CStdString(m_iptcInfo.Urgency);
118     ar << CStdString(m_iptcInfo.CopyrightNotice);
119     ar << CStdString(m_iptcInfo.Country);
120     ar << CStdString(m_iptcInfo.CountryCode);
121     ar << CStdString(m_iptcInfo.Credit);
122     ar << CStdString(m_iptcInfo.Date);
123     ar << CStdString(m_iptcInfo.Headline);
124     ar << CStdString(m_iptcInfo.Keywords);
125     ar << CStdString(m_iptcInfo.ObjectName);
126     ar << CStdString(m_iptcInfo.ReferenceService);
127     ar << CStdString(m_iptcInfo.Source);
128     ar << CStdString(m_iptcInfo.SpecialInstructions);
129     ar << CStdString(m_iptcInfo.State);
130     ar << CStdString(m_iptcInfo.SupplementalCategories);
131     ar << CStdString(m_iptcInfo.TransmissionReference);
132     ar << CStdString(m_iptcInfo.TimeCreated);
133     ar << CStdString(m_iptcInfo.SubLocation);
134     ar << CStdString(m_iptcInfo.ImageType);
135   }
136   else
137   {
138     ar >> m_isLoaded;
139     ar >> m_isInfoSetExternally;
140     ar >> m_exifInfo.ApertureFNumber;
141     GetStringFromArchive(ar, m_exifInfo.CameraMake, sizeof(m_exifInfo.CameraMake));
142     GetStringFromArchive(ar, m_exifInfo.CameraModel, sizeof(m_exifInfo.CameraModel));
143     ar >> m_exifInfo.CCDWidth;
144     GetStringFromArchive(ar, m_exifInfo.Comments, sizeof(m_exifInfo.Comments));
145     m_exifInfo.CommentsCharset = EXIF_COMMENT_CHARSET_CONVERTED; // Store and restore the comment charset converted
146     GetStringFromArchive(ar, m_exifInfo.Description, sizeof(m_exifInfo.Description));
147     GetStringFromArchive(ar, m_exifInfo.DateTime, sizeof(m_exifInfo.DateTime));
148     for (int i = 0; i < 10; i++)
149       ar >> m_exifInfo.DateTimeOffsets[i];
150     ar >> m_exifInfo.DigitalZoomRatio;
151     ar >> m_exifInfo.Distance;
152     ar >> m_exifInfo.ExposureBias;
153     ar >> m_exifInfo.ExposureMode;
154     ar >> m_exifInfo.ExposureProgram;
155     ar >> m_exifInfo.ExposureTime;
156     ar >> m_exifInfo.FlashUsed;
157     ar >> m_exifInfo.FocalLength;
158     ar >> m_exifInfo.FocalLength35mmEquiv;
159     ar >> m_exifInfo.GpsInfoPresent;
160     GetStringFromArchive(ar, m_exifInfo.GpsAlt, sizeof(m_exifInfo.GpsAlt));
161     GetStringFromArchive(ar, m_exifInfo.GpsLat, sizeof(m_exifInfo.GpsLat));
162     GetStringFromArchive(ar, m_exifInfo.GpsLong, sizeof(m_exifInfo.GpsLong));
163     ar >> m_exifInfo.Height;
164     ar >> m_exifInfo.IsColor;
165     ar >> m_exifInfo.ISOequivalent;
166     ar >> m_exifInfo.LargestExifOffset;
167     ar >> m_exifInfo.LightSource;
168     ar >> m_exifInfo.MeteringMode;
169     ar >> m_exifInfo.numDateTimeTags;
170     ar >> m_exifInfo.Orientation;
171     ar >> m_exifInfo.Process;
172     ar >> m_exifInfo.ThumbnailAtEnd;
173     ar >> m_exifInfo.ThumbnailOffset;
174     ar >> m_exifInfo.ThumbnailSize;
175     ar >> m_exifInfo.ThumbnailSizeOffset;
176     ar >> m_exifInfo.Whitebalance;
177     ar >> m_exifInfo.Width;
178     ar >> m_dateTimeTaken;
179
180     GetStringFromArchive(ar, m_iptcInfo.Author, sizeof(m_iptcInfo.Author));
181     GetStringFromArchive(ar, m_iptcInfo.Byline, sizeof(m_iptcInfo.Byline));
182     GetStringFromArchive(ar, m_iptcInfo.BylineTitle, sizeof(m_iptcInfo.BylineTitle));
183     GetStringFromArchive(ar, m_iptcInfo.Caption, sizeof(m_iptcInfo.Caption));
184     GetStringFromArchive(ar, m_iptcInfo.Category, sizeof(m_iptcInfo.Category));
185     GetStringFromArchive(ar, m_iptcInfo.City, sizeof(m_iptcInfo.City));
186     GetStringFromArchive(ar, m_iptcInfo.Urgency, sizeof(m_iptcInfo.Urgency));
187     GetStringFromArchive(ar, m_iptcInfo.CopyrightNotice, sizeof(m_iptcInfo.CopyrightNotice));
188     GetStringFromArchive(ar, m_iptcInfo.Country, sizeof(m_iptcInfo.Country));
189     GetStringFromArchive(ar, m_iptcInfo.CountryCode, sizeof(m_iptcInfo.CountryCode));
190     GetStringFromArchive(ar, m_iptcInfo.Credit, sizeof(m_iptcInfo.Credit));
191     GetStringFromArchive(ar, m_iptcInfo.Date, sizeof(m_iptcInfo.Date));
192     GetStringFromArchive(ar, m_iptcInfo.Headline, sizeof(m_iptcInfo.Headline));
193     GetStringFromArchive(ar, m_iptcInfo.Keywords, sizeof(m_iptcInfo.Keywords));
194     GetStringFromArchive(ar, m_iptcInfo.ObjectName, sizeof(m_iptcInfo.ObjectName));
195     GetStringFromArchive(ar, m_iptcInfo.ReferenceService, sizeof(m_iptcInfo.ReferenceService));
196     GetStringFromArchive(ar, m_iptcInfo.Source, sizeof(m_iptcInfo.Source));
197     GetStringFromArchive(ar, m_iptcInfo.SpecialInstructions, sizeof(m_iptcInfo.SpecialInstructions));
198     GetStringFromArchive(ar, m_iptcInfo.State, sizeof(m_iptcInfo.State));
199     GetStringFromArchive(ar, m_iptcInfo.SupplementalCategories, sizeof(m_iptcInfo.SupplementalCategories));
200     GetStringFromArchive(ar, m_iptcInfo.TransmissionReference, sizeof(m_iptcInfo.TransmissionReference));
201     GetStringFromArchive(ar, m_iptcInfo.TimeCreated, sizeof(m_iptcInfo.TimeCreated));
202     GetStringFromArchive(ar, m_iptcInfo.SubLocation, sizeof(m_iptcInfo.SubLocation));
203     GetStringFromArchive(ar, m_iptcInfo.ImageType, sizeof(m_iptcInfo.ImageType));
204   }
205 }
206
207 void CPictureInfoTag::Serialize(CVariant& value) const
208 {
209   value["aperturefnumber"] = m_exifInfo.ApertureFNumber;
210   value["cameramake"] = CStdString(m_exifInfo.CameraMake);
211   value["cameramodel"] = CStdString(m_exifInfo.CameraModel);
212   value["ccdwidth"] = m_exifInfo.CCDWidth;
213   value["comments"] = GetInfo(SLIDE_EXIF_COMMENT); // Charset conversion
214   value["description"] = CStdString(m_exifInfo.Description);
215   value["datetime"] = CStdString(m_exifInfo.DateTime);
216   for (int i = 0; i < 10; i++)
217     value["datetimeoffsets"][i] = m_exifInfo.DateTimeOffsets[i];
218   value["digitalzoomratio"] = m_exifInfo.DigitalZoomRatio;
219   value["distance"] = m_exifInfo.Distance;
220   value["exposurebias"] = m_exifInfo.ExposureBias;
221   value["exposuremode"] = m_exifInfo.ExposureMode;
222   value["exposureprogram"] = m_exifInfo.ExposureProgram;
223   value["exposuretime"] = m_exifInfo.ExposureTime;
224   value["flashused"] = m_exifInfo.FlashUsed;
225   value["focallength"] = m_exifInfo.FocalLength;
226   value["focallength35mmequiv"] = m_exifInfo.FocalLength35mmEquiv;
227   value["gpsinfopresent"] = m_exifInfo.GpsInfoPresent;
228   value["gpsinfo"]["alt"] = CStdString(m_exifInfo.GpsAlt);
229   value["gpsinfo"]["lat"] = CStdString(m_exifInfo.GpsLat);
230   value["gpsinfo"]["long"] = CStdString(m_exifInfo.GpsLong);
231   value["height"] = m_exifInfo.Height;
232   value["iscolor"] = m_exifInfo.IsColor;
233   value["isoequivalent"] = m_exifInfo.ISOequivalent;
234   value["largestexifoffset"] = m_exifInfo.LargestExifOffset;
235   value["lightsource"] = m_exifInfo.LightSource;
236   value["meteringmode"] = m_exifInfo.MeteringMode;
237   value["numdatetimetags"] = m_exifInfo.numDateTimeTags;
238   value["orientation"] = m_exifInfo.Orientation;
239   value["process"] = m_exifInfo.Process;
240   value["thumbnailatend"] = m_exifInfo.ThumbnailAtEnd;
241   value["thumbnailoffset"] = m_exifInfo.ThumbnailOffset;
242   value["thumbnailsize"] = m_exifInfo.ThumbnailSize;
243   value["thumbnailsizeoffset"] = m_exifInfo.ThumbnailSizeOffset;
244   value["whitebalance"] = m_exifInfo.Whitebalance;
245   value["width"] = m_exifInfo.Width;
246
247   value["author"] = CStdString(m_iptcInfo.Author);
248   value["byline"] = CStdString(m_iptcInfo.Byline);
249   value["bylinetitle"] = CStdString(m_iptcInfo.BylineTitle);
250   value["caption"] = CStdString(m_iptcInfo.Caption);
251   value["category"] = CStdString(m_iptcInfo.Category);
252   value["city"] = CStdString(m_iptcInfo.City);
253   value["urgency"] = CStdString(m_iptcInfo.Urgency);
254   value["copyrightnotice"] = CStdString(m_iptcInfo.CopyrightNotice);
255   value["country"] = CStdString(m_iptcInfo.Country);
256   value["countrycode"] = CStdString(m_iptcInfo.CountryCode);
257   value["credit"] = CStdString(m_iptcInfo.Credit);
258   value["date"] = CStdString(m_iptcInfo.Date);
259   value["headline"] = CStdString(m_iptcInfo.Headline);
260   value["keywords"] = CStdString(m_iptcInfo.Keywords);
261   value["objectname"] = CStdString(m_iptcInfo.ObjectName);
262   value["referenceservice"] = CStdString(m_iptcInfo.ReferenceService);
263   value["source"] = CStdString(m_iptcInfo.Source);
264   value["specialinstructions"] = CStdString(m_iptcInfo.SpecialInstructions);
265   value["state"] = CStdString(m_iptcInfo.State);
266   value["supplementalcategories"] = CStdString(m_iptcInfo.SupplementalCategories);
267   value["transmissionreference"] = CStdString(m_iptcInfo.TransmissionReference);
268   value["timecreated"] = CStdString(m_iptcInfo.TimeCreated);
269   value["sublocation"] = CStdString(m_iptcInfo.SubLocation);
270   value["imagetype"] = CStdString(m_iptcInfo.ImageType);
271 }
272
273 void CPictureInfoTag::ToSortable(SortItem& sortable, Field field) const
274 {
275   if (field == FieldDateTaken && m_dateTimeTaken.IsValid())
276     sortable[FieldDateTaken] = m_dateTimeTaken.GetAsDBDateTime();
277 }
278
279 void CPictureInfoTag::GetStringFromArchive(CArchive &ar, char *string, size_t length)
280 {
281   CStdString temp;
282   ar >> temp;
283   length = min((size_t)temp.GetLength(), length - 1);
284   if (!temp.IsEmpty())
285     memcpy(string, temp.c_str(), length);
286   string[length] = 0;
287 }
288
289 const CStdString CPictureInfoTag::GetInfo(int info) const
290 {
291   if (!m_isLoaded && !m_isInfoSetExternally) // If no metadata has been loaded from the picture file or set with SetInfo(), just return
292     return "";
293
294   CStdString value;
295   switch (info)
296   {
297   case SLIDE_RESOLUTION:
298     value = StringUtils::Format("%d x %d", m_exifInfo.Width, m_exifInfo.Height);
299     break;
300   case SLIDE_COLOUR:
301     value = m_exifInfo.IsColor ? "Colour" : "Black and White";
302     break;
303   case SLIDE_PROCESS:
304     switch (m_exifInfo.Process)
305     {
306       case M_SOF0:
307         // don't show it if its the plain old boring 'baseline' process, but do
308         // show it if its something else, like 'progressive' (used on web sometimes)
309         value = "Baseline";
310       break;
311       case M_SOF1:    value = "Extended sequential";      break;
312       case M_SOF2:    value = "Progressive";      break;
313       case M_SOF3:    value = "Lossless";      break;
314       case M_SOF5:    value = "Differential sequential";      break;
315       case M_SOF6:    value = "Differential progressive";      break;
316       case M_SOF7:    value = "Differential lossless";      break;
317       case M_SOF9:    value = "Extended sequential, arithmetic coding";      break;
318       case M_SOF10:   value = "Progressive, arithmetic coding";     break;
319       case M_SOF11:   value = "Lossless, arithmetic coding";     break;
320       case M_SOF13:   value = "Differential sequential, arithmetic coding";     break;
321       case M_SOF14:   value = "Differential progressive, arithmetic coding";     break;
322       case M_SOF15:   value = "Differential lossless, arithmetic coding";     break;
323       default:        value = "Unknown";   break;
324     }
325     break;
326   case SLIDE_COMMENT:
327   case SLIDE_EXIF_COMMENT:
328     // The charset used for the UserComment is stored in CommentsCharset:
329     // Ascii, Unicode (UCS2), JIS (X208-1990), Unknown (application specific)
330     if (m_exifInfo.CommentsCharset == EXIF_COMMENT_CHARSET_UNICODE)
331     {
332       g_charsetConverter.ucs2ToUTF8(std::u16string((char16_t*)m_exifInfo.Comments), value);
333     }
334     else
335     {
336       // Ascii doesn't need to be converted (EXIF_COMMENT_CHARSET_ASCII)
337       // Archived data is already converted (EXIF_COMMENT_CHARSET_CONVERTED)
338       // Unknown data can't be converted as it could be any codec (EXIF_COMMENT_CHARSET_UNKNOWN)
339       // JIS data can't be converted as CharsetConverter and iconv lacks support (EXIF_COMMENT_CHARSET_JIS)
340       value = m_exifInfo.Comments;
341     }
342     break;
343   case SLIDE_EXIF_LONG_DATE_TIME:
344     if (m_dateTimeTaken.IsValid())
345       value = m_dateTimeTaken.GetAsLocalizedDateTime(true);
346     break;
347   case SLIDE_EXIF_DATE_TIME:
348     if (m_dateTimeTaken.IsValid())
349       value = m_dateTimeTaken.GetAsLocalizedDateTime();
350     break;
351   case SLIDE_EXIF_LONG_DATE:
352     if (m_dateTimeTaken.IsValid())
353       value = m_dateTimeTaken.GetAsLocalizedDate(true);
354     break;
355   case SLIDE_EXIF_DATE:
356     if (m_dateTimeTaken.IsValid())
357       value = m_dateTimeTaken.GetAsLocalizedDate();
358     break;
359   case SLIDE_EXIF_DESCRIPTION:
360     value = m_exifInfo.Description;
361     break;
362   case SLIDE_EXIF_CAMERA_MAKE:
363     value = m_exifInfo.CameraMake;
364     break;
365   case SLIDE_EXIF_CAMERA_MODEL:
366     value = m_exifInfo.CameraModel;
367     break;
368 //  case SLIDE_EXIF_SOFTWARE:
369 //    value = m_exifInfo.Software;
370   case SLIDE_EXIF_APERTURE:
371     if (m_exifInfo.ApertureFNumber)
372       value = StringUtils::Format("%3.1f", m_exifInfo.ApertureFNumber);
373     break;
374   case SLIDE_EXIF_ORIENTATION:
375     switch (m_exifInfo.Orientation)
376     {
377       case 1:   value = "Top Left";     break;
378       case 2:   value = "Top Right";    break;
379       case 3:   value = "Bottom Right"; break;
380       case 4:   value = "Bottom Left";  break;
381       case 5:   value = "Left Top";     break;
382       case 6:   value = "Right Top";    break;
383       case 7:   value = "Right Bottom"; break;
384       case 8:   value = "Left Bottom";  break;
385     }
386     break;
387   case SLIDE_EXIF_FOCAL_LENGTH:
388     if (m_exifInfo.FocalLength)
389     {
390       value = StringUtils::Format("%4.2fmm", m_exifInfo.FocalLength);
391       if (m_exifInfo.FocalLength35mmEquiv != 0)
392         value.AppendFormat("  (35mm Equivalent = %umm)", m_exifInfo.FocalLength35mmEquiv);
393     }
394     break;
395   case SLIDE_EXIF_FOCUS_DIST:
396     if (m_exifInfo.Distance < 0)
397       value = "Infinite";
398     else if (m_exifInfo.Distance > 0)
399       value = StringUtils::Format("%4.2fm", m_exifInfo.Distance);
400     break;
401   case SLIDE_EXIF_EXPOSURE:
402     switch (m_exifInfo.ExposureProgram)
403     {
404       case 1:  value = "Manual";              break;
405       case 2:  value = "Program (Auto)";     break;
406       case 3:  value = "Aperture priority (Semi-Auto)";    break;
407       case 4:  value = "Shutter priority (semi-auto)";     break;
408       case 5:  value = "Creative Program (based towards depth of field)";    break;
409       case 6:  value = "Action program (based towards fast shutter speed)";      break;
410       case 7:  value = "Portrait Mode";    break;
411       case 8:  value = "Landscape Mode";   break;
412     }
413     break;
414   case SLIDE_EXIF_EXPOSURE_TIME:
415     if (m_exifInfo.ExposureTime)
416     {
417       if (m_exifInfo.ExposureTime < 0.010f)
418         value = StringUtils::Format("%6.4fs", m_exifInfo.ExposureTime);
419       else
420         value = StringUtils::Format("%5.3fs", m_exifInfo.ExposureTime);
421       if (m_exifInfo.ExposureTime <= 0.5)
422         value.AppendFormat(" (1/%d)", (int)(0.5 + 1/m_exifInfo.ExposureTime));
423     }
424     break;
425   case SLIDE_EXIF_EXPOSURE_BIAS:
426     if (m_exifInfo.ExposureBias != 0)
427       value = StringUtils::Format("%4.2f EV", m_exifInfo.ExposureBias);
428     break;
429   case SLIDE_EXIF_EXPOSURE_MODE:
430     switch (m_exifInfo.ExposureMode)
431     {
432       case 0:  value = "Automatic";          break;
433       case 1:  value = "Manual";             break;
434       case 2:  value = "Auto bracketing";    break;
435     }
436     break;
437   case SLIDE_EXIF_FLASH_USED:
438     if (m_exifInfo.FlashUsed >= 0)
439     {
440       if (m_exifInfo.FlashUsed & 1)
441       {
442         value = "Yes";
443         switch (m_exifInfo.FlashUsed)
444         {
445           case 0x5:  value = "Yes (Strobe light not detected)";                break;
446           case 0x7:  value = "Yes (Strobe light detected)";                  break;
447           case 0x9:  value = "Yes (Manual)";                  break;
448           case 0xd:  value = "Yes (Manual, return light not detected)";          break;
449           case 0xf:  value = "Yes (Manual, return light detected)";            break;
450           case 0x19: value = "Yes (Auto)";                    break;
451           case 0x1d: value = "Yes (Auto, return light not detected)";            break;
452           case 0x1f: value = "Yes (Auto, return light detected)";              break;
453           case 0x41: value = "Yes (Red eye reduction mode)";                  break;
454           case 0x45: value = "Yes (Red eye reduction mode return light not detected)";          break;
455           case 0x47: value = "Yes (Red eye reduction mode return light detected)";            break;
456           case 0x49: value = "Yes (Manual, red eye reduction mode)";            break;
457           case 0x4d: value = "Yes (Manual, red eye reduction mode, return light not detected)";    break;
458           case 0x4f: value = "Yes (Manual, red eye reduction mode, return light detected)";      break;
459           case 0x59: value = "Yes (Auto, red eye reduction mode)";              break;
460           case 0x5d: value = "Yes (Auto, red eye reduction mode, return light not detected)";      break;
461           case 0x5f: value = "Yes (Auto, red eye reduction mode, return light detected)";        break;
462         }
463       }
464       else
465         value = m_exifInfo.FlashUsed == 0x18 ? "No (Auto)" : "No";
466     }
467     break;
468   case SLIDE_EXIF_WHITE_BALANCE:
469     return m_exifInfo.Whitebalance ? "Manual" : "Auto";
470   case SLIDE_EXIF_LIGHT_SOURCE:
471     switch (m_exifInfo.LightSource)
472     {
473       case 1:   value = "Daylight";       break;
474       case 2:   value = "Fluorescent";    break;
475       case 3:   value = "Incandescent";   break;
476       case 4:   value = "Flash";          break;
477       case 9:   value = "Fine Weather";    break;
478       case 11:  value = "Shade";          break;
479       default:;   //Quercus: 17-1-2004 There are many more modes for this, check Exif2.2 specs
480                   // If it just says 'unknown' or we don't know it, then
481                   // don't bother showing it - it doesn't add any useful information.
482     }
483     break;
484   case SLIDE_EXIF_METERING_MODE:
485     switch (m_exifInfo.MeteringMode)
486     {
487       case 2:  value = "Center weight"; break;
488       case 3:  value = "Spot";   break;
489       case 5:  value = "Matrix"; break;
490     }
491     break;
492   case SLIDE_EXIF_ISO_EQUIV:
493     if (m_exifInfo.ISOequivalent)
494       value = StringUtils::Format("%2d", m_exifInfo.ISOequivalent);
495     break;
496   case SLIDE_EXIF_DIGITAL_ZOOM:
497     if (m_exifInfo.DigitalZoomRatio)
498       value = StringUtils::Format("%1.3fx", m_exifInfo.DigitalZoomRatio);
499     break;
500   case SLIDE_EXIF_CCD_WIDTH:
501     if (m_exifInfo.CCDWidth)
502       value = StringUtils::Format("%4.2fmm", m_exifInfo.CCDWidth);
503     break;
504   case SLIDE_EXIF_GPS_LATITUDE:
505     value = m_exifInfo.GpsLat;
506     break;
507   case SLIDE_EXIF_GPS_LONGITUDE:
508     value = m_exifInfo.GpsLong;
509     break;
510   case SLIDE_EXIF_GPS_ALTITUDE:
511     value = m_exifInfo.GpsAlt;
512     break;
513   case SLIDE_IPTC_SUP_CATEGORIES:   value = m_iptcInfo.SupplementalCategories;  break;
514   case SLIDE_IPTC_KEYWORDS:         value = m_iptcInfo.Keywords;                break;
515   case SLIDE_IPTC_CAPTION:          value = m_iptcInfo.Caption;                 break;
516   case SLIDE_IPTC_AUTHOR:           value = m_iptcInfo.Author;                  break;
517   case SLIDE_IPTC_HEADLINE:         value = m_iptcInfo.Headline;                break;
518   case SLIDE_IPTC_SPEC_INSTR:       value = m_iptcInfo.SpecialInstructions;     break;
519   case SLIDE_IPTC_CATEGORY:         value = m_iptcInfo.Category;                break;
520   case SLIDE_IPTC_BYLINE:           value = m_iptcInfo.Byline;                  break;
521   case SLIDE_IPTC_BYLINE_TITLE:     value = m_iptcInfo.BylineTitle;             break;
522   case SLIDE_IPTC_CREDIT:           value = m_iptcInfo.Credit;                  break;
523   case SLIDE_IPTC_SOURCE:           value = m_iptcInfo.Source;                  break;
524   case SLIDE_IPTC_COPYRIGHT_NOTICE: value = m_iptcInfo.CopyrightNotice;         break;
525   case SLIDE_IPTC_OBJECT_NAME:      value = m_iptcInfo.ObjectName;              break;
526   case SLIDE_IPTC_CITY:             value = m_iptcInfo.City;                    break;
527   case SLIDE_IPTC_STATE:            value = m_iptcInfo.State;                   break;
528   case SLIDE_IPTC_COUNTRY:          value = m_iptcInfo.Country;                 break;
529   case SLIDE_IPTC_TX_REFERENCE:     value = m_iptcInfo.TransmissionReference;   break;
530   case SLIDE_IPTC_DATE:             value = m_iptcInfo.Date;                    break;
531   case SLIDE_IPTC_URGENCY:          value = m_iptcInfo.Urgency;                 break;
532   case SLIDE_IPTC_COUNTRY_CODE:     value = m_iptcInfo.CountryCode;             break;
533   case SLIDE_IPTC_REF_SERVICE:      value = m_iptcInfo.ReferenceService;        break;
534   case SLIDE_IPTC_TIMECREATED:      value = m_iptcInfo.TimeCreated;             break;
535   case SLIDE_IPTC_SUBLOCATION:      value = m_iptcInfo.SubLocation;             break;
536   case SLIDE_IPTC_IMAGETYPE:        value = m_iptcInfo.ImageType;               break;
537   default:
538     break;
539   }
540   return value;
541 }
542
543 int CPictureInfoTag::TranslateString(const CStdString &info)
544 {
545   if (info.Equals("filename")) return SLIDE_FILE_NAME;
546   else if (info.Equals("path")) return SLIDE_FILE_PATH;
547   else if (info.Equals("filesize")) return SLIDE_FILE_SIZE;
548   else if (info.Equals("filedate")) return SLIDE_FILE_DATE;
549   else if (info.Equals("slideindex")) return SLIDE_INDEX;
550   else if (info.Equals("resolution")) return SLIDE_RESOLUTION;
551   else if (info.Equals("slidecomment")) return SLIDE_COMMENT;
552   else if (info.Equals("colour")) return SLIDE_COLOUR;
553   else if (info.Equals("process")) return SLIDE_PROCESS;
554   else if (info.Equals("exiftime")) return SLIDE_EXIF_DATE_TIME;
555   else if (info.Equals("exifdate")) return SLIDE_EXIF_DATE;
556   else if (info.Equals("longexiftime")) return SLIDE_EXIF_LONG_DATE_TIME;
557   else if (info.Equals("longexifdate")) return SLIDE_EXIF_LONG_DATE;
558   else if (info.Equals("exifdescription")) return SLIDE_EXIF_DESCRIPTION;
559   else if (info.Equals("cameramake")) return SLIDE_EXIF_CAMERA_MAKE;
560   else if (info.Equals("cameramodel")) return SLIDE_EXIF_CAMERA_MODEL;
561   else if (info.Equals("exifcomment")) return SLIDE_EXIF_COMMENT;
562   else if (info.Equals("exifsoftware")) return SLIDE_EXIF_SOFTWARE;
563   else if (info.Equals("aperture")) return SLIDE_EXIF_APERTURE;
564   else if (info.Equals("focallength")) return SLIDE_EXIF_FOCAL_LENGTH;
565   else if (info.Equals("focusdistance")) return SLIDE_EXIF_FOCUS_DIST;
566   else if (info.Equals("exposure")) return SLIDE_EXIF_EXPOSURE;
567   else if (info.Equals("exposuretime")) return SLIDE_EXIF_EXPOSURE_TIME;
568   else if (info.Equals("exposurebias")) return SLIDE_EXIF_EXPOSURE_BIAS;
569   else if (info.Equals("exposuremode")) return SLIDE_EXIF_EXPOSURE_MODE;
570   else if (info.Equals("flashused")) return SLIDE_EXIF_FLASH_USED;
571   else if (info.Equals("whitebalance")) return SLIDE_EXIF_WHITE_BALANCE;
572   else if (info.Equals("lightsource")) return SLIDE_EXIF_LIGHT_SOURCE;
573   else if (info.Equals("meteringmode")) return SLIDE_EXIF_METERING_MODE;
574   else if (info.Equals("isoequivalence")) return SLIDE_EXIF_ISO_EQUIV;
575   else if (info.Equals("digitalzoom")) return SLIDE_EXIF_DIGITAL_ZOOM;
576   else if (info.Equals("ccdwidth")) return SLIDE_EXIF_CCD_WIDTH;
577   else if (info.Equals("orientation")) return SLIDE_EXIF_ORIENTATION;
578   else if (info.Equals("supplementalcategories")) return SLIDE_IPTC_SUP_CATEGORIES;
579   else if (info.Equals("keywords")) return SLIDE_IPTC_KEYWORDS;
580   else if (info.Equals("caption")) return SLIDE_IPTC_CAPTION;
581   else if (info.Equals("author")) return SLIDE_IPTC_AUTHOR;
582   else if (info.Equals("headline")) return SLIDE_IPTC_HEADLINE;
583   else if (info.Equals("specialinstructions")) return SLIDE_IPTC_SPEC_INSTR;
584   else if (info.Equals("category")) return SLIDE_IPTC_CATEGORY;
585   else if (info.Equals("byline")) return SLIDE_IPTC_BYLINE;
586   else if (info.Equals("bylinetitle")) return SLIDE_IPTC_BYLINE_TITLE;
587   else if (info.Equals("credit")) return SLIDE_IPTC_CREDIT;
588   else if (info.Equals("source")) return SLIDE_IPTC_SOURCE;
589   else if (info.Equals("copyrightnotice")) return SLIDE_IPTC_COPYRIGHT_NOTICE;
590   else if (info.Equals("objectname")) return SLIDE_IPTC_OBJECT_NAME;
591   else if (info.Equals("city")) return SLIDE_IPTC_CITY;
592   else if (info.Equals("state")) return SLIDE_IPTC_STATE;
593   else if (info.Equals("country")) return SLIDE_IPTC_COUNTRY;
594   else if (info.Equals("transmissionreference")) return SLIDE_IPTC_TX_REFERENCE;
595   else if (info.Equals("iptcdate")) return SLIDE_IPTC_DATE;
596   else if (info.Equals("urgency")) return SLIDE_IPTC_URGENCY;
597   else if (info.Equals("countrycode")) return SLIDE_IPTC_COUNTRY_CODE;
598   else if (info.Equals("referenceservice")) return SLIDE_IPTC_REF_SERVICE;
599   else if (info.Equals("latitude")) return SLIDE_EXIF_GPS_LATITUDE;
600   else if (info.Equals("longitude")) return SLIDE_EXIF_GPS_LONGITUDE;
601   else if (info.Equals("altitude")) return SLIDE_EXIF_GPS_ALTITUDE;
602   else if (info.Equals("timecreated")) return SLIDE_IPTC_TIMECREATED;
603   else if (info.Equals("sublocation")) return SLIDE_IPTC_SUBLOCATION;
604   else if (info.Equals("imagetype")) return SLIDE_IPTC_IMAGETYPE;
605   return 0;
606 }
607
608 void CPictureInfoTag::SetInfo(int info, const CStdString& value)
609 {
610   switch (info)
611   {
612   case SLIDE_RESOLUTION:
613     {
614       vector<std::string> dimension;
615       StringUtils::Tokenize(value, dimension, ",");
616       if (dimension.size() == 2)
617       {
618         m_exifInfo.Width = atoi(dimension[0].c_str());
619         m_exifInfo.Height = atoi(dimension[1].c_str());
620         m_isInfoSetExternally = true; // Set the internal state to show metadata has been set by call to SetInfo
621       }
622       break;
623     }
624   case SLIDE_EXIF_DATE_TIME:
625     {
626       strcpy(m_exifInfo.DateTime, value.c_str());
627       m_isInfoSetExternally = true; // Set the internal state to show metadata has been set by call to SetInfo
628       ConvertDateTime();
629       break;
630     }
631   default:
632     break;
633   }
634 }
635
636 const CDateTime& CPictureInfoTag::GetDateTimeTaken() const
637 {
638   return m_dateTimeTaken;
639 }
640
641 void CPictureInfoTag::ConvertDateTime()
642 {
643   if (strlen(m_exifInfo.DateTime) >= 19 && m_exifInfo.DateTime[0] != ' ')
644   {
645     CStdString dateTime = m_exifInfo.DateTime;
646     int year  = atoi(dateTime.Mid(0, 4).c_str());
647     int month = atoi(dateTime.Mid(5, 2).c_str());
648     int day   = atoi(dateTime.Mid(8, 2).c_str());
649     int hour  = atoi(dateTime.Mid(11,2).c_str());
650     int min   = atoi(dateTime.Mid(14,2).c_str());
651     int sec   = atoi(dateTime.Mid(17,2).c_str());
652     m_dateTimeTaken.SetDateTime(year, month, day, hour, min, sec);
653   }
654 }