GcodeTools


NameGcodeTools JSON
Version 0.2.1 PyPI version JSON
download
home_pageNone
SummaryPython G-Code Tools library with complete G-Code Reader and Writer
upload_time2025-07-20 13:21:13
maintainerNone
docs_urlNone
authorNone
requires_python>=3.8
licenseNone
keywords 3d g-code gcode printing
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Python G-Code Tools library with complete* G-Code Reader and Writer

\*as per 3D-Printing needs


**This library is under development - method names, workflow and logic will differ between releases!**

**Ensure your printer software can catch illegal g-code moves, as this library has still very large amount of bugs! Also keep an eye on your print.**

# Installation

```sh
pip install GcodeTools
```

# Available G-Code Tools

| Feature                                              | Status |                            command                             |
| ---------------------------------------------------- | :----: | :------------------------------------------------------------: |
| Translate Gcode                                      |   ✅   |                `Tools.translate(gcode, Vector)`                |
| Rotate Gcode                                         |   ✅   |                  `Tools.rotate(gcode, int) `                   |
| Scale Gcode                                          |   ✅   |              `Tools.scale(gcode, Vector\|float)`               |
| subdivide Gcode                                      |   ✅   |                     `move.subdivide(step)`                     |
| Get move's flowrate                                  |   ✅   |                     `move.get_flowrate()`                      |
| Set flowrate <br> (in mm^2, use `scale` to set in %) |   ✅   |                   `move.set_flowrate(float)`                   |
| Detect Gcode features                                |   ✅   | `Tools.fill_meta(gcode)`, param `meta_provider` at gcode load  |
| Split layers                                         |   ✅   |                       `Gcode.layers[n]`                        |
| Split bodies                                         |  🔜   |                      `Tools.split(gcode)`                      |
| Insert custom Gcode                                  |   ❌   |                                                                |
| Read Thumbnails (raw PNG data)                       |   ✅   |                 `Tools.read_thumbnails(gcode)`                 |
| Write Thumbnails (raw PNG data)                      |   ✅   | `Tools.write_thumbnail(gcode, data, width, height, textwidth)` |
| Convert from/to Arc Moves                            |   ❌   |        currently auto-translation to G1 in GcodeParser         |
| Find body bounds                                     |   ✅   |                `Tools.get_bounding_box(gcode)`                 |
| Trim unused Gcode                                    |  🔜   |                      `Tools.trim(gcode)`                       |
| Offset Gcodes in time                                |   ❌   |                                                                |
| Create custom travel movement                        |   ❌   |                                                                |
| convert to firmware retraction                       |  🔜   |               `Tools.regenerate_travels(gcode)`                |


### Legend:

- ✅ Fully supported
- ❌ Not yet supported, to be implemented
- 🔜 Partially supported, to be implemented

More features soon! Feel free to open feature request


# G-Code

## Current G-Code object relation:
```
Gcode (list[Block])
│
├─ slicing config (precision, speed): Config
│
├─ single Gcode instruction: Block
│  │
│  ├─ Object handling everything move-related: Move
│  │  ├─ Position: Vector
│  │  └─ speed: float
│  │
│  ├─ Every other standard G-code: BlockData
│  ├─ Slicer-specific features (meta) (non-standarized, one may set their own custom meta provider method): dict
│  └─ Original command and if it's to be emitted: command, emit_command
└─ ...
```

In each block, every G-Code variable is contained. That means, blocks can be taken out of Gcode, rearranged, etc.

That however does not take move origin (move starting position) in count! That will be adressed in future.

`Gcode` structure and its components will be changing heavily during beta!
- Current target is to get rid of original command (work on trimmed `Gcode`) to decrease RAM usage and computation time
- Gcode is in the first tests of linked-list approach for simplification of iterating methods


# G-Code Parser

```py
from GcodeTools import Gcode

gcode = Gcode('file.gcode')
```

## Progress Callback example implementation

```py
my_tqdm = tqdm(unit="lines", desc="Reading Gcode")
update = lambda i, length: (setattr(my_tqdm, 'total', length), my_tqdm.update(1))
gcode = Gcode().from_file('file.gcode', update)
```


# Example usage

Example to move objects that have `benchy` in their name, by `translation` vector. It will also trim gcode (minify).
```py
from GcodeTools import Gcode, Tools, Vector

do_verbose = False

gcode = Gcode()
gcode.config.speed = 1200 # initial speed before first Gcode's `F` parameter

gcode.from_file('file.gcode')
out_gcode: Gcode = Tools.trim(gcode)

translation = Vector(-200, -100, 0)

for x in out_gcode:
    obj: str = x.meta.get('object') or ''
    if 'benchy' in obj.lower():
        x.move.translate(translation)

out_gcode.write_file('out.gcode', do_verbose)
```


Change tool to `T1` when printing sparse infill, otherwise change to `T0`.
For bridges set fan speed to 100%.
```py
from GcodeTools import *

gcode = Gcode('file.gcode')

for block in gcode:
    if block.meta.get('type') == MoveTypes.SPARSE_INFILL:
        block.block_data.set_tool(1)
    else:
        block.block_data.set_tool(0)
    
    if block.meta.get('type') == MoveTypes.BRIDGE:
        block.block_data.set_fan(255)

gcode.write_file('out.gcode')
```


Plot histogram of flow ratios. Useful for checking arachne settings.

```py
from GcodeTools import Gcode
import matplotlib.pyplot as plt

gcode_file = "1.gcode"

gcode = Gcode(gcode_file)

flowrates = []
for block in gcode:
    if flowrate := block.move.get_flowrate():
        flowrates.append(flowrate)

plt.figure(figsize=(12, 6))
plt.hist(flowrates, bins=100)
plt.xlabel("Flowrate (mm E / mm XYZ)")
plt.ylabel("Frequency")
plt.title(f"Flowrate Distribution for {gcode_file}")
plt.grid(axis='y', alpha=0.75)
plt.show()
plt.close()
```


# Supported Slicers

Tested with:
- Prusa Slicer `2.8.1`
- Orca Slicer `2.1.1`
- Super Slicer `2.5.59.12`
- Slic3r `1.3.0`
- Cura `5.8.1`
- Simplify3D `4.0.0`
- Bambu Studio `2.0.3.54`


|                           | Any slicer | Cura | Prusa&nbsp;Slicer | Orca&nbsp;Slicer | Slic3r | Super&nbsp;Slicer | Simplify3D | Bambu&nbsp;Studio |
| ------------------------- | :--------: | :--: | :---------------: | :--------------: | :----: | :---------------: | :--------: | :----------: |
| Reading Gcode             |     ✅     |      |                   |                  |        |                   |            |              |
| Keep track of coordinates |     ✅     |      |                   |                  |        |                   |            |              |
| Temperature control       |     ✅     |      |                   |                  |        |                   |            |              |
| Fan control               |     ✅     |      |                   |                  |        |                   |            |              |
| Spliting Objects          |     ❌     |  ✅  |        ✅1        |        ✅        |   ❌   |        ✅         |     ✅     |     ✅      |
| Extracting features       |     ❌     |  ➖  |        ✅         |        ✅        |   ❌   |        ✅        |     ✅     |      ✅      |
| Arc Moves                 |    🔜2    |      |                   |                  |        |                   |            |              |


### Legend:

1: Turn on `LABEL_OBJECTS`\
2: Arc moves currently automatically translate to G1 moves

- ✅ Fully supported
- ❌ Not supported, limited by slicer
- 🔜 To be implemented
- ➖ Partially supported, limited by slicer
            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "GcodeTools",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "3d, g-code, gcode, printing",
    "author": null,
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/74/bd/f4ffd1fc2cafccf779e97e7f505e1ecc33f2247396899649a31722b63300/gcodetools-0.2.1.tar.gz",
    "platform": null,
    "description": "# Python G-Code Tools library with complete* G-Code Reader and Writer\n\n\\*as per 3D-Printing needs\n\n\n**This library is under development - method names, workflow and logic will differ between releases!**\n\n**Ensure your printer software can catch illegal g-code moves, as this library has still very large amount of bugs! Also keep an eye on your print.**\n\n# Installation\n\n```sh\npip install GcodeTools\n```\n\n# Available G-Code Tools\n\n| Feature                                              | Status |                            command                             |\n| ---------------------------------------------------- | :----: | :------------------------------------------------------------: |\n| Translate Gcode                                      |   \u2705   |                `Tools.translate(gcode, Vector)`                |\n| Rotate Gcode                                         |   \u2705   |                  `Tools.rotate(gcode, int) `                   |\n| Scale Gcode                                          |   \u2705   |              `Tools.scale(gcode, Vector\\|float)`               |\n| subdivide Gcode                                      |   \u2705   |                     `move.subdivide(step)`                     |\n| Get move's flowrate                                  |   \u2705   |                     `move.get_flowrate()`                      |\n| Set flowrate <br> (in mm^2, use `scale` to set in %) |   \u2705   |                   `move.set_flowrate(float)`                   |\n| Detect Gcode features                                |   \u2705   | `Tools.fill_meta(gcode)`, param `meta_provider` at gcode load  |\n| Split layers                                         |   \u2705   |                       `Gcode.layers[n]`                        |\n| Split bodies                                         |  \ud83d\udd1c   |                      `Tools.split(gcode)`                      |\n| Insert custom Gcode                                  |   \u274c   |                                                                |\n| Read Thumbnails (raw PNG data)                       |   \u2705   |                 `Tools.read_thumbnails(gcode)`                 |\n| Write Thumbnails (raw PNG data)                      |   \u2705   | `Tools.write_thumbnail(gcode, data, width, height, textwidth)` |\n| Convert from/to Arc Moves                            |   \u274c   |        currently auto-translation to G1 in GcodeParser         |\n| Find body bounds                                     |   \u2705   |                `Tools.get_bounding_box(gcode)`                 |\n| Trim unused Gcode                                    |  \ud83d\udd1c   |                      `Tools.trim(gcode)`                       |\n| Offset Gcodes in time                                |   \u274c   |                                                                |\n| Create custom travel movement                        |   \u274c   |                                                                |\n| convert to firmware retraction                       |  \ud83d\udd1c   |               `Tools.regenerate_travels(gcode)`                |\n\n\n### Legend:\n\n- \u2705 Fully supported\n- \u274c Not yet supported, to be implemented\n- \ud83d\udd1c Partially supported, to be implemented\n\nMore features soon! Feel free to open feature request\n\n\n# G-Code\n\n## Current G-Code object relation:\n```\nGcode (list[Block])\n\u2502\n\u251c\u2500 slicing config (precision, speed): Config\n\u2502\n\u251c\u2500 single Gcode instruction: Block\n\u2502  \u2502\n\u2502  \u251c\u2500 Object handling everything move-related: Move\n\u2502  \u2502  \u251c\u2500 Position: Vector\n\u2502  \u2502  \u2514\u2500 speed: float\n\u2502  \u2502\n\u2502  \u251c\u2500 Every other standard G-code: BlockData\n\u2502  \u251c\u2500 Slicer-specific features (meta) (non-standarized, one may set their own custom meta provider method): dict\n\u2502  \u2514\u2500 Original command and if it's to be emitted: command, emit_command\n\u2514\u2500 ...\n```\n\nIn each block, every G-Code variable is contained. That means, blocks can be taken out of Gcode, rearranged, etc.\n\nThat however does not take move origin (move starting position) in count! That will be adressed in future.\n\n`Gcode` structure and its components will be changing heavily during beta!\n- Current target is to get rid of original command (work on trimmed `Gcode`) to decrease RAM usage and computation time\n- Gcode is in the first tests of linked-list approach for simplification of iterating methods\n\n\n# G-Code Parser\n\n```py\nfrom GcodeTools import Gcode\n\ngcode = Gcode('file.gcode')\n```\n\n## Progress Callback example implementation\n\n```py\nmy_tqdm = tqdm(unit=\"lines\", desc=\"Reading Gcode\")\nupdate = lambda i, length: (setattr(my_tqdm, 'total', length), my_tqdm.update(1))\ngcode = Gcode().from_file('file.gcode', update)\n```\n\n\n# Example usage\n\nExample to move objects that have `benchy` in their name, by `translation` vector. It will also trim gcode (minify).\n```py\nfrom GcodeTools import Gcode, Tools, Vector\n\ndo_verbose = False\n\ngcode = Gcode()\ngcode.config.speed = 1200 # initial speed before first Gcode's `F` parameter\n\ngcode.from_file('file.gcode')\nout_gcode: Gcode = Tools.trim(gcode)\n\ntranslation = Vector(-200, -100, 0)\n\nfor x in out_gcode:\n    obj: str = x.meta.get('object') or ''\n    if 'benchy' in obj.lower():\n        x.move.translate(translation)\n\nout_gcode.write_file('out.gcode', do_verbose)\n```\n\n\nChange tool to `T1` when printing sparse infill, otherwise change to `T0`.\nFor bridges set fan speed to 100%.\n```py\nfrom GcodeTools import *\n\ngcode = Gcode('file.gcode')\n\nfor block in gcode:\n    if block.meta.get('type') == MoveTypes.SPARSE_INFILL:\n        block.block_data.set_tool(1)\n    else:\n        block.block_data.set_tool(0)\n    \n    if block.meta.get('type') == MoveTypes.BRIDGE:\n        block.block_data.set_fan(255)\n\ngcode.write_file('out.gcode')\n```\n\n\nPlot histogram of flow ratios. Useful for checking arachne settings.\n\n```py\nfrom GcodeTools import Gcode\nimport matplotlib.pyplot as plt\n\ngcode_file = \"1.gcode\"\n\ngcode = Gcode(gcode_file)\n\nflowrates = []\nfor block in gcode:\n    if flowrate := block.move.get_flowrate():\n        flowrates.append(flowrate)\n\nplt.figure(figsize=(12, 6))\nplt.hist(flowrates, bins=100)\nplt.xlabel(\"Flowrate (mm E / mm XYZ)\")\nplt.ylabel(\"Frequency\")\nplt.title(f\"Flowrate Distribution for {gcode_file}\")\nplt.grid(axis='y', alpha=0.75)\nplt.show()\nplt.close()\n```\n\n\n# Supported Slicers\n\nTested with:\n- Prusa Slicer `2.8.1`\n- Orca Slicer `2.1.1`\n- Super Slicer `2.5.59.12`\n- Slic3r `1.3.0`\n- Cura `5.8.1`\n- Simplify3D `4.0.0`\n- Bambu Studio `2.0.3.54`\n\n\n|                           | Any slicer | Cura | Prusa&nbsp;Slicer | Orca&nbsp;Slicer | Slic3r | Super&nbsp;Slicer | Simplify3D | Bambu&nbsp;Studio |\n| ------------------------- | :--------: | :--: | :---------------: | :--------------: | :----: | :---------------: | :--------: | :----------: |\n| Reading Gcode             |     \u2705     |      |                   |                  |        |                   |            |              |\n| Keep track of coordinates |     \u2705     |      |                   |                  |        |                   |            |              |\n| Temperature control       |     \u2705     |      |                   |                  |        |                   |            |              |\n| Fan control               |     \u2705     |      |                   |                  |        |                   |            |              |\n| Spliting Objects          |     \u274c     |  \u2705  |        \u27051        |        \u2705        |   \u274c   |        \u2705         |     \u2705     |     \u2705      |\n| Extracting features       |     \u274c     |  \u2796  |        \u2705         |        \u2705        |   \u274c   |        \u2705        |     \u2705     |      \u2705      |\n| Arc Moves                 |    \ud83d\udd1c2    |      |                   |                  |        |                   |            |              |\n\n\n### Legend:\n\n1: Turn on `LABEL_OBJECTS`\\\n2: Arc moves currently automatically translate to G1 moves\n\n- \u2705 Fully supported\n- \u274c Not supported, limited by slicer\n- \ud83d\udd1c To be implemented\n- \u2796 Partially supported, limited by slicer",
    "bugtrack_url": null,
    "license": null,
    "summary": "Python G-Code Tools library with complete G-Code Reader and Writer",
    "version": "0.2.1",
    "project_urls": {
        "Homepage": "https://github.com/matszwe02/GcodeTools",
        "Issues": "https://github.com/matszwe02/GcodeTools/issues"
    },
    "split_keywords": [
        "3d",
        " g-code",
        " gcode",
        " printing"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "6ba203f8939f9fa2bfbc16ed9eb38863a6ec62fa12ccf57fe96a9b9725dc8851",
                "md5": "e037c3b1cf928162f133d00d5e290b5f",
                "sha256": "85546d6e2a55b042f22a00e88e505ad6d6fb8f63bb2d7ec73f5c219a858bdeaf"
            },
            "downloads": -1,
            "filename": "gcodetools-0.2.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "e037c3b1cf928162f133d00d5e290b5f",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 20523,
            "upload_time": "2025-07-20T13:21:12",
            "upload_time_iso_8601": "2025-07-20T13:21:12.318180Z",
            "url": "https://files.pythonhosted.org/packages/6b/a2/03f8939f9fa2bfbc16ed9eb38863a6ec62fa12ccf57fe96a9b9725dc8851/gcodetools-0.2.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "74bdf4ffd1fc2cafccf779e97e7f505e1ecc33f2247396899649a31722b63300",
                "md5": "8308867650a3965fc96b9cd678261cde",
                "sha256": "e83e941e1e2b5e94a52f592e12819c460c46afffc65572592b1ec6b837f6dc47"
            },
            "downloads": -1,
            "filename": "gcodetools-0.2.1.tar.gz",
            "has_sig": false,
            "md5_digest": "8308867650a3965fc96b9cd678261cde",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 19663,
            "upload_time": "2025-07-20T13:21:13",
            "upload_time_iso_8601": "2025-07-20T13:21:13.741601Z",
            "url": "https://files.pythonhosted.org/packages/74/bd/f4ffd1fc2cafccf779e97e7f505e1ecc33f2247396899649a31722b63300/gcodetools-0.2.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-20 13:21:13",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "matszwe02",
    "github_project": "GcodeTools",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [],
    "lcname": "gcodetools"
}
        
Elapsed time: 0.88240s