Fix #145259: Grease Pencil: Bail when no frame is selected for SVG export

Previously `SVGExporter::export_scene` can work on a empty `frames`
index mask, causing crash. Now it will exit early when no frames are
selected, and it will show a warning to the user.

Pull Request: https://projects.blender.org/blender/blender/pulls/145286
This commit is contained in:
YimingWu
2025-08-29 12:03:29 +02:00
committed by YimingWu
parent 1fe5096101
commit af700685e7
3 changed files with 48 additions and 16 deletions

View File

@@ -295,6 +295,7 @@ static wmOperatorStatus grease_pencil_export_svg_invoke(bContext *C,
static wmOperatorStatus grease_pencil_export_svg_exec(bContext *C, wmOperator *op)
{
using blender::io::grease_pencil::ExportParams;
using blender::io::grease_pencil::ExportStatus;
using blender::io::grease_pencil::IOContext;
Scene *scene = CTX_data_scene(C);
@@ -337,11 +338,25 @@ static wmOperatorStatus grease_pencil_export_svg_exec(bContext *C, wmOperator *o
stroke_sample};
WM_cursor_wait(true);
const bool done = blender::io::grease_pencil::export_svg(io_context, params, *scene, filepath);
ExportStatus status = blender::io::grease_pencil::export_svg(
io_context, params, *scene, filepath);
WM_cursor_wait(false);
if (!done) {
BKE_report(op->reports, RPT_WARNING, "Unable to export SVG");
switch (status) {
case ExportStatus::Ok:
break;
case ExportStatus::InvalidActiveObjectType:
BKE_report(op->reports, RPT_WARNING, "Active object is not a Grease Pencil object");
break;
case ExportStatus::NoFramesSelected:
BKE_report(op->reports, RPT_WARNING, "No frames selected in the Grease Pencil object");
break;
case ExportStatus::FileWriteError:
BKE_reportf(op->reports, RPT_WARNING, "Error during file write for \"%s\"", filepath);
break;
case ExportStatus::UnknownError:
BLI_assert_unreachable();
break;
}
return OPERATOR_FINISHED;

View File

@@ -45,6 +45,14 @@ struct ImportParams {
bool recenter_bounds = false;
};
enum class ExportStatus : int8_t {
Ok = 0,
NoFramesSelected,
InvalidActiveObjectType,
FileWriteError,
UnknownError,
};
struct ExportParams {
/* Object to be exported. */
enum class SelectMode {
@@ -74,10 +82,10 @@ struct ExportParams {
};
bool import_svg(const IOContext &context, const ImportParams &params, StringRefNull filepath);
bool export_svg(const IOContext &context,
const ExportParams &params,
Scene &scene,
StringRefNull filepath);
ExportStatus export_svg(const IOContext &context,
const ExportParams &params,
Scene &scene,
StringRefNull filepath);
bool export_pdf(const IOContext &context,
const ExportParams &params,
Scene &scene,

View File

@@ -106,7 +106,7 @@ class SVGExporter : public GreasePencilExporter {
pugi::xml_document main_doc_;
bool export_scene(Scene &scene, StringRefNull filepath);
ExportStatus export_scene(Scene &scene, StringRefNull filepath);
void export_grease_pencil_objects(pugi::xml_node node, int frame_number);
void export_grease_pencil_layer(pugi::xml_node node,
const Object &object,
@@ -146,7 +146,7 @@ std::string SVGExporter::get_node_uuid_string()
return id;
}
bool SVGExporter::export_scene(Scene &scene, StringRefNull filepath)
ExportStatus SVGExporter::export_scene(Scene &scene, StringRefNull filepath)
{
this->_node_uuid = 0;
@@ -160,7 +160,8 @@ bool SVGExporter::export_scene(Scene &scene, StringRefNull filepath)
this->export_grease_pencil_objects(main_node, frame_number);
return this->write_to_file(filepath);
const bool write_success = this->write_to_file(filepath);
return write_success ? ExportStatus::Ok : ExportStatus::FileWriteError;
}
case ExportParams::FrameMode::Selected:
case ExportParams::FrameMode::Scene: {
@@ -172,6 +173,9 @@ bool SVGExporter::export_scene(Scene &scene, StringRefNull filepath)
IndexMaskMemory memory;
if (selection_only) {
const Object &ob_eval = *DEG_get_evaluated(context_.depsgraph, params_.object);
if (ob_eval.type != OB_GREASE_PENCIL) {
return ExportStatus::InvalidActiveObjectType;
}
const GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob_eval.data);
frames = IndexMask::from_predicate(
frames, GrainSize(1024), memory, [&](const int frame_number) {
@@ -179,6 +183,10 @@ bool SVGExporter::export_scene(Scene &scene, StringRefNull filepath)
});
}
if (frames.is_empty()) {
return ExportStatus::NoFramesSelected;
}
this->prepare_render_params(scene, frames.first());
this->write_document_header();
@@ -209,11 +217,12 @@ bool SVGExporter::export_scene(Scene &scene, StringRefNull filepath)
this->write_animation_node(main_node, frames, duration);
return this->write_to_file(filepath);
const bool write_success = this->write_to_file(filepath);
return write_success ? ExportStatus::Ok : ExportStatus::FileWriteError;
}
default:
BLI_assert_unreachable();
return false;
return ExportStatus::UnknownError;
}
}
@@ -572,10 +581,10 @@ bool SVGExporter::write_to_file(StringRefNull filepath)
return result;
}
bool export_svg(const IOContext &context,
const ExportParams &params,
Scene &scene,
StringRefNull filepath)
ExportStatus export_svg(const IOContext &context,
const ExportParams &params,
Scene &scene,
StringRefNull filepath)
{
SVGExporter exporter(context, params);
return exporter.export_scene(scene, filepath);