diff --git a/wrap/Exif/Readme.txt b/wrap/Exif/Readme.txt deleted file mode 100644 index 0ea5e049..00000000 --- a/wrap/Exif/Readme.txt +++ /dev/null @@ -1,13 +0,0 @@ -How to read exif metadata from a jpg file. - = = = = = = = = = = = = = = = = = = = = = - -1- In your .pro file, define the EXIF_DIR variable which locates the Exif directory in your system, and include the exif.pri file -e.g. - EXIF_DIR = ./yourSandboxPath/Exif - include($$EXIF_DIR/exif.pri) - -2- In your source file (where you need the exif reader), add: - #include "jhead.h" -Then, invoke: - ::ProcessFile(filename); -and get the available exif information from the "ImageInfo" global variable of type ImageInfo_t, defined in jhead.h. diff --git a/wrap/Exif/exif.pri b/wrap/Exif/exif.pri deleted file mode 100644 index 802f0ad8..00000000 --- a/wrap/Exif/exif.pri +++ /dev/null @@ -1,16 +0,0 @@ -#Please define the EXIF_DIR variable which locates the glUtils directory in your system. -#eg. EXIF_DIR = ../vcglib/wrap/Exif - -!contains(DEFINES, EXIF_DIR){ - DEFINES += EXIF_DIR - - INCLUDEPATH += $$EXIF_DIR/include - SOURCES += $$EXIF_DIR/src/exif.cpp - SOURCES += $$EXIF_DIR/src/gpsinfo.cpp - SOURCES += $$EXIF_DIR/src/iptc.cpp - SOURCES += $$EXIF_DIR/src/jhead.cpp - SOURCES += $$EXIF_DIR/src/jpgfile.cpp - SOURCES += $$EXIF_DIR/src/makernote.cpp - win32:SOURCES += $$EXIF_DIR/src/myglob.cpp - SOURCES += $$EXIF_DIR/src/paths.cpp -} diff --git a/wrap/Exif/include/Exif/exif.h b/wrap/Exif/include/Exif/exif.h deleted file mode 100644 index d9799751..00000000 --- a/wrap/Exif/include/Exif/exif.h +++ /dev/null @@ -1,915 +0,0 @@ -#ifndef EXIF_H -#define EXIF_H - -#include -#include -using namespace std; - -template -class Exif{ -public: - Exif(){ - sections.resize(0); - motorolaOrder = false; - } - - bool readJPEG(const char *filename){ - FILE *fp = fopen(filename, "rb"); // Unix ignores 'b', windows needs it. - //parse the marker stream until SOS or EOI is seen - if(!fp || !readJpegSections(fp)) return false; - fclose(fp); - return true; - } - - //Compute the CCD width, in millimeters - // 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 Jhad can do about it - its a camera problem. - T CCDwidthMm() const { - if(!FocalplaneXRes) return -1; - return T(ExifImageWidth * FocalplaneUnits / FocalplaneXRes); - } - - // Compute 35 mm equivalent focal length based on sensor geometry if we haven't - // already got it explicitly from a tag. - T FocalLength35mmEquiv() const { - if( intrinsics.FocalMm && !FocalLength35mmEquiv ) - FocalLength35mmEquiv = T(ImageInfo.FocalLength/ImageInfo.CCDWidth*36 + 0.5); - return FocalLength35mmEquiv; - } - - vcg::Camera vcgCamera() const { - vcg::Camera intrinsics; - return intrinsics; - } - -private: -// 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 program. -#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. Also used for XMP data! -#define M_XMP 0x10E1 // Not a real tag (same value in file as Exif!) -#define M_COM 0xFE // COMment -#define M_DQT 0xDB -#define M_DHT 0xC4 -#define M_DRI 0xDD -#define M_IPTC 0xED // IPTC marker - -// Exif format descriptor stuff -#define MAX_DATE_COPIES 10 -#ifdef _WIN32 - #define PATH_MAX _MAX_PATH - #define SLASH '\\' -#else - #define SLASH '/' -#endif -const int *BytesPerFormat; -#define NUM_FORMATS 12 -#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 - -// Describes tag values -#define TAG_INTEROP_INDEX 0x0001 -#define TAG_INTEROP_VERSION 0x0002 -#define TAG_IMAGE_WIDTH 0x0100 -#define TAG_IMAGE_LENGTH 0x0101 -#define TAG_BITS_PER_SAMPLE 0x0102 -#define TAG_COMPRESSION 0x0103 -#define TAG_PHOTOMETRIC_INTERP 0x0106 -#define TAG_FILL_ORDER 0x010A -#define TAG_DOCUMENT_NAME 0x010D -#define TAG_IMAGE_DESCRIPTION 0x010E -#define TAG_MAKE 0x010F -#define TAG_MODEL 0x0110 -#define TAG_SRIP_OFFSET 0x0111 -#define TAG_ORIENTATION 0x0112 -#define TAG_SAMPLES_PER_PIXEL 0x0115 -#define TAG_ROWS_PER_STRIP 0x0116 -#define TAG_STRIP_BYTE_COUNTS 0x0117 -#define TAG_X_RESOLUTION 0x011A -#define TAG_Y_RESOLUTION 0x011B -#define TAG_PLANAR_CONFIGURATION 0x011C -#define TAG_RESOLUTION_UNIT 0x0128 -#define TAG_TRANSFER_FUNCTION 0x012D -#define TAG_SOFTWARE 0x0131 -#define TAG_DATETIME 0x0132 -#define TAG_ARTIST 0x013B -#define TAG_WHITE_POINT 0x013E -#define TAG_PRIMARY_CHROMATICITIES 0x013F -#define TAG_TRANSFER_RANGE 0x0156 -#define TAG_JPEG_PROC 0x0200 -#define TAG_THUMBNAIL_OFFSET 0x0201 -#define TAG_THUMBNAIL_LENGTH 0x0202 -#define TAG_Y_CB_CR_COEFFICIENTS 0x0211 -#define TAG_Y_CB_CR_SUB_SAMPLING 0x0212 -#define TAG_Y_CB_CR_POSITIONING 0x0213 -#define TAG_REFERENCE_BLACK_WHITE 0x0214 -#define TAG_RELATED_IMAGE_WIDTH 0x1001 -#define TAG_RELATED_IMAGE_LENGTH 0x1002 -#define TAG_CFA_REPEAT_PATTERN_DIM 0x828D -#define TAG_CFA_PATTERN1 0x828E -#define TAG_BATTERY_LEVEL 0x828F -#define TAG_COPYRIGHT 0x8298 -#define TAG_EXPOSURETIME 0x829A -#define TAG_FNUMBER 0x829D -#define TAG_IPTC_NAA 0x83BB -#define TAG_EXIF_OFFSET 0x8769 -#define TAG_INTER_COLOR_PROFILE 0x8773 -#define TAG_EXPOSURE_PROGRAM 0x8822 -#define TAG_SPECTRAL_SENSITIVITY 0x8824 -#define TAG_GPSINFO 0x8825 -#define TAG_ISO_EQUIVALENT 0x8827 -#define TAG_OECF 0x8828 -#define TAG_EXIF_VERSION 0x9000 -#define TAG_DATETIME_ORIGINAL 0x9003 -#define TAG_DATETIME_DIGITIZED 0x9004 -#define TAG_COMPONENTS_CONFIG 0x9101 -#define TAG_CPRS_BITS_PER_PIXEL 0x9102 -#define TAG_SHUTTERSPEED 0x9201 -#define TAG_APERTURE 0x9202 -#define TAG_BRIGHTNESS_VALUE 0x9203 -#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 -#define TAG_USERCOMMENT 0x9286 -#define TAG_SUBSEC_TIME 0x9290 -#define TAG_SUBSEC_TIME_ORIG 0x9291 -#define TAG_SUBSEC_TIME_DIG 0x9292 -#define TAG_WINXP_TITLE 0x9c9b // Windows XP - not part of exif standard. -#define TAG_WINXP_COMMENT 0x9c9c // Windows XP - not part of exif standard. -#define TAG_WINXP_AUTHOR 0x9c9d // Windows XP - not part of exif standard. -#define TAG_WINXP_KEYWORDS 0x9c9e // Windows XP - not part of exif standard. -#define TAG_WINXP_SUBJECT 0x9c9f // Windows XP - not part of exif standard. -#define TAG_FLASH_PIX_VERSION 0xA000 -#define TAG_COLOR_SPACE 0xA001 -#define TAG_EXIF_IMAGEWIDTH 0xA002 -#define TAG_EXIF_IMAGELENGTH 0xA003 -#define TAG_RELATED_AUDIO_FILE 0xA004 -#define TAG_INTEROP_OFFSET 0xA005 -#define TAG_FLASH_ENERGY 0xA20B -#define TAG_SPATIAL_FREQ_RESP 0xA20C -#define TAG_FOCAL_PLANE_XRES 0xA20E -#define TAG_FOCAL_PLANE_YRES 0xA20F -#define TAG_FOCAL_PLANE_UNITS 0xA210 -#define TAG_SUBJECT_LOCATION 0xA214 -#define TAG_EXPOSURE_INDEX 0xA215 -#define TAG_SENSING_METHOD 0xA217 -#define TAG_FILE_SOURCE 0xA300 -#define TAG_SCENE_TYPE 0xA301 -#define TAG_CFA_PATTERN 0xA302 -#define TAG_CUSTOM_RENDERED 0xA401 -#define TAG_EXPOSURE_MODE 0xA402 -#define TAG_WHITEBALANCE 0xA403 -#define TAG_DIGITALZOOMRATIO 0xA404 -#define TAG_FOCALLENGTH_35MM 0xA405 -#define TAG_SCENE_CAPTURE_TYPE 0xA406 -#define TAG_GAIN_CONTROL 0xA407 -#define TAG_CONTRAST 0xA408 -#define TAG_SATURATION 0xA409 -#define TAG_SHARPNESS 0xA40A -#define TAG_DISTANCE_RANGE 0xA40C - - typedef unsigned int uint; - typedef unsigned char uchar; - static const uint MAX_COMMENT_SIZE = 2000; - - typedef struct Section{ - int type; - uint size; - uchar *data; - }Section; - vector
sections; - - bool motorolaOrder; - - // This structure stores Exif header image elements in a simple manner - // Used to store camera data as extracted from the various ways that it can be - // stored in an exif header - typedef struct { - char FileName [PATH_MAX+1]; - time_t FileDateTime; - unsigned FileSize; - 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; - int DistanceRange; - - char Comments[MAX_COMMENT_SIZE]; - int CommentWidchars; // If nonzer, widechar comment, indicates number of chars. - - 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]; - }ImageInfo_t; - - ImageInfo_t ImageInfo; - - uchar *DirWithThumbnailPtrs; - T FocalplaneXRes; - T FocalplaneUnits; - int ExifImageWidth; - void * OrientationPtr[2]; - int OrientationNumFormat[2]; - int NumOrientations; - - // Get 16 bits motorola order (always) for jpeg header stuff. - int Get16m(const void *Short){ return (((uchar*)Short)[0] << 8) | ((uchar*)Short)[1]; } - // Convert a 16 bit unsigned value from file's native byte order - int Get16u(void *Short){ - return (motorolaOrder)? - (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1] : - (((uchar *)Short)[1] << 8) | ((uchar *)Short)[0] ; - } - // Convert a 32 bit unsigned value from file's native byte order - unsigned Get32u(void *Long){ return (unsigned)Get32s(Long) & 0xffffffff; } - // Convert a 32 bit signed value from file's native byte order - int Get32s(void * Long){ - return (motorolaOrder)? - ((( char *)Long)[0] << 24) | (((uchar *)Long)[1] << 16) | (((uchar *)Long)[2] << 8 ) | (((uchar *)Long)[3] << 0 ) : - ((( char *)Long)[3] << 24) | (((uchar *)Long)[2] << 16) | (((uchar *)Long)[1] << 8 ) | (((uchar *)Long)[0] << 0 ) ; - } - - // Evaluate number, be it int, rational, or float from directory. - double ConvertAnyFormat(void * ValuePtr, int Format){ - double Value = 0; - - switch(Format){ - case FMT_SBYTE: Value = *(signed char *)ValuePtr; break; - case FMT_BYTE: Value = *(uchar *)ValuePtr; break; - case FMT_USHORT: Value = Get16u(ValuePtr); break; - case FMT_ULONG: Value = Get32u(ValuePtr); break; - case FMT_URATIONAL: - case FMT_SRATIONAL:{ - int Num = Get32s(ValuePtr); - int Den = Get32s(4+(char *)ValuePtr); - Value = (Den == 0)? 0 : double(Num/Den); - break; - } - case FMT_SSHORT: Value = (signed short)Get16u(ValuePtr); break; - case FMT_SLONG: Value = Get32s(ValuePtr); 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: - fprintf(stderr, "Illegal format code %d", Format); - } - - return Value; - } - - bool readJpegSections(FILE *fp){ - //parse the marker stream until SOS or EOI is seen - if(fgetc(fp) != 0xff) return false; - if(fgetc(fp) != M_SOI) return false; - - uint status = 0; - while(!status){ - Section sec; - - int marker = 0; - - for(int i=0 ; i<=16 ; i++){ - marker = fgetc(fp); - if(marker) break; - } - if(!marker){ - fprintf(stderr,"too many padding bytes\n"); - status = 1; - continue; - } -/* - for(int a=0;a<=16;a++){ - marker = fgetc(fp); - if(marker != 0xff) break; - if(a >= 16){ - fprintf(stderr, "too many padding bytes\n"); - status = 1; - continue; - } - } -*/ - sec.type = marker; - - //read the length of the section - int lh = fgetc(fp); - int ll = fgetc(fp); - int itemlen = (lh << 8) | ll; - if(itemlen < 2){ - fprintf(stderr, "invalid marker\n"); - status = 1; - continue; - } - sec.size = itemlen; - - sec.data = (uchar*)malloc(itemlen); - //store first two pre-read bytes - sec.data[0] = (uchar)lh; - sec.data[1] = (uchar)ll; - - int got = fread(sec.data+2, 1, itemlen-2, fp); - if(itemlen-2 != got){ //read the whole section - fprintf(stderr, "Premature end of file?\n"); - status = 1; - continue; - } - - switch(marker){ - case M_SOS: //stop before hitting compressed data - status = 2; - continue; - case M_EOI: //in case it's a tables-only JPEG stream - fprintf(stderr, "No image in jpeg!\n"); - status = 1; - continue; - case M_COM: //comment section - //process_COM(data, itemlen); - 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. - free(sec.data); - sec.data = NULL; - break; - case M_EXIF: - // There can be different section using the same marker. Ignore all but "Exif" one - if(memcmp(sec.data+2, "Exif", 4) == 0){ - if( !process_EXIF(sec.data, itemlen) ) status = 1; - }else // Oterwise, discard this section - free(sec.data); - sec.data = NULL; - break; - case M_IPTC: - 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: - process_SOFn(sec.data, marker); - break; - default: // Skip any other sections - break; - } - } - return (status==2); - } - - /* - Process a COM marker. - we must guard against random junk and varying newline representations. - */ -/* UNUSED - void process_COM(const uchar *data, uint length){ - char Comment[MAX_COMMENT_SIZE+1]; - int nch = 0; - - length = max(length, MAX_COMMENT_SIZE); //truncate if it won't fit in our structure - - for(int a=2 ; a=32) || (ch=='\n') || (ch=='\t') )? char(ch) : '?'; - } - Comment[nch] = '\0'; //null terminate - } -*/ - - // Process exif format directory, as used by Cannon maker note - void ProcessCanonMakerNoteDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength){ - int NumDirEntries; - - NumDirEntries = Get16u(DirStart); - #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry)) - - uchar *DirEnd; - DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries); - if(DirEnd > (OffsetBase+ExifLength)){ - fprintf(stderr, "Illegally sized exif makernote subdir (%d entries)", NumDirEntries); - return; - } - - for(int de=0 ; de= NUM_FORMATS){ - // (-1) catches illegal zero case as unsigned underflows to positive large. - fprintf(stderr, "Illegal number format %d for tag %04x", Format, Tag); - continue; - } - if((unsigned)Components > 0x10000){ - fprintf(stderr, "Illegal number of components %d for tag %04x", Components, Tag); - continue; - } - - ByteCount = Components * BytesPerFormat[Format]; - - if (ByteCount > 4){ - unsigned OffsetVal; - OffsetVal = Get32u(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 - fprintf(stderr, "Illegal value pointer for tag %04x", Tag); - continue; - } - ValuePtr = OffsetBase+OffsetVal; - }else{ - // 4 bytes or less and value is in the dir entry itself - ValuePtr = DirEntry+8; - } - - if( (Tag == 1) && (Components > 16) ){ - int IsoCode = Get16u(ValuePtr + 16*sizeof(unsigned short)); - if( (IsoCode >= 16) && (IsoCode <= 24) ) - ImageInfo.ISOequivalent = 50 << (IsoCode-16); - } - - if( (Tag == 4) && (Format == FMT_USHORT) ){ - if(Components > 7){ - int WhiteBalance = Get16u(ValuePtr + 7*sizeof(unsigned short)); - switch(WhiteBalance){ - // 0=Auto, 6=Custom - case 1: ImageInfo.LightSource = 1; break; // Sunny - case 2: ImageInfo.LightSource = 1; break; // Cloudy - case 3: ImageInfo.LightSource = 3; break; // Thungsten - case 4: ImageInfo.LightSource = 2; break; // Fourescent - case 5: ImageInfo.LightSource = 4; break; // Flash - } - } - if( (Components > 19) && (ImageInfo.Distance <= 0) ){ - // Indicates the distance the autofocus camera is focused to. - // Tends to be less accurate as distance increases. - int temp_dist = Get16u(ValuePtr + 19*sizeof(unsigned short)); - ImageInfo.Distance = (temp_dist != 65535)? (float)temp_dist/100 : -1; - } - } - } - } - - // Process maker note - to the limited extent that its supported. - void ProcessMakerNote(unsigned char * ValuePtr, unsigned char * OffsetBase, unsigned ExifLength){ - if(strstr(ImageInfo.CameraMake, "Canon")) - ProcessCanonMakerNoteDir(ValuePtr, OffsetBase, ExifLength); - } - - /* - Process a SOFn marker. This is useful for the image dimensions - JPEG image is data[7] color components, data[2] bits per sample - */ - void process_SOFn(const uchar *data, int marker){ - //data[2] contains the data precision value - ImageInfo.Height = Get16m(data+3); - ImageInfo.Width = Get16m(data+5); - int num_components = data[7]; - ImageInfo.IsColor = (num_components == 3); - ImageInfo.Process = marker; - } - - /* - Process a EXIF marker. - Describes all the drivel that most digital cameras include... - */ - bool process_EXIF(uchar *ExifSection, uint length){ - FocalplaneXRes = 0; - FocalplaneUnits = 0; - ExifImageWidth = 0; - NumOrientations = 0; - - // Check the EXIF header component - static char *ExifHeader = "Exif\0\0"; - if(memcmp(ExifSection+2, ExifHeader,6)){ - fprintf(stderr, "Incorrect Exif header"); - return false; - } - if(memcmp(ExifSection+8,"II",2) == 0) motorolaOrder = false; //Exif section in Intel order - else if(memcmp(ExifSection+8,"MM",2) == 0) motorolaOrder = true; //Exif section in Motorola order - else{ - fprintf(stderr, "Invalid Exif alignment marker"); - return false; - } - // Check the next value for correctness - if(Get16u(ExifSection+10) != 0x2a){ - fprintf(stderr, "Invalid Exif start (1)"); - return false; - } - - const uint FirstOffset = Get32u(ExifSection+12); - if(FirstOffset < 8 || FirstOffset > 16){ - // Usually set to 8, but other values valid too - fprintf(stderr, "Suspicious offset of first IFD value"); - return false; - } - - DirWithThumbnailPtrs = NULL; - - // First directory starts 16 bytes in. All offset are relative to 8 bytes in. - if( !ProcessExifDir(ExifSection+8+FirstOffset, ExifSection+8, length-8, 0) ) return false; - - ImageInfo.ThumbnailAtEnd = (ImageInfo.ThumbnailOffset >= ImageInfo.LargestExifOffset); - - return true; - } - - // Process one of the nested EXIF directories. - bool ProcessExifDir(uchar *DirStart, uchar *OffsetBase, unsigned ExifLength, int NestingLevel){ - int NumDirEntries; - unsigned ThumbnailOffset = 0; - unsigned ThumbnailSize = 0; - char IndentString[25]; - - if(NestingLevel > 4){ - fprintf(stderr, "Maximum directory nesting exceeded (corrupt exif header)"); - return false; - } - - memset(IndentString, ' ', 25); - IndentString[NestingLevel * 4] = '\0'; - - NumDirEntries = Get16u(DirStart); -#define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry)) - uchar *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{ - fprintf(stderr, "Illegally sized exif subdirectory (%d entries)", NumDirEntries); - return false; - } - } - - for(int de=0 ; de= NUM_FORMATS){ - // (-1) catches illegal zero case as unsigned underflows to positive large. - fprintf(stderr, "Illegal number format %d for tag %04x", Format, Tag); - continue; - } - - if ((unsigned)Components > 0x10000){ - fprintf(stderr, "Illegal number of components %d for tag %04x", Components, Tag); - continue; - } - - int ByteCount = Components * BytesPerFormat[Format]; - - uchar *ValuePtr; - if(ByteCount > 4){ - unsigned OffsetVal; - OffsetVal = Get32u(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 - fprintf(stderr, "Illegal value pointer for tag %04x", Tag,0); - continue; - } - ValuePtr = OffsetBase+OffsetVal; - if(OffsetVal > ImageInfo.LargestExifOffset) ImageInfo.LargestExifOffset = OffsetVal; - }else{ - // 4 bytes or less and value is in the dir entry itself - ValuePtr = DirEntry+8; - } - - if(Tag == TAG_MAKER_NOTE){ - ProcessMakerNote(ValuePtr, OffsetBase, ExifLength); - continue; - } - - // Extract useful components of tag - switch(Tag){ - case TAG_MAKE: - strncpy(ImageInfo.CameraMake, (char*)ValuePtr, ByteCount < 31 ? ByteCount : 31); - break; - case TAG_MODEL: - strncpy(ImageInfo.CameraModel, (char*)ValuePtr, ByteCount < 39 ? ByteCount : 39); - break; - case TAG_DATETIME_ORIGINAL: - // If we get a DATETIME_ORIGINAL, we use that one. - strncpy(ImageInfo.DateTime, (char*)ValuePtr, 19); - // Fallthru... - case TAG_DATETIME_DIGITIZED: - case TAG_DATETIME: - // If we don't already have a DATETIME_ORIGINAL, use whatever time fields we may have. - if(!isdigit(ImageInfo.DateTime[0])) strncpy(ImageInfo.DateTime, (char*)ValuePtr, 19); - if(ImageInfo.numDateTimeTags >= MAX_DATE_COPIES) - fprintf(stderr, "More than %d date fields! This is nuts", MAX_DATE_COPIES, 0); - else - ImageInfo.DateTimeOffsets[ImageInfo.numDateTimeTags++] = (char*)ValuePtr - (char*)OffsetBase; - break; - case TAG_WINXP_COMMENT: - // We already have a jpeg comment (probably windows comment), skip this one. - if(ImageInfo.Comments[0]) break; - if(ByteCount > 1){ - if(ByteCount > MAX_COMMENT_SIZE) ByteCount = MAX_COMMENT_SIZE; - memcpy(ImageInfo.Comments, ValuePtr, ByteCount); - ImageInfo.CommentWidchars = ByteCount/2; - } - break; - case TAG_USERCOMMENT:{ - // We already have a jpeg comment (probably windows comment), skip this one. - if(ImageInfo.Comments[0]) break; - // Comment is often padded with trailing spaces. Remove these first. - int a = ByteCount-1; - while( a && ((ValuePtr)[a]==' ') ) (ValuePtr)[a--] = '\0'; - - // Copy the comment - if(memcmp(ValuePtr, "ASCII",5) == 0){ - for(a=5 ; a<10 ; a++){ - uchar c = (ValuePtr)[a]; - if( (c!='\0') && (c!=' ') ){ - strncpy(ImageInfo.Comments, (char *)ValuePtr+a, 199); - break; - } - } - }else{ - strncpy(ImageInfo.Comments, (char *)ValuePtr, MAX_COMMENT_SIZE-1); - } - break; - } - case TAG_FNUMBER: - // Simplest way of expressing aperture, so I trust it the most. - // (overwrite previously computd value if there is one) - ImageInfo.ApertureFNumber = T(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(ImageInfo.ApertureFNumber == 0) - ImageInfo.ApertureFNumber = T(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 farthey are zoomed in. - ImageInfo.FocalLength = T(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. - ImageInfo.Distance = T(ConvertAnyFormat(ValuePtr, Format)); - break; - case TAG_EXPOSURETIME: - // Simplest way of expressing exposure time, so I trust it most. - // (overwrite previously computd value if there is one) - ImageInfo.ExposureTime = T(ConvertAnyFormat(ValuePtr, Format)); - 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(ImageInfo.ExposureTime == 0) - ImageInfo.ExposureTime = T(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0))); - break; - case TAG_FLASH: - ImageInfo.FlashUsed=(int)ConvertAnyFormat(ValuePtr, Format); - break; - case TAG_ORIENTATION: - if(NumOrientations >= 2){ - // Can have another orientation tag for the thumbnail, but if there's a third one, things are stringae. - fprintf(stderr, "More than two orientation tags!"); - break; - } - OrientationPtr[NumOrientations] = ValuePtr; - OrientationNumFormat[NumOrientations] = Format; - if(NumOrientations == 0) - ImageInfo.Orientation = (int)ConvertAnyFormat(ValuePtr, Format); - if(ImageInfo.Orientation < 0 || ImageInfo.Orientation > 8){ - fprintf(stderr, "Undefined rotation value %d", ImageInfo.Orientation); - ImageInfo.Orientation = 0; - } - NumOrientations += 1; - 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 (ExifImageWidth < a) ExifImageWidth = a; - break; - } - case TAG_FOCAL_PLANE_XRES: - FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format); - break; - case TAG_FOCAL_PLANE_UNITS: - switch((int)ConvertAnyFormat(ValuePtr, Format)){ - case 1: FocalplaneUnits = 25.4; break; // inch - case 2: - // According to the information I was using, 2 means meters. - // But looking at the Cannon powershot's files, inches is the only - // sensible value. - FocalplaneUnits = 25.4; - break; - case 3: FocalplaneUnits = 10; break; // centimeter - case 4: FocalplaneUnits = 1; break; // millimeter - case 5: FocalplaneUnits = .001; break; // micrometer - } - break; - case TAG_EXPOSURE_BIAS: - ImageInfo.ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format); - break; - case TAG_WHITEBALANCE: - ImageInfo.Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format); - break; - case TAG_LIGHT_SOURCE: - ImageInfo.LightSource = (int)ConvertAnyFormat(ValuePtr, Format); - break; - case TAG_METERING_MODE: - ImageInfo.MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format); - break; - case TAG_EXPOSURE_PROGRAM: - ImageInfo.ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format); - break; - case TAG_EXPOSURE_INDEX: - if(ImageInfo.ISOequivalent == 0){ - // Exposure index and ISO equivalent are often used interchangeably, - // so we will do the same in jhead. - // http://photography.about.com/library/glossary/bldef_ei.htm - ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format); - } - break; - case TAG_EXPOSURE_MODE: - ImageInfo.ExposureMode = (int)ConvertAnyFormat(ValuePtr, Format); - break; - case TAG_ISO_EQUIVALENT: - ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format); - // Fixes strange encoding on some older digicams. - if( ImageInfo.ISOequivalent < 50 ) ImageInfo.ISOequivalent *= 200; - break; - case TAG_DIGITALZOOMRATIO: - ImageInfo.DigitalZoomRatio = (float)ConvertAnyFormat(ValuePtr, Format); - break; - case TAG_THUMBNAIL_OFFSET: - ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format); - DirWithThumbnailPtrs = DirStart; - break; - case TAG_THUMBNAIL_LENGTH: - ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format); - ImageInfo.ThumbnailSizeOffset = ValuePtr-OffsetBase; - break; - case TAG_EXIF_OFFSET: - case TAG_INTEROP_OFFSET:{ - uchar *SubdirStart = OffsetBase + Get32u(ValuePtr); - if(SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength) - fprintf(stderr, "Illegal exif or interop offset directory link"); - else - ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1); - break; - } - case TAG_GPSINFO:{ - uchar *SubdirStart = OffsetBase + Get32u(ValuePtr); - if(SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength) - fprintf(stderr, "Illegal GPS directory link"); - else - ;//ProcessGpsInfo(SubdirStart, ByteCount, OffsetBase, ExifLength); - 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. - ImageInfo.FocalLength35mmEquiv = (unsigned)ConvertAnyFormat(ValuePtr, Format); - break; - case TAG_DISTANCE_RANGE: - // Three possible standard values: - // 1 = macro, 2 = close, 3 = distant - ImageInfo.DistanceRange = (int)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 char * SubdirStart; - unsigned Offset; - - if(DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength){ - Offset = Get32u(DirStart+2+12*NumDirEntries); - if (Offset){ - 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{ - fprintf(stderr, "Illegal subdirectory link"); - } - }else{ - if(SubdirStart <= OffsetBase+ExifLength) - ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1); - } - if(Offset > ImageInfo.LargestExifOffset){ - ImageInfo.LargestExifOffset = Offset; - } - } - }else{ - // The exif header ends before the last next directory pointer. - } - - if(ThumbnailOffset){ - ImageInfo.ThumbnailAtEnd = false; - if(ThumbnailOffset <= ExifLength){ - if(ThumbnailSize > ExifLength-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. - ThumbnailSize = ExifLength-ThumbnailOffset; - } - // The thumbnail pointer appears to be valid. Store it. - ImageInfo.ThumbnailOffset = ThumbnailOffset; - ImageInfo.ThumbnailSize = ThumbnailSize; - } - } - } - -}; - -#endif \ No newline at end of file diff --git a/wrap/Exif/include/Exif/jhead.h b/wrap/Exif/include/Exif/jhead.h deleted file mode 100644 index 42940439..00000000 --- a/wrap/Exif/include/Exif/jhead.h +++ /dev/null @@ -1,244 +0,0 @@ -//-------------------------------------------------------------------------- -// Include file for jhead program. -// -// This include file only defines stuff that goes across modules. -// I like to keep the definitions for macros and structures as close to -// where they get used as possible, so include files only get stuff that -// gets used in more than one file. -//-------------------------------------------------------------------------- -#define _CRT_SECURE_NO_DEPRECATE 1 - -#include -#include -#include -#include -#include -#include - -//-------------------------------------------------------------------------- - -#ifdef _WIN32 - #include -#else - #include - #include - #include - #include - #include -#endif - - -typedef unsigned char uchar; - -#ifndef TRUE - #define TRUE 1 - #define FALSE 0 -#endif - -#define MAX_COMMENT_SIZE 2000 - -#ifdef _WIN32 - #define PATH_MAX _MAX_PATH - #define SLASH '\\' -#else - #define SLASH '/' -#endif - - -//-------------------------------------------------------------------------- -// This structure is used to store jpeg file sections in memory. -typedef struct { - uchar * Data; - int Type; - unsigned Size; -}Section_t; - -extern int ExifSectionIndex; - -extern int DumpExifMap; - -#define MAX_DATE_COPIES 10 - -//-------------------------------------------------------------------------- -// This structure stores Exif header image elements in a simple manner -// Used to store camera data as extracted from the various ways that it can be -// stored in an exif header -typedef struct { - char FileName [PATH_MAX+1]; - time_t FileDateTime; - unsigned FileSize; - 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; - int DistanceRange; - - double FocalplaneXRes; - double FocalplaneUnits; - int ExifImageWidth; - - char Comments[MAX_COMMENT_SIZE]; - int CommentWidchars; // If nonzer, widechar comment, indicates number of chars. - - 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]; -}ImageInfo_t; - - - -#define EXIT_FAILURE 1 -#define EXIT_SUCCESS 0 - -// jpgfile.c functions -//typedef -enum { - READ_METADATA = 1, - READ_IMAGE = 2, - READ_ALL = 3 -};//ReadMode_t; -typedef int ReadMode_t; - - -// prototypes for jhead.c functions -void ErrFatal(const char * msg); -void ErrNonfatal(const char * msg, int a1, int a2); -void FileTimeAsString(char * TimeStr); - -void ProcessFile(const char * FileName); - -// Prototypes for exif.c functions. -int Exif2tm(struct tm * timeptr, char * ExifTime); -void process_EXIF (unsigned char * CharBuf, unsigned int length); -int RemoveThumbnail(unsigned char * ExifSection); -void ShowImageInfo(int ShowFileInfo); -void ShowConciseImageInfo(void); -const char * ClearOrientation(void); -void PrintFormatNumber(void * ValuePtr, int Format, int ByteCount); -double ConvertAnyFormat(void * ValuePtr, int Format); -int Get16u(void * Short); -unsigned Get32u(void * Long); -int Get32s(void * Long); -void Put32u(void * Value, unsigned PutValue); -void create_EXIF(void); - -//-------------------------------------------------------------------------- -// Exif format descriptor stuff -extern const int BytesPerFormat[]; -#define NUM_FORMATS 12 - -#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 - - -// makernote.c prototypes -extern void ProcessMakerNote(unsigned char * DirStart, int ByteCount, - unsigned char * OffsetBase, unsigned ExifLength); - -// gpsinfo.c prototypes -void ProcessGpsInfo(unsigned char * ValuePtr, int ByteCount, - unsigned char * OffsetBase, unsigned ExifLength); - -// iptc.c prototpyes -void show_IPTC (unsigned char * CharBuf, unsigned int length); -void ShowXmp(Section_t XmpSection); - -// Prototypes for myglob.c module -#ifdef _WIN32 -void MyGlob(const char * Pattern , void (*FileFuncParm)(const char * FileName)); -void SlashToNative(char * Path); -#endif - -// Prototypes for paths.c module -int EnsurePathExists(const char * FileName); -void CatPath(char * BasePath, const char * FilePath); - -// Prototypes from jpgfile.c -int ReadJpegSections (FILE * infile, ReadMode_t ReadMode); -void DiscardData(void); -void DiscardAllButExif(void); -int ReadJpegFile(const char * FileName, ReadMode_t ReadMode); -int ReplaceThumbnail(const char * ThumbFileName); -int SaveThumbnail(char * ThumbFileName); -int RemoveSectionType(int SectionType); -int RemoveUnknownSections(void); -void WriteJpegFile(const char * FileName); -Section_t * FindSection(int SectionType); -Section_t * CreateSection(int SectionType, unsigned char * Data, int size); -void ResetJpgfile(void); - - -// Variables from jhead.c used by exif.c -extern ImageInfo_t ImageInfo; -extern int ShowTags; - -//-------------------------------------------------------------------------- -// 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 program. (See jdmarker.c for a more complete list.) -//-------------------------------------------------------------------------- - -#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. Also used for XMP data! -#define M_XMP 0x10E1 // Not a real tag (same value in file as Exif!) -#define M_COM 0xFE // COMment -#define M_DQT 0xDB -#define M_DHT 0xC4 -#define M_DRI 0xDD -#define M_IPTC 0xED // IPTC marker diff --git a/wrap/Exif/src/exif.cpp b/wrap/Exif/src/exif.cpp deleted file mode 100644 index ce38f64d..00000000 --- a/wrap/Exif/src/exif.cpp +++ /dev/null @@ -1,1586 +0,0 @@ -//-------------------------------------------------------------------------- -// Program to pull the information out of various types of EXIF digital -// camera files and show it in a reasonably consistent way -// -// This module parses the very complicated exif structures. -// -// Matthias Wandel -//-------------------------------------------------------------------------- -#include "../include/Exif/jhead.h" - -#include - -static unsigned char * DirWithThumbnailPtrs; -/* -static double FocalplaneXRes; -static double FocalplaneUnits; -static int ExifImageWidth; -*/ -static int MotorolaOrder = 0; - -// for fixing the rotation. -static void * OrientationPtr[2]; -static int OrientationNumFormat[2]; -int NumOrientations = 0; - -typedef struct { - unsigned short Tag; - const char * Desc; -}TagTable_t; - - -//-------------------------------------------------------------------------- -// Table of Jpeg encoding process names -static const TagTable_t ProcessTable[] = { - { M_SOF0, "Baseline"}, - { M_SOF1, "Extended sequential"}, - { M_SOF2, "Progressive"}, - { M_SOF3, "Lossless"}, - { M_SOF5, "Differential sequential"}, - { M_SOF6, "Differential progressive"}, - { M_SOF7, "Differential lossless"}, - { M_SOF9, "Extended sequential, arithmetic coding"}, - { M_SOF10, "Progressive, arithmetic coding"}, - { M_SOF11, "Lossless, arithmetic coding"}, - { M_SOF13, "Differential sequential, arithmetic coding"}, - { M_SOF14, "Differential progressive, arithmetic coding"}, - { M_SOF15, "Differential lossless, arithmetic coding"}, -}; - -#define PROCESS_TABLE_SIZE (int)(sizeof(ProcessTable) / sizeof(TagTable_t)) - -// 1 - "The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side." -// 2 - "The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side." -// 3 - "The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side." -// 4 - "The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side." - -// 5 - "The 0th row is the visual left-hand side of of the image, and the 0th column is the visual top." -// 6 - "The 0th row is the visual right-hand side of of the image, and the 0th column is the visual top." -// 7 - "The 0th row is the visual right-hand side of of the image, and the 0th column is the visual bottom." -// 8 - "The 0th row is the visual left-hand side of of the image, and the 0th column is the visual bottom." - -// Note: The descriptions here are the same as the name of the command line -// option to pass to jpegtran to right the image - -static const char * OrientTab[9] = { - "Undefined", - "Normal", // 1 - "flip horizontal", // left right reversed mirror - "rotate 180", // 3 - "flip vertical", // upside down mirror - "transpose", // Flipped about top-left <--> bottom-right axis. - "rotate 90", // rotate 90 cw to right it. - "transverse", // flipped about top-right <--> bottom-left axis - "rotate 270", // rotate 270 to right it. -}; - -const int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8}; - -//-------------------------------------------------------------------------- -// Describes tag values - -#define TAG_INTEROP_INDEX 0x0001 -#define TAG_INTEROP_VERSION 0x0002 -#define TAG_IMAGE_WIDTH 0x0100 -#define TAG_IMAGE_LENGTH 0x0101 -#define TAG_BITS_PER_SAMPLE 0x0102 -#define TAG_COMPRESSION 0x0103 -#define TAG_PHOTOMETRIC_INTERP 0x0106 -#define TAG_FILL_ORDER 0x010A -#define TAG_DOCUMENT_NAME 0x010D -#define TAG_IMAGE_DESCRIPTION 0x010E -#define TAG_MAKE 0x010F -#define TAG_MODEL 0x0110 -#define TAG_SRIP_OFFSET 0x0111 -#define TAG_ORIENTATION 0x0112 -#define TAG_SAMPLES_PER_PIXEL 0x0115 -#define TAG_ROWS_PER_STRIP 0x0116 -#define TAG_STRIP_BYTE_COUNTS 0x0117 -#define TAG_X_RESOLUTION 0x011A -#define TAG_Y_RESOLUTION 0x011B -#define TAG_PLANAR_CONFIGURATION 0x011C -#define TAG_RESOLUTION_UNIT 0x0128 -#define TAG_TRANSFER_FUNCTION 0x012D -#define TAG_SOFTWARE 0x0131 -#define TAG_DATETIME 0x0132 -#define TAG_ARTIST 0x013B -#define TAG_WHITE_POINT 0x013E -#define TAG_PRIMARY_CHROMATICITIES 0x013F -#define TAG_TRANSFER_RANGE 0x0156 -#define TAG_JPEG_PROC 0x0200 -#define TAG_THUMBNAIL_OFFSET 0x0201 -#define TAG_THUMBNAIL_LENGTH 0x0202 -#define TAG_Y_CB_CR_COEFFICIENTS 0x0211 -#define TAG_Y_CB_CR_SUB_SAMPLING 0x0212 -#define TAG_Y_CB_CR_POSITIONING 0x0213 -#define TAG_REFERENCE_BLACK_WHITE 0x0214 -#define TAG_RELATED_IMAGE_WIDTH 0x1001 -#define TAG_RELATED_IMAGE_LENGTH 0x1002 -#define TAG_CFA_REPEAT_PATTERN_DIM 0x828D -#define TAG_CFA_PATTERN1 0x828E -#define TAG_BATTERY_LEVEL 0x828F -#define TAG_COPYRIGHT 0x8298 -#define TAG_EXPOSURETIME 0x829A -#define TAG_FNUMBER 0x829D -#define TAG_IPTC_NAA 0x83BB -#define TAG_EXIF_OFFSET 0x8769 -#define TAG_INTER_COLOR_PROFILE 0x8773 -#define TAG_EXPOSURE_PROGRAM 0x8822 -#define TAG_SPECTRAL_SENSITIVITY 0x8824 -#define TAG_GPSINFO 0x8825 -#define TAG_ISO_EQUIVALENT 0x8827 -#define TAG_OECF 0x8828 -#define TAG_EXIF_VERSION 0x9000 -#define TAG_DATETIME_ORIGINAL 0x9003 -#define TAG_DATETIME_DIGITIZED 0x9004 -#define TAG_COMPONENTS_CONFIG 0x9101 -#define TAG_CPRS_BITS_PER_PIXEL 0x9102 -#define TAG_SHUTTERSPEED 0x9201 -#define TAG_APERTURE 0x9202 -#define TAG_BRIGHTNESS_VALUE 0x9203 -#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 -#define TAG_USERCOMMENT 0x9286 -#define TAG_SUBSEC_TIME 0x9290 -#define TAG_SUBSEC_TIME_ORIG 0x9291 -#define TAG_SUBSEC_TIME_DIG 0x9292 - -#define TAG_WINXP_TITLE 0x9c9b // Windows XP - not part of exif standard. -#define TAG_WINXP_COMMENT 0x9c9c // Windows XP - not part of exif standard. -#define TAG_WINXP_AUTHOR 0x9c9d // Windows XP - not part of exif standard. -#define TAG_WINXP_KEYWORDS 0x9c9e // Windows XP - not part of exif standard. -#define TAG_WINXP_SUBJECT 0x9c9f // Windows XP - not part of exif standard. - -#define TAG_FLASH_PIX_VERSION 0xA000 -#define TAG_COLOR_SPACE 0xA001 -#define TAG_EXIF_IMAGEWIDTH 0xA002 -#define TAG_EXIF_IMAGELENGTH 0xA003 -#define TAG_RELATED_AUDIO_FILE 0xA004 -#define TAG_INTEROP_OFFSET 0xA005 -#define TAG_FLASH_ENERGY 0xA20B -#define TAG_SPATIAL_FREQ_RESP 0xA20C -#define TAG_FOCAL_PLANE_XRES 0xA20E -#define TAG_FOCAL_PLANE_YRES 0xA20F -#define TAG_FOCAL_PLANE_UNITS 0xA210 -#define TAG_SUBJECT_LOCATION 0xA214 -#define TAG_EXPOSURE_INDEX 0xA215 -#define TAG_SENSING_METHOD 0xA217 -#define TAG_FILE_SOURCE 0xA300 -#define TAG_SCENE_TYPE 0xA301 -#define TAG_CFA_PATTERN 0xA302 -#define TAG_CUSTOM_RENDERED 0xA401 -#define TAG_EXPOSURE_MODE 0xA402 -#define TAG_WHITEBALANCE 0xA403 -#define TAG_DIGITALZOOMRATIO 0xA404 -#define TAG_FOCALLENGTH_35MM 0xA405 -#define TAG_SCENE_CAPTURE_TYPE 0xA406 -#define TAG_GAIN_CONTROL 0xA407 -#define TAG_CONTRAST 0xA408 -#define TAG_SATURATION 0xA409 -#define TAG_SHARPNESS 0xA40A -#define TAG_DISTANCE_RANGE 0xA40C - -static const TagTable_t TagTable[] = { - { TAG_INTEROP_INDEX, "InteropIndex"}, - { TAG_INTEROP_VERSION, "InteropVersion"}, - { TAG_IMAGE_WIDTH, "ImageWidth"}, - { TAG_IMAGE_LENGTH, "ImageLength"}, - { TAG_BITS_PER_SAMPLE, "BitsPerSample"}, - { TAG_COMPRESSION, "Compression"}, - { TAG_PHOTOMETRIC_INTERP, "PhotometricInterpretation"}, - { TAG_FILL_ORDER, "FillOrder"}, - { TAG_DOCUMENT_NAME, "DocumentName"}, - { TAG_IMAGE_DESCRIPTION, "ImageDescription"}, - { TAG_MAKE, "Make"}, - { TAG_MODEL, "Model"}, - { TAG_SRIP_OFFSET, "StripOffsets"}, - { TAG_ORIENTATION, "Orientation"}, - { TAG_SAMPLES_PER_PIXEL, "SamplesPerPixel"}, - { TAG_ROWS_PER_STRIP, "RowsPerStrip"}, - { TAG_STRIP_BYTE_COUNTS, "StripByteCounts"}, - { TAG_X_RESOLUTION, "XResolution"}, - { TAG_Y_RESOLUTION, "YResolution"}, - { TAG_PLANAR_CONFIGURATION, "PlanarConfiguration"}, - { TAG_RESOLUTION_UNIT, "ResolutionUnit"}, - { TAG_TRANSFER_FUNCTION, "TransferFunction"}, - { TAG_SOFTWARE, "Software"}, - { TAG_DATETIME, "DateTime"}, - { TAG_ARTIST, "Artist"}, - { TAG_WHITE_POINT, "WhitePoint"}, - { TAG_PRIMARY_CHROMATICITIES, "PrimaryChromaticities"}, - { TAG_TRANSFER_RANGE, "TransferRange"}, - { TAG_JPEG_PROC, "JPEGProc"}, - { TAG_THUMBNAIL_OFFSET, "ThumbnailOffset"}, - { TAG_THUMBNAIL_LENGTH, "ThumbnailLength"}, - { TAG_Y_CB_CR_COEFFICIENTS, "YCbCrCoefficients"}, - { TAG_Y_CB_CR_SUB_SAMPLING, "YCbCrSubSampling"}, - { TAG_Y_CB_CR_POSITIONING, "YCbCrPositioning"}, - { TAG_REFERENCE_BLACK_WHITE, "ReferenceBlackWhite"}, - { TAG_RELATED_IMAGE_WIDTH, "RelatedImageWidth"}, - { TAG_RELATED_IMAGE_LENGTH, "RelatedImageLength"}, - { TAG_CFA_REPEAT_PATTERN_DIM, "CFARepeatPatternDim"}, - { TAG_CFA_PATTERN1, "CFAPattern"}, - { TAG_BATTERY_LEVEL, "BatteryLevel"}, - { TAG_COPYRIGHT, "Copyright"}, - { TAG_EXPOSURETIME, "ExposureTime"}, - { TAG_FNUMBER, "FNumber"}, - { TAG_IPTC_NAA, "IPTC/NAA"}, - { TAG_EXIF_OFFSET, "ExifOffset"}, - { TAG_INTER_COLOR_PROFILE, "InterColorProfile"}, - { TAG_EXPOSURE_PROGRAM, "ExposureProgram"}, - { TAG_SPECTRAL_SENSITIVITY, "SpectralSensitivity"}, - { TAG_GPSINFO, "GPS Dir offset"}, - { TAG_ISO_EQUIVALENT, "ISOSpeedRatings"}, - { TAG_OECF, "OECF"}, - { TAG_EXIF_VERSION, "ExifVersion"}, - { TAG_DATETIME_ORIGINAL, "DateTimeOriginal"}, - { TAG_DATETIME_DIGITIZED, "DateTimeDigitized"}, - { TAG_COMPONENTS_CONFIG, "ComponentsConfiguration"}, - { TAG_CPRS_BITS_PER_PIXEL, "CompressedBitsPerPixel"}, - { TAG_SHUTTERSPEED, "ShutterSpeedValue"}, - { TAG_APERTURE, "ApertureValue"}, - { TAG_BRIGHTNESS_VALUE, "BrightnessValue"}, - { TAG_EXPOSURE_BIAS, "ExposureBiasValue"}, - { TAG_MAXAPERTURE, "MaxApertureValue"}, - { TAG_SUBJECT_DISTANCE, "SubjectDistance"}, - { TAG_METERING_MODE, "MeteringMode"}, - { TAG_LIGHT_SOURCE, "LightSource"}, - { TAG_FLASH, "Flash"}, - { TAG_FOCALLENGTH, "FocalLength"}, - { TAG_MAKER_NOTE, "MakerNote"}, - { TAG_USERCOMMENT, "UserComment"}, - { TAG_SUBSEC_TIME, "SubSecTime"}, - { TAG_SUBSEC_TIME_ORIG, "SubSecTimeOriginal"}, - { TAG_SUBSEC_TIME_DIG, "SubSecTimeDigitized"}, - { TAG_WINXP_TITLE, "Windows-XP Title"}, - { TAG_WINXP_COMMENT, "Windows-XP comment"}, - { TAG_WINXP_AUTHOR, "Windows-XP author"}, - { TAG_WINXP_KEYWORDS, "Windows-XP keywords"}, - { TAG_WINXP_SUBJECT, "Windows-XP subject"}, - { TAG_FLASH_PIX_VERSION, "FlashPixVersion"}, - { TAG_COLOR_SPACE, "ColorSpace"}, - { TAG_EXIF_IMAGEWIDTH, "ExifImageWidth"}, - { TAG_EXIF_IMAGELENGTH, "ExifImageLength"}, - { TAG_RELATED_AUDIO_FILE, "RelatedAudioFile"}, - { TAG_INTEROP_OFFSET, "InteroperabilityOffset"}, - { TAG_FLASH_ENERGY, "FlashEnergy"}, - { TAG_SPATIAL_FREQ_RESP, "SpatialFrequencyResponse"}, - { TAG_FOCAL_PLANE_XRES, "FocalPlaneXResolution"}, - { TAG_FOCAL_PLANE_YRES, "FocalPlaneYResolution"}, - { TAG_FOCAL_PLANE_UNITS, "FocalPlaneResolutionUnit"}, - { TAG_SUBJECT_LOCATION, "SubjectLocation"}, - { TAG_EXPOSURE_INDEX, "ExposureIndex"}, - { TAG_SENSING_METHOD, "SensingMethod"}, - { TAG_FILE_SOURCE, "FileSource"}, - { TAG_SCENE_TYPE, "SceneType"}, - { TAG_CFA_PATTERN, "CFA Pattern"}, - { TAG_CUSTOM_RENDERED, "CustomRendered"}, - { TAG_EXPOSURE_MODE, "ExposureMode"}, - { TAG_WHITEBALANCE, "WhiteBalance"}, - { TAG_DIGITALZOOMRATIO, "DigitalZoomRatio"}, - { TAG_FOCALLENGTH_35MM, "FocalLengthIn35mmFilm"}, - { TAG_SCENE_CAPTURE_TYPE, "SceneCaptureType"}, - { TAG_GAIN_CONTROL, "GainControl"}, - { TAG_CONTRAST, "Contrast"}, - { TAG_SATURATION, "Saturation"}, - { TAG_SHARPNESS, "Sharpness"}, - { TAG_DISTANCE_RANGE, "SubjectDistanceRange"}, -} ; - -#define TAG_TABLE_SIZE (int)(sizeof(TagTable) / sizeof(TagTable_t)) - - -//-------------------------------------------------------------------------- -// Convert a 16 bit unsigned value to file's native byte order -//-------------------------------------------------------------------------- -static void Put16u(void * Short, unsigned short PutValue) -{ - if (MotorolaOrder){ - ((uchar *)Short)[0] = (uchar)(PutValue>>8); - ((uchar *)Short)[1] = (uchar)PutValue; - }else{ - ((uchar *)Short)[0] = (uchar)PutValue; - ((uchar *)Short)[1] = (uchar)(PutValue>>8); - } -} - -//-------------------------------------------------------------------------- -// Convert a 16 bit unsigned value from file's native byte order -//-------------------------------------------------------------------------- -int Get16u(void * Short) -{ - if (MotorolaOrder){ - return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1]; - }else{ - return (((uchar *)Short)[1] << 8) | ((uchar *)Short)[0]; - } -} - -//-------------------------------------------------------------------------- -// Convert a 32 bit signed value from file's native byte order -//-------------------------------------------------------------------------- -int Get32s(void * Long) -{ - if (MotorolaOrder){ - return ((( char *)Long)[0] << 24) | (((uchar *)Long)[1] << 16) - | (((uchar *)Long)[2] << 8 ) | (((uchar *)Long)[3] << 0 ); - }else{ - return ((( char *)Long)[3] << 24) | (((uchar *)Long)[2] << 16) - | (((uchar *)Long)[1] << 8 ) | (((uchar *)Long)[0] << 0 ); - } -} - -//-------------------------------------------------------------------------- -// Convert a 32 bit unsigned value to file's native byte order -//-------------------------------------------------------------------------- -void Put32u(void * Value, unsigned PutValue) -{ - if (MotorolaOrder){ - ((uchar *)Value)[0] = (uchar)(PutValue>>24); - ((uchar *)Value)[1] = (uchar)(PutValue>>16); - ((uchar *)Value)[2] = (uchar)(PutValue>>8); - ((uchar *)Value)[3] = (uchar)PutValue; - }else{ - ((uchar *)Value)[0] = (uchar)PutValue; - ((uchar *)Value)[1] = (uchar)(PutValue>>8); - ((uchar *)Value)[2] = (uchar)(PutValue>>16); - ((uchar *)Value)[3] = (uchar)(PutValue>>24); - } -} - -//-------------------------------------------------------------------------- -// Convert a 32 bit unsigned value from file's native byte order -//-------------------------------------------------------------------------- -unsigned Get32u(void * Long) -{ - return (unsigned)Get32s(Long) & 0xffffffff; -} - -//-------------------------------------------------------------------------- -// Display a number as one of its many formats -//-------------------------------------------------------------------------- -void PrintFormatNumber(void * ValuePtr, int Format, int ByteCount) -{ - int s,n; - - for(n=0;n<16;n++){ - switch(Format){ - case FMT_SBYTE: - case FMT_BYTE: printf("%02x",*(uchar *)ValuePtr); s=1; break; - case FMT_USHORT: printf("%d",Get16u(ValuePtr)); s=2; break; - case FMT_ULONG: - case FMT_SLONG: printf("%d",Get32s(ValuePtr)); s=4; break; - case FMT_SSHORT: printf("%hd",(signed short)Get16u(ValuePtr)); s=2; break; - case FMT_URATIONAL: - case FMT_SRATIONAL: - printf("%d/%d",Get32s(ValuePtr), Get32s(4+(char *)ValuePtr)); - s = 8; - break; - - case FMT_SINGLE: printf("%f",(double)*(float *)ValuePtr); s=8; break; - case FMT_DOUBLE: printf("%f",*(double *)ValuePtr); s=8; break; - default: - printf("Unknown format %d:", Format); - return; - } - ByteCount -= s; - if (ByteCount <= 0) break; - printf(", "); - ValuePtr = (void *)((char *)ValuePtr + s); - - } - if (n >= 16) printf("..."); -} - - -//-------------------------------------------------------------------------- -// Evaluate number, be it int, rational, or float from directory. -//-------------------------------------------------------------------------- -double ConvertAnyFormat(void * ValuePtr, int Format) -{ - double Value; - Value = 0; - - switch(Format){ - case FMT_SBYTE: Value = *(signed char *)ValuePtr; break; - case FMT_BYTE: Value = *(uchar *)ValuePtr; break; - - case FMT_USHORT: Value = Get16u(ValuePtr); break; - case FMT_ULONG: Value = Get32u(ValuePtr); break; - - case FMT_URATIONAL: - case FMT_SRATIONAL: - { - int Num,Den; - Num = Get32s(ValuePtr); - Den = Get32s(4+(char *)ValuePtr); - if (Den == 0){ - Value = 0; - }else{ - Value = (double)Num/Den; - } - break; - } - - case FMT_SSHORT: Value = (signed short)Get16u(ValuePtr); break; - case FMT_SLONG: Value = Get32s(ValuePtr); 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; -} - -//-------------------------------------------------------------------------- -// Process one of the nested EXIF directories. -//-------------------------------------------------------------------------- -static void ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, - unsigned ExifLength, int NestingLevel) -{ - int de; - int a; - int NumDirEntries; - unsigned ThumbnailOffset = 0; - unsigned ThumbnailSize = 0; - char IndentString[25]; - - if (NestingLevel > 4){ - ErrNonfatal("Maximum directory nesting exceeded (corrupt exif header)", 0,0); - return; - } - - memset(IndentString, ' ', 25); - IndentString[NestingLevel * 4] = '\0'; - - - NumDirEntries = Get16u(DirStart); - #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry)) - - { - unsigned char * DirEnd; - 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 exif subdirectory (%d entries)",NumDirEntries,0); - return; - } - } - if (DumpExifMap){ - printf("Map: %05d-%05d: Directory\n",(int)(DirStart-OffsetBase), (int)(DirEnd+4-OffsetBase)); - } - - - } - - if (ShowTags){ - printf("(dir has %d entries)\n",NumDirEntries); - } - - for (de=0;de= 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 = Get32u(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; - - if (OffsetVal > ImageInfo.LargestExifOffset){ - ImageInfo.LargestExifOffset = OffsetVal; - } - - if (DumpExifMap){ - printf("Map: %05d-%05d: Data for tag %04x\n",OffsetVal, OffsetVal+ByteCount, Tag); - } - }else{ - // 4 bytes or less and value is in the dir entry itself - ValuePtr = DirEntry+8; - } - - if (Tag == TAG_MAKER_NOTE){ - if (ShowTags){ - printf("%s Maker note: ",IndentString); - } - ProcessMakerNote(ValuePtr, ByteCount, OffsetBase, ExifLength); - continue; - } - - if (ShowTags){ - // Show tag name - for (a=0;;a++){ - if (a >= TAG_TABLE_SIZE){ - printf(IndentString); - printf(" Unknown Tag %04x Value = ", Tag); - break; - } - if (TagTable[a].Tag == Tag){ - printf(IndentString); - printf(" %s = ",TagTable[a].Desc); - break; - } - } - - // Show tag value. - switch(Format){ - case FMT_BYTE: - if(ByteCount>1){ - printf("%.*ls\n", ByteCount/2, (wchar_t *)ValuePtr); - }else{ - PrintFormatNumber(ValuePtr, Format, ByteCount); - printf("\n"); - } - break; - - case FMT_UNDEFINED: - // Undefined is typically an ascii string. - - case FMT_STRING: - // String arrays printed without function call (different from int arrays) - { - int NoPrint = 0; - printf("\""); - for (a=0;a= 32){ - putchar(ValuePtr[a]); - NoPrint = 0; - }else{ - // Avoiding indicating too many unprintable characters of proprietary - // bits of binary information this program may not know how to parse. - if (!NoPrint && a != ByteCount-1){ - putchar('?'); - NoPrint = 1; - } - } - } - printf("\"\n"); - } - break; - - default: - // Handle arrays of numbers later (will there ever be?) - PrintFormatNumber(ValuePtr, Format, ByteCount); - printf("\n"); - } - } - - // Extract useful components of tag - switch(Tag){ - - case TAG_MAKE: - strncpy(ImageInfo.CameraMake, (char *)ValuePtr, ByteCount < 31 ? ByteCount : 31); - break; - - case TAG_MODEL: - strncpy(ImageInfo.CameraModel, (char *)ValuePtr, ByteCount < 39 ? ByteCount : 39); - break; - - case TAG_DATETIME_ORIGINAL: - // If we get a DATETIME_ORIGINAL, we use that one. - strncpy(ImageInfo.DateTime, (char *)ValuePtr, 19); - // Fallthru... - - case TAG_DATETIME_DIGITIZED: - case TAG_DATETIME: - if (!isdigit(ImageInfo.DateTime[0])){ - // If we don't already have a DATETIME_ORIGINAL, use whatever - // time fields we may have. - strncpy(ImageInfo.DateTime, (char *)ValuePtr, 19); - } - - if (ImageInfo.numDateTimeTags >= MAX_DATE_COPIES){ - ErrNonfatal("More than %d date fields! This is nuts", MAX_DATE_COPIES, 0); - break; - } - ImageInfo.DateTimeOffsets[ImageInfo.numDateTimeTags++] = - (char *)ValuePtr - (char *)OffsetBase; - break; - - case TAG_WINXP_COMMENT: - if (ImageInfo.Comments[0]){ // We already have a jpeg comment. - // Already have a comment (probably windows comment), skip this one. - if (ShowTags) printf("Windows XP commend and other comment in header\n"); - break; // Already have a windows comment, skip this one. - } - - if (ByteCount > 1){ - if (ByteCount > MAX_COMMENT_SIZE) ByteCount = MAX_COMMENT_SIZE; - memcpy(ImageInfo.Comments, ValuePtr, ByteCount); - ImageInfo.CommentWidchars = ByteCount/2; - } - break; - - case TAG_USERCOMMENT: - if (ImageInfo.Comments[0]){ // We already have a jpeg comment. - // Already have a comment (probably windows comment), skip this one. - if (ShowTags) printf("Multiple comments in exif header\n"); - break; // Already have a windows comment, skip this one. - } - - // Comment is often padded with trailing spaces. Remove these first. - for (a=ByteCount;;){ - a--; - if ((ValuePtr)[a] == ' '){ - (ValuePtr)[a] = '\0'; - }else{ - break; - } - if (a == 0) break; - } - - // Copy the comment - if (memcmp(ValuePtr, "ASCII",5) == 0){ - for (a=5;a<10;a++){ - int c; - c = (ValuePtr)[a]; - if (c != '\0' && c != ' '){ - strncpy(ImageInfo.Comments, (char *)ValuePtr+a, 199); - break; - } - } - }else{ - strncpy(ImageInfo.Comments, (char *)ValuePtr, MAX_COMMENT_SIZE-1); - } - break; - - case TAG_FNUMBER: - // Simplest way of expressing aperture, so I trust it the most. - // (overwrite previously computd value if there is one) - ImageInfo.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 (ImageInfo.ApertureFNumber == 0){ - ImageInfo.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 farthey are zoomed in. - ImageInfo.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. - ImageInfo.Distance = (float)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_EXPOSURETIME: - // Simplest way of expressing exposure time, so I trust it most. - // (overwrite previously computd value if there is one) - ImageInfo.ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format); - 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 (ImageInfo.ExposureTime == 0){ - ImageInfo.ExposureTime - = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0))); - } - break; - - - case TAG_FLASH: - ImageInfo.FlashUsed=(int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_ORIENTATION: - if (NumOrientations >= 2){ - // Can have another orientation tag for the thumbnail, but if there's - // a third one, things are stringae. - ErrNonfatal("More than two orientation tags!",0,0); - break; - } - OrientationPtr[NumOrientations] = ValuePtr; - OrientationNumFormat[NumOrientations] = Format; - if (NumOrientations == 0){ - ImageInfo.Orientation = (int)ConvertAnyFormat(ValuePtr, Format); - } - if (ImageInfo.Orientation < 0 || ImageInfo.Orientation > 8){ - ErrNonfatal("Undefined rotation value %d", ImageInfo.Orientation, 0); - ImageInfo.Orientation = 0; - } - NumOrientations += 1; - 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. - a = (int)ConvertAnyFormat(ValuePtr, Format); - if (ImageInfo.ExifImageWidth < a) ImageInfo.ExifImageWidth = a; - break; - - case TAG_FOCAL_PLANE_XRES: - ImageInfo.FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_FOCAL_PLANE_UNITS: - switch((int)ConvertAnyFormat(ValuePtr, Format)){ - case 1: ImageInfo.FocalplaneUnits = 25.4; break; // inch - case 2: - // According to the information I was using, 2 means meters. - // But looking at the Cannon powershot's files, inches is the only - // sensible value. - ImageInfo.FocalplaneUnits = 25.4; - break; - - case 3: ImageInfo.FocalplaneUnits = 10; break; // centimeter - case 4: ImageInfo.FocalplaneUnits = 1; break; // millimeter - case 5: ImageInfo.FocalplaneUnits = .001; break; // micrometer - } - break; - - case TAG_EXPOSURE_BIAS: - ImageInfo.ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_WHITEBALANCE: - ImageInfo.Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_LIGHT_SOURCE: - ImageInfo.LightSource = (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_METERING_MODE: - ImageInfo.MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_EXPOSURE_PROGRAM: - ImageInfo.ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_EXPOSURE_INDEX: - if (ImageInfo.ISOequivalent == 0){ - // Exposure index and ISO equivalent are often used interchangeably, - // so we will do the same in jhead. - // http://photography.about.com/library/glossary/bldef_ei.htm - ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format); - } - break; - - case TAG_EXPOSURE_MODE: - ImageInfo.ExposureMode = (int)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_ISO_EQUIVALENT: - ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format); - if ( ImageInfo.ISOequivalent < 50 ){ - // Fixes strange encoding on some older digicams. - ImageInfo.ISOequivalent *= 200; - } - break; - - case TAG_DIGITALZOOMRATIO: - ImageInfo.DigitalZoomRatio = (float)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_THUMBNAIL_OFFSET: - ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format); - DirWithThumbnailPtrs = DirStart; - break; - - case TAG_THUMBNAIL_LENGTH: - ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format); - ImageInfo.ThumbnailSizeOffset = ValuePtr-OffsetBase; - break; - - case TAG_EXIF_OFFSET: - if (ShowTags) printf("%s Exif Dir:",IndentString); - - case TAG_INTEROP_OFFSET: - if (Tag == TAG_INTEROP_OFFSET && ShowTags) printf("%s Interop Dir:",IndentString); - { - unsigned char * SubdirStart; - SubdirStart = OffsetBase + Get32u(ValuePtr); - if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){ - ErrNonfatal("Illegal exif or interop ofset directory link",0,0); - }else{ - ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1); - } - continue; - } - break; - - case TAG_GPSINFO: - if (ShowTags) printf("%s GPS info dir:",IndentString); - { - unsigned char * SubdirStart; - SubdirStart = OffsetBase + Get32u(ValuePtr); - 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. - ImageInfo.FocalLength35mmEquiv = (unsigned)ConvertAnyFormat(ValuePtr, Format); - break; - - case TAG_DISTANCE_RANGE: - // Three possible standard values: - // 1 = macro, 2 = close, 3 = distant - ImageInfo.DistanceRange = (int)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 char * SubdirStart; - unsigned Offset; - - if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength){ - Offset = Get32u(DirStart+2+12*NumDirEntries); - if (Offset){ - 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 - if (ShowTags) printf("Thumbnail removed with Jhead 1.3 or earlier\n"); - }else{ - ErrNonfatal("Illegal subdirectory link",0,0); - } - }else{ - if (SubdirStart <= OffsetBase+ExifLength){ - if (ShowTags) printf("%s Continued directory ",IndentString); - ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1); - } - } - if (Offset > ImageInfo.LargestExifOffset){ - ImageInfo.LargestExifOffset = Offset; - } - } - }else{ - // The exif header ends before the last next directory pointer. - } - } - - if (ThumbnailOffset){ - ImageInfo.ThumbnailAtEnd = FALSE; - - if (DumpExifMap){ - printf("Map: %05d-%05d: Thumbnail\n",ThumbnailOffset, ThumbnailOffset+ThumbnailSize); - } - - if (ThumbnailOffset <= ExifLength){ - if (ThumbnailSize > ExifLength-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. - ThumbnailSize = ExifLength-ThumbnailOffset; - if (ShowTags) printf("Thumbnail incorrectly placed in header\n"); - - } - // The thumbnail pointer appears to be valid. Store it. - ImageInfo.ThumbnailOffset = ThumbnailOffset; - ImageInfo.ThumbnailSize = ThumbnailSize; - - if (ShowTags){ - printf("Thumbnail size: %d bytes\n",ThumbnailSize); - } - } - } -} - - -//-------------------------------------------------------------------------- -// Process a EXIF marker -// Describes all the drivel that most digital cameras include... -//-------------------------------------------------------------------------- -void process_EXIF (unsigned char * ExifSection, unsigned int length) -{ - int FirstOffset; - - ImageInfo.FocalplaneXRes = 0; - ImageInfo.FocalplaneUnits = 0; - ImageInfo.ExifImageWidth = 0; - NumOrientations = 0; - - if (ShowTags){ - printf("Exif header %d bytes long\n",length); - } - - { // Check the EXIF header component - static uchar ExifHeader[] = "Exif\0\0"; - if (memcmp(ExifSection+2, ExifHeader,6)){ - ErrNonfatal("Incorrect Exif header",0,0); - return; - } - } - - if (memcmp(ExifSection+8,"II",2) == 0){ - if (ShowTags) printf("Exif section in Intel order\n"); - MotorolaOrder = 0; - }else{ - if (memcmp(ExifSection+8,"MM",2) == 0){ - if (ShowTags) printf("Exif section in Motorola order\n"); - MotorolaOrder = 1; - }else{ - ErrNonfatal("Invalid Exif alignment marker.",0,0); - return; - } - } - - // Check the next value for correctness. - if (Get16u(ExifSection+10) != 0x2a){ - ErrNonfatal("Invalid Exif start (1)",0,0); - return; - } - - FirstOffset = Get32u(ExifSection+12); - if (FirstOffset < 8 || FirstOffset > 16){ - // Usually set to 8, but other values valid too. - ErrNonfatal("Suspicious offset of first IFD value",0,0); - } - - DirWithThumbnailPtrs = NULL; - - - // First directory starts 16 bytes in. All offset are relative to 8 bytes in. - ProcessExifDir(ExifSection+8+FirstOffset, ExifSection+8, length-8, 0); - - ImageInfo.ThumbnailAtEnd = ImageInfo.ThumbnailOffset >= ImageInfo.LargestExifOffset ? TRUE : FALSE; - - if (DumpExifMap){ - unsigned a,b; - printf("Map: %05d- End of exif\n",length-8); - for (a=0;a> 8); - Buffer[1] = (unsigned char)DataWriteIndex; - - // Remove old exif section, if there was one. - RemoveSectionType(M_EXIF); - - { - // Sections need malloced buffers, so do that now, especially because - // we now know how big it needs to be allocated. - unsigned char * NewBuf = (unsigned char *)malloc(DataWriteIndex); - if (NewBuf == NULL){ - ErrFatal("Could not allocate memory"); - } - memcpy(NewBuf, Buffer, DataWriteIndex); - - CreateSection(M_EXIF, NewBuf, DataWriteIndex); - - // Re-parse new exif section, now that its in place - // otherwise, we risk touching data that has already been freed. - process_EXIF(NewBuf, DataWriteIndex); - } -} - -//-------------------------------------------------------------------------- -// Cler the rotation tag in the exif header to 1. -//-------------------------------------------------------------------------- -const char * ClearOrientation(void) -{ - int a; - if (NumOrientations == 0) return NULL; - - for (a=0;atm_wday = -1; - - // Check for format: YYYY:MM:DD HH:MM:SS format. - // Date and time normally separated by a space, but also seen a ':' there, so - // skip the middle space with '%*c' so it can be any character. - a = sscanf(ExifTime, "%d%*c%d%*c%d%*c%d:%d:%d", - &timeptr->tm_year, &timeptr->tm_mon, &timeptr->tm_mday, - &timeptr->tm_hour, &timeptr->tm_min, &timeptr->tm_sec); - - - if (a == 6){ - timeptr->tm_isdst = -1; - timeptr->tm_mon -= 1; // Adjust for unix zero-based months - timeptr->tm_year -= 1900; // Adjust for year starting at 1900 - return TRUE; // worked. - } - - return FALSE; // Wasn't in Exif date format. -} - - -//-------------------------------------------------------------------------- -// Show the collected image info, displaying camera F-stop and shutter speed -// in a consistent and legible fashion. -//-------------------------------------------------------------------------- -void ShowImageInfo(int ShowFileInfo) -{ - if (ShowFileInfo){ - printf("File name : %s\n",ImageInfo.FileName); - printf("File size : %d bytes\n",ImageInfo.FileSize); - - { - char Temp[20]; - FileTimeAsString(Temp); - printf("File date : %s\n",Temp); - } - } - - if (ImageInfo.CameraMake[0]){ - printf("Camera make : %s\n",ImageInfo.CameraMake); - printf("Camera model : %s\n",ImageInfo.CameraModel); - } - if (ImageInfo.DateTime[0]){ - printf("Date/Time : %s\n",ImageInfo.DateTime); - } - printf("Resolution : %d x %d\n",ImageInfo.Width, ImageInfo.Height); - - if (ImageInfo.Orientation > 1){ - // Only print orientation if one was supplied, and if its not 1 (normal orientation) - printf("Orientation : %s\n", OrientTab[ImageInfo.Orientation]); - } - - if (ImageInfo.IsColor == 0){ - printf("Color/bw : Black and white\n"); - } - - if (ImageInfo.FlashUsed >= 0){ - if (ImageInfo.FlashUsed & 1){ - printf("Flash used : Yes"); - switch (ImageInfo.FlashUsed){ - case 0x5: printf(" (Strobe light not detected)"); break; - case 0x7: printf(" (Strobe light detected) "); break; - case 0x9: printf(" (manual)"); break; - case 0xd: printf(" (manual, return light not detected)"); break; - case 0xf: printf(" (manual, return light detected)"); break; - case 0x19:printf(" (auto)"); break; - case 0x1d:printf(" (auto, return light not detected)"); break; - case 0x1f:printf(" (auto, return light detected)"); break; - case 0x41:printf(" (red eye reduction mode)"); break; - case 0x45:printf(" (red eye reduction mode return light not detected)"); break; - case 0x47:printf(" (red eye reduction mode return light detected)"); break; - case 0x49:printf(" (manual, red eye reduction mode)"); break; - case 0x4d:printf(" (manual, red eye reduction mode, return light not detected)"); break; - case 0x4f:printf(" (red eye reduction mode, return light detected)"); break; - case 0x59:printf(" (auto, red eye reduction mode)"); break; - case 0x5d:printf(" (auto, red eye reduction mode, return light not detected)"); break; - case 0x5f:printf(" (auto, red eye reduction mode, return light detected)"); break; - } - }else{ - printf("Flash used : No"); - switch (ImageInfo.FlashUsed){ - case 0x18:printf(" (auto)"); break; - } - } - printf("\n"); - } - - - if (ImageInfo.FocalLength){ - printf("Focal length : %4.1fmm",(double)ImageInfo.FocalLength); - if (ImageInfo.FocalLength35mmEquiv){ - printf(" (35mm equivalent: %dmm)", ImageInfo.FocalLength35mmEquiv); - } - printf("\n"); - } - - if (ImageInfo.DigitalZoomRatio > 1){ - // Digital zoom used. Shame on you! - printf("Digital Zoom : %1.3fx\n", (double)ImageInfo.DigitalZoomRatio); - } - - if (ImageInfo.CCDWidth){ - printf("CCD width : %4.2fmm\n",(double)ImageInfo.CCDWidth); - } - - if (ImageInfo.ExposureTime){ - if (ImageInfo.ExposureTime < 0.010){ - printf("Exposure time: %6.4f s ",(double)ImageInfo.ExposureTime); - }else{ - printf("Exposure time: %5.3f s ",(double)ImageInfo.ExposureTime); - } - if (ImageInfo.ExposureTime <= 0.5){ - printf(" (1/%d)",(int)(0.5 + 1/ImageInfo.ExposureTime)); - } - printf("\n"); - } - if (ImageInfo.ApertureFNumber){ - printf("Aperture : f/%3.1f\n",(double)ImageInfo.ApertureFNumber); - } - if (ImageInfo.Distance){ - if (ImageInfo.Distance < 0){ - printf("Focus dist. : Infinite\n"); - }else{ - printf("Focus dist. : %4.2fm\n",(double)ImageInfo.Distance); - } - } - - if (ImageInfo.ISOequivalent){ - printf("ISO equiv. : %2d\n",(int)ImageInfo.ISOequivalent); - } - - if (ImageInfo.ExposureBias){ - // If exposure bias was specified, but set to zero, presumably its no bias at all, - // so only show it if its nonzero. - printf("Exposure bias: %4.2f\n",(double)ImageInfo.ExposureBias); - } - - switch(ImageInfo.Whitebalance) { - case 1: - printf("Whitebalance : Manual\n"); - break; - case 0: - printf("Whitebalance : Auto\n"); - break; - } - - //Quercus: 17-1-2004 Added LightSource, some cams return this, whitebalance or both - switch(ImageInfo.LightSource) { - case 1: - printf("Light Source : Daylight\n"); - break; - case 2: - printf("Light Source : Fluorescent\n"); - break; - case 3: - printf("Light Source : Incandescent\n"); - break; - case 4: - printf("Light Source : Flash\n"); - break; - case 9: - printf("Light Source : Fine weather\n"); - break; - case 11: - printf("Light Source : Shade\n"); - break; - default:; //Quercus: 17-1-2004 There are many more modes for this, check Exif2.2 specs - // If it just says 'unknown' or we don't know it, then - // don't bother showing it - it doesn't add any useful information. - } - - if (ImageInfo.MeteringMode){ // 05-jan-2001 vcs - switch(ImageInfo.MeteringMode) { - case 2: - printf("Metering Mode: center weight\n"); - break; - case 3: - printf("Metering Mode: spot\n"); - break; - case 5: - printf("Metering Mode: matrix\n"); - break; - } - } - - if (ImageInfo.ExposureProgram){ // 05-jan-2001 vcs - switch(ImageInfo.ExposureProgram) { - case 1: - printf("Exposure : Manual\n"); - break; - case 2: - printf("Exposure : program (auto)\n"); - break; - case 3: - printf("Exposure : aperture priority (semi-auto)\n"); - break; - case 4: - printf("Exposure : shutter priority (semi-auto)\n"); - break; - case 5: - printf("Exposure : Creative Program (based towards depth of field)\n"); - break; - case 6: - printf("Exposure : Action program (based towards fast shutter speed)\n"); - break; - case 7: - printf("Exposure : Portrait Mode\n"); - break; - case 8: - printf("Exposure : LandscapeMode \n"); - break; - default: - break; - } - } - switch(ImageInfo.ExposureMode){ - case 0: // Automatic (not worth cluttering up output for) - break; - case 1: printf("Exposure Mode: Manual\n"); - break; - case 2: printf("Exposure Mode: Auto bracketing\n"); - break; - } - - if (ImageInfo.DistanceRange) { - printf("Focus range : "); - switch(ImageInfo.DistanceRange) { - case 1: - printf("macro"); - break; - case 2: - printf("close"); - break; - case 3: - printf("distant"); - break; - } - printf("\n"); - } - - - - if (ImageInfo.Process != M_SOF0){ - // don't show it if its the plain old boring 'baseline' process, but do - // show it if its something else, like 'progressive' (used on web sometimes) - int a; - for (a=0;;a++){ - if (a >= PROCESS_TABLE_SIZE){ - // ran off the end of the table. - printf("Jpeg process : Unknown\n"); - break; - } - if (ProcessTable[a].Tag == ImageInfo.Process){ - printf("Jpeg process : %s\n",ProcessTable[a].Desc); - break; - } - } - } - - if (ImageInfo.GpsInfoPresent){ - printf("GPS Latitude : %s\n",ImageInfo.GpsLat); - printf("GPS Longitude: %s\n",ImageInfo.GpsLong); - if (ImageInfo.GpsAlt[0]) printf("GPS Altitude : %s\n",ImageInfo.GpsAlt); - } - - // Print the comment. Print 'Comment:' for each new line of comment. - if (ImageInfo.Comments[0]){ - int a,c; - printf("Comment : "); - if (!ImageInfo.CommentWidchars){ - for (a=0;a= 0 && ImageInfo.FlashUsed & 1){ - printf(" (flash)"); - } - - if (ImageInfo.IsColor == 0){ - printf(" (bw)"); - } - - printf("\n"); -} diff --git a/wrap/Exif/src/gpsinfo.cpp b/wrap/Exif/src/gpsinfo.cpp deleted file mode 100644 index 04b07456..00000000 --- a/wrap/Exif/src/gpsinfo.cpp +++ /dev/null @@ -1,217 +0,0 @@ -//-------------------------------------------------------------------------- -// Parsing of GPS info from exif header. -// -// Matthias Wandel, Dec 1999 - Dec 2002 -//-------------------------------------------------------------------------- -#include "../include/Exif/jhead.h" - -#define MAX_GPS_TAG 0x1e - - -#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 - - -static const char * GpsTags[MAX_GPS_TAG+1]= { - "VersionID ",//0x00 - "LatitudeRef ",//0x01 - "Latitude ",//0x02 - "LongitudeRef ",//0x03 - "Longitude ",//0x04 - "AltitudeRef ",//0x05 - "Altitude ",//0x06 - "TimeStamp ",//0x07 - "Satellites ",//0x08 - "Status ",//0x09 - "MeasureMode ",//0x0A - "DOP ",//0x0B - "SpeedRef ",//0x0C - "Speed ",//0x0D - "TrackRef ",//0x0E - "Track ",//0x0F - "ImgDirectionRef ",//0x10 - "ImgDirection ",//0x11 - "MapDatum ",//0x12 - "DestLatitudeRef ",//0x13 - "DestLatitude ",//0x14 - "DestLongitudeRef",//0x15 - "DestLongitude ",//0x16 - "DestBearingRef ",//0x17 - "DestBearing ",//0x18 - "DestDistanceRef ",//0x19 - "DestDistance ",//0x1A - "ProcessingMethod",//0x1B - "AreaInformation ",//0x1C - "DateStamp ",//0x1D - "Differential ",//0x1E -}; - -//-------------------------------------------------------------------------- -// Process GPS info directory -//-------------------------------------------------------------------------- -void ProcessGpsInfo(unsigned char * DirStart, int ByteCountUnused, unsigned char * OffsetBase, unsigned ExifLength) -{ - int de; - unsigned a; - int NumDirEntries; - - NumDirEntries = Get16u(DirStart); - #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry)) - - if (ShowTags){ - printf("(dir has %d entries)\n",NumDirEntries); - } - - ImageInfo.GpsInfoPresent = TRUE; - strcpy(ImageInfo.GpsLat, "? ?"); - strcpy(ImageInfo.GpsLong, "? ?"); - ImageInfo.GpsAlt[0] = 0; - - for (de=0;de OffsetBase+ExifLength){ - ErrNonfatal("GPS info directory goes past end of exif",0,0); - return; - } - - Tag = Get16u(DirEntry); - Format = Get16u(DirEntry+2); - Components = Get32u(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; - } - - ComponentSize = BytesPerFormat[Format]; - ByteCount = Components * ComponentSize; - - if (ByteCount > 4){ - unsigned OffsetVal; - OffsetVal = Get32u(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){ - char FmtString[21]; - char TempString[50]; - double Values[3]; - - case TAG_GPS_LAT_REF: - ImageInfo.GpsLat[0] = ValuePtr[0]; - break; - - case TAG_GPS_LONG_REF: - ImageInfo.GpsLong[0] = ValuePtr[0]; - break; - - case TAG_GPS_LAT: - case TAG_GPS_LONG: - if (Format != FMT_URATIONAL){ - ErrNonfatal("Inappropriate format (%d) for GPS coordinates!", Format, 0); - } - strcpy(FmtString, "%0.0fd %0.0fm %0.0fs"); - for (a=0;a<3;a++){ - int den, digits; - - den = Get32s(ValuePtr+4+a*ComponentSize); - digits = 0; - while (den > 1 && digits <= 6){ - den = den / 10; - digits += 1; - } - if (digits > 6) digits = 6; - FmtString[1+a*7] = (char)('2'+digits+(digits ? 1 : 0)); - FmtString[3+a*7] = (char)('0'+digits); - - Values[a] = ConvertAnyFormat(ValuePtr+a*ComponentSize, Format); - } - - sprintf(TempString, FmtString, Values[0], Values[1], Values[2]); - - if (Tag == TAG_GPS_LAT){ - strncpy(ImageInfo.GpsLat+2, TempString, 29); - }else{ - strncpy(ImageInfo.GpsLong+2, TempString, 29); - } - break; - - case TAG_GPS_ALT_REF: - ImageInfo.GpsAlt[0] = (char)(ValuePtr[0] ? '-' : ' '); - break; - - case TAG_GPS_ALT: - sprintf(ImageInfo.GpsAlt + 1, "%.2fm", - ConvertAnyFormat(ValuePtr, Format)); - break; - } - - if (ShowTags){ - // Show tag value. - if (Tag < MAX_GPS_TAG){ - printf(" GPS%s =", GpsTags[Tag]); - }else{ - // Show unknown tag - printf(" Illegal GPS tag %04x=", Tag); - } - - switch(Format){ - case FMT_UNDEFINED: - // Undefined is typically an ascii string. - - case FMT_STRING: - // String arrays printed without function call (different from int arrays) - { - printf("\""); - for (a=0;a= 32){ - if (ZeroSkipped){ - printf("?"); - ZeroSkipped = 0; - } - putchar(ValuePtr[a]); - }else{ - if (ValuePtr[a] == 0){ - ZeroSkipped = 1; - } - } - } - printf("\"\n"); - } - break; - - default: - // Handle arrays of numbers later (will there ever be?) - for (a=0;;){ - PrintFormatNumber(ValuePtr+a*ComponentSize, Format, ByteCount); - if (++a >= Components) break; - printf(", "); - } - printf("\n"); - } - } - } -} - - diff --git a/wrap/Exif/src/iptc.cpp b/wrap/Exif/src/iptc.cpp deleted file mode 100644 index f62cddda..00000000 --- a/wrap/Exif/src/iptc.cpp +++ /dev/null @@ -1,205 +0,0 @@ -//-------------------------------------------------------------------------- -// Process IPTC data and XMP data. -//-------------------------------------------------------------------------- -#include "../include/Exif/jhead.h" - -// IPTC entry types known to Jhead (there's many more defined) -#define IPTC_RECORD_VERSION 0x00 -#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 -#define IPTC_TIME_CREATED 0x3C -#define IPTC_SUB_LOCATION 0x5C -#define IPTC_IMAGE_TYPE 0x82 - -//-------------------------------------------------------------------------- -// Process and display IPTC 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 -// -//-------------------------------------------------------------------------- -void show_IPTC (unsigned char* Data, unsigned int itemlen) -{ - const char IptcSig1[] = "Photoshop 3.0"; - const char IptcSig2[] = "8BIM"; - const char IptcSig3[] = {0x04, 0x04}; - - unsigned char * pos = Data + sizeof(short); // position data pointer after length field - unsigned char * maxpos = Data+itemlen; - char headerLen = 0; - - if (itemlen < 25) goto corrupt; - - // Check IPTC signatures - if (memcmp(pos, IptcSig1, sizeof(IptcSig1)-1) != 0) goto badsig; - pos += sizeof(IptcSig1); // move data pointer to the next field - - if (memcmp(pos, IptcSig2, sizeof(IptcSig2)-1) != 0) goto badsig; - pos += sizeof(IptcSig2)-1; // move data pointer to the next field - - if (memcmp(pos, IptcSig3, sizeof(IptcSig3)) != 0){ -badsig: - if (ShowTags){ - ErrNonfatal("IPTC type signature mismatch\n",0,0); - } - return; - } - pos += sizeof(IptcSig3); // move data pointer to the next field - - if (pos >= maxpos) goto corrupt; - - // IPTC section found - - // Skip header - 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) - - if (pos+4 >= maxpos) goto corrupt; - - // Get length (from motorola format) - //length = (*pos << 24) | (*(pos+1) << 16) | (*(pos+2) << 8) | *(pos+3); - - pos += 4; // move data pointer to the next field - - printf("======= IPTC data: =======\n"); - - // Now read IPTC data - while (pos < (Data + itemlen-5)) { - short signature; - unsigned char type = 0; - short length = 0; - char * description = NULL; - - if (pos+5 > maxpos) goto corrupt; - - signature = (*pos << 8) + (*(pos+1)); - pos += 2; - - if (signature != 0x1C02){ - break; - } - - type = *pos++; - length = (*pos << 8) + (*(pos+1)); - pos += 2; // Skip tag length - - if (pos+length > maxpos) goto corrupt; - // Process tag here - switch (type) { - case IPTC_RECORD_VERSION: - printf("Record vers. : %d\n", (*pos << 8) + (*(pos+1))); - break; - - case IPTC_SUPLEMENTAL_CATEGORIES: description = (char*)"SuplementalCategories"; break; - case IPTC_KEYWORDS: description = (char*)"Keywords"; break; - case IPTC_CAPTION: description = (char*)"Caption"; break; - case IPTC_AUTHOR: description = (char*)"Author"; break; - case IPTC_HEADLINE: description = (char*)"Headline"; break; - case IPTC_SPECIAL_INSTRUCTIONS: description = (char*)"Spec. Instr."; break; - case IPTC_CATEGORY: description = (char*)"Category"; break; - case IPTC_BYLINE: description = (char*)"Byline"; break; - case IPTC_BYLINE_TITLE: description = (char*)"Byline Title"; break; - case IPTC_CREDIT: description = (char*)"Credit"; break; - case IPTC_SOURCE: description = (char*)"Source"; break; - case IPTC_COPYRIGHT_NOTICE: description = (char*)"(C)Notice"; break; - case IPTC_OBJECT_NAME: description = (char*)"Object Name"; break; - case IPTC_CITY: description = (char*)"City"; break; - case IPTC_STATE: description = (char*)"State"; break; - case IPTC_COUNTRY: description = (char*)"Country"; break; - case IPTC_TRANSMISSION_REFERENCE: description = (char*)"OriginalTransmissionReference"; break; - case IPTC_DATE: description = (char*)"DateCreated"; break; - case IPTC_COPYRIGHT: description = (char*)"(C)Flag"; break; - case IPTC_REFERENCE_SERVICE: description = (char*)"Country Code"; break; - case IPTC_COUNTRY_CODE: description = (char*)"Ref. Service"; break; - case IPTC_TIME_CREATED: description = (char*)"Time Created"; break; - case IPTC_SUB_LOCATION: description = (char*)"Sub Location"; break; - case IPTC_IMAGE_TYPE: description = (char*)"Image type"; break; - - default: - if (ShowTags){ - printf("Unrecognised IPTC tag: %d\n", type ); - } - break; - } - if (description != NULL) { - char TempBuf[32]; - memset(TempBuf, 0, sizeof(TempBuf)); - memset(TempBuf, ' ', 14); - memcpy(TempBuf, description, strlen(description)); - strcat(TempBuf, ":"); - printf("%s %*.*s\n", TempBuf, length, length, pos); - } - pos += length; - } - return; -corrupt: - ErrNonfatal("Pointer corruption in IPTC\n",0,0); -} - - - -//-------------------------------------------------------------------------- -// Dump contents of XMP section -//-------------------------------------------------------------------------- -void ShowXmp(Section_t XmpSection) -{ - unsigned char * Data; - char OutLine[101]; - int OutLineChars; - int NonBlank; - unsigned a; - NonBlank = 0; - Data = XmpSection.Data; - OutLineChars = 0; - - - for (a=0;a= 32 && Data[a] < 128){ - OutLine[OutLineChars++] = Data[a]; - if (Data[a] != ' ') NonBlank |= 1; - }else{ - if (Data[a] != '\n'){ - OutLine[OutLineChars++] = '?'; - } - } - if (Data[a] == '\n' || OutLineChars >= 100){ - OutLine[OutLineChars] = 0; - if (NonBlank){ - puts(OutLine); - } - NonBlank = (NonBlank & 1) << 1; - OutLineChars = 0; - } - } -} diff --git a/wrap/Exif/src/jhead.cpp b/wrap/Exif/src/jhead.cpp deleted file mode 100644 index a63aac23..00000000 --- a/wrap/Exif/src/jhead.cpp +++ /dev/null @@ -1,1558 +0,0 @@ -//-------------------------------------------------------------------------- -// Program to pull the information out of various types of EXIF digital -// camera files and show it in a reasonably consistent way -// -// Version 2.86 -// -// Compiling under Windows: -// Make sure you have Microsoft's compiler on the path, then run make.bat -// -// Dec 1999 - Mar 2009 -// -// by Matthias Wandel www.sentex.net/~mwandel -//-------------------------------------------------------------------------- -#include "../include/Exif/jhead.h" - -#include - -#define JHEAD_VERSION "2.87" - -// This #define turns on features that are too very specific to -// how I organize my photos. Best to ignore everything inside #ifdef MATTHIAS -//#define MATTHIAS - -#ifdef _WIN32 - #include -#endif - -static int FilesMatched; -static int FileSequence; - -static const char * CurrentFile; - -//static const char * progname; // program name for error messages - -//-------------------------------------------------------------------------- -// Command line options flags -static int TrimExif = FALSE; // Cut off exif beyond interesting data. -static int RenameToDate = 0; // 1=rename, 2=rename all. -#ifdef _WIN32 -static int RenameAssociatedFiles = FALSE; -#endif -static char * strftime_args = NULL; // Format for new file name. -static int Exif2FileTime = FALSE; -static int DoModify = FALSE; -static int DoReadAction = FALSE; - int ShowTags = FALSE; // Do not show raw by default. -static int Quiet = FALSE; // Be quiet on success (like unix programs) - int DumpExifMap = FALSE; -static int ShowConcise = FALSE; -static int CreateExifSection = FALSE; -static char * ApplyCommand = NULL; // Apply this command to all images. -static char * FilterModel = NULL; -static int ExifOnly = FALSE; -static int PortraitOnly = FALSE; -static time_t ExifTimeAdjust = 0; // Timezone adjust -static time_t ExifTimeSet = 0; // Set exif time to a value. -static char DateSet[11]; -static unsigned DateSetChars = 0; -static unsigned FileTimeToExif = FALSE; - -static int DeleteComments = FALSE; -static int DeleteExif = FALSE; -static int DeleteIptc = FALSE; -static int DeleteXmp = FALSE; -static int DeleteUnknown = FALSE; -static char * ThumbSaveName = NULL; // If not NULL, use this string to make up - // the filename to store the thumbnail to. - -static char * ThumbInsertName = NULL; // If not NULL, use this string to make up - // the filename to retrieve the thumbnail from. - -static int RegenThumbnail = FALSE; - -static char * ExifXferScrFile = NULL;// Extract Exif header from this file, and - // put it into the Jpegs processed. - -static int EditComment = FALSE; // Invoke an editor for editing the comment -static int SupressNonFatalErrors = FALSE; // Wether or not to pint warnings on recoverable errors - -static char * CommentSavefileName = NULL; // Save comment to this file. -static char * CommentInsertfileName = NULL; // Insert comment from this file. -static char * CommentInsertLiteral = NULL; // Insert this comment (from command line) - -static int AutoRotate = FALSE; -static int ZeroRotateTagOnly = FALSE; - -static int ShowFileInfo = TRUE; // Indicates to show standard file info - // (file name, file size, file date) - - -#ifdef MATTHIAS - // This #ifdef to take out less than elegant stuff for editing - // the comments in a JPEG. The programs rdjpgcom and wrjpgcom - // included with Linux distributions do a better job. - - static char * AddComment = NULL; // Add this tag. - static char * RemComment = NULL; // Remove this tag - static int AutoResize = FALSE; -#endif // MATTHIAS - -//-------------------------------------------------------------------------- -// Error exit handler -//-------------------------------------------------------------------------- -void ErrFatal(const char * msg) -{ - fprintf(stderr,"\nError : %s\n", msg); - if (CurrentFile) fprintf(stderr,"in file '%s'\n",CurrentFile); - exit(EXIT_FAILURE); -} - -//-------------------------------------------------------------------------- -// Report non fatal errors. Now that microsoft.net modifies exif headers, -// there's corrupted ones, and there could be more in the future. -//-------------------------------------------------------------------------- -void ErrNonfatal(const char * msg, int a1, int a2) -{ - if (SupressNonFatalErrors) return; - - fprintf(stderr,"\nNonfatal Error : "); - if (CurrentFile) fprintf(stderr,"'%s' ",CurrentFile); - fprintf(stderr, msg, a1, a2); - fprintf(stderr, "\n"); -} - - -//-------------------------------------------------------------------------- -// Invoke an editor for editing a string. -//-------------------------------------------------------------------------- -static int FileEditComment(char * TempFileName, char * Comment, int CommentSize) -{ - FILE * file; - int a; - char QuotedPath[PATH_MAX+10]; - - file = fopen(TempFileName, "w"); - if (file == NULL){ - fprintf(stderr, "Can't create file '%s'\n",TempFileName); - ErrFatal("could not create temporary file"); - } - fwrite(Comment, CommentSize, 1, file); - - fclose(file); - - fflush(stdout); // So logs are contiguous. - - { - char * Editor; - Editor = getenv("EDITOR"); - if (Editor == NULL){ -#ifdef _WIN32 - Editor = (char*)"notepad"; -#else - Editor = "vi"; -#endif - } - if (strlen(Editor) > PATH_MAX) ErrFatal("env too long"); - - sprintf(QuotedPath, "%s \"%s\"",Editor, TempFileName); - a = system(QuotedPath); - } - - if (a != 0){ - perror("Editor failed to launch"); - exit(-1); - } - - file = fopen(TempFileName, "r"); - if (file == NULL){ - ErrFatal("could not open temp file for read"); - } - - // Read the file back in. - CommentSize = fread(Comment, 1, 999, file); - - fclose(file); - - unlink(TempFileName); - - return CommentSize; -} - -//-------------------------------------------------------------------------- -// Escape an argument such that it is interpreted literally by the shell -// (returns the number of written characters) -//-------------------------------------------------------------------------- -static int shellescape(char* to, const char* from) -{ - int i, j; - i = j = 0; - - // Enclosing characters in double quotes preserves the literal value of - // all characters within the quotes, with the exception of $, `, and \. - to[j++] = '"'; - while(from[i]) - { -#ifdef _WIN32 - // Under WIN32, there isn't really anything dangerous you can do with - // escape characters, plus windows users aren't as sercurity paranoid. - // Hence, no need to do fancy escaping. - to[j++] = from[i++]; -#else - switch(from[i]) { - case '"': - case '$': - case '`': - case '\\': - to[j++] = '\\'; - // Fallthru... - default: - to[j++] = from[i++]; - } -#endif - if (j >= PATH_MAX) ErrFatal("max path exceeded"); - } - to[j++] = '"'; - return j; -} - - -//-------------------------------------------------------------------------- -// Apply the specified command to the JPEG file. -//-------------------------------------------------------------------------- -static void DoCommand(const char * FileName, int ShowIt) -{ - int a,e; - char ExecString[PATH_MAX*3]; - char TempName[PATH_MAX+10]; - int TempUsed = FALSE; - - e = 0; - - // Generate an unused temporary file name in the destination directory - // (a is the number of characters to copy from FileName) - a = strlen(FileName)-1; - while(a > 0 && FileName[a-1] != SLASH) a--; - memcpy(TempName, FileName, a); - strcpy(TempName+a, "XXXXXX"); - mktemp(TempName); - if(!TempName[0]) { - ErrFatal("Cannot find available temporary file name"); - } - - - - // Build the exec string. &i and &o in the exec string get replaced by input and output files. - for (a=0;;a++){ - if (ApplyCommand[a] == '&'){ - if (ApplyCommand[a+1] == 'i'){ - // Input file. - e += shellescape(ExecString+e, FileName); - a += 1; - continue; - } - if (ApplyCommand[a+1] == 'o'){ - // Needs an output file distinct from the input file. - e += shellescape(ExecString+e, TempName); - a += 1; - TempUsed = TRUE; - continue; - } - } - ExecString[e++] = ApplyCommand[a]; - if (ApplyCommand[a] == 0) break; - } - - if (ShowIt) printf("Cmd:%s\n",ExecString); - - errno = 0; - a = system(ExecString); - - if (a || errno){ - // A command can however fail without errno getting set or system returning an error. - if (errno) perror("system"); - ErrFatal("Problem executing specified command"); - } - - if (TempUsed){ - // Don't delete original file until we know a new one was created by the command. - struct stat dummy; - if (stat(TempName, &dummy) == 0){ - unlink(FileName); - rename(TempName, FileName); - }else{ - ErrFatal("specified command did not produce expected output file"); - } - } -} - -//-------------------------------------------------------------------------- -// check if this file should be skipped based on contents. -//-------------------------------------------------------------------------- -static int CheckFileSkip(void) -{ - // I sometimes add code here to only process images based on certain - // criteria - for example, only to convert non progressive Jpegs to progressives, etc.. - - if (FilterModel){ - // Filtering processing by camera model. - // This feature is useful when pictures from multiple cameras are colated, - // the its found that one of the cameras has the time set incorrectly. - if (strstr(ImageInfo.CameraModel, FilterModel) == NULL){ - // Skip. - return TRUE; - } - } - - if (ExifOnly){ - // Filtering by EXIF only. Skip all files that have no Exif. - if (FindSection(M_EXIF) == NULL){ - return TRUE; - } - } - - if (PortraitOnly == 1){ - if (ImageInfo.Width > ImageInfo.Height) return TRUE; - } - - if (PortraitOnly == -1){ - if (ImageInfo.Width < ImageInfo.Height) return TRUE; - } - - return FALSE; -} - -//-------------------------------------------------------------------------- -// Subsititute original name for '&i' if present in specified name. -// This to allow specifying relative names when manipulating multiple files. -//-------------------------------------------------------------------------- -static void RelativeName(char * OutFileName, const char * NamePattern, const char * OrigName) -{ - // If the filename contains substring "&i", then substitute the - // filename for that. This gives flexibility in terms of processing - // multiple files at a time. - const char * Subst = strstr(NamePattern, "&i"); - if (Subst){ - strncpy(OutFileName, NamePattern, Subst-NamePattern); - OutFileName[Subst-NamePattern] = 0; - strncat(OutFileName, OrigName, PATH_MAX); - strncat(OutFileName, Subst+2, PATH_MAX); - }else{ - strncpy(OutFileName, NamePattern, PATH_MAX); - } -} - - -#ifdef _WIN32 -//-------------------------------------------------------------------------- -// Rename associated files -//-------------------------------------------------------------------------- -void RenameAssociated(const char * FileName, char * NewBaseName) -{ - int a; - int PathLen; - int ExtPos; - char FilePattern[_MAX_PATH+1]; - char NewName[_MAX_PATH+1]; - struct _finddata_t finddata; - long find_handle; - - for(ExtPos = strlen(FileName);FileName[ExtPos-1] != '.';){ - if (--ExtPos == 0) return; // No extension! - } - - memcpy(FilePattern, FileName, ExtPos); - FilePattern[ExtPos] = '*'; - FilePattern[ExtPos+1] = '\0'; - - for(PathLen = strlen(FileName);FileName[PathLen-1] != SLASH;){ - if (--PathLen == 0) break; - } - - find_handle = _findfirst(FilePattern, &finddata); - - for (;;){ - if (find_handle == -1) break; - - // Eliminate the obvious patterns. - if (!memcmp(finddata.name, ".",2)) goto next_file; - if (!memcmp(finddata.name, "..",3)) goto next_file; - if (finddata.attrib & _A_SUBDIR) goto next_file; - - strncpy(FilePattern+PathLen, finddata.name, PATH_MAX-PathLen); // full name with path - - strcpy(NewName, NewBaseName); - for(a = strlen(finddata.name);finddata.name[a] != '.';){ - if (--a == 0) goto next_file; - } - strncat(NewName, finddata.name+a, _MAX_PATH-strlen(NewName)); // add extension to new name - - if (rename(FilePattern, NewName) == 0){ - if (!Quiet){ - printf("%s --> %s\n",FilePattern, NewName); - } - } - - next_file: - if (_findnext(find_handle, &finddata) != 0) break; - } - _findclose(find_handle); -} -#endif - -//-------------------------------------------------------------------------- -// Handle renaming of files by date. -//-------------------------------------------------------------------------- -static void DoFileRenaming(const char * FileName) -{ - int NumAlpha = 0; - int NumDigit = 0; - int PrefixPart = 0; // Where the actual filename starts. - int ExtensionPart; // Where the file extension starts. - int a; - struct tm tm; - char NewBaseName[PATH_MAX*2]; - int AddLetter = 0; - char NewName[PATH_MAX+2]; - - ExtensionPart = strlen(FileName); - for (a=0;FileName[a];a++){ - if (FileName[a] == SLASH){ - // Don't count path component. - NumAlpha = 0; - NumDigit = 0; - PrefixPart = a+1; - } - - if (FileName[a] == '.') ExtensionPart = a; // Remember where extension starts. - - if (isalpha(FileName[a])) NumAlpha += 1; // Tally up alpha vs. digits to judge wether to rename. - if (isdigit(FileName[a])) NumDigit += 1; - } - - if (RenameToDate <= 1){ - // If naming isn't forced, ensure name is mostly digits, or leave it alone. - if (NumAlpha > 8 || NumDigit < 4){ - return; - } - } - - if (!Exif2tm(&tm, ImageInfo.DateTime)){ - printf("File '%s' contains no exif date stamp. Using file date\n",FileName); - // Use file date/time instead. - tm = *localtime(&ImageInfo.FileDateTime); - } - - - strncpy(NewBaseName, FileName, PATH_MAX); // Get path component of name. - - if (strftime_args){ - // Complicated scheme for flexibility. Just pass the args to strftime. - time_t UnixTime; - - char *s; - char pattern[PATH_MAX+20]; - int n = ExtensionPart - PrefixPart; - - // Call mktime to get weekday and such filled in. - UnixTime = mktime(&tm); - if ((int)UnixTime == -1){ - printf("Could not convert %s to unix time",ImageInfo.DateTime); - return; - } - - // Substitute "%f" for the original name (minus path & extension) - pattern[PATH_MAX-1]=0; - strncpy(pattern, strftime_args, PATH_MAX-1); - while ((s = strstr(pattern, "%f")) && strlen(pattern) + n < PATH_MAX-1){ - memmove(s + n, s + 2, strlen(s+2) + 1); - memmove(s, FileName + PrefixPart, n); - } - - { - // Sequential number renaming part. - // '%i' type pattern becomes sequence number. - int ppos = -1; - for (a=0;pattern[a];a++){ - if (pattern[a] == '%'){ - ppos = a; - }else if (pattern[a] == 'i'){ - if (ppos >= 0 && a= PATH_MAX) ErrFatal("str overflow"); - memmove(pattern+ppos+nl, pattern+a+1, l+1); - memcpy(pattern+ppos, num, nl); - break; - } - }else if (!isdigit(pattern[a])){ - ppos = -1; - } - } - } - strftime(NewName, PATH_MAX, pattern, &tm); - }else{ - // My favourite scheme. - sprintf(NewName, "%02d%02d-%02d%02d%02d", - tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); - } - - NewBaseName[PrefixPart] = 0; - CatPath(NewBaseName, NewName); - - AddLetter = isdigit(NewBaseName[strlen(NewBaseName)-1]); - for (a=0;;a++){ - char NewName[PATH_MAX+10]; - char NameExtra[3]; - struct stat dummy; - - if (a){ - // Generate a suffix for the file name if previous choice of names is taken. - // depending on wether the name ends in a letter or digit, pick the opposite to separate - // it. This to avoid using a separator character - this because any good separator - // is before the '.' in ascii, and so sorting the names would put the later name before - // the name without suffix, causing the pictures to more likely be out of order. - if (AddLetter){ - NameExtra[0] = (char)('a'-1+a); // Try a,b,c,d... for suffix if it ends in a number. - }else{ - NameExtra[0] = (char)('0'-1+a); // Try 0,1,2,3... for suffix if it ends in a latter. - } - NameExtra[1] = 0; - }else{ - NameExtra[0] = 0; - } - - sprintf(NewName, "%s%s.jpg", NewBaseName, NameExtra); - - if (!strcmp(FileName, NewName)) break; // Skip if its already this name. - - if (!EnsurePathExists(NewBaseName)){ - break; - } - - - if (stat(NewName, &dummy)){ - // This name does not pre-exist. - if (rename(FileName, NewName) == 0){ - printf("%s --> %s\n",FileName, NewName); -#ifdef _WIN32 - if (RenameAssociatedFiles){ - sprintf(NewName, "%s%s", NewBaseName, NameExtra); - RenameAssociated(FileName, NewName); - } -#endif - }else{ - printf("Error: Couldn't rename '%s' to '%s'\n",FileName, NewName); - } - break; - - } - - if (a > 25 || (!AddLetter && a > 9)){ - printf("Possible new names for for '%s' already exist\n",FileName); - break; - } - } -} - -//-------------------------------------------------------------------------- -// Rotate the image and its thumbnail -//-------------------------------------------------------------------------- -static int DoAutoRotate(const char * FileName) -{ - if (ImageInfo.Orientation >= 2 && ImageInfo.Orientation <= 8){ - const char * Argument; - Argument = ClearOrientation(); - - if (!ZeroRotateTagOnly){ - char RotateCommand[PATH_MAX*2+50]; - if (Argument == NULL){ - ErrFatal("Orientation screwup"); - } - - sprintf(RotateCommand, "jpegtran -trim -%s -outfile &o &i", Argument); - ApplyCommand = RotateCommand; - DoCommand(FileName, FALSE); - ApplyCommand = NULL; - - // Now rotate the thumbnail, if there is one. - if (ImageInfo.ThumbnailOffset && - ImageInfo.ThumbnailSize && - ImageInfo.ThumbnailAtEnd){ - // Must have a thumbnail that exists and is modifieable. - - char ThumbTempName_in[PATH_MAX+5]; - char ThumbTempName_out[PATH_MAX+5]; - - strcpy(ThumbTempName_in, FileName); - strcat(ThumbTempName_in, ".thi"); - strcpy(ThumbTempName_out, FileName); - strcat(ThumbTempName_out, ".tho"); - SaveThumbnail(ThumbTempName_in); - sprintf(RotateCommand,"jpegtran -trim -%s -outfile \"%s\" \"%s\"", - Argument, ThumbTempName_out, ThumbTempName_in); - - if (system(RotateCommand) == 0){ - // Put the thumbnail back in the header - ReplaceThumbnail(ThumbTempName_out); - } - - unlink(ThumbTempName_in); - unlink(ThumbTempName_out); - } - } - return TRUE; - } - return FALSE; -} - -//-------------------------------------------------------------------------- -// Regenerate the thumbnail using mogrify -//-------------------------------------------------------------------------- -static int RegenerateThumbnail(const char * FileName) -{ - char ThumbnailGenCommand[PATH_MAX*2+50]; - if (ImageInfo.ThumbnailOffset == 0 || ImageInfo.ThumbnailAtEnd == FALSE){ - // There is no thumbnail, or the thumbnail is not at the end. - return FALSE; - } - - sprintf(ThumbnailGenCommand, "mogrify -thumbnail %dx%d \"%s\"", - RegenThumbnail, RegenThumbnail, FileName); - - if (system(ThumbnailGenCommand) == 0){ - // Put the thumbnail back in the header - return ReplaceThumbnail(FileName); - }else{ - ErrFatal("Unable to run 'mogrify' command"); - return FALSE; - } -} - -//-------------------------------------------------------------------------- -// Set file time as exif time. -//-------------------------------------------------------------------------- -void FileTimeAsString(char * TimeStr) -{ - struct tm ts; - ts = *localtime(&ImageInfo.FileDateTime); - strftime(TimeStr, 20, "%Y:%m:%d %H:%M:%S", &ts); -} - -//-------------------------------------------------------------------------- -// Do selected operations to one file at a time. -//-------------------------------------------------------------------------- -void ProcessFile(const char * FileName) -{ - int Modified = FALSE; - ReadMode_t ReadMode; - - if (strlen(FileName) >= PATH_MAX-1){ - // Protect against buffer overruns in strcpy / strcat's on filename - ErrFatal("filename too long"); - } - - ReadMode = READ_METADATA; - CurrentFile = FileName; - FilesMatched = 1; - - ResetJpgfile(); - - // Start with an empty image information structure. - memset(&ImageInfo, 0, sizeof(ImageInfo)); - ImageInfo.FlashUsed = -1; - ImageInfo.MeteringMode = -1; - ImageInfo.Whitebalance = -1; - - // Store file date/time. - { - struct stat st; - if (stat(FileName, &st) >= 0){ - ImageInfo.FileDateTime = st.st_mtime; - ImageInfo.FileSize = st.st_size; - }else{ - ErrFatal("No such file"); - } - } - - if (DoModify || RenameToDate || Exif2FileTime){ - if (access(FileName, 2 /*W_OK*/)){ - printf("Skipping readonly file '%s'\n",FileName); - return; - } - } - - strncpy(ImageInfo.FileName, FileName, PATH_MAX); - - - if (ApplyCommand || AutoRotate){ - // Applying a command is special - the headers from the file have to be - // pre-read, then the command executed, and then the image part of the file read. - - if (!ReadJpegFile(FileName, READ_METADATA)) return; - - #ifdef MATTHIAS - if (AutoResize){ - // Automatic resize computation - to customize for each run... - if (AutoResizeCmdStuff() == 0){ - DiscardData(); - return; - } - } - #endif // MATTHIAS - - - if (CheckFileSkip()){ - DiscardData(); - return; - } - - DiscardAllButExif(); - - if (AutoRotate){ - if (DoAutoRotate(FileName)){ - Modified = TRUE; - } - }else{ - struct stat dummy; - DoCommand(FileName, Quiet ? FALSE : TRUE); - - if (stat(FileName, &dummy)){ - // The file is not there anymore. Perhaps the command - // was a delete or a move. So we are all done. - return; - } - Modified = TRUE; - } - ReadMode = READ_IMAGE; // Don't re-read exif section again on next read. - - }else if (ExifXferScrFile){ - char RelativeExifName[PATH_MAX+1]; - - // Make a relative name. - RelativeName(RelativeExifName, ExifXferScrFile, FileName); - - if(!ReadJpegFile(RelativeExifName, READ_METADATA)) return; - - DiscardAllButExif(); // Don't re-read exif section again on next read. - - Modified = TRUE; - ReadMode = READ_IMAGE; - } - - if (DoModify){ - ReadMode = ReadMode | READ_IMAGE; - } - - if (!ReadJpegFile(FileName, ReadMode)) return; - - if (CheckFileSkip()){ - DiscardData(); - return; - } - - FileSequence += 1; // Count files processed. - - if (ShowConcise){ - ShowConciseImageInfo(); - }else{ -//PB line changed, it was: if (!(DoModify || DoReadAction) || ShowTags){ - if (!(DoModify || DoReadAction) && ShowTags){ - ShowImageInfo(ShowFileInfo); - { - // if IPTC section is present, show it also. - Section_t * IptcSection; - IptcSection = FindSection(M_IPTC); - - if (IptcSection){ - show_IPTC(IptcSection->Data, IptcSection->Size); - } - } - printf("\n"); - } - } - - if (ThumbSaveName){ - char OutFileName[PATH_MAX+1]; - // Make a relative name. - RelativeName(OutFileName, ThumbSaveName, FileName); - - if (SaveThumbnail(OutFileName)){ - printf("Created: '%s'\n", OutFileName); - } - } - - if (CreateExifSection){ - // Make a new minimal exif section - create_EXIF(); - Modified = TRUE; - } - - if (RegenThumbnail){ - if (RegenerateThumbnail(FileName)){ - Modified = TRUE; - } - } - - if (ThumbInsertName){ - char ThumbFileName[PATH_MAX+1]; - // Make a relative name. - RelativeName(ThumbFileName, ThumbInsertName, FileName); - - if (ReplaceThumbnail(ThumbFileName)){ - Modified = TRUE; - } - }else if (TrimExif){ - // Deleting thumbnail is just replacing it with a null thumbnail. - if (ReplaceThumbnail(NULL)){ - Modified = TRUE; - } - } - - if ( - EditComment || CommentInsertfileName || CommentInsertLiteral){ - - Section_t * CommentSec; - char Comment[MAX_COMMENT_SIZE+1]; - int CommentSize; - - CommentSec = FindSection(M_COM); - - if (CommentSec == NULL){ - unsigned char * DummyData; - - DummyData = (uchar *) malloc(3); - DummyData[0] = 0; - DummyData[1] = 2; - DummyData[2] = 0; - CommentSec = CreateSection(M_COM, DummyData, 2); - } - - CommentSize = CommentSec->Size-2; - if (CommentSize > MAX_COMMENT_SIZE){ - fprintf(stderr, "Truncating comment at %d chars\n",MAX_COMMENT_SIZE); - CommentSize = MAX_COMMENT_SIZE; - } - - if (CommentInsertfileName){ - // Read a new comment section from file. - char CommentFileName[PATH_MAX+1]; - FILE * CommentFile; - - // Make a relative name. - RelativeName(CommentFileName, CommentInsertfileName, FileName); - - CommentFile = fopen(CommentFileName,"r"); - if (CommentFile == NULL){ - printf("Could not open '%s'\n",CommentFileName); - }else{ - // Read it in. - // Replace the section. - CommentSize = fread(Comment, 1, 999, CommentFile); - fclose(CommentFile); - if (CommentSize < 0) CommentSize = 0; - } - }else if (CommentInsertLiteral){ - strncpy(Comment, CommentInsertLiteral, MAX_COMMENT_SIZE); - CommentSize = strlen(Comment); - }else{ - memcpy(Comment, (char *)CommentSec->Data+2, CommentSize); - char EditFileName[PATH_MAX+5]; - strcpy(EditFileName, FileName); - strcat(EditFileName, ".txt"); - - CommentSize = FileEditComment(EditFileName, Comment, CommentSize); - } - - if (strcmp(Comment, (char *)CommentSec->Data+2)){ - // Discard old comment section and put a new one in. - int size; - size = CommentSize+2; - free(CommentSec->Data); - CommentSec->Size = size; - CommentSec->Data = (uchar*)malloc(size); - CommentSec->Data[0] = (uchar)(size >> 8); - CommentSec->Data[1] = (uchar)(size); - memcpy((CommentSec->Data)+2, Comment, size-2); - Modified = TRUE; - } - if (!Modified){ - printf("Comment not modified\n"); - } - } - - - if (CommentSavefileName){ - Section_t * CommentSec; - CommentSec = FindSection(M_COM); - - if (CommentSec != NULL){ - char OutFileName[PATH_MAX+1]; - FILE * CommentFile; - - // Make a relative name. - RelativeName(OutFileName, CommentSavefileName, FileName); - - CommentFile = fopen(OutFileName,"w"); - - if (CommentFile){ - fwrite((char *)CommentSec->Data+2, CommentSec->Size-2 ,1, CommentFile); - fclose(CommentFile); - }else{ - ErrFatal("Could not write comment file"); - } - }else{ - printf("File '%s' contains no comment section\n",FileName); - } - } - - if (ExifTimeAdjust || ExifTimeSet || DateSetChars || FileTimeToExif){ - if (ImageInfo.numDateTimeTags){ - struct tm tm; - time_t UnixTime; - char TempBuf[50]; - int a; - Section_t * ExifSection; - if (ExifTimeSet){ - // A time to set was specified. - UnixTime = ExifTimeSet; - }else{ - if (FileTimeToExif){ - FileTimeAsString(ImageInfo.DateTime); - } - if (DateSetChars){ - memcpy(ImageInfo.DateTime, DateSet, DateSetChars); - a = 1970; - sscanf(DateSet, "%d", &a); - if (a < 1970){ - strcpy(TempBuf, ImageInfo.DateTime); - goto skip_unixtime; - } - } - // A time offset to adjust by was specified. - if (!Exif2tm(&tm, ImageInfo.DateTime)) goto badtime; - - // Convert to unix 32 bit time value, add offset, and convert back. - UnixTime = mktime(&tm); - if ((int)UnixTime == -1) goto badtime; - UnixTime += ExifTimeAdjust; - } - tm = *localtime(&UnixTime); - - // Print to temp buffer first to avoid putting null termination in destination. - // snprintf() would do the trick, hbut not available everywhere (like FreeBSD 4.4) - sprintf(TempBuf, "%04d:%02d:%02d %02d:%02d:%02d", - tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); - -skip_unixtime: - ExifSection = FindSection(M_EXIF); - - for (a = 0; a < ImageInfo.numDateTimeTags; a++) { - uchar * Pointer; - Pointer = ExifSection->Data+ImageInfo.DateTimeOffsets[a]+8; - memcpy(Pointer, TempBuf, 19); - } - memcpy(ImageInfo.DateTime, TempBuf, 19); - - Modified = TRUE; - }else{ - printf("File '%s' contains no Exif timestamp to change\n", FileName); - } - } - - if (DeleteComments){ - if (RemoveSectionType(M_COM)) Modified = TRUE; - } - if (DeleteExif){ - if (RemoveSectionType(M_EXIF)) Modified = TRUE; - } - if (DeleteIptc){ - if (RemoveSectionType(M_IPTC)) Modified = TRUE; - } - if (DeleteXmp){ - if (RemoveSectionType(M_XMP)) Modified = TRUE; - } - if (DeleteUnknown){ - if (RemoveUnknownSections()) Modified = TRUE; - } - - - if (Modified){ - char BackupName[PATH_MAX+5]; - struct stat buf; - - if (!Quiet) printf("Modified: %s\n",FileName); - - strcpy(BackupName, FileName); - strcat(BackupName, ".t"); - - // Remove any .old file name that may pre-exist - unlink(BackupName); - - // Rename the old file. - rename(FileName, BackupName); - - // Write the new file. - WriteJpegFile(FileName); - - // Copy the access rights from original file - if (stat(BackupName, &buf) == 0){ - // set Unix access rights and time to new file - struct utimbuf mtime; - chmod(FileName, buf.st_mode); - - mtime.actime = buf.st_mtime; - mtime.modtime = buf.st_mtime; - - utime(FileName, &mtime); - } - - // Now that we are done, remove original file. - unlink(BackupName); - } - - - if (Exif2FileTime){ - // Set the file date to the date from the exif header. - if (ImageInfo.numDateTimeTags){ - // Converte the file date to Unix time. - struct tm tm; - time_t UnixTime; - struct utimbuf mtime; - if (!Exif2tm(&tm, ImageInfo.DateTime)) goto badtime; - - UnixTime = mktime(&tm); - if ((int)UnixTime == -1){ - goto badtime; - } - - mtime.actime = UnixTime; - mtime.modtime = UnixTime; - - if (utime(FileName, &mtime) != 0){ - printf("Error: Could not change time of file '%s'\n",FileName); - }else{ - if (!Quiet) printf("%s\n",FileName); - } - }else{ - printf("File '%s' contains no Exif timestamp\n", FileName); - } - } - - // Feature to rename image according to date and time from camera. - // I use this feature to put images from multiple digicams in sequence. - - if (RenameToDate){ - DoFileRenaming(FileName); - } -//PB DiscardData(); - return; -badtime: - printf("Error: Time '%s': cannot convert to Unix time\n",ImageInfo.DateTime); - DiscardData(); -} - -#if 0 //disabled because it is never called -//-------------------------------------------------------------------------- -// complain about bad state of the command line. -//-------------------------------------------------------------------------- -static void Usage (void) -{ - printf("Jhead is a program for manipulating settings and thumnails in Exif jpeg headers\n" - "used by most Digital Cameras. v"JHEAD_VERSION" Matthias Wandel, Mar 02 2009.\n" - "http://www.sentex.net/~mwandel/jhead\n" - "\n"); - - printf("Usage: %s [options] files\n", progname); - printf("Where:\n" - " files path/filenames with or without wildcards\n" - - "[options] are:\n" - "\nGENERAL METADATA:\n" - " -te Transfer exif header from another image file \n" - " Uses same name mangling as '-st' option\n" - " -dc Delete comment field (as left by progs like Photoshop & Compupic)\n" - " -de Strip Exif section (smaller JPEG file, but lose digicam info)\n" - " -di Delete IPTC section (from Photoshop, or Picasa)\n" - " -dx Deletex XMP section\n" - " -du Delete non image sections except for Exif and comment sections\n" - " -purejpg Strip all unnecessary data from jpeg (combines -dc -de and -du)\n" - " -mkexif Create new minimal exif section (overwrites pre-existing exif)\n" - " -ce Edit comment field. Uses environment variable 'editor' to\n" - " determine which editor to use. If editor not set, uses VI\n" - " under Unix and notepad with windows\n" - " -cs Save comment section to a file\n" - " -ci Insert comment section from a file. -cs and -ci use same naming\n" - " scheme as used by the -st option\n" - " -cl string Insert literal comment string\n" - - "\nDATE / TIME MANIPULATION:\n" - " -ft Set file modification time to Exif time\n" - " -dsft Set Exif time to file modification time\n" - " -n[format-string]\n" - " Rename files according to date. Uses exif date if present, file\n" - " date otherwise. If the optional format-string is not supplied,\n" - " the format is mmdd-hhmmss. If a format-string is given, it is\n" - " is passed to the 'strftime' function for formatting\n" - " In addition to strftime format codes:\n" - " '%%f' as part of the string will include the original file name\n" - " '%%i' will include a sequence number, starting from 1. You can\n" - " You can specify '%%03i' for example to get leading zeros.\n" - " This feature is useful for ordering files from multiple digicams to\n" - " sequence of taking. Only renames files whose names are mostly\n" - " numerical (as assigned by digicam)\n" - " The '.jpg' is automatically added to the end of the name. If the\n" - " destination name already exists, a letter or digit is added to \n" - " the end of the name to make it unique.\n" - " The new name may include a path as part of the name. If this path\n" - " does not exist, it will be created\n" - " -nf[format-string]\n" - " Same as -n, but rename regardless of original name\n" - " -a (Windows only) Rename files with same name but different extension\n" - " Use together with -n to rename .AVI files from exif in .THM files\n" - " for example\n" - " -ta<+|->h[:mm[:ss]]\n" - " Adjust time by h:mm backwards or forwards. Useful when having\n" - " taken pictures with the wrong time set on the camera, such as when\n" - " traveling across time zones or DST changes. Dates can be adjusted\n" - " by offsetting by 24 hours or more. For large date adjustments,\n" - " use the -da option\n" - " -da-\n" - " Adjust date by large amounts. This is used to fix photos from\n" - " cameras where the date got set back to the default camera date\n" - " by accident or battery removal.\n" - " To deal with different months and years having different numbers of\n" - " days, a simple date-month-year offset would result in unexpected\n" - " results. Instead, the difference is specified as desired date\n" - " minus original date. Date is specified as yyyy:mm:dd or as date\n" - " and time in the format yyyy:mm:dd/hh:mm:ss\n" - " -ts