libbgcode.NET 0.2.0

dotnet add package libbgcode.NET --version 0.2.0
                    
NuGet\Install-Package libbgcode.NET -Version 0.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="libbgcode.NET" Version="0.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="libbgcode.NET" Version="0.2.0" />
                    
Directory.Packages.props
<PackageReference Include="libbgcode.NET" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add libbgcode.NET --version 0.2.0
                    
#r "nuget: libbgcode.NET, 0.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package libbgcode.NET@0.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=libbgcode.NET&version=0.2.0
                    
Install as a Cake Addin
#tool nuget:?package=libbgcode.NET&version=0.2.0
                    
Install as a Cake Tool

libbgcode.NET

CI

A .NET reader and writer for Prusa's binary G-code (bgcode) container format: the file header, lazy block enumeration, per-block compression (deflate, heatshrink), MeatPack G-code encoding and decoding, and CRC-32 checksums.

Implemented from the format's published specification. The facts the specification does not state — that deflate payloads are zlib-wrapped, that the CRC-32 covers each block from its header through its data, the reconstruction rules MeatPack's lossy packing demands of a decoder, and the JSON metadata encoding PrusaSlicer 3 adds (it writes its slicer metadata twice, a legacy INI block and a JSON block) — are established from real PrusaSlicer output and pinned by interop tests against pybgcode, Prusa's own binding of the reference implementation, at the exact commit PrusaSlicer 3.0.0-alpha11 pins.

The library targets net10.0 and depends on HeatshrinkDotNet for the heatshrink blocks.

Untrusted input

The reader is written for files anybody may have uploaded. Every size on the wire is treated as attacker-influenced: nothing is allocated from a declared size without a caller-configurable bound, a payload must decompress to exactly its declared size, and the block walk refuses a file whose offsets cannot be trusted. A malformed file yields null from whichever call discovered it, never an exception — a contract held in place by a seeded mutation test and a coverage-guided fuzzing harness (libbgcode.NET.Fuzz).

Usage

using libbgcode.NET;

using FileStream file = File.OpenRead("model.bgcode");

BgcodeReader? reader = BgcodeReader.Open(file);

if (reader is null)
{
    // Not a readable binary G-code file. Note that the name decides nothing:
    // PrusaSlicer routinely writes binary G-code to files called .gcode, so
    // dispatch on BgcodeReader.Magic, never on the extension.
    return;
}

while (reader.NextBlock() is { } block)
{
    switch (block.Type)
    {
        case BgcodeBlockType.PrinterMetadata:
            // "printer_model=COREONE\nnozzle_diameter=0.4\n..." - INI, one pair per line.
            string? ini = reader.ReadText(block);
            break;

        case BgcodeBlockType.Thumbnail:
            // block.Thumbnail carries format and pixel size; ReadData returns the image bytes.
            byte[]? image = reader.ReadData(block);
            break;

        case BgcodeBlockType.GCode:
            // Decompressed and MeatPack-decoded to plain G-code text.
            string? gcode = reader.ReadText(block);
            break;
    }
}

Blocks are descriptors: NextBlock() reads headers only and seeks past payloads, so walking to the one block you want costs a few small reads regardless of file size. The specification orders blocks (file metadata, printer metadata, thumbnails, print metadata, slicer metadata, G-code), so a reader after early metadata can stop at the first later type.

BgcodeReaderOptions bounds what a payload may cost (MaxDataBytes, default 64 MiB) and turns on per-block CRC-32 verification (VerifyChecksum, off by default).

Writing

using FileStream file = File.Create("model.bgcode");
using BgcodeWriter writer = new(file);          // CRC-32 trailers by default

writer.WritePrinterMetadata("printer_model=COREONE\nnozzle_diameter=0.4\n");
writer.WriteThumbnail(new BgcodeThumbnailParameters(BgcodeThumbnailFormat.Png, 16, 16), pngBytes);
writer.WritePrintMetadata("estimated printing time (normal mode)=34s\n");
writer.WriteSlicerMetadata("layer_height=0.2\n");
writer.WriteGCode(gcodeText);                   // MeatPack with comments, heatshrink 12/4 - the slicers' defaults

The writer enforces the specification's block order and the reference reader's mandatory chain (printer, print and slicer metadata before any G-code), so it cannot produce a file the reference implementation refuses; a call out of order throws before it writes. G-code is cut into blocks at 64 KiB of source on line boundaries, each with fresh MeatPack state, exactly as the reference binarizer cuts it. Every compression and encoding the format allows is available per block; the defaults are what PrusaSlicer writes.

MeatPack lives in its own package, MeatPack.NET, developed in this repository — MeatPackDecoder.Unpack and MeatPackEncoder.Pack work on payloads from anywhere, serial hosts included; libbgcode.NET depends on it for the G-code blocks.

Converting whole files

BgcodeConverter.ToAscii and BgcodeConverter.ToBinary convert between the container and the ASCII G-code PrusaSlicer writes: the producer line, the head of ; key = value comments a printer reads from the first kilobytes, thumbnail sections, print statistics, and the config section (plus PrusaSlicer 3's JSON one). Which comment keys the printer and print metadata blocks gather was learned by observing the reference implementation's behaviour, not by reading its code; both directions are cross-checked against pybgcode.

Two small apps wrap them: bin2gcode <in.bgcode> [out.gcode] and gcode2bin <in.gcode> [out.bgcode] [--drop-comments] [--plain] [--no-compression] [--no-checksum].

What this is not

It does not parse the G-code itself — it hands you the text.

Licenses

  • libbgcode.NET and MeatPack.NET are licensed under the Mozilla Public License 2.0.
  • The MeatPack scheme is Scott Mudge's (BSD-3-Clause, LICENSE.meatpack); the decoder here is an independent implementation of the documented scheme, including the reconstruction behaviour the bgcode variant expects.
  • The binary G-code format and its specification are Prusa's; this library is an independent implementation of that published format and shares no code with libbgcode.
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.0 203 9/5/2026
0.1.0 98 9/1/2026