pto_move.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00012 /*  This program is free software; you can redistribute it and/or
00013  *  modify it under the terms of the GNU General Public
00014  *  License as published by the Free Software Foundation; either
00015  *  version 2 of the License, or (at your option) any later version.
00016  *
00017  *  This software is distributed in the hope that it will be useful,
00018  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00020  *  General Public License for more details.
00021  *
00022  *  You should have received a copy of the GNU General Public
00023  *  License along with this software. If not, see
00024  *  <http://www.gnu.org/licenses/>.
00025  *
00026  */
00027 
00028 #include "hugin_config.h"
00029 #include <iostream>
00030 #include <string>
00031 #include <fstream>
00032 #include <hugin_utils/filesystem.h>
00033 #include <getopt.h>
00034 #include <panodata/Panorama.h>
00035 #include <hugin_utils/stl_utils.h>
00036 
00037 std::string IncludeTrailingDelimiter(std::string path)
00038 {
00039     std::string s=path;
00040 #ifdef _WIN32
00041     if(s.compare(s.length()-1,1,"\\")!=0 && s.compare(s.length()-1,1,"/")!=0)
00042     {
00043         s.append("\\");
00044     };
00045 #else
00046     if(s.compare(s.length()-1,1,"/")!=0)
00047     {
00048         s.append("/");
00049     };
00050 #endif
00051     return s;
00052 };
00053 
00054 // rebase a filename from relative to srcPath to relative to destPath and return absolute new dest path
00055 bool RebaseFilename(fs::path srcFile, fs::path& destFile, std::string srcPath, std::string destPath)
00056 {
00057     fs::path input=fs::absolute(srcFile);
00058     std::string fullInputPath=input.string();
00059     std::string srcPathWithTrailingDelimiter=IncludeTrailingDelimiter(srcPath);
00060     if(fullInputPath.compare(0, srcPathWithTrailingDelimiter.length(), srcPathWithTrailingDelimiter)!=0)
00061     {
00062         return false;
00063     };
00064     fullInputPath.replace(0, srcPathWithTrailingDelimiter.length(), IncludeTrailingDelimiter(destPath));
00065     destFile=fs::path(fullInputPath);
00066     return true;
00067 };
00068 
00069 bool checkDestinationDirectory(std::string dir, fs::path& pathTo)
00070 {
00071     pathTo=fs::path(dir);
00072     try
00073     {
00074         // check if a destination directory is given
00075         if(pathTo.extension().string().length()>0)
00076         {
00077             std::cerr << "ERROR: Your destination is a file. Copy/Move several files to " << std::endl
00078                       << "a single file is not allowed." << std::endl
00079                       << "Canceled operation." << std::endl;
00080             return false;
00081         };
00082         // create destination directory if not exists
00083         if(!fs::exists(pathTo))
00084         {
00085             if(!fs::create_directories(pathTo))
00086             {
00087                 std::cerr << "ERROR: Could not create destination directory: " << pathTo.string() << std::endl
00088                           << "Maybe you have not sufficient rights to create this directory." << std::endl;
00089                 return false;
00090             };
00091         };
00092     }
00093     catch (const fs::filesystem_error& ex)
00094     {
00095         std::cout << ex.what() << std::endl;
00096         return false;
00097     }
00098     pathTo=fs::absolute(pathTo);
00099     return true;
00100 };
00101 
00102 typedef std::vector<fs::path> pathVec;
00103 
00104 bool PTOCopyMove(bool movingFile, fs::path src, fs::path dest, bool overwriteAllFiles)
00105 {
00106     fs::path destFile(hugin_utils::GetAbsoluteFilename(dest.string()));
00107     std::cout << (movingFile ? "Moving project file  " : "Copying project file ") << src.filename() << std::endl
00108               << "  from " << src.parent_path() << std::endl
00109               << "  to " << destFile.parent_path() << std::endl;
00110     // open project file
00111     HuginBase::Panorama pano;
00112     std::string input=src.string();
00113     std::ifstream prjfile(input.c_str());
00114     if (!prjfile.good())
00115     {
00116         std::cerr << "ERROR: Could not open script: " << src.string() << std::endl;
00117         return false;
00118     }
00119     std::string inputPathPrefix=hugin_utils::getPathPrefix(input);
00120     std::string outputPathPrefix=hugin_utils::getPathPrefix(destFile.string());
00121     pano.setFilePrefix(inputPathPrefix);
00122     AppBase::DocumentData::ReadWriteError err = pano.readData(prjfile);
00123     if (err != AppBase::DocumentData::SUCCESSFUL)
00124     {
00125         std::cerr << "ERROR: error while parsing panos tool script: " << input << std::endl
00126                   << "AppBase::DocumentData::ReadWriteError code: " << err << std::endl;
00127         return false;
00128     };
00129     prjfile.close();
00130     if(pano.getNrOfImages()==0)
00131     {
00132         std::cerr << "ERROR: project " << input << " does not contain any images." << std::endl;
00133         return false;
00134     };
00135     pathVec imagesFrom, imagesTo;
00136     // check if all images exists
00137     for(size_t i=0; i<pano.getNrOfImages(); i++)
00138     {
00139         fs::path p(pano.getImage(i).getFilename());
00140         imagesFrom.push_back(p);
00141         if(!fs::exists(p) || !fs::is_regular_file(p))
00142         {
00143             std::cerr << "ERROR: image " << p.string() << " not found on disc." << std::endl
00144                       << "Skipping project " << input << std::endl;
00145             return false;
00146         };
00147         p=fs::absolute(p);
00148         // now build now image filename
00149         fs::path newFilename;
00150         if(RebaseFilename(p, newFilename, inputPathPrefix, outputPathPrefix))
00151         {
00152             pano.setImageFilename(i, newFilename.string());
00153             imagesTo.push_back(newFilename);
00154         };
00155     };
00156     if(!imagesFrom.empty())
00157     {
00158         if(imagesFrom.size()==imagesTo.size())
00159         {
00160             fs::path targetDir(destFile);
00161             targetDir.remove_filename();
00162             if(!checkDestinationDirectory(targetDir.string(), targetDir))
00163             {
00164                 return false;
00165             };
00166             if(fs::exists(destFile) && !overwriteAllFiles)
00167             {
00168                 std::cout << "Project file " << destFile << " does already exists." << std::endl
00169                           << "  Overwrite this file? [Y|N] ";
00170                 std::string userAnswer;
00171                 while(userAnswer.length()==0)
00172                 {
00173                     std::cin >> userAnswer;
00174                 };
00175                 userAnswer=hugin_utils::toupper(userAnswer);
00176                 if(userAnswer!="YES" && userAnswer!="Y")
00177                 {
00178                     std::cout << std::endl << "Moving/Copying of project file " << input << " canceled." << std::endl << std::endl;
00179                     return false;
00180                 }
00181             };
00182             //copy/moving images
00183             for(size_t i=0; i<imagesFrom.size(); i++)
00184             {
00185                 // check if target directory already exists
00186                 targetDir=fs::path(imagesTo[i]);
00187                 targetDir.remove_filename();
00188                 if(!checkDestinationDirectory(targetDir.string(), targetDir))
00189                 {
00190                     return false;
00191                 };
00192                 //check if target image file already exists
00193                 if(fs::exists(imagesTo[i]) && !overwriteAllFiles)
00194                 {
00195                     std::cout << "Images file " << imagesTo[i] << " does already exists." << std::endl
00196                               << "  Overwrite this file? [Y|N] ";
00197                     std::string userAnswer;
00198                     while(userAnswer.length()==0)
00199                     {
00200                         std::cin >> userAnswer;
00201                     };
00202                     userAnswer=hugin_utils::toupper(userAnswer);
00203                     if(userAnswer!="YES" && userAnswer!="Y")
00204                     {
00205                         std::cout << std::endl << "Moving/Copying of project file " << input << " canceled." << std::endl << std::endl;
00206                         return false;
00207                     }
00208                 };
00209                 if(movingFile)
00210                 {
00211                     try
00212                     {
00213                         fs::rename(imagesFrom[i], imagesTo[i]);
00214                     }
00215                     catch (const fs::filesystem_error& ex)
00216                     {
00217                         std::cout << ex.what() << std::endl;
00218                         return false;
00219                     }
00220                 }
00221                 else
00222                 {
00223                     try
00224                     {
00225                         fs::copy_file(imagesFrom[i], imagesTo[i], OVERWRITE_EXISTING);
00226                     }
00227                     catch (const fs::filesystem_error& ex)
00228                     {
00229                         std::cout << ex.what() << std::endl;
00230                         return false;
00231                     }
00232                 };
00233             }; // for loop for all images
00234             // now create pano file in new destination
00235             // write output
00236             HuginBase::UIntSet imgs;
00237             fill_set(imgs, 0, pano.getNrOfImages()-1);
00238             std::ofstream of(destFile.string().c_str());
00239             pano.printPanoramaScript(of, pano.getOptimizeVector(), pano.getOptions(), imgs, false, outputPathPrefix);
00240             of.close();
00241             if(movingFile)
00242             {
00243                 try
00244                 {
00245                     fs::remove(src);
00246                 }
00247                 catch (const fs::filesystem_error& ex)
00248                 {
00249                     std::cout << "Could not remove original file: " << input << std::endl;
00250                     std::cout << ex.what() << std::endl;
00251                     return false;
00252                 }
00253             };
00254         }
00255         else
00256         {
00257             // the images in the project file are not all relative to the same base path
00258             std::cout << "WARNING: Images location in project file are not consistent. " << std::endl
00259                       << "So don't move/copy project file " << src.string() << std::endl;
00260             return false;
00261         };
00262     }
00263     else
00264     {
00265         // now create pano file in new destination, project contains images in paths
00266         // not relative to base directory
00267         // so create only the new project file without copying/moving image files
00268         HuginBase::UIntSet imgs;
00269         fill_set(imgs, 0, pano.getNrOfImages()-1);
00270         std::ofstream of(destFile.string().c_str());
00271         pano.printPanoramaScript(of, pano.getOptimizeVector(), pano.getOptions(), imgs, false, outputPathPrefix);
00272         of.close();
00273         if(movingFile)
00274         {
00275             try
00276             {
00277                 fs::remove(src);
00278             }
00279             catch (const fs::filesystem_error& ex)
00280             {
00281                 std::cout << "Could not remove original file: " << input << std::endl;
00282                 std::cout << ex.what() << std::endl;
00283                 return false;
00284             }
00285         };
00286     };
00287     return true;
00288 };
00289 
00290 template <class iteratorType>
00291 bool iterateFileSystem(std::string src, pathVec& projectFiles)
00292 {
00293     try
00294     {
00295         for(iteratorType it(src); it != iteratorType(); it++)
00296         {
00297             std::string ext=hugin_utils::toupper(it->path().extension().string());
00298             if(ext==".PTO")
00299             {
00300                 projectFiles.push_back(*it);
00301             };
00302         }
00303     }
00304     catch(fs::filesystem_error& e)
00305     {
00306         std::cout << e.what() << std::endl;
00307         return false;
00308     }
00309     return true;
00310 };
00311 
00312 void SearchPTOFilesInDirectory(pathVec& projectFiles, std::string src, bool recursive)
00313 {
00314     if(recursive)
00315     {
00316         iterateFileSystem<fs::recursive_directory_iterator>(src, projectFiles);
00317     }
00318     else
00319     {
00320         iterateFileSystem<fs::directory_iterator>(src, projectFiles);
00321     };
00322 };
00323 
00324 static void usage(const char* name)
00325 {
00326     std::cout << name << ": move a project file with all images in it" << std::endl
00327               << name << " version " << hugin_utils::GetHuginVersion() << std::endl
00328               << std::endl
00329               << "Usage:  pto_move [options] path1/source.pto path2/dest.pto" << std::endl
00330               << "             Rename project file path1/source.pto to " << std::endl
00331               << "             path2/dest.pto. All images contained in the project will" << std::endl
00332               << "             be moved accordingly." << std::endl << std::endl
00333               << "        pto_move [options] sourceFolder destFolder" << std::endl
00334               << "             Moves all project files in the source folder to " << std::endl
00335               << "             the destination folder including all images." << std::endl
00336               << std::endl
00337               << "Options: " << std::endl
00338               << "  --copy       Copy project files and images instead of moving" << std::endl
00339               << "  --recursive  Only effective in use case 2. Go recursive in the" << std::endl
00340               << "               the source folder and move all project files with images" << std::endl
00341               << "               to destination folder by maintaining the folder structure" << std::endl
00342               << "               relative to source folder." << std::endl
00343               << "  --overwrite  Overwrite all existing files. Otherwise you will be asked" << std::endl
00344               << "               for each existing file." << std::endl
00345               << std::endl
00346               << std::endl;
00347 };
00348 
00349 int main(int argc, char* argv[])
00350 {
00351     // parse arguments
00352     const char* optstring = "croh";
00353 
00354     static struct option longOptions[] =
00355     {
00356         {"copy", no_argument, NULL, 'c' },
00357         {"recursive", no_argument, NULL, 'r' },
00358         {"overwrite", no_argument, NULL, 'o' },
00359         {"help", no_argument, NULL, 'h' },
00360         0
00361     };
00362 
00363     bool movingFiles=true; //movingFiles: false->copy, true->move
00364     bool recursive=false;
00365     bool forceOverwrite=false;
00366     int c;
00367     while ((c = getopt_long (argc, argv, optstring, longOptions,nullptr)) != -1)
00368     {
00369         switch (c)
00370         {
00371             case 'h':
00372                 usage(hugin_utils::stripPath(argv[0]).c_str());
00373                 return 0;
00374             case 'c':
00375                 movingFiles=false;
00376                 break;
00377             case 'r':
00378                 recursive=true;
00379                 break;
00380             case 'o':
00381                 forceOverwrite=true;
00382                 break;
00383             case ':':
00384             case '?':
00385                 // missing argument or invalid switch
00386                 return 1;
00387                 break;
00388             default:
00389                 // this should not happen
00390                 abort();
00391         }
00392     }
00393 
00394     if(argc-optind<2)
00395     {
00396         std::cerr << hugin_utils::stripPath(argv[0]) << ": You need to give at least a source and a destination project file or directory." << std::endl;
00397         return 1;
00398     };
00399 
00400     try
00401     {
00402         fs::path p(argv[optind]);
00403         if(fs::exists(p))
00404         {
00405             p=fs::absolute(p);
00406             if(fs::is_directory(p))
00407             {
00408                 // first parameter is a directory
00409                 fs::path pathTo;
00410                 if(!checkDestinationDirectory(std::string(argv[argc-1]), pathTo))
00411                 {
00412                     return 1;
00413                 };
00414                 // search all pto files in directory
00415                 pathVec projectFiles;
00416                 std::cout << "Searching project files in " << p << std::endl;
00417                 SearchPTOFilesInDirectory(projectFiles, p.string(), recursive);
00418                 if(projectFiles.empty())
00419                 {
00420                     std::cout << "No project files found in given directory " << p.string() << std::endl;
00421                     return 0;
00422                 };
00423                 std::cout << "Found " << projectFiles.size() << " project files." << std::endl << std::endl;
00424                 for(pathVec::const_iterator it=projectFiles.begin(); it!=projectFiles.end(); ++it)
00425                 {
00426                     fs::path newPath;
00427                     if(RebaseFilename(*it, newPath, p.string(), pathTo.string()))
00428                     {
00429                         PTOCopyMove(movingFiles, *it, newPath, forceOverwrite);
00430                     };
00431                 };
00432             }
00433             else
00434             {
00435                 if(argc-optind>2)
00436                 {
00437                     // several files given
00438                     // check if destination is a directory and create it if necessary
00439                     fs::path pathTo;
00440                     if(!checkDestinationDirectory(std::string(argv[argc-1]), pathTo))
00441                     {
00442                         return 1;
00443                     };
00444                     while(optind<argc-1)
00445                     {
00446                         p=fs::path(argv[optind]);
00447                         std::string ext=hugin_utils::toupper(p.extension().string());
00448                         // work only on pto files
00449                         if(ext==".PTO")
00450                         {
00451                             if(fs::exists(p) && fs::is_regular_file(p))
00452                             {
00453                                 p=fs::absolute(p);
00454                                 fs::path newPath = pathTo / p.filename();
00455                                 PTOCopyMove(movingFiles, p, newPath, forceOverwrite);
00456                             }
00457                             else
00458                             {
00459                                 std::cout << "WARNING: File " << p << " does not exists" << std::endl
00460                                           << "Skipping this file." << std::endl;
00461                             };
00462                         };
00463                         optind++;
00464                     };
00465                 }
00466                 else
00467                 {
00468                     // exactly 2 files given
00469                     fs::path pathTo(argv[argc-1]);
00470                     if(pathTo.extension().string().length()>0)
00471                     {
00472                         // user has given filename with extension
00473                         // so simply copy/move file
00474                         pathTo=fs::absolute(pathTo);
00475                         PTOCopyMove(movingFiles, p, pathTo, forceOverwrite);
00476                     }
00477                     else
00478                     {
00479                         // target is a directory
00480                         if(!checkDestinationDirectory(std::string(argv[argc-1]), pathTo))
00481                         {
00482                             return 1;
00483                         };
00484                         pathTo=pathTo / p.filename();
00485                         if(p==pathTo)
00486                         {
00487                             std::cerr << "ERROR: Target and destination file are the same." << std::endl
00488                                       << "Skipping file processing." << std::endl;
00489                             return 1;
00490                         };
00491                         PTOCopyMove(movingFiles, p, pathTo, forceOverwrite);
00492                     };
00493                 };
00494             };
00495         };
00496     }
00497     catch (const fs::filesystem_error& ex)
00498     {
00499         std::cout << ex.what() << std::endl;
00500     }
00501     return 0;
00502 }

Generated on 26 Apr 2018 for Hugintrunk by  doxygen 1.4.7