1 /*
2 * PTmender
3 *
4 * Based on the program PTStitcher by Helmut Dersch.
5 *
6 * Dec 2005
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This software is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this software; see the file COPYING. If not, a copy
20 * can be downloaded from http://www.gnu.org/licenses/gpl.html, or
21 * obtained by writing to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 *
24 *
25 * Author: Daniel M German dmgerman at uvic doooot ca
26 *
27 */
28
29
30 // TODO
31 // Create_Panorama requires some floating point assembly to be interpreted
32
33 #define __DEBUG__
34
35 #include <assert.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/types.h>
40
41 #ifndef _MSC_VER
42 #include <unistd.h>
43 #else
44 #include "compat_win32/getopt.h"
45 #endif
46
47 #include "tiffio.h"
48 #include "filter.h"
49 #include "panorama.h"
50
51 #include "PTmender.h"
52 #include "PTcommon.h"
53 #include "file.h"
54 #include "ColourBrightness.h"
55
56
57 // Global variables for the program
58
59
60 int ptDebug = 0;
61
62 #define DEFAULT_OUTPUT_NAME "pano"
63
64 #define PT_MENDER_VERSION "PTmender Version " VERSION ", originally written by Helmut Dersch, rewritten by Daniel German\n"
65
66 #define PT_MENDER_USAGE "PTmender [options] <script filename> <images>*\n\n"\
67 "Options:\n"\
68 "\t-o <prefix>\tPrefix for output filename, defaults to " DEFAULT_OUTPUT_NAME "\n"\
69 "\t-q\t\tQuiet run\n"\
70 "\t-h\t\tShow this message\n"\
71 "\t-s\t\tSort the filenames provided in the command line in lexicographical order (and only in the command line)\n"\
72 "\n\nIf no images are specified in the command line, then the 'i' lines are used. If 'i' lines do not contain "\
73 "a valid filename then the 'o' lines are used.\n"\
74 "\n"
75
76
77 static int hasPathInfo(char *aName);
78 static int panoMenderSortingFunction(const void *p1, const void *p2);
79
80
panoMenderDuplicateScriptFile(char * scriptFileName,char * script,fullPath * scriptPathName)81 static void panoMenderDuplicateScriptFile(char *scriptFileName, char *script, fullPath *scriptPathName)
82 {
83 FILE* scriptFD;
84 int temp;
85
86 strcpy(scriptPathName->name, scriptFileName);
87
88 // Get a temp filename for the copy of the script
89 if (panoFileMakeTemp(scriptPathName) == 0) {
90 PrintError("Could not make Tempfile");
91 exit(1);
92 }
93
94 // Copy the script
95 if ((scriptFD = fopen(scriptPathName->name, "w")) == NULL) {
96 PrintError("Could not open temporary Scriptfile");
97 exit(1);
98 }
99
100 temp = fwrite(script, 1, (int) strlen(script), scriptFD);
101
102 if (strlen(script) != temp) {
103 PrintError("Could not write temporary Scriptfile");
104 exit(1);
105 }
106
107 fclose(scriptFD);
108
109 }
110
panoMenderSetFileName(fullPath * ptrImageFileName,char * name,fullPath * scriptFileName)111 void panoMenderSetFileName(fullPath *ptrImageFileName, char *name, fullPath *scriptFileName)
112 {
113 //Only prepend the path to the script to the filenames if the filenames
114 //don't already have path information
115 assert(ptrImageFileName != NULL);
116 assert(name != NULL);
117 assert(scriptFileName != NULL);
118
119 if ( (hasPathInfo(name)) == 0 )
120 strcpy(ptrImageFileName->name, scriptFileName->name);
121 else
122 strcpy(ptrImageFileName->name, "");
123
124 InsertFileName(ptrImageFileName, name);
125 }
126
panoMenderImageFileNamesReadFromScript(fullPath ** ptrImageFileNames,fullPath * scriptFileName)127 static int panoMenderImageFileNamesReadFromScript(fullPath **ptrImageFileNames, fullPath *scriptFileName)
128 {
129 char *script;
130 AlignInfo alignInfo;
131 int counter;
132 int i;
133
134 // We don't have any images yet. We read the Script and load them from it.
135 if (ptDebug) {
136 fprintf(stderr, "Loading script [%s]\n", scriptFileName->name);
137 }
138
139 script = LoadScript(scriptFileName);
140
141 if (script == NULL) {
142 PrintError("Could not load script [%s]", scriptFileName->name);
143 return -1;
144 }
145
146 // parse input script and set up an array of input file names
147 if (ParseScript(script, &alignInfo) != 0) {
148 // print error
149
150 PrintError("Panorama script parsing error");
151 return 0;
152 }
153
154 // The parser of panotools is really broken. To retrieve each
155 // input filename it reads the file,
156 // finds the first filename, then removes it, and writes the rest of the file again
157 // This is done recursively
158
159 counter = alignInfo.numIm;
160
161 if (counter != 0) {
162
163 // Try to find filenames in input section
164 if (ptDebug) {
165 fprintf(stderr, "Found %d images in script file in INPUT section\n", counter);
166 }
167 // Allocate their space
168 if ((*ptrImageFileNames = malloc(512 * counter)) == NULL) {
169 PrintError("Not enough memory");
170 exit(1);
171 }
172
173 //Iterate over input images and populate input filename array
174 for (i = 0; i < counter; i ++) {
175 //If the image filenames don't appear to have any path information, then
176 //prepend the path to the script (if any) that was specified on the
177 //command line (Note: this was the only behavior in the original
178 //PTStitcher. It has been moved into this conditional block because
179 //the script path could get prepended to an already fully qualified
180 //filename...not very useful.
181 if (ptDebug) {
182 fprintf(stderr, "Processing image [%s] from 'i' line %d\n", alignInfo.im[i].name, i);
183 }
184
185 panoMenderSetFileName(&((*ptrImageFileNames)[i]), alignInfo.im[i].name, scriptFileName);
186
187 if (ptDebug) {
188 fprintf(stderr, "Reading image filename [%s] from 'i' line %d\n", (*ptrImageFileNames)[i].name, i);
189 }
190
191
192 }
193 DisposeAlignInfo(&alignInfo);
194 }
195 if (counter == 0) {
196 // Sometimes the names of the images are not in the 'o' line, then assume they are
197 // in the 'i' line.
198
199
200 // create a temporary copy we can overwrite
201 fullPath scriptPathName;
202
203 counter = numLines(script, 'o');
204
205 if (counter == 0) {
206 PrintError("No images found input file script file (there are no 'o' lines nor 'i' lines");
207 exit(1);
208 }
209 // Allocate their space
210 if ((*ptrImageFileNames = malloc(512 * counter)) == NULL) {
211 PrintError("Not enough memory");
212 exit(1);
213 }
214
215
216 panoMenderDuplicateScriptFile(scriptFileName->name, script, &scriptPathName);
217
218 for (i = 0; i < counter; i++) {
219 aPrefs* preferences;
220 if ( (preferences = readAdjustLine(&scriptPathName)) == NULL) {
221 PrintError("No 'i' line for image number %d", i);
222 exit(1);
223 }
224
225 if (ptDebug) {
226 fprintf(stderr, "Processing image [%s] from 'o' line %d\n", preferences->im.name, i);
227 }
228
229 panoMenderSetFileName(&((*ptrImageFileNames)[i]), preferences->im.name, scriptFileName);
230
231 if (ptDebug) {
232 fprintf(stderr, "Reading image filename [%s] from 'i' line %d\n",
233 (*ptrImageFileNames)[i].name, i);
234 }
235 if (preferences->td != NULL)
236 free(preferences->td);
237
238 if (preferences->ts != NULL)
239 free(preferences->ts);
240
241 free(preferences);
242
243 } // end of for (i = 0; i < counter; i++) {
244 free(script);
245
246 remove(scriptPathName.name);
247
248 }
249 return counter;
250 }
251
252
main(int argc,char * argv[])253 int main(int argc,char *argv[])
254 {
255 int counter;
256 int sort = 0; // do we sort command line filenames?
257 fullPath *ptrImageFileNames;
258
259 fullPath scriptFileName;
260 fullPath panoFileName;
261
262 int opt;
263
264 char *currentParm;
265 ptrImageFileNames = NULL;
266 counter = 0;
267 strcpy(panoFileName.name, DEFAULT_OUTPUT_NAME);
268 strcpy(scriptFileName.name, "");
269
270 printf(PT_MENDER_VERSION);
271
272 while ((opt = getopt(argc, argv, "o:f:hsqd")) != -1) {
273
274 // o -> set output file
275 // h -> help?
276 // q -> quiet?
277
278 switch(opt) {
279
280 case 'o': // specifies output file name
281 if (StringtoFullPath(&panoFileName, optarg) != 0) {
282 PrintError("Syntax error: Not a valid pathname");
283 return(-1);
284 }
285 break;
286 case 's':
287 sort = 1;
288 break;
289 case 'd':
290 ptDebug = 1;
291 break;
292 case 'q':
293 ptQuietFlag = 1;
294 break;
295
296 case 'h':
297 PrintError(PT_MENDER_USAGE);
298 return -1;
299
300 default:
301 break;
302 }
303 }
304
305
306 if (ptDebug) {
307 fprintf(stderr, "Number of options to process %d\n", argc- optind);
308 }
309
310 if (optind - argc == 0) {
311 PrintError(PT_MENDER_USAGE);
312 return -1;
313 }
314
315 // First we get the name of the script
316 if (StringtoFullPath(&scriptFileName, argv[optind]) !=0) { // success
317 PrintError("Syntax error: Not a valid pathname");
318 PrintError(PT_MENDER_USAGE);
319 return(-1);
320 }
321
322 // Check if we got a filename
323 if (strlen(scriptFileName.name) == 0) {
324 PrintError("No script name provided\n");
325 PrintError(PT_MENDER_USAGE);
326 return -1;
327
328 } // end of if (scriptFileName[0] != 0) {
329
330 if (ptDebug){
331 fprintf(stderr,"Script filename %s\n", scriptFileName.name);
332 }
333
334
335
336 // optionally we receive a list of filenames
337 optind ++;
338 currentParm = NULL;
339 while (optind < argc ) {
340 currentParm = argv[optind];
341 optind++;
342 counter++;
343
344 if((ptrImageFileNames = realloc(ptrImageFileNames, counter * 512)) == NULL) {
345 PrintError("Not enough memory");
346 exit(1);
347 }
348
349
350 if (StringtoFullPath(&ptrImageFileNames[counter-1], currentParm) != 0) {
351 PrintError("Syntax error: Not a valid pathname");
352 return(-1);
353 }
354 if (ptDebug){
355 fprintf(stderr,"Getting file from command line %s index %d\n", ptrImageFileNames[counter-1].name, counter);
356 }
357 } // end of while loop while (optind < argc ) {
358
359 if (sort && counter > 0) {
360 // We have filenames that need to be sorted
361 qsort(ptrImageFileNames, counter, 512, panoMenderSortingFunction);;
362 }
363
364
365 // Handle some lack of information
366 if (strlen(panoFileName.name) == 0) {
367 PrintError("No output filename specified\n");
368 PrintError(PT_MENDER_USAGE);
369 return -1;
370 }
371
372 if (counter == 0) {
373 counter = panoMenderImageFileNamesReadFromScript(&ptrImageFileNames, &scriptFileName);
374 }
375 if (counter == 0) {
376 PrintError("No images found input file script file (there are no 'o' lines nor 'i' lines");
377 exit(1);
378 }
379
380 // By now we should have loaded up the input filename array, the output
381 // panorama name, and the name of the script file (copied to a temporary
382 // directory). Now we can create the output image.
383 return panoCreatePanorama(ptrImageFileNames, counter, &panoFileName, &scriptFileName);
384
385 }
386
387
388 //////////////////////////////////////////////////////////////////////
389
Filename(fullPath * path)390 char* Filename(fullPath* path)
391 {
392 char *temp;
393 if ((temp = strrchr(path->name, PATH_SEP)) != NULL) {
394 temp++;
395 } else {
396 temp = path->name;
397 }
398 return temp;
399 }
400
401
hasPathInfo(char * aName)402 static int hasPathInfo(char *aName)
403 {
404 return ((strchr(aName, PATH_SEP) == NULL) ? 0 : 1);
405 }
406
panoMenderSortingFunction(const void * p1,const void * p2)407 static int panoMenderSortingFunction(const void *p1, const void *p2)
408 {
409 return strcmp(p1, p2);
410 }
411