ENH: 3mf: refine the rels to correct link

JIRA: STUDIO-4231
Change-Id: I02ff6343124ef2ea3642e5799469249538a4b97f
(cherry picked from commit 781793a4c84b3e8a01f38d990d34bee9add8850a)
This commit is contained in:
lane.wei 2023-09-09 18:57:35 +08:00 committed by Lane.Wei
parent bf8afa9889
commit e76be77cfc
5 changed files with 208 additions and 44 deletions

View file

@ -3180,7 +3180,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
m_curr_object->name = bbs_get_attribute_value_string(attributes, num_attributes, NAME_ATTR);
m_curr_object->uuid = bbs_get_attribute_value_string(attributes, num_attributes, PUUID_ATTR);
if (m_curr_object->uuid.empty()) {
if (m_curr_object->uuid.empty()) {
m_curr_object->uuid = bbs_get_attribute_value_string(attributes, num_attributes, PUUID_LOWER_ATTR);
}
m_curr_object->pid = bbs_get_attribute_value_int(attributes, num_attributes, PID_ATTR);
@ -4716,8 +4716,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
current_object->name = bbs_get_attribute_value_string(attributes, num_attributes, NAME_ATTR);
current_object->uuid = bbs_get_attribute_value_string(attributes, num_attributes, PUUID_ATTR);
if (current_object->uuid.empty()) {
current_object->uuid = bbs_get_attribute_value_string(attributes, num_attributes, PUUID_LOWER_ATTR);
if (current_object->uuid.empty()) {
current_object->uuid = bbs_get_attribute_value_string(attributes, num_attributes, PUUID_LOWER_ATTR);
}
current_object->pid = bbs_get_attribute_value_int(attributes, num_attributes, PID_ATTR);
}
@ -5946,27 +5946,46 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
if (from.empty()) {
stream << " <Relationship Target=\"/" << MODEL_FILE << "\" Id=\"rel-1\" Type=\"http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel\"/>\n";
if (data._3mf_thumbnail.empty()) {
if (export_plate_idx < 0) {
stream << " <Relationship Target=\"/" << THUMBNAIL_FILE
<< "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\"/>\n";
if (export_plate_idx < 0) {
//use cover image if have
if (data._3mf_thumbnail.empty()) {
stream << " <Relationship Target=\"/Metadata/plate_1.png"
<< "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\"/>\n";
} else {
std::string thumbnail_file_str = (boost::format("Metadata/plate_%1%.png") % (export_plate_idx + 1)).str();
stream << " <Relationship Target=\"/" << xml_escape(thumbnail_file_str)
<< "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\"/>\n";
stream << " <Relationship Target=\"/" << xml_escape(data._3mf_thumbnail)
<< "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\"/>\n";
}
} else {
stream << " <Relationship Target=\"/" << xml_escape(data._3mf_thumbnail)
<< "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\"/>\n";
}
if (!data._3mf_printer_thumbnail_middle.empty()) {
stream << " <Relationship Target=\"/" << xml_escape(data._3mf_printer_thumbnail_middle)
<< "\" Id=\"rel-4\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-middle\"/>\n";
if (data._3mf_printer_thumbnail_middle.empty()) {
stream << " <Relationship Target=\"/Metadata/plate_1.png"
<< "\" Id=\"rel-4\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-middle\"/>\n";
} else {
stream << " <Relationship Target=\"/" << xml_escape(data._3mf_printer_thumbnail_middle)
<< "\" Id=\"rel-4\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-middle\"/>\n";
}
if (data._3mf_printer_thumbnail_small.empty()) {
stream << "<Relationship Target=\"/Metadata/plate_1_small.png"
<< "\" Id=\"rel-5\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-small\"/>\n";
} else {
stream << " <Relationship Target=\"/" << xml_escape(data._3mf_printer_thumbnail_small)
<< "\" Id=\"rel-5\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-small\"/>\n";
}
}
else {
//always use plate thumbnails
std::string thumbnail_file_str = (boost::format("Metadata/plate_%1%.png") % (export_plate_idx + 1)).str();
stream << " <Relationship Target=\"/" << xml_escape(thumbnail_file_str)
<< "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\"/>\n";
thumbnail_file_str = (boost::format("Metadata/plate_%1%.png") % (export_plate_idx + 1)).str();
stream << " <Relationship Target=\"/" << xml_escape(thumbnail_file_str)
<< "\" Id=\"rel-4\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-middle\"/>\n";
thumbnail_file_str = (boost::format("Metadata/plate_%1%_small.png") % (export_plate_idx + 1)).str();
stream << " <Relationship Target=\"/" << xml_escape(thumbnail_file_str)
<< "\" Id=\"rel-5\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-small\"/>\n";
}
if (!data._3mf_printer_thumbnail_small.empty())
stream << " <Relationship Target=\"/" << xml_escape(data._3mf_printer_thumbnail_small)
<< "\" Id=\"rel-5\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-small\"/>\n";
}
else if (targets.empty()) {
return false;

View file

@ -100,6 +100,74 @@ bool decode_png(IStream &in_buf, ImageGreyscale &out_img)
return true;
}
bool decode_colored_png(IStream &in_buf, ImageColorscale &out_img)
{
static const constexpr int PNG_SIG_BYTES = 8;
std::vector<png_byte> sig(PNG_SIG_BYTES, 0);
in_buf.read(sig.data(), PNG_SIG_BYTES);
if (!png_check_sig(sig.data(), PNG_SIG_BYTES)) {
BOOST_LOG_TRIVIAL(error) << boost::format("decode_colored_png: png_check_sig failed");
return false;
}
PNGDescr dsc;
dsc.png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr,
nullptr);
if(!dsc.png) {
BOOST_LOG_TRIVIAL(error) << boost::format("decode_colored_png: png_create_read_struct failed");
return false;
}
dsc.info = png_create_info_struct(dsc.png);
if(!dsc.info) {
BOOST_LOG_TRIVIAL(error) << boost::format("decode_colored_png: png_create_info_struct failed");
return false;
}
png_set_read_fn(dsc.png, static_cast<void *>(&in_buf), png_read_callback);
// Tell that we have already read the first bytes to check the signature
png_set_sig_bytes(dsc.png, PNG_SIG_BYTES);
png_read_info(dsc.png, dsc.info);
out_img.cols = png_get_image_width(dsc.png, dsc.info);
out_img.rows = png_get_image_height(dsc.png, dsc.info);
size_t color_type = png_get_color_type(dsc.png, dsc.info);
size_t bit_depth = png_get_bit_depth(dsc.png, dsc.info);
switch(color_type)
{
case PNG_COLOR_TYPE_RGB:
out_img.bytes_per_pixel = 3;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
out_img.bytes_per_pixel = 4;
break;
default: //not supported currently
return false;
}
BOOST_LOG_TRIVIAL(info) << boost::format("png's cols %1%, rows %2%, color_type %3%, bit_depth %4%, bytes_per_pixel %5%")%out_img.cols %out_img.rows %color_type %bit_depth %out_img.bytes_per_pixel;
out_img.buf.resize(out_img.rows * out_img.cols * out_img.bytes_per_pixel);
auto readbuf = static_cast<png_bytep>(out_img.buf.data());
for (size_t r = 0; r < out_img.rows; ++r)
png_read_row(dsc.png, readbuf + r * out_img.cols * out_img.bytes_per_pixel, nullptr);
return true;
}
bool decode_colored_png(const ReadBuf &in_buf, ImageColorscale &out_img)
{
struct ReadBufStream stream{in_buf};
return decode_colored_png(stream, out_img);
}
// Down to earth function to store a packed RGB image to file. Mostly useful for debugging purposes.
// Based on https://www.lemoda.net/c/write-png/
// png_color_type is PNG_COLOR_TYPE_RGB or PNG_COLOR_TYPE_GRAY
@ -112,7 +180,7 @@ static bool write_rgb_or_gray_to_file(const char *file_name_utf8, size_t width,
png_structp png_ptr = nullptr;
png_infop info_ptr = nullptr;
png_byte **row_pointers = nullptr;
FILE *fp = boost::nowide::fopen(file_name_utf8, "wb");
if (! fp) {
BOOST_LOG_TRIVIAL(error) << "write_png_file: File could not be opened for writing: " << file_name_utf8;

View file

@ -23,11 +23,19 @@ template<class PxT> struct Image {
};
using ImageGreyscale = Image<uint8_t>;
struct ImageColorscale:Image<unsigned char>
{
int bytes_per_pixel;
};
// Only decodes true 8 bit grayscale png images. Returns false for other formats
// TODO (if needed): implement transformation of rgb images into grayscale...
bool decode_png(IStream &stream, ImageGreyscale &out_img);
//BBS: decode png for other format
bool decode_colored_png(IStream &in_buf, ImageColorscale &out_img);
// TODO (if needed)
// struct RGB { uint8_t r, g, b; };
// using ImageRGB = Image<RGB>;
@ -39,30 +47,36 @@ struct ReadBuf { const void *buf = nullptr; const size_t sz = 0; };
bool is_png(const ReadBuf &pngbuf);
struct ReadBufStream: public IStream {
const ReadBuf &rbuf_ref;
size_t pos = 0;
explicit ReadBufStream(const ReadBuf &buf): rbuf_ref{buf} {}
size_t read(std::uint8_t *outp, size_t amount) override
{
if (amount > rbuf_ref.sz - pos) return 0;
auto buf = static_cast<const std::uint8_t *>(rbuf_ref.buf);
std::copy(buf + pos, buf + (pos + amount), outp);
pos += amount;
return amount;
}
bool is_ok() const override { return pos < rbuf_ref.sz; }
};
template<class Img> bool decode_png(const ReadBuf &in_buf, Img &out_img)
{
struct ReadBufStream: public IStream {
const ReadBuf &rbuf_ref; size_t pos = 0;
explicit ReadBufStream(const ReadBuf &buf): rbuf_ref{buf} {}
size_t read(std::uint8_t *outp, size_t amount) override
{
if (amount > rbuf_ref.sz - pos) return 0;
auto buf = static_cast<const std::uint8_t *>(rbuf_ref.buf);
std::copy(buf + pos, buf + (pos + amount), outp);
pos += amount;
return amount;
}
bool is_ok() const override { return pos < rbuf_ref.sz; }
} stream{in_buf};
struct ReadBufStream stream{in_buf};
return decode_png(stream, out_img);
}
bool decode_colored_png(const ReadBuf &in_buf, ImageColorscale &out_img);
// TODO: std::istream of FILE* could be similarly adapted in case its needed...