Get SVG from clipboard

I am writing a program, and want to load images from the clipboard. I copied the approach used in obfuscate. using clipboard.read_texture_future().await.
My imagined use is people copying svg icons using the icon library and pasting them in my program. However the pasted images are incredibly low resolution. They are unusable. I understand textures are used for raster images so do not support svgs but I do not understand why the returned texture is of such a low resolution. Is it possible to load the svg’s at a higher resolution. Or is there another possible solution?


Many thanks!

afaik texture is always pixels, i think you need to use read_async with mime type list ["image/svg+xml"], here is an example in vala (vala yield do_async() = rust do_async().await)

#! /usr/bin/env -S vala --pkg gtk4 --pkg posix --pkg gio-unix-2.0
async void svg_to_stdout() {
	var display = Gdk.Display.get_default();
	var clip = display.get_clipboard();
	string mime;
	InputStream stream = null;
	try {
		stream = yield clip.read_async({"image/svg+xml"}, Priority.DEFAULT, null, out mime);
	} catch (Error e) {
		print("couldnt read an svg, %s\n", e.message);
		return;
	}
	var stdout_stream = new UnixOutputStream(Posix.STDOUT_FILENO, false);
	yield stdout_stream.splice_async(stream, NONE); // copy from stream to stdout
	stdout_stream.flush();
}
void main() {
	var app = new Gtk.Application(null, 0);
	// wm won't allow us to read the clipboard with no reason, need a window and a button
	app.activate.connect(() => {
		var btn = new Gtk.Button.with_label("read svg to stdout");
		btn.clicked.connect(() => {svg_to_stdout.begin();});
		var win = new Gtk.ApplicationWindow(app) {child = btn};
		win.present();
	});
	app.run();
}

This seems like a lot of complicated code. But if there is no other way to make it happen. Then I guess I’ll just have to try and understand it.
Internally my program also only works in pixels so it is really not an issue that textures are pixels. Would it be possible through some way, for it to load a higher resolution pixel version of the svg. Instead of the low resolution it does now?

but most of that code is just error handling, creating a window, and printing the svg xml to the console

to convert an svg to pixels, you can use the rsvg library (it’s written in rust, but it’s also what gtk uses to render icons)
i looked at the rust docs, and if i understand correctly, you should write:

let stream = match clipboard.read_future(&["image/svg+xml"], glib::source::priority::DEFAULT).await {
    Ok((stream, _mime)) => stream,
    Err(_) => return, // no svg in clipboard
};
let loader = rsvg::Loader::new().read_stream(stream, None, None);
...

…then draw it to a surface like in the example
also if you want to accept other image types you should add them to the array and match on the mime variable

1 Like

oh wow thank you for this. This looks way easier to understand. I will try this!

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.