Hello community, here is the log from the commit of package jhead checked in at Mon Aug 6 21:48:20 CEST 2007. -------- --- jhead/jhead.changes 2006-12-16 12:23:15.000000000 +0100 +++ /mounts/work_src_done/STABLE/jhead/jhead.changes 2007-08-06 21:47:04.449654000 +0200 @@ -1,0 +2,10 @@ +Mon Aug 6 16:12:05 CEST 2007 - sbrabec@suse.cz + +- Updated to version 2.7: + * Remove maximum jpeg sections limit + * Added -ds option + * On clearing rotation, clear the image and the optional + thumbnail rotation tags. + * Add -mkexif option to make a new exif header. + +------------------------------------------------------------------- Old: ---- jhead-2.6-strcmp.patch jhead-2.6.tar.bz2 New: ---- jhead-2.7.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ jhead.spec ++++++ --- /var/tmp/diff_new_pack.Zy3160/_old 2007-08-06 21:47:13.000000000 +0200 +++ /var/tmp/diff_new_pack.Zy3160/_new 2007-08-06 21:47:13.000000000 +0200 @@ -1,7 +1,7 @@ # -# spec file for package jhead (Version 2.6) +# spec file for package jhead (Version 2.7) # -# Copyright (c) 2006 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2007 SUSE LINUX Products GmbH, Nuernberg, Germany. # This file and all modifications and additions to the pristine # package are under the same license as the package itself. # @@ -14,13 +14,12 @@ License: Public Domain, Freeware Group: Productivity/Graphics/Other Autoreqprov: on -Version: 2.6 -Release: 12 -Requires: /usr/bin/jpegtran +Version: 2.7 +Release: 1 +Requires: %{_bindir}/jpegtran Summary: Tool to Manipulate the Nonimage Part of EXIF Compliant JPEG Files URL: http://www.sentex.net/~mwandel/jhead/ Source: %{name}-%{version}.tar.bz2 -Patch: %{name}-%{version}-strcmp.patch BuildRoot: %{_tmppath}/%{name}-%{version}-build %description @@ -38,17 +37,18 @@ Matthias Wandel <mwandel@sentex.net> %prep -%setup -%patch +%setup -q +# Let RPM compress it according to actual policy. +gunzip jhead.1.gz %build make CC="gcc $RPM_OPT_FLAGS" %install -install -d -m 755 $RPM_BUILD_ROOT/%_bindir -install -d -m 755 $RPM_BUILD_ROOT/%_mandir/man1 -install -m 755 jhead $RPM_BUILD_ROOT/%_bindir -install -m 644 jhead.1.gz $RPM_BUILD_ROOT/%_mandir/man1 +install -d -m 755 $RPM_BUILD_ROOT/%{_bindir} +install -d -m 755 $RPM_BUILD_ROOT/%{_mandir}/man1 +install -m 755 jhead $RPM_BUILD_ROOT/%{_bindir} +install -m 644 jhead.1 $RPM_BUILD_ROOT/%{_mandir}/man1 %clean rm -rf $RPM_BUILD_ROOT @@ -56,10 +56,17 @@ %files %defattr(-,root,root) %doc changes.txt readme.txt usage.html -%_bindir/jhead -%_mandir/man1/jhead.1.gz +%{_bindir}/* +%doc %{_mandir}/man1/*.* -%changelog -n jhead +%changelog +* Mon Aug 06 2007 - sbrabec@suse.cz +- Updated to version 2.7: + * Remove maximum jpeg sections limit + * Added -ds option + * On clearing rotation, clear the image and the optional + thumbnail rotation tags. + * Add -mkexif option to make a new exif header. * Sat Dec 16 2006 - prusnak@suse.cz - fixed comparison with string literal (strcmp.patch) [#226477] * Fri Oct 20 2006 - sbrabec@suse.cz ++++++ jhead-2.6.tar.bz2 -> jhead-2.7.tar.bz2 ++++++ diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/jhead-2.6/changes.txt new/jhead-2.7/changes.txt --- old/jhead-2.6/changes.txt 2006-04-30 01:14:59.000000000 +0200 +++ new/jhead-2.7/changes.txt 2007-01-12 03:54:53.000000000 +0100 @@ -267,6 +267,20 @@ -------Released version 2.6 -- April 29 2006 -------- +Sept 9 2006 +Remove maximum jpeg sections limit + +Sept 10 2006 +Added -ds option + +Oct 18 2006 +On clearing rotation, clear the image and the optinoal thumbnail rotation tags. +(some viewers use the wrong tag) + +Dec 29 2006 +Add -mkexif option to make a new exif header. + +-------Released version 2.7 -- Jan 11 2006 -------- to do: * Someday - read/write implementation of exif file system. This will allow diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/jhead-2.6/exif.c new/jhead-2.7/exif.c --- old/jhead-2.6/exif.c 2006-04-30 01:14:59.000000000 +0200 +++ new/jhead-2.7/exif.c 2007-01-12 03:54:53.000000000 +0100 @@ -34,8 +34,9 @@ static int MotorolaOrder = 0; // for fixing the rotation. -static void * OrientationPtr; -static int OrientationNumFormat; +static void * OrientationPtr[2]; +static int OrientationNumFormat[2]; +int NumOrientations = 0; typedef struct { unsigned short Tag; @@ -233,6 +234,7 @@ #define TAG_TABLE_SIZE (sizeof(TagTable) / sizeof(TagTable_t)) + //-------------------------------------------------------------------------- // Convert a 16 bit unsigned value to file's native byte order //-------------------------------------------------------------------------- @@ -649,18 +651,22 @@ break; case TAG_ORIENTATION: - if (OrientationPtr){ - // Already have orientation. The second orientation is likely - // to be that of the thumbnail image. + 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; } - ImageInfo.Orientation = (int)ConvertAnyFormat(ValuePtr, Format); - OrientationPtr = ValuePtr; - OrientationNumFormat = Format; + 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: @@ -790,7 +796,7 @@ { // 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 comitee! + // directory. this has got to be the result of a committee! unsigned char * SubdirStart; unsigned Offset; @@ -849,6 +855,7 @@ } } + //-------------------------------------------------------------------------- // Process a EXIF marker // Describes all the drivel that most digital cameras include... @@ -860,8 +867,7 @@ FocalplaneXRes = 0; FocalplaneUnits = 0; ExifImageWidth = 0; - OrientationPtr = NULL; - + NumOrientations = 0; if (ShowTags){ printf("Exif header %d bytes long\n",length); @@ -896,13 +902,13 @@ FirstOffset = Get32u(ExifSection+12); if (FirstOffset < 8 || FirstOffset > 16){ - // I used to ensure this was set to 8 (website I used indicated its 8) - // but PENTAX Optio 230 has it set differently, and uses it as offset. (Sept 11 2002) + // 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); @@ -935,44 +941,159 @@ } } + //-------------------------------------------------------------------------- -// Cler the rotation tag in the exif header to 1. -// Note: The thumbnail is NOT rotated. That would be really hard, especially -// stuffing it back into the exif header, because its size might change. +// Create minimal exif header - just date and thumbnail pointers, +// so that date and thumbnail may be filled later. //-------------------------------------------------------------------------- -const char * ClearOrientation(void) +void create_EXIF(void) { - if (OrientationPtr == NULL) return NULL; - - switch(OrientationNumFormat){ - case FMT_SBYTE: - case FMT_BYTE: - *(uchar *)OrientationPtr = 1; - break; - - case FMT_USHORT: - Put16u(OrientationPtr, 1); - break; - - case FMT_ULONG: - case FMT_SLONG: - memset(OrientationPtr, 0, 4); - // Can't be bothered to write generic Put32 if I only use it once. - if (MotorolaOrder){ - ((uchar *)OrientationPtr)[3] = 1; + char Buffer[256]; + + unsigned short NumEntries; + int DataWriteIndex; + int DirIndex; + + MotorolaOrder = 0; + + memcpy(Buffer+2, "Exif\0\0II",8); + Put16u(Buffer+10, 0x2a); + + DataWriteIndex = 16; + Put32u(Buffer+12, DataWriteIndex-8); // first IFD offset. Means start 16 bytes in. + + { + DirIndex = DataWriteIndex; + NumEntries = 2; + DataWriteIndex += 2 + NumEntries*12 + 4; + + Put16u(Buffer+DirIndex, NumEntries); // Number of entries + DirIndex += 2; + // Entries go here.... + { + // Date/time entry + Put16u(Buffer+DirIndex, TAG_DATETIME); // Tag + Put16u(Buffer+DirIndex + 2, FMT_STRING); // Format + Put32u(Buffer+DirIndex + 4, 20); // Components + Put32u(Buffer+DirIndex + 8, DataWriteIndex-8); // Pointer or value. + DirIndex += 12; + + if (ImageInfo.numDateTimeTags){ + // If we had a pre-existing exif header, use time from that. + memcpy(Buffer+DataWriteIndex, ImageInfo.DateTime, 19); + Buffer[DataWriteIndex+19] = '\0'; }else{ - ((uchar *)OrientationPtr)[0] = 1; + // Oterwise, use the file's timestamp. + FileTimeAsString(Buffer+DataWriteIndex); } - break; + DataWriteIndex += 20; + } + { + // Link to exif dir entry + Put16u(Buffer+DirIndex, TAG_EXIF_OFFSET); // Tag + Put16u(Buffer+DirIndex + 2, FMT_ULONG); // Format + Put32u(Buffer+DirIndex + 4, 1); // Components + Put32u(Buffer+DirIndex + 8, DataWriteIndex-8); // Pointer or value. + DirIndex += 12; + } - default: - return NULL; + // End of directory - contains optional link to continued directory. + Put32u(Buffer+DirIndex, 0); + } + + + { + DirIndex = DataWriteIndex; + NumEntries = 2; + DataWriteIndex += 2 + NumEntries*12 + 4; + + Put16u(Buffer+DirIndex, NumEntries); // Number of entries + DirIndex += 2; + { + // Link to exif dir entry + Put16u(Buffer+DirIndex, TAG_THUMBNAIL_OFFSET); // Tag + Put16u(Buffer+DirIndex + 2, FMT_ULONG); // Format + Put32u(Buffer+DirIndex + 4, 1); // Components + Put32u(Buffer+DirIndex + 8, DataWriteIndex-8); // Pointer or value. + DirIndex += 12; + } + + { + // Link to exif dir entry + Put16u(Buffer+DirIndex, TAG_THUMBNAIL_LENGTH); // Tag + Put16u(Buffer+DirIndex + 2, FMT_ULONG); // Format + Put32u(Buffer+DirIndex + 4, 1); // Components + Put32u(Buffer+DirIndex + 8, 0); // Pointer or value. + DirIndex += 12; + } + + // End of directory - contains optional link to continued directory. + Put32u(Buffer+DirIndex, 0); + } + + Buffer[0] = (unsigned char)(DataWriteIndex >> 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 = 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;a<NumOrientations;a++){ + switch(OrientationNumFormat[a]){ + case FMT_SBYTE: + case FMT_BYTE: + *(uchar *)(OrientationPtr[a]) = 1; + break; + + case FMT_USHORT: + Put16u(OrientationPtr[a], 1); + break; + + case FMT_ULONG: + case FMT_SLONG: + memset(OrientationPtr, 0, 4); + // Can't be bothered to write generic Put32 if I only use it once. + if (MotorolaOrder){ + ((uchar *)OrientationPtr[a])[3] = 1; + }else{ + ((uchar *)OrientationPtr[a])[0] = 1; + } + break; + + default: + return NULL; + } } return OrientTab[ImageInfo.Orientation]; } + //-------------------------------------------------------------------------- // Remove thumbnail out of the exif image. //-------------------------------------------------------------------------- @@ -1044,6 +1165,7 @@ 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. @@ -1056,9 +1178,7 @@ { char Temp[20]; - struct tm ts; - ts = *localtime(&ImageInfo.FileDateTime); - strftime(Temp, 20, "%Y:%m:%d %H:%M:%S", &ts); + FileTimeAsString(Temp); printf("File date : %s\n",Temp); } } Files old/jhead-2.6/jhead.1.gz and new/jhead-2.7/jhead.1.gz differ diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/jhead-2.6/jhead.c new/jhead-2.7/jhead.c --- old/jhead-2.6/jhead.c 2006-04-30 01:14:59.000000000 +0200 +++ new/jhead-2.7/jhead.c 2007-01-12 03:54:53.000000000 +0100 @@ -2,27 +2,25 @@ // Program to pull the information out of various types of EXIF digital // camera files and show it in a reasonably consistent way // -// Version 2.6 -// +// Version 2.7 // // Compiling under Windows: -// Make sure you have microsoft's compiler on the path, then run make.bat +// Make sure you have Microsoft's compiler on the path, then run make.bat // -// Dec 1999 - April 2006 +// Dec 1999 - Jan 2007 // // by Matthias Wandel www.sentex.net/~mwandel //-------------------------------------------------------------------------- #include <stdio.h> #include <stdlib.h> #include <memory.h> -#include <stdlib.h> #include <string.h> #include <time.h> #include <sys/stat.h> #include <errno.h> #include <ctype.h> -#define JHEAD_VERSION "2.6" +#define JHEAD_VERSION "2.7" // This #define turns on features that are too very specific to // how I organize my photos. Best to ignore everything inside #ifdef MATTHIAS @@ -61,12 +59,16 @@ int ShowTags = FALSE; // Do not show raw by default. 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 = 0; +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; @@ -77,7 +79,7 @@ static char * ThumbInsertName = NULL; // If not NULL, use this string to make up // the filename to retrieve the thumbnail from. -static int RegenThumbnail = 0; +static int RegenThumbnail = FALSE; static char * ExifXferScrFile = NULL;// Extract Exif header from this file, and // put it into the Jpegs processed. @@ -89,10 +91,10 @@ static char * CommentInsertfileName = NULL; // Insert comment from this file. static char * CommentInsertLiteral = NULL; // Insert this comment (from command line) -static int AutoRotate = 0; -static int ZeroRotateTagOnly = 0; +static int AutoRotate = FALSE; +static int ZeroRotateTagOnly = FALSE; -static int ShowFileInfo = 1; // Indicates to show standard file info +static int ShowFileInfo = TRUE; // Indicates to show standard file info // (file name, file size, file date) @@ -700,6 +702,16 @@ } //-------------------------------------------------------------------------- +// 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) @@ -709,13 +721,6 @@ CurrentFile = FileName; FilesMatched = 1; - if (DoModify || RenameToDate || Exif2FileTime){ - if (access(FileName, 2 /*W_OK*/)){ - printf("Skipping readonly file '%s'\n",FileName); - return; - } - } - ResetJpgfile(); // Start with an empty image information structure. @@ -735,6 +740,13 @@ } } + if (DoModify || RenameToDate || Exif2FileTime){ + if (access(FileName, 2 /*W_OK*/)){ + printf("Skipping readonly file '%s'\n",FileName); + return; + } + } + strncpy(ImageInfo.FileName, FileName, PATH_MAX); @@ -820,12 +832,16 @@ RelativeName(OutFileName, ThumbSaveName, FileName); if (SaveThumbnail(OutFileName)){ - if (OutFileName != "-"){ - printf("Created: '%s'\n", 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; @@ -960,19 +976,23 @@ } } - - if (ExifTimeAdjust || ExifTimeSet){ + 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 time offset to adjust by was specified. if (!Exif2tm(&tm, ImageInfo.DateTime)) goto badtime; @@ -984,10 +1004,11 @@ tm = *localtime(&UnixTime); // Print to temp buffer first to avoid putting null termination in destination. - // snprintf() would do the trick ,but not available everywhere (like FreeBSD 4.4) + // 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); + ExifSection = FindSection(M_EXIF); @@ -1111,6 +1132,7 @@ " -de Strip Exif section (smaller JPEG file, but lose digicam info)\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" @@ -1120,7 +1142,8 @@ " -cl string Insert literal comment string\n" "\nDATE / TIME MANIPULATION:\n" - " -ft Set file modification time to Exif time.\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" @@ -1158,6 +1181,8 @@ " and time in the format yyyy:mmm:dd/hh:mm:ss\n" " -ts<time> Set the Exif internal time to <time>. <time> is in the format\n" " yyyy:mm:dd-hh:mm:ss\n" + " -ds<date> Set the Exif internal date. <date> is in the format YYYY:MM:DD\n" + " or YYYY:MM or YYYY\n" "\nTHUMBNAIL MANIPULATION:\n" " -dt Remove exif integral thumbnails. Typically trims 10k\n" @@ -1305,13 +1330,15 @@ DoModify = TRUE; }else if (!strcmp(arg,"-cs")){ CommentSavefileName = argv[++argn]; - DoModify = TRUE; }else if (!strcmp(arg,"-ci")){ CommentInsertfileName = argv[++argn]; DoModify = TRUE; }else if (!strcmp(arg,"-cl")){ CommentInsertLiteral = argv[++argn]; DoModify = TRUE; + }else if (!strcmp(arg,"-mkexif")){ + CreateExifSection = TRUE; + DoModify = TRUE; // Output verbosity control }else if (!strcmp(arg,"-h")){ @@ -1409,6 +1436,19 @@ if (ExifTimeAdjust) ErrFatal("Can only use one of -da or -ta options at once"); ExifTimeAdjust = NewDate-OldDate; DoModify = TRUE; + }else if (!memcmp(arg,"-dsft",5)){ + // Set file time to date/time in exif + FileTimeToExif = TRUE; + DoModify = TRUE; + }else if (!memcmp(arg,"-ds",3)){ + // Set date feature + DateSetChars = strlen(arg)-3; + strcpy(DateSet, "0000:01:01"); + if (DateSetChars < 4 || DateSetChars > 10){ + ErrFatal("Date must be in format YYYY, YYYY:MM, or YYYY:MM:DD"); + } + memcpy(DateSet, arg+3, DateSetChars); + DoModify = TRUE; }else if (!memcmp(arg,"-ts",3)){ // Set the exif time. // Time must be specified as "yyyy:mm:dd-hh:mm:ss" diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/jhead-2.6/jhead.h new/jhead-2.7/jhead.h --- old/jhead-2.6/jhead.h 2006-04-30 01:14:59.000000000 +0200 +++ new/jhead-2.7/jhead.h 2007-01-12 03:54:53.000000000 +0100 @@ -98,6 +98,7 @@ // prototypes for jhead.c functions void ErrFatal(char * msg); void ErrNonfatal(char * msg, int a1, int a2); +void FileTimeAsString(char * TimeStr); // Prototypes for exif.c functions. int Exif2tm(struct tm * timeptr, char * ExifTime); @@ -112,6 +113,7 @@ unsigned Get32u(void * Long); int Get32s(void * Long); void Put32u(void * Value, unsigned PutValue); +void create_EXIF(void); //-------------------------------------------------------------------------- // Exif format descriptor stuff diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/jhead-2.6/jpgfile.c new/jhead-2.7/jpgfile.c --- old/jhead-2.6/jpgfile.c 2006-04-30 01:14:59.000000000 +0200 +++ new/jhead-2.7/jpgfile.c 2007-01-12 03:54:53.000000000 +0100 @@ -4,7 +4,7 @@ // // This module handles basic Jpeg file handling // -// Matthias Wandel, Dec 1999 - Dec 2002 +// Matthias Wandel //-------------------------------------------------------------------------- #include <stdio.h> #include <stdlib.h> @@ -34,8 +34,8 @@ ImageInfo_t ImageInfo; -#define MAX_SECTIONS 100 -static Section_t Sections[MAX_SECTIONS]; +static Section_t * Sections = NULL; +static int SectionsAllocated; static int SectionsRead; static int HaveAll; @@ -116,6 +116,22 @@ } +//-------------------------------------------------------------------------- +// Check sections array to see if it needs to be increased in size. +//-------------------------------------------------------------------------- +void CheckSectionsAllocated(void) +{ + if (SectionsRead > SectionsAllocated){ + ErrFatal("allocation screwup"); + } + if (SectionsRead >= SectionsAllocated){ + SectionsAllocated += SectionsAllocated/2; + Sections = (Section_t *)realloc(Sections, sizeof(Section_t)*SectionsAllocated); + if (Sections == NULL){ + ErrFatal("could not allocate data for entire image"); + } + } +} //-------------------------------------------------------------------------- @@ -128,7 +144,6 @@ a = fgetc(infile); - if (a != 0xff || fgetc(infile) != M_SOI){ return FALSE; } @@ -138,16 +153,14 @@ int ll,lh, got; uchar * Data; - if (SectionsRead >= MAX_SECTIONS){ - ErrFatal("Too many sections in jpg file"); - } + CheckSectionsAllocated(); for (a=0;a<7;a++){ marker = fgetc(infile); if (marker != 0xff) break; if (a >= 6){ - printf("too many padding bytes\n"); + fprintf(stderr,"too many padding bytes\n"); return FALSE; } } @@ -210,6 +223,7 @@ ErrFatal("could not read the rest of the image"); } + CheckSectionsAllocated(); Sections[SectionsRead].Data = Data; Sections[SectionsRead].Size = size; Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER; @@ -219,7 +233,7 @@ return TRUE; case M_EOI: // in case it's a tables-only JPEG stream - printf("No image in jpeg!\n"); + fprintf(stderr,"No image in jpeg!\n"); return FALSE; case M_COM: // Comment section @@ -284,9 +298,11 @@ void DiscardData(void) { int a; + for (a=0;a<SectionsRead;a++){ free(Sections[a].Data); } + memset(&ImageInfo, 0, sizeof(ImageInfo)); SectionsRead = 0; HaveAll = 0; @@ -310,7 +326,7 @@ // Scan the JPEG headers. ret = ReadJpegSections(infile, ReadMode); if (!ret){ - printf("Not JPEG: %s\n",FileName); + fprintf(stderr,"Not JPEG: %s\n",FileName); } fclose(infile); @@ -330,7 +346,7 @@ FILE * ThumbnailFile; if (ImageInfo.ThumbnailOffset == 0 || ImageInfo.ThumbnailSize == 0){ - printf("Image contains no thumbnail\n"); + fprintf(stderr,"Image contains no thumbnail\n"); return FALSE; } @@ -371,7 +387,7 @@ // Adding or removing of thumbnail is not possible - that would require rearranging // of the exif header, which is risky, and jhad doesn't know how to do. - printf("Image contains no thumbnail to replace - add is not possible\n"); + fprintf(stderr,"Image contains no thumbnail to replace - add is not possible\n"); return FALSE; } @@ -444,9 +460,11 @@ } SectionsRead = 0; if (ExifKeeper.Type){ + CheckSectionsAllocated(); Sections[SectionsRead++] = ExifKeeper; } if (CommentKeeper.Type){ + CheckSectionsAllocated(); Sections[SectionsRead++] = CommentKeeper; } } @@ -579,29 +597,31 @@ //-------------------------------------------------------------------------- // Add a section (assume it doesn't already exist) - used for -// adding comment sections. +// adding comment sections and exif sections //-------------------------------------------------------------------------- Section_t * CreateSection(int SectionType, unsigned char * Data, int Size) { Section_t * NewSection; int a; + int NewIndex; + NewIndex = 2; + + if (SectionType == M_EXIF) NewIndex = 0; // Exif alwas goes first! // Insert it in third position - seems like a safe place to put // things like comments. - if (SectionsRead < 2){ + if (SectionsRead < NewIndex){ ErrFatal("Too few sections!"); } - if (SectionsRead >= MAX_SECTIONS){ - ErrFatal("Too many sections!"); - } - for (a=SectionsRead;a>2;a--){ + CheckSectionsAllocated(); + for (a=SectionsRead;a>NewIndex;a--){ Sections[a] = Sections[a-1]; } SectionsRead += 1; - NewSection = Sections+2; + NewSection = Sections+NewIndex; NewSection->Type = SectionType; NewSection->Size = Size; @@ -616,7 +636,11 @@ //-------------------------------------------------------------------------- void ResetJpgfile(void) { - memset(&Sections, 0, sizeof(Sections)); + if (Sections == NULL){ + Sections = (Section_t *)malloc(sizeof(Section_t)*5); + SectionsAllocated = 5; + } + SectionsRead = 0; HaveAll = 0; } diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/jhead-2.6/myglob.c new/jhead-2.7/myglob.c --- old/jhead-2.6/myglob.c 2006-04-30 01:14:59.000000000 +0200 +++ new/jhead-2.7/myglob.c 2007-01-12 03:54:53.000000000 +0100 @@ -48,7 +48,7 @@ if (!l){ strcpy(dest, p2); }else{ - if (l+strlen(p2) > 200){ + if (l+strlen(p2) > _MAX_PATH-2){ fprintf(stderr,"Path too long\n"); exit(-1); } diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/jhead-2.6/usage.html new/jhead-2.7/usage.html --- old/jhead-2.6/usage.html 2006-04-30 01:14:59.000000000 +0200 +++ new/jhead-2.7/usage.html 2007-01-12 03:54:53.000000000 +0100 @@ -8,7 +8,7 @@ or Mac OS-X won't do anything for you - you have to <b>use it from the Command prompt</b> (or DOS prompt under Win95/98/Me) -<h3>Jhead v2.6 program Features</h3> +<h3>Jhead v2.7 program Features</h3> <ul> <li>Extracting camera settings from Exif image files <li>Able to set and/or adjust the Exif time field @@ -32,13 +32,14 @@ As most photo editing programs will wipe out the Exif header, this option can be used to re-transplant them back in after editing the photos. <br> - Like the '-st' option, this option uses a 'relative path', which is useful for doing - a batch of photos at a time. For example, if you have a directory full of digital camera - photos, before editing them, you could copy them into the subdirectory 'originals. - Then edit them (or batch convert them using mogrify). After editing, you can put the - original Exif headers back in to the whole directory of images at a time using the - incantation: - <ul> jhead -te "originals\&i" *.jpg</ul> + This feature has an interesting 'relative path' option for specifying the thumbnail name. + Whenever the <name> contains the characters '&i', jhead will substitute the original + filename for this name. This allows creating a 'relative name' when doing a whole + batch of files. For example, the incantation: + <ul>jhead -te "originals\&i" *.jpg</ul> + would transfer the exif header for each .jpg file in the originals directory by the same name, + Both Win32 and most Unix shells treat the '&' character in a special way, so you have to + put quotes around that command line option for the '&' to even be passed to the program. <tr valign=top><td><b>-dc @@ -58,6 +59,13 @@ metadata that various applications may have left in the image. A combination of the -de -dc and -du options. +<tr valign=top><td><b>-mkexif +<td>Creates minimal exif header. Exif header contains date/time, and empty thumbnail + fields only. Date/time set to file time by default. + use with -rgt option if you want the exif header to contain a thumbnail. + Note that exif header creation is very limited at this time, and no other fields + can be added to the exif header this way. + <tr valign=top><td><b>-ce <td>Edit the JPEG header comment field (note, this comment field is outside the Exif structure and can be part of Exif and non Exif style JPEG images). @@ -73,7 +81,7 @@ <tr valign=top><td><b>-ci <name> <td>Replace comment with text from file. -<tr valign=top><td><b>-cl <comment> +<tr valign=top><td><b>-cl <comment> <td>Replace comment with comment from command line. </table> @@ -82,7 +90,11 @@ <table cellpadding=5> <tr valign=top><td><b>-ft - <td>Sets the file's system time stamp to what is stored in the Exif header. +<td>Sets the file's system time stamp to what is stored in the Exif header. + +<tr valign=top><td><b>-dsft +<td>Sets the Exif timestamp to the file's timestamp. Requires an Exif header to pre-exist. + Use -mkexif option to create one if needed. <tr valign=top><td><b>-n[<fmt-string>] <td>This option causes files to be renamed according to the Exif header "DateTimeOriginal" field. @@ -131,6 +143,9 @@     jhead -n%Y%m%d-%H%M%S *.jpg<p> This will rename files matched by *.jpg according to YYYYMMDD-HHMMSS <p> + Note to Windows batch file users: '%' is used to deliminate macros in Windows batch files. You must + use %% to get one % passed to the program. So from a batch file, you would have to write "jhead -n%%Y%%m%%d-%%H%%M%%S *.jpg" + <p> For a full listing of strftime arguments, look up the strftime function. Note that some arguments to the strftime function (not listed here) produce strings with characters such as '/' and ':' that may not be valid as part of a filename on various systems. @@ -165,7 +180,9 @@ <tr valign=top><td><b>-da<date>-<date> <td>Works like -ta, but for specifying large date offsets, to be used when fixing dates from cameras where the date was set incorrectly, such as having date and time reset by battery - removal on some cameras + removal on some cameras. This feature is best for adjusting dates on pictures taken + over a large range of dates. For pictures all taken the same date, the "-ds" option + is often easier to use. <p> Because different months and years have different numbers of days in them, a simple offset for months, days, years would lead to unexpected results at times. The time offset is @@ -182,12 +199,17 @@ <ul>jhead -da2005:05:29/11:21-2002:01:01</ul> <tr valign=top><td><b>-ts<date-time> -<td>Sets the time stored in the Exif header to what is specified on the command line. - This option changes all the date fields in the Exif header. Version 2.0 and earlier - only changed the "DateTimeOriginal" (tag 0x9003) field, but too many people thought - this was a bug. Time must be specified as:<br> +<td>Sets the date and time stored in the Exif header to what is specified on the command line. + This option changes all the date fields in the Exif header. + Time must be specified as:<br> <font face=courier>     yyyy:mm:dd-hh:mm:ss</font><p> +<tr valign=top><td><b>-ds<date-time> +<td>Sets the date stored in the Exif header to what is specified on the command line. + Can be used to set date, just year and month, or just year. + Date is specified as:<br> + <font face=courier>     yyyy:mm:dd, yyyy:mm, or yyyy</font><p> + </table> <h3>Thumbnail manipulation options</h3> <table cellpadding=5> @@ -211,7 +233,8 @@ built in thumbnails to be all that useful - too low res. However, now you can see for yourself. I always generate my thumbnails using ImageMagick (see end of this page). <br> - This feature has an interesting 'relative path' option for specifying the thumbnail name. + Like the '-te' option, this feature has the 'relative path' option for specifying the + thumbnail name. Whenever the <name> contains the characters '&i', jhead will substitute the original filename for this name. This allows creating a 'relative name' when doing a whole batch of files. For example, the incantation: @@ -386,10 +409,11 @@ to create minimal Exif headers. <p> - Some CANON digital SLR cameras fail to adjust the effective sensor resolution when shooting at less + Some Canon digital SLR cameras fail to adjust the effective sensor resolution when shooting at less than full resolution, causing jhead to incorrectly miscalculate the sensor width and 35mm equivalent - focal length. Jhead usually gets blamed for this bug, but it is in fact a camera bug, and jhead - can't do much about it, and I'm not about to add camera bug specific hacks to it. + focal length. The same can result from resizing photos with Photoshop, which will manipulate + parts of the exif header. + This is often reported as a bug in Jhead, but Jhead can't do much about incorrect data. </ul> <h3>Name globbing and recursive directories under Windows</h3> @@ -464,5 +488,5 @@ </ul> <p><br> Jhead homeage: <a href="http://www.sentex.net/~mwandel/jhead">http://www.sentex.net/~mwandel/jhead</a><br> -Last Updateed: April 29 2006 +Last Updateed: Jan 11 2007 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Remember to have fun... --------------------------------------------------------------------- To unsubscribe, e-mail: opensuse-commit+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-commit+help@opensuse.org