1 /*
2 */
3
4 /*
5
6 Copyright (C) 2014 Ferrero Andrea
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 This program 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
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21
22 */
23
24 /*
25
26 These files are distributed with PhotoFlow - http://aferrero2707.github.io/PhotoFlow/
27
28 */
29
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <errno.h>
33 #include <limits.h>
34 #include <stdlib.h>
35 #include <glibmm.h>
36
37 #include <stdio.h> /* defines FILENAME_MAX */
38 //#ifdef WINDOWS
39 #if defined(__MINGW32__) || defined(__MINGW64__)
40 #include <direct.h>
41 #include <shlobj.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <unistd.h>
45 #define GetCurrentDir _getcwd
46 #else
47 #include <sys/time.h>
48 #include <sys/resource.h>
49 #include <unistd.h>
50 #define GetCurrentDir getcwd
51 #endif
52
53 #if defined(__MINGW32__) || defined(__MINGW64__)
54 #include<windows.h>
55 #endif
56
57 #if defined(__APPLE__) && defined (__MACH__)
58 #include <mach-o/dyld.h>
59 #endif
60
61 #include "pf_mkstemp.hh"
62 #include "imageprocessor.hh"
63 #include "photoflow.hh"
64 #include "print_display_profile.hh"
65
66 #include "../rt/rtengine/rtlensfun.h"
67
68 #include "../vips/gmic/gmic/src/gmic.h"
69
70
71 #if defined(__MINGW32__) || defined(__MINGW64__)
_lf_get_database_dir()72 const char* _lf_get_database_dir()
73 {
74 std::string dbdir;
75 //if( getenv("LOCALAPPDATA") ) {
76 // dbdir = getenv("LOCALAPPDATA");
77 if( getenv("PROGRAMDATA") ) {
78 dbdir = getenv("PROGRAMDATA");
79 dbdir += "\\lensfun\\version_1";
80 }
81 std::cout<<"LensFun database dir: "<<dbdir<<std::endl;
82 return dbdir.c_str();
83 }
84 #endif
85
write_escaped(std::string const & s,std::string & s2)86 static void write_escaped(std::string const& s, std::string& s2) {
87 //s2 += '"';
88 for (std::string::const_iterator i = s.begin(), end = s.end(); i != end; ++i) {
89 unsigned char c = *i;
90 if (' ' <= c and c <= '~' and c != '\\' and c != '"') {
91 s2 += c;
92 }
93 else {
94 s2 += '\\';
95 switch(c) {
96 case '"': s2 += '"'; break;
97 case '\\': s2 += '\\'; break;
98 case '\t': s2 += 't'; break;
99 case '\r': s2 += 'r'; break;
100 case '\n': s2 += 'n'; break;
101 default:
102 char const* const hexdig = "0123456789ABCDEF";
103 s2 += 'x';
104 s2 += hexdig[c >> 4];
105 s2 += hexdig[c & 0xF];
106 }
107 }
108 }
109 //s2 += '"';
110 }
111
PhotoFlow()112 PF::PhotoFlow::PhotoFlow():
113 active_image( NULL ), messanger( NULL ),
114 batch(true), plugin(false),
115 single_win_mode(true)
116 {
117 // Create the cache directory if possible
118 char fname[500];
119
120 PF::print_display_profile();
121
122 #if defined(__MINGW32__) || defined(__MINGW64__)
123 char fname2[500];
124 DWORD check = GetTempPath(499, fname);
125 if (0 != check) {
126 sprintf( fname2,"%s\\photoflow", fname );
127 int result = mkdir(fname2);
128 if( (result != 0) && (errno != EEXIST) ) {
129 perror("mkdir");
130 std::cout<<"Cannot create "<<fname2<<" exiting."<<std::endl;
131 exit( 1 );
132 }
133 sprintf( fname2,"%s\\photoflow\\cache\\", fname );
134 result = mkdir(fname2);
135 if( (result != 0) && (errno != EEXIST) ) {
136 perror("mkdir");
137 std::cout<<"Cannot create "<<fname2<<" exiting."<<std::endl;
138 exit( 1 );
139 }
140 cache_dir = fname2;
141 }
142 #else
143 if( getenv("HOME") ) {
144 sprintf( fname,"%s/.photoflow", getenv("HOME") );
145 int result = mkdir(fname, 0755);
146 if( (result == 0) || (errno == EEXIST) ) {
147 sprintf( fname,"%s/.photoflow/cache/", getenv("HOME") );
148 result = mkdir(fname, 0755);
149 if( (result != 0) && (errno != EEXIST) ) {
150 perror("mkdir");
151 std::cout<<"Cannot create "<<fname<<" exiting."<<std::endl;
152 exit( 1 );
153 }
154 } else {
155 perror("mkdir");
156 std::cout<<"Cannot create "<<fname<<" (result="<<result<<") exiting."<<std::endl;
157 exit( 1 );
158 }
159 cache_dir = fname;
160 }
161 #endif
162
163 #if defined(__MINGW32__) || defined(__MINGW64__)
164 WCHAR pathW[MAX_PATH] = {0};
165 char pathA[MAX_PATH];
166
167 if (SHGetSpecialFolderPathW(NULL, pathW, CSIDL_LOCAL_APPDATA, false)) {
168 WideCharToMultiByte(CP_UTF8, 0, pathW, -1, pathA, MAX_PATH, 0, 0);
169 presets_dir = Glib::build_filename(Glib::ustring(pathA), "photoflow");
170 int result = mkdir(presets_dir.c_str());
171 if( (result == 0) || (errno == EEXIST) ) {
172 presets_dir = Glib::build_filename(presets_dir, "presets");
173 result = mkdir(presets_dir.c_str());
174 if( (result != 0) && (errno != EEXIST) ) {
175 perror("mkdir");
176 std::cout<<"Cannot create "<<presets_dir<<" exiting."<<std::endl;
177 exit( 1 );
178 }
179 }
180 }
181 #else
182 if( getenv("HOME") ) {
183 sprintf( fname,"%s/.photoflow", getenv("HOME") );
184 int result = mkdir(fname, 0755);
185 if( (result == 0) || (errno == EEXIST) ) {
186 sprintf( fname,"%s/.photoflow/presets/", getenv("HOME") );
187 result = mkdir(fname, 0755);
188 if( (result != 0) && (errno != EEXIST) ) {
189 perror("mkdir");
190 std::cout<<"Cannot create "<<fname<<" exiting."<<std::endl;
191 exit( 1 );
192 }
193 } else {
194 perror("mkdir");
195 std::cout<<"Cannot create "<<fname<<" (result="<<result<<") exiting."<<std::endl;
196 exit( 1 );
197 }
198 presets_dir = fname;
199 }
200 #endif
201
202 #if defined(__MINGW32__) || defined(__MINGW64__)
203 if (SHGetSpecialFolderPathW(NULL, pathW, CSIDL_LOCAL_APPDATA, false)) {
204 WideCharToMultiByte(CP_UTF8, 0, pathW, -1, pathA, MAX_PATH, 0, 0);
205 config_dir = Glib::build_filename(Glib::ustring(pathA), "photoflow");
206 int result = mkdir(config_dir.c_str());
207 if( (result == 0) || (errno == EEXIST) ) {
208 config_dir = Glib::build_filename(config_dir, "config");
209 result = mkdir(config_dir.c_str());
210 if( (result != 0) && (errno != EEXIST) ) {
211 perror("mkdir");
212 std::cout<<"Cannot create "<<config_dir<<" exiting."<<std::endl;
213 exit( 1 );
214 }
215 }
216 }
217 #else
218 if( getenv("HOME") ) {
219 sprintf( fname,"%s/.photoflow", getenv("HOME") );
220 int result = mkdir(fname, 0755);
221 if( (result == 0) || (errno == EEXIST) ) {
222 sprintf( fname,"%s/.photoflow/config/", getenv("HOME") );
223 result = mkdir(fname, 0755);
224 if( (result != 0) && (errno != EEXIST) ) {
225 perror("mkdir");
226 std::cout<<"Cannot create "<<fname<<" exiting."<<std::endl;
227 exit( 1 );
228 }
229 } else {
230 perror("mkdir");
231 std::cout<<"Cannot create "<<fname<<" (result="<<result<<") exiting."<<std::endl;
232 exit( 1 );
233 }
234 config_dir = fname;
235 }
236 #endif
237
238 char exname[512] = {0};
239 Glib::ustring exePath;
240 // get the path where the executable is stored
241 #ifdef WIN32
242 WCHAR exnameU[512] = {0};
243 GetModuleFileNameW (NULL, exnameU, 512);
244 WideCharToMultiByte(CP_UTF8,0,exnameU,-1,exname,512,0,0 );
245 #elif defined(__APPLE__) && defined (__MACH__)
246 char path[1024];
247 uint32_t size = sizeof(exname);
248 if (_NSGetExecutablePath(exname, &size) == 0)
249 printf("executable path is %s\n", exname);
250 else
251 printf("buffer too small; need size %u\n", size);
252 #else
253 if (readlink("/proc/self/exe", exname, 512) < 0) {
254 //strncpy(exname, argv[0], 512);
255 std::cout<<"Cannot determine full executable name."<<std::endl;
256 exname[0] = '\0';
257 }
258 #endif
259 exePath = Glib::path_get_dirname(exname);
260 std::cout<<"exePath: "<<exePath<<std::endl;
261
262 Glib::ustring dataPath;
263 #if defined(__APPLE__) && defined (__MACH__)
264 char* dataPath_env = getenv("PF_DATA_DIR");
265 if( dataPath_env ) {
266 dataPath = Glib::ustring(dataPath_env) + "/photoflow/";
267 } else {
268 dataPath = exePath + "/../share/photoflow/";
269 }
270 #elif defined(WIN32)
271 //if( getenv("LOCALAPPDATA") ) {
272 // dataPath = getenv("LOCALAPPDATA");
273 if( false && getenv("PROGRAMDATA") ) {
274 dataPath = getenv("PROGRAMDATA");
275 dataPath += "\\photoflow\\";
276 Glib::ustring testPath = dataPath + "\\gmic_def.gmic";
277 struct stat stat_buf;
278 if( stat(testPath.c_str(), &stat_buf) ) {
279 dataPath = exePath + "\\..\\share\\photoflow\\";
280 }
281 } else {
282 dataPath = exePath + "\\..\\share\\photoflow\\";
283 }
284 #else
285 char* dataPath_env = getenv("PF_DATA_DIR");
286 if( dataPath_env ) {
287 dataPath = Glib::ustring(dataPath_env) + "/photoflow/";
288 } else {
289 dataPath = Glib::ustring(INSTALL_PREFIX) + "/share/photoflow/";
290 }
291 #endif
292 std::cout<<"dataPath: "<<dataPath<<std::endl;
293
294 std::string dataPathEscaped;
295 write_escaped(dataPath, dataPathEscaped);
296 Glib::setenv("GMIC_SYSTEM_PATH", dataPathEscaped.c_str(), 1);
297
298 lensfun_db_dir = dataPath;
299 #if defined(WIN32)
300 lensfun_db_dir += "\\lensfun\\version_1\\";
301 #else
302 lensfun_db_dir += "/lensfun/version_1/";
303 #endif
304
305 Glib::ustring localePath;
306 #if defined(__APPLE__) && defined (__MACH__)
307 if( dataPath_env ) {
308 localePath = Glib::ustring(dataPath_env) + "/locale";
309 } else {
310 localePath = exePath + "/../share/locale";
311 }
312 #elif defined(WIN32)
313 localePath = exePath + "\\..\\share\\locale\\";
314 #else
315 if( dataPath_env ) {
316 localePath = Glib::ustring(dataPath_env) + "/locale";
317 } else {
318 localePath = Glib::ustring(INSTALL_PREFIX) + "/share/locale";
319 }
320 #endif
321 std::cout<<"localePath: "<<localePath<<std::endl;
322
323 gmic::init_rc();
324
325 set_base_dir( exePath );
326 set_data_dir( dataPath );
327 set_locale_dir( localePath );
328
329 Glib::ustring lfdb;
330 #if (BUNDLED_LENSFUN_DB == 1)
331 lfdb = get_lensfun_db_dir();
332 #endif
333 std::cout<<"Calling rtengine::LFDatabase::init(\""<<lfdb<<"\")"<<std::endl;
334 rtengine::LFDatabase::init( lfdb );
335 }
336
337
338 PF::PhotoFlow* PF::PhotoFlow::instance = NULL;
339
Instance()340 PF::PhotoFlow& PF::PhotoFlow::Instance()
341 {
342 if(!PF::PhotoFlow::instance)
343 PF::PhotoFlow::instance = new PF::PhotoFlow();
344 return( *instance );
345 };
346
347
close()348 void PF::PhotoFlow::close()
349 {
350 //PF::ImageProcessor::Instance().join();
351
352 //im_close_plugins();
353 //sleep(10);
354 std::cout<<"PhotoFlow::close(): calling vips shutdown"<<std::endl;
355 vips_shutdown();
356 std::cout<<"PhotoFlow::close(): vips shutdown done"<<std::endl;
357
358 options.save();
359 /*
360 #if defined(__MINGW32__) || defined(__MINGW64__)
361 for (int i = 0; i < _getmaxstdio(); ++i) ::close (i);
362 #elif defined(__APPLE__) && defined(__MACH__)
363 #else
364 rlimit rlim;
365 //getrlimit(RLIMIT_NOFILE, &rlim);
366 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
367 std::cout<<"rlim.rlim_max="<<rlim.rlim_max<<std::endl;
368 for (int i = 3; i < rlim.rlim_max; ++i) {
369 //std::cout<<"i="<<i<<std::endl;
370 //::close (i);
371 }
372 }
373 #endif
374 */
375 std::cout<<"PhotoFlow::close(): deleting cache files"<<std::endl;
376 std::list<std::string>::iterator fi;
377 for(fi = cache_files.begin(); fi != cache_files.end(); fi++) {
378 std::cout<<" deleting "<<fi->c_str()<<std::endl;
379 unlink( fi->c_str() );
380 std::cout<<" "<<fi->c_str()<<" deleted"<<std::endl;
381 }
382 std::cout<<"PhotoFlow::close(): cache files deleted"<<std::endl;
383 }
384
385
386
obj_unref(GObject * obj,char * msg)387 void PF::PhotoFlow::obj_unref( GObject* obj, char* msg )
388 {
389 if( PF::PhotoFlow::Instance().is_batch() ){
390 PF_UNREF( obj, msg );
391 } else {
392 ProcessRequestInfo request;
393 request.obj = obj;
394 request.request = PF::OBJECT_UNREF;
395 PF::ImageProcessor::Instance().submit_request( request );
396 }
397 }
398
399
pf_object_ref(GObject * object,const char * msg)400 void PF::pf_object_ref(GObject* object, const char* msg)
401 {
402 #ifdef PF_VERBOSE_UNREF
403 std::cout<<"pf_object_ref()";
404 if(msg) std::cout<<": "<<msg;
405 std::cout<<std::endl;
406 std::cout<<" object="<<object<<std::endl;
407 #endif
408 if( !object ) {
409 #ifdef PF_VERBOSE_UNREF
410 std::cout<<" NULL object!!!"<<std::endl;
411 #endif
412 return;
413 }
414 #ifdef PF_VERBOSE_UNREF
415 std::cout<<" ref_count before: "<<object->ref_count<<std::endl;
416 #endif
417 g_object_ref( object );
418 #ifdef PF_VERBOSE_UNREF
419 std::cout<<" ref_count after: "<<object->ref_count<<std::endl;
420 #endif
421 }
422
423
424 //#define PF_VERBOSE_UNREF 1
425
pf_object_unref(GObject * object,const char * msg)426 void PF::pf_object_unref(GObject* object, const char* msg)
427 {
428 #ifdef PF_VERBOSE_UNREF
429 std::cout<<"pf_object_unref()";
430 if(msg) std::cout<<": "<<msg;
431 std::cout<<std::endl;
432 std::cout<<" object="<<object<<std::endl;
433 #endif
434 if( !object ) {
435 #ifdef PF_VERBOSE_UNREF
436 std::cout<<" NULL object!!!"<<std::endl;
437 #endif
438 return;
439 }
440 #ifdef PF_VERBOSE_UNREF
441 std::cout<<" ref_count before: "<<object->ref_count<<std::endl;
442 #endif
443 g_assert( object->ref_count > 0 );
444 g_object_unref( object );
445 #ifdef PF_VERBOSE_UNREF
446 std::cout<<" ref_count after: "<<object->ref_count<<std::endl;
447 #endif
448 }
449