#!/usr/bin/env python3 # ------------------------------------------------------------------------------ # Orca / Prusa / Super Slicer post-processor script for the Professional Firmware # URL: https://github.com/mriscoc/Ender3V2S1 # Miguel A. Risco-Castillo # version: 2.2 # date: 2023/12/10 # # Contains code from the jpg re-encoder thumbnail post processor script: # github.com/alexqzd/Marlin/blob/Gcode-preview/Display%20firmware/gcode_thumb_to_jpg.py # ------------------------------------------------------------------------------ """ Copy and paste this into "Machine start G-code" in Printer Settings (see Orca-PrinterSettings-StartScript.png) ; ; First layer print x min = [first_layer_print_min_0] ; First layer print y min = [first_layer_print_min_1] ; First layer print x max = [first_layer_print_max_0] ; First layer print y max = [first_layer_print_max_1] ; Total layer count = [total_layer_count] ; """ import sys import re import os import base64 import io import subprocess try: from PIL import Image except ImportError: subprocess.check_call([sys.executable, "-m", "pip", "install", "Pillow"]) from PIL import Image def install(package): subprocess.check_call([sys.executable, "-m", "pip", "install", package]) # Get the g-code source file name SOURCE_FILE = sys.argv[1] # Read the ENTIRE g-code file into memory with open(SOURCE_FILE, "r") as f: lines = f.read() thumb_expresion = "; thumbnail begin.*?\n((.|\n)*?); thumbnail end" size_expresion = "; thumbnail begin [0-9]+x[0-9]+ [0-9]+" size_expresion_group = "; thumbnail begin [0-9]+x[0-9]+ ([0-9]+)" thumb_matches = re.findall(thumb_expresion, lines) size_matches = re.findall(size_expresion, lines) def encodedStringToGcodeComment(encodedString): n = 78 return ("; " + "\n; ".join(encodedString[i : i + n] for i in range(0, len(encodedString), n)) + "\n") for idx, match in enumerate(thumb_matches): original = match[0] encoded = original.replace("; ", "") encoded = encoded.replace("\n", "") encoded = encoded.replace("\r", "") decoded = base64.b64decode(encoded) img_png = Image.open(io.BytesIO(decoded)) img_png_rgb = img_png.convert("RGB") img_byte_arr = io.BytesIO() img_png_rgb.save(img_byte_arr, format="jpeg") img_byte_arr = img_byte_arr.getvalue() encodedjpg = base64.b64encode(img_byte_arr).decode("utf-8") encodedjpg_gcode = encodedStringToGcodeComment(encodedjpg) lines = lines.replace(original, encodedjpg_gcode) size_match = size_matches[idx] size = re.findall(size_expresion_group, size_match) new_size = size_match.replace(size[0], str(len(encodedjpg))) lines = lines.replace(size_match, new_size) # If the thumbnail was already a JPG, reformat block start lines = lines.replace("thumbnail_JPG", "thumbnail") # Prepare header values ph = re.search("; generated by (.*)\n", lines) if ph is not None: lines = lines.replace(ph[0], "") time = 0 match = re.search(r'; estimated printing time \(normal mode\) = (.*)\n', lines) if match is not None: h = re.search(r'(\d+)h', match[1]) h = int(h[1]) if h is not None else 0 m = re.search(r'(\d+)m', match[1]) m = int(m[1]) if m is not None else 0 s = re.search(r'(\d+)s', match[1]) s = int(s[1]) if s is not None else 0 time = h * 3600 + m * 60 + s match = re.search(r'; filament used \[mm\] = ([0-9.]+)', lines) filament = float(match[1]) / 1000 if match is not None else 0 match = os.getenv("SLIC3R_LAYER_HEIGHT") layer = float(match) if match is not None else 0 match = re.search("; First layer print x min = ([0-9.]+)", lines) minx = float(match[1]) if match is not None else 0 match = re.search("; First layer print y min = ([0-9.]+)", lines) miny = float(match[1]) if match is not None else 0 match = re.search("; First layer print x max = ([0-9.]+)", lines) maxx = float(match[1]) if match is not None else 0 match = re.search("; First layer print y max = ([0-9.]+)", lines) maxy = float(match[1]) if match is not None else 0 match = re.search("; Total layer count = ([0-9.]+)", lines) totlc = float(match[1]) if match is not None else 0 maxz = layer * totlc minz = 0 # Generate output file try: with open(SOURCE_FILE, "w+") as of: # Write header values if ph is not None: of.write(ph[0]) of.write(";FLAVOR:Marlin\n") of.write(";TIME:{:d}\n".format(time)) of.write(";Filament used: {:.6f}\n".format(filament)) of.write(";Layer height: {:.2f}\n".format(layer)) of.write(";MINX:{:.3f}\n".format(minx)) of.write(";MINY:{:.3f}\n".format(miny)) of.write(";MINZ:{:.3f}\n".format(minz)) of.write(";MAXX:{:.3f}\n".format(maxx)) of.write(";MAXY:{:.3f}\n".format(maxy)) of.write(";MAXZ:{:.3f}\n".format(maxz)) of.write(";POSTPROCESSED\n") of.write(";Header generated for the MRiscoCProUI Firmware\n") of.write(";https://github.com/classicrocker883/MRiscoCProU\n") of.write(lines) except: print("Error writing output file") input() finally: of.close() f.close()