diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index e668703710..fab1ad5715 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -58,6 +58,8 @@ #include "libslic3r/Format/STL.hpp" #include "libslic3r/Format/OBJ.hpp" #include "libslic3r/Format/SL1.hpp" +#include "libslic3r/miniz_extension.hpp" +#include "libslic3r/PNGReadWrite.hpp" #include "libslic3r/Utils.hpp" #include "libslic3r/Thread.hpp" #include "libslic3r/BlacklistedLibraryCheck.hpp" @@ -671,8 +673,67 @@ int CLI::run(int argc, char **argv) std::string outfile_final; print->process(); if (printer_technology == ptFFF) { + + + + + + std::function thumbnail_generator_cli; + if (!fff_print.model().objects.empty() && boost::iends_with(fff_print.model().objects.front()->input_file, ".3mf")) { + std::string filename = fff_print.model().objects.front()->input_file; + thumbnail_generator_cli = [filename](const ThumbnailsParams&) { + ThumbnailsList list_out; + + mz_zip_archive archive; + mz_zip_zero_struct(&archive); + + if (!open_zip_reader(&archive, filename)) + return list_out; + mz_uint num_entries = mz_zip_reader_get_num_files(&archive); + mz_zip_archive_file_stat stat; + + int index = mz_zip_reader_locate_file(&archive, "Metadata/thumbnail.png", nullptr, 0); + if (index < 0 || !mz_zip_reader_file_stat(&archive, index, &stat)) + return list_out; + std::string buffer; + buffer.resize(int(stat.m_uncomp_size)); + mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, buffer.data(), (size_t)stat.m_uncomp_size, 0); + if (res == 0) + return list_out; + close_zip_reader(&archive); + + std::vector data; + unsigned width = 0; + unsigned height = 0; + png::decode_png(buffer, data, width, height); + + { + // Flip the image vertically so it matches the convention in Thumbnails generator. + const int row_size = width * 4; // Each pixel is 4 bytes (RGBA) + std::vector temp_row(row_size); + for (int i = 0; i < height / 2; ++i) { + unsigned char* top_row = &data[i * row_size]; + unsigned char* bottom_row = &data[(height - i - 1) * row_size]; + std::copy(bottom_row, bottom_row + row_size, temp_row.begin()); + std::copy(top_row, top_row + row_size, bottom_row); + std::copy(temp_row.begin(), temp_row.end(), top_row); + } + } + + ThumbnailData th; + th.set(width, height); + th.pixels = data; + list_out.push_back(th); + return list_out; + }; + } + + + + + // The outfile is processed by a PlaceholderParser. - outfile = fff_print.export_gcode(outfile, nullptr, nullptr); + outfile = fff_print.export_gcode(outfile, nullptr, thumbnail_generator_cli); outfile_final = fff_print.print_statistics().finalize_output_path(outfile); } else { outfile = sla_print.output_filepath(outfile); diff --git a/src/libslic3r/PNGReadWrite.cpp b/src/libslic3r/PNGReadWrite.cpp index f8b3696834..fb1b120a5d 100644 --- a/src/libslic3r/PNGReadWrite.cpp +++ b/src/libslic3r/PNGReadWrite.cpp @@ -190,6 +190,34 @@ fopen_failed: return result; } + +bool decode_png(const std::string& png_data, std::vector& image_data, unsigned& width, unsigned& height) +{ + png_image image; + memset(&image, 0, sizeof(image)); + image.version = PNG_IMAGE_VERSION; + + if (!png_image_begin_read_from_memory(&image, png_data.data(), png_data.size())) + return false; + + image.format = PNG_FORMAT_RGBA; + + // Allocate memory for the image data + image_data.resize(PNG_IMAGE_SIZE(image)); + if (!png_image_finish_read(&image, nullptr, image_data.data(), 0, nullptr)) { + png_image_free(&image); + return false; + } + + width = image.width; + height = image.height; + + png_image_free(&image); + return true; +} + + + bool write_rgb_to_file(const char *file_name_utf8, size_t width, size_t height, const uint8_t *data_rgb) { return write_rgb_or_gray_to_file(file_name_utf8, width, height, PNG_COLOR_TYPE_RGB, data_rgb); diff --git a/src/libslic3r/PNGReadWrite.hpp b/src/libslic3r/PNGReadWrite.hpp index 0e8432581a..1f6e567d47 100644 --- a/src/libslic3r/PNGReadWrite.hpp +++ b/src/libslic3r/PNGReadWrite.hpp @@ -74,7 +74,7 @@ template bool decode_png(const ReadBuf &in_buf, Img &out_img) // TODO: std::istream of FILE* could be similarly adapted in case its needed... - +bool decode_png(const std::string& png_data, std::vector& image_data, unsigned& width, unsigned& height); // Down to earth function to store a packed RGB image to file. Mostly useful for debugging purposes. bool write_rgb_to_file(const char *file_name_utf8, size_t width, size_t height, const uint8_t *data_rgb);