diff options
author | theuni <theuni-nospam-@xbmc.org> | 2011-01-24 16:05:21 -0500 |
---|---|---|
committer | theuni <theuni-nospam-@xbmc.org> | 2011-01-24 16:05:21 -0500 |
commit | c51b1189e3d5353e842991f5859ddcea0f73e426 (patch) | |
tree | ef2cb8a6184699aa614f3655dca4ce661cdc108e /lib/libexif | |
parent | be61ebdc9e897fe40c6f371111724de79ddee8d5 (diff) |
Merged cptspiff's code-reshuffle branch.
Squashed commit due to build breakage during code-reshuffle history.
Conflicts:
xbmc/Util.cpp
xbmc/cdrip/CDDARipper.cpp
xbmc/filesystem/Directory.cpp
xbmc/filesystem/File.cpp
Diffstat (limited to 'lib/libexif')
-rw-r--r-- | lib/libexif/ExifParse.cpp | 888 | ||||
-rw-r--r-- | lib/libexif/ExifParse.h | 38 | ||||
-rw-r--r-- | lib/libexif/IptcParse.cpp | 178 | ||||
-rw-r--r-- | lib/libexif/IptcParse.h | 12 | ||||
-rw-r--r-- | lib/libexif/JpegParse.cpp | 324 | ||||
-rw-r--r-- | lib/libexif/JpegParse.h | 57 | ||||
-rw-r--r-- | lib/libexif/Makefile.in | 20 | ||||
-rw-r--r-- | lib/libexif/libexif.cpp | 42 | ||||
-rw-r--r-- | lib/libexif/libexif.h | 126 | ||||
-rw-r--r-- | lib/libexif/libexif.sln | 24 | ||||
-rw-r--r-- | lib/libexif/libexif.vcproj | 303 | ||||
-rw-r--r-- | lib/libexif/libexif.vcxproj | 174 | ||||
-rw-r--r-- | lib/libexif/libexif.vcxproj.filters | 45 |
13 files changed, 2231 insertions, 0 deletions
diff --git a/lib/libexif/ExifParse.cpp b/lib/libexif/ExifParse.cpp new file mode 100644 index 0000000000..41690df245 --- /dev/null +++ b/lib/libexif/ExifParse.cpp @@ -0,0 +1,888 @@ +/* + * Copyright (C) 2005-2007 Team XboxMediaCenter + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +//-------------------------------------------------------------------------- +// Program to pull the EXIF information out of various types of digital +// images and present it in a reasonably consistent way +// +// Original code pulled from 'jhead' by Matthias Wandel (http://www.sentex.net/~mwandel/) - jhead +// Adapted for XBMC by DD. +//-------------------------------------------------------------------------- + +// Note: Jhead supports TAG_MAKER_NOTE exif field, +// but that is ommited for now - to make porting easier and addition smaller +#ifndef _LINUX +#include <windows.h> +#else +#include <memory.h> +#define min(a,b) (a)>(b)?(b):(a) +#define max(a,b) (a)<(b)?(b):(a) +#endif +#include <math.h> +#include <stdio.h> +#include "ExifParse.h" + + +// Prototypes for exif utility functions. +static void ErrNonfatal(const char* const msg, int a1, int a2); + +#define DIR_ENTRY_ADDR(Start, Entry) ((Start)+2+12*(Entry)) + + +//-------------------------------------------------------------------------- +// Describes tag values +#define TAG_DESCRIPTION 0x010E +#define TAG_MAKE 0x010F +#define TAG_MODEL 0x0110 +#define TAG_ORIENTATION 0x0112 +#define TAG_X_RESOLUTION 0x011A // Not processed. Format rational64u (see http://search.cpan.org/src/EXIFTOOL/Image-ExifTool-6.76/html/TagNames/EXIF.html) +#define TAG_Y_RESOLUTION 0x011B // Not processed. Format rational64u +#define TAG_RESOLUTION_UNIT 0x0128 // Not processed. Format int16u. Values: 1-none; 2-inches; 3-cm +#define TAG_SOFTWARE 0x0131 +#define TAG_DATETIME 0x0132 +#define TAG_THUMBNAIL_OFFSET 0x0201 +#define TAG_THUMBNAIL_LENGTH 0x0202 +#define TAG_Y_CB_CR_POS 0x0213 // Not processed. Format int16u. Values: 1-Centered; 2-Co-sited +#define TAG_EXPOSURETIME 0x829A +#define TAG_FNUMBER 0x829D +#define TAG_EXIF_OFFSET 0x8769 +#define TAG_EXPOSURE_PROGRAM 0x8822 +#define TAG_GPSINFO 0x8825 +#define TAG_ISO_EQUIVALENT 0x8827 +#define TAG_EXIF_VERSION 0x9000 // Not processed. +#define TAG_COMPONENT_CFG 0x9101 // Not processed. +#define TAG_DATETIME_ORIGINAL 0x9003 +#define TAG_DATETIME_DIGITIZED 0x9004 +#define TAG_SHUTTERSPEED 0x9201 +#define TAG_APERTURE 0x9202 +#define TAG_EXPOSURE_BIAS 0x9204 +#define TAG_MAXAPERTURE 0x9205 +#define TAG_SUBJECT_DISTANCE 0x9206 +#define TAG_METERING_MODE 0x9207 +#define TAG_LIGHT_SOURCE 0x9208 +#define TAG_FLASH 0x9209 +#define TAG_FOCALLENGTH 0x920A +#define TAG_MAKER_NOTE 0x927C // Not processed yet. Maybe in the future. +#define TAG_USERCOMMENT 0x9286 +#define TAG_FLASHPIX_VERSION 0xA000 // Not processed. +#define TAG_COLOUR_SPACE 0xA001 // Not processed. Format int16u. Values: 1-RGB; 2-Adobe RGB 65535-Uncalibrated +#define TAG_EXIF_IMAGEWIDTH 0xa002 +#define TAG_EXIF_IMAGELENGTH 0xa003 +#define TAG_INTEROP_OFFSET 0xa005 +#define TAG_FOCALPLANEXRES 0xa20E +#define TAG_FOCALPLANEUNITS 0xa210 +#define TAG_EXPOSURE_INDEX 0xa215 +#define TAG_EXPOSURE_MODE 0xa402 +#define TAG_WHITEBALANCE 0xa403 +#define TAG_DIGITALZOOMRATIO 0xA404 +#define TAG_FOCALLENGTH_35MM 0xa405 + +#define TAG_GPS_LAT_REF 1 +#define TAG_GPS_LAT 2 +#define TAG_GPS_LONG_REF 3 +#define TAG_GPS_LONG 4 +#define TAG_GPS_ALT_REF 5 +#define TAG_GPS_ALT 6 + +//-------------------------------------------------------------------------- +// Exif format descriptor stuff +#define FMT_BYTE 1 +#define FMT_STRING 2 +#define FMT_USHORT 3 +#define FMT_ULONG 4 +#define FMT_URATIONAL 5 +#define FMT_SBYTE 6 +#define FMT_UNDEFINED 7 +#define FMT_SSHORT 8 +#define FMT_SLONG 9 +#define FMT_SRATIONAL 10 +#define FMT_SINGLE 11 +#define FMT_DOUBLE 12 +// NOTE: Remember to change NUM_FORMATS if you define a new format +#define NUM_FORMATS 12 + +//-------------------------------------------------------------------------- +// Internationalisation string IDs. The enum order must match that in the +// language file (e.g. 'language/English/strings.xml', and EXIF_PARSE_STRING_ID_BASE +// must match the ID of the first Exif string in that file. +#define EXIF_PARSE_STRING_ID_BASE 21800 +enum { +// Distance + ExifStrDistanceInfinite = EXIF_PARSE_STRING_ID_BASE, +// Whitebalance et.al. + ExifStrManual, + ExifStrAuto, +// Flash modes + ExifStrYes, + ExifStrNo, + ExifStrFlashNoStrobe, + ExifStrFlashStrobe, + ExifStrFlashManual, + ExifStrFlashManualNoReturn, + ExifStrFlashManualReturn, + ExifStrFlashAuto, + ExifStrFlashAutoNoReturn, + ExifStrFlashAutoReturn, + ExifStrFlashRedEye, + ExifStrFlashRedEyeNoReturn, + ExifStrFlashRedEyeReturn, + ExifStrFlashManualRedEye, + ExifStrFlashManualRedEyeNoReturn, + ExifStrFlashManualRedEyeReturn, + ExifStrFlashAutoRedEye, + ExifStrFlashAutoRedEyeNoReturn, + ExifStrFlashAutoRedEyeReturn, +// Light sources + ExifStrDaylight, + ExifStrFluorescent, + ExifStrIncandescent, + ExifStrFlash, + ExifStrFineWeather, + ExifStrShade, +// Metering Mode + ExifStrMeteringCenter, + ExifStrMeteringSpot, + ExifStrMeteringMatrix, +// Exposure Program + ExifStrExposureProgram, + ExifStrExposureAperture, + ExifStrExposureShutter, + ExifStrExposureCreative, + ExifStrExposureAction, + ExifStrExposurePortrait, + ExifStrExposureLandscape, +// Exposure mode + ExifStrExposureModeAuto, +// ISO equivalent + ExifStrIsoEquivalent, +// GPS latitude, longitude, altitude + ExifStrGpsLatitude, + ExifStrGpsLongitude, + ExifStrGpsAltitude, +}; + + + + +//-------------------------------------------------------------------------- +// Report non fatal errors. Now that microsoft.net modifies exif headers, +// there's corrupted ones, and there could be more in the future. +//-------------------------------------------------------------------------- +static void ErrNonfatal(const char* const msg, int a1, int a2) +{ + printf("ExifParse - Nonfatal Error : %s %d %d", msg, a1, a2); +} + +//-------------------------------------------------------------------------- +// Constructor. +//-------------------------------------------------------------------------- +CExifParse::CExifParse () : m_FocalPlaneXRes(0.0), + m_FocalPlaneUnits(0.0), m_ExifImageWidth(0), m_MotorolaOrder(false), + m_DateFound(false) +{ + m_ExifInfo = NULL; +} + +//-------------------------------------------------------------------------- +// Convert a 16 bit unsigned value from file's native byte order +//-------------------------------------------------------------------------- +int CExifParse::Get16(const void* const Short, const bool motorolaOrder) +{ + if (motorolaOrder) { + return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1]; + } else { + return (((unsigned char *)Short)[1] << 8) | ((unsigned char *)Short)[0]; + } +} + +//-------------------------------------------------------------------------- +// Convert a 32 bit signed value from file's native byte order +//-------------------------------------------------------------------------- +int CExifParse::Get32(const void* const Long, const bool motorolaOrder) +{ + if (motorolaOrder) { + return ((( char *)Long)[0] << 24) | (((unsigned char *)Long)[1] << 16) + | (((unsigned char *)Long)[2] << 8 ) | (((unsigned char *)Long)[3] << 0 ); + } else { + return ((( char *)Long)[3] << 24) | (((unsigned char *)Long)[2] << 16) + | (((unsigned char *)Long)[1] << 8 ) | (((unsigned char *)Long)[0] << 0 ); + } +} + +//-------------------------------------------------------------------------- +// It appears that CStdString constructor replaces "\n" with "\r\n" which results +// in "\r\r\n" if there already is "\r\n", which in turn results in corrupted +// display. So this is an attempt to undo effects of a smart constructor. Also, +// replaces all nonprintable characters with "." +//-------------------------------------------------------------------------- +/*void CExifParse::FixComment(CStdString& comment) +{ + comment.Replace("\r\r\n", "\r\n"); + for (unsigned int i=0; i<comment.length(); i++) + { + if ((comment[i] < 32) && (comment[i] != '\n') && (comment[i] != '\t') && (comment[i] != '\r')) + { + comment[i] = '.'; + } + } +}*/ + +//-------------------------------------------------------------------------- +// Evaluate number, be it int, rational, or float from directory. +//-------------------------------------------------------------------------- +double CExifParse::ConvertAnyFormat(const void* const ValuePtr, int Format) +{ + double Value; + Value = 0; + + switch(Format) + { + case FMT_SBYTE: Value = *( signed char*)ValuePtr; break; + case FMT_BYTE: Value = *(unsigned char*)ValuePtr; break; + + case FMT_USHORT: Value = Get16(ValuePtr, m_MotorolaOrder); break; + case FMT_ULONG: Value = (unsigned)Get32(ValuePtr, m_MotorolaOrder); break; + + case FMT_URATIONAL: + case FMT_SRATIONAL: + { + int Num,Den; + Num = Get32(ValuePtr, m_MotorolaOrder); + Den = Get32(4+(char *)ValuePtr, m_MotorolaOrder); + + if (Den == 0) Value = 0; + else Value = (double)Num/Den; + } + break; + + case FMT_SSHORT: Value = (signed short)Get16(ValuePtr, m_MotorolaOrder); break; + case FMT_SLONG: Value = Get32(ValuePtr, m_MotorolaOrder); break; + + // Not sure if this is correct (never seen float used in Exif format) + case FMT_SINGLE: Value = (double)*(float*)ValuePtr; break; + case FMT_DOUBLE: Value = *(double*)ValuePtr; break; + + default: + ErrNonfatal("Illegal format code %d",Format,0); + } + return Value; +} + +//-------------------------------------------------------------------------- +// Exif date tag is stored as a fixed format string "YYYY:MM:DD HH:MM:SS". +// If date is not set, then the string is filled with blanks and colons: +// " : : : : ". We want this string localised. +//-------------------------------------------------------------------------- +/*void CExifParse::LocaliseDate (void) +{ + if (m_ExifInfo[SLIDE_EXIF_DATE_TIME][0] != ' ') + { + int year = atoi(m_ExifInfo[SLIDE_EXIF_DATE_TIME].substr(0, 4).c_str()); + int month = atoi(m_ExifInfo[SLIDE_EXIF_DATE_TIME].substr(5, 2).c_str()); + int day = atoi(m_ExifInfo[SLIDE_EXIF_DATE_TIME].substr(8, 2).c_str()); + int hour = atoi(m_ExifInfo[SLIDE_EXIF_DATE_TIME].substr(11,2).c_str()); + int min = atoi(m_ExifInfo[SLIDE_EXIF_DATE_TIME].substr(14,2).c_str()); + int sec = atoi(m_ExifInfo[SLIDE_EXIF_DATE_TIME].substr(17,2).c_str()); + CDateTime date(year, month, day, hour, min, sec); + m_ExifInfo[SLIDE_EXIF_DATE_TIME] = date.GetAsLocalizedDateTime(); + } +}*/ + + +//-------------------------------------------------------------------------- +// Convert exposure time into a human readable format +//-------------------------------------------------------------------------- +/*void CExifParse::GetExposureTime(const float exposureTime, CStdString& outStr) +{ + if (exposureTime) + { + if (exposureTime < 0.010) outStr.Format("%6.4fs ", exposureTime); + else outStr.Format("%5.3fs ", exposureTime); + if (exposureTime <= 0.5) outStr.Format("%s (1/%d)", outStr, (int)(0.5 + 1/exposureTime)); + } +}*/ + +//-------------------------------------------------------------------------- +// Process one of the nested EXIF directories. +//-------------------------------------------------------------------------- +void CExifParse::ProcessDir(const unsigned char* const DirStart, + const unsigned char* const OffsetBase, + const unsigned ExifLength, + int NestingLevel) +{ + if (NestingLevel > 4) + { + ErrNonfatal("Maximum directory nesting exceeded (corrupt exif header)", 0,0); + return; + } + + char IndentString[25]; + memset(IndentString, ' ', 25); + IndentString[NestingLevel * 4] = '\0'; + + + int NumDirEntries = Get16((void*)DirStart, m_MotorolaOrder); + + const unsigned char* const DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries); + if (DirEnd+4 > (OffsetBase+ExifLength)) + { + if (DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength) + { + // Version 1.3 of jhead would truncate a bit too much. + // This also caught later on as well. + } + else + { + ErrNonfatal("Illegally sized directory", 0,0); + return; + } + } + + const int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8}; + + + for (int de=0;de<NumDirEntries;de++) + { + int Tag, Format, Components; + unsigned char* ValuePtr; + int ByteCount; + const unsigned char* const DirEntry = DIR_ENTRY_ADDR(DirStart, de); + + Tag = Get16(DirEntry, m_MotorolaOrder); + Format = Get16(DirEntry+2, m_MotorolaOrder); + Components = Get32(DirEntry+4, m_MotorolaOrder); + + if ((Format-1) >= NUM_FORMATS) + { + // (-1) catches illegal zero case as unsigned underflows to positive large. + ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag); + continue; + } + + if ((unsigned)Components > 0x10000) + { + ErrNonfatal("Illegal number of components %d for tag %04x", Components, Tag); + continue; + } + + ByteCount = Components * BytesPerFormat[Format]; + + if (ByteCount > 4) + { + unsigned OffsetVal; + OffsetVal = (unsigned)Get32(DirEntry+8, m_MotorolaOrder); + // If its bigger than 4 bytes, the dir entry contains an offset. + if (OffsetVal+ByteCount > ExifLength) + { + // Bogus pointer offset and / or bytecount value + ErrNonfatal("Illegal value pointer for tag %04x", Tag,0); + continue; + } + ValuePtr = (unsigned char*)(OffsetBase+OffsetVal); + + if (OffsetVal > m_LargestExifOffset) + { + m_LargestExifOffset = OffsetVal; + } + + } + else { + // 4 bytes or less and value is in the dir entry itself + ValuePtr = (unsigned char*)(DirEntry+8); + } + + + // Extract useful components of tag + switch(Tag) + { +// case TAG_DESCRIPTION: strncpy(m_ExifInfo->Description, ValuePtr, 5); break; + case TAG_MAKE: strncpy(m_ExifInfo->CameraMake, (char *)ValuePtr, 32); break; + case TAG_MODEL: strncpy(m_ExifInfo->CameraModel, (char *)ValuePtr, 40); break; +// case TAG_SOFTWARE: strncpy(m_ExifInfo->Software, ValuePtr, 5); break; + case TAG_FOCALPLANEXRES: m_FocalPlaneXRes = ConvertAnyFormat(ValuePtr, Format); break; + case TAG_THUMBNAIL_OFFSET: m_ExifInfo->ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format); break; + case TAG_THUMBNAIL_LENGTH: m_ExifInfo->ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format); break; + + case TAG_MAKER_NOTE: + continue; + break; + + case TAG_DATETIME_ORIGINAL: + // If we get a DATETIME_ORIGINAL, we use that one. + strncpy(m_ExifInfo->DateTime, (char *)ValuePtr, 20); + m_DateFound = true; + break; + + case TAG_DATETIME_DIGITIZED: + case TAG_DATETIME: + if (m_DateFound == false) + { + // If we don't already have a DATETIME_ORIGINAL, use whatever + // time fields we may have. + strncpy(m_ExifInfo->DateTime, (char *)ValuePtr, 20); +// LocaliseDate(); + } + break; + + case TAG_USERCOMMENT: + { + const int EXIF_COMMENT_HDR_LENGTH = 8; // All comment tags have 8 bytes of header info + int length = max(ByteCount - EXIF_COMMENT_HDR_LENGTH, 0); + length = min(length, 2000); + strncpy(m_ExifInfo->Comments, (char *)ValuePtr+EXIF_COMMENT_HDR_LENGTH, length); +// FixComment(comment); // Ensure comment is printable + } + break; + + case TAG_FNUMBER: + // Simplest way of expressing aperture, so I trust it the most. + // (overwrite previously computd value if there is one) + m_ExifInfo->ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_APERTURE: + case TAG_MAXAPERTURE: + // More relevant info always comes earlier, so only use this field if we don't + // have appropriate aperture information yet. + if (m_ExifInfo->ApertureFNumber == 0) + { + m_ExifInfo->ApertureFNumber = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0)*0.5); + } + break; + + case TAG_FOCALLENGTH: + // Nice digital cameras actually save the focal length as a function + // of how far they are zoomed in. + m_ExifInfo->FocalLength = (float)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_SUBJECT_DISTANCE: + // Inidcates the distacne the autofocus camera is focused to. + // Tends to be less accurate as distance increases. + { + float distance = (float)ConvertAnyFormat(ValuePtr, Format); + if (distance < 0) + m_ExifInfo->Distance = distance; // infinite + else + m_ExifInfo->Distance = distance; + } + break; + + case TAG_EXPOSURETIME: + { + // Simplest way of expressing exposure time, so I trust it most. + // (overwrite previously computd value if there is one) + float expTime = (float)ConvertAnyFormat(ValuePtr, Format); + if (expTime) + m_ExifInfo->ExposureTime = expTime; + } + break; + + case TAG_SHUTTERSPEED: + // More complicated way of expressing exposure time, so only use + // this value if we don't already have it from somewhere else. + if (m_ExifInfo->ExposureTime == 0) + { + m_ExifInfo->ExposureTime = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0))); + } + break; + + case TAG_FLASH: + m_ExifInfo->FlashUsed = (int)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_ORIENTATION: + m_ExifInfo->Orientation = (int)ConvertAnyFormat(ValuePtr, Format); + if (m_ExifInfo->Orientation < 0 || m_ExifInfo->Orientation > 8) + { + ErrNonfatal("Undefined rotation value %d", m_ExifInfo->Orientation, 0); + m_ExifInfo->Orientation = 0; + } + break; + + case TAG_EXIF_IMAGELENGTH: + case TAG_EXIF_IMAGEWIDTH: + // Use largest of height and width to deal with images that have been + // rotated to portrait format. + { + int a = (int)ConvertAnyFormat(ValuePtr, Format); + if (m_ExifImageWidth < a) m_ExifImageWidth = a; + } + break; + + case TAG_FOCALPLANEUNITS: + switch((int)ConvertAnyFormat(ValuePtr, Format)) + { + // According to the information I was using, 2 means meters. + // But looking at the Cannon powershot's files, inches is the only + // sensible value. + case 1: m_FocalPlaneUnits = 25.4; break; // inch + case 2: m_FocalPlaneUnits = 25.4; break; + case 3: m_FocalPlaneUnits = 10; break; // centimeter + case 4: m_FocalPlaneUnits = 1; break; // millimeter + case 5: m_FocalPlaneUnits = .001; break; // micrometer + } + break; + + case TAG_EXPOSURE_BIAS: + m_ExifInfo->ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_WHITEBALANCE: + m_ExifInfo->Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_LIGHT_SOURCE: + //Quercus: 17-1-2004 Added LightSource, some cams return this, whitebalance or both + m_ExifInfo->LightSource = (int)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_METERING_MODE: + m_ExifInfo->MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_EXPOSURE_PROGRAM: + m_ExifInfo->ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_EXPOSURE_INDEX: + if (m_ExifInfo->ISOequivalent == 0) + { + // Exposure index and ISO equivalent are often used interchangeably, + // so we will do the same. + // http://photography.about.com/library/glossary/bldef_ei.htm + m_ExifInfo->ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format); + } + break; + + case TAG_ISO_EQUIVALENT: + m_ExifInfo->ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format); + if (m_ExifInfo->ISOequivalent < 50) + m_ExifInfo->ISOequivalent *= 200; // Fixes strange encoding on some older digicams. + break; + + case TAG_EXPOSURE_MODE: + m_ExifInfo->ExposureMode = (int)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_DIGITALZOOMRATIO: + m_ExifInfo->DigitalZoomRatio = (float)ConvertAnyFormat(ValuePtr, Format); + break; + + case TAG_EXIF_OFFSET: + case TAG_INTEROP_OFFSET: + { + const unsigned char* const SubdirStart = OffsetBase + (unsigned)Get32(ValuePtr, m_MotorolaOrder); + if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength) + { + ErrNonfatal("Illegal exif or interop ofset directory link",0,0); + } + else + { + ProcessDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1); + } + continue; + } + break; + + case TAG_GPSINFO: + { + const unsigned char* const SubdirStart = OffsetBase + (unsigned)Get32(ValuePtr, m_MotorolaOrder); + if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength) + { + ErrNonfatal("Illegal GPS directory link",0,0); + } + else + { + ProcessGpsInfo(SubdirStart, ByteCount, OffsetBase, ExifLength); + } + continue; + } + break; + + case TAG_FOCALLENGTH_35MM: + // The focal length equivalent 35 mm is a 2.2 tag (defined as of April 2002) + // if its present, use it to compute equivalent focal length instead of + // computing it from sensor geometry and actual focal length. + m_ExifInfo->FocalLength35mmEquiv = (unsigned)ConvertAnyFormat(ValuePtr, Format); + break; + } + } + + + // In addition to linking to subdirectories via exif tags, + // there's also a potential link to another directory at the end of each + // directory. this has got to be the result of a committee! + unsigned Offset; + + if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength) + { + Offset = (unsigned)Get32(DirStart+2+12*NumDirEntries, m_MotorolaOrder); + if (Offset) + { + const unsigned char* const SubdirStart = OffsetBase + Offset; + if (SubdirStart > OffsetBase+ExifLength || SubdirStart < OffsetBase) + { + if (SubdirStart > OffsetBase && SubdirStart < OffsetBase+ExifLength+20) + { + // Jhead 1.3 or earlier would crop the whole directory! + // As Jhead produces this form of format incorrectness, + // I'll just let it pass silently + } + else + { + ErrNonfatal("Illegal subdirectory link",0,0); + } + } + else + { + if (SubdirStart <= OffsetBase+ExifLength) + { + ProcessDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1); + } + } + if (Offset > m_LargestExifOffset) + { + m_LargestExifOffset = Offset; + } + } + } + else + { + // The exif header ends before the last next directory pointer. + } + + if (m_ExifInfo->ThumbnailOffset) + { + m_ExifInfo->ThumbnailAtEnd = false; + + if (m_ExifInfo->ThumbnailOffset <= ExifLength) + { + if (m_ExifInfo->ThumbnailSize > ExifLength - m_ExifInfo->ThumbnailOffset) + { + // If thumbnail extends past exif header, only save the part that + // actually exists. Canon's EOS viewer utility will do this - the + // thumbnail extracts ok with this hack. + m_ExifInfo->ThumbnailSize = ExifLength - m_ExifInfo->ThumbnailOffset; + } + } + } +} + + +//-------------------------------------------------------------------------- +// Process a EXIF marker +// Describes all the drivel that most digital cameras include... +//-------------------------------------------------------------------------- +bool CExifParse::Process (const unsigned char* const ExifSection, const unsigned short length, ExifInfo_t *info) +{ + m_ExifInfo = info; + // EXIF signature: "Exif\0\0" + // Check EXIF signatures + const char ExifHeader[] = "Exif\0\0"; + const char ExifAlignment0[] = "II"; + const char ExifAlignment1[] = "MM"; + const char ExifExtra = 0x2a; + + char* pos = (char*)(ExifSection + sizeof(short)); // position data pointer after length field + + if (memcmp(pos, ExifHeader,6)) + { + printf("ExifParse: incorrect Exif header"); + return false; + } + pos += 6; + + if (memcmp(pos, ExifAlignment0, strlen(ExifAlignment0)) == 0) + { + m_MotorolaOrder = false; + } + else if (memcmp(pos, ExifAlignment1, strlen(ExifAlignment1)) == 0) + { + m_MotorolaOrder = true; + } + else + { + printf("ExifParse: invalid Exif alignment marker"); + return false; + } + pos += strlen(ExifAlignment0); + + // Check the next value for correctness. + if (Get16((void*)(pos), m_MotorolaOrder) != ExifExtra) + { + printf("ExifParse: invalid Exif start (1)"); + return false; + } + pos += sizeof(short); + + unsigned long FirstOffset = (unsigned)Get32((void*)pos, m_MotorolaOrder); + if (FirstOffset < 8 || FirstOffset > 16) + { + // Usually set to 8, but other values valid too. +// CLog::Log(LOGERROR, "ExifParse: suspicious offset of first IFD value"); + } + + + + // First directory starts 16 bytes in. All offset are relative to 8 bytes in. + ProcessDir(ExifSection+8+FirstOffset, ExifSection+8, length-8, 0); + + m_ExifInfo->ThumbnailAtEnd = m_ExifInfo->ThumbnailOffset >= m_LargestExifOffset ? true : false; + + // Compute the CCD width, in millimeters. + if (m_FocalPlaneXRes != 0) + { + // Note: With some cameras, its not possible to compute this correctly because + // they don't adjust the indicated focal plane resolution units when using less + // than maximum resolution, so the CCDWidth value comes out too small. Nothing + // that Jhead can do about it - its a camera problem. + m_ExifInfo->CCDWidth = (float)(m_ExifImageWidth * m_FocalPlaneUnits / m_FocalPlaneXRes); + } + + if (m_ExifInfo->FocalLength) + { + if (m_ExifInfo->FocalLength35mmEquiv == 0) + { + // Compute 35 mm equivalent focal length based on sensor geometry if we haven't + // already got it explicitly from a tag. + if (m_ExifInfo->CCDWidth != 0.0) + { + m_ExifInfo->FocalLength35mmEquiv = (int)(m_ExifInfo->FocalLength/m_ExifInfo->CCDWidth*36 + 0.5); + } + } + } + return true; +} + + + +//-------------------------------------------------------------------------- +// GPS Lat/Long extraction helper function +//-------------------------------------------------------------------------- +void CExifParse::GetLatLong( + const unsigned int Format, + const unsigned char* ValuePtr, + const int ComponentSize, + char *latLongString) +{ + if (Format != FMT_URATIONAL) + { + ErrNonfatal("Illegal number format %d for GPS Lat/Long", Format, 0); + } + else + { + double Values[3]; + for (unsigned a=0; a<3 ;a++) + { + Values[a] = ConvertAnyFormat(ValuePtr+a*ComponentSize, Format); + } + char latLong[30]; + sprintf(latLong, "%3.0fd %2.0f' %5.2f\"", Values[0], Values[1], Values[2]); + strcat(latLongString, latLong); + } +} + +//-------------------------------------------------------------------------- +// Process GPS info directory +//-------------------------------------------------------------------------- +void CExifParse::ProcessGpsInfo( + const unsigned char* const DirStart, + int ByteCountUnused, + const unsigned char* const OffsetBase, + unsigned ExifLength) +{ + int NumDirEntries = Get16(DirStart); + + for (int de=0;de<NumDirEntries;de++) + { + const unsigned char* DirEntry = DIR_ENTRY_ADDR(DirStart, de); + + unsigned Tag = Get16(DirEntry); + unsigned Format = Get16(DirEntry+2); + unsigned Components = (unsigned)Get32(DirEntry+4); + if ((Format-1) >= NUM_FORMATS) + { + // (-1) catches illegal zero case as unsigned underflows to positive large. + ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag); + continue; + } + + const int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8}; + int ComponentSize = BytesPerFormat[Format]; + unsigned ByteCount = Components * ComponentSize; + + const unsigned char* ValuePtr; + + if (ByteCount > 4) + { + unsigned OffsetVal = (unsigned)Get32(DirEntry+8); + // If its bigger than 4 bytes, the dir entry contains an offset. + if (OffsetVal+ByteCount > ExifLength) + { + // Bogus pointer offset and / or bytecount value + ErrNonfatal("Illegal value pointer for tag %04x", Tag,0); + continue; + } + ValuePtr = OffsetBase+OffsetVal; + } + else + { + // 4 bytes or less and value is in the dir entry itself + ValuePtr = DirEntry+8; + } + + switch(Tag) + { + case TAG_GPS_LAT_REF: + m_ExifInfo->GpsLat[0] = ValuePtr[0]; + m_ExifInfo->GpsLat[1] = 0; + break; + + case TAG_GPS_LONG_REF: + m_ExifInfo->GpsLong[0] = ValuePtr[0]; + m_ExifInfo->GpsLong[1] = 0; + break; + + case TAG_GPS_LAT: + GetLatLong(Format, ValuePtr, ComponentSize, m_ExifInfo->GpsLat); + break; + case TAG_GPS_LONG: + GetLatLong(Format, ValuePtr, ComponentSize, m_ExifInfo->GpsLong); + break; + + case TAG_GPS_ALT_REF: + if (ValuePtr[0] != 0) + m_ExifInfo->GpsAlt[0] = '-'; + m_ExifInfo->GpsAlt[1] = 0; + break; + + case TAG_GPS_ALT: + { + char temp[18]; + sprintf(temp,"%dm", Get32(ValuePtr)); + strcat(m_ExifInfo->GpsAlt, temp); + } + break; + } + } +} + diff --git a/lib/libexif/ExifParse.h b/lib/libexif/ExifParse.h new file mode 100644 index 0000000000..94e6cd0fc2 --- /dev/null +++ b/lib/libexif/ExifParse.h @@ -0,0 +1,38 @@ +#pragma once + +#include "libexif.h" + +class CExifParse +{ + public: + CExifParse (); + ~CExifParse (void) {} + bool Process (const unsigned char* const Data, const unsigned short length, ExifInfo_t *info); + static int Get16 (const void* const Short, const bool motorolaOrder=true); + static int Get32 (const void* const Long, const bool motorolaOrder=true); + + private: + ExifInfo_t *m_ExifInfo; + double m_FocalPlaneXRes; + double m_FocalPlaneUnits; + unsigned m_LargestExifOffset; // Last exif data referenced (to check if thumbnail is at end) + int m_ExifImageWidth; + bool m_MotorolaOrder; + bool m_DateFound; + +// void LocaliseDate (void); +// void GetExposureTime (const float exposureTime); + double ConvertAnyFormat (const void* const ValuePtr, int Format); + void ProcessDir (const unsigned char* const DirStart, + const unsigned char* const OffsetBase, + const unsigned ExifLength, int NestingLevel); + void ProcessGpsInfo (const unsigned char* const DirStart, + int ByteCountUnused, + const unsigned char* const OffsetBase, + unsigned ExifLength); + void GetLatLong (const unsigned int Format, + const unsigned char* ValuePtr, + const int ComponentSize, + char *latlongString); +}; + diff --git a/lib/libexif/IptcParse.cpp b/lib/libexif/IptcParse.cpp new file mode 100644 index 0000000000..732a2f3c8b --- /dev/null +++ b/lib/libexif/IptcParse.cpp @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2005-2007 Team XboxMediaCenter + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +//-------------------------------------------------------------------------- +// Module to pull IPTC information out of various types of digital images. +//-------------------------------------------------------------------------- + +//-------------------------------------------------------------------------- +// Process IPTC data. +//-------------------------------------------------------------------------- +#ifndef _LINUX +#include <windows.h> +#else +#include <string.h> +#define min(a,b) (a)>(b)?(b):(a) +#endif +#include <stdio.h> +#include "IptcParse.h" +#include "ExifParse.h" + +// Supported IPTC entry types +#define IPTC_SUPLEMENTAL_CATEGORIES 0x14 +#define IPTC_KEYWORDS 0x19 +#define IPTC_CAPTION 0x78 +#define IPTC_AUTHOR 0x7A +#define IPTC_HEADLINE 0x69 +#define IPTC_SPECIAL_INSTRUCTIONS 0x28 +#define IPTC_CATEGORY 0x0F +#define IPTC_BYLINE 0x50 +#define IPTC_BYLINE_TITLE 0x55 +#define IPTC_CREDIT 0x6E +#define IPTC_SOURCE 0x73 +#define IPTC_COPYRIGHT_NOTICE 0x74 +#define IPTC_OBJECT_NAME 0x05 +#define IPTC_CITY 0x5A +#define IPTC_STATE 0x5F +#define IPTC_COUNTRY 0x65 +#define IPTC_TRANSMISSION_REFERENCE 0x67 +#define IPTC_DATE 0x37 +#define IPTC_COPYRIGHT 0x0A +#define IPTC_COUNTRY_CODE 0x64 +#define IPTC_REFERENCE_SERVICE 0x2D + + +//-------------------------------------------------------------------------- +// Process IPTC marker. Return FALSE if unable to process marker. +// +// IPTC block consists of: +// - Marker: 1 byte (0xED) +// - Block length: 2 bytes +// - IPTC Signature: 14 bytes ("Photoshop 3.0\0") +// - 8BIM Signature 4 bytes ("8BIM") +// - IPTC Block start 2 bytes (0x04, 0x04) +// - IPTC Header length 1 byte +// - IPTC header Header is padded to even length, counting the length byte +// - Length 4 bytes +// - IPTC Data which consists of a number of entries, each of which has the following format: +// - Signature 2 bytes (0x1C02) +// - Entry type 1 byte (for defined entry types, see #defines above) +// - entry length 2 bytes +// - entry data 'entry length' bytes +// +//-------------------------------------------------------------------------- +bool CIptcParse::Process (const unsigned char* const Data, const unsigned short itemlen, IPTCInfo_t *info) +{ + if (!info) return false; + + const char IptcSignature1[] = "Photoshop 3.0"; + const char IptcSignature2[] = "8BIM"; + const char IptcSignature3[] = {0x04, 0x04}; + + // Check IPTC signatures + char* pos = (char*)(Data + sizeof(short)); // position data pointer after length field + + if (memcmp(pos, IptcSignature1, strlen(IptcSignature1)) != 0) return false; + pos += strlen(IptcSignature1) + 1; // move data pointer to the next field + + if (memcmp(pos, IptcSignature2, strlen(IptcSignature2)) != 0) return false; + pos += strlen(IptcSignature2); // move data pointer to the next field + + if (memcmp(pos, IptcSignature3, sizeof(IptcSignature3)) != 0) return false; + pos += sizeof(IptcSignature3); // move data pointer to the next field + + // IPTC section found + + // Skip header + unsigned char headerLen = *pos++; // get header length and move data pointer to the next field + pos += headerLen + 1 - (headerLen % 2); // move data pointer to the next field (Header is padded to even length, counting the length byte) + + // Get length (Motorola format) + unsigned long length = CExifParse::Get32(pos); + pos += sizeof(long); // move data pointer to the next field + + // Now read IPTC data + while (pos < (char*)(Data + itemlen-5)) + { + short signature = (*pos << 8) + (*(pos+1)); + + pos += sizeof(short); + if (signature != 0x1C02) + break; + + unsigned char type = *pos++; + unsigned short length = (*pos << 8) + (*(pos+1)); + pos += sizeof(short); // Skip tag length + // Process tag here + char *tag = NULL; + switch (type) + { + case IPTC_SUPLEMENTAL_CATEGORIES: tag = info->SupplementalCategories; break; + case IPTC_KEYWORDS: tag = info->Keywords; break; + case IPTC_CAPTION: tag = info->Caption; break; + case IPTC_AUTHOR: tag = info->Author; break; + case IPTC_HEADLINE: tag = info->Headline; break; + case IPTC_SPECIAL_INSTRUCTIONS: tag = info->SpecialInstructions; break; + case IPTC_CATEGORY: tag = info->Category; break; + case IPTC_BYLINE: tag = info->Byline; break; + case IPTC_BYLINE_TITLE: tag = info->BylineTitle; break; + case IPTC_CREDIT: tag = info->Credit; break; + case IPTC_SOURCE: tag = info->Source; break; + case IPTC_COPYRIGHT_NOTICE: tag = info->CopyrightNotice; break; + case IPTC_OBJECT_NAME: tag = info->ObjectName; break; + case IPTC_CITY: tag = info->City; break; + case IPTC_STATE: tag = info->State; break; + case IPTC_COUNTRY: tag = info->Country; break; + case IPTC_TRANSMISSION_REFERENCE: tag = info->TransmissionReference; break; + case IPTC_DATE: tag = info->Date; break; + case IPTC_COPYRIGHT: tag = info->Copyright; break; + case IPTC_REFERENCE_SERVICE: tag = info->ReferenceService; break; + case IPTC_COUNTRY_CODE: tag = info->CountryCode; break; + default: + printf("IptcParse: Unrecognised IPTC tag: 0x%02x", type); + break; + } + + if (tag) + { + if (type != IPTC_KEYWORDS || *tag == 0) + { + strncpy(tag, pos, min(length, MAX_IPTC_STRING - 1)); + tag[min(length, MAX_IPTC_STRING - 1)] = 0; + } + else if (type == IPTC_KEYWORDS) + { + // there may be multiple keywords - lets join them + size_t maxLen = MAX_IPTC_STRING - strlen(tag); + if (maxLen > 2) + strcat(tag, ", "); + strncat(tag, pos, min(length, MAX_IPTC_STRING - maxLen - 3)); + } +/* if (id == SLIDE_IPTC_CAPTION) + { + CExifParse::FixComment(m_IptcInfo[id]); // Ensure comment is printable + }*/ + } + pos += length; + } + return true; +} + diff --git a/lib/libexif/IptcParse.h b/lib/libexif/IptcParse.h new file mode 100644 index 0000000000..e175ef769f --- /dev/null +++ b/lib/libexif/IptcParse.h @@ -0,0 +1,12 @@ +#ifndef __IPTC_PARSE_H +#define __IPTC_PARSE_H + +#include "libexif.h" + +class CIptcParse +{ + public: + static bool Process(const unsigned char* const Data, const unsigned short length, IPTCInfo_t *info); +}; + +#endif // __IPTC_H diff --git a/lib/libexif/JpegParse.cpp b/lib/libexif/JpegParse.cpp new file mode 100644 index 0000000000..87f0d6296b --- /dev/null +++ b/lib/libexif/JpegParse.cpp @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2005-2007 Team XboxMediaCenter + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +//-------------------------------------------------------------------------- +// This module gathers information about a digital image file. This includes: +// - File name and path +// - File size +// - Resolution (if available) +// - IPTC information (if available) +// - EXIF information (if available) +// All gathered information is stored in a vector of 'description' and 'value' +// pairs (where both description and value fields are of CStdString types). +//-------------------------------------------------------------------------- + +#ifndef _LINUX +#include <windows.h> +#else +#include <memory.h> +#define min(a,b) (a)>(b)?(b):(a) +typedef unsigned char BYTE; +#endif +#include "JpegParse.h" + + + +//-------------------------------------------------------------------------- +#define JPEG_PARSE_STRING_ID_BASE 21500 +enum { + ProcessUnknown = JPEG_PARSE_STRING_ID_BASE, + ProcessSof0, + ProcessSof1, + ProcessSof2, + ProcessSof3, + ProcessSof5, + ProcessSof6, + ProcessSof7, + ProcessSof9, + ProcessSof10, + ProcessSof11, + ProcessSof13, + ProcessSof14, + ProcessSof15, +}; + + + + +//-------------------------------------------------------------------------- +// Constructor +//-------------------------------------------------------------------------- +CJpegParse::CJpegParse(): + m_SectionBuffer(NULL) +{ + memset(&m_ExifInfo, 0, sizeof(m_ExifInfo)); + memset(&m_IPTCInfo, 0, sizeof(m_IPTCInfo)); +} + +//-------------------------------------------------------------------------- +// Process a SOFn marker. This is useful for the image dimensions +//-------------------------------------------------------------------------- +void CJpegParse::ProcessSOFn (void) +{ + m_ExifInfo.Height = CExifParse::Get16(m_SectionBuffer+3); + m_ExifInfo.Width = CExifParse::Get16(m_SectionBuffer+5); + + unsigned char num_components = m_SectionBuffer[7]; + if (num_components != 3) + { + m_ExifInfo.IsColor = 0; + } + else + { + m_ExifInfo.IsColor = 1; + } +} + + +//-------------------------------------------------------------------------- +// Read a section from a JPEG file. Note that this function allocates memory. +// It must be called in pair with ReleaseSection +//-------------------------------------------------------------------------- +bool CJpegParse::GetSection (FILE *infile, const unsigned short sectionLength) +{ + m_SectionBuffer = new unsigned char[sectionLength]; + if (m_SectionBuffer == NULL) + { + printf("JpgParse: could not allocate memory"); + return false; + } + // Store first two pre-read bytes. + m_SectionBuffer[0] = (unsigned char)(sectionLength >> 8); + m_SectionBuffer[1] = (unsigned char)(sectionLength && 0x00FF); + + unsigned int len = (unsigned int)sectionLength; + + size_t bytesRead = fread(m_SectionBuffer+sizeof(sectionLength), 1, len-sizeof(sectionLength), infile); + if (bytesRead != sectionLength-sizeof(sectionLength)) + { + printf("JpgParse: premature end of file?"); + ReleaseSection(); + return false; + } + return true; +} + +//-------------------------------------------------------------------------- +// Deallocate memory allocated in GetSection. This function must always +// be paired by a preceeding GetSection call. +//-------------------------------------------------------------------------- +void CJpegParse::ReleaseSection (void) +{ + delete[] m_SectionBuffer; + m_SectionBuffer = NULL; +} + +//-------------------------------------------------------------------------- +// Parse the marker stream until SOS or EOI is seen; infile has already been +// successfully open +//-------------------------------------------------------------------------- +bool CJpegParse::ExtractInfo (FILE *infile) +{ + // Get file marker (two bytes - must be 0xFFD8 for JPEG files + BYTE a; + size_t bytesRead = fread(&a, 1, sizeof(BYTE), infile); + if ((bytesRead != sizeof(BYTE)) || (a != 0xFF)) + { + return false; + } + bytesRead = fread(&a, 1, sizeof(BYTE), infile); + if ((bytesRead != sizeof(BYTE)) || (a != M_SOI)) + { + return false; + } + + for(;;) + { + BYTE marker = 0; + for (a=0; a<7; a++) { + bytesRead = fread(&marker, 1, sizeof(BYTE), infile); + if (marker != 0xFF) + break; + + if (a >= 6) + { + printf("JpgParse: too many padding bytes"); + return false; + } + marker = 0; + } + + if (marker == 0xff) + { + // 0xff is legal padding, but if we get that many, something's wrong. + printf("JpgParse: too many padding bytes"); + return false; + } + + // Read the length of the section. + unsigned short itemlen = 0; + bytesRead = fread(&itemlen, 1, sizeof(itemlen), infile); + itemlen = CExifParse::Get16(&itemlen); + + if ((bytesRead != sizeof(itemlen)) || (itemlen < sizeof(itemlen))) + { + printf("JpgParse: invalid marker"); + return false; + } + + switch(marker) + { + case M_SOS: // stop before hitting compressed data + return true; + + case M_EOI: // in case it's a tables-only JPEG stream + printf("JpgParse: No image in jpeg!"); + return false; + break; + + case M_COM: // Comment section + GetSection(infile, itemlen); + if (m_SectionBuffer != NULL) + { + // CExifParse::FixComment(comment); // Ensure comment is printable + strncpy(m_ExifInfo.Comments, (char *)&m_SectionBuffer[2], min(itemlen-2, MAX_COMMENT)); + } + ReleaseSection(); + break; + + case M_SOF0: + case M_SOF1: + case M_SOF2: + case M_SOF3: + case M_SOF5: + case M_SOF6: + case M_SOF7: + case M_SOF9: + case M_SOF10: + case M_SOF11: + case M_SOF13: + case M_SOF14: + case M_SOF15: + GetSection(infile, itemlen); + if ((m_SectionBuffer != NULL) && (itemlen >= 7)) + { + ProcessSOFn(); + m_ExifInfo.Process = marker; + } + ReleaseSection(); + break; + + case M_IPTC: + GetSection(infile, itemlen); + if (m_SectionBuffer != NULL) + { + CIptcParse::Process(m_SectionBuffer, itemlen, &m_IPTCInfo); + } + ReleaseSection(); + break; + + case M_EXIF: + // Seen files from some 'U-lead' software with Vivitar scanner + // that uses marker 31 for non exif stuff. Thus make sure + // it says 'Exif' in the section before treating it as exif. + GetSection(infile, itemlen); + if (m_SectionBuffer != NULL) + { + CExifParse exif; + exif.Process(m_SectionBuffer, itemlen, &m_ExifInfo); + } + ReleaseSection(); + break; + + case M_JFIF: + // Regular jpegs always have this tag, exif images have the exif + // marker instead, althogh ACDsee will write images with both markers. + // this program will re-create this marker on absence of exif marker. + // hence no need to keep the copy from the file. + // fall through to default case + default: + // Skip any other sections. + GetSection(infile, itemlen); + ReleaseSection(); + break; + } + } + return true; +} + +//-------------------------------------------------------------------------- +// Process a file. Check if it is JPEG. Extract exif/iptc info if it is. +//-------------------------------------------------------------------------- +bool CJpegParse::Process (const char *picFileName) +{ + FILE *file; + + file = fopen(picFileName, "rb"); + if (!file) + return false; + + // File exists and successfully opened. Start processing + // Gather all information about the file + +/* // Get file name... + CStdString tmp, urlFName, path; + CURL url(picFileName); + url.GetURLWithoutUserDetails(urlFName); + CUtil::Split(urlFName, path, tmp); + m_JpegInfo[SLIDE_FILE_NAME] = tmp; + // ...then path... + m_JpegInfo[SLIDE_FILE_PATH] = path; + + // ...then size... + __stat64 fileStat; + CFile::Stat(picFileName, &fileStat); + float fileSize = (float)fileStat.st_size; + tmp = ""; + if (fileSize > 1024) + { + fileSize /= 1024; + tmp = "KB"; + } + if (fileSize > 1024) + { + fileSize /= 1024; + tmp = "MB"; + } + if (fileSize > 1024) + { + fileSize /= 1024; + tmp = "GB"; + } + tmp.Format("%.2f %s", fileSize, tmp); + m_JpegInfo[SLIDE_FILE_SIZE] = tmp; + + // ...then date and time... + CDateTime date((time_t)fileStat.st_mtime); + tmp.Format("%s %s", date.GetAsLocalizedDate(), date.GetAsLocalizedTime()); + m_JpegInfo[SLIDE_FILE_DATE] = tmp;*/ + + bool result = ExtractInfo(file); + fclose(file); + if (result == false) + printf("JpgParse: Not a JPEG file %s", picFileName); + return result; +} + diff --git a/lib/libexif/JpegParse.h b/lib/libexif/JpegParse.h new file mode 100644 index 0000000000..1e9eeeb764 --- /dev/null +++ b/lib/libexif/JpegParse.h @@ -0,0 +1,57 @@ +#pragma once + +#include "IptcParse.h" +#include "ExifParse.h" +#include "stdio.h" + +//-------------------------------------------------------------------------- +// JPEG markers consist of one or more 0xFF bytes, followed by a marker +// code byte (which is not an FF). Here are the marker codes of interest +// in this application. +//-------------------------------------------------------------------------- + +#define M_SOF0 0xC0 // Start Of Frame N +#define M_SOF1 0xC1 // N indicates which compression process +#define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use +#define M_SOF3 0xC3 +#define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers +#define M_SOF6 0xC6 +#define M_SOF7 0xC7 +#define M_SOF9 0xC9 +#define M_SOF10 0xCA +#define M_SOF11 0xCB +#define M_SOF13 0xCD +#define M_SOF14 0xCE +#define M_SOF15 0xCF +#define M_SOI 0xD8 // Start Of Image (beginning of datastream) +#define M_EOI 0xD9 // End Of Image (end of datastream) +#define M_SOS 0xDA // Start Of Scan (begins compressed data) +#define M_JFIF 0xE0 // Jfif marker +#define M_EXIF 0xE1 // Exif marker +#define M_COM 0xFE // COMment +#define M_DQT 0xDB +#define M_DHT 0xC4 +#define M_DRI 0xDD +#define M_IPTC 0xED // IPTC marker + + +class CJpegParse +{ + public: + CJpegParse (); + ~CJpegParse (void) {} + bool Process (const char *picFileName); + const ExifInfo_t * GetExifInfo() const { return &m_ExifInfo; }; + const IPTCInfo_t * GetIptcInfo() const { return &m_IPTCInfo; }; + + private: + bool ExtractInfo (FILE *infile); + bool GetSection (FILE *infile, const unsigned short sectionLength); + void ReleaseSection (void); + void ProcessSOFn (void); + + unsigned char* m_SectionBuffer; + ExifInfo_t m_ExifInfo; + IPTCInfo_t m_IPTCInfo; +}; + diff --git a/lib/libexif/Makefile.in b/lib/libexif/Makefile.in new file mode 100644 index 0000000000..7e3d3e9dbf --- /dev/null +++ b/lib/libexif/Makefile.in @@ -0,0 +1,20 @@ +ARCH=@ARCH@ + +OBJS +=libexif.o ExifParse.o IptcParse.o JpegParse.o +CFLAGS +=-D_LINUX -D_DLL -fPIC -O2 +CXXFLAGS +=-D_LINUX -D_DLL -fPIC -O2 + +SYSDIR=@abs_top_srcdir@/system +SO=libexif-$(ARCH).so +SLIB=@abs_top_srcdir@/system/$(SO) + +$(SLIB): $(OBJS) +ifeq ($(findstring osx,$(ARCH)), osx) + $(CXX) $(CFLAGS) -bundle -flat_namespace -undefined suppress -shared -fPIC -o $@ $(OBJS) + @abs_top_srcdir@/tools/Mach5/wrapper.rb $@;mv output.so $@ +else + $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared -o $@ $(OBJS) \ + `cat @abs_top_srcdir@/xbmc/cores/DllLoader/exports/wrapper.def` @abs_top_srcdir@/xbmc/cores/DllLoader/exports/wrapper.o +endif + +include @abs_top_srcdir@/Makefile.include diff --git a/lib/libexif/libexif.cpp b/lib/libexif/libexif.cpp new file mode 100644 index 0000000000..12e298c304 --- /dev/null +++ b/lib/libexif/libexif.cpp @@ -0,0 +1,42 @@ +// libexif.cpp : Defines the entry point for the console application. +// + +#ifndef _LINUX +#include <windows.h> +#else +#include <memory.h> +#endif +#include "JpegParse.h" +#include "libexif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool process_jpeg(const char *filename, ExifInfo_t *exifInfo, IPTCInfo_t *iptcInfo) +{ + if (!exifInfo || !iptcInfo) return false; + CJpegParse jpeg; + memset(exifInfo, 0, sizeof(ExifInfo_t)); + memset(iptcInfo, 0, sizeof(IPTCInfo_t)); + if (jpeg.Process(filename)) + { + memcpy(exifInfo, jpeg.GetExifInfo(), sizeof(ExifInfo_t)); + memcpy(iptcInfo, jpeg.GetIptcInfo(), sizeof(IPTCInfo_t)); + return true; + } + return false; +} +#ifdef __cplusplus +} +#endif + +#ifndef _DLL +int main(int argc, char* argv[]) +{ + ExifInfo_t exifInfo; + IPTCInfo_t iptcInfo; + process_jpeg("C:\\Documents and Settings\\jcmarsha\\My Documents\\My Pictures\\396179226_f09242e21e_o.jpg", &exifInfo, &iptcInfo); + return 0; +} +#endif diff --git a/lib/libexif/libexif.h b/lib/libexif/libexif.h new file mode 100644 index 0000000000..e889892a73 --- /dev/null +++ b/lib/libexif/libexif.h @@ -0,0 +1,126 @@ +#ifndef HAS_LIBEXIF_H +#define HAS_LIBEXIF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _DLL +#ifdef WIN32 +#define EXIF_EXPORT __declspec(dllexport) +#else +#define EXIF_EXPORT +#endif +#else +#define EXIF_EXPORT +#endif + +//-------------------------------------------------------------------------- +// JPEG markers consist of one or more 0xFF bytes, followed by a marker +// code byte (which is not an FF). Here are the marker codes of interest +// in this application. +//-------------------------------------------------------------------------- + +#define M_SOF0 0xC0 // Start Of Frame N +#define M_SOF1 0xC1 // N indicates which compression process +#define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use +#define M_SOF3 0xC3 +#define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers +#define M_SOF6 0xC6 +#define M_SOF7 0xC7 +#define M_SOF9 0xC9 +#define M_SOF10 0xCA +#define M_SOF11 0xCB +#define M_SOF13 0xCD +#define M_SOF14 0xCE +#define M_SOF15 0xCF +#define M_SOI 0xD8 // Start Of Image (beginning of datastream) +#define M_EOI 0xD9 // End Of Image (end of datastream) +#define M_SOS 0xDA // Start Of Scan (begins compressed data) +#define M_JFIF 0xE0 // Jfif marker +#define M_EXIF 0xE1 // Exif marker +#define M_COM 0xFE // COMment +#define M_DQT 0xDB +#define M_DHT 0xC4 +#define M_DRI 0xDD +#define M_IPTC 0xED // IPTC marker + +#define MAX_IPTC_STRING 256 + +typedef struct { + char SupplementalCategories[MAX_IPTC_STRING]; + char Keywords[MAX_IPTC_STRING]; + char Caption[MAX_IPTC_STRING]; + char Author[MAX_IPTC_STRING]; + char Headline[MAX_IPTC_STRING]; + char SpecialInstructions[MAX_IPTC_STRING]; + char Category[MAX_IPTC_STRING]; + char Byline[MAX_IPTC_STRING]; + char BylineTitle[MAX_IPTC_STRING]; + char Credit[MAX_IPTC_STRING]; + char Source[MAX_IPTC_STRING]; + char CopyrightNotice[MAX_IPTC_STRING]; + char ObjectName[MAX_IPTC_STRING]; + char City[MAX_IPTC_STRING]; + char State[MAX_IPTC_STRING]; + char Country[MAX_IPTC_STRING]; + char TransmissionReference[MAX_IPTC_STRING]; + char Date[MAX_IPTC_STRING]; + char Copyright[MAX_IPTC_STRING]; + char ReferenceService[MAX_IPTC_STRING]; + char CountryCode[MAX_IPTC_STRING]; +} IPTCInfo_t; + +#define MAX_COMMENT 2000 +#define MAX_DATE_COPIES 10 + +typedef struct { + char CameraMake [32]; + char CameraModel [40]; + char DateTime [20]; + int Height, Width; + int Orientation; + int IsColor; + int Process; + int FlashUsed; + float FocalLength; + float ExposureTime; + float ApertureFNumber; + float Distance; + float CCDWidth; + float ExposureBias; + float DigitalZoomRatio; + int FocalLength35mmEquiv; // Exif 2.2 tag - usually not present. + int Whitebalance; + int MeteringMode; + int ExposureProgram; + int ExposureMode; + int ISOequivalent; + int LightSource; + char Comments[MAX_COMMENT]; + + unsigned ThumbnailOffset; // Exif offset to thumbnail + unsigned ThumbnailSize; // Size of thumbnail. + unsigned LargestExifOffset; // Last exif data referenced (to check if thumbnail is at end) + + char ThumbnailAtEnd; // Exif header ends with the thumbnail + // (we can only modify the thumbnail if its at the end) + int ThumbnailSizeOffset; + + int DateTimeOffsets[MAX_DATE_COPIES]; + int numDateTimeTags; + + int GpsInfoPresent; + char GpsLat[31]; + char GpsLong[31]; + char GpsAlt[20]; +} ExifInfo_t; + +EXIF_EXPORT bool process_jpeg(const char *filename, ExifInfo_t *exifInfo, IPTCInfo_t *iptcInfo); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/lib/libexif/libexif.sln b/lib/libexif/libexif.sln new file mode 100644 index 0000000000..4c85df300a --- /dev/null +++ b/lib/libexif/libexif.sln @@ -0,0 +1,24 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libexif", "libexif.vcproj", "{AD20A3E2-09CB-42DB-9A70-27F7CDC886CE}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + Release (DLL) = Release (DLL) + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {AD20A3E2-09CB-42DB-9A70-27F7CDC886CE}.Debug.ActiveCfg = Debug|Win32 + {AD20A3E2-09CB-42DB-9A70-27F7CDC886CE}.Debug.Build.0 = Debug|Win32 + {AD20A3E2-09CB-42DB-9A70-27F7CDC886CE}.Release.ActiveCfg = Release|Win32 + {AD20A3E2-09CB-42DB-9A70-27F7CDC886CE}.Release.Build.0 = Release|Win32 + {AD20A3E2-09CB-42DB-9A70-27F7CDC886CE}.Release (DLL).ActiveCfg = Release (DLL)|Win32 + {AD20A3E2-09CB-42DB-9A70-27F7CDC886CE}.Release (DLL).Build.0 = Release (DLL)|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/lib/libexif/libexif.vcproj b/lib/libexif/libexif.vcproj new file mode 100644 index 0000000000..90eaac7fb5 --- /dev/null +++ b/lib/libexif/libexif.vcproj @@ -0,0 +1,303 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9,00" + Name="libexif_dll" + ProjectGUID="{AD20A3E2-09CB-42DB-9A70-27F7CDC886CE}" + RootNamespace="libexif_dll" + Keyword="Win32Proj" + TargetFrameworkVersion="131072" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)libs\$(ProjectName)\$(ConfigurationName)\" + IntermediateDirectory="$(SolutionDir)objs\$(ProjectName)\$(ConfigurationName)\" + ConfigurationType="1" + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + CharacterSet="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="1" + UsePrecompiledHeader="0" + WarningLevel="3" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + OutputFile="$(OutDir)/libexif.exe" + LinkIncremental="2" + GenerateDebugInformation="true" + ProgramDatabaseFile="$(OutDir)/libexif.pdb" + SubSystem="1" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)libs\$(ProjectName)\$(ConfigurationName)\" + IntermediateDirectory="$(SolutionDir)objs\$(ProjectName)\$(ConfigurationName)\" + ConfigurationType="1" + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + CharacterSet="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS" + RuntimeLibrary="0" + UsePrecompiledHeader="0" + WarningLevel="3" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + OutputFile="$(OutDir)/libexif.exe" + LinkIncremental="1" + GenerateDebugInformation="true" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release (DLL)|Win32" + OutputDirectory="$(SolutionDir)libs\$(ProjectName)\$(ConfigurationName)\" + IntermediateDirectory="$(SolutionDir)objs\$(ProjectName)\$(ConfigurationName)\" + ConfigurationType="2" + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + CharacterSet="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_DLL;_CRT_SECURE_NO_WARNINGS" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + OutputFile="..\..\..\system\libexif.dll" + LinkIncremental="1" + GenerateDebugInformation="true" + ProgramDatabaseFile="$(TargetName).pdb" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + ProfileGuidedDatabase="" + RandomizedBaseAddress="2" + DataExecutionPrevention="0" + ImportLibrary="$(TargetName).lib" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath=".\ExifParse.cpp" + > + </File> + <File + RelativePath=".\ExifParse.h" + > + </File> + <File + RelativePath=".\IptcParse.cpp" + > + </File> + <File + RelativePath=".\IptcParse.h" + > + </File> + <File + RelativePath=".\JpegParse.cpp" + > + </File> + <File + RelativePath=".\JpegParse.h" + > + </File> + <File + RelativePath=".\libexif.cpp" + > + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + </Filter> + <File + RelativePath=".\ReadMe.txt" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/lib/libexif/libexif.vcxproj b/lib/libexif/libexif.vcxproj new file mode 100644 index 0000000000..cd65ac93c8 --- /dev/null +++ b/lib/libexif/libexif.vcxproj @@ -0,0 +1,174 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release (DLL)|Win32"> + <Configuration>Release (DLL)</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>libexif_dll</ProjectName> + <ProjectGuid>{AD20A3E2-09CB-42DB-9A70-27F7CDC886CE}</ProjectGuid> + <RootNamespace>libexif_dll</RootNamespace> + <Keyword>Win32Proj</Keyword> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release (DLL)|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release (DLL)|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" /> + <Import Project="..\..\project\VS2010Express\XBMC for Windows.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" /> + <Import Project="..\..\project\VS2010Express\XBMC for Windows.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" /> + <Import Project="..\..\project\VS2010Express\XBMC for Windows.props" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup> + <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)libs\$(TargetName)\$(Configuration)\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)objs\$(TargetName)\$(Configuration)\</IntDir> + <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)libs\$(TargetName)\$(Configuration)\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)objs\$(TargetName)\$(Configuration)\</IntDir> + <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental> + <OutDir Condition="'$(Configuration)|$(Platform)'=='Release (DLL)|Win32'">$(SolutionDir)libs\$(TargetName)\$(Configuration)\</OutDir> + <IntDir Condition="'$(Configuration)|$(Platform)'=='Release (DLL)|Win32'">$(SolutionDir)objs\$(TargetName)\$(Configuration)\</IntDir> + <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release (DLL)|Win32'">false</LinkIncremental> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Release (DLL)|Win32'">libexif</TargetName> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">libexif</TargetName> + <CustomBuildAfterTargets Condition="'$(Configuration)|$(Platform)'=='Release (DLL)|Win32'">Build</CustomBuildAfterTargets> + <TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.dll</TargetExt> + <TargetExt Condition="'$(Configuration)|$(Platform)'=='Release (DLL)|Win32'">.dll</TargetExt> + <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">libexif</TargetName> + <TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.dll</TargetExt> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <MinimalRebuild>true</MinimalRebuild> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>EditAndContinue</DebugInformationFormat> + </ClCompile> + <Link> + <OutputFile>$(OutDir)libexif.exe</OutputFile> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ProgramDatabaseFile>$(OutDir)libexif.pdb</ProgramDatabaseFile> + <SubSystem>Console</SubSystem> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <DataExecutionPrevention> + </DataExecutionPrevention> + <TargetMachine>MachineX86</TargetMachine> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + </ClCompile> + <Link> + <OutputFile>$(OutDir)libexif.exe</OutputFile> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Console</SubSystem> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <DataExecutionPrevention> + </DataExecutionPrevention> + <TargetMachine>MachineX86</TargetMachine> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release (DLL)|Win32'"> + <ClCompile> + <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + </ClCompile> + <Link> + <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ProgramDatabaseFile>$(TargetName).pdb</ProgramDatabaseFile> + <SubSystem>Console</SubSystem> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <ProfileGuidedDatabase> + </ProfileGuidedDatabase> + <RandomizedBaseAddress>true</RandomizedBaseAddress> + <DataExecutionPrevention> + </DataExecutionPrevention> + <ImportLibrary>$(TargetName).lib</ImportLibrary> + <TargetMachine>MachineX86</TargetMachine> + </Link> + <PostBuildEvent> + <Command> + </Command> + </PostBuildEvent> + <CustomBuildStep> + <Command>copy /B /Y "$(TargetPath)" "$(SolutionDir)..\..\system\$(TargetFileName)"</Command> + </CustomBuildStep> + <CustomBuildStep> + <Message>Copy output</Message> + </CustomBuildStep> + <CustomBuildStep> + <Outputs>$(SolutionDir)..\..\system\$(TargetFileName)</Outputs> + <Inputs>$(TargetPath)</Inputs> + </CustomBuildStep> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="ExifParse.cpp" /> + <ClCompile Include="IptcParse.cpp" /> + <ClCompile Include="JpegParse.cpp" /> + <ClCompile Include="libexif.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="ExifParse.h" /> + <ClInclude Include="IptcParse.h" /> + <ClInclude Include="JpegParse.h" /> + </ItemGroup> + <ItemGroup> + <None Include="ReadMe.txt" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/lib/libexif/libexif.vcxproj.filters b/lib/libexif/libexif.vcxproj.filters new file mode 100644 index 0000000000..5ca80ed9aa --- /dev/null +++ b/lib/libexif/libexif.vcxproj.filters @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="ExifParse.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="IptcParse.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="JpegParse.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="libexif.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="ExifParse.h"> + <Filter>Source Files</Filter> + </ClInclude> + <ClInclude Include="IptcParse.h"> + <Filter>Source Files</Filter> + </ClInclude> + <ClInclude Include="JpegParse.h"> + <Filter>Source Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <None Include="ReadMe.txt" /> + </ItemGroup> +</Project>
\ No newline at end of file |