Skip to content

Commit

Permalink
[MWP-366] feat: support model preview for Elegoo Neptune and Artiller…
Browse files Browse the repository at this point in the history
…y Sidewinder series (#391)

Updated the list of printers in the preview settings:
- Artillery Sidewinder X3 (must support any other version of Sidewinder)
- Elegoo Neptune3+ (any versions of Neptune3)
- Elegoo Neptune2 | NeptureX (previous versions of Neptune)

Added support for custom encoders:
- ColPic encoder, which was used in Elegoo and Artillery (with corrected variable naming)
  • Loading branch information
Jeredian authored Jan 27, 2024
1 parent 2e46e1c commit 59bde01
Show file tree
Hide file tree
Showing 6 changed files with 402 additions and 31 deletions.
1 change: 1 addition & 0 deletions Constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
SCREENSHOT_INDEX = "mks_screenshot_index"
SIMAGE = "mks_simage"
GIMAGE = "mks_gimage"
IS_PREVIEW_ENCODED = "mks_is_preview_encoded"

# Errors
EXCEPTION_MESSAGE = "An exception occurred in network connection: %s"
121 changes: 96 additions & 25 deletions MKSPreview.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
# Copyright (c) 2021
# MKS Plugin is released under the terms of the AGPLv3 or higher.
from array import array
from UM.Application import Application
from cura.Snapshot import Snapshot
from PyQt6 import QtCore
from UM.Logger import Logger


from . import Constants
from .encoders import ColPicEncoder

def add_leading_zeros(rgb):
str_hex = "%x" % rgb
Expand All @@ -18,19 +21,21 @@ def add_leading_zeros(rgb):
str_hex = '000' + str_hex[0:1]
return str_hex

def add_screenshot_str(img, width, height, img_type):
result = ""
b_image = img.scaled(width, height, QtCore.Qt.AspectRatioMode.KeepAspectRatio)
img_size = b_image.size()
result += img_type
def convert_to_rgb(image, height_pixel, width_pixel):
pixel_color = image.pixelColor(width_pixel, height_pixel)
r = pixel_color.red() >> 3
g = pixel_color.green() >> 2
b = pixel_color.blue() >> 3
rgb = (r << 11) | (g << 5) | b
return rgb


def default_encode(scaled_image, img_type, img_size):
result = img_type
datasize = 0
for i in range(img_size.height()):
for j in range(img_size.width()):
pixel_color = b_image.pixelColor(j, i)
r = pixel_color.red() >> 3
g = pixel_color.green() >> 2
b = pixel_color.blue() >> 3
rgb = (r << 11) | (g << 5) | b
rgb = convert_to_rgb(scaled_image, i, j)
str_hex = add_leading_zeros(rgb)
if str_hex[2:4] != '':
result += str_hex[2:4]
Expand All @@ -40,15 +45,91 @@ def add_screenshot_str(img, width, height, img_type):
datasize += 2
if datasize >= 50:
datasize = 0
# if i != img_size.height() - 1:
result += '\rM10086 ;'
if i == img_size.height() - 1:
result += "\r"
return result

def custom_encode(scaled_image, img_type, img_size):
result = ""
color16 = array('H')
for i in range(img_size.height()):
for j in range(img_size.width()):
rgb = convert_to_rgb(scaled_image, i, j)
color16.append(rgb)
max_size = img_size.height()*img_size.width()*10
output_data = bytearray(max_size)
resultInt = ColPicEncoder.ColPic_EncodeStr(
color16,
img_size.height(),
img_size.width(),
output_data,
max_size,
1024
)
# legacy code, don't try to understand
# in short - add img_type and new lines where its needed
data_without_zeros = str(output_data).replace('\\x00', '')
data = data_without_zeros[2:len(data_without_zeros) - 2]
each_line_max = 1024 - 8 - 1
max_lines = int(len(data)/each_line_max)
length_to_append = each_line_max - 3 - int(len(data)%each_line_max)+10
j = 0
for i in range(len(output_data)):
if (output_data[i] != 0):
if j == max_lines*each_line_max:
result += '\r;' + img_type + chr(output_data[i])
elif j == 0:
result += img_type + chr(output_data[i])
elif j%each_line_max == 0:
result += '\r' + img_type + chr(output_data[i])
else:
result += chr(output_data[i])
j += 1
result += '\r;'
# add zeros to the end
for m in range(length_to_append):
result += '0'
return result


def add_screenshot_str(img, width, height, img_type, encoded):
result = ""
scaled_image = img.scaled(width, height, QtCore.Qt.AspectRatioMode.KeepAspectRatio)
img_size = scaled_image.size()
try:
if encoded:
result = custom_encode(scaled_image, img_type, img_size)
else:
result = default_encode(scaled_image, img_type, img_size)
except Exception as e:
Logger.log("d", "Unable to encode screenshot: " + str(e))
return result

def take_screenshot():
cut_image = Snapshot.snapshot(width = 900, height = 900)
return cut_image
# param width: width of the aspect ratio default 300
# param height: height of the aspect ratio default 300
# return: None when there is no model on the build plate otherwise it will return an image
return Snapshot.snapshot(width = 900, height = 900)

def generate_preview(global_container_stack, image):
screenshot_string = ""
meta_data = global_container_stack.getMetaData()
Logger.log("d", "Get current preview settings.")
encoded = False
if Constants.IS_PREVIEW_ENCODED in meta_data:
encoded = True
if Constants.SIMAGE in meta_data:
simage = int(global_container_stack.getMetaDataEntry(Constants.SIMAGE))
Logger.log("d", "mks_simage value: " + str(simage))
screenshot_string += add_screenshot_str(image, simage, simage, ";simage:",encoded)
if Constants.GIMAGE in meta_data:
gimage = int(global_container_stack.getMetaDataEntry(Constants.GIMAGE))
Logger.log("d", "mks_gimage value: " + str(gimage))
# ;; - needed for correct colors. do not remove them.
screenshot_string += add_screenshot_str(image, gimage, gimage, ";;gimage:",encoded)
screenshot_string += "\r"
return simage,gimage,screenshot_string

def add_preview(self):
application = Application.getInstance()
Expand All @@ -75,18 +156,7 @@ def add_preview(self):
gimage = 0

if image:
meta_data = global_container_stack.getMetaData()
Logger.log("d", "Get current preview settings.")
if Constants.SIMAGE in meta_data:
simage = int(global_container_stack.getMetaDataEntry(Constants.SIMAGE))
Logger.log("d", "mks_simage value: " + str(simage))
screenshot_string += add_screenshot_str(image, simage, simage, ";simage:")
if Constants.GIMAGE in meta_data:
gimage = int(global_container_stack.getMetaDataEntry(Constants.GIMAGE))
Logger.log("d", "mks_gimage value: " + str(gimage))
# ;; - needed for correct colors. do not remove them.
screenshot_string += add_screenshot_str(image, gimage, gimage, ";;gimage:")
screenshot_string += "\r"
simage, gimage, screenshot_string = generate_preview(global_container_stack, image)
else:
Logger.log("d", "Skipping adding screenshot")
return
Expand All @@ -112,3 +182,4 @@ def add_preview(self):

if dict_changed:
setattr(scene, "gcode_dict", gcode_dict)

25 changes: 24 additions & 1 deletion MachineConfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ def pluginDisable(self):
global_container_stack.removeMetaDataEntry(Constants.SIMAGE)
global_container_stack.setMetaDataEntry(Constants.GIMAGE, None)
global_container_stack.removeMetaDataEntry(Constants.GIMAGE)
global_container_stack.setMetaDataEntry(Constants.IS_PREVIEW_ENCODED, None)
global_container_stack.removeMetaDataEntry(Constants.IS_PREVIEW_ENCODED)
global_container_stack.setMetaDataEntry(Constants.CURRENT_IP, None)
global_container_stack.removeMetaDataEntry(Constants.CURRENT_IP)
global_container_stack.setMetaDataEntry(Constants.IP_LIST, None)
Expand Down Expand Up @@ -276,6 +278,26 @@ def supportScreenshot(self):
return True
return False

@pyqtSlot(result=bool)
def isPreviewEncoded(self):
global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack:
meta_data = global_container_stack.getMetaData()
if Constants.IS_PREVIEW_ENCODED in meta_data:
return True
return False

@pyqtSlot(str)
def setPreviewEncodeSettings(self, is_preview_encoded):
global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack:
Logger.log("d", "Is preview encoded: "+ str(is_preview_encoded))
if is_preview_encoded == "true":
global_container_stack.setMetaDataEntry(Constants.IS_PREVIEW_ENCODED, is_preview_encoded)
else:
global_container_stack.setMetaDataEntry(Constants.IS_PREVIEW_ENCODED, None)
global_container_stack.removeMetaDataEntry(Constants.IS_PREVIEW_ENCODED)

@pyqtSlot(result="QVariantList")
def getScreenshotOptions(self):
Logger.log("d", "Trying to get screenshot options")
Expand All @@ -290,13 +312,14 @@ def getScreenshotOptions(self):
@pyqtSlot(str, result="QVariant")
def getScreenshotSettings(self, label):
Logger.log("d", "Get screenshot settings for: "+ label)
result = {"simage": "", "gimage": ''}
result = {"simage": "", "gimage": '', "encoded": False}
options = sorted(self.screenshot_info, key=lambda k: k['index'])
for option in options:
value = option["label"]
if value == label:
result["simage"] = option["simage"]
result["gimage"] = option["gimage"]
result["encoded"] = option["encoded"]
return result

@pyqtSlot(str)
Expand Down
13 changes: 8 additions & 5 deletions config/screenshot.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
[
{ "index": 1, "label": "Default", "simage": "100", "gimage": "200" },
{ "index": 2, "label": "FLSUN QQ-S", "simage": "", "gimage": "" },
{ "index": 3, "label": "Flying Bear Ghost 4S/5", "simage": "50", "gimage": "200" },
{ "index": 4, "label": "Two Trees Sapphire", "simage": "100", "gimage": "200" },
{ "index": 5, "label": "Wanhao D12", "simage": "100", "gimage": "200" }
{ "index": 1, "label": "Default", "simage": "100", "gimage": "200", "encoded": false },
{ "index": 2, "label": "FLSUN QQ-S", "simage": "", "gimage": "" , "encoded": false },
{ "index": 3, "label": "Flying Bear Ghost 4S/5", "simage": "50", "gimage": "200", "encoded": false },
{ "index": 4, "label": "Two Trees Sapphire", "simage": "100", "gimage": "200" , "encoded": false },
{ "index": 5, "label": "Wanhao D12", "simage": "100", "gimage": "200" , "encoded": false },
{ "index": 6, "label": "Artillery Sidewinder X3", "simage": "85", "gimage": "230", "mimage": "170", "encoded": true },
{ "index": 7, "label": "Elegoo Neptune2 | NeptureX", "simage": "100", "gimage": "200", "encoded": true },
{ "index": 8, "label": "Elegoo Neptune3+", "simage": "160", "gimage": "200", "encoded": true }
]
Loading

0 comments on commit 59bde01

Please sign in to comment.