Commit 56415f0ed79f7b5e686f125e817273231ab1b616

Authored by Thiago Franco de Moraes
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).
app.py
... ... @@ -54,6 +54,22 @@ import invesalius.i18n as i18n
54 54 import invesalius.session as ses
55 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 173 # Only after language was defined, splash screen will be
158 174 # shown
159 175 if lang:
160   - print "LANG", lang, _, wx.Locale(), wx.GetLocale()
  176 + # print "LANG", lang, _, wx.Locale(), wx.GetLocale()
161 177 import locale
162 178 locale.setlocale(locale.LC_ALL, '')
163 179 # For pt_BR, splash_pt.png should be used
... ... @@ -237,6 +253,8 @@ def parse_comand_line():
237 253 """
238 254 session = ses.Session()
239 255  
  256 + print ">>>> stdin encoding", sys.stdin.encoding
  257 +
240 258 # Parse command line arguments
241 259 parser = op.OptionParser()
242 260  
... ... @@ -269,7 +287,7 @@ def parse_comand_line():
269 287 i = len(args)
270 288 while i:
271 289 i -= 1
272   - file = args[i]
  290 + file = args[i].decode(sys.stdin.encoding)
273 291 if os.path.isfile(file):
274 292 path = os.path.abspath(file)
275 293 Publisher.sendMessage('Open project', path)
... ... @@ -308,22 +326,16 @@ if __name__ == '__main__':
308 326 os.chdir(path)
309 327  
310 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 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 336 if hasattr(sys,"frozen") and sys.frozen == "windows_exe":
325 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 339 sys.stderr = open(path, "w")
328 340  
329 341 # Add current directory to PYTHONPATH, so other classes can
... ...
invesalius/constants.py
... ... @@ -320,46 +320,63 @@ WINDOW_LEVEL = {_("Abdomen"):(350,50),
320 320  
321 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 342 if hasattr(sys,"frozen") and (sys.frozen == "windows_exe"\
326 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 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 366 # MAC App
350 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 382 # if 1, use vtkVolumeRaycastMapper, if 0, use vtkFixedPointVolumeRayCastMapper
... ... @@ -405,19 +422,10 @@ RAYCASTING_FILES = {_("Airways"): "Airways.plist",
405 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 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 429 RAYCASTING_TYPES += RAYCASTING_FILES.keys()
422 430 RAYCASTING_TYPES.append(_(' Off'))
423 431 RAYCASTING_TYPES.sort()
... ...
invesalius/control.py
... ... @@ -338,6 +338,9 @@ class Controller():
338 338 else:
339 339 dirpath, filename = session.project_path
340 340  
  341 + if isinstance(filename, str):
  342 + filename = filename.decode(const.FS_ENCODE)
  343 +
341 344 proj = prj.Project()
342 345 prj.Project().SavePlistProject(dirpath, filename)
343 346  
... ...
invesalius/data/imagedata_utils.py
... ... @@ -227,7 +227,7 @@ def CreateImageData(filelist, zspacing, xyspacing,size,
227 227 message = _("Generating multiplanar visualization...")
228 228  
229 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 231 fow = vtk.vtkFileOutputWindow()
232 232 fow.SetFileName(log_path)
233 233 ow = vtk.vtkOutputWindow()
... ... @@ -332,7 +332,7 @@ class ImageCreator:
332 332 message = _("Generating multiplanar visualization...")
333 333  
334 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 336 fow = vtk.vtkFileOutputWindow()
337 337 fow.SetFileName(log_path)
338 338 ow = vtk.vtkOutputWindow()
... ...
invesalius/data/mask.py
... ... @@ -245,7 +245,7 @@ class Mask():
245 245 mask['mask_shape'] = self.matrix.shape
246 246 mask['edited'] = self.was_edited
247 247  
248   - plist_filename = filename + '.plist'
  248 + plist_filename = filename + u'.plist'
249 249 #plist_filepath = os.path.join(dir_temp, plist_filename)
250 250  
251 251 temp_plist = tempfile.mktemp()
... ...
invesalius/data/polydata_utils.py
... ... @@ -23,7 +23,18 @@ import vtk
23 23 import wx
24 24 from wx.lib.pubsub import pub as Publisher
25 25  
  26 +import invesalius.constants as const
26 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 39 # Update progress value in GUI
29 40 UpdateProgress = vu.ShowProgress()
... ... @@ -109,8 +120,10 @@ def Merge(polydata_list):
109 120  
110 121 def Export(polydata, filename, bin=False):
111 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 127 if bin:
115 128 writer.SetDataModeToBinary()
116 129 else:
... ...
invesalius/data/surface.py
... ... @@ -21,6 +21,8 @@ import multiprocessing
21 21 import os
22 22 import plistlib
23 23 import random
  24 +import shutil
  25 +import sys
24 26 import tempfile
25 27 import weakref
26 28  
... ... @@ -28,6 +30,15 @@ import vtk
28 30 import wx
29 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 42 import invesalius.constants as const
32 43 import invesalius.data.imagedata_utils as iu
33 44 import invesalius.data.polydata_utils as pu
... ... @@ -64,8 +75,8 @@ class Surface():
64 75 self.name = name
65 76  
66 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 80 vtp_filepath = os.path.join(dir_temp, vtp_filename)
70 81 pu.Export(self.polydata, vtp_filepath, bin=True)
71 82  
... ... @@ -80,7 +91,7 @@ class Surface():
80 91 'volume': self.volume,
81 92 'area': self.area,
82 93 }
83   - plist_filename = filename + '.plist'
  94 + plist_filename = filename + u'.plist'
84 95 #plist_filepath = os.path.join(dir_temp, filename + '.plist')
85 96 temp_plist = tempfile.mktemp()
86 97 plistlib.writePlist(surface, temp_plist)
... ... @@ -263,7 +274,11 @@ class SurfaceManager():
263 274 wx.MessageBox(_("File format not reconized by InVesalius"), _("Import surface error"))
264 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 282 reader.Update()
268 283 polydata = reader.GetOutput()
269 284  
... ... @@ -869,11 +884,31 @@ class SurfaceManager():
869 884  
870 885 def OnExportSurface(self, pubsub_evt):
871 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 912 # First we identify all surfaces that are selected
878 913 # (if any)
879 914 proj = prj.Project()
... ... @@ -912,7 +947,9 @@ class SurfaceManager():
912 947 #writer.SetColorModeToUniformCellColor()
913 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 953 # Invert normals
917 954 normals = vtk.vtkPolyDataNormals()
918 955 normals.SetInputData(polydata)
... ... @@ -923,7 +960,7 @@ class SurfaceManager():
923 960 normals.Update()
924 961 polydata = normals.GetOutput()
925 962  
926   - filename = filename.encode(wx.GetDefaultPyEncoding())
  963 + filename = filename.encode(const.FS_ENCODE)
927 964 writer.SetFileName(filename)
928 965 writer.SetInputData(polydata)
929 966 writer.Write()
... ...
invesalius/data/viewer_slice.py
... ... @@ -21,6 +21,7 @@
21 21  
22 22 import collections
23 23 import itertools
  24 +import os
24 25 import tempfile
25 26  
26 27 import numpy as np
... ... @@ -49,6 +50,15 @@ import invesalius.session as ses
49 50 import invesalius.data.converters as converters
50 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 62 ID_TO_TOOL_ITEM = {}
53 63 STR_WL = "WL: %d WW: %d"
54 64  
... ... @@ -1250,12 +1260,27 @@ class Viewer(wx.Panel):
1250 1260 self.interactor.SetCursor(wx.StockCursor(wx.CURSOR_SIZING))
1251 1261  
1252 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 1280 view_prop_list = []
1255 1281 view_prop_list.append(self.slice_data.box_actor)
1256 1282 self.slice_data.renderer.RemoveViewProp(self.slice_data.box_actor)
1257 1283  
1258   - id, filename, filetype = pubsub_evt.data
1259 1284 dict = {"AXIAL": const.AXIAL,
1260 1285 "CORONAL": const.CORONAL,
1261 1286 "SAGITAL": const.SAGITAL}
... ... @@ -1294,9 +1319,12 @@ class Viewer(wx.Panel):
1294 1319 filename = "%s.tif"%filename.strip(".tif")
1295 1320  
1296 1321 writer.SetInputData(image)
1297   - writer.SetFileName(filename)
  1322 + writer.SetFileName(filename.encode(const.FS_ENCODE))
1298 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 1328 for actor in view_prop_list:
1301 1329 self.slice_data.renderer.AddViewProp(actor)
1302 1330  
... ... @@ -1321,9 +1349,10 @@ class Viewer(wx.Panel):
1321 1349 del self.slice_data
1322 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 1357 self.orientation_texts = []
1329 1358  
... ...
invesalius/data/viewer_volume.py
... ... @@ -20,6 +20,7 @@
20 20 # detalhes.
21 21 #--------------------------------------------------------------------------
22 22  
  23 +import os
23 24 import sys
24 25  
25 26 import numpy as np
... ... @@ -37,6 +38,15 @@ import invesalius.style as st
37 38 import invesalius.utils as utils
38 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 50 PROP_MEASURE = 0.8
41 51  
42 52 class Viewer(wx.Panel):
... ... @@ -314,15 +324,24 @@ class Viewer(wx.Panel):
314 324 self.seed_points)
315 325  
316 326 def OnExportPicture(self, pubsub_evt):
317   - Publisher.sendMessage('Begin busy cursor')
318 327 id, filename, filetype = pubsub_evt.data
319 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 339 if filetype == const.FILETYPE_POV:
321 340 renwin = self.interactor.GetRenderWindow()
322 341 image = vtk.vtkWindowToImageFilter()
323 342 image.SetInput(renwin)
324 343 writer = vtk.vtkPOVExporter()
325   - writer.SetFileName(filename)
  344 + writer.SetFileName(filename.encode(const.FS_ENCODE))
326 345 writer.SetRenderWindow(renwin)
327 346 writer.Write()
328 347 else:
... ... @@ -345,12 +364,15 @@ class Viewer(wx.Panel):
345 364 writer = vtk.vtkPostScriptWriter()
346 365 elif (filetype == const.FILETYPE_TIF):
347 366 writer = vtk.vtkTIFFWriter()
348   - filename = "%s.tif"%filename.strip(".tif")
  367 + filename = u"%s.tif"%filename.strip(".tif")
349 368  
350 369 writer.SetInputData(image)
351   - writer.SetFileName(filename)
  370 + writer.SetFileName(filename.encode(const.FS_ENCODE))
352 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 377 def OnCloseProject(self, pubsub_evt):
356 378 if self.raycasting_volume:
... ... @@ -764,6 +786,18 @@ class Viewer(wx.Panel):
764 786  
765 787 def OnExportSurface(self, pubsub_evt):
766 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 801 fileprefix = filename.split(".")[-2]
768 802 renwin = self.interactor.GetRenderWindow()
769 803  
... ...
invesalius/expanduser.py 0 → 100644
... ... @@ -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 323 if dlg.ShowModal() == wx.ID_OK:
324 324 # GetPath returns in unicode, if a path has non-ascii characters a
325 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 328 except(wx._core.PyAssertionError): #TODO: error win64
332 329 if (dlg.GetPath()):
... ... @@ -398,12 +395,7 @@ def ShowImportMeshFilesDialog():
398 395 filename = None
399 396 try:
400 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 400 except(wx._core.PyAssertionError): # TODO: error win64
409 401 if (dlg.GetPath()):
... ... @@ -1058,52 +1050,52 @@ def ShowAboutDialog(parent):
1058 1050 info.WebSite = ("https://www.cti.gov.br/invesalius")
1059 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 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 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 1100 # Then we call wx.AboutBox providing its info object
1109 1101 wx.AboutBox(info)
... ...
invesalius/gui/dicom_preview_panel.py
... ... @@ -21,6 +21,7 @@
21 21 # -*- coding: UTF-8 -*-
22 22  
23 23 #TODO: To create a beautiful API
  24 +import sys
24 25 import time
25 26 import tempfile
26 27  
... ... @@ -37,6 +38,14 @@ import invesalius.data.vtk_utils as vtku
37 38 import invesalius.utils as utils
38 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 50 NROWS = 3
42 51 NCOLS = 6
... ... @@ -837,7 +846,10 @@ class SingleImagePreview(wx.Panel):
837 846 self.text_acquisition.SetValue(value)
838 847  
839 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 853 rdicom.Update()
842 854  
843 855 # ADJUST CONTRAST
... ...
invesalius/gui/task_exporter.py
... ... @@ -331,6 +331,13 @@ class InnerTaskPanel(wx.Panel):
331 331 filename = filename + "."+ extension
332 332 Publisher.sendMessage('Export surface to file',
333 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 341 else:
335 342 dlg = wx.MessageDialog(None,
336 343 _("You need to create a surface and make it ") +
... ...
invesalius/project.py
... ... @@ -22,6 +22,7 @@ import glob
22 22 import os
23 23 import plistlib
24 24 import shutil
  25 +import sys
25 26 import tarfile
26 27 import tempfile
27 28  
... ... @@ -32,9 +33,18 @@ import vtk
32 33 import invesalius.constants as const
33 34 import invesalius.data.polydata_utils as pu
34 35 from invesalius.presets import Presets
35   -from invesalius.utils import Singleton, debug
  36 +from invesalius.utils import Singleton, debug, touch
36 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 48 class Project(object):
39 49 # Only one project will be initialized per time. Therefore, we use
40 50 # Singleton design pattern for implementing it
... ... @@ -193,10 +203,14 @@ class Project(object):
193 203 return measures
194 204  
195 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 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 214 project = {
201 215 # Format info
202 216 "format_version": 1,
... ... @@ -214,10 +228,11 @@ class Project(object):
214 228 }
215 229  
216 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 236 project['matrix'] = matrix
222 237 filelist[self.matrix_filename] = 'matrix.dat'
223 238 #shutil.copyfile(self.matrix_filename, filename_tmp)
... ... @@ -270,9 +285,9 @@ class Project(object):
270 285 import invesalius.data.surface as srf
271 286  
272 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 289 fow = vtk.vtkFileOutputWindow()
275   - fow.SetFileName(log_path)
  290 + fow.SetFileName(log_path.encode(const.FS_ENCODE))
276 291 ow = vtk.vtkOutputWindow()
277 292 ow.SetInstance(fow)
278 293  
... ... @@ -328,29 +343,37 @@ class Project(object):
328 343 def Compress(folder, filename, filelist):
329 344 tmpdir, tmpdir_ = os.path.split(folder)
330 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 352 #os.chdir(tmpdir)
332 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 356 for name in filelist:
336 357 tar.add(name, arcname=os.path.join(tmpdir_, filelist[name]))
337 358 tar.close()
338   - #shutil.move(tmpdir_+ ".inv3", filename)
  359 + shutil.move(temp_inv3, filename)
339 360 #os.chdir(current_dir)
340 361  
  362 +
341 363 def Extract(filename, folder):
  364 + if _has_win32api:
  365 + folder = win32api.GetShortPathName(folder)
  366 + folder = folder.decode(const.FS_ENCODE)
  367 +
342 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 371 filelist = []
346 372 for t in tar.getmembers():
347 373 fsrc = tar.extractfile(t)
348   -
349 374 fname = os.path.join(folder, t.name.decode('utf-8'))
350 375 fdst = file(fname, 'wb')
351   -
352 376 shutil.copyfileobj(fsrc, fdst)
353   -
354 377 filelist.append(fname)
355 378 fsrc.close()
356 379 fdst.close()
... ... @@ -359,7 +382,7 @@ def Extract(filename, folder):
359 382 tar.close()
360 383 return filelist
361 384  
362   -
  385 +
363 386 def Extract_(filename, folder):
364 387 tar = tarfile.open(filename, "r:gz")
365 388 #tar.list(verbose=True)
... ...
invesalius/reader/bitmap_reader.py
... ... @@ -40,6 +40,15 @@ import invesalius.data.converters as converters
40 40 no_error = True
41 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 52 class Singleton:
44 53  
45 54 def __init__(self,klass):
... ... @@ -127,10 +136,7 @@ class LoadBitmap:
127 136  
128 137 def __init__(self, bmp_file, filepath):
129 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 141 self.run()
136 142  
... ... @@ -294,9 +300,9 @@ def ScipyRead(filepath):
294 300  
295 301 def VtkRead(filepath, t):
296 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 304 fow = vtk.vtkFileOutputWindow()
299   - fow.SetFileName(log_path)
  305 + fow.SetFileName(log_path.encode(const.FS_ENCODE))
300 306 ow = vtk.vtkOutputWindow()
301 307 ow.SetInstance(fow)
302 308  
... ... @@ -317,8 +323,10 @@ def VtkRead(filepath, t):
317 323 else:
318 324 return False
319 325  
  326 + print ">>>> bmp reader", type(filepath)
  327 +
320 328 reader.AddObserver("ErrorEvent", VtkErrorToPy)
321   - reader.SetFileName(filepath)
  329 + reader.SetFileName(filepath.encode(const.FS_ENCODE))
322 330 reader.Update()
323 331  
324 332 if no_error:
... ... @@ -345,6 +353,9 @@ def VtkRead(filepath, t):
345 353 def ReadBitmap(filepath):
346 354 t = VerifyDataType(filepath)
347 355  
  356 + if _has_win32api:
  357 + filepath = win32api.GetShortPathName(filepath)
  358 +
348 359 if t == False:
349 360 measures_info = GetPixelSpacingFromInfoFile(filepath)
350 361  
... ... @@ -368,7 +379,6 @@ def ReadBitmap(filepath):
368 379  
369 380  
370 381 def GetPixelSpacingFromInfoFile(filepath):
371   -
372 382 fi = open(filepath, 'r')
373 383 lines = fi.readlines()
374 384 measure_scale = 'mm'
... ...
invesalius/reader/dicom_grouper.py
... ... @@ -51,9 +51,23 @@
51 51 # <dicom.image.number> and <dicom.acquisition.series_number>
52 52 # were swapped
53 53  
  54 +import sys
  55 +
54 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 67 import invesalius.utils as utils
  68 +import invesalius.constants as const
  69 +
  70 +
57 71 ORIENT_MAP = {"SAGITTAL":0, "CORONAL":1, "AXIAL":2, "OBLIQUE":2}
58 72  
59 73  
... ... @@ -109,8 +123,13 @@ class DicomGroup:
109 123 # This list will be used to create the vtkImageData
110 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 134 # Sort slices using GDCM
116 135 if (self.dicom.image.orientation_label <> "CORONAL"):
... ...
invesalius/reader/dicom_reader.py
... ... @@ -38,6 +38,15 @@ import invesalius.utils as utils
38 38  
39 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 50 def ReadDicomGroup(dir_):
42 51  
43 52 patient_group = GetDicomGroups(dir_)
... ... @@ -88,18 +97,18 @@ class LoadDicom:
88 97  
89 98 def __init__(self, grouper, filepath):
90 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 102 self.run()
97 103  
98 104 def run(self):
99   -
100 105 grouper = self.grouper
101 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 112 if (reader.Read()):
104 113 file = reader.GetFile()
105 114  
... ... @@ -180,7 +189,12 @@ class LoadDicom:
180 189  
181 190 # -------------- To Create DICOM Thumbnail -----------
182 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 198 rvtk.Update()
185 199  
186 200 try:
... ... @@ -341,7 +355,7 @@ class ProgressDicomReader:
341 355 def GetDicomGroups(self, path, recursive):
342 356  
343 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 359 fow = vtk.vtkFileOutputWindow()
346 360 fow.SetFileName(log_path)
347 361 ow = vtk.vtkOutputWindow()
... ...
invesalius/reader/others_reader.py
... ... @@ -38,9 +38,9 @@ def ReadOthers(dir_):
38 38 """
39 39  
40 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 42 fow = vtk.vtkFileOutputWindow()
43   - fow.SetFileName(log_path)
  43 + fow.SetFileName(log_path.encode(const.FS_ENCODE))
44 44 ow = vtk.vtkOutputWindow()
45 45 ow.SetInstance(fow)
46 46  
... ...
invesalius/session.py
... ... @@ -36,7 +36,24 @@ import wx
36 36 from invesalius.utils import Singleton, debug
37 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 58 class Session(object):
42 59 # Only one session will be initialized per time. Therefore, we use
... ... @@ -62,7 +79,7 @@ class Session(object):
62 79 # const.MODE_ODONTOLOGY
63 80  
64 81 # InVesalius default projects' directory
65   - homedir = self.homedir = os.path.expanduser('~').decode(ENCODE)
  82 + homedir = self.homedir = USER_DIR
66 83 tempdir = os.path.join(homedir, u".invesalius", u"temp")
67 84 if not os.path.isdir(tempdir):
68 85 os.makedirs(tempdir)
... ... @@ -72,10 +89,9 @@ class Session(object):
72 89 self.language = "" # "pt_BR", "es"
73 90  
74 91 self.random_id = randint(0,pow(10,16))
75   - #print self.random_id
76 92  
77 93 # Recent projects list
78   - self.recent_projects = [(const.SAMPLE_DIR, "Cranium.inv3")]
  94 + self.recent_projects = [(const.SAMPLE_DIR, u"Cranium.inv3")]
79 95 self.last_dicom_folder = ''
80 96 self.surface_interpolation = 1
81 97 self.slice_interpolation = 0
... ... @@ -88,18 +104,18 @@ class Session(object):
88 104  
89 105 def SaveConfigFileBackup(self):
90 106 path = os.path.join(self.homedir ,
91   - '.invesalius', 'config.cfg')
  107 + u'.invesalius', u'config.cfg')
92 108 path_dst = os.path.join(self.homedir ,
93   - '.invesalius', 'config.backup')
  109 + u'.invesalius', u'config.backup')
94 110 shutil.copy(path, path_dst)
95 111  
96 112 def RecoveryConfigFile(self):
97 113 homedir = self.homedir = os.path.expanduser('~')
98 114 try:
99 115 path = os.path.join(self.homedir ,
100   - '.invesalius', 'config.backup')
  116 + u'.invesalius', u'config.backup')
101 117 path_dst = os.path.join(self.homedir ,
102   - '.invesalius', 'config.cfg')
  118 + u'.invesalius', u'config.cfg')
103 119 shutil.copy(path, path_dst)
104 120 return True
105 121 except(IOError):
... ... @@ -163,10 +179,6 @@ class Session(object):
163 179 def WriteSessionFile(self):
164 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 182 config.add_section('session')
171 183 config.set('session', 'mode', self.mode)
172 184 config.set('session', 'status', self.project_status)
... ... @@ -185,18 +197,10 @@ class Session(object):
185 197 config.set('paths','tempdir',self.tempdir)
186 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 200 path = os.path.join(self.homedir ,
193 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 204 config.write(configfile)
201 205 configfile.close()
202 206  
... ... @@ -238,12 +242,15 @@ class Session(object):
238 242  
239 243 def ReadLanguage(self):
240 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 246 try:
244   - config.read(path)
  247 + f = codecs.open(path, 'rb', SESSION_ENCODING)
  248 + config.readfp(f)
  249 + f.close()
245 250 self.language = config.get('session','language')
246 251 return self.language
  252 + except IOError:
  253 + return False
247 254 except (ConfigParser.NoSectionError,
248 255 ConfigParser.NoOptionError,
249 256 ConfigParser.MissingSectionHeaderError):
... ... @@ -251,12 +258,15 @@ class Session(object):
251 258  
252 259 def ReadRandomId(self):
253 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 262 try:
257   - config.read(path)
  263 + f = codecs.open(path, 'rb', SESSION_ENCODING)
  264 + config.readfp(f)
  265 + f.close()
258 266 self.random_id = config.get('session','random_id')
259 267 return self.random_id
  268 + except IOError:
  269 + return False
260 270 except (ConfigParser.NoSectionError,
261 271 ConfigParser.NoOptionError,
262 272 ConfigParser.MissingSectionHeaderError):
... ... @@ -264,10 +274,11 @@ class Session(object):
264 274  
265 275 def ReadSession(self):
266 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 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 282 self.mode = config.get('session', 'mode')
272 283 # Do not reading project status from the config file, since there
273 284 # isn't a recover sessession tool in InVesalius
... ... @@ -295,7 +306,6 @@ class Session(object):
295 306 except(ConfigParser.NoSectionError, ConfigParser.MissingSectionHeaderError,
296 307 ConfigParser.ParsingError):
297 308  
298   - print 'Error 1'
299 309 if (self.RecoveryConfigFile()):
300 310 self.ReadSession()
301 311 return True
... ... @@ -303,7 +313,6 @@ class Session(object):
303 313 return False
304 314  
305 315 except(ConfigParser.NoOptionError):
306   - print 'Error 2'
307 316 #Added to fix new version compatibility
308 317 self.surface_interpolation = 0
309 318 self.slice_interpolation = 0
... ... @@ -312,6 +321,5 @@ class Session(object):
312 321 try:
313 322 self.WriteSessionFile()
314 323 except AttributeError:
315   - print 'Error 3'
316 324 return False
317 325 return True
... ...
invesalius/utils.py
... ... @@ -436,3 +436,8 @@ def vtkarray_to_numpy(m):
436 436 for j in xrange(4):
437 437 nm[i, j] = m.GetElement(i, j)
438 438 return nm
  439 +
  440 +
  441 +def touch(fname):
  442 + with open(fname, 'a'):
  443 + pass
... ...