@ghylander Thanks for the pointers. I had a stab at it last night by trying to read as much as I could from your PrusaSlicer code, comparing it to the Creality Slicer gcode then applying that to the Cura script. It seems like I’ve got it to work.
The main headache was working out how to extract the required data from Cura & format it correctly. I ended up having to use some different calcs & syntax.
# Cura Ender-3 S1 Pro Thumbnail Generator
#
# Based on: https://github.com/KenHuffman/UltimakerCuraScripts for the Ender-3 V2 Neo
# Created by: Ken Huffman (huffmancoding@gmail.com)
# Modified by: PartySausage for the Ender-3 S1 Pro to display Thumbnail & Print Data
import base64
from UM.Logger import Logger
from cura.Snapshot import Snapshot
from PyQt6.QtCore import QByteArray, QIODevice, QBuffer
from ..Script import Script
from UM.Application import Application
from UM.Qt.Duration import DurationFormat
class CreateEnder3S1ProThumbnailV2(Script):
def __init__(self):
super().__init__()
def _createSnapshot(self, width, height):
Logger.log("d", "Creating thumbnail image...")
try:
return Snapshot.snapshot(width, height)
except Exception:
Logger.logException("w", "Failed to create snapshot image")
def _encodeSnapshot(self, snapshot):
Logger.log("d", "Encoding thumbnail image...")
try:
thumbnail_buffer = QBuffer()
thumbnail_buffer.open(QBuffer.OpenModeFlag.ReadWrite)
thumbnail_image = snapshot
thumbnail_image.save(thumbnail_buffer, "JPG")
thumbnail_data = thumbnail_buffer.data()
thumbnail_length = thumbnail_data.length()
base64_bytes = base64.b64encode(thumbnail_data)
base64_message = base64_bytes.decode('ascii')
thumbnail_buffer.close()
Logger.log("d", "Snapshot thumbnail_length={}".format(thumbnail_length))
return (base64_message, thumbnail_length)
except Exception:
Logger.logException("w", "Failed to encode snapshot image")
def _convertSnapshotToGcode(self, data, thumbnail_length, encoded_snapshot, width, height, chunk_size=76):
Logger.log("d", "Converting snapshot into gcode...")
gcode = []
# these numbers appear to be related to image size, guessing here
x1 = (int)(width/80) + 1
x2 = width - x1
header = "; jpg begin {}*{} {} {} {} {}".format(
width, height, thumbnail_length, x1, x2, 500)
Logger.log("d", "Gcode header={}".format(header))
gcode.append(header)
chunks = ["; {}".format(encoded_snapshot[i:i+chunk_size])
for i in range(0, len(encoded_snapshot), chunk_size)]
gcode.extend(chunks)
gcode.append("; jpg end")
gcode.append(";")
gcode.append("")
# Generate Print Data
gcode.append(";FLAVOR:Marlin")
# Retrieve Print Time 'H:M:S'
TIME_HMS = str(Application.getInstance().getPrintInformation().currentPrintTime.getDisplayString(DurationFormat.Format.ISO8601))
# Format Print Time 'S'
TIME_S = float(float(TIME_HMS.split(":")[0]) * 3600 + float(TIME_HMS.split(":")[1]) * 60 + float(TIME_HMS.split(":",2)[2]))
gcode.append(";TIME:" + str(TIME_S))
mycura = Application.getInstance().getGlobalContainerStack()
# Retrieve Filament Length (m)
filament_amt = Application.getInstance().getPrintInformation().materialLengths
gcode.append(";Filament used:" + str(filament_amt[0]))
# Retrieve Filament Layer Height (mm)
gcode.append(";Layer height:" + str(mycura.getProperty("layer_height", "value")))
# Retrieve No. of Layers)
layer_count_string = ""
for layer in data:
layer_index = data.index(layer)
lines = layer.split("\n")
for line in lines:
if line.startswith(";LAYER_COUNT:"):
layer_count_string = line
# Retrieve & Calculate Print Dimensions (mm)
# Only MINZ & MAXZ used for Ender 3 S1 Pro 'Number of Layers' Print Data Calculations
# The reset is used to format the gcode correctly
minx = 0
miny = 0
minz = mycura.getProperty("layer_height", "value")
maxx = 0
maxy = 0
maxz = float(layer_count_string.split(":",1)[1]) * minz
gcode.append(";MINX:" + "{:.3f}".format(minx))
gcode.append(";MINY:" + "{:.3f}".format(miny))
gcode.append(";MINZ:" + "{:.3f}".format(minz))
gcode.append(";MAXX:" + "{:.3f}".format(maxx))
gcode.append(";MAXY:" + "{:.3f}".format(maxy))
gcode.append(";MAXZ:" + "{:.3f}".format(maxz))
# Footer
gcode.append("")
gcode.append(";---------------- End of Ender 3 S1 Pro Thumbnail & Print Data ---------------")
gcode.append("")
return gcode
def getSettingDataString(self):
return """{
"name": "Create Ender-3 S1 Pro Thumbnail V2",
"key": "CreateEnder3S1ProThumbnailV2",
"metadata": {},
"version": 2,
"settings":
{
"width":
{
"label": "Width",
"description": "Width of the generated thumbnail",
"unit": "px",
"type": "int",
"default_value": 300,
"minimum_value": "0",
"minimum_value_warning": "12",
"maximum_value_warning": "800"
},
"height":
{
"label": "Height",
"description": "Height of the generated thumbnail",
"unit": "px",
"type": "int",
"default_value": 300,
"minimum_value": "0",
"minimum_value_warning": "12",
"maximum_value_warning": "600"
}
}
}"""
def execute(self, data):
width = self.getSettingValueByKey("width")
height = self.getSettingValueByKey("height")
Logger.log("d", "CreateEnder3S1ProThumbnailV2 Plugin start with width={}, height={}...".format(width, height))
snapshot = self._createSnapshot(width, height)
if snapshot:
Logger.log("d", "Snapshot created")
(encoded_snapshot, thumbnail_length) = self._encodeSnapshot(snapshot)
snapshot_gcode = self._convertSnapshotToGcode(
data, thumbnail_length, encoded_snapshot, width, height)
Logger.log("d", "Layer count={}".format(len(data)))
if len(data) > 0:
# The Ender-3 S1 Pro really wants this at the top of the file
layer_index = 0
lines = data[layer_index].split("\n")
Logger.log("d", "Adding snapshot gcode lines (len={}) before '{}'".format(len(snapshot_gcode), lines[0]))
lines[0:0] = snapshot_gcode
final_lines = "\n".join(lines)
data[layer_index] = final_lines
Logger.log("d", "CreateEnder3S1ProThumbnailV2 Plugin end")
return data