Commit 56415f0ed79f7b5e686f125e817273231ab1b616
Committed by
GitHub
1 parent
f30a57f6
Exists in
master
Encoding Errors in Windows (#110)
Fix the above unicode related errors: - InVesalius was not starting in Windows with users with non ascii chars. - Not opening dicom files from path with non ascii chars. - Not opening bitmap files from path with non ascii chars. - Not opening Analyze, Nifti with filename with non ascii chars. - Not exporting surface when the path has non ascii chars. - Not exporting picture when the path has non ascii chars. - Not importing surface when the path has non ascii chars. - Strange chars when showing developers and translators with non ascii chars. To fix that errors we are convert all paths and filenames to unicode. wxPythons eases this, since it gives the paths and filenames as unicode. When using VTK to save or open a file we encode the filename to sys.getfilesystemencoding. In Windows it is necessary an additional step, convert the filename to an short representation using [win32api](http://docs.activestate.com/activepython/2.6/pywin32/win32api__GetShortPathName_meth.html).
Showing
20 changed files
with
477 additions
and
205 deletions
Show diff stats
app.py
@@ -54,6 +54,22 @@ import invesalius.i18n as i18n | @@ -54,6 +54,22 @@ import invesalius.i18n as i18n | ||
54 | import invesalius.session as ses | 54 | import invesalius.session as ses |
55 | import invesalius.utils as utils | 55 | import invesalius.utils as utils |
56 | 56 | ||
57 | +FS_ENCODE = sys.getfilesystemencoding() | ||
58 | + | ||
59 | +if sys.platform == 'win32': | ||
60 | + from invesalius.expanduser import expand_user | ||
61 | + try: | ||
62 | + USER_DIR = expand_user() | ||
63 | + except: | ||
64 | + USER_DIR = os.path.expanduser('~').decode(FS_ENCODE) | ||
65 | +else: | ||
66 | + USER_DIR = os.path.expanduser('~').decode(FS_ENCODE) | ||
67 | + | ||
68 | +USER_INV_DIR = os.path.join(USER_DIR, u'.invesalius') | ||
69 | +USER_PRESET_DIR = os.path.join(USER_INV_DIR, u'presets') | ||
70 | +USER_RAYCASTING_PRESETS_DIRECTORY = os.path.join(USER_PRESET_DIR, u'raycasting') | ||
71 | +USER_LOG_DIR = os.path.join(USER_INV_DIR, u'logs') | ||
72 | + | ||
57 | # ------------------------------------------------------------------ | 73 | # ------------------------------------------------------------------ |
58 | 74 | ||
59 | 75 | ||
@@ -157,7 +173,7 @@ class SplashScreen(wx.SplashScreen): | @@ -157,7 +173,7 @@ class SplashScreen(wx.SplashScreen): | ||
157 | # Only after language was defined, splash screen will be | 173 | # Only after language was defined, splash screen will be |
158 | # shown | 174 | # shown |
159 | if lang: | 175 | if lang: |
160 | - print "LANG", lang, _, wx.Locale(), wx.GetLocale() | 176 | + # print "LANG", lang, _, wx.Locale(), wx.GetLocale() |
161 | import locale | 177 | import locale |
162 | locale.setlocale(locale.LC_ALL, '') | 178 | locale.setlocale(locale.LC_ALL, '') |
163 | # For pt_BR, splash_pt.png should be used | 179 | # For pt_BR, splash_pt.png should be used |
@@ -237,6 +253,8 @@ def parse_comand_line(): | @@ -237,6 +253,8 @@ def parse_comand_line(): | ||
237 | """ | 253 | """ |
238 | session = ses.Session() | 254 | session = ses.Session() |
239 | 255 | ||
256 | + print ">>>> stdin encoding", sys.stdin.encoding | ||
257 | + | ||
240 | # Parse command line arguments | 258 | # Parse command line arguments |
241 | parser = op.OptionParser() | 259 | parser = op.OptionParser() |
242 | 260 | ||
@@ -269,7 +287,7 @@ def parse_comand_line(): | @@ -269,7 +287,7 @@ def parse_comand_line(): | ||
269 | i = len(args) | 287 | i = len(args) |
270 | while i: | 288 | while i: |
271 | i -= 1 | 289 | i -= 1 |
272 | - file = args[i] | 290 | + file = args[i].decode(sys.stdin.encoding) |
273 | if os.path.isfile(file): | 291 | if os.path.isfile(file): |
274 | path = os.path.abspath(file) | 292 | path = os.path.abspath(file) |
275 | Publisher.sendMessage('Open project', path) | 293 | Publisher.sendMessage('Open project', path) |
@@ -308,22 +326,16 @@ if __name__ == '__main__': | @@ -308,22 +326,16 @@ if __name__ == '__main__': | ||
308 | os.chdir(path) | 326 | os.chdir(path) |
309 | 327 | ||
310 | # Create raycasting presets' folder, if it doens't exist | 328 | # Create raycasting presets' folder, if it doens't exist |
311 | - dirpath = os.path.join(os.path.expanduser('~'), | ||
312 | - ".invesalius", | ||
313 | - "presets") | ||
314 | - if not os.path.isdir(dirpath): | ||
315 | - os.makedirs(dirpath) | 329 | + if not os.path.isdir(USER_RAYCASTING_PRESETS_DIRECTORY): |
330 | + os.makedirs(USER_RAYCASTING_PRESETS_DIRECTORY) | ||
316 | 331 | ||
317 | # Create logs' folder, if it doesn't exist | 332 | # Create logs' folder, if it doesn't exist |
318 | - dirpath = os.path.join(os.path.expanduser('~'), | ||
319 | - ".invesalius", | ||
320 | - "logs") | ||
321 | - if not os.path.isdir(dirpath): | ||
322 | - os.makedirs(dirpath) | 333 | + if not os.path.isdir(USER_LOG_DIR): |
334 | + os.makedirs(USER_LOG_DIR) | ||
323 | 335 | ||
324 | if hasattr(sys,"frozen") and sys.frozen == "windows_exe": | 336 | if hasattr(sys,"frozen") and sys.frozen == "windows_exe": |
325 | # Set system standard error output to file | 337 | # Set system standard error output to file |
326 | - path = os.path.join(dirpath, "stderr.log") | 338 | + path = os.path.join(USER_LOG_DIR, u"stderr.log") |
327 | sys.stderr = open(path, "w") | 339 | sys.stderr = open(path, "w") |
328 | 340 | ||
329 | # Add current directory to PYTHONPATH, so other classes can | 341 | # Add current directory to PYTHONPATH, so other classes can |
invesalius/constants.py
@@ -320,46 +320,63 @@ WINDOW_LEVEL = {_("Abdomen"):(350,50), | @@ -320,46 +320,63 @@ WINDOW_LEVEL = {_("Abdomen"):(350,50), | ||
320 | 320 | ||
321 | REDUCE_IMAGEDATA_QUALITY = 0 | 321 | REDUCE_IMAGEDATA_QUALITY = 0 |
322 | 322 | ||
323 | -FILE_PATH = os.path.split(__file__)[0] | 323 | + |
324 | +# PATHS | ||
325 | +FS_ENCODE = sys.getfilesystemencoding() | ||
326 | + | ||
327 | +if sys.platform == 'win32': | ||
328 | + from invesalius.expanduser import expand_user | ||
329 | + try: | ||
330 | + USER_DIR = expand_user() | ||
331 | + except: | ||
332 | + USER_DIR = os.path.expanduser('~').decode(FS_ENCODE) | ||
333 | +else: | ||
334 | + USER_DIR = os.path.expanduser('~').decode(FS_ENCODE) | ||
335 | + | ||
336 | +USER_INV_DIR = os.path.join(USER_DIR, u'.invesalius') | ||
337 | +USER_PRESET_DIR = os.path.join(USER_INV_DIR, u'presets') | ||
338 | +USER_LOG_DIR = os.path.join(USER_INV_DIR, u'logs') | ||
339 | + | ||
340 | +FILE_PATH = os.path.split(__file__)[0].decode(FS_ENCODE) | ||
324 | 341 | ||
325 | if hasattr(sys,"frozen") and (sys.frozen == "windows_exe"\ | 342 | if hasattr(sys,"frozen") and (sys.frozen == "windows_exe"\ |
326 | or sys.frozen == "console_exe"): | 343 | or sys.frozen == "console_exe"): |
327 | - abs_path = os.path.abspath(FILE_PATH + os.sep + ".." + os.sep + ".." + os.sep + "..") | ||
328 | - ICON_DIR = os.path.join(abs_path, "icons") | ||
329 | - SAMPLE_DIR = os.path.join(FILE_PATH, 'samples') | ||
330 | - DOC_DIR = os.path.join(FILE_PATH, 'docs') | ||
331 | - folder=RAYCASTING_PRESETS_DIRECTORY= os.path.join(abs_path, "presets", "raycasting") | ||
332 | - RAYCASTING_PRESETS_COLOR_DIRECTORY = os.path.join(abs_path, "presets", "raycasting", "color_list") | 344 | + abs_path = os.path.abspath(FILE_PATH, u'..', u'..', u'..') |
345 | + ICON_DIR = os.path.join(abs_path, u"icons") | ||
346 | + SAMPLE_DIR = os.path.join(FILE_PATH, u'samples') | ||
347 | + DOC_DIR = os.path.join(FILE_PATH, u'docs') | ||
348 | + folder=RAYCASTING_PRESETS_DIRECTORY= os.path.join(abs_path, u"presets", u"raycasting") | ||
349 | + RAYCASTING_PRESETS_COLOR_DIRECTORY = os.path.join(abs_path, u"presets", u"raycasting", u"color_list") | ||
333 | 350 | ||
334 | else: | 351 | else: |
335 | - ICON_DIR = os.path.abspath(os.path.join(FILE_PATH, '..', 'icons')) | ||
336 | - SAMPLE_DIR = os.path.abspath(os.path.join(FILE_PATH,'..', 'samples')) | ||
337 | - DOC_DIR = os.path.abspath(os.path.join(FILE_PATH,'..', 'docs')) | 352 | + ICON_DIR = os.path.abspath(os.path.join(FILE_PATH, u'..', u'icons')) |
353 | + SAMPLE_DIR = os.path.abspath(os.path.join(FILE_PATH, u'..', u'samples')) | ||
354 | + DOC_DIR = os.path.abspath(os.path.join(FILE_PATH, u'..', u'docs')) | ||
338 | 355 | ||
339 | - folder=RAYCASTING_PRESETS_DIRECTORY= os.path.abspath(os.path.join(".", | ||
340 | - "presets", | ||
341 | - "raycasting")) | 356 | + folder=RAYCASTING_PRESETS_DIRECTORY= os.path.abspath(os.path.join(u".", |
357 | + u"presets", | ||
358 | + u"raycasting")) | ||
342 | 359 | ||
343 | - RAYCASTING_PRESETS_COLOR_DIRECTORY = os.path.abspath(os.path.join(".", | ||
344 | - "presets", | ||
345 | - "raycasting", | ||
346 | - "color_list")) | 360 | + RAYCASTING_PRESETS_COLOR_DIRECTORY = os.path.abspath(os.path.join(u".", |
361 | + u"presets", | ||
362 | + u"raycasting", | ||
363 | + u"color_list")) | ||
347 | 364 | ||
348 | 365 | ||
349 | # MAC App | 366 | # MAC App |
350 | if not os.path.exists(ICON_DIR): | 367 | if not os.path.exists(ICON_DIR): |
351 | - ICON_DIR = os.path.abspath(os.path.join(FILE_PATH, '..', '..', '..', '..', 'icons')) | ||
352 | - SAMPLE_DIR = os.path.abspath(os.path.join(FILE_PATH,'..', '..', '..', '..', 'samples')) | ||
353 | - DOC_DIR = os.path.abspath(os.path.join(FILE_PATH,'..', '..', '..', '..', 'docs')) | ||
354 | - | ||
355 | - | ||
356 | -ID_TO_BMP = {VOL_FRONT: [_("Front"), os.path.join(ICON_DIR, "view_front.png")], | ||
357 | - VOL_BACK: [_("Back"), os.path.join(ICON_DIR, "view_back.png")], | ||
358 | - VOL_TOP: [_("Top"), os.path.join(ICON_DIR, "view_top.png")], | ||
359 | - VOL_BOTTOM: [_("Bottom"), os.path.join(ICON_DIR, "view_bottom.png")], | ||
360 | - VOL_RIGHT: [_("Right"), os.path.join(ICON_DIR, "view_right.png")], | ||
361 | - VOL_LEFT: [_("Left"), os.path.join(ICON_DIR, "view_left.png")], | ||
362 | - VOL_ISO:[_("Isometric"), os.path.join(ICON_DIR,"view_isometric.png")] | 368 | + ICON_DIR = os.path.abspath(os.path.join(FILE_PATH, u'..', u'..', u'..', u'..', u'icons')) |
369 | + SAMPLE_DIR = os.path.abspath(os.path.join(FILE_PATH, u'..', u'..', u'..', u'..', u'samples')) | ||
370 | + DOC_DIR = os.path.abspath(os.path.join(FILE_PATH, u'..', u'..', u'..', u'..', u'docs')) | ||
371 | + | ||
372 | + | ||
373 | +ID_TO_BMP = {VOL_FRONT: [_("Front"), os.path.join(ICON_DIR, u"view_front.png")], | ||
374 | + VOL_BACK: [_("Back"), os.path.join(ICON_DIR, u"view_back.png")], | ||
375 | + VOL_TOP: [_("Top"), os.path.join(ICON_DIR, u"view_top.png")], | ||
376 | + VOL_BOTTOM: [_("Bottom"), os.path.join(ICON_DIR, u"view_bottom.png")], | ||
377 | + VOL_RIGHT: [_("Right"), os.path.join(ICON_DIR, u"view_right.png")], | ||
378 | + VOL_LEFT: [_("Left"), os.path.join(ICON_DIR, u"view_left.png")], | ||
379 | + VOL_ISO:[_("Isometric"), os.path.join(ICON_DIR, u"view_isometric.png")] | ||
363 | } | 380 | } |
364 | 381 | ||
365 | # if 1, use vtkVolumeRaycastMapper, if 0, use vtkFixedPointVolumeRayCastMapper | 382 | # if 1, use vtkVolumeRaycastMapper, if 0, use vtkFixedPointVolumeRayCastMapper |
@@ -405,19 +422,10 @@ RAYCASTING_FILES = {_("Airways"): "Airways.plist", | @@ -405,19 +422,10 @@ RAYCASTING_FILES = {_("Airways"): "Airways.plist", | ||
405 | # os.path.isfile(os.path.join(folder,filename))] | 422 | # os.path.isfile(os.path.join(folder,filename))] |
406 | 423 | ||
407 | 424 | ||
408 | -LOG_FOLDER = os.path.join(os.path.expanduser('~'), '.invesalius', 'logs') | ||
409 | -if not os.path.isdir(LOG_FOLDER): | ||
410 | - os.makedirs(LOG_FOLDER) | ||
411 | - | ||
412 | -folder = os.path.join(os.path.expanduser('~'), '.invesalius', 'presets') | ||
413 | -if not os.path.isdir(folder): | ||
414 | - os.makedirs(folder) | ||
415 | - | ||
416 | - | ||
417 | -USER_RAYCASTING_PRESETS_DIRECTORY = folder | 425 | +USER_RAYCASTING_PRESETS_DIRECTORY = os.path.join(USER_PRESET_DIR, u'raycasting') |
418 | RAYCASTING_TYPES = [_(filename.split(".")[0]) for filename in | 426 | RAYCASTING_TYPES = [_(filename.split(".")[0]) for filename in |
419 | - os.listdir(folder) if | ||
420 | - os.path.isfile(os.path.join(folder,filename))] | 427 | + os.listdir(USER_RAYCASTING_PRESETS_DIRECTORY) if |
428 | + os.path.isfile(os.path.join(USER_RAYCASTING_PRESETS_DIRECTORY, filename))] | ||
421 | RAYCASTING_TYPES += RAYCASTING_FILES.keys() | 429 | RAYCASTING_TYPES += RAYCASTING_FILES.keys() |
422 | RAYCASTING_TYPES.append(_(' Off')) | 430 | RAYCASTING_TYPES.append(_(' Off')) |
423 | RAYCASTING_TYPES.sort() | 431 | RAYCASTING_TYPES.sort() |
invesalius/control.py
@@ -338,6 +338,9 @@ class Controller(): | @@ -338,6 +338,9 @@ class Controller(): | ||
338 | else: | 338 | else: |
339 | dirpath, filename = session.project_path | 339 | dirpath, filename = session.project_path |
340 | 340 | ||
341 | + if isinstance(filename, str): | ||
342 | + filename = filename.decode(const.FS_ENCODE) | ||
343 | + | ||
341 | proj = prj.Project() | 344 | proj = prj.Project() |
342 | prj.Project().SavePlistProject(dirpath, filename) | 345 | prj.Project().SavePlistProject(dirpath, filename) |
343 | 346 |
invesalius/data/imagedata_utils.py
@@ -227,7 +227,7 @@ def CreateImageData(filelist, zspacing, xyspacing,size, | @@ -227,7 +227,7 @@ def CreateImageData(filelist, zspacing, xyspacing,size, | ||
227 | message = _("Generating multiplanar visualization...") | 227 | message = _("Generating multiplanar visualization...") |
228 | 228 | ||
229 | if not const.VTK_WARNING: | 229 | if not const.VTK_WARNING: |
230 | - log_path = os.path.join(const.LOG_FOLDER, 'vtkoutput.txt') | 230 | + log_path = os.path.join(const.USER_LOG_DIR, 'vtkoutput.txt') |
231 | fow = vtk.vtkFileOutputWindow() | 231 | fow = vtk.vtkFileOutputWindow() |
232 | fow.SetFileName(log_path) | 232 | fow.SetFileName(log_path) |
233 | ow = vtk.vtkOutputWindow() | 233 | ow = vtk.vtkOutputWindow() |
@@ -332,7 +332,7 @@ class ImageCreator: | @@ -332,7 +332,7 @@ class ImageCreator: | ||
332 | message = _("Generating multiplanar visualization...") | 332 | message = _("Generating multiplanar visualization...") |
333 | 333 | ||
334 | if not const.VTK_WARNING: | 334 | if not const.VTK_WARNING: |
335 | - log_path = os.path.join(const.LOG_FOLDER, 'vtkoutput.txt') | 335 | + log_path = os.path.join(const.USER_LOG_DIR, 'vtkoutput.txt') |
336 | fow = vtk.vtkFileOutputWindow() | 336 | fow = vtk.vtkFileOutputWindow() |
337 | fow.SetFileName(log_path) | 337 | fow.SetFileName(log_path) |
338 | ow = vtk.vtkOutputWindow() | 338 | ow = vtk.vtkOutputWindow() |
invesalius/data/mask.py
@@ -245,7 +245,7 @@ class Mask(): | @@ -245,7 +245,7 @@ class Mask(): | ||
245 | mask['mask_shape'] = self.matrix.shape | 245 | mask['mask_shape'] = self.matrix.shape |
246 | mask['edited'] = self.was_edited | 246 | mask['edited'] = self.was_edited |
247 | 247 | ||
248 | - plist_filename = filename + '.plist' | 248 | + plist_filename = filename + u'.plist' |
249 | #plist_filepath = os.path.join(dir_temp, plist_filename) | 249 | #plist_filepath = os.path.join(dir_temp, plist_filename) |
250 | 250 | ||
251 | temp_plist = tempfile.mktemp() | 251 | temp_plist = tempfile.mktemp() |
invesalius/data/polydata_utils.py
@@ -23,7 +23,18 @@ import vtk | @@ -23,7 +23,18 @@ import vtk | ||
23 | import wx | 23 | import wx |
24 | from wx.lib.pubsub import pub as Publisher | 24 | from wx.lib.pubsub import pub as Publisher |
25 | 25 | ||
26 | +import invesalius.constants as const | ||
26 | import invesalius.data.vtk_utils as vu | 27 | import invesalius.data.vtk_utils as vu |
28 | +from invesalius.utils import touch | ||
29 | + | ||
30 | +if sys.platform == 'win32': | ||
31 | + try: | ||
32 | + import win32api | ||
33 | + _has_win32api = True | ||
34 | + except ImportError: | ||
35 | + _has_win32api = False | ||
36 | +else: | ||
37 | + _has_win32api = False | ||
27 | 38 | ||
28 | # Update progress value in GUI | 39 | # Update progress value in GUI |
29 | UpdateProgress = vu.ShowProgress() | 40 | UpdateProgress = vu.ShowProgress() |
@@ -109,8 +120,10 @@ def Merge(polydata_list): | @@ -109,8 +120,10 @@ def Merge(polydata_list): | ||
109 | 120 | ||
110 | def Export(polydata, filename, bin=False): | 121 | def Export(polydata, filename, bin=False): |
111 | writer = vtk.vtkXMLPolyDataWriter() | 122 | writer = vtk.vtkXMLPolyDataWriter() |
112 | - print filename, type(filename) | ||
113 | - writer.SetFileName(filename.encode('utf-8')) | 123 | + if _has_win32api: |
124 | + touch(filename) | ||
125 | + filename = win32api.GetShortPathName(filename) | ||
126 | + writer.SetFileName(filename.encode(const.FS_ENCODE)) | ||
114 | if bin: | 127 | if bin: |
115 | writer.SetDataModeToBinary() | 128 | writer.SetDataModeToBinary() |
116 | else: | 129 | else: |
invesalius/data/surface.py
@@ -21,6 +21,8 @@ import multiprocessing | @@ -21,6 +21,8 @@ import multiprocessing | ||
21 | import os | 21 | import os |
22 | import plistlib | 22 | import plistlib |
23 | import random | 23 | import random |
24 | +import shutil | ||
25 | +import sys | ||
24 | import tempfile | 26 | import tempfile |
25 | import weakref | 27 | import weakref |
26 | 28 | ||
@@ -28,6 +30,15 @@ import vtk | @@ -28,6 +30,15 @@ import vtk | ||
28 | import wx | 30 | import wx |
29 | from wx.lib.pubsub import pub as Publisher | 31 | from wx.lib.pubsub import pub as Publisher |
30 | 32 | ||
33 | +if sys.platform == 'win32': | ||
34 | + try: | ||
35 | + import win32api | ||
36 | + _has_win32api = True | ||
37 | + except ImportError: | ||
38 | + _has_win32api = False | ||
39 | +else: | ||
40 | + _has_win32api = False | ||
41 | + | ||
31 | import invesalius.constants as const | 42 | import invesalius.constants as const |
32 | import invesalius.data.imagedata_utils as iu | 43 | import invesalius.data.imagedata_utils as iu |
33 | import invesalius.data.polydata_utils as pu | 44 | import invesalius.data.polydata_utils as pu |
@@ -64,8 +75,8 @@ class Surface(): | @@ -64,8 +75,8 @@ class Surface(): | ||
64 | self.name = name | 75 | self.name = name |
65 | 76 | ||
66 | def SavePlist(self, dir_temp, filelist): | 77 | def SavePlist(self, dir_temp, filelist): |
67 | - filename = 'surface_%d' % self.index | ||
68 | - vtp_filename = filename + '.vtp' | 78 | + filename = u'surface_%d' % self.index |
79 | + vtp_filename = filename + u'.vtp' | ||
69 | vtp_filepath = os.path.join(dir_temp, vtp_filename) | 80 | vtp_filepath = os.path.join(dir_temp, vtp_filename) |
70 | pu.Export(self.polydata, vtp_filepath, bin=True) | 81 | pu.Export(self.polydata, vtp_filepath, bin=True) |
71 | 82 | ||
@@ -80,7 +91,7 @@ class Surface(): | @@ -80,7 +91,7 @@ class Surface(): | ||
80 | 'volume': self.volume, | 91 | 'volume': self.volume, |
81 | 'area': self.area, | 92 | 'area': self.area, |
82 | } | 93 | } |
83 | - plist_filename = filename + '.plist' | 94 | + plist_filename = filename + u'.plist' |
84 | #plist_filepath = os.path.join(dir_temp, filename + '.plist') | 95 | #plist_filepath = os.path.join(dir_temp, filename + '.plist') |
85 | temp_plist = tempfile.mktemp() | 96 | temp_plist = tempfile.mktemp() |
86 | plistlib.writePlist(surface, temp_plist) | 97 | plistlib.writePlist(surface, temp_plist) |
@@ -263,7 +274,11 @@ class SurfaceManager(): | @@ -263,7 +274,11 @@ class SurfaceManager(): | ||
263 | wx.MessageBox(_("File format not reconized by InVesalius"), _("Import surface error")) | 274 | wx.MessageBox(_("File format not reconized by InVesalius"), _("Import surface error")) |
264 | return | 275 | return |
265 | 276 | ||
266 | - reader.SetFileName(filename) | 277 | + if _has_win32api: |
278 | + reader.SetFileName(win32api.GetShortPathName(filename).encode(const.FS_ENCODE)) | ||
279 | + else: | ||
280 | + reader.SetFileName(filename.encode(const.FS_ENCODE)) | ||
281 | + | ||
267 | reader.Update() | 282 | reader.Update() |
268 | polydata = reader.GetOutput() | 283 | polydata = reader.GetOutput() |
269 | 284 | ||
@@ -869,11 +884,31 @@ class SurfaceManager(): | @@ -869,11 +884,31 @@ class SurfaceManager(): | ||
869 | 884 | ||
870 | def OnExportSurface(self, pubsub_evt): | 885 | def OnExportSurface(self, pubsub_evt): |
871 | filename, filetype = pubsub_evt.data | 886 | filename, filetype = pubsub_evt.data |
872 | - if (filetype == const.FILETYPE_STL) or\ | ||
873 | - (filetype == const.FILETYPE_VTP) or\ | ||
874 | - (filetype == const.FILETYPE_PLY) or\ | ||
875 | - (filetype == const.FILETYPE_STL_ASCII): | ||
876 | - | 887 | + ftype_prefix = { |
888 | + const.FILETYPE_STL: '.stl', | ||
889 | + const.FILETYPE_VTP: '.vtp', | ||
890 | + const.FILETYPE_PLY: '.ply', | ||
891 | + const.FILETYPE_STL_ASCII: '.stl', | ||
892 | + } | ||
893 | + if filetype in ftype_prefix: | ||
894 | + temp_file = tempfile.mktemp(suffix=ftype_prefix[filetype]) | ||
895 | + | ||
896 | + if _has_win32api: | ||
897 | + utl.touch(temp_file) | ||
898 | + _temp_file = temp_file | ||
899 | + temp_file = win32api.GetShortPathName(temp_file) | ||
900 | + os.remove(_temp_file) | ||
901 | + | ||
902 | + temp_file = temp_file.decode(const.FS_ENCODE) | ||
903 | + self._export_surface(temp_file, filetype) | ||
904 | + | ||
905 | + shutil.move(temp_file, filename) | ||
906 | + | ||
907 | + def _export_surface(self, filename, filetype): | ||
908 | + if filetype in (const.FILETYPE_STL, | ||
909 | + const.FILETYPE_VTP, | ||
910 | + const.FILETYPE_PLY, | ||
911 | + const.FILETYPE_STL_ASCII): | ||
877 | # First we identify all surfaces that are selected | 912 | # First we identify all surfaces that are selected |
878 | # (if any) | 913 | # (if any) |
879 | proj = prj.Project() | 914 | proj = prj.Project() |
@@ -912,7 +947,9 @@ class SurfaceManager(): | @@ -912,7 +947,9 @@ class SurfaceManager(): | ||
912 | #writer.SetColorModeToUniformCellColor() | 947 | #writer.SetColorModeToUniformCellColor() |
913 | #writer.SetColor(255, 0, 0) | 948 | #writer.SetColor(255, 0, 0) |
914 | 949 | ||
915 | - if filetype in (const.FILETYPE_STL, const.FILETYPE_PLY): | 950 | + if filetype in (const.FILETYPE_STL, |
951 | + const.FILETYPE_STL_ASCII, | ||
952 | + const.FILETYPE_PLY): | ||
916 | # Invert normals | 953 | # Invert normals |
917 | normals = vtk.vtkPolyDataNormals() | 954 | normals = vtk.vtkPolyDataNormals() |
918 | normals.SetInputData(polydata) | 955 | normals.SetInputData(polydata) |
@@ -923,7 +960,7 @@ class SurfaceManager(): | @@ -923,7 +960,7 @@ class SurfaceManager(): | ||
923 | normals.Update() | 960 | normals.Update() |
924 | polydata = normals.GetOutput() | 961 | polydata = normals.GetOutput() |
925 | 962 | ||
926 | - filename = filename.encode(wx.GetDefaultPyEncoding()) | 963 | + filename = filename.encode(const.FS_ENCODE) |
927 | writer.SetFileName(filename) | 964 | writer.SetFileName(filename) |
928 | writer.SetInputData(polydata) | 965 | writer.SetInputData(polydata) |
929 | writer.Write() | 966 | writer.Write() |
invesalius/data/viewer_slice.py
@@ -21,6 +21,7 @@ | @@ -21,6 +21,7 @@ | ||
21 | 21 | ||
22 | import collections | 22 | import collections |
23 | import itertools | 23 | import itertools |
24 | +import os | ||
24 | import tempfile | 25 | import tempfile |
25 | 26 | ||
26 | import numpy as np | 27 | import numpy as np |
@@ -49,6 +50,15 @@ import invesalius.session as ses | @@ -49,6 +50,15 @@ import invesalius.session as ses | ||
49 | import invesalius.data.converters as converters | 50 | import invesalius.data.converters as converters |
50 | import invesalius.data.measures as measures | 51 | import invesalius.data.measures as measures |
51 | 52 | ||
53 | +if sys.platform == 'win32': | ||
54 | + try: | ||
55 | + import win32api | ||
56 | + _has_win32api = True | ||
57 | + except ImportError: | ||
58 | + _has_win32api = False | ||
59 | +else: | ||
60 | + _has_win32api = False | ||
61 | + | ||
52 | ID_TO_TOOL_ITEM = {} | 62 | ID_TO_TOOL_ITEM = {} |
53 | STR_WL = "WL: %d WW: %d" | 63 | STR_WL = "WL: %d WW: %d" |
54 | 64 | ||
@@ -1250,12 +1260,27 @@ class Viewer(wx.Panel): | @@ -1250,12 +1260,27 @@ class Viewer(wx.Panel): | ||
1250 | self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_SIZING)) | 1260 | self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_SIZING)) |
1251 | 1261 | ||
1252 | def OnExportPicture(self, pubsub_evt): | 1262 | def OnExportPicture(self, pubsub_evt): |
1253 | - Publisher.sendMessage('Begin busy cursor') | 1263 | + id, filename, filetype = pubsub_evt.data |
1264 | + | ||
1265 | + dict = {"AXIAL": const.AXIAL, | ||
1266 | + "CORONAL": const.CORONAL, | ||
1267 | + "SAGITAL": const.SAGITAL} | ||
1268 | + | ||
1269 | + if id == dict[self.orientation]: | ||
1270 | + Publisher.sendMessage('Begin busy cursor') | ||
1271 | + if _has_win32api: | ||
1272 | + utils.touch(filename) | ||
1273 | + win_filename = win32api.GetShortPathName(filename) | ||
1274 | + self._export_picture(id, win_filename, filetype) | ||
1275 | + else: | ||
1276 | + self._export_picture(id, filename, filetype) | ||
1277 | + Publisher.sendMessage('End busy cursor') | ||
1278 | + | ||
1279 | + def _export_picture(self, id, filename, filetype): | ||
1254 | view_prop_list = [] | 1280 | view_prop_list = [] |
1255 | view_prop_list.append(self.slice_data.box_actor) | 1281 | view_prop_list.append(self.slice_data.box_actor) |
1256 | self.slice_data.renderer.RemoveViewProp(self.slice_data.box_actor) | 1282 | self.slice_data.renderer.RemoveViewProp(self.slice_data.box_actor) |
1257 | 1283 | ||
1258 | - id, filename, filetype = pubsub_evt.data | ||
1259 | dict = {"AXIAL": const.AXIAL, | 1284 | dict = {"AXIAL": const.AXIAL, |
1260 | "CORONAL": const.CORONAL, | 1285 | "CORONAL": const.CORONAL, |
1261 | "SAGITAL": const.SAGITAL} | 1286 | "SAGITAL": const.SAGITAL} |
@@ -1294,9 +1319,12 @@ class Viewer(wx.Panel): | @@ -1294,9 +1319,12 @@ class Viewer(wx.Panel): | ||
1294 | filename = "%s.tif"%filename.strip(".tif") | 1319 | filename = "%s.tif"%filename.strip(".tif") |
1295 | 1320 | ||
1296 | writer.SetInputData(image) | 1321 | writer.SetInputData(image) |
1297 | - writer.SetFileName(filename) | 1322 | + writer.SetFileName(filename.encode(const.FS_ENCODE)) |
1298 | writer.Write() | 1323 | writer.Write() |
1299 | 1324 | ||
1325 | + if not os.path.exists(filename): | ||
1326 | + wx.MessageBox(_("InVesalius was not able to export this picture"), _("Export picture error")) | ||
1327 | + | ||
1300 | for actor in view_prop_list: | 1328 | for actor in view_prop_list: |
1301 | self.slice_data.renderer.AddViewProp(actor) | 1329 | self.slice_data.renderer.AddViewProp(actor) |
1302 | 1330 | ||
@@ -1321,9 +1349,10 @@ class Viewer(wx.Panel): | @@ -1321,9 +1349,10 @@ class Viewer(wx.Panel): | ||
1321 | del self.slice_data | 1349 | del self.slice_data |
1322 | self.slice_data = None | 1350 | self.slice_data = None |
1323 | 1351 | ||
1324 | - self.canvas.draw_list = [] | ||
1325 | - self.canvas.remove_from_renderer() | ||
1326 | - self.canvas = None | 1352 | + if self.canvas: |
1353 | + self.canvas.draw_list = [] | ||
1354 | + self.canvas.remove_from_renderer() | ||
1355 | + self.canvas = None | ||
1327 | 1356 | ||
1328 | self.orientation_texts = [] | 1357 | self.orientation_texts = [] |
1329 | 1358 |
invesalius/data/viewer_volume.py
@@ -20,6 +20,7 @@ | @@ -20,6 +20,7 @@ | ||
20 | # detalhes. | 20 | # detalhes. |
21 | #-------------------------------------------------------------------------- | 21 | #-------------------------------------------------------------------------- |
22 | 22 | ||
23 | +import os | ||
23 | import sys | 24 | import sys |
24 | 25 | ||
25 | import numpy as np | 26 | import numpy as np |
@@ -37,6 +38,15 @@ import invesalius.style as st | @@ -37,6 +38,15 @@ import invesalius.style as st | ||
37 | import invesalius.utils as utils | 38 | import invesalius.utils as utils |
38 | import invesalius.data.measures as measures | 39 | import invesalius.data.measures as measures |
39 | 40 | ||
41 | +if sys.platform == 'win32': | ||
42 | + try: | ||
43 | + import win32api | ||
44 | + _has_win32api = True | ||
45 | + except ImportError: | ||
46 | + _has_win32api = False | ||
47 | +else: | ||
48 | + _has_win32api = False | ||
49 | + | ||
40 | PROP_MEASURE = 0.8 | 50 | PROP_MEASURE = 0.8 |
41 | 51 | ||
42 | class Viewer(wx.Panel): | 52 | class Viewer(wx.Panel): |
@@ -314,15 +324,24 @@ class Viewer(wx.Panel): | @@ -314,15 +324,24 @@ class Viewer(wx.Panel): | ||
314 | self.seed_points) | 324 | self.seed_points) |
315 | 325 | ||
316 | def OnExportPicture(self, pubsub_evt): | 326 | def OnExportPicture(self, pubsub_evt): |
317 | - Publisher.sendMessage('Begin busy cursor') | ||
318 | id, filename, filetype = pubsub_evt.data | 327 | id, filename, filetype = pubsub_evt.data |
319 | if id == const.VOLUME: | 328 | if id == const.VOLUME: |
329 | + Publisher.sendMessage('Begin busy cursor') | ||
330 | + if _has_win32api: | ||
331 | + utils.touch(filename) | ||
332 | + win_filename = win32api.GetShortPathName(filename) | ||
333 | + self._export_picture(id, win_filename, filetype) | ||
334 | + else: | ||
335 | + self._export_picture(id, filename, filetype) | ||
336 | + Publisher.sendMessage('End busy cursor') | ||
337 | + | ||
338 | + def _export_picture(self, id, filename, filetype): | ||
320 | if filetype == const.FILETYPE_POV: | 339 | if filetype == const.FILETYPE_POV: |
321 | renwin = self.interactor.GetRenderWindow() | 340 | renwin = self.interactor.GetRenderWindow() |
322 | image = vtk.vtkWindowToImageFilter() | 341 | image = vtk.vtkWindowToImageFilter() |
323 | image.SetInput(renwin) | 342 | image.SetInput(renwin) |
324 | writer = vtk.vtkPOVExporter() | 343 | writer = vtk.vtkPOVExporter() |
325 | - writer.SetFileName(filename) | 344 | + writer.SetFileName(filename.encode(const.FS_ENCODE)) |
326 | writer.SetRenderWindow(renwin) | 345 | writer.SetRenderWindow(renwin) |
327 | writer.Write() | 346 | writer.Write() |
328 | else: | 347 | else: |
@@ -345,12 +364,15 @@ class Viewer(wx.Panel): | @@ -345,12 +364,15 @@ class Viewer(wx.Panel): | ||
345 | writer = vtk.vtkPostScriptWriter() | 364 | writer = vtk.vtkPostScriptWriter() |
346 | elif (filetype == const.FILETYPE_TIF): | 365 | elif (filetype == const.FILETYPE_TIF): |
347 | writer = vtk.vtkTIFFWriter() | 366 | writer = vtk.vtkTIFFWriter() |
348 | - filename = "%s.tif"%filename.strip(".tif") | 367 | + filename = u"%s.tif"%filename.strip(".tif") |
349 | 368 | ||
350 | writer.SetInputData(image) | 369 | writer.SetInputData(image) |
351 | - writer.SetFileName(filename) | 370 | + writer.SetFileName(filename.encode(const.FS_ENCODE)) |
352 | writer.Write() | 371 | writer.Write() |
353 | - Publisher.sendMessage('End busy cursor') | 372 | + |
373 | + if not os.path.exists(filename): | ||
374 | + wx.MessageBox(_("InVesalius was not able to export this picture"), _("Export picture error")) | ||
375 | + | ||
354 | 376 | ||
355 | def OnCloseProject(self, pubsub_evt): | 377 | def OnCloseProject(self, pubsub_evt): |
356 | if self.raycasting_volume: | 378 | if self.raycasting_volume: |
@@ -764,6 +786,18 @@ class Viewer(wx.Panel): | @@ -764,6 +786,18 @@ class Viewer(wx.Panel): | ||
764 | 786 | ||
765 | def OnExportSurface(self, pubsub_evt): | 787 | def OnExportSurface(self, pubsub_evt): |
766 | filename, filetype = pubsub_evt.data | 788 | filename, filetype = pubsub_evt.data |
789 | + if filetype not in (const.FILETYPE_STL, | ||
790 | + const.FILETYPE_VTP, | ||
791 | + const.FILETYPE_PLY, | ||
792 | + const.FILETYPE_STL_ASCII): | ||
793 | + if _has_win32api: | ||
794 | + utils.touch(filename) | ||
795 | + win_filename = win32api.GetShortPathName(filename) | ||
796 | + self._export_surface(win_filename.encode(const.FS_ENCODE), filetype) | ||
797 | + else: | ||
798 | + self._export_surface(filename.encode(const.FS_ENCODE), filetype) | ||
799 | + | ||
800 | + def _export_surface(self, filename, filetype): | ||
767 | fileprefix = filename.split(".")[-2] | 801 | fileprefix = filename.split(".")[-2] |
768 | renwin = self.interactor.GetRenderWindow() | 802 | renwin = self.interactor.GetRenderWindow() |
769 | 803 |
@@ -0,0 +1,46 @@ | @@ -0,0 +1,46 @@ | ||
1 | +#!/usr/bin/python | ||
2 | +# -*- coding: utf-8 -*- | ||
3 | +# From http://bugs.python.org/file23442/expanduser.py | ||
4 | + | ||
5 | +import ctypes | ||
6 | +from ctypes import windll, wintypes | ||
7 | + | ||
8 | +class GUID(ctypes.Structure): | ||
9 | + _fields_ = [ | ||
10 | + ('Data1', wintypes.DWORD), | ||
11 | + ('Data2', wintypes.WORD), | ||
12 | + ('Data3', wintypes.WORD), | ||
13 | + ('Data4', wintypes.BYTE * 8) | ||
14 | + ] | ||
15 | + | ||
16 | + def __init__(self, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8): | ||
17 | + """Create a new GUID.""" | ||
18 | + self.Data1 = l | ||
19 | + self.Data2 = w1 | ||
20 | + self.Data3 = w2 | ||
21 | + self.Data4[:] = (b1, b2, b3, b4, b5, b6, b7, b8) | ||
22 | + | ||
23 | + def __repr__(self): | ||
24 | + b1, b2, b3, b4, b5, b6, b7, b8 = self.Data4 | ||
25 | + return 'GUID(%x-%x-%x-%x%x%x%x%x%x%x%x)' % ( | ||
26 | + self.Data1, self.Data2, self.Data3, b1, b2, b3, b4, b5, b6, b7, b8) | ||
27 | + | ||
28 | +# constants to be used according to the version on shell32 | ||
29 | +CSIDL_PROFILE = 40 | ||
30 | +FOLDERID_Profile = GUID(0x5E6C858F, 0x0E22, 0x4760, 0x9A, 0xFE, 0xEA, 0x33, 0x17, 0xB6, 0x71, 0x73) | ||
31 | + | ||
32 | +def expand_user(): | ||
33 | + # get the function that we can find from Vista up, not the one in XP | ||
34 | + get_folder_path = getattr(windll.shell32, 'SHGetKnownFolderPath', None) | ||
35 | + #import pdb; pdb.set_trace() | ||
36 | + if get_folder_path is not None: | ||
37 | + # ok, we can use the new function which is recomended by the msdn | ||
38 | + ptr = ctypes.c_wchar_p() | ||
39 | + get_folder_path(ctypes.byref(FOLDERID_Profile), 0, 0, ctypes.byref(ptr)) | ||
40 | + return ptr.value | ||
41 | + else: | ||
42 | + # use the deprecated one found in XP and on for compatibility reasons | ||
43 | + get_folder_path = getattr(windll.shell32, 'SHGetSpecialFolderPathW', None) | ||
44 | + buf = ctypes.create_unicode_buffer(300) | ||
45 | + get_folder_path(None, buf, CSIDL_PROFILE, False) | ||
46 | + return buf.value |
invesalius/gui/dialogs.py
@@ -323,10 +323,7 @@ def ShowImportBitmapDirDialog(): | @@ -323,10 +323,7 @@ def ShowImportBitmapDirDialog(): | ||
323 | if dlg.ShowModal() == wx.ID_OK: | 323 | if dlg.ShowModal() == wx.ID_OK: |
324 | # GetPath returns in unicode, if a path has non-ascii characters a | 324 | # GetPath returns in unicode, if a path has non-ascii characters a |
325 | # UnicodeEncodeError is raised. To avoid this, path is encoded in utf-8 | 325 | # UnicodeEncodeError is raised. To avoid this, path is encoded in utf-8 |
326 | - if sys.platform == "win32": | ||
327 | - path = dlg.GetPath() | ||
328 | - else: | ||
329 | - path = dlg.GetPath().encode('utf-8') | 326 | + path = dlg.GetPath() |
330 | 327 | ||
331 | except(wx._core.PyAssertionError): #TODO: error win64 | 328 | except(wx._core.PyAssertionError): #TODO: error win64 |
332 | if (dlg.GetPath()): | 329 | if (dlg.GetPath()): |
@@ -398,12 +395,7 @@ def ShowImportMeshFilesDialog(): | @@ -398,12 +395,7 @@ def ShowImportMeshFilesDialog(): | ||
398 | filename = None | 395 | filename = None |
399 | try: | 396 | try: |
400 | if dlg.ShowModal() == wx.ID_OK: | 397 | if dlg.ShowModal() == wx.ID_OK: |
401 | - # GetPath returns in unicode, if a path has non-ascii characters a | ||
402 | - # UnicodeEncodeError is raised. To avoid this, path is encoded in utf-8 | ||
403 | - if sys.platform == "win32": | ||
404 | - filename = dlg.GetPath() | ||
405 | - else: | ||
406 | - filename = dlg.GetPath().encode('utf-8') | 398 | + filename = dlg.GetPath() |
407 | 399 | ||
408 | except(wx._core.PyAssertionError): # TODO: error win64 | 400 | except(wx._core.PyAssertionError): # TODO: error win64 |
409 | if (dlg.GetPath()): | 401 | if (dlg.GetPath()): |
@@ -1058,52 +1050,52 @@ def ShowAboutDialog(parent): | @@ -1058,52 +1050,52 @@ def ShowAboutDialog(parent): | ||
1058 | info.WebSite = ("https://www.cti.gov.br/invesalius") | 1050 | info.WebSite = ("https://www.cti.gov.br/invesalius") |
1059 | info.License = _("GNU GPL (General Public License) version 2") | 1051 | info.License = _("GNU GPL (General Public License) version 2") |
1060 | 1052 | ||
1061 | - info.Developers = ["Paulo Henrique Junqueira Amorim", | ||
1062 | - "Thiago Franco de Moraes", | ||
1063 | - "Hélio Pedrini", | ||
1064 | - "Jorge Vicente Lopes da Silva", | ||
1065 | - "Victor Hugo de Oliveira e Souza (navigator)", | ||
1066 | - "Renan Hiroshi Matsuda (navigator)", | ||
1067 | - "André Salles Cunha Peres (navigator)", | ||
1068 | - "Oswaldo Baffa Filho (navigator)", | ||
1069 | - "Tatiana Al-Chueyr (former)", | ||
1070 | - "Guilherme Cesar Soares Ruppert (former)", | ||
1071 | - "Fabio de Souza Azevedo (former)", | ||
1072 | - "Bruno Lara Bottazzini (contributor)", | ||
1073 | - "Olly Betts (patches to support wxPython3)"] | ||
1074 | - | ||
1075 | - info.Translators = ["Alex P. Natsios", | ||
1076 | - "Alicia Perez", | ||
1077 | - "Anderson Antonio Mamede da Silva", | ||
1078 | - "Andreas Loupasakis", | ||
1079 | - "Angelo Pucillo", | ||
1080 | - "Annalisa Manenti", | ||
1081 | - "Cheng-Chia Tseng", | ||
1082 | - "Dan", | ||
1083 | - "DCamer", | ||
1084 | - "Dimitris Glezos", | ||
1085 | - "Eugene Liscio", | 1053 | + info.Developers = [u"Paulo Henrique Junqueira Amorim", |
1054 | + u"Thiago Franco de Moraes", | ||
1055 | + u"Hélio Pedrini", | ||
1056 | + u"Jorge Vicente Lopes da Silva", | ||
1057 | + u"Victor Hugo de Oliveira e Souza (navigator)", | ||
1058 | + u"Renan Hiroshi Matsuda (navigator)", | ||
1059 | + u"André Salles Cunha Peres (navigator)", | ||
1060 | + u"Oswaldo Baffa Filho (navigator)", | ||
1061 | + u"Tatiana Al-Chueyr (former)", | ||
1062 | + u"Guilherme Cesar Soares Ruppert (former)", | ||
1063 | + u"Fabio de Souza Azevedo (former)", | ||
1064 | + u"Bruno Lara Bottazzini (contributor)", | ||
1065 | + u"Olly Betts (patches to support wxPython3)"] | ||
1066 | + | ||
1067 | + info.Translators = [u"Alex P. Natsios", | ||
1068 | + u"Alicia Perez", | ||
1069 | + u"Anderson Antonio Mamede da Silva", | ||
1070 | + u"Andreas Loupasakis", | ||
1071 | + u"Angelo Pucillo", | ||
1072 | + u"Annalisa Manenti", | ||
1073 | + u"Cheng-Chia Tseng", | ||
1074 | + u"Dan", | ||
1075 | + u"DCamer", | ||
1076 | + u"Dimitris Glezos", | ||
1077 | + u"Eugene Liscio", | ||
1086 | u"Frédéric Lopez", | 1078 | u"Frédéric Lopez", |
1087 | - "Florin Putura", | ||
1088 | - "Fri", | ||
1089 | - "Jangblue", | ||
1090 | - "Javier de Lima Moreno", | ||
1091 | - "Kensey Okinawa", | ||
1092 | - "Maki Sugimoto", | ||
1093 | - "Mario Regino Moreno Guerra", | ||
1094 | - "Massimo Crisantemo", | ||
1095 | - "Nikos Korkakakis", | ||
1096 | - "Raul Bolliger Neto", | ||
1097 | - "Sebastian Hilbert", | ||
1098 | - "Semarang Pari", | ||
1099 | - "Silvério Santos", | ||
1100 | - "Vasily Shishkin", | ||
1101 | - "Yohei Sotsuka", | ||
1102 | - "Yoshihiro Sato"] | 1079 | + u"Florin Putura", |
1080 | + u"Fri", | ||
1081 | + u"Jangblue", | ||
1082 | + u"Javier de Lima Moreno", | ||
1083 | + u"Kensey Okinawa", | ||
1084 | + u"Maki Sugimoto", | ||
1085 | + u"Mario Regino Moreno Guerra", | ||
1086 | + u"Massimo Crisantemo", | ||
1087 | + u"Nikos Korkakakis", | ||
1088 | + u"Raul Bolliger Neto", | ||
1089 | + u"Sebastian Hilbert", | ||
1090 | + u"Semarang Pari", | ||
1091 | + u"Silvério Santos", | ||
1092 | + u"Vasily Shishkin", | ||
1093 | + u"Yohei Sotsuka", | ||
1094 | + u"Yoshihiro Sato"] | ||
1103 | 1095 | ||
1104 | #info.DocWriters = ["Fabio Francisco da Silva (PT)"] | 1096 | #info.DocWriters = ["Fabio Francisco da Silva (PT)"] |
1105 | 1097 | ||
1106 | - info.Artists = ["Otavio Henrique Junqueira Amorim"] | 1098 | + info.Artists = [u"Otavio Henrique Junqueira Amorim"] |
1107 | 1099 | ||
1108 | # Then we call wx.AboutBox providing its info object | 1100 | # Then we call wx.AboutBox providing its info object |
1109 | wx.AboutBox(info) | 1101 | wx.AboutBox(info) |
invesalius/gui/dicom_preview_panel.py
@@ -21,6 +21,7 @@ | @@ -21,6 +21,7 @@ | ||
21 | # -*- coding: UTF-8 -*- | 21 | # -*- coding: UTF-8 -*- |
22 | 22 | ||
23 | #TODO: To create a beautiful API | 23 | #TODO: To create a beautiful API |
24 | +import sys | ||
24 | import time | 25 | import time |
25 | import tempfile | 26 | import tempfile |
26 | 27 | ||
@@ -37,6 +38,14 @@ import invesalius.data.vtk_utils as vtku | @@ -37,6 +38,14 @@ import invesalius.data.vtk_utils as vtku | ||
37 | import invesalius.utils as utils | 38 | import invesalius.utils as utils |
38 | import vtkgdcm | 39 | import vtkgdcm |
39 | 40 | ||
41 | +if sys.platform == 'win32': | ||
42 | + try: | ||
43 | + import win32api | ||
44 | + _has_win32api = True | ||
45 | + except ImportError: | ||
46 | + _has_win32api = False | ||
47 | +else: | ||
48 | + _has_win32api = False | ||
40 | 49 | ||
41 | NROWS = 3 | 50 | NROWS = 3 |
42 | NCOLS = 6 | 51 | NCOLS = 6 |
@@ -837,7 +846,10 @@ class SingleImagePreview(wx.Panel): | @@ -837,7 +846,10 @@ class SingleImagePreview(wx.Panel): | ||
837 | self.text_acquisition.SetValue(value) | 846 | self.text_acquisition.SetValue(value) |
838 | 847 | ||
839 | rdicom = vtkgdcm.vtkGDCMImageReader() | 848 | rdicom = vtkgdcm.vtkGDCMImageReader() |
840 | - rdicom.SetFileName(dicom.image.file) | 849 | + if _has_win32api: |
850 | + rdicom.SetFileName(win32api.GetShortPathName(dicom.image.file).encode(const.FS_ENCODE)) | ||
851 | + else: | ||
852 | + rdicom.SetFileName(dicom.image.file) | ||
841 | rdicom.Update() | 853 | rdicom.Update() |
842 | 854 | ||
843 | # ADJUST CONTRAST | 855 | # ADJUST CONTRAST |
invesalius/gui/task_exporter.py
@@ -331,6 +331,13 @@ class InnerTaskPanel(wx.Panel): | @@ -331,6 +331,13 @@ class InnerTaskPanel(wx.Panel): | ||
331 | filename = filename + "."+ extension | 331 | filename = filename + "."+ extension |
332 | Publisher.sendMessage('Export surface to file', | 332 | Publisher.sendMessage('Export surface to file', |
333 | (filename, filetype)) | 333 | (filename, filetype)) |
334 | + if not os.path.exists(filename): | ||
335 | + dlg = wx.MessageDialog(None, | ||
336 | + _("It was not possible to save the surface."), | ||
337 | + _("Error saving surface"), | ||
338 | + wx.OK | wx.ICON_ERROR) | ||
339 | + dlg.ShowModal() | ||
340 | + dlg.Destroy() | ||
334 | else: | 341 | else: |
335 | dlg = wx.MessageDialog(None, | 342 | dlg = wx.MessageDialog(None, |
336 | _("You need to create a surface and make it ") + | 343 | _("You need to create a surface and make it ") + |
invesalius/project.py
@@ -22,6 +22,7 @@ import glob | @@ -22,6 +22,7 @@ import glob | ||
22 | import os | 22 | import os |
23 | import plistlib | 23 | import plistlib |
24 | import shutil | 24 | import shutil |
25 | +import sys | ||
25 | import tarfile | 26 | import tarfile |
26 | import tempfile | 27 | import tempfile |
27 | 28 | ||
@@ -32,9 +33,18 @@ import vtk | @@ -32,9 +33,18 @@ import vtk | ||
32 | import invesalius.constants as const | 33 | import invesalius.constants as const |
33 | import invesalius.data.polydata_utils as pu | 34 | import invesalius.data.polydata_utils as pu |
34 | from invesalius.presets import Presets | 35 | from invesalius.presets import Presets |
35 | -from invesalius.utils import Singleton, debug | 36 | +from invesalius.utils import Singleton, debug, touch |
36 | import invesalius.version as version | 37 | import invesalius.version as version |
37 | 38 | ||
39 | +if sys.platform == 'win32': | ||
40 | + try: | ||
41 | + import win32api | ||
42 | + _has_win32api = True | ||
43 | + except ImportError: | ||
44 | + _has_win32api = False | ||
45 | +else: | ||
46 | + _has_win32api = False | ||
47 | + | ||
38 | class Project(object): | 48 | class Project(object): |
39 | # Only one project will be initialized per time. Therefore, we use | 49 | # Only one project will be initialized per time. Therefore, we use |
40 | # Singleton design pattern for implementing it | 50 | # Singleton design pattern for implementing it |
@@ -193,10 +203,14 @@ class Project(object): | @@ -193,10 +203,14 @@ class Project(object): | ||
193 | return measures | 203 | return measures |
194 | 204 | ||
195 | def SavePlistProject(self, dir_, filename): | 205 | def SavePlistProject(self, dir_, filename): |
196 | - dir_temp = tempfile.mkdtemp() | ||
197 | - filename_tmp = os.path.join(dir_temp, 'matrix.dat') | 206 | + dir_temp = tempfile.mkdtemp().decode(const.FS_ENCODE) |
207 | + | ||
208 | + filename_tmp = os.path.join(dir_temp, u'matrix.dat') | ||
198 | filelist = {} | 209 | filelist = {} |
199 | 210 | ||
211 | + print type(dir_temp), type(filename) | ||
212 | + print filename.encode('utf8'), dir_.encode('utf8'), type(filename), type(dir_) | ||
213 | + | ||
200 | project = { | 214 | project = { |
201 | # Format info | 215 | # Format info |
202 | "format_version": 1, | 216 | "format_version": 1, |
@@ -214,10 +228,11 @@ class Project(object): | @@ -214,10 +228,11 @@ class Project(object): | ||
214 | } | 228 | } |
215 | 229 | ||
216 | # Saving the matrix containing the slices | 230 | # Saving the matrix containing the slices |
217 | - matrix = {'filename': u'matrix.dat', | ||
218 | - 'shape': self.matrix_shape, | ||
219 | - 'dtype': self.matrix_dtype, | ||
220 | - } | 231 | + matrix = { |
232 | + 'filename': u'matrix.dat', | ||
233 | + 'shape': self.matrix_shape, | ||
234 | + 'dtype': self.matrix_dtype, | ||
235 | + } | ||
221 | project['matrix'] = matrix | 236 | project['matrix'] = matrix |
222 | filelist[self.matrix_filename] = 'matrix.dat' | 237 | filelist[self.matrix_filename] = 'matrix.dat' |
223 | #shutil.copyfile(self.matrix_filename, filename_tmp) | 238 | #shutil.copyfile(self.matrix_filename, filename_tmp) |
@@ -270,9 +285,9 @@ class Project(object): | @@ -270,9 +285,9 @@ class Project(object): | ||
270 | import invesalius.data.surface as srf | 285 | import invesalius.data.surface as srf |
271 | 286 | ||
272 | if not const.VTK_WARNING: | 287 | if not const.VTK_WARNING: |
273 | - log_path = os.path.join(const.LOG_FOLDER, 'vtkoutput.txt') | 288 | + log_path = os.path.join(const.USER_LOG_DIR, 'vtkoutput.txt') |
274 | fow = vtk.vtkFileOutputWindow() | 289 | fow = vtk.vtkFileOutputWindow() |
275 | - fow.SetFileName(log_path) | 290 | + fow.SetFileName(log_path.encode(const.FS_ENCODE)) |
276 | ow = vtk.vtkOutputWindow() | 291 | ow = vtk.vtkOutputWindow() |
277 | ow.SetInstance(fow) | 292 | ow.SetInstance(fow) |
278 | 293 | ||
@@ -328,29 +343,37 @@ class Project(object): | @@ -328,29 +343,37 @@ class Project(object): | ||
328 | def Compress(folder, filename, filelist): | 343 | def Compress(folder, filename, filelist): |
329 | tmpdir, tmpdir_ = os.path.split(folder) | 344 | tmpdir, tmpdir_ = os.path.split(folder) |
330 | current_dir = os.path.abspath(".") | 345 | current_dir = os.path.abspath(".") |
346 | + temp_inv3 = tempfile.mktemp() | ||
347 | + if _has_win32api: | ||
348 | + touch(temp_inv3) | ||
349 | + temp_inv3 = win32api.GetShortPathName(temp_inv3) | ||
350 | + | ||
351 | + temp_inv3 = temp_inv3.decode(const.FS_ENCODE) | ||
331 | #os.chdir(tmpdir) | 352 | #os.chdir(tmpdir) |
332 | #file_list = glob.glob(os.path.join(tmpdir_,"*")) | 353 | #file_list = glob.glob(os.path.join(tmpdir_,"*")) |
333 | - tar_filename = tmpdir_ + ".inv3" | ||
334 | - tar = tarfile.open(filename.encode(wx.GetDefaultPyEncoding()), "w:gz") | 354 | + print "Tar file", temp_inv3, type(temp_inv3), filename.encode('utf8'), type(filename) |
355 | + tar = tarfile.open(temp_inv3, "w:gz") | ||
335 | for name in filelist: | 356 | for name in filelist: |
336 | tar.add(name, arcname=os.path.join(tmpdir_, filelist[name])) | 357 | tar.add(name, arcname=os.path.join(tmpdir_, filelist[name])) |
337 | tar.close() | 358 | tar.close() |
338 | - #shutil.move(tmpdir_+ ".inv3", filename) | 359 | + shutil.move(temp_inv3, filename) |
339 | #os.chdir(current_dir) | 360 | #os.chdir(current_dir) |
340 | 361 | ||
362 | + | ||
341 | def Extract(filename, folder): | 363 | def Extract(filename, folder): |
364 | + if _has_win32api: | ||
365 | + folder = win32api.GetShortPathName(folder) | ||
366 | + folder = folder.decode(const.FS_ENCODE) | ||
367 | + | ||
342 | tar = tarfile.open(filename, "r:gz") | 368 | tar = tarfile.open(filename, "r:gz") |
343 | - idir = os.path.split(tar.getnames()[0])[0] | ||
344 | - os.mkdir(os.path.join(folder, idir.decode('utf8'))) | 369 | + idir = os.path.split(tar.getnames()[0])[0].decode('utf8') |
370 | + os.mkdir(os.path.join(folder, idir)) | ||
345 | filelist = [] | 371 | filelist = [] |
346 | for t in tar.getmembers(): | 372 | for t in tar.getmembers(): |
347 | fsrc = tar.extractfile(t) | 373 | fsrc = tar.extractfile(t) |
348 | - | ||
349 | fname = os.path.join(folder, t.name.decode('utf-8')) | 374 | fname = os.path.join(folder, t.name.decode('utf-8')) |
350 | fdst = file(fname, 'wb') | 375 | fdst = file(fname, 'wb') |
351 | - | ||
352 | shutil.copyfileobj(fsrc, fdst) | 376 | shutil.copyfileobj(fsrc, fdst) |
353 | - | ||
354 | filelist.append(fname) | 377 | filelist.append(fname) |
355 | fsrc.close() | 378 | fsrc.close() |
356 | fdst.close() | 379 | fdst.close() |
@@ -359,7 +382,7 @@ def Extract(filename, folder): | @@ -359,7 +382,7 @@ def Extract(filename, folder): | ||
359 | tar.close() | 382 | tar.close() |
360 | return filelist | 383 | return filelist |
361 | 384 | ||
362 | - | 385 | + |
363 | def Extract_(filename, folder): | 386 | def Extract_(filename, folder): |
364 | tar = tarfile.open(filename, "r:gz") | 387 | tar = tarfile.open(filename, "r:gz") |
365 | #tar.list(verbose=True) | 388 | #tar.list(verbose=True) |
invesalius/reader/bitmap_reader.py
@@ -40,6 +40,15 @@ import invesalius.data.converters as converters | @@ -40,6 +40,15 @@ import invesalius.data.converters as converters | ||
40 | no_error = True | 40 | no_error = True |
41 | vtk_error = False | 41 | vtk_error = False |
42 | 42 | ||
43 | +if sys.platform == 'win32': | ||
44 | + try: | ||
45 | + import win32api | ||
46 | + _has_win32api = True | ||
47 | + except ImportError: | ||
48 | + _has_win32api = False | ||
49 | +else: | ||
50 | + _has_win32api = False | ||
51 | + | ||
43 | class Singleton: | 52 | class Singleton: |
44 | 53 | ||
45 | def __init__(self,klass): | 54 | def __init__(self,klass): |
@@ -127,10 +136,7 @@ class LoadBitmap: | @@ -127,10 +136,7 @@ class LoadBitmap: | ||
127 | 136 | ||
128 | def __init__(self, bmp_file, filepath): | 137 | def __init__(self, bmp_file, filepath): |
129 | self.bmp_file = bmp_file | 138 | self.bmp_file = bmp_file |
130 | - if sys.platform == 'win32': | ||
131 | - self.filepath = filepath.encode(utils.get_system_encoding()) | ||
132 | - else: | ||
133 | - self.filepath = filepath | 139 | + self.filepath = filepath |
134 | 140 | ||
135 | self.run() | 141 | self.run() |
136 | 142 | ||
@@ -294,9 +300,9 @@ def ScipyRead(filepath): | @@ -294,9 +300,9 @@ def ScipyRead(filepath): | ||
294 | 300 | ||
295 | def VtkRead(filepath, t): | 301 | def VtkRead(filepath, t): |
296 | if not const.VTK_WARNING: | 302 | if not const.VTK_WARNING: |
297 | - log_path = os.path.join(const.LOG_FOLDER, 'vtkoutput.txt') | 303 | + log_path = os.path.join(const.USER_LOG_DIR, 'vtkoutput.txt') |
298 | fow = vtk.vtkFileOutputWindow() | 304 | fow = vtk.vtkFileOutputWindow() |
299 | - fow.SetFileName(log_path) | 305 | + fow.SetFileName(log_path.encode(const.FS_ENCODE)) |
300 | ow = vtk.vtkOutputWindow() | 306 | ow = vtk.vtkOutputWindow() |
301 | ow.SetInstance(fow) | 307 | ow.SetInstance(fow) |
302 | 308 | ||
@@ -317,8 +323,10 @@ def VtkRead(filepath, t): | @@ -317,8 +323,10 @@ def VtkRead(filepath, t): | ||
317 | else: | 323 | else: |
318 | return False | 324 | return False |
319 | 325 | ||
326 | + print ">>>> bmp reader", type(filepath) | ||
327 | + | ||
320 | reader.AddObserver("ErrorEvent", VtkErrorToPy) | 328 | reader.AddObserver("ErrorEvent", VtkErrorToPy) |
321 | - reader.SetFileName(filepath) | 329 | + reader.SetFileName(filepath.encode(const.FS_ENCODE)) |
322 | reader.Update() | 330 | reader.Update() |
323 | 331 | ||
324 | if no_error: | 332 | if no_error: |
@@ -345,6 +353,9 @@ def VtkRead(filepath, t): | @@ -345,6 +353,9 @@ def VtkRead(filepath, t): | ||
345 | def ReadBitmap(filepath): | 353 | def ReadBitmap(filepath): |
346 | t = VerifyDataType(filepath) | 354 | t = VerifyDataType(filepath) |
347 | 355 | ||
356 | + if _has_win32api: | ||
357 | + filepath = win32api.GetShortPathName(filepath) | ||
358 | + | ||
348 | if t == False: | 359 | if t == False: |
349 | measures_info = GetPixelSpacingFromInfoFile(filepath) | 360 | measures_info = GetPixelSpacingFromInfoFile(filepath) |
350 | 361 | ||
@@ -368,7 +379,6 @@ def ReadBitmap(filepath): | @@ -368,7 +379,6 @@ def ReadBitmap(filepath): | ||
368 | 379 | ||
369 | 380 | ||
370 | def GetPixelSpacingFromInfoFile(filepath): | 381 | def GetPixelSpacingFromInfoFile(filepath): |
371 | - | ||
372 | fi = open(filepath, 'r') | 382 | fi = open(filepath, 'r') |
373 | lines = fi.readlines() | 383 | lines = fi.readlines() |
374 | measure_scale = 'mm' | 384 | measure_scale = 'mm' |
invesalius/reader/dicom_grouper.py
@@ -51,9 +51,23 @@ | @@ -51,9 +51,23 @@ | ||
51 | # <dicom.image.number> and <dicom.acquisition.series_number> | 51 | # <dicom.image.number> and <dicom.acquisition.series_number> |
52 | # were swapped | 52 | # were swapped |
53 | 53 | ||
54 | +import sys | ||
55 | + | ||
54 | import gdcm | 56 | import gdcm |
55 | 57 | ||
58 | +if sys.platform == 'win32': | ||
59 | + try: | ||
60 | + import win32api | ||
61 | + _has_win32api = True | ||
62 | + except ImportError: | ||
63 | + _has_win32api = False | ||
64 | +else: | ||
65 | + _has_win32api = False | ||
66 | + | ||
56 | import invesalius.utils as utils | 67 | import invesalius.utils as utils |
68 | +import invesalius.constants as const | ||
69 | + | ||
70 | + | ||
57 | ORIENT_MAP = {"SAGITTAL":0, "CORONAL":1, "AXIAL":2, "OBLIQUE":2} | 71 | ORIENT_MAP = {"SAGITTAL":0, "CORONAL":1, "AXIAL":2, "OBLIQUE":2} |
58 | 72 | ||
59 | 73 | ||
@@ -109,8 +123,13 @@ class DicomGroup: | @@ -109,8 +123,13 @@ class DicomGroup: | ||
109 | # This list will be used to create the vtkImageData | 123 | # This list will be used to create the vtkImageData |
110 | # (interpolated) | 124 | # (interpolated) |
111 | 125 | ||
112 | - filelist = [dicom.image.file for dicom in | ||
113 | - self.slices_dict.values()] | 126 | + if _has_win32api: |
127 | + filelist = [win32api.GetShortPathName(dicom.image.file).encode(const.FS_ENCODE) | ||
128 | + for dicom in | ||
129 | + self.slices_dict.values()] | ||
130 | + else: | ||
131 | + filelist = [dicom.image.file for dicom in | ||
132 | + self.slices_dict.values()] | ||
114 | 133 | ||
115 | # Sort slices using GDCM | 134 | # Sort slices using GDCM |
116 | if (self.dicom.image.orientation_label <> "CORONAL"): | 135 | if (self.dicom.image.orientation_label <> "CORONAL"): |
invesalius/reader/dicom_reader.py
@@ -38,6 +38,15 @@ import invesalius.utils as utils | @@ -38,6 +38,15 @@ import invesalius.utils as utils | ||
38 | 38 | ||
39 | import plistlib | 39 | import plistlib |
40 | 40 | ||
41 | +if sys.platform == 'win32': | ||
42 | + try: | ||
43 | + import win32api | ||
44 | + _has_win32api = True | ||
45 | + except ImportError: | ||
46 | + _has_win32api = False | ||
47 | +else: | ||
48 | + _has_win32api = False | ||
49 | + | ||
41 | def ReadDicomGroup(dir_): | 50 | def ReadDicomGroup(dir_): |
42 | 51 | ||
43 | patient_group = GetDicomGroups(dir_) | 52 | patient_group = GetDicomGroups(dir_) |
@@ -88,18 +97,18 @@ class LoadDicom: | @@ -88,18 +97,18 @@ class LoadDicom: | ||
88 | 97 | ||
89 | def __init__(self, grouper, filepath): | 98 | def __init__(self, grouper, filepath): |
90 | self.grouper = grouper | 99 | self.grouper = grouper |
91 | - if sys.platform == 'win32': | ||
92 | - self.filepath = filepath.encode(utils.get_system_encoding()) | ||
93 | - else: | ||
94 | - self.filepath = filepath | 100 | + self.filepath = filepath |
95 | 101 | ||
96 | self.run() | 102 | self.run() |
97 | 103 | ||
98 | def run(self): | 104 | def run(self): |
99 | - | ||
100 | grouper = self.grouper | 105 | grouper = self.grouper |
101 | reader = gdcm.ImageReader() | 106 | reader = gdcm.ImageReader() |
102 | - reader.SetFileName(self.filepath) | 107 | + if _has_win32api: |
108 | + reader.SetFileName(win32api.GetShortPathName(self.filepath).encode(const.FS_ENCODE)) | ||
109 | + else: | ||
110 | + reader.SetFileName(self.filepath) | ||
111 | + | ||
103 | if (reader.Read()): | 112 | if (reader.Read()): |
104 | file = reader.GetFile() | 113 | file = reader.GetFile() |
105 | 114 | ||
@@ -180,7 +189,12 @@ class LoadDicom: | @@ -180,7 +189,12 @@ class LoadDicom: | ||
180 | 189 | ||
181 | # -------------- To Create DICOM Thumbnail ----------- | 190 | # -------------- To Create DICOM Thumbnail ----------- |
182 | rvtk = vtkgdcm.vtkGDCMImageReader() | 191 | rvtk = vtkgdcm.vtkGDCMImageReader() |
183 | - rvtk.SetFileName(self.filepath) | 192 | + |
193 | + if _has_win32api: | ||
194 | + print 'dicom', win32api.GetShortPathName(self.filepath) | ||
195 | + rvtk.SetFileName(win32api.GetShortPathName(self.filepath).encode(const.FS_ENCODE)) | ||
196 | + else: | ||
197 | + rvtk.SetFileName(self.filepath) | ||
184 | rvtk.Update() | 198 | rvtk.Update() |
185 | 199 | ||
186 | try: | 200 | try: |
@@ -341,7 +355,7 @@ class ProgressDicomReader: | @@ -341,7 +355,7 @@ class ProgressDicomReader: | ||
341 | def GetDicomGroups(self, path, recursive): | 355 | def GetDicomGroups(self, path, recursive): |
342 | 356 | ||
343 | if not const.VTK_WARNING: | 357 | if not const.VTK_WARNING: |
344 | - log_path = os.path.join(const.LOG_FOLDER, 'vtkoutput.txt') | 358 | + log_path = os.path.join(const.USER_LOG_DIR, 'vtkoutput.txt').encode(const.FS_ENCODE) |
345 | fow = vtk.vtkFileOutputWindow() | 359 | fow = vtk.vtkFileOutputWindow() |
346 | fow.SetFileName(log_path) | 360 | fow.SetFileName(log_path) |
347 | ow = vtk.vtkOutputWindow() | 361 | ow = vtk.vtkOutputWindow() |
invesalius/reader/others_reader.py
@@ -38,9 +38,9 @@ def ReadOthers(dir_): | @@ -38,9 +38,9 @@ def ReadOthers(dir_): | ||
38 | """ | 38 | """ |
39 | 39 | ||
40 | if not const.VTK_WARNING: | 40 | if not const.VTK_WARNING: |
41 | - log_path = os.path.join(const.LOG_FOLDER, 'vtkoutput.txt') | 41 | + log_path = os.path.join(const.USER_LOG_DIR, 'vtkoutput.txt') |
42 | fow = vtk.vtkFileOutputWindow() | 42 | fow = vtk.vtkFileOutputWindow() |
43 | - fow.SetFileName(log_path) | 43 | + fow.SetFileName(log_path.encode(const.FS_ENCODE)) |
44 | ow = vtk.vtkOutputWindow() | 44 | ow = vtk.vtkOutputWindow() |
45 | ow.SetInstance(fow) | 45 | ow.SetInstance(fow) |
46 | 46 |
invesalius/session.py
@@ -36,7 +36,24 @@ import wx | @@ -36,7 +36,24 @@ import wx | ||
36 | from invesalius.utils import Singleton, debug | 36 | from invesalius.utils import Singleton, debug |
37 | from random import randint | 37 | from random import randint |
38 | 38 | ||
39 | -ENCODE=wx.GetDefaultPyEncoding() | 39 | +FS_ENCODE = sys.getfilesystemencoding() |
40 | + | ||
41 | +if sys.platform == 'win32': | ||
42 | + from invesalius.expanduser import expand_user | ||
43 | + try: | ||
44 | + USER_DIR = expand_user() | ||
45 | + except: | ||
46 | + USER_DIR = os.path.expanduser('~').decode(FS_ENCODE) | ||
47 | +else: | ||
48 | + USER_DIR = os.path.expanduser('~').decode(FS_ENCODE) | ||
49 | + | ||
50 | +USER_INV_DIR = os.path.join(USER_DIR, u'.invesalius') | ||
51 | +USER_PRESET_DIR = os.path.join(USER_INV_DIR, u'presets') | ||
52 | +USER_LOG_DIR = os.path.join(USER_INV_DIR, u'logs') | ||
53 | +USER_INV_CFG_PATH = os.path.join(USER_INV_DIR, 'config.cfg') | ||
54 | + | ||
55 | +SESSION_ENCODING = 'utf8' | ||
56 | + | ||
40 | 57 | ||
41 | class Session(object): | 58 | class Session(object): |
42 | # Only one session will be initialized per time. Therefore, we use | 59 | # Only one session will be initialized per time. Therefore, we use |
@@ -62,7 +79,7 @@ class Session(object): | @@ -62,7 +79,7 @@ class Session(object): | ||
62 | # const.MODE_ODONTOLOGY | 79 | # const.MODE_ODONTOLOGY |
63 | 80 | ||
64 | # InVesalius default projects' directory | 81 | # InVesalius default projects' directory |
65 | - homedir = self.homedir = os.path.expanduser('~').decode(ENCODE) | 82 | + homedir = self.homedir = USER_DIR |
66 | tempdir = os.path.join(homedir, u".invesalius", u"temp") | 83 | tempdir = os.path.join(homedir, u".invesalius", u"temp") |
67 | if not os.path.isdir(tempdir): | 84 | if not os.path.isdir(tempdir): |
68 | os.makedirs(tempdir) | 85 | os.makedirs(tempdir) |
@@ -72,10 +89,9 @@ class Session(object): | @@ -72,10 +89,9 @@ class Session(object): | ||
72 | self.language = "" # "pt_BR", "es" | 89 | self.language = "" # "pt_BR", "es" |
73 | 90 | ||
74 | self.random_id = randint(0,pow(10,16)) | 91 | self.random_id = randint(0,pow(10,16)) |
75 | - #print self.random_id | ||
76 | 92 | ||
77 | # Recent projects list | 93 | # Recent projects list |
78 | - self.recent_projects = [(const.SAMPLE_DIR, "Cranium.inv3")] | 94 | + self.recent_projects = [(const.SAMPLE_DIR, u"Cranium.inv3")] |
79 | self.last_dicom_folder = '' | 95 | self.last_dicom_folder = '' |
80 | self.surface_interpolation = 1 | 96 | self.surface_interpolation = 1 |
81 | self.slice_interpolation = 0 | 97 | self.slice_interpolation = 0 |
@@ -88,18 +104,18 @@ class Session(object): | @@ -88,18 +104,18 @@ class Session(object): | ||
88 | 104 | ||
89 | def SaveConfigFileBackup(self): | 105 | def SaveConfigFileBackup(self): |
90 | path = os.path.join(self.homedir , | 106 | path = os.path.join(self.homedir , |
91 | - '.invesalius', 'config.cfg') | 107 | + u'.invesalius', u'config.cfg') |
92 | path_dst = os.path.join(self.homedir , | 108 | path_dst = os.path.join(self.homedir , |
93 | - '.invesalius', 'config.backup') | 109 | + u'.invesalius', u'config.backup') |
94 | shutil.copy(path, path_dst) | 110 | shutil.copy(path, path_dst) |
95 | 111 | ||
96 | def RecoveryConfigFile(self): | 112 | def RecoveryConfigFile(self): |
97 | homedir = self.homedir = os.path.expanduser('~') | 113 | homedir = self.homedir = os.path.expanduser('~') |
98 | try: | 114 | try: |
99 | path = os.path.join(self.homedir , | 115 | path = os.path.join(self.homedir , |
100 | - '.invesalius', 'config.backup') | 116 | + u'.invesalius', u'config.backup') |
101 | path_dst = os.path.join(self.homedir , | 117 | path_dst = os.path.join(self.homedir , |
102 | - '.invesalius', 'config.cfg') | 118 | + u'.invesalius', u'config.cfg') |
103 | shutil.copy(path, path_dst) | 119 | shutil.copy(path, path_dst) |
104 | return True | 120 | return True |
105 | except(IOError): | 121 | except(IOError): |
@@ -163,10 +179,6 @@ class Session(object): | @@ -163,10 +179,6 @@ class Session(object): | ||
163 | def WriteSessionFile(self): | 179 | def WriteSessionFile(self): |
164 | config = ConfigParser.RawConfigParser() | 180 | config = ConfigParser.RawConfigParser() |
165 | 181 | ||
166 | - print ">>>", type(self.homedir), self.homedir, repr(self.homedir) | ||
167 | - print ">>>", type(self.tempdir), self.tempdir, repr(self.tempdir) | ||
168 | - print ">>>", type(self.language), self.language, repr(self.language) | ||
169 | - | ||
170 | config.add_section('session') | 182 | config.add_section('session') |
171 | config.set('session', 'mode', self.mode) | 183 | config.set('session', 'mode', self.mode) |
172 | config.set('session', 'status', self.project_status) | 184 | config.set('session', 'status', self.project_status) |
@@ -185,18 +197,10 @@ class Session(object): | @@ -185,18 +197,10 @@ class Session(object): | ||
185 | config.set('paths','tempdir',self.tempdir) | 197 | config.set('paths','tempdir',self.tempdir) |
186 | config.set('paths','last_dicom_folder',self.last_dicom_folder) | 198 | config.set('paths','last_dicom_folder',self.last_dicom_folder) |
187 | 199 | ||
188 | - print config.items('session') | ||
189 | - print config.items('project') | ||
190 | - print config.items('paths') | ||
191 | - | ||
192 | path = os.path.join(self.homedir , | 200 | path = os.path.join(self.homedir , |
193 | '.invesalius', 'config.cfg') | 201 | '.invesalius', 'config.cfg') |
194 | 202 | ||
195 | - if sys.platform == 'win32': | ||
196 | - configfile = codecs.open(path, 'wb', 'utf8') | ||
197 | - else: | ||
198 | - configfile = open(path, 'wb') | ||
199 | - | 203 | + configfile = codecs.open(path, 'wb', SESSION_ENCODING) |
200 | config.write(configfile) | 204 | config.write(configfile) |
201 | configfile.close() | 205 | configfile.close() |
202 | 206 | ||
@@ -238,12 +242,15 @@ class Session(object): | @@ -238,12 +242,15 @@ class Session(object): | ||
238 | 242 | ||
239 | def ReadLanguage(self): | 243 | def ReadLanguage(self): |
240 | config = ConfigParser.ConfigParser() | 244 | config = ConfigParser.ConfigParser() |
241 | - home_path = os.path.expanduser('~') | ||
242 | - path = os.path.join(home_path ,'.invesalius', 'config.cfg') | 245 | + path = os.path.join(USER_INV_DIR, 'config.cfg') |
243 | try: | 246 | try: |
244 | - config.read(path) | 247 | + f = codecs.open(path, 'rb', SESSION_ENCODING) |
248 | + config.readfp(f) | ||
249 | + f.close() | ||
245 | self.language = config.get('session','language') | 250 | self.language = config.get('session','language') |
246 | return self.language | 251 | return self.language |
252 | + except IOError: | ||
253 | + return False | ||
247 | except (ConfigParser.NoSectionError, | 254 | except (ConfigParser.NoSectionError, |
248 | ConfigParser.NoOptionError, | 255 | ConfigParser.NoOptionError, |
249 | ConfigParser.MissingSectionHeaderError): | 256 | ConfigParser.MissingSectionHeaderError): |
@@ -251,12 +258,15 @@ class Session(object): | @@ -251,12 +258,15 @@ class Session(object): | ||
251 | 258 | ||
252 | def ReadRandomId(self): | 259 | def ReadRandomId(self): |
253 | config = ConfigParser.ConfigParser() | 260 | config = ConfigParser.ConfigParser() |
254 | - home_path = os.path.expanduser('~') | ||
255 | - path = os.path.join(home_path ,'.invesalius', 'config.cfg') | 261 | + path = os.path.join(USER_INV_DIR, 'config.cfg') |
256 | try: | 262 | try: |
257 | - config.read(path) | 263 | + f = codecs.open(path, 'rb', SESSION_ENCODING) |
264 | + config.readfp(f) | ||
265 | + f.close() | ||
258 | self.random_id = config.get('session','random_id') | 266 | self.random_id = config.get('session','random_id') |
259 | return self.random_id | 267 | return self.random_id |
268 | + except IOError: | ||
269 | + return False | ||
260 | except (ConfigParser.NoSectionError, | 270 | except (ConfigParser.NoSectionError, |
261 | ConfigParser.NoOptionError, | 271 | ConfigParser.NoOptionError, |
262 | ConfigParser.MissingSectionHeaderError): | 272 | ConfigParser.MissingSectionHeaderError): |
@@ -264,10 +274,11 @@ class Session(object): | @@ -264,10 +274,11 @@ class Session(object): | ||
264 | 274 | ||
265 | def ReadSession(self): | 275 | def ReadSession(self): |
266 | config = ConfigParser.ConfigParser() | 276 | config = ConfigParser.ConfigParser() |
267 | - home_path = os.path.expanduser('~').decode(ENCODE) | ||
268 | - path = os.path.join(home_path ,'.invesalius', 'config.cfg') | 277 | + path = USER_INV_CFG_PATH |
269 | try: | 278 | try: |
270 | - config.readfp(codecs.open(path, 'rb', 'utf8')) | 279 | + f = codecs.open(path, 'rb', SESSION_ENCODING) |
280 | + config.readfp(f) | ||
281 | + f.close() | ||
271 | self.mode = config.get('session', 'mode') | 282 | self.mode = config.get('session', 'mode') |
272 | # Do not reading project status from the config file, since there | 283 | # Do not reading project status from the config file, since there |
273 | # isn't a recover sessession tool in InVesalius | 284 | # isn't a recover sessession tool in InVesalius |
@@ -295,7 +306,6 @@ class Session(object): | @@ -295,7 +306,6 @@ class Session(object): | ||
295 | except(ConfigParser.NoSectionError, ConfigParser.MissingSectionHeaderError, | 306 | except(ConfigParser.NoSectionError, ConfigParser.MissingSectionHeaderError, |
296 | ConfigParser.ParsingError): | 307 | ConfigParser.ParsingError): |
297 | 308 | ||
298 | - print 'Error 1' | ||
299 | if (self.RecoveryConfigFile()): | 309 | if (self.RecoveryConfigFile()): |
300 | self.ReadSession() | 310 | self.ReadSession() |
301 | return True | 311 | return True |
@@ -303,7 +313,6 @@ class Session(object): | @@ -303,7 +313,6 @@ class Session(object): | ||
303 | return False | 313 | return False |
304 | 314 | ||
305 | except(ConfigParser.NoOptionError): | 315 | except(ConfigParser.NoOptionError): |
306 | - print 'Error 2' | ||
307 | #Added to fix new version compatibility | 316 | #Added to fix new version compatibility |
308 | self.surface_interpolation = 0 | 317 | self.surface_interpolation = 0 |
309 | self.slice_interpolation = 0 | 318 | self.slice_interpolation = 0 |
@@ -312,6 +321,5 @@ class Session(object): | @@ -312,6 +321,5 @@ class Session(object): | ||
312 | try: | 321 | try: |
313 | self.WriteSessionFile() | 322 | self.WriteSessionFile() |
314 | except AttributeError: | 323 | except AttributeError: |
315 | - print 'Error 3' | ||
316 | return False | 324 | return False |
317 | return True | 325 | return True |
invesalius/utils.py
@@ -436,3 +436,8 @@ def vtkarray_to_numpy(m): | @@ -436,3 +436,8 @@ def vtkarray_to_numpy(m): | ||
436 | for j in xrange(4): | 436 | for j in xrange(4): |
437 | nm[i, j] = m.GetElement(i, j) | 437 | nm[i, j] = m.GetElement(i, j) |
438 | return nm | 438 | return nm |
439 | + | ||
440 | + | ||
441 | +def touch(fname): | ||
442 | + with open(fname, 'a'): | ||
443 | + pass |