15#include <glibmm/i18n.h>
36Glib::ustring image_get_editor_name(
bool is_svg)
40 return prefs->
getString(
"/options/svgeditor/value",
"inkscape");
42 return prefs->
getString(
"/options/bitmapeditor/value",
"gimp");
53bool has_svg_extension(std::string
const &filename)
55 return Glib::str_has_suffix(filename,
".svg") || Glib::str_has_suffix(filename,
".SVG");
63 if (selection->isEmpty()) {
68 for (
auto item : selection->items()) {
70 if (
auto const *clone = cast<SPUse>(
item)) {
71 item = clone->trueOriginal();
73 if (!is<SPImage>(
item)) {
83 auto const uri =
Inkscape::URI(href, get_base_path_uri(*selection->document()));
84 if (uri.hasScheme(
"data")) {
86 g_warning(
"Edit Externally: Editing embedded images (data URL) is not supported");
89 if (
const char *other_scheme = uri.getScheme(); other_scheme && !uri.hasScheme(
"file")) {
91 g_warning(
"Edit Externally: Cannot edit image (scheme '%s' not supported)", other_scheme);
95 std::string
const filename = uri.toNativeFilename();
96 std::string
const command = Glib::shell_quote(image_get_editor_name(has_svg_extension(filename))) +
" " +
97 Glib::shell_quote(filename);
99 const char *
const message = _(
"Failed to edit external image.\n<small>Note: Path to editor can be set in "
100 "Preferences dialog.</small>");
102 Glib::spawn_command_line_async(command);
103 }
catch (Glib::SpawnError &error) {
105 auto dialog = std::make_unique<Gtk::MessageDialog>(*window, message,
true, Gtk::MessageType::WARNING, Gtk::ButtonsType::OK);
106 dialog->property_destroy_with_parent() =
true;
107 dialog->set_name(
"SetEditorDialog");
108 dialog->set_title(_(
"External Edit Image:"));
109 dialog->set_secondary_text(
110 Glib::ustring::compose(_(
"System error message: %1"), error.what()));
113 show_output(Glib::ustring(
"image_edit: ") + message);
115 }
catch (Glib::ShellError &error) {
116 g_error(
"Edit Externally: %s\n%s %s", message, _(
"System error message:"), error.what());
129 auto msg = win->get_desktop()->messageStack();
130 auto const tool = win->get_desktop()->getTool();
135 if (selection->isEmpty()) {
143 for (
auto item : selection->items()) {
144 rect = cast<SPRect>(
item);
153 for (
auto item : selection->items()) {
155 bytes -= std::strlen(
image->href);
160 }
else if (
auto clip =
image->getClipObject()) {
162 area =
clip->geometricBounds(
image->i2doc_affine());
164 done += (int)(area &&
image->cropToArea(*area));
165 bytes += std::strlen(
image->href);
176 selector->updateDescriber(selection);
178 std::stringstream ss;
179 ss << ngettext(
"<b>%d</b> image cropped",
"<b>%d</b> images cropped", done);
181 ss <<
", " << ngettext(
"%s byte removed",
"%s bytes removed", abs(bytes));
182 }
else if (bytes > 0) {
183 ss <<
", <b>" << ngettext(
"%s byte added!",
"%s bytes added!", bytes) <<
"</b>";
193const Glib::ustring
SECTION = NC_(
"Action Section",
"Images");
198 {
"app.element-image-crop", N_(
"Crop image to clip"),
SECTION, N_(
"Remove parts of the image outside the applied clipping area.") },
199 {
"app.element-image-edit", N_(
"Edit externally"),
SECTION, N_(
"Edit image externally (image must be selected and not embedded).") },
209 gapp->add_action(
"element-image-crop", sigc::bind(sigc::ptr_fun(&
image_crop), app));
210 gapp->add_action(
"element-image-edit", sigc::bind(sigc::ptr_fun(&
image_edit), app));
void add_actions_element_image(InkscapeApplication *app)
const Glib::ustring SECTION
void image_edit(InkscapeApplication *app)
void image_crop(InkscapeApplication *app)
Attempt to crop an image's physical pixels by the rectangle give OR if not specified,...
std::vector< std::vector< Glib::ustring > > raw_data_element_image
void show_output(Glib::ustring const &data, bool const is_cerr)
Axis-aligned rectangle that can be empty.
InkActionExtraData & get_action_extra_data()
InkscapeWindow * get_active_window()
Gio::Application * gio_app()
The Gio application instance, never NULL.
SPDocument * get_active_document()
Inkscape::Selection * get_active_selection()
static void done(SPDocument *document, Glib::ustring const &event_description, Glib::ustring const &undo_icon, unsigned int object_modified_tag=0)
Preference storage class.
Glib::ustring getString(Glib::ustring const &pref_path, Glib::ustring const &def="")
Retrieve an UTF-8 string.
static Preferences * get()
Access the singleton Preferences object.
Represents an URI as per RFC 2396.
static URI from_dirname(char const *path)
URI of a local directory.
Typed SVG document implementation.
char const * getDocumentBase() const
Geom::OptRect geometricBounds(Geom::Affine const &transform=Geom::identity()) const
Get item's geometric bounding box in this item's coordinate system.
Geom::Affine i2doc_affine() const
Returns the accumulated transformation of the item and all its ancestors, including root's viewport.
void deleteObject(bool propagate, bool propagate_descendants)
Deletes an object, unparenting it from its parent.
Inkscape::XML::Node * getRepr()
Returns the XML representation of tree.
Editable view implementation.
TODO: insert short description here.
std::unique_ptr< Magick::Image > image
Inkscape - An SVG editor.
void dialog_show_modal_and_selfdestruct(std::unique_ptr< Gtk::Dialog > dialog, Gtk::Root *root)
Show a dialog modally, destroying it when the user dismisses it.
Glib::ustring format_size(std::size_t value)
std::pair< char const *, char const * > getHrefAttribute(XML::Node const &node)
Get the 'href' or 'xlink:href' (fallback) attribute from an XML node.
static T clip(T const &v, T const &a, T const &b)
Singleton class to access the preferences file in a convenient way.
SVG <image> implementation.