ENH: 3mf: refine the rels to correct link
JIRA: STUDIO-4231 Change-Id: I02ff6343124ef2ea3642e5799469249538a4b97f
This commit is contained in:
parent
9757ec5fc3
commit
ae7b205e10
|
@ -67,6 +67,7 @@ using namespace nlohmann;
|
||||||
#include "libslic3r/FlushVolCalc.hpp"
|
#include "libslic3r/FlushVolCalc.hpp"
|
||||||
|
|
||||||
#include "libslic3r/Orient.hpp"
|
#include "libslic3r/Orient.hpp"
|
||||||
|
#include "libslic3r/PNGReadWrite.hpp"
|
||||||
|
|
||||||
#include "BambuStudio.hpp"
|
#include "BambuStudio.hpp"
|
||||||
//BBS: add exception handler for win32
|
//BBS: add exception handler for win32
|
||||||
|
@ -422,6 +423,39 @@ void record_exit_reson(std::string outputdir, int code, int plate_id, std::strin
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int decode_png_to_thumbnail(std::string png_file, ThumbnailData& thumbnail_data)
|
||||||
|
{
|
||||||
|
if (!boost::filesystem::exists(png_file))
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(error) << boost::format("can not find file %1%")%png_file;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t &size = boost::filesystem::file_size(png_file);
|
||||||
|
std::string png_buffer(size, '\0');
|
||||||
|
png_buffer.reserve(size);
|
||||||
|
|
||||||
|
boost::filesystem::ifstream ifs(png_file, std::ios::binary);
|
||||||
|
ifs.read(png_buffer.data(), png_buffer.size());
|
||||||
|
ifs.close();
|
||||||
|
|
||||||
|
Slic3r::png::ImageColorscale img;
|
||||||
|
Slic3r::png::ReadBuf rb{png_buffer.data(), png_buffer.size()};
|
||||||
|
BOOST_LOG_TRIVIAL(info) << boost::format("read png file %1%, size %2%")%png_file %size;
|
||||||
|
|
||||||
|
if ( !Slic3r::png::decode_colored_png(rb, img))
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(error) << boost::format("decode png file %1% failed")%png_file;
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
thumbnail_data.width = img.cols;
|
||||||
|
thumbnail_data.height = img.rows;
|
||||||
|
thumbnail_data.pixels = std::move(img.buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void glfw_callback(int error_code, const char* description)
|
static void glfw_callback(int error_code, const char* description)
|
||||||
{
|
{
|
||||||
BOOST_LOG_TRIVIAL(error) << "error_code " <<error_code <<", description: " <<description<< std::endl;
|
BOOST_LOG_TRIVIAL(error) << "error_code " <<error_code <<", description: " <<description<< std::endl;
|
||||||
|
@ -3616,8 +3650,9 @@ int CLI::run(int argc, char **argv)
|
||||||
BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: regenerate thumbnail, reset plate %2%'s thumbnail.")%__LINE__%(i+1);
|
BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: regenerate thumbnail, reset plate %2%'s thumbnail.")%__LINE__%(i+1);
|
||||||
plate_data->plate_thumbnail.reset();
|
plate_data->plate_thumbnail.reset();
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% has a valid thumbnail, width %2%, height %3%, directly using it")%(i+1) %plate_data->plate_thumbnail.width %plate_data->plate_thumbnail.height;
|
BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% has a valid thumbnail, width %2%, height %3%, directly using it")%(i+1) %plate_data->plate_thumbnail.width %plate_data->plate_thumbnail.height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (!plate_data->thumbnail_file.empty() && (boost::filesystem::exists(plate_data->thumbnail_file)))
|
else if (!plate_data->thumbnail_file.empty() && (boost::filesystem::exists(plate_data->thumbnail_file)))
|
||||||
{
|
{
|
||||||
|
@ -3625,8 +3660,17 @@ int CLI::run(int argc, char **argv)
|
||||||
BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: regenerate thumbnail, clear plate %2%'s thumbnail file path to empty.")%__LINE__%(i+1);
|
BOOST_LOG_TRIVIAL(info) << boost::format("Line %1%: regenerate thumbnail, clear plate %2%'s thumbnail file path to empty.")%__LINE__%(i+1);
|
||||||
plate_data->thumbnail_file.clear();
|
plate_data->thumbnail_file.clear();
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% has a valid thumbnail %2% extracted from 3mf, directly using it")%(i+1) %plate_data->thumbnail_file;
|
BOOST_LOG_TRIVIAL(info) << boost::format("plate %1% has a valid thumbnail %2% extracted from 3mf, directly using it")%(i+1) %plate_data->thumbnail_file;
|
||||||
|
int dec_ret = decode_png_to_thumbnail(plate_data->thumbnail_file, plate_data->plate_thumbnail);
|
||||||
|
if (!dec_ret)
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(info) << boost::format("decode png to mem sucess.");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << boost::format("decode png to mem failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ThumbnailData* thumbnail_data = &plate_data->plate_thumbnail;
|
ThumbnailData* thumbnail_data = &plate_data->plate_thumbnail;
|
||||||
|
@ -3774,6 +3818,24 @@ int CLI::run(int argc, char **argv)
|
||||||
plate_data->top_file.clear();
|
plate_data->top_file.clear();
|
||||||
plate_data->pick_file.clear();
|
plate_data->pick_file.clear();
|
||||||
}
|
}
|
||||||
|
else if (!plate_data->plate_thumbnail.is_valid() && !plate_data->thumbnail_file.empty() && (boost::filesystem::exists(plate_data->thumbnail_file)))
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(info) << boost::format("no need to generate: plate %1% has a valid thumbnail %2% extracted from 3mf, convert to data")%(i+1) %plate_data->thumbnail_file;
|
||||||
|
int dec_ret = decode_png_to_thumbnail(plate_data->thumbnail_file, plate_data->plate_thumbnail);
|
||||||
|
if (!dec_ret)
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(info) << boost::format("decode png to mem sucess.");
|
||||||
|
need_create_thumbnail_group = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << boost::format("decode png to mem failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < partplate_list.get_plate_count(); i++) {
|
||||||
|
PlateData *plate_data = plate_data_list[i];
|
||||||
|
Slic3r::GUI::PartPlate *part_plate = partplate_list.get_plate(i);
|
||||||
|
|
||||||
if (need_create_thumbnail_group) {
|
if (need_create_thumbnail_group) {
|
||||||
thumbnails.push_back(&plate_data->plate_thumbnail);
|
thumbnails.push_back(&plate_data->plate_thumbnail);
|
||||||
|
@ -3919,7 +3981,7 @@ int CLI::run(int argc, char **argv)
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(info) << "will export 3mf to " << export_3mf_file << std::endl;
|
BOOST_LOG_TRIVIAL(info) << "will export 3mf to " << export_3mf_file << std::endl;
|
||||||
if (! this->export_project(&m_models[0], export_3mf_file, plate_data_list, project_presets, thumbnails, top_thumbnails, pick_thumbnails,
|
if (! this->export_project(&m_models[0], export_3mf_file, plate_data_list, project_presets, thumbnails, top_thumbnails, pick_thumbnails,
|
||||||
calibration_thumbnails, plate_bboxes, &m_print_config, minimum_save))
|
calibration_thumbnails, plate_bboxes, &m_print_config, minimum_save, plate_to_slice - 1))
|
||||||
{
|
{
|
||||||
release_PlateData_list(plate_data_list);
|
release_PlateData_list(plate_data_list);
|
||||||
record_exit_reson(outfile_dir, CLI_EXPORT_3MF_ERROR, 0, cli_errors[CLI_EXPORT_3MF_ERROR], sliced_info);
|
record_exit_reson(outfile_dir, CLI_EXPORT_3MF_ERROR, 0, cli_errors[CLI_EXPORT_3MF_ERROR], sliced_info);
|
||||||
|
@ -4141,7 +4203,7 @@ bool CLI::export_models(IO::ExportFormat format)
|
||||||
//BBS: add export_project function
|
//BBS: add export_project function
|
||||||
bool CLI::export_project(Model *model, std::string& path, PlateDataPtrs &partplate_data,
|
bool CLI::export_project(Model *model, std::string& path, PlateDataPtrs &partplate_data,
|
||||||
std::vector<Preset*>& project_presets, std::vector<ThumbnailData*>& thumbnails, std::vector<ThumbnailData*>& top_thumbnails, std::vector<ThumbnailData*>& pick_thumbnails,
|
std::vector<Preset*>& project_presets, std::vector<ThumbnailData*>& thumbnails, std::vector<ThumbnailData*>& top_thumbnails, std::vector<ThumbnailData*>& pick_thumbnails,
|
||||||
std::vector<ThumbnailData*>& calibration_thumbnails, std::vector<PlateBBoxData*>& plate_bboxes, const DynamicPrintConfig* config, bool minimum_save)
|
std::vector<ThumbnailData*>& calibration_thumbnails, std::vector<PlateBBoxData*>& plate_bboxes, const DynamicPrintConfig* config, bool minimum_save, int plate_to_export)
|
||||||
{
|
{
|
||||||
//const std::string path = this->output_filepath(*model, IO::TMF);
|
//const std::string path = this->output_filepath(*model, IO::TMF);
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
@ -4158,6 +4220,7 @@ bool CLI::export_project(Model *model, std::string& path, PlateDataPtrs &partpla
|
||||||
store_params.calibration_thumbnail_data = calibration_thumbnails;
|
store_params.calibration_thumbnail_data = calibration_thumbnails;
|
||||||
store_params.id_bboxes = plate_bboxes;
|
store_params.id_bboxes = plate_bboxes;
|
||||||
store_params.strategy = SaveStrategy::Silence|SaveStrategy::WithGcode|SaveStrategy::SplitModel|SaveStrategy::UseLoadedId|SaveStrategy::ShareMesh;
|
store_params.strategy = SaveStrategy::Silence|SaveStrategy::WithGcode|SaveStrategy::SplitModel|SaveStrategy::UseLoadedId|SaveStrategy::ShareMesh;
|
||||||
|
store_params.export_plate_idx = plate_to_export;
|
||||||
if (minimum_save)
|
if (minimum_save)
|
||||||
store_params.strategy = store_params.strategy | SaveStrategy::SkipModel;
|
store_params.strategy = store_params.strategy | SaveStrategy::SkipModel;
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ private:
|
||||||
bool export_project(Model *model, std::string& path, PlateDataPtrs &partplate_data, std::vector<Preset*>& project_presets,
|
bool export_project(Model *model, std::string& path, PlateDataPtrs &partplate_data, std::vector<Preset*>& project_presets,
|
||||||
std::vector<ThumbnailData*>& thumbnails, std::vector<ThumbnailData*>& top_thumbnails, std::vector<ThumbnailData*>& pick_thumbnails,
|
std::vector<ThumbnailData*>& thumbnails, std::vector<ThumbnailData*>& top_thumbnails, std::vector<ThumbnailData*>& pick_thumbnails,
|
||||||
std::vector<ThumbnailData*>& calibration_thumbnails,
|
std::vector<ThumbnailData*>& calibration_thumbnails,
|
||||||
std::vector<PlateBBoxData*>& plate_bboxes, const DynamicPrintConfig* config, bool minimum_save);
|
std::vector<PlateBBoxData*>& plate_bboxes, const DynamicPrintConfig* config, bool minimum_save, int plate_to_export = -1);
|
||||||
|
|
||||||
bool has_print_action() const { return m_config.opt_bool("export_gcode") || m_config.opt_bool("export_sla"); }
|
bool has_print_action() const { return m_config.opt_bool("export_gcode") || m_config.opt_bool("export_sla"); }
|
||||||
|
|
||||||
|
|
|
@ -5951,27 +5951,46 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
||||||
if (from.empty()) {
|
if (from.empty()) {
|
||||||
stream << " <Relationship Target=\"/" << MODEL_FILE << "\" Id=\"rel-1\" Type=\"http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel\"/>\n";
|
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) {
|
||||||
if (export_plate_idx < 0) {
|
//use cover image if have
|
||||||
stream << " <Relationship Target=\"/" << THUMBNAIL_FILE
|
if (data._3mf_thumbnail.empty()) {
|
||||||
<< "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\"/>\n";
|
stream << " <Relationship Target=\"/Metadata/plate_1.png"
|
||||||
|
<< "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\"/>\n";
|
||||||
} else {
|
} else {
|
||||||
std::string thumbnail_file_str = (boost::format("Metadata/plate_%1%.png") % (export_plate_idx + 1)).str();
|
stream << " <Relationship Target=\"/" << xml_escape(data._3mf_thumbnail)
|
||||||
stream << " <Relationship Target=\"/" << xml_escape(thumbnail_file_str)
|
<< "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\"/>\n";
|
||||||
<< "\" 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()) {
|
if (data._3mf_printer_thumbnail_middle.empty()) {
|
||||||
stream << " <Relationship Target=\"/" << xml_escape(data._3mf_printer_thumbnail_middle)
|
stream << " <Relationship Target=\"/Metadata/plate_1.png"
|
||||||
<< "\" Id=\"rel-4\" Type=\"http://schemas.bambulab.com/package/2021/cover-thumbnail-middle\"/>\n";
|
<< "\" 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()) {
|
else if (targets.empty()) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -100,6 +100,74 @@ bool decode_png(IStream &in_buf, ImageGreyscale &out_img)
|
||||||
return true;
|
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.
|
// 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/
|
// Based on https://www.lemoda.net/c/write-png/
|
||||||
// png_color_type is PNG_COLOR_TYPE_RGB or PNG_COLOR_TYPE_GRAY
|
// png_color_type is PNG_COLOR_TYPE_RGB or PNG_COLOR_TYPE_GRAY
|
||||||
|
|
|
@ -23,11 +23,19 @@ template<class PxT> struct Image {
|
||||||
};
|
};
|
||||||
|
|
||||||
using ImageGreyscale = Image<uint8_t>;
|
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
|
// Only decodes true 8 bit grayscale png images. Returns false for other formats
|
||||||
// TODO (if needed): implement transformation of rgb images into grayscale...
|
// TODO (if needed): implement transformation of rgb images into grayscale...
|
||||||
bool decode_png(IStream &stream, ImageGreyscale &out_img);
|
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)
|
// TODO (if needed)
|
||||||
// struct RGB { uint8_t r, g, b; };
|
// struct RGB { uint8_t r, g, b; };
|
||||||
// using ImageRGB = Image<RGB>;
|
// 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);
|
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)
|
template<class Img> bool decode_png(const ReadBuf &in_buf, Img &out_img)
|
||||||
{
|
{
|
||||||
struct ReadBufStream: public IStream {
|
struct ReadBufStream stream{in_buf};
|
||||||
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};
|
|
||||||
|
|
||||||
return decode_png(stream, out_img);
|
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...
|
// TODO: std::istream of FILE* could be similarly adapted in case its needed...
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue