PrusaSlicer icon indicating copy to clipboard operation
PrusaSlicer copied to clipboard

Feature Request: add mks-preview encoding for g-code thumbnails

Open Alexx40in opened this issue 4 years ago • 8 comments

Thumbnails embedded in g-code are not displayed on printers with Marlin firmware and interface from MKS or SHUI due to the fact that Prusa Slicer uses PNG format to compress them. If it was possible to choose the mks-preview image coding method, then the problem would be solved.

Alexx40in avatar Sep 01 '21 07:09 Alexx40in

Script for converting prusa-preview to mks-preview:

import os
import struct
from sys import argv
import re
from PIL import Image
import base64
from io import BytesIO

data=None

file_in="/home/shubin/Downloads/Telegram Desktop/Doc_merged_idea_PLA_0.2mm_14h4m.gcode"
file_out="/home/shubin/Downloads/Telegram Desktop/Doc_merged_idea_PLA_0.2mm_14h4m_shui.gcode"

with open(file_in, "r") as g_gile:
    data=g_gile.readlines()
    g_gile.close()

thumbs=[]
current_thumb=None
meta={}

def check_key(data, key, value_key):
    if (data.startswith(key)):
        meta[value_key]=d[len(key):].strip()
        return True
    return False

index=0
for d in data:
    index+=1
    if current_thumb==None:
        if (d.startswith("; thumbnail begin")):
            current_thumb = {"base64":""}
            current_thumb["start_row"] = index - 1
            thumbs.append(current_thumb)
            continue
        if check_key(d, "; filament used [mm] = ", "filament used"):
            continue
        if check_key(d, "; estimated printing time (normal mode) = ", "printing time"):
            continue
        if check_key(d, "; layer_height = ", "layer_height"):
            continue
    if (d.startswith("; thumbnail end")) and (current_thumb!=None):
        current_thumb["end_row"] = index - 1
        current_thumb=None
        continue
    if current_thumb!=None:
        str=d.strip()[2:]
        current_thumb["base64"]+=str


large_preview=None
small_preview=None

for t in thumbs:
    stream=BytesIO(base64.b64decode(t["base64"]))
    image=Image.open(stream).convert("RGB")
    stream.close()
    if (image.height==image.width):
        if image.height==200:
            large_preview=image
        if (image.height==100) or (image.height==50):
            small_preview=image

def generate_preview(preview):
    size=preview.width
    res=""
    index=0
    row = bytearray()
    for d in preview.getdata():
        r=d[0]>>3
        g=d[1]>>2
        b=d[2]>>3
        rgb = (r << 11) | (g << 5) | b
        row.append((rgb >> 8) & 0xFF)
        row.append(rgb & 0xFF)
        index+=1
        if (index==size):
            index=0;
            res += ";" + base64.b64encode(row).decode('utf-8') + "\n"
            row = bytearray()
    return res

def dummy_filter(idx):
    return True

def thumb_filter(idx):
    for t in thumbs:
        if (t["start_row"]<=idx) and (t["end_row"]>=idx):
            return False
    return True

with open(file_out, "w") as out_gile:
    filter_proc=dummy_filter
    if (large_preview!=None) and (small_preview!=None):
        filter_proc=thumb_filter
        out_gile.write(";SHUI PREVIEW {}x{}\n".format(small_preview.width, small_preview.width))
        out_gile.write(generate_preview(small_preview))
        out_gile.write(generate_preview(large_preview))
        out_gile.write(";POSTPROCESSING SHUI PRUSHA PLUGIN\r\n")
        if meta["filament used"]!=None:
            f_used=float(meta["filament used"])
            out_gile.write(";Filament used: {:1.5f}\r\n".format(f_used/1000))
        if meta["layer_height"]!=None:
            layer_height=float(meta["layer_height"])
            out_gile.write(";Layer height: {:1.2f}\r\n".format(layer_height))
        if meta["printing time"]!=None:
            match = re.match('((\d+)h\s)((\d+)m\s)((\d+)s\s*)?', meta["printing time"])
            time=0
            if (match[6]!=None):
                time+=int(match[6])
            if (match[4]!=None):
                time+=int(match[4])*60
            if (match[2]!=None):
                time+=int(match[4])*60*60
            out_gile.write(";TIME:{}\r\n".format(time))
    index=0
    for d in data:
        if filter_proc(index):
            out_gile.write(d)
        index+=1

Alexx40in avatar Sep 01 '21 08:09 Alexx40in

Examples: https://github.com/vyacheslav-shubin/shui/tree/master/misc/preview-test

Alexx40in avatar Sep 01 '21 08:09 Alexx40in

image

Alexx40in avatar Sep 01 '21 08:09 Alexx40in

I am leaving the issue open flagged with "volunteer needed', but a pull request will only be accepted if enough of interest will be voiced by others.

bubnikv avatar Oct 23 '21 17:10 bubnikv

@RandoMan70 You may be interested to implement the MKS thumbnail format for PrusaSlicer 2.5 now that we have a framework for other thumbnail formats in place, see https://github.com/prusa3d/PrusaSlicer/commit/87cff55856ae14096cd57f8e2542f1f1caef7167

bubnikv avatar Feb 02 '22 16:02 bubnikv

Support for this feature is needed

LLHCrack avatar Nov 15 '22 03:11 LLHCrack

Please add this feature

bland74 avatar Jan 11 '23 20:01 bland74

add my vote for this feature

daviddegliame avatar Aug 23 '25 15:08 daviddegliame