GCodeReader.py 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. # Copyright (c) 2017 Aleph Objects, Inc.
  2. # Copyright (c) 2020 Ultimaker B.V.
  3. # Cura is released under the terms of the LGPLv3 or higher.
  4. from typing import Optional, Union, List, TYPE_CHECKING
  5. from UM.FileHandler.FileReader import FileReader
  6. from UM.Mesh.MeshReader import MeshReader
  7. from UM.i18n import i18nCatalog
  8. from UM.Application import Application
  9. from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType
  10. catalog = i18nCatalog("cura")
  11. from .FlavorParser import FlavorParser
  12. from . import MarlinFlavorParser, RepRapFlavorParser
  13. if TYPE_CHECKING:
  14. from UM.Scene.SceneNode import SceneNode
  15. from cura.Scene.CuraSceneNode import CuraSceneNode
  16. # Class for loading and parsing G-code files
  17. class GCodeReader(MeshReader):
  18. _flavor_default = "Marlin"
  19. _flavor_keyword = ";FLAVOR:"
  20. _flavor_readers_dict = {"RepRap" : RepRapFlavorParser.RepRapFlavorParser(),
  21. "Marlin" : MarlinFlavorParser.MarlinFlavorParser()}
  22. def __init__(self) -> None:
  23. super().__init__()
  24. MimeTypeDatabase.addMimeType(
  25. MimeType(
  26. name = "application/x-cura-gcode-file",
  27. comment = "Cura G-code File",
  28. suffixes = ["gcode"]
  29. )
  30. )
  31. self._supported_extensions = [".gcode", ".g"]
  32. self._flavor_reader = None # type: Optional[FlavorParser]
  33. Application.getInstance().getPreferences().addPreference("gcodereader/show_caution", True)
  34. def preReadFromStream(self, stream, *args, **kwargs):
  35. for line in stream.split("\n"):
  36. if line[:len(self._flavor_keyword)] == self._flavor_keyword:
  37. try:
  38. self._flavor_reader = self._flavor_readers_dict[line[len(self._flavor_keyword):].rstrip()]
  39. return FileReader.PreReadResult.accepted
  40. except:
  41. # If there is no entry in the dictionary for this flavor, just skip and select the by-default flavor
  42. break
  43. # If no flavor is found in the GCode, then we use the by-default
  44. self._flavor_reader = self._flavor_readers_dict[self._flavor_default]
  45. return FileReader.PreReadResult.accepted
  46. # PreRead is used to get the correct flavor. If not, Marlin is set by default
  47. def preRead(self, file_name, *args, **kwargs):
  48. with open(file_name, "r", encoding = "utf-8") as file:
  49. file_data = file.read()
  50. return self.preReadFromStream(file_data, args, kwargs)
  51. def readFromStream(self, stream: str, filename: str) -> Optional["CuraSceneNode"]:
  52. if self._flavor_reader is None:
  53. return None
  54. return self._flavor_reader.processGCodeStream(stream, filename)
  55. def _read(self, file_name: str) -> Union["SceneNode", List["SceneNode"]]:
  56. with open(file_name, "r", encoding = "utf-8") as file:
  57. file_data = file.read()
  58. result = [] # type: List[SceneNode]
  59. node = self.readFromStream(file_data, file_name)
  60. if node is not None:
  61. result.append(node)
  62. return result