Skip to content

Commit

Permalink
Merge pull request #43 from prusa3d/read-metadata-python
Browse files Browse the repository at this point in the history
Python library can read metadata from bgcode files
  • Loading branch information
fiksupojka authored Dec 19, 2023
2 parents 02d005c + 38831e5 commit 7aaf717
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 8 deletions.
2 changes: 1 addition & 1 deletion pybgcode/pybgcode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ PYBIND11_MODULE(MODULE_NAME, m) {
py::enum_<core::EBlockType>(m, "EBlockType")
.value("FileMetadata", core::EBlockType::FileMetadata)
.value("GCode", core::EBlockType::GCode)
.value("SlicerMetadata,", core::EBlockType::SlicerMetadata)
.value("SlicerMetadata", core::EBlockType::SlicerMetadata)
.value("PrinterMetadata", core::EBlockType::PrinterMetadata)
.value("PrintMetadata", core::EBlockType::PrintMetadata)
.value("Thumbnail", core::EBlockType::Thumbnail);
Expand Down
70 changes: 63 additions & 7 deletions pybgcode/pybgcode/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Prusa Block & Binary G-code reader / writer / converter"""
# pylint: disable=redefined-builtin
from typing import Type, Union
from ._bgcode import ( # type: ignore
BlockHeader,
CompressionType,
Expand All @@ -8,6 +9,10 @@
EThumbnailFormat,
FileHeader,
FILEWrapper,
PrintMetadataBlock,
PrinterMetadataBlock,
SlicerMetadataBlock,
FileMetadataBlock,
ThumbnailBlock,
close,
from_ascii_to_binary,
Expand All @@ -31,6 +36,9 @@
"EResult",
"EThumbnailFormat",
"FileHeader",
"FileMetadataBlock",
"PrintMetadataBlock",
"PrinterMetadataBlock",
"ThumbnailBlock",
"close",
"from_ascii_to_binary",
Expand All @@ -51,30 +59,78 @@ def __init__(self, res: EResult):
super().__init__(translate_result(res))


def read_thumbnails(gcodefile: FILEWrapper):
"""Read thumbnails from binary gcode file."""
def get_header(gcodefile: FILEWrapper):
assert is_open(gcodefile)
rewind(gcodefile)

header = FileHeader()
res = read_header(gcodefile, header)
if res != EResult.Success:
raise ResultError(res)
return res, header

def get_block_header(gcodefile: FILEWrapper, header: FileHeader,
block_type: int):
block = BlockHeader()
res = read_next_block_header(gcodefile, header, block, block_type)
if res != EResult.Success:
return None
return block

def get_metadata(gcodefile: FILEWrapper, header: FileHeader,
block_header: BlockHeader,
metadata_block_class: Union[Type[PrinterMetadataBlock],
Type[PrintMetadataBlock],
Type[FileMetadataBlock]]):
metadata_block = metadata_block_class()
res = metadata_block.read_data(gcodefile, header, block_header)
if res != EResult.Success:
raise ResultError(res)
return dict(metadata_block.raw_data) if metadata_block else metadata_block

def read_thumbnails(gcodefile: FILEWrapper):
"""Read thumbnails from binary gcode file."""
res, header = get_header(gcodefile)
thumbnails = []

while res == EResult.Success:
res = read_next_block_header(gcodefile, header, block,
EBlockType.Thumbnail)
if res != EResult.Success:
block_header = get_block_header(gcodefile, header,
EBlockType.Thumbnail)
if not block_header:
break

thumbnail_block = ThumbnailBlock()
res = thumbnail_block.read_data(gcodefile, header, block)
res = thumbnail_block.read_data(gcodefile, header, block_header)
if res != EResult.Success:
raise ResultError(res)

thumbnails.append({"meta": thumbnail_block.params,
"bytes": thumbnail_block.data()})

return thumbnails

def read_metadata(gcodefile: FILEWrapper, type: str = 'printer'):
"""Read metadata from binary gcode file.
Possible variants for metadata type are 'file', 'print', 'printer'
and 'slicer' with 'printer' as a default."""

_, header = get_header(gcodefile)

if type == 'file':
block_type = EBlockType.FileMetadata
metadata_block_class = FileMetadataBlock
elif type == 'print':
block_type = EBlockType.PrintMetadata
metadata_block_class = PrintMetadataBlock
elif type == 'slicer':
block_type = EBlockType.SlicerMetadata
metadata_block_class = SlicerMetadataBlock
else:
block_type = EBlockType.PrinterMetadata
metadata_block_class = PrinterMetadataBlock

block_header = get_block_header(gcodefile, header, block_type)
if not block_header:
return None

return get_metadata(gcodefile, header, block_header, metadata_block_class)

29 changes: 29 additions & 0 deletions pybgcode/tests/test_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
EResult,
EThumbnailFormat,
read_thumbnails,
read_metadata
)

# pylint: disable=missing-function-docstring
Expand All @@ -16,6 +17,26 @@
TEST_BGCODE = "test.bgcode"
TEST_THUMBNAILS = 2

TEST_PRINTER_METADATA = {'printer_model': 'MINI', 'filament_type': 'PETG',
'nozzle_diameter': '0.4', 'bed_temperature': '90',
'brim_width': '0', 'fill_density': '15%',
'layer_height': '0.15', 'temperature': '240',
'ironing': '0', 'support_material': '0',
'max_layer_z': '18.05', 'extruder_colour': '""',
'filament used [mm]': '986.61',
'filament used [cm3]': '2.37',
'filament used [g]': '3.01', 'filament cost': '0.08',
'estimated printing time (normal mode)': '32m 6s'}
TEST_FILE_METADATA = {'Producer': 'PrusaSlicer 2.6.0'}
TEST_PRINT_METADATA = {
'filament used [mm]': '986.61', 'filament used [cm3]': '2.37',
'filament used [g]': '3.01', 'filament cost': '0.08',
'total filament used [g]': '3.01', 'total filament cost': '0.08',
'estimated printing time (normal mode)': '32m 6s',
'estimated first layer printing time (normal mode)': '1m 8s'}
TEST_LEN_SLICER_METADATA = 302



def get_thumbnail_extension(format_id):
ret = "unknown"
Expand Down Expand Up @@ -53,6 +74,14 @@ def test_main():
thumb_f = pybgcode.open(TEST_BGCODE, "rb")
thumbnails = read_thumbnails(thumb_f)
assert len(thumbnails) == TEST_THUMBNAILS
printer_metadata = read_metadata(thumb_f)
assert printer_metadata == TEST_PRINTER_METADATA
file_metadata = read_metadata(thumb_f, 'file')
assert file_metadata == TEST_FILE_METADATA
print_metadata = read_metadata(thumb_f, 'print')
assert print_metadata == TEST_PRINT_METADATA
slicer_metadata = read_metadata(thumb_f, 'slicer')
assert len(slicer_metadata) == TEST_LEN_SLICER_METADATA
pybgcode.close(thumb_f)

# write thumbnails to png files
Expand Down

0 comments on commit 7aaf717

Please sign in to comment.