Просмотр исходного кода

Make a snapshot on slice instead of write.

In some cases, UFP-writing is going to be done when the OpenGL-context is off the main window. This doesn't work. That unfortunately also goes for this commit, but it's a work in progress.
Remco Burema 4 лет назад
Родитель
Сommit
4fc0612806
2 измененных файлов с 45 добавлено и 34 удалено
  1. 22 2
      plugins/CuraEngineBackend/CuraEngineBackend.py
  2. 23 32
      plugins/UFPWriter/UFPWriter.py

+ 22 - 2
plugins/CuraEngineBackend/CuraEngineBackend.py

@@ -1,4 +1,4 @@
-# Copyright (c) 2018 Ultimaker B.V.
+# Copyright (c) 2021 Ultimaker B.V.
 # Cura is released under the terms of the LGPLv3 or higher.
 
 import argparse #To run the engine in debug mode if the front-end is in debug mode.
@@ -9,6 +9,8 @@ import sys
 from time import time
 from typing import Any, cast, Dict, List, Optional, Set, TYPE_CHECKING
 
+from PyQt5.QtGui import QImage
+
 from UM.Backend.Backend import Backend, BackendState
 from UM.Scene.SceneNode import SceneNode
 from UM.Signal import Signal
@@ -24,6 +26,8 @@ from UM.Tool import Tool #For typing.
 
 from cura.CuraApplication import CuraApplication
 from cura.Settings.ExtruderManager import ExtruderManager
+from cura.Snapshot import Snapshot
+from cura.Utils.Threading import call_on_qt_thread
 from .ProcessSlicedLayersJob import ProcessSlicedLayersJob
 from .StartSliceJob import StartSliceJob, StartJobResult
 
@@ -153,6 +157,8 @@ class CuraEngineBackend(QObject, Backend):
         self.determineAutoSlicing()
         application.getPreferences().preferenceChanged.connect(self._onPreferencesChanged)
 
+        self._snapshot = None #type: Optional[QImage]
+
         application.initializationFinished.connect(self.initialize)
 
     def initialize(self) -> None:
@@ -241,9 +247,24 @@ class CuraEngineBackend(QObject, Backend):
         self.markSliceAll()
         self.slice()
 
+    @call_on_qt_thread  # must be called from the main thread because of OpenGL
+    def _createSnapshot(self) -> None:
+        self._snapshot = None
+        Logger.log("i", "Creating thumbnail image (just before slice)...")
+        try:
+            self._snapshot = Snapshot.snapshot(width = 300, height = 300)
+        except:
+            Logger.logException("w", "Failed to create snapshot image")
+            self._snapshot = None  # Failing to create thumbnail should not fail creation of UFP
+
+    def getLatestSnapShot(self) -> Optional[QImage]:
+        return self._snapshot
+
     def slice(self) -> None:
         """Perform a slice of the scene."""
 
+        self._createSnapshot()
+
         Logger.log("i", "Starting to slice...")
         self._slice_start_time = time()
         if not self._build_plates_to_be_sliced:
@@ -331,7 +352,6 @@ class CuraEngineBackend(QObject, Backend):
 
     def _onStartSliceCompleted(self, job: StartSliceJob) -> None:
         """Event handler to call when the job to initiate the slicing process is
-
         completed.
 
         When the start slice job is successfully completed, it will be happily

+ 23 - 32
plugins/UFPWriter/UFPWriter.py

@@ -7,19 +7,20 @@ from Charon.VirtualFile import VirtualFile  # To open UFP files.
 from Charon.OpenMode import OpenMode  # To indicate that we want to write to UFP files.
 from io import StringIO  # For converting g-code to bytes.
 
+from PyQt5.QtCore import QBuffer
+
 from UM.Logger import Logger
 from UM.Mesh.MeshWriter import MeshWriter  # The writer we need to implement.
 from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType
 from UM.PluginRegistry import PluginRegistry  # To get the g-code writer.
-from PyQt5.QtCore import QBuffer
 
 from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
 from UM.Scene.SceneNode import SceneNode
 from cura.CuraApplication import CuraApplication
-from cura.Snapshot import Snapshot
 from cura.Utils.Threading import call_on_qt_thread
 
 from UM.i18n import i18nCatalog
+from plugins.CuraEngineBackend.CuraEngineBackend import CuraEngineBackend
 
 METADATA_OBJECTS_PATH = "metadata/objects"
 
@@ -38,17 +39,6 @@ class UFPWriter(MeshWriter):
             )
         )
 
-        self._snapshot = None
-
-    def _createSnapshot(self, *args):
-        # must be called from the main thread because of OpenGL
-        Logger.log("d", "Creating thumbnail image...")
-        try:
-            self._snapshot = Snapshot.snapshot(width = 300, height = 300)
-        except Exception:
-            Logger.logException("w", "Failed to create snapshot image")
-            self._snapshot = None  # Failing to create thumbnail should not fail creation of UFP
-
     # This needs to be called on the main thread (Qt thread) because the serialization of material containers can
     # trigger loading other containers. Because those loaded containers are QtObjects, they must be created on the
     # Qt thread. The File read/write operations right now are executed on separated threads because they are scheduled
@@ -72,25 +62,26 @@ class UFPWriter(MeshWriter):
         gcode.write(gcode_textio.getvalue().encode("UTF-8"))
         archive.addRelation(virtual_path = "/3D/model.gcode", relation_type = "http://schemas.ultimaker.org/package/2018/relationships/gcode")
 
-        # TODO temporarily commented out, as is causes a crash whenever the UFPWriter is called outside of the main thread
-        # self._createSnapshot()
-        #
-        # # Store the thumbnail.
-        # if self._snapshot:
-        #     archive.addContentType(extension = "png", mime_type = "image/png")
-        #     thumbnail = archive.getStream("/Metadata/thumbnail.png")
-        #
-        #     thumbnail_buffer = QBuffer()
-        #     thumbnail_buffer.open(QBuffer.ReadWrite)
-        #     thumbnail_image = self._snapshot
-        #     thumbnail_image.save(thumbnail_buffer, "PNG")
-        #
-        #     thumbnail.write(thumbnail_buffer.data())
-        #     archive.addRelation(virtual_path = "/Metadata/thumbnail.png",
-        #                         relation_type = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail",
-        #                         origin = "/3D/model.gcode")
-        # else:
-        #     Logger.log("d", "Thumbnail not created, cannot save it")
+        snapshot = None
+        backend = CuraApplication.getInstance().getBackend()
+        if isinstance(backend, CuraEngineBackend):
+            snapshot = backend.getLatestSnapshot()
+
+        # Store the thumbnail.
+        if snapshot:
+            archive.addContentType(extension = "png", mime_type = "image/png")
+            thumbnail = archive.getStream("/Metadata/thumbnail.png")
+
+            thumbnail_buffer = QBuffer()
+            thumbnail_buffer.open(QBuffer.ReadWrite)
+            snapshot.save(thumbnail_buffer, "PNG")
+
+            thumbnail.write(thumbnail_buffer.data())
+            archive.addRelation(virtual_path = "/Metadata/thumbnail.png",
+                                relation_type = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail",
+                                origin = "/3D/model.gcode")
+        else:
+            Logger.log("w", "Thumbnail not created, cannot save it")
 
         # Store the material.
         application = CuraApplication.getInstance()