From 8ccdd8e80e69ee5b2de303f97eaed700e87e356e Mon Sep 17 00:00:00 2001 From: Roy-043 <70520633+Roy-043@users.noreply.github.com> Date: Sun, 7 May 2023 09:56:01 +0200 Subject: [PATCH] Draft: improve handling of DWG-converters (#9444) * Draft: improve handling of DWG-converters * Lint import statement. --- src/Mod/Draft/importDWG.py | 290 ++++++++++++++++++++++++------------- 1 file changed, 193 insertions(+), 97 deletions(-) diff --git a/src/Mod/Draft/importDWG.py b/src/Mod/Draft/importDWG.py index 61bc6becef..967040a839 100644 --- a/src/Mod/Draft/importDWG.py +++ b/src/Mod/Draft/importDWG.py @@ -12,10 +12,6 @@ This module is only a thin layer that uses the ODA (formerly Teigha) File Converter application to convert to/from DXF. Then the real work is done by importDXF -The converter may be called -/usr/bin/TeighaFileConverter -/usr/bin/ODAFileConverter - Test files https://knowledge.autodesk.com/support/autocad/downloads/ caas/downloads/content/autocad-sample-files.html @@ -125,7 +121,9 @@ def export(objectslist, filename): str The same `filename` input. """ - import importDXF, os, tempfile + import importDXF + import os + import tempfile outdir = tempfile.mkdtemp() _basename = os.path.splitext(os.path.basename(filename))[0] dxf = outdir + os.sep + _basename + ".dxf" @@ -134,11 +132,54 @@ def export(objectslist, filename): return filename -def getTeighaConverter(): - """Find the ODA (formerly Teigha) executable. +def get_libredwg_converter(typ): + """Find the LibreDWG converter. + + It searches the FreeCAD parameters database, then searches the OS search path + on Linux and Windows systems. There are no standard installation paths. + + `typ` is required because LibreDWG uses two converters and we store only one. + + Parameters + ---------- + typ : str + "dwg2dxf" or "dxf2dwg". + + Returns + ------- + str + The full path of the converter. + """ + import os + import platform + + p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") + path = p.GetString("TeighaFileConverter") + + if "dwg2dxf" in path or "dxf2dwg" in path: # path set manually + if typ not in path: + path = os.path.dirname(path) + "/" + typ + os.path.splitext(path)[1] + if os.path.exists(path) and os.path.isfile(path): + return path + elif platform.system() == "Linux": + for sub in os.getenv("PATH").split(":"): + path = sub + "/" + typ + if os.path.exists(path) and os.path.isfile(path): + return path + elif platform.system() == "Windows": + for sub in os.getenv("PATH").split(";"): + path = sub.replace("\\", "/") + "/" + typ + ".exe" + if os.path.exists(path) and os.path.isfile(path): + return path + + return None + + +def get_oda_converter(): + """Find the ODA converter. It searches the FreeCAD parameters database, then searches for common - paths in Linux and Windows systems. + paths on Linux and Windows systems. Parameters ---------- @@ -147,26 +188,67 @@ def getTeighaConverter(): Returns ------- str - The full path of the converter executable - '/usr/bin/ODAFileConverter' + The full path of the converter. """ - import FreeCAD, os, platform + import os + import platform + p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") path = p.GetString("TeighaFileConverter") - if path: - # path set manually - return path + + if "ODAFileConverter" in path: # path set manually + if os.path.exists(path) and os.path.isfile(path): + return path elif platform.system() == "Linux": path = "/usr/bin/ODAFileConverter" - if os.path.exists(path): + if os.path.exists(path) and os.path.isfile(path): return path elif platform.system() == "Windows": - odadir = os.path.expandvars("%ProgramFiles%\ODA") + odadir = os.path.expandvars("%ProgramFiles%\\ODA").replace("\\", "/") if os.path.exists(odadir): for sub in os.listdir(odadir): - path = os.path.join(odadir, sub, "ODAFileConverter.exe") - if os.path.exists(path): + path = odadir + "/" + sub + "/" + "ODAFileConverter.exe" + if os.path.exists(path) and os.path.isfile(path): return path + + return None + + +def get_qcad_converter(): + """Find the QCAD converter. + + It searches the FreeCAD parameters database, then searches for common + paths on Linux and Windows systems. + + Parameters + ---------- + None + + Returns + ------- + str + The full path of the converter. + """ + import os + import platform + + p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") + path = p.GetString("TeighaFileConverter") + + if "dwg2dwg" in path: # path set manually + pass + elif platform.system() == "Linux": + # /home/$USER/opt/qcad-3.28.1-trial-linux-qt5.14-x86_64/dwg2dwg + path = os.path.expandvars("/home/$USER/opt") + for sub in os.listdir(path): + if "qcad" in sub: + path = path + "/" + sub + "/" + "dwg2dwg" + break + elif platform.system() == "Windows": + path = os.path.expandvars("%ProgramFiles%\\QCAD\\dwg2dwg.bat").replace("\\", "/") + + if os.path.exists(path) and os.path.isfile(path): + return path return None @@ -185,63 +267,76 @@ def convertToDxf(dwgfilename): str The new file produced. """ - import os, tempfile, subprocess, sys + import os + import subprocess + import tempfile + dwgfilename = dwgfilename.replace("\\", "/") p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") - conv = p.GetInt("DWGConversion",0) - path = p.GetString("TeighaFileConverter","") + conv = p.GetInt("DWGConversion", 0) + error_msg = translate("draft", """Error during DWG conversion. +Try moving the DWG file to a directory path without spaces and non-english characters, +or try saving to a lower DWG version.""") + "\n" - if conv in [0,1]: # LibreDWG dxf2dwg/dwg2dxf - if not path: - path = "dwg2dxf" - if path.endswith("dxf2dwg"): - path = os.path.join(os.path.dirname,"dwg2dxf") - try: - outdir = tempfile.mkdtemp() + if conv in [0, 1]: # LibreDWG + libredwg = get_libredwg_converter("dwg2dxf") + if libredwg is not None: + outdir = tempfile.mkdtemp().replace("\\", "/") basename = os.path.basename(dwgfilename) - result = outdir + os.sep + os.path.splitext(basename)[0] + ".dxf" - proc = subprocess.Popen((path, dwgfilename, "-o", result)) - proc.communicate() - return result - except Exception: - if conv != 0: - FCC.PrintError(translate("draft", "LibreDWG error") + "\n") - - if conv in [0,2]: # ODA - teigha = getTeighaConverter() - if teigha: - indir = os.path.dirname(dwgfilename) - outdir = tempfile.mkdtemp() - basename = os.path.basename(dwgfilename) - cmdline = [teigha, indir, outdir, "ACAD2000", "DXF", "0", "1", basename] + result = outdir + "/" + os.path.splitext(basename)[0] + ".dxf" + cmdline = [libredwg, dwgfilename, "-o", result] FCC.PrintMessage(translate("draft", "Converting:") + " " + str(cmdline) + "\n") proc = subprocess.Popen(cmdline) proc.communicate() - result = outdir + os.sep + os.path.splitext(basename)[0] + ".dxf" if os.path.exists(result): FCC.PrintMessage(translate("draft", "Conversion successful") + "\n") return result else: - FCC.PrintError(translate("draft","""Error during DWG conversion. -Try moving the DWG file to a directory path without spaces and non-english characters, -or try saving to a lower DWG version.""") + "\n") - else: - if conv != 0: - FCC.PrintError(translate("draft", "ODA File Converter not found") + "\n") + FCC.PrintError(error_msg) + elif conv != 0: + FCC.PrintError(translate("draft", "LibreDWG converter not found") + "\n") - if conv in [0,3]: # QCAD - if not path: - path = "dwg2dwg" - try: - outdir = tempfile.mkdtemp() + if conv in [0, 2]: # ODA + oda = get_oda_converter() + if oda is not None: + indir = os.path.dirname(dwgfilename) + outdir = tempfile.mkdtemp().replace("\\", "/") basename = os.path.basename(dwgfilename) - result = outdir + os.sep + os.path.splitext(basename)[0] + ".dxf" - proc = subprocess.Popen((path, "-f", "-o", result, dwgfilename)) + cmdline = [oda, indir, outdir, "ACAD2000", "DXF", "0", "1", basename] + FCC.PrintMessage(translate("draft", "Converting:") + " " + str(cmdline) + "\n") + proc = subprocess.Popen(cmdline) proc.communicate() - return result - except Exception: - FCC.PrintError(translate("draft", "QCAD error") + "\n") + result = outdir + "/" + os.path.splitext(basename)[0] + ".dxf" + if os.path.exists(result): + FCC.PrintMessage(translate("draft", "Conversion successful") + "\n") + return result + else: + FCC.PrintError(error_msg) + elif conv != 0: + FCC.PrintError(translate("draft", "ODA converter not found") + "\n") + if conv in [0, 3]: # QCAD + qcad = get_qcad_converter() + if qcad is not None: + outdir = tempfile.mkdtemp().replace("\\", "/") + basename = os.path.basename(dwgfilename) + result = outdir + "/" + os.path.splitext(basename)[0] + ".dxf" + cmdline = [qcad, "-f", "-o", result, dwgfilename] + FCC.PrintMessage(translate("draft", "Converting:") + " " + str(cmdline) + "\n") + proc = subprocess.Popen(cmdline, cwd=os.path.dirname(qcad)) # cwd required for Windows + proc.communicate() + if os.path.exists(result): + FCC.PrintMessage(translate("draft", "Conversion successful") + "\n") + return result + else: + FCC.PrintError(error_msg) + elif conv != 0: + FCC.PrintError(translate("draft", "QCAD converter not found") + "\n") + + FCC.PrintError(translate("draft", """No suitable external DWG converter has been found. +Please set one manually under menu Edit -> Preferences -> Import/Export -> DWG +For more information see: +https://wiki.freecad.org/Import_Export_Preferences""") + "\n") return None @@ -262,51 +357,52 @@ def convertToDwg(dxffilename, dwgfilename): str The same `dwgfilename` file path. """ - import os, subprocess, shutil + import os + import subprocess + dxffilename = dxffilename.replace("\\", "/") + dwgfilename = dwgfilename.replace("\\", "/") p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") - conv = p.GetInt("DWGConversion",0) - path = p.GetString("TeighaFileConverter","") + conv = p.GetInt("DWGConversion", 0) - if conv in [0,1]: # LibreDWG dxf2dwg/dwg2dxf - if not path: - path = "dxf2dwg" - if path.endswith("dwg2dxf"): - path = os.path.join(os.path.dirname,"dxf2dwg") - try: - proc = subprocess.Popen((path, dxffilename, "-y", "-o", dwgfilename)) - proc.communicate() - return dwgfilename - except Exception: - if conv != 0: - FCC.PrintError(translate("draft", "LibreDWG error") + "\n") - - if conv in [0,2]: # ODA - teigha = getTeighaConverter() - if teigha: - indir = os.path.dirname(dxffilename) - outdir = os.path.dirname(dwgfilename) - basename = os.path.basename(dxffilename) - cmdline = [teigha, indir, outdir, "ACAD2000", "DWG", "0", "1", basename] + if conv in [0, 1]: # LibreDWG + libredwg = get_libredwg_converter("dxf2dwg") + if libredwg is not None: + cmdline = [libredwg, dxffilename, "-y", "-o", dwgfilename] FCC.PrintMessage(translate("draft", "Converting:") + " " + str(cmdline) + "\n") proc = subprocess.Popen(cmdline) proc.communicate() return dwgfilename - else: - if conv != 0: - FCC.PrintError(translate("draft", "ODA File Converter not found") + "\n") + elif conv != 0: + FCC.PrintError(translate("draft", "LibreDWG converter not found") + "\n") - if conv in [0,3]: # QCAD - if not path: - path = "dwg2dwg" - try: - proc = subprocess.Popen((path, "-o", dwgfilename, dxffilename)) + if conv in [0, 2]: # ODA + oda = get_oda_converter() + if oda is not None: + indir = os.path.dirname(dxffilename) + outdir = os.path.dirname(dwgfilename) + basename = os.path.basename(dxffilename) + cmdline = [oda, indir, outdir, "ACAD2000", "DWG", "0", "1", basename] + FCC.PrintMessage(translate("draft", "Converting:") + " " + str(cmdline) + "\n") + proc = subprocess.Popen(cmdline) proc.communicate() return dwgfilename - except Exception: - if conv != 0: - FCC.PrintError(translate("draft", "QCAD error") + "\n") - else: - FCC.PrintError(translate("draft", """No suitable DWG converter has been found. -Please set one manually under menu Edit -> Preferences -> Import/Export -> DWG""") + "\n") + elif conv != 0: + FCC.PrintError(translate("draft", "ODA converter not found") + "\n") + + if conv in [0, 3]: # QCAD + qcad = get_qcad_converter() + if qcad is not None: + cmdline = [qcad, "-f", "-o", dwgfilename, dxffilename] + FCC.PrintMessage(translate("draft", "Converting:") + " " + str(cmdline) + "\n") + proc = subprocess.Popen(cmdline, cwd=os.path.dirname(qcad)) # cwd required for Windows + proc.communicate() + return dwgfilename + elif conv != 0: + FCC.PrintError(translate("draft", "QCAD converter not found") + "\n") + + FCC.PrintError(translate("draft", """No suitable external DWG converter has been found. +Please set one manually under menu Edit -> Preferences -> Import/Export -> DWG +For more information see: +https://wiki.freecad.org/Import_Export_Preferences""") + "\n") return None