Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ jobs:
path: ${{github.workspace}}/build/dist/lib/wasm/

build-msvc:
runs-on: windows-2019
runs-on: windows-2022

strategy:
matrix:
Expand Down
53 changes: 53 additions & 0 deletions example/bginfo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env python3
import pybgcode as bg

def dump_info(fn):
fp = bg.open(fn, 'r')
file_header = bg.FileHeader()
file_header.read(fp)

block_header = bg.BlockHeader()


res = bg.read_next_block_header(fp, file_header, block_header)
TYPES = dict(enumerate([
'FileMetadata',
'GCode',
'SlicerMetadata',
'PrinterMetadata',
'PrintMetadata',
'Thumbnail'
]))
while res == bg.EResult.Success:
print(f'Block type: {TYPES.get(block_header.type, block_header.type)} size {block_header.compressed_size} / {block_header.uncompressed_size}')
cls = None
if block_header.type == bg.EBlockType.FileMetadata.value:
cls = bg.FileMetadataBlock
elif block_header.type == bg.EBlockType.PrinterMetadata.value:
cls = bg.PrinterMetadataBlock
elif block_header.type == bg.EBlockType.PrintMetadata.value:
cls = bg.PrintMetadataBlock
# elif block_header.type == bg.EBlockType.Thumbnail.value:
# cls = bg.ThumbnailBlock
elif block_header.type == bg.EBlockType.SlicerMetadata.value:
tp = bg.peek_slicer_metadata_block(fp, block_header)
if tp == bg.EPeekSlicerMetadataResult.SlicerMetadataFound:
cls = bg.SlicerMetadataBlock
elif tp == bg.EPeekSlicerMetadataResult.Slicer3MetadataFound:
cls = bg.Slicer3MetadataBlock
if cls is not None:
metadata = cls()
metadata.read_data(fp, file_header, block_header)
for k, v in metadata.raw_data:
w = v if len(v) < 120 else f'... ({len(v)} bytes)'
print(f' {k}: {w}')
else:
bg.skip_block_content(fp, file_header, block_header)
res = bg.read_next_block_header(fp, file_header, block_header)



if __name__ == '__main__':
import sys
for fn in sys.argv[1:]:
dump_info(fn)
21 changes: 21 additions & 0 deletions pybgcode/pybgcode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,26 @@ PYBIND11_MODULE(MODULE_NAME, m) {
return self.read_data(*file.fptr, file_header, block_header);
}, R"pbdoc(read block data)pbdoc", py::arg("file"), py::arg("file_header"), py::arg("block_header"));

py::class_<binarize::Slicer3MetadataBlock, binarize::BaseMetadataBlock>(m, "Slicer3MetadataBlock")
.def(py::init<>())
.def("write", [](binarize::Slicer3MetadataBlock &self, FILEWrapper &file, core::ECompressionType compression_type, core::EChecksumType checksum_type){
return self.write(*file.fptr, compression_type, checksum_type);
}, R"pbdoc(write block header and data)pbdoc", py::arg("file"), py::arg("compression_type"), py::arg("checksum_type"))
.def("read_data", [](binarize::Slicer3MetadataBlock &self, FILEWrapper &file, const core::FileHeader &file_header, const core::BlockHeader& block_header) {
return self.read_data(*file.fptr, file_header, block_header);
}, R"pbdoc(read block data)pbdoc", py::arg("file"), py::arg("file_header"), py::arg("block_header"));

py::enum_<binarize::EPeekSlicerMetadataResult>(m, "EPeekSlicerMetadataResult")
.value("Slicer3MetadataFound", binarize::EPeekSlicerMetadataResult::Slicer3MetadataFound)
.value("SlicerMetadataFound", binarize::EPeekSlicerMetadataResult::SlicerMetadataFound)
.value("OtherBlockFound", binarize::EPeekSlicerMetadataResult::OtherBlockFound)
.value("ReadError", binarize::EPeekSlicerMetadataResult::ReadError)
;

m.def("peek_slicer_metadata_block", [](FILEWrapper& file, const core::BlockHeader& block_header) {
return binarize::peek_slicer_metadata_block(*file.fptr, block_header);
});

py::class_<binarize::BinarizerConfig::Compression>(m, "BinarizerCompression")
.def(py::init<>())
.def_readwrite("file_metadata", &binarize::BinarizerConfig::Compression::file_metadata)
Expand All @@ -487,6 +507,7 @@ PYBIND11_MODULE(MODULE_NAME, m) {
.def_readwrite("printer_metadata", &binarize::BinaryData::printer_metadata)
.def_readwrite("thumbnails", &binarize::BinaryData::thumbnails)
.def_readwrite("slicer_metadata", &binarize::BinaryData::slicer_metadata)
.def_readwrite("slicer3_metadata", &binarize::BinaryData::slicer3_metadata)
.def_readwrite("printer_metadata", &binarize::BinaryData::printer_metadata);

py::class_<binarize::Binarizer>(m, "Binarizer")
Expand Down
9 changes: 9 additions & 0 deletions pybgcode/pybgcode/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
EBlockType,
EResult,
EThumbnailFormat,
EPeekSlicerMetadataResult,
FileHeader,
FILEWrapper,
PrintMetadataBlock,
PrinterMetadataBlock,
SlicerMetadataBlock,
Slicer3MetadataBlock,
FileMetadataBlock,
ThumbnailBlock,
close,
Expand All @@ -24,7 +26,10 @@
read_header,
read_next_block_header,
rewind,
skip_block,
skip_block_content,
translate_result,
peek_slicer_metadata_block,
version,
)

Expand All @@ -36,6 +41,7 @@
"EBlockType",
"EResult",
"EThumbnailFormat",
"EPeekSlicerMetadataResult",
"FileHeader",
"FileMetadataBlock",
"PrintMetadataBlock",
Expand All @@ -47,9 +53,12 @@
"get_config",
"is_open",
"open",
"peek_slicer_metadata_block",
"read_header",
"read_next_block_header",
"rewind",
"skip_block",
"skip_block_content",
"translate_result"]


Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "pybgcode"
version = "0.2.0"
version = "0.3.0"
description = "Prusa Block & Binary G-code reader / writer / converter"
authors = [
{ name = "Enrico Turri" }, { name = "Tomas Meszaros" }
Expand Down
130 changes: 114 additions & 16 deletions src/LibBGCode/binarize/binarize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,25 +49,34 @@ static std::vector<uint8_t> encode(const std::byte* data, size_t data_size)
return ret;
}

static uint16_t metadata_encoding_types_count() { return 1 + (uint16_t)EMetadataEncodingType::INI; }
static uint16_t metadata_encoding_types_count() { return 1 + (uint16_t)EMetadataEncodingType::JSON; }
static uint16_t thumbnail_formats_count() { return 1 + (uint16_t)EThumbnailFormat::QOI; }
static uint16_t gcode_encoding_types_count() { return 1 + (uint16_t)EGCodeEncodingType::MeatPackComments; }

static bool encode_metadata(const std::vector<std::pair<std::string, std::string>>& src, std::vector<uint8_t>& dst,
EMetadataEncodingType encoding_type)
{
for (const auto& [key, value] : src) {
switch (encoding_type)
{
case EMetadataEncodingType::INI:
{

switch (encoding_type)
{
case EMetadataEncodingType::INI:
{
for (const auto& [key, value] : src) {
dst.insert(dst.end(), key.begin(), key.end());
dst.emplace_back('=');
dst.insert(dst.end(), value.begin(), value.end());
dst.emplace_back('\n');
break;
}
}
break;
}
case EMetadataEncodingType::JSON:
{
if (src.size() != 1)
return false;
const auto& [k, v] = src.at(0);
dst.insert(dst.end(), v.begin(), v.end());
break;
}
}
return true;
}
Expand All @@ -88,12 +97,19 @@ static bool decode_metadata(const std::vector<uint8_t>& src, std::vector<std::pa
const std::string item(begin_it, end_it);
const size_t pos = item.find_first_of('=');
if (pos != std::string::npos) {
dst.emplace_back(std::make_pair(item.substr(0, pos), item.substr(pos + 1)));
dst.emplace_back(item.substr(0, pos), item.substr(pos + 1));
begin_it = ++end_it;
}
}
break;
}
case EMetadataEncodingType::JSON:
{
std::string v;
v.insert(v.end(), src.begin(), src.end());
dst.emplace_back("", v);
break;
}
}

return true;
Expand Down Expand Up @@ -784,6 +800,76 @@ EResult SlicerMetadataBlock::read_data(FILE& file, const FileHeader& file_header
return EResult::Success;
}

void Slicer3MetadataBlock::set_json(std::string_view json)
{
if (raw_data.empty())
raw_data.emplace_back("", json);
else
raw_data.front().second = json;
}

const std::string& Slicer3MetadataBlock::json() const
{
if (raw_data.empty()) {
static std::string EMPTY;
return EMPTY;
}
return raw_data.front().second;
}


EResult Slicer3MetadataBlock::write(FILE& file, ECompressionType compression_type, EChecksumType checksum_type) const
{
Checksum cs(checksum_type);

// write block header, payload
EResult res = binarize::write(*this, file, EBlockType::SlicerMetadata, compression_type, cs);
if (res != EResult::Success)
// propagate error
return res;

// write block checksum
if (checksum_type != EChecksumType::None)
return cs.write(file);

return EResult::Success;
}

EResult Slicer3MetadataBlock::read_data(FILE& file, const FileHeader& file_header, const BlockHeader& block_header)
{
// read block payload
EResult res = BaseMetadataBlock::read_data(file, block_header);
if (res != EResult::Success)
// propagate error
return res;

const EChecksumType checksum_type = (EChecksumType)file_header.checksum_type;
if (checksum_type != EChecksumType::None) {
// read block checksum
Checksum cs(checksum_type);
res = cs.read(file);
if (res != EResult::Success)
// propagate error
return res;
}
return EResult::Success;
}

EPeekSlicerMetadataResult peek_slicer_metadata_block(FILE& file, const core::BlockHeader& block_header)
{
if (EBlockType{block_header.type} != EBlockType::SlicerMetadata)
return EPeekSlicerMetadataResult::OtherBlockFound;
decltype(Slicer3MetadataBlock::encoding_type) encoding_type;
auto pos = ftell(&file);
if (pos < 0)
return EPeekSlicerMetadataResult::ReadError;
if (!read_from_file(file, (void*)&encoding_type, sizeof(encoding_type)))
return EPeekSlicerMetadataResult::ReadError;
// rewind back the file like we didn't read it
fseek(&file, pos, SEEK_SET);
return EMetadataEncodingType{encoding_type} == EMetadataEncodingType::JSON ? EPeekSlicerMetadataResult::Slicer3MetadataFound : EPeekSlicerMetadataResult::SlicerMetadataFound;
}

bool Binarizer::is_enabled() const { return m_enabled; }
void Binarizer::set_enabled(bool enable) { m_enabled = enable; }
BinaryData& Binarizer::get_binary_data() { return m_binary_data; }
Expand Down Expand Up @@ -842,14 +928,26 @@ EResult Binarizer::initialize(FILE& file, const BinarizerConfig& config)
// propagate error
return res;

// save slicer metadata block
if (m_binary_data.slicer_metadata.raw_data.empty())
// save slicer metadata blocks
if (m_binary_data.slicer_metadata.raw_data.empty() && m_binary_data.slicer3_metadata.raw_data.empty())
return EResult::MissingSlicerMetadata;
m_binary_data.slicer_metadata.encoding_type = (uint16_t)config.metadata_encoding;
res = m_binary_data.slicer_metadata.write(*m_file, m_config.compression.slicer_metadata, m_config.checksum);
if (res != EResult::Success)
// propagate error
return res;

if (!m_binary_data.slicer_metadata.raw_data.empty()) {
m_binary_data.slicer_metadata.encoding_type = (uint16_t)config.metadata_encoding;
res = m_binary_data.slicer_metadata.write(*m_file, m_config.compression.slicer_metadata, m_config.checksum);
if (res != EResult::Success) {
// propagate error
return res;
}
}

if (!m_binary_data.slicer3_metadata.raw_data.empty()) {
res = m_binary_data.slicer3_metadata.write(*m_file, m_config.compression.slicer3_metadata, m_config.checksum);
if (res != EResult::Success) {
// propagate error
return res;
}
}

return EResult::Success;
}
Expand Down
29 changes: 29 additions & 0 deletions src/LibBGCode/binarize/binarize.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,33 @@ struct BGCODE_BINARIZE_EXPORT SlicerMetadataBlock : public BaseMetadataBlock
core::EResult read_data(FILE& file, const core::FileHeader& file_header, const core::BlockHeader& block_header);
};

struct BGCODE_BINARIZE_EXPORT Slicer3MetadataBlock : public BaseMetadataBlock
{
Slicer3MetadataBlock() : BaseMetadataBlock() {
encoding_type = static_cast<std::underlying_type_t<core::EMetadataEncodingType>>(
core::EMetadataEncodingType::JSON);
}

void set_json(std::string_view);
const std::string& json() const;

// write block header and data
core::EResult write(FILE& file, core::ECompressionType compression_type, core::EChecksumType checksum_type) const;
// read block data
core::EResult read_data(FILE& file, const core::FileHeader& file_header, const core::BlockHeader& block_header);
};

enum class EPeekSlicerMetadataResult {
Slicer3MetadataFound,
SlicerMetadataFound,
OtherBlockFound,
ReadError
};

// Peek the block content (just metadata extra "header") and decide what kind of block follows
extern BGCODE_BINARIZE_EXPORT EPeekSlicerMetadataResult peek_slicer_metadata_block(FILE& file, const core::BlockHeader& block_header);


struct BinarizerConfig
{
struct Compression
Expand All @@ -80,6 +107,7 @@ struct BinarizerConfig
core::ECompressionType print_metadata{ core::ECompressionType::None };
core::ECompressionType slicer_metadata{ core::ECompressionType::None };
core::ECompressionType gcode{ core::ECompressionType::None };
core::ECompressionType slicer3_metadata{ core::ECompressionType::None };
};
Compression compression;
core::EGCodeEncodingType gcode_encoding{ core::EGCodeEncodingType::None };
Expand All @@ -93,6 +121,7 @@ struct BGCODE_BINARIZE_EXPORT BinaryData
PrinterMetadataBlock printer_metadata;
std::vector<ThumbnailBlock> thumbnails;
SlicerMetadataBlock slicer_metadata;
Slicer3MetadataBlock slicer3_metadata;
PrintMetadataBlock print_metadata;
};

Expand Down
Loading