ThreeMFWorkspaceWriter.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. from UM.Workspace.WorkspaceWriter import WorkspaceWriter
  2. from UM.Application import Application
  3. from UM.Preferences import Preferences
  4. from UM.Settings.ContainerRegistry import ContainerRegistry
  5. from UM.Settings.ContainerStack import ContainerStack
  6. from cura.Settings.ExtruderManager import ExtruderManager
  7. import zipfile
  8. from io import StringIO
  9. import copy
  10. import configparser
  11. class ThreeMFWorkspaceWriter(WorkspaceWriter):
  12. def __init__(self):
  13. super().__init__()
  14. def write(self, stream, nodes, mode=WorkspaceWriter.OutputMode.BinaryMode):
  15. mesh_writer = Application.getInstance().getMeshFileHandler().getWriter("3MFWriter")
  16. if not mesh_writer: # We need to have the 3mf mesh writer, otherwise we can't save the entire workspace
  17. return False
  18. # Indicate that the 3mf mesh writer should not close the archive just yet (we still need to add stuff to it).
  19. mesh_writer.setStoreArchive(True)
  20. mesh_writer.write(stream, nodes, mode)
  21. archive = mesh_writer.getArchive()
  22. if archive is None: # This happens if there was no mesh data to write.
  23. archive = zipfile.ZipFile(stream, "w", compression = zipfile.ZIP_DEFLATED)
  24. global_container_stack = Application.getInstance().getGlobalContainerStack()
  25. # Add global container stack data to the archive.
  26. self._writeContainerToArchive(global_container_stack, archive)
  27. # Also write all containers in the stack to the file
  28. for container in global_container_stack.getContainers():
  29. self._writeContainerToArchive(container, archive)
  30. # Check if the machine has extruders and save all that data as well.
  31. for extruder_stack in ExtruderManager.getInstance().getMachineExtruders(global_container_stack.getId()):
  32. self._writeContainerToArchive(extruder_stack, archive)
  33. for container in extruder_stack.getContainers():
  34. self._writeContainerToArchive(container, archive)
  35. # Write preferences to archive
  36. preferences_file = zipfile.ZipInfo("Cura/preferences.cfg")
  37. preferences_string = StringIO()
  38. Preferences.getInstance().writeToFile(preferences_string)
  39. archive.writestr(preferences_file, preferences_string.getvalue())
  40. # Save Cura version
  41. version_file = zipfile.ZipInfo("Cura/version.ini")
  42. version_config_parser = configparser.ConfigParser()
  43. version_config_parser.add_section("versions")
  44. version_config_parser.set("versions", "cura_version", Application.getStaticVersion())
  45. version_file_string = StringIO()
  46. version_config_parser.write(version_file_string)
  47. archive.writestr(version_file, version_file_string.getvalue())
  48. # Close the archive & reset states.
  49. archive.close()
  50. mesh_writer.setStoreArchive(False)
  51. return True
  52. ## Helper function that writes ContainerStacks, InstanceContainers and DefinitionContainers to the archive.
  53. # \param container That follows the \type{ContainerInterface} to archive.
  54. # \param archive The archive to write to.
  55. @staticmethod
  56. def _writeContainerToArchive(container, archive):
  57. if type(container) == type(ContainerRegistry.getInstance().getEmptyInstanceContainer()):
  58. return # Empty file, do nothing.
  59. file_suffix = ContainerRegistry.getMimeTypeForContainer(type(container)).preferredSuffix
  60. # Some containers have a base file, which should then be the file to use.
  61. if "base_file" in container.getMetaData():
  62. base_file = container.getMetaDataEntry("base_file")
  63. container = ContainerRegistry.getInstance().findContainers(id = base_file)[0]
  64. file_name = "Cura/%s.%s" % (container.getId(), file_suffix)
  65. if file_name in archive.namelist():
  66. return # File was already saved, no need to do it again. Uranium guarantees unique ID's, so this should hold.
  67. file_in_archive = zipfile.ZipInfo(file_name)
  68. # For some reason we have to set the compress type of each file as well (it doesn't keep the type of the entire archive)
  69. file_in_archive.compress_type = zipfile.ZIP_DEFLATED
  70. if type(container) == ContainerStack and (container.getMetaDataEntry("network_authentication_id") or container.getMetaDataEntry("network_authentication_key")):
  71. # TODO: Hack
  72. # Create a shallow copy of the container, so we can filter out the network auth (if any)
  73. container_copy = copy.deepcopy(container)
  74. container_copy.removeMetaDataEntry("network_authentication_id")
  75. container_copy.removeMetaDataEntry("network_authentication_key")
  76. serialized_data = container_copy.serialize()
  77. else:
  78. serialized_data = container.serialize()
  79. archive.writestr(file_in_archive, serialized_data)