rjhead 2.88.1 → 2.88.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,251 +0,0 @@
1
- //--------------------------------------------------------------------------
2
- // Include file for jhead program.
3
- //
4
- // This include file only defines stuff that goes across modules.
5
- // I like to keep the definitions for macros and structures as close to
6
- // where they get used as possible, so include files only get stuff that
7
- // gets used in more than one file.
8
- //--------------------------------------------------------------------------
9
- #define _CRT_SECURE_NO_DEPRECATE 1
10
-
11
- #include <stdio.h>
12
- #include <stdlib.h>
13
- #include <string.h>
14
- #include <time.h>
15
- #include <errno.h>
16
- #include <ctype.h>
17
-
18
- //--------------------------------------------------------------------------
19
-
20
- #ifdef _WIN32
21
- #include <sys/utime.h>
22
- #else
23
- #include <utime.h>
24
- #include <sys/types.h>
25
- #include <unistd.h>
26
- #include <errno.h>
27
- #include <limits.h>
28
- #endif
29
-
30
-
31
- typedef unsigned char uchar;
32
-
33
- #ifndef TRUE
34
- #define TRUE 1
35
- #define FALSE 0
36
- #endif
37
-
38
- #define MAX_COMMENT_SIZE 2000
39
-
40
- #ifdef _WIN32
41
- #define PATH_MAX _MAX_PATH
42
- #define SLASH '\\'
43
- #else
44
- #define SLASH '/'
45
- #endif
46
-
47
-
48
- //--------------------------------------------------------------------------
49
- // This structure is used to store jpeg file sections in memory.
50
- typedef struct {
51
- uchar * Data;
52
- int Type;
53
- unsigned Size;
54
- }Section_t;
55
-
56
- extern int ExifSectionIndex;
57
-
58
- extern int DumpExifMap;
59
-
60
- #define MAX_DATE_COPIES 10
61
-
62
- //--------------------------------------------------------------------------
63
- // This structure stores Exif header image elements in a simple manner
64
- // Used to store camera data as extracted from the various ways that it can be
65
- // stored in an exif header
66
- typedef struct {
67
- char FileName [PATH_MAX+1];
68
- time_t FileDateTime;
69
-
70
- struct {
71
- // Info in the jfif header.
72
- // This info is not used much - jhead used to just replace it with default
73
- // values, and over 10 years, only two people pointed this out.
74
- char Present;
75
- char ResolutionUnits;
76
- short XDensity;
77
- short YDensity;
78
- }JfifHeader;
79
-
80
- unsigned FileSize;
81
- char CameraMake [32];
82
- char CameraModel [40];
83
- char DateTime [20];
84
- int Height, Width;
85
- int Orientation;
86
- int IsColor;
87
- int Process;
88
- int FlashUsed;
89
- float FocalLength;
90
- float ExposureTime;
91
- float ApertureFNumber;
92
- float Distance;
93
- float CCDWidth;
94
- float ExposureBias;
95
- float DigitalZoomRatio;
96
- int FocalLength35mmEquiv; // Exif 2.2 tag - usually not present.
97
- int Whitebalance;
98
- int MeteringMode;
99
- int ExposureProgram;
100
- int ExposureMode;
101
- int ISOequivalent;
102
- int LightSource;
103
- int DistanceRange;
104
-
105
- float xResolution;
106
- float yResolution;
107
- int ResolutionUnit;
108
-
109
- char Comments[MAX_COMMENT_SIZE];
110
- int CommentWidthchars; // If nonzero, widechar comment, indicates number of chars.
111
-
112
- unsigned ThumbnailOffset; // Exif offset to thumbnail
113
- unsigned ThumbnailSize; // Size of thumbnail.
114
- unsigned LargestExifOffset; // Last exif data referenced (to check if thumbnail is at end)
115
-
116
- char ThumbnailAtEnd; // Exif header ends with the thumbnail
117
- // (we can only modify the thumbnail if its at the end)
118
- int ThumbnailSizeOffset;
119
-
120
- int DateTimeOffsets[MAX_DATE_COPIES];
121
- int numDateTimeTags;
122
-
123
- int GpsInfoPresent;
124
- char GpsLat[31];
125
- char GpsLong[31];
126
- char GpsAlt[20];
127
- }ImageInfo_t;
128
-
129
-
130
-
131
- #define EXIT_FAILURE 1
132
- #define EXIT_SUCCESS 0
133
-
134
- // jpgfile.c functions
135
- typedef enum {
136
- READ_METADATA = 1,
137
- READ_IMAGE = 2,
138
- READ_ALL = 3
139
- }ReadMode_t;
140
-
141
-
142
- // prototypes for jhead.c functions
143
- void ErrFatal(char * msg);
144
- void ErrNonfatal(char * msg, int a1, int a2);
145
- void FileTimeAsString(char * TimeStr);
146
-
147
- // Prototypes for exif.c functions.
148
- int Exif2tm(struct tm * timeptr, char * ExifTime);
149
- void process_EXIF (unsigned char * CharBuf, unsigned int length);
150
- int RemoveThumbnail(unsigned char * ExifSection);
151
- void ShowImageInfo(int ShowFileInfo);
152
- void ShowConciseImageInfo(void);
153
- const char * ClearOrientation(void);
154
- void PrintFormatNumber(void * ValuePtr, int Format, int ByteCount);
155
- double ConvertAnyFormat(void * ValuePtr, int Format);
156
- int Get16u(void * Short);
157
- unsigned Get32u(void * Long);
158
- int Get32s(void * Long);
159
- void Put32u(void * Value, unsigned PutValue);
160
- void create_EXIF(void);
161
-
162
- //--------------------------------------------------------------------------
163
- // Exif format descriptor stuff
164
- extern const int BytesPerFormat[];
165
- #define NUM_FORMATS 12
166
-
167
- #define FMT_BYTE 1
168
- #define FMT_STRING 2
169
- #define FMT_USHORT 3
170
- #define FMT_ULONG 4
171
- #define FMT_URATIONAL 5
172
- #define FMT_SBYTE 6
173
- #define FMT_UNDEFINED 7
174
- #define FMT_SSHORT 8
175
- #define FMT_SLONG 9
176
- #define FMT_SRATIONAL 10
177
- #define FMT_SINGLE 11
178
- #define FMT_DOUBLE 12
179
-
180
-
181
- // makernote.c prototypes
182
- extern void ProcessMakerNote(unsigned char * DirStart, int ByteCount,
183
- unsigned char * OffsetBase, unsigned ExifLength);
184
-
185
- // gpsinfo.c prototypes
186
- void ProcessGpsInfo(unsigned char * ValuePtr, int ByteCount,
187
- unsigned char * OffsetBase, unsigned ExifLength);
188
-
189
- // iptc.c prototpyes
190
- void show_IPTC (unsigned char * CharBuf, unsigned int length);
191
- void ShowXmp(Section_t XmpSection);
192
-
193
- // Prototypes for myglob.c module
194
- #ifdef _WIN32
195
- void MyGlob(const char * Pattern , void (*FileFuncParm)(const char * FileName));
196
- void SlashToNative(char * Path);
197
- #endif
198
-
199
- // Prototypes for paths.c module
200
- int EnsurePathExists(const char * FileName);
201
- void CatPath(char * BasePath, const char * FilePath);
202
-
203
- // Prototypes from jpgfile.c
204
- int ReadJpegSections (FILE * infile, ReadMode_t ReadMode);
205
- void DiscardData(void);
206
- void DiscardAllButExif(void);
207
- int ReadJpegFile(const char * FileName, ReadMode_t ReadMode);
208
- int ReplaceThumbnail(const char * ThumbFileName);
209
- int SaveThumbnail(char * ThumbFileName);
210
- int RemoveSectionType(int SectionType);
211
- int RemoveUnknownSections(void);
212
- void WriteJpegFile(const char * FileName);
213
- Section_t * FindSection(int SectionType);
214
- Section_t * CreateSection(int SectionType, unsigned char * Data, int size);
215
- void ResetJpgfile(void);
216
-
217
-
218
- // Variables from jhead.c used by exif.c
219
- extern ImageInfo_t ImageInfo;
220
- extern int ShowTags;
221
-
222
- //--------------------------------------------------------------------------
223
- // JPEG markers consist of one or more 0xFF bytes, followed by a marker
224
- // code byte (which is not an FF). Here are the marker codes of interest
225
- // in this program. (See jdmarker.c for a more complete list.)
226
- //--------------------------------------------------------------------------
227
-
228
- #define M_SOF0 0xC0 // Start Of Frame N
229
- #define M_SOF1 0xC1 // N indicates which compression process
230
- #define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use
231
- #define M_SOF3 0xC3
232
- #define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers
233
- #define M_SOF6 0xC6
234
- #define M_SOF7 0xC7
235
- #define M_SOF9 0xC9
236
- #define M_SOF10 0xCA
237
- #define M_SOF11 0xCB
238
- #define M_SOF13 0xCD
239
- #define M_SOF14 0xCE
240
- #define M_SOF15 0xCF
241
- #define M_SOI 0xD8 // Start Of Image (beginning of datastream)
242
- #define M_EOI 0xD9 // End Of Image (end of datastream)
243
- #define M_SOS 0xDA // Start Of Scan (begins compressed data)
244
- #define M_JFIF 0xE0 // Jfif marker
245
- #define M_EXIF 0xE1 // Exif marker. Also used for XMP data!
246
- #define M_XMP 0x10E1 // Not a real tag (same value in file as Exif!)
247
- #define M_COM 0xFE // COMment
248
- #define M_DQT 0xDB
249
- #define M_DHT 0xC4
250
- #define M_DRI 0xDD
251
- #define M_IPTC 0xED // IPTC marker
@@ -1,149 +0,0 @@
1
- # -----------------------------------------------------
2
- # Define static values
3
- # -----------------------------------------------------
4
-
5
- # -----------------------------------------------------
6
- # Define requirements for configure, BuildRequire,
7
- # Require and so on (depending on macros)
8
- # -----------------------------------------------------
9
-
10
- # -----------------------------------------------------
11
- # RPM-Information
12
- # -----------------------------------------------------
13
- Name: jhead
14
- Summary: Tool for handling EXIF metadata in JPEG image files
15
-
16
- Version: 2.88
17
- Release: 0
18
-
19
- Group: Libraries
20
- License: Public Domain
21
- URL: http://www.sentex.net/~mwandel/jhead/
22
-
23
- Source: http://www.sentex.net/~mwandel/jhead/%{name}-%{version}.tar.gz
24
-
25
- BuildRoot: %{_tmppath}/%{name}-%{version}-root
26
- BuildRequires: glibc-devel
27
-
28
- # -----------------------------------------------------
29
- # Package-Information (for main package)
30
- # -----------------------------------------------------
31
- %description
32
- This package provides a tool for displaying and manipulating non-image
33
- portions of EXIF format JPEG image files, as produced by most digital cameras.
34
-
35
- # -----------------------------------------------------
36
- # Prepare-Section
37
- # -----------------------------------------------------
38
- %prep
39
- %setup -q
40
-
41
- # -----------------------------------------------------
42
- # Build-Section
43
- # -----------------------------------------------------
44
- %build
45
- make %{?_smp_mflags}
46
-
47
- # -----------------------------------------------------
48
- # Install-Section
49
- # -----------------------------------------------------
50
- %install
51
- mkdir -p %{buildroot}%{_bindir}
52
- cp jhead %{buildroot}%{_bindir}
53
- mkdir -p %{buildroot}%{_mandir}/man1/
54
- cp jhead.1.gz %{buildroot}%{_mandir}/man1/
55
-
56
- # -----------------------------------------------------
57
- # Clean-Section
58
- # -----------------------------------------------------
59
- %clean
60
- rm -rf %{buildroot}
61
-
62
- # -----------------------------------------------------
63
- # Files-Section (for main package)
64
- # -----------------------------------------------------
65
- %files
66
- %defattr(0644,root,root,0755)
67
- %attr(0755,root,root) %{_bindir}/*
68
- %doc readme.txt usage.html
69
- %{_mandir}/man1/jhead.1.gz
70
-
71
- # -----------------------------------------------------
72
- # Changelog-Section
73
- # -----------------------------------------------------
74
- %changelog
75
-
76
- * Fri Nov 6 2009 - 2.88
77
- - Added ability to move files around with the -n command
78
- - Various minor bugfixes and maintenance changes
79
-
80
- * Thu Mar 3 2009 - 2.87
81
- - Added the ability to move files with the -n option
82
- - Fix a bunch of breakages from security fixes asked
83
- for by debian people
84
-
85
- * Sat Feb 14 2009 - 2.86
86
- - Added ability to move files around with the -n command
87
- - Various minor bugfixes and maintenance changes
88
-
89
- * Mon Oct 4 2008 - 2.84
90
- - decode more exif tags in -v mode
91
- - Fix gpsinfo altitude bug
92
- - Fix several potential stirng overflows
93
-
94
- * Thu Apr 03 2008 - 2.82
95
- - No longer delete XMP section on some operations
96
- - Improve IPTC display
97
- - Minor tweaks and cleanups
98
-
99
- * Tue Nov 13 2007 - 2.8
100
- - Limited IPTC handling
101
- - Added -q option
102
- - Fix handling of corrupted GPS directory.
103
- - Extract focus distance from canon makernote.
104
- - Extract subject range (pentax and fuji cameras)
105
-
106
- * Thu Jan 11 2007 - 2.7
107
- - Release version 2.7
108
-
109
- * Sat Apr 29 2006 - 2.6
110
- - Release version 2.6
111
-
112
- * Sun Jan 08 2006 - 2.5
113
- - Release version 2.5
114
-
115
- * Thu Jun 10 2005 - 2.4-2
116
- - Minor fixups.
117
-
118
- * Sun May 29 2005 - 2.4
119
- - Display gps info
120
- - Added -da optino for large date adjust
121
- - Fix time reference bug for -ta option
122
- - Fix crashes with some corrupt jpeg files
123
-
124
- * Mon Jan 03 2005 - 2.4
125
- - Handle readonly files better
126
- - Handle more strange jpegs
127
- - added 'purejpg' option
128
- - Display digital zoom ratio
129
-
130
- * Sun Jun 20 2004 - 2.2-0
131
- - Various bug and spelling fixes.
132
- - added ability to do sequential renaming
133
-
134
- * Tue Jan 08 2004 Matthias Wandel <mwandel[at]sentex.net> - 2.1-0
135
- - Bumped version number to 2.1 for new jhead release.
136
- - Added -cl feature
137
- - added -noroot feature
138
-
139
- * Tue Jun 03 2003 Oliver Pitzeier <oliver@linux-kernel.at> - 2.0-3
140
- - Specfile cleanup/beautifying
141
- - Use _smp_mflags within make
142
- - Add versions to the changelog entries
143
-
144
- * Mon Apr 14 2003 Matthias Wandel <mwandel[at]sentex.net> - 2.0-2
145
- - First jhead 2.0 RPM built by me.
146
- - Finally wrote a nice man page for jhead
147
- - Using jhead 1.9 RPM from connectiva linux as starting point (left in the portugese tags)
148
-
149
-
@@ -1,738 +0,0 @@
1
- //--------------------------------------------------------------------------
2
- // Program to pull the information out of various types of EXIF digital
3
- // camera files and show it in a reasonably consistent way
4
- //
5
- // This module handles basic Jpeg file handling
6
- //
7
- // Matthias Wandel
8
- //--------------------------------------------------------------------------
9
- #include "jhead.h"
10
-
11
- // Storage for simplified info extracted from file.
12
- ImageInfo_t ImageInfo;
13
-
14
-
15
- static Section_t * Sections = NULL;
16
- static int SectionsAllocated;
17
- static int SectionsRead;
18
- static int HaveAll;
19
-
20
-
21
-
22
- #define PSEUDO_IMAGE_MARKER 0x123; // Extra value.
23
- //--------------------------------------------------------------------------
24
- // Get 16 bits motorola order (always) for jpeg header stuff.
25
- //--------------------------------------------------------------------------
26
- static int Get16m(const void * Short)
27
- {
28
- return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
29
- }
30
-
31
-
32
- //--------------------------------------------------------------------------
33
- // Process a COM marker.
34
- // We want to print out the marker contents as legible text;
35
- // we must guard against random junk and varying newline representations.
36
- //--------------------------------------------------------------------------
37
- static void process_COM (const uchar * Data, int length)
38
- {
39
- int ch;
40
- char Comment[MAX_COMMENT_SIZE+1];
41
- int nch;
42
- int a;
43
-
44
- nch = 0;
45
-
46
- if (length > MAX_COMMENT_SIZE) length = MAX_COMMENT_SIZE; // Truncate if it won't fit in our structure.
47
-
48
- for (a=2;a<length;a++){
49
- ch = Data[a];
50
-
51
- if (ch == '\r' && Data[a+1] == '\n') continue; // Remove cr followed by lf.
52
-
53
- if (ch >= 32 || ch == '\n' || ch == '\t'){
54
- Comment[nch++] = (char)ch;
55
- }else{
56
- Comment[nch++] = '?';
57
- }
58
- }
59
-
60
- Comment[nch] = '\0'; // Null terminate
61
-
62
- if (ShowTags){
63
- printf("COM marker comment: %s\n",Comment);
64
- }
65
-
66
- strcpy(ImageInfo.Comments,Comment);
67
- ImageInfo.CommentWidthchars = 0;
68
- }
69
-
70
-
71
- //--------------------------------------------------------------------------
72
- // Process a SOFn marker. This is useful for the image dimensions
73
- //--------------------------------------------------------------------------
74
- static void process_SOFn (const uchar * Data, int marker)
75
- {
76
- int data_precision, num_components;
77
-
78
- data_precision = Data[2];
79
- ImageInfo.Height = Get16m(Data+3);
80
- ImageInfo.Width = Get16m(Data+5);
81
- num_components = Data[7];
82
-
83
- if (num_components == 3){
84
- ImageInfo.IsColor = 1;
85
- }else{
86
- ImageInfo.IsColor = 0;
87
- }
88
-
89
- ImageInfo.Process = marker;
90
-
91
- if (ShowTags){
92
- printf("JPEG image is %uw * %uh, %d color components, %d bits per sample\n",
93
- ImageInfo.Width, ImageInfo.Height, num_components, data_precision);
94
- }
95
- }
96
-
97
-
98
- //--------------------------------------------------------------------------
99
- // Check sections array to see if it needs to be increased in size.
100
- //--------------------------------------------------------------------------
101
- void CheckSectionsAllocated(void)
102
- {
103
- if (SectionsRead > SectionsAllocated){
104
- ErrFatal("allocation screwup");
105
- }
106
- if (SectionsRead >= SectionsAllocated){
107
- SectionsAllocated += SectionsAllocated/2;
108
- Sections = (Section_t *)realloc(Sections, sizeof(Section_t)*SectionsAllocated);
109
- if (Sections == NULL){
110
- ErrFatal("could not allocate data for entire image");
111
- }
112
- }
113
- }
114
-
115
-
116
- //--------------------------------------------------------------------------
117
- // Parse the marker stream until SOS or EOI is seen;
118
- //--------------------------------------------------------------------------
119
- int ReadJpegSections (FILE * infile, ReadMode_t ReadMode)
120
- {
121
- int a;
122
- int HaveCom = FALSE;
123
-
124
- a = fgetc(infile);
125
-
126
- if (a != 0xff || fgetc(infile) != M_SOI){
127
- return FALSE;
128
- }
129
-
130
- ImageInfo.JfifHeader.XDensity = ImageInfo.JfifHeader.YDensity = 300;
131
- ImageInfo.JfifHeader.ResolutionUnits = 1;
132
-
133
- for(;;){
134
- int itemlen;
135
- int prev;
136
- int marker = 0;
137
- int ll,lh, got;
138
- uchar * Data;
139
-
140
- CheckSectionsAllocated();
141
-
142
- prev = 0;
143
- for (a=0;;a++){
144
- marker = fgetc(infile);
145
- if (marker != 0xff && prev == 0xff) break;
146
- prev = marker;
147
- }
148
-
149
- if (a > 10){
150
- ErrNonfatal("Extraneous %d padding bytes before section %02X",a-1,marker);
151
- }
152
-
153
- Sections[SectionsRead].Type = marker;
154
-
155
- // Read the length of the section.
156
- lh = fgetc(infile);
157
- ll = fgetc(infile);
158
-
159
- itemlen = (lh << 8) | ll;
160
-
161
- if (itemlen < 2){
162
- ErrFatal("invalid marker");
163
- }
164
-
165
- Sections[SectionsRead].Size = itemlen;
166
-
167
- Data = (uchar *)malloc(itemlen);
168
- if (Data == NULL){
169
- ErrFatal("Could not allocate memory");
170
- }
171
- Sections[SectionsRead].Data = Data;
172
-
173
- // Store first two pre-read bytes.
174
- Data[0] = (uchar)lh;
175
- Data[1] = (uchar)ll;
176
-
177
- got = fread(Data+2, 1, itemlen-2, infile); // Read the whole section.
178
- if (got != itemlen-2){
179
- ErrFatal("Premature end of file?");
180
- }
181
- SectionsRead += 1;
182
-
183
- switch(marker){
184
-
185
- case M_SOS: // stop before hitting compressed data
186
- // If reading entire image is requested, read the rest of the data.
187
- if (ReadMode & READ_IMAGE){
188
- int cp, ep, size;
189
- // Determine how much file is left.
190
- cp = ftell(infile);
191
- fseek(infile, 0, SEEK_END);
192
- ep = ftell(infile);
193
- fseek(infile, cp, SEEK_SET);
194
-
195
- size = ep-cp;
196
- Data = (uchar *)malloc(size);
197
- if (Data == NULL){
198
- ErrFatal("could not allocate data for entire image");
199
- }
200
-
201
- got = fread(Data, 1, size, infile);
202
- if (got != size){
203
- ErrFatal("could not read the rest of the image");
204
- }
205
-
206
- CheckSectionsAllocated();
207
- Sections[SectionsRead].Data = Data;
208
- Sections[SectionsRead].Size = size;
209
- Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER;
210
- SectionsRead ++;
211
- HaveAll = 1;
212
- }
213
- return TRUE;
214
-
215
- case M_EOI: // in case it's a tables-only JPEG stream
216
- fprintf(stderr,"No image in jpeg!\n");
217
- return FALSE;
218
-
219
- case M_COM: // Comment section
220
- if (HaveCom || ((ReadMode & READ_METADATA) == 0)){
221
- // Discard this section.
222
- free(Sections[--SectionsRead].Data);
223
- }else{
224
- process_COM(Data, itemlen);
225
- HaveCom = TRUE;
226
- }
227
- break;
228
-
229
- case M_JFIF:
230
- // Regular jpegs always have this tag, exif images have the exif
231
- // marker instead, althogh ACDsee will write images with both markers.
232
- // this program will re-create this marker on absence of exif marker.
233
- // hence no need to keep the copy from the file.
234
- if (memcmp(Data+2, "JFIF\0",5)){
235
- fprintf(stderr,"Header missing JFIF marker\n");
236
- }
237
- if (itemlen < 16){
238
- fprintf(stderr,"Jfif header too short\n");
239
- goto ignore;
240
- }
241
-
242
- ImageInfo.JfifHeader.Present = TRUE;
243
- ImageInfo.JfifHeader.ResolutionUnits = Data[9];
244
- ImageInfo.JfifHeader.XDensity = (Data[10]<<8) | Data[11];
245
- ImageInfo.JfifHeader.YDensity = (Data[12]<<8) | Data[13];
246
- if (ShowTags){
247
- printf("JFIF SOI marker: Units: %d ",ImageInfo.JfifHeader.ResolutionUnits);
248
- switch(ImageInfo.JfifHeader.ResolutionUnits){
249
- case 0: printf("(aspect ratio)"); break;
250
- case 1: printf("(dots per inch)"); break;
251
- case 2: printf("(dots per cm)"); break;
252
- default: printf("(unknown)"); break;
253
- }
254
- printf(" X-density=%d Y-density=%d\n",ImageInfo.JfifHeader.XDensity, ImageInfo.JfifHeader.YDensity);
255
-
256
- if (Data[14] || Data[15]){
257
- fprintf(stderr,"Ignoring jfif header thumbnail\n");
258
- }
259
- }
260
-
261
- ignore:
262
-
263
- free(Sections[--SectionsRead].Data);
264
- break;
265
-
266
- case M_EXIF:
267
- // There can be different section using the same marker.
268
- if (ReadMode & READ_METADATA){
269
- if (memcmp(Data+2, "Exif", 4) == 0){
270
- process_EXIF(Data, itemlen);
271
- break;
272
- }else if (memcmp(Data+2, "http:", 5) == 0){
273
- Sections[SectionsRead-1].Type = M_XMP; // Change tag for internal purposes.
274
- if (ShowTags){
275
- printf("Image cotains XMP section, %d bytes long\n", itemlen);
276
- if (ShowTags){
277
- ShowXmp(Sections[SectionsRead-1]);
278
- }
279
- }
280
- break;
281
- }
282
- }
283
- // Oterwise, discard this section.
284
- free(Sections[--SectionsRead].Data);
285
- break;
286
-
287
- case M_IPTC:
288
- if (ReadMode & READ_METADATA){
289
- if (ShowTags){
290
- printf("Image cotains IPTC section, %d bytes long\n", itemlen);
291
- }
292
- // Note: We just store the IPTC section. Its relatively straightforward
293
- // and we don't act on any part of it, so just display it at parse time.
294
- }else{
295
- free(Sections[--SectionsRead].Data);
296
- }
297
- break;
298
-
299
- case M_SOF0:
300
- case M_SOF1:
301
- case M_SOF2:
302
- case M_SOF3:
303
- case M_SOF5:
304
- case M_SOF6:
305
- case M_SOF7:
306
- case M_SOF9:
307
- case M_SOF10:
308
- case M_SOF11:
309
- case M_SOF13:
310
- case M_SOF14:
311
- case M_SOF15:
312
- process_SOFn(Data, marker);
313
- break;
314
- default:
315
- // Skip any other sections.
316
- if (ShowTags){
317
- printf("Jpeg section marker 0x%02x size %d\n",marker, itemlen);
318
- }
319
- break;
320
- }
321
- }
322
- return TRUE;
323
- }
324
-
325
- //--------------------------------------------------------------------------
326
- // Discard read data.
327
- //--------------------------------------------------------------------------
328
- void DiscardData(void)
329
- {
330
- int a;
331
-
332
- for (a=0;a<SectionsRead;a++){
333
- free(Sections[a].Data);
334
- }
335
-
336
- memset(&ImageInfo, 0, sizeof(ImageInfo));
337
- SectionsRead = 0;
338
- HaveAll = 0;
339
- }
340
-
341
- //--------------------------------------------------------------------------
342
- // Read image data.
343
- //--------------------------------------------------------------------------
344
- int ReadJpegFile(const char * FileName, ReadMode_t ReadMode)
345
- {
346
- FILE * infile;
347
- int ret;
348
-
349
- infile = fopen(FileName, "rb"); // Unix ignores 'b', windows needs it.
350
-
351
- if (infile == NULL) {
352
- fprintf(stderr, "can't open '%s'\n", FileName);
353
- return FALSE;
354
- }
355
-
356
-
357
- // Scan the JPEG headers.
358
- ret = ReadJpegSections(infile, ReadMode);
359
- if (!ret){
360
- fprintf(stderr,"Not JPEG: %s\n",FileName);
361
- }
362
-
363
- fclose(infile);
364
-
365
- if (ret == FALSE){
366
- DiscardData();
367
- }
368
- return ret;
369
- }
370
-
371
-
372
- //--------------------------------------------------------------------------
373
- // Replace or remove exif thumbnail
374
- //--------------------------------------------------------------------------
375
- int SaveThumbnail(char * ThumbFileName)
376
- {
377
- FILE * ThumbnailFile;
378
-
379
- if (ImageInfo.ThumbnailOffset == 0 || ImageInfo.ThumbnailSize == 0){
380
- fprintf(stderr,"Image contains no thumbnail\n");
381
- return FALSE;
382
- }
383
-
384
- if (strcmp(ThumbFileName, "-") == 0){
385
- // A filename of '-' indicates thumbnail goes to stdout.
386
- // This doesn't make much sense under Windows, so this feature is unix only.
387
- ThumbnailFile = stdout;
388
- }else{
389
- ThumbnailFile = fopen(ThumbFileName,"wb");
390
- }
391
-
392
- if (ThumbnailFile){
393
- uchar * ThumbnailPointer;
394
- Section_t * ExifSection;
395
- ExifSection = FindSection(M_EXIF);
396
- ThumbnailPointer = ExifSection->Data+ImageInfo.ThumbnailOffset+8;
397
-
398
- fwrite(ThumbnailPointer, ImageInfo.ThumbnailSize ,1, ThumbnailFile);
399
- fclose(ThumbnailFile);
400
- return TRUE;
401
- }else{
402
- ErrFatal("Could not write thumbnail file");
403
- return FALSE;
404
- }
405
- }
406
-
407
- //--------------------------------------------------------------------------
408
- // Replace or remove exif thumbnail
409
- //--------------------------------------------------------------------------
410
- int ReplaceThumbnail(const char * ThumbFileName)
411
- {
412
- FILE * ThumbnailFile;
413
- int ThumbLen, NewExifSize;
414
- Section_t * ExifSection;
415
- uchar * ThumbnailPointer;
416
-
417
- if (ImageInfo.ThumbnailOffset == 0 || ImageInfo.ThumbnailAtEnd == FALSE){
418
- if (ThumbFileName == NULL){
419
- // Delete of nonexistent thumbnail (not even pointers present)
420
- // No action, no error.
421
- return FALSE;
422
- }
423
-
424
- // Adding or removing of thumbnail is not possible - that would require rearranging
425
- // of the exif header, which is risky, and jhad doesn't know how to do.
426
- fprintf(stderr,"Image contains no thumbnail to replace - add is not possible\n");
427
- return FALSE;
428
- }
429
-
430
- if (ThumbFileName){
431
- ThumbnailFile = fopen(ThumbFileName,"rb");
432
-
433
- if (ThumbnailFile == NULL){
434
- ErrFatal("Could not read thumbnail file");
435
- return FALSE;
436
- }
437
-
438
- // get length
439
- fseek(ThumbnailFile, 0, SEEK_END);
440
-
441
- ThumbLen = ftell(ThumbnailFile);
442
- fseek(ThumbnailFile, 0, SEEK_SET);
443
-
444
- if (ThumbLen + ImageInfo.ThumbnailOffset > 0x10000-20){
445
- ErrFatal("Thumbnail is too large to insert into exif header");
446
- }
447
- }else{
448
- if (ImageInfo.ThumbnailSize == 0){
449
- return FALSE;
450
- }
451
-
452
- ThumbLen = 0;
453
- ThumbnailFile = NULL;
454
- }
455
-
456
- ExifSection = FindSection(M_EXIF);
457
-
458
- NewExifSize = ImageInfo.ThumbnailOffset+8+ThumbLen;
459
- ExifSection->Data = (uchar *)realloc(ExifSection->Data, NewExifSize);
460
-
461
- ThumbnailPointer = ExifSection->Data+ImageInfo.ThumbnailOffset+8;
462
-
463
- if (ThumbnailFile){
464
- fread(ThumbnailPointer, ThumbLen, 1, ThumbnailFile);
465
- fclose(ThumbnailFile);
466
- }
467
-
468
- ImageInfo.ThumbnailSize = ThumbLen;
469
-
470
- Put32u(ExifSection->Data+ImageInfo.ThumbnailSizeOffset+8, ThumbLen);
471
-
472
- ExifSection->Data[0] = (uchar)(NewExifSize >> 8);
473
- ExifSection->Data[1] = (uchar)NewExifSize;
474
- ExifSection->Size = NewExifSize;
475
-
476
- return TRUE;
477
- }
478
-
479
-
480
- //--------------------------------------------------------------------------
481
- // Discard everything but the exif and comment sections.
482
- //--------------------------------------------------------------------------
483
- void DiscardAllButExif(void)
484
- {
485
- Section_t ExifKeeper;
486
- Section_t CommentKeeper;
487
- Section_t IptcKeeper;
488
- Section_t XmpKeeper;
489
- int a;
490
-
491
- memset(&ExifKeeper, 0, sizeof(ExifKeeper));
492
- memset(&CommentKeeper, 0, sizeof(CommentKeeper));
493
- memset(&IptcKeeper, 0, sizeof(IptcKeeper));
494
- memset(&XmpKeeper, 0, sizeof(IptcKeeper));
495
-
496
- for (a=0;a<SectionsRead;a++){
497
- if (Sections[a].Type == M_EXIF && ExifKeeper.Type == 0){
498
- ExifKeeper = Sections[a];
499
- }else if (Sections[a].Type == M_XMP && XmpKeeper.Type == 0){
500
- XmpKeeper = Sections[a];
501
- }else if (Sections[a].Type == M_COM && CommentKeeper.Type == 0){
502
- CommentKeeper = Sections[a];
503
- }else if (Sections[a].Type == M_IPTC && IptcKeeper.Type == 0){
504
- IptcKeeper = Sections[a];
505
- }else{
506
- free(Sections[a].Data);
507
- }
508
- }
509
- SectionsRead = 0;
510
- if (ExifKeeper.Type){
511
- CheckSectionsAllocated();
512
- Sections[SectionsRead++] = ExifKeeper;
513
- }
514
- if (CommentKeeper.Type){
515
- CheckSectionsAllocated();
516
- Sections[SectionsRead++] = CommentKeeper;
517
- }
518
- if (IptcKeeper.Type){
519
- CheckSectionsAllocated();
520
- Sections[SectionsRead++] = IptcKeeper;
521
- }
522
-
523
- if (XmpKeeper.Type){
524
- CheckSectionsAllocated();
525
- Sections[SectionsRead++] = XmpKeeper;
526
- }
527
- }
528
-
529
- //--------------------------------------------------------------------------
530
- // Write image data back to disk.
531
- //--------------------------------------------------------------------------
532
- void WriteJpegFile(const char * FileName)
533
- {
534
- FILE * outfile;
535
- int a;
536
-
537
- if (!HaveAll){
538
- ErrFatal("Can't write back - didn't read all");
539
- }
540
-
541
- outfile = fopen(FileName,"wb");
542
- if (outfile == NULL){
543
- ErrFatal("Could not open file for write");
544
- }
545
-
546
- // Initial static jpeg marker.
547
- fputc(0xff,outfile);
548
- fputc(0xd8,outfile);
549
-
550
- if (Sections[0].Type != M_EXIF && Sections[0].Type != M_JFIF){
551
- // The image must start with an exif or jfif marker. If we threw those away, create one.
552
- static uchar JfifHead[18] = {
553
- 0xff, M_JFIF,
554
- 0x00, 0x10, 'J' , 'F' , 'I' , 'F' , 0x00, 0x01,
555
- 0x01, 0x01, 0x01, 0x2C, 0x01, 0x2C, 0x00, 0x00
556
- };
557
-
558
- if (ImageInfo.ResolutionUnit == 2 || ImageInfo.ResolutionUnit == 3){
559
- // Use the exif resolution info to fill out the jfif header.
560
- // Usually, for exif images, there's no jfif header, so if wediscard
561
- // the exif header, use info from the exif header for the jfif header.
562
-
563
- ImageInfo.JfifHeader.ResolutionUnits = (char)(ImageInfo.ResolutionUnit-1);
564
- // Jfif is 1 and 2, Exif is 2 and 3 for In and cm respecively
565
- ImageInfo.JfifHeader.XDensity = (int)ImageInfo.xResolution;
566
- ImageInfo.JfifHeader.YDensity = (int)ImageInfo.yResolution;
567
- }
568
-
569
- JfifHead[11] = ImageInfo.JfifHeader.ResolutionUnits;
570
- JfifHead[12] = (uchar)(ImageInfo.JfifHeader.XDensity >> 8);
571
- JfifHead[13] = (uchar)ImageInfo.JfifHeader.XDensity;
572
- JfifHead[14] = (uchar)(ImageInfo.JfifHeader.YDensity >> 8);
573
- JfifHead[15] = (uchar)ImageInfo.JfifHeader.YDensity;
574
-
575
-
576
- fwrite(JfifHead, 18, 1, outfile);
577
-
578
- // use the values from the exif data for the jfif header, if we have found values
579
- if (ImageInfo.ResolutionUnit != 0) {
580
- // JFIF.ResolutionUnit is {1,2}, EXIF.ResolutionUnit is {2,3}
581
- JfifHead[11] = (uchar)ImageInfo.ResolutionUnit - 1;
582
- }
583
- if (ImageInfo.xResolution > 0.0 && ImageInfo.yResolution > 0.0) {
584
- JfifHead[12] = (uchar)((int)ImageInfo.xResolution>>8);
585
- JfifHead[13] = (uchar)((int)ImageInfo.xResolution);
586
-
587
- JfifHead[14] = (uchar)((int)ImageInfo.yResolution>>8);
588
- JfifHead[15] = (uchar)((int)ImageInfo.yResolution);
589
- }
590
- }
591
-
592
-
593
- // Write all the misc sections
594
- for (a=0;a<SectionsRead-1;a++){
595
- fputc(0xff,outfile);
596
- fputc((unsigned char)Sections[a].Type, outfile);
597
- fwrite(Sections[a].Data, Sections[a].Size, 1, outfile);
598
- }
599
-
600
- // Write the remaining image data.
601
- fwrite(Sections[a].Data, Sections[a].Size, 1, outfile);
602
-
603
- fclose(outfile);
604
- }
605
-
606
-
607
- //--------------------------------------------------------------------------
608
- // Check if image has exif header.
609
- //--------------------------------------------------------------------------
610
- Section_t * FindSection(int SectionType)
611
- {
612
- int a;
613
-
614
- for (a=0;a<SectionsRead;a++){
615
- if (Sections[a].Type == SectionType){
616
- return &Sections[a];
617
- }
618
- }
619
- // Could not be found.
620
- return NULL;
621
- }
622
-
623
- //--------------------------------------------------------------------------
624
- // Remove a certain type of section.
625
- //--------------------------------------------------------------------------
626
- int RemoveSectionType(int SectionType)
627
- {
628
- int a;
629
- for (a=0;a<SectionsRead-1;a++){
630
- if (Sections[a].Type == SectionType){
631
- // Free up this section
632
- free (Sections[a].Data);
633
- // Move succeding sections back by one to close space in array.
634
- memmove(Sections+a, Sections+a+1, sizeof(Section_t) * (SectionsRead-a));
635
- SectionsRead -= 1;
636
- return TRUE;
637
- }
638
- }
639
- return FALSE;
640
- }
641
-
642
- //--------------------------------------------------------------------------
643
- // Remove sectons not part of image and not exif or comment sections.
644
- //--------------------------------------------------------------------------
645
- int RemoveUnknownSections(void)
646
- {
647
- int a;
648
- int Modified = FALSE;
649
- for (a=0;a<SectionsRead-1;){
650
- switch(Sections[a].Type){
651
- case M_SOF0:
652
- case M_SOF1:
653
- case M_SOF2:
654
- case M_SOF3:
655
- case M_SOF5:
656
- case M_SOF6:
657
- case M_SOF7:
658
- case M_SOF9:
659
- case M_SOF10:
660
- case M_SOF11:
661
- case M_SOF13:
662
- case M_SOF14:
663
- case M_SOF15:
664
- case M_SOI:
665
- case M_EOI:
666
- case M_SOS:
667
- case M_JFIF:
668
- case M_EXIF:
669
- case M_XMP:
670
- case M_COM:
671
- case M_DQT:
672
- case M_DHT:
673
- case M_DRI:
674
- case M_IPTC:
675
- // keep.
676
- a++;
677
- break;
678
- default:
679
- // Unknown. Delete.
680
- free (Sections[a].Data);
681
- // Move succeding sections back by one to close space in array.
682
- memmove(Sections+a, Sections+a+1, sizeof(Section_t) * (SectionsRead-a));
683
- SectionsRead -= 1;
684
- Modified = TRUE;
685
- }
686
- }
687
- return Modified;
688
- }
689
-
690
- //--------------------------------------------------------------------------
691
- // Add a section (assume it doesn't already exist) - used for
692
- // adding comment sections and exif sections
693
- //--------------------------------------------------------------------------
694
- Section_t * CreateSection(int SectionType, unsigned char * Data, int Size)
695
- {
696
- Section_t * NewSection;
697
- int a;
698
- int NewIndex;
699
- NewIndex = 2;
700
-
701
- if (SectionType == M_EXIF) NewIndex = 0; // Exif alwas goes first!
702
-
703
- // Insert it in third position - seems like a safe place to put
704
- // things like comments.
705
-
706
- if (SectionsRead < NewIndex){
707
- ErrFatal("Too few sections!");
708
- }
709
-
710
- CheckSectionsAllocated();
711
- for (a=SectionsRead;a>NewIndex;a--){
712
- Sections[a] = Sections[a-1];
713
- }
714
- SectionsRead += 1;
715
-
716
- NewSection = Sections+NewIndex;
717
-
718
- NewSection->Type = SectionType;
719
- NewSection->Size = Size;
720
- NewSection->Data = Data;
721
-
722
- return NewSection;
723
- }
724
-
725
-
726
- //--------------------------------------------------------------------------
727
- // Initialisation.
728
- //--------------------------------------------------------------------------
729
- void ResetJpgfile(void)
730
- {
731
- if (Sections == NULL){
732
- Sections = (Section_t *)malloc(sizeof(Section_t)*5);
733
- SectionsAllocated = 5;
734
- }
735
-
736
- SectionsRead = 0;
737
- HaveAll = 0;
738
- }