Post-processing scripts explained

Hello, I really tried to find some real documentation on this topic, but couldn’t!
Is there some real world mini example how this feature works, what kind of code (python?) one can put into this field and when it is applied and so on?

I just recently began to print with wood PLA and would like to take advantage of eg. these kind of post-processing (GitHub - mbodenham/woodgrain-filament: Program to create woodgrain effect when using wood PLA filament on Creality 3D Ender-3.). Would that be possible using this Bambu Studio input field?

I am also interested to learn more about this and will be following the thread.

In the meantime, there are some other ways to achieve woodgrain effects available/explained on MakerWorld.
Here are two very different approaches:
Add Wood Grain Effects to Your Models - Using a Small Plate as an Example by PandaN MakerWorld: Download Free 3D Models
How to print Wood by NPeter MakerWorld: Download Free 3D Models

I looked at this feature three years ago when I first got into the Bambu ecosystem. I checked again and it doesn’t look like this topic has advanced at all either in the Orca GitHub community or elsewhere.

Here’s what my research points to:

  1. This appears to be vestigial Slic3r-era functionality inherited by modern slicers such as PrusaSlicer and Cura.

  2. Everything suggests it only runs when the file is sliced. The slicer calls an external routine with the G-Code filename as an argument. Here’s how I tested it. It executed the BAT file at the click of the slice plate action but I couldn’t backtrack what happened after that. I couldn’t find the file it operated on. It’s probably staring me in the face but I couldn’t find it.

If you’re looking for documentation. The closest I came to was this old manual. It is very sparse but gives Slic3r examples.

https://manual.slic3r.org/advanced/post-processing

Sorry, I mixed two questions here. The question about the post-processing script and my motivation for it, the wood look.

Thanks for the links to the approaches for wood imitation. The second link changes the 3D shape and creates spatial contours, while the first link seems to be more like the approach described at gcode_postprocessors/wood/Woodgrain_Cura.py at master · MoonCactus/gcode_postprocessors · GitHub, where different nozzle temperature leads to different colors of the wood PLA. Thanks for the links. I need to look into the topic in more detail.

That’s very interesting. I hadn’t realized that BambuStudio (Software Bambu Studio | Bambu Lab US) is based on open source software and is itself open source (GitHub - bambulab/BambuStudio: PC Software for BambuLab and other 3D printers).

I’ll definitely give it a try now that you’ve shared links to sample scripts. Let’s see how and if it works. It looks like the script simply gets the GCODE on stdin and returns the modified GCODE on stdout. Something like that, right?

I believe that is correct. The paramters that I saw posted elsewhere - can’t find the link at the moment - looked something like this ( this is from memory so don’t hold me to it):

"C:\Path\To\Python\python.exe" "C:\Path\To\myscript.py" "{input_file}" "{output_file}"

What I was never able to prove is that there was in fact an output file that was sent to the printer. But in all candor, I didn’t test it that far. I guess one simple test would be to create a simple primitive like a cube, save that to a G-Coded file on the local system. Then generate a cylinder primitive, slice it, then create a simple script which calls that file as the output. If one gets the cylinder, then one knows it didn’t work, if a cube is output, then there is the proof. I may try this at some point.

So with your help and the links to Slic3r I was able to come up with some basic shell script as a test case.

#!/bin/sh
echo "file: $*" > /Users/matths/pps/output.log
env | grep ^SLIC3R >> /Users/matths/pps/output.log
cp $* /Users/matths/pps/gcode2.txt # save sphere gcode
cp /Users/matths/pps/gcode.txt $* # replace with cube gcode

I loaded a sphere object, added the path to this script in post-processing scripts field.

Then I did hit the slice button. The preview then still shows a slices sphere, but when I download the result using the ‘export sliced file’ button, it was the cube gcode and not the sphere. So my script did work. I did not send it to the printer yet.

So a script just needs to overwrite the file. Sounds easy. I’ll check tomorrow with printing.

I was also able to log a lot of SLIC3R prefixed environment variables from within the script that might be useful, maybe.

Thanks for sharing this data. It is very helpful. Let us know how the print turns out and anything you may learn. This really helps the community.

It may also help my motivation to try out some calibration ideas I’ve had for a while but really have been just too lazy to fight HAL. :yum:

I’ve tried post-processing scripts to disable bed heating 5 minutes before print ends, so that i could grab part instantly after printing. Gemini was very helpful at explaining and writing script.

If you are interested, here’s how I did it:

  1. install python from official python website (or microsoft store on Windows).
  2. When it asks while installing:
We can add the directory (C:\Users\YourName\AppData\Local\Python\bin) to PATH now,

but you will need to restart your terminal to use it. The entry will be removed

if you run py uninstall --purge, or else you can remove it manually when

uninstalling Python.

Add commands directory to your PATH now? [y/N]

write ‘y’ and press enter. Then I restarted PC, not sure if i had to.

  1. open cmd in windows and write “where python”. This will be first filepath you will need for bambu studio eg. “C:\Users\YourName\AppData\Local\Python\bin\python.exe”.

  2. create your script file wherever you want and save it with .py extension. Absolute path to this file will be second filepath you will need for bambustudio eg. “C:\Users\YourName\Documents\myScript.py”.

  3. Now you need to enter into bambu studio Process / others / Post-processing script and copy both paths with semicolons and space between them like this:
    "C:\Users\YourName\AppData\Local\Python\bin\python.exe" "C:\Users\YourName\Documents\myScript.py";

Now this script should run on every slicing, remember to put something in myScript.py file :slight_smile:

My script for turning off bed 5 minutes before end looks like this (open myScript.py with notepad or any differect text-editor and put it inside):

import sys
import re
import os
import datetime

# --- CONFIGURATION ---
MINUTES_BEFORE_END = 5
MIN_PROGRESS_PERCENT = 10  # % - prevents turning off the bed at startup/calibration
# ---------------------

def log_debug(message):
    # Saves logs to 'debug_log.txt' in the same folder as this script
    log_path = os.path.join(os.path.dirname(sys.argv[0]), "debug_log.txt")
    with open(log_path, "a") as log:
        log.write(f"[{datetime.datetime.now()}] {message}\n")

try:
    # Check if the Slicer provided the G-code file path
    if len(sys.argv) < 2:
        sys.exit(1)

    source_file = sys.argv[1]
    
    with open(source_file, "r") as f:
        lines = f.readlines()

    output_lines = []
    bed_turned_off = False
    
    # Regex to find: M73 P(progress) R(minutes_remaining)
    # Example: M73 P15 R4 (15% progress, 4 minutes left)
    pattern = re.compile(r"M73 P(\d+) R(\d+)")

    for line in lines:
        if not bed_turned_off:
            match = pattern.search(line)
            if match:
                progress = int(match.group(1))
                minutes_left = int(match.group(2))
                
                # CONDITION: Less than X minutes left AND progress > Y% (to ignore header/start)
                if minutes_left <= MINUTES_BEFORE_END and progress > MIN_PROGRESS_PERCENT:
                    log_debug(f"Trigger found: {minutes_left} min remaining at {progress}% progress.")
                    
                    output_lines.append(f"; --- AUTO COOL DOWN (script: {minutes_left} min left / {progress}% done) ---\n")
                    output_lines.append("M140 S0 ; Turn off bed heating\n")
                    output_lines.append("; -------------------------------\n")
                    
                    bed_turned_off = True
        
        output_lines.append(line)

    # Overwrite the original G-code file
    with open(source_file, "w") as f:
        f.writelines(output_lines)

except Exception as e:
    log_debug(f"CRITICAL ERROR: {str(e)}")
    sys.exit(1)

When succesful, new file “debug_log.txt” should be created in your script directory after slicing, you can see inside if there was any error.

Just reviving this thread. I created a routine that in my custom filament profiles end gcode for engineering grade filaments. The routine was for a slow bed cool down after the print had finished to help minimise warping, and a 5 minute 100% exhaust fan at the end to clear the chamber of noxious fumes. It works but my OCD didn’t like the fact that the progress bar didn’t update until the end of the routine. With a bit of help from ChatGPT I wrote a Python script that is invoked when slicing the model that calculates the progress as the bed cools down and displays it (M73 P R). It writes this to the sliced gcode.

Welcome to the community. Since this is your first post, there is an important point of forum etiquette worth mentioning.

This is a community-driven forum. Bambu’s participation here is minimal, so most of the value comes from members helping other members by sharing what they have learned, built, tested, and discovered.

As you can see from this thread, another member shared their work so that others could benefit from it. That is the whole point of a technical community like this: share and share alike.

Simply posting that you wrote your own Python script, without sharing the script or enough information for anyone else to reproduce what you did, doesn’t really contribute anything to the discussion. To be candid, it comes across more as bragging than contributing.

If you post the code, explain how it works, or provide enough detail for other members to implement the same solution, that becomes a useful contribution to the community.

But simply saying, in effect, “Yeah, I did that too,” without sharing the work doesn’t help your fellow 3D-printing enthusiasts. It just adds noise to the board.

The value here comes from sharing the solution, not merely announcing that you have one.

Thanks. It wasn’t my intention to “brag” and as I was just browsing through on my phone I wasn’t able to share my script, which is on my PC. I am more than happy to share and will do this when I am back home and have access to my PC.