27 #include "hugin_version.h"
28 #include "hugin_config.h"
32 #include <sys/utime.h>
38 #include <sys/types.h>
49 #include <hugin_config.h>
56 #include <mach-o/dyld.h>
61 #if defined HAVE_EPOXY && HAVE_EPOXY
64 #include <epoxy/wgl.h>
73 #include <GLUT/glut.h>
76 namespace hugin_utils {
84 gettimeofday(&tv,NULL);
85 localtime_r((time_t*)&tv.tv_sec, &t);
86 strftime(tmp,99,
"%H:%M:%S",&t);
87 sprintf(tmp+8,
".%06ld", (
long)tv.tv_usec);
101 std::string::size_type idx = basename2.rfind(
'.');
104 if (idx == std::string::npos) {
106 return std::string(
"");
110 std::string::size_type slashidx = basename2.find(
'/', idx);
111 if ( slashidx == std::string::npos)
113 return basename2.substr(idx+1);
115 return std::string(
"");
119 std::string::size_type slashidx = basename2.find(
'/', idx);
120 std::string::size_type backslashidx = basename2.find(
'\\', idx);
121 if ( slashidx == std::string::npos && backslashidx == std::string::npos)
123 return basename2.substr(idx+1);
125 return std::string(
"");
132 std::string::size_type idx = basename2.rfind(
'.');
135 if (idx == std::string::npos) {
140 std::string::size_type slashidx = basename2.find(
'/', idx);
141 if ( slashidx == std::string::npos)
143 return basename2.substr(0, idx);
149 std::string::size_type slashidx = basename2.find(
'/', idx);
150 std::string::size_type backslashidx = basename2.find(
'\\', idx);
151 if ( slashidx == std::string::npos && backslashidx == std::string::npos)
153 return basename2.substr(0, idx);
163 std::string::size_type idx = filename.rfind(
'/');
165 std::string::size_type idx1 = filename.rfind(
'\\');
166 std::string::size_type idx2 = filename.rfind(
'/');
167 std::string::size_type idx;
168 if (idx1 == std::string::npos) {
170 }
else if (idx2 == std::string::npos) {
176 if (idx != std::string::npos) {
178 return filename.substr(idx + 1);
187 std::string::size_type idx = filename.rfind(
'/');
189 std::string::size_type idx1 = filename.rfind(
'\\');
190 std::string::size_type idx2 = filename.rfind(
'/');
191 std::string::size_type idx;
192 if (idx1 == std::string::npos) {
194 }
else if (idx2 == std::string::npos) {
200 if (idx != std::string::npos) {
202 return filename.substr(0, idx+1);
211 std::string::size_type pos = s.find_last_not_of(
" \t");
212 if (pos != std::string::npos)
215 pos = s.find_first_not_of(
" \t");
216 if (pos != std::string::npos)
223 s.erase(s.begin(), s.end());
235 std::sprintf(fmt,
"%%.%df",
std::min(digits, 16));
240 _snprintf (c, 1023, fmt, d);
242 snprintf (c, 1023, fmt, d);
245 std::string number (c);
247 int l = (int)number.length()-1;
249 while ( l != 0 && number[l] ==
'0' ) {
253 if ( number[l] ==
',' ) {
257 if ( number[l] ==
'.' ) {
271 int x = atoi(s.c_str());
287 val =
static_cast<unsigned int>(x);
294 std::vector<std::string>
SplitString(
const std::string& s,
const std::string& sep)
296 std::vector<std::string> result;
297 std::size_t pos = s.find_first_of(sep, 0);
298 std::size_t pos2 = 0;
299 while (pos != std::string::npos)
303 std::string t(s.substr(pos2, pos - pos2));
311 pos = s.find_first_of(sep, pos2);
313 if (pos2 < s.length())
315 std::string t(s.substr(pos2));
325 void ReplaceAll(std::string& s,
const std::string& oldChar,
char newChar)
327 std::size_t found = s.find_first_of(oldChar);
328 while (found != std::string::npos)
331 found = s.find_first_of(oldChar, found + 1);
337 const auto it = std::search(s1.begin(), s1.end(), s2.begin(), s2.end(), [](
const char a,
const char b)->
bool {
return std::tolower(a) ==
std::tolower(b); });
338 return it != s1.end();
342 double &r,
double &g,
double &b)
357 g = 0.75 * ((1.0 - std::min<double>(cperr -
XP1,
XP2 -
XP1) / (
XP2 - XP1)));
364 std::ifstream ifile(filename.c_str());
365 return !ifile.fail();
371 char fullpath[_MAX_PATH];
372 _fullpath(fullpath,filename.c_str(),_MAX_PATH);
373 return std::string(fullpath);
379 bool tempFileCreated=
false;
382 tempFileCreated=
true;
383 std::ofstream os(filename.c_str());
386 char *real_path = realpath(filename.c_str(), NULL);
390 absPath=std::string(real_path);
399 remove(filename.c_str());
408 return (vigra::impexListExtensions().find(extension) != std::string::npos);
414 if (extension.empty())
420 std::string
GetOutputFilename(
const std::string& out,
const std::string& in,
const std::string& suffix)
425 if (extension.empty())
427 return in +
"_" + suffix;
431 return in.substr(0, in.length() - extension.length() - 1).append(
"_" + suffix +
"." + extension);
444 char buffer[MAX_PATH];
445 GetModuleFileName(NULL,buffer,
sizeof(buffer));
446 std::filesystem::path data_path(buffer);
447 data_path.remove_filename();
448 if (data_path.has_parent_path())
450 return std::filesystem::absolute(data_path.parent_path() /
".." /
"share" /
"hugin" /
"data").
string() +
"\\";
452 return std::string();
453 #elif defined MAC_SELF_CONTAINED_BUNDLE
454 char path[PATH_MAX + 1];
455 uint32_t size =
sizeof(path);
456 std::string data_path(
"");
457 if (_NSGetExecutablePath(path, &size) == 0)
459 data_path=dirname(path);
460 data_path.append(
"/../Resources/xrc/");
463 #elif defined UNIX_SELF_CONTAINED_BUNDLE
464 std::filesystem::path data_path = std::filesystem::read_symlink(
"/proc/self/exe");
465 data_path.remove_filename();
466 if (data_path.has_parent_path())
468 return (data_path.parent_path() /
"share/hugin/data").
string() +
"/";
470 return std::string();
472 return std::string(INSTALL_DATA_DIR);
479 char *homedir = getenv(
"HOME");
483 pw = getpwuid(getuid());
486 homedir = pw->pw_dir;
491 return std::string();
493 return std::string(homedir);
499 std::filesystem::path path;
501 char fullpath[_MAX_PATH];
502 if(SHGetFolderPath(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, fullpath)!=S_OK)
504 return std::string();
506 path = std::filesystem::path(fullpath);
509 char *xdgDataDir = getenv(
"XDG_DATA_HOME");
510 if (xdgDataDir == NULL || strlen(xdgDataDir) == 0)
517 return std::string();
519 path = std::filesystem::path(homeDir);
520 path /=
".local/share/hugin";
525 path = std::filesystem::path(xdgDataDir);
529 if (!std::filesystem::exists(path))
531 if (!std::filesystem::create_directories(path))
533 std::cerr <<
"ERROR: Could not create destination directory: " << path.string() << std::endl
534 <<
"Maybe you have not sufficient rights to create this directory." << std::endl;
535 return std::string();
538 return path.string();
543 struct ContextSettings
547 HGLRC renderingContext;
553 renderingContext = NULL;
556 static ContextSettings
context;
561 WNDCLASS windowClass;
563 ZeroMemory(&windowClass,
sizeof(WNDCLASS));
564 windowClass.hInstance = GetModuleHandle(NULL);
565 windowClass.lpfnWndProc = DefWindowProc;
566 windowClass.lpszClassName =
"Hugin";
567 if (RegisterClass(&windowClass) == 0)
572 context.
window = CreateWindow(
"Hugin",
"Hugin", 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
573 CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), NULL);
585 PIXELFORMATDESCRIPTOR pixelFormatDesc;
586 ZeroMemory(&pixelFormatDesc,
sizeof(PIXELFORMATDESCRIPTOR));
587 pixelFormatDesc.nSize =
sizeof(PIXELFORMATDESCRIPTOR);
588 pixelFormatDesc.nVersion = 1;
589 pixelFormatDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
590 int pixelFormat = ChoosePixelFormat(
context.dc, &pixelFormatDesc);
591 if (pixelFormat == 0)
596 if (SetPixelFormat(
context.dc, pixelFormat, &pixelFormatDesc) == FALSE)
602 if (
context.renderingContext == NULL)
606 if (wglMakeCurrent(
context.dc,
context.renderingContext) == FALSE)
610 #if defined HAVE_EPOXY && HAVE_EPOXY
611 epoxy_handle_external_wglMakeCurrent();
618 if (
context.renderingContext != NULL)
620 wglMakeCurrent(NULL, NULL);
621 #if defined HAVE_EPOXY && HAVE_EPOXY
622 epoxy_handle_external_wglMakeCurrent();
624 wglDeleteContext(
context.renderingContext);
634 UnregisterClass(
"Hugin", GetModuleHandle(NULL));
637 #elif defined __APPLE__
638 static GLuint GlutWindowHandle;
643 char workingDir[FILENAME_MAX];
644 getcwd(workingDir, FILENAME_MAX);
645 glutInit(argcp, argv);
646 glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_ALPHA);
647 GlutWindowHandle = glutCreateWindow(
"Hugin");
655 glutDestroyWindow(GlutWindowHandle);
659 #if defined HAVE_EGL && HAVE_EGL
660 #if defined HAVE_EPOXY && HAVE_EPOXY
661 #include <epoxy/egl.h>
666 struct ContextSettings
668 EGLDisplay m_display;
669 EGLContext m_context;
672 static ContextSettings
context;
674 static const EGLint configAttribs[] = {
679 EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
680 EGL_CONFORMANT, EGL_OPENGL_BIT,
681 EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
688 context.m_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
689 if (
context.m_display == EGL_NO_DISPLAY)
691 std::cerr <<
"Could not connect to EGL_DEFAULT_DISPLAY" << std::endl;
696 if (eglInitialize(
context.m_display, &major, &minor) != EGL_TRUE)
698 std::cerr <<
"Could not initialize EGL" << std::endl
699 <<
"Error: 0x" << std::hex << eglGetError() << std::endl;
702 std::cout <<
"Init OpenGL ES " << major <<
"." << minor << std::endl;
703 std::cout <<
"Client API: " << eglQueryString(
context.m_display, EGL_CLIENT_APIS) << std::endl
704 <<
"Vendor: " << eglQueryString(
context.m_display, EGL_VENDOR) << std::endl
705 <<
"Version: " << eglQueryString(
context.m_display, EGL_VERSION) << std::endl
706 <<
"EGL Extensions: " << eglQueryString(
context.m_display, EGL_EXTENSIONS) << std::endl;
708 if (!eglBindAPI(EGL_OPENGL_API))
710 std::cerr <<
"Could not bind OpenGL API" << std::endl
711 <<
"Error: 0x" << std::hex << eglGetError() << std::endl;
716 EGLConfig egl_config;
717 if (eglChooseConfig(
context.m_display, configAttribs, &egl_config, 1, &numConfigs) != EGL_TRUE)
719 std::cerr <<
"Cound not set egl config" << std::endl
720 <<
"Error: 0x" << std::hex << eglGetError() << std::endl;
725 context.m_context = eglCreateContext(
context.m_display, egl_config, EGL_NO_CONTEXT, NULL);
726 if (
context.m_context == EGL_NO_CONTEXT)
728 std::cerr <<
"Cound not create context" << std::endl
729 <<
"Error: 0x" << std::hex << eglGetError() << std::endl;
732 if (eglMakeCurrent(
context.m_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
context.m_context) != EGL_TRUE)
734 std::cerr <<
"Could not make current context" << std::endl
735 <<
"Error: 0x" << std::hex << eglGetError() << std::endl;
744 eglTerminate(
context.m_display);
748 #include <X11/Xlib.h>
749 #include <X11/Xutil.h>
750 #if defined HAVE_EPOXY && HAVE_EPOXY
751 #include <epoxy/glx.h>
791 int attrib[] = { GLX_RGBA, None };
805 XSetWindowAttributes swa;
806 swa.border_pixel = 0;
810 CWBorderPixel | CWColormap, &swa);
851 std::cout <<
hugin_utils::stripPath(argv[0]) <<
": using graphics card: " << glGetString(GL_VENDOR) <<
" " << glGetString(GL_RENDERER) << std::endl;
852 #if defined HAVE_EPOXY && HAVE_EPOXY
853 const GLboolean has_arb_fragment_shader = epoxy_has_gl_extension(
"GL_ARB_fragment_shader");
854 const GLboolean has_arb_vertex_shader = epoxy_has_gl_extension(
"GL_ARB_vertex_shader");
855 const GLboolean has_arb_shader_objects = epoxy_has_gl_extension(
"GL_ARB_shader_objects");
856 const GLboolean has_arb_shading_language = epoxy_has_gl_extension(
"GL_ARB_shading_language_100");
857 const GLboolean has_ext_framebuffer = epoxy_has_gl_extension(
"GL_EXT_framebuffer_object");
858 const GLboolean has_arb_texture_rectangle = epoxy_has_gl_extension(
"GL_ARB_texture_rectangle");
859 const GLboolean has_arb_texture_border_clamp = epoxy_has_gl_extension(
"GL_ARB_texture_border_clamp");
860 const GLboolean has_arb_texture_float = epoxy_has_gl_extension(
"GL_ARB_texture_float");
862 int err = glewInit();
865 std::cerr << argv[0] <<
": an error occurred while setting up the GPU:" << std::endl;
866 std::cerr << glewGetErrorString(err) << std::endl;
867 std::cerr << argv[0] <<
": Switching to CPU calculation." << std::endl;
872 const GLboolean has_arb_fragment_shader = glewGetExtension(
"GL_ARB_fragment_shader");
873 const GLboolean has_arb_vertex_shader = glewGetExtension(
"GL_ARB_vertex_shader");
874 const GLboolean has_arb_shader_objects = glewGetExtension(
"GL_ARB_shader_objects");
875 const GLboolean has_arb_shading_language = glewGetExtension(
"GL_ARB_shading_language_100");
876 const GLboolean has_ext_framebuffer = glewGetExtension(
"GL_EXT_framebuffer_object");
877 const GLboolean has_arb_texture_rectangle = glewGetExtension(
"GL_ARB_texture_rectangle");
878 const GLboolean has_arb_texture_border_clamp = glewGetExtension(
"GL_ARB_texture_border_clamp");
879 const GLboolean has_arb_texture_float = glewGetExtension(
"GL_ARB_texture_float");
882 if (!(has_arb_fragment_shader && has_arb_vertex_shader && has_arb_shader_objects && has_arb_shading_language && has_ext_framebuffer && has_arb_texture_rectangle && has_arb_texture_border_clamp && has_arb_texture_float)) {
883 const char * msg[] = {
"false",
"true"};
884 std::cerr << argv[0] <<
": extension GL_ARB_fragment_shader = " << msg[has_arb_fragment_shader] << std::endl;
885 std::cerr << argv[0] <<
": extension GL_ARB_vertex_shader = " << msg[has_arb_vertex_shader] << std::endl;
886 std::cerr << argv[0] <<
": extension GL_ARB_shader_objects = " << msg[has_arb_shader_objects] << std::endl;
887 std::cerr << argv[0] <<
": extension GL_ARB_shading_language_100 = " << msg[has_arb_shading_language] << std::endl;
888 std::cerr << argv[0] <<
": extension GL_EXT_framebuffer_object = " << msg[has_ext_framebuffer] << std::endl;
889 std::cerr << argv[0] <<
": extension GL_ARB_texture_rectangle = " << msg[has_arb_texture_rectangle] << std::endl;
890 std::cerr << argv[0] <<
": extension GL_ARB_texture_border_clamp = " << msg[has_arb_texture_border_clamp] << std::endl;
891 std::cerr << argv[0] <<
": extension GL_ARB_texture_float = " << msg[has_arb_texture_float] << std::endl;
892 std::cerr << argv[0] <<
": This graphics system lacks the necessary extensions for -g." << std::endl;
893 std::cerr << argv[0] <<
": Switching to CPU calculation." << std::endl;
909 return std::string(DISPLAY_VERSION);
912 std::string
GetICCDesc(
const vigra::ImageImportInfo::ICCProfile& iccProfile)
914 if (iccProfile.empty())
917 return std::string();
919 cmsHPROFILE profile = cmsOpenProfileFromMem(iccProfile.data(), iccProfile.size());
923 return std::string();
926 cmsCloseProfile(profile);
932 const size_t size = cmsGetProfileInfoASCII(profile, cmsInfoDescription, cmsNoLanguage, cmsNoCountry,
nullptr, 0);
933 std::string information(size,
'\000');
934 cmsGetProfileInfoASCII(profile, cmsInfoDescription, cmsNoLanguage, cmsNoCountry, &information[0], size);
942 std::vector<std::string> rawExt{
"dng",
"crw",
"cr2",
"cr3",
"raw",
"erf",
"raf",
"mrw",
"nef",
"orf",
"rw2",
"pef",
"srw",
"arw" };
948 const std::string testExtLower =
tolower(testExt);
950 for (
const auto& ext : rawExts)
952 if (testExtLower.compare(ext) == 0)
static ContextSettings context
std::string GetICCDesc(const vigra::ImageImportInfo::ICCProfile &iccProfile)
returns description of given icc profile
bool wrapupGPU()
cleanup GPU settings
bool FileExists(const std::string &filename)
checks if file exists
std::string StrTrim(const std::string &str)
remove trailing and leading white spaces and tabs
std::string GetCurrentTimeString()
current time as a string
std::string GetOutputFilename(const std::string &out, const std::string &in, const std::string &suffix)
construct output filename, if ouput is known return this value otherwise use the input filename and a...
void EnforceExtension(std::string &filename, const std::string &defaultExtension)
check if filename contains extension, if not add default extension
std::string doubleToString(double d, int digits)
convert a double to a string, suitable for display within a GUI.
bool stringToUInt(const std::string &s, unsigned int &val)
convert string to unsigned integer value, returns true, if sucessful
std::string GetDataDir()
returns the full path to the data directory
std::string getPathPrefix(const std::string &filename)
Get the path to a filename.
std::string GetAbsoluteFilename(const std::string &filename)
returns the full absolute filename
bool IsFileTypeSupported(const std::string &filename)
return true, if file type by extension is supported by vigra
std::string getExtension(const std::string &basename2)
Get extension of a filename.
std::string stripExtension(const std::string &basename2)
remove extension of a filename
bool stringToInt(const std::string &s, int &val)
convert string to integer value, returns true, if sucessful
bool initGPU(int *argcp, char **argv)
Try to initalise GLUT and GLEW, and create an OpenGL context for GPU stitching.
bool StringContainsCaseInsensitive(const std::string &s1, const std::string &s2)
check if s1 contains s2 using case insensitive comparison
void ReplaceAll(std::string &s, const std::string &oldChar, char newChar)
replace all characters oldChar in s with newChar
bool CreateContext(int *argcp, char **argv)
std::vector< std::string > GetRawExtensions()
return vector of known extensions of raw files, all lower case
std::string GetUserAppDataDir()
returns the directory for user specific Hugin settings, e.g.
void ControlPointErrorColour(const double cperr, double &r, double &g, double &b)
std::string GetHuginVersion()
return a string with version numbers
bool IsRawExtension(const std::string testExt)
return true if extension belongs to a raw file
std::vector< std::string > SplitString(const std::string &s, const std::string &sep)
split string s at given sep, returns vector of strings
std::string tolower(const std::string &s)
convert a string to lowercase
std::string stripPath(const std::string &filename)
remove the path of a filename (mainly useful for gui display of filenames)