There are two ways to get bounding boxes using Inkscape.
1. Using a command line call - inkscape --query-all which returns a long output list of bounding boxes for all object in pixel. ( This is a visual bounding box which includes stroke width and is capable of getting boxes for text ). You can query individual objects, but the command call itself is slower than the cost of returning all object so pointless. I put the output of --query-all into a dictionary which I can look up the visual bounding boxes for objects.
2. Using bounding_box() or shape_box() in the extension. ( This is a geometric bounding box which excludes any stroke width, for text it will only return the topleft (x,y) instead of a true bounding box ). There is also a slight oddity in Inkscape 1.1, which returns paths etc in user set units (mm etc) but <rect>, <ellipse>, <circle>, <image> in pixels.
In that extension I insert a rectangle the same dimensions as the image, then create an inverse clipping path ( a hole in the rectangle ). Then apply the clip.
I could waffle on more.
If you are just using command line calls which return information - then a temp file is not required. Anything else, a temp file is required.
Some of my other extensions create and insert objects before using --query-all, to minimise the number of command calls.
First Inkscape script...
Iterate over Paths: bounding square+margin over each.
For each Path: boolean difference (Box - Path) and export png
So far the extensions I've examined:
- deep_difference: internally call CLI inkscape verbs
- destructive_clip: Is commmmplicated.
Are booleans possible in extensions without true horror?
Here's the script, up until the boolean:
import inkex
from inkex.elements import TextElement
from lxml import etree
class Char_Map(inkex.EffectExtension):
def __init__(self):
inkex.Effect.__init__(self)
def drawBBox(self, bbox):
offset = 0 # self.options.offset
corner_radius = 0
attribs = {
'style' : str(inkex.Style({'stroke':'#ff0000','stroke-width' : '1','fill':'none'})),
'x' : str(bbox.left - offset),
'y' : str(bbox.top - offset),
'width' : str(bbox.width + 2 * offset),
'height': str(bbox.height + 2 * offset),
'ry' : str(corner_radius),
'rx' : str(corner_radius)
}
etree.SubElement(self.svg.get_current_layer(), inkex.addNS('rect','svg'), attribs)
def effect(self):
for id in self.options.ids:
id_split = id.split("_")
if id_split[0] == 'clip':
node = self.svg.selected[id]
bbox = node.bounding_box()
bb_x = bbox.x
bb_y = bbox.y
x_size = bb_x.size
y_size = bb_y.size
max_size = max(x_size,y_size)
half = max_size * 0.55
x_center = bb_x.center
y_center = bb_y.center
x_span = (x_center-half,x_center+half)
y_span = (y_center-half,y_center+half)
bb = inkex.transforms.BoundingBox(x_span,y_span)
box = self.drawBBox(bb)
# TODO: boolean difference box - node. Export png and loop.
if __name__ == "__main__":
Char_Map().run()
There are two ways to get bounding boxes using Inkscape.
1. Using a command line call -
inkscape --query-all
which returns a long output list of bounding boxes for all object in pixel. ( This is a visual bounding box which includes stroke width and is capable of getting boxes for text ). You can query individual objects, but the command call itself is slower than the cost of returning all object so pointless. I put the output of --query-all into a dictionary which I can look up the visual bounding boxes for objects.2. Using bounding_box() or shape_box() in the extension. ( This is a geometric bounding box which excludes any stroke width, for text it will only return the topleft (x,y) instead of a true bounding box ). There is also a slight oddity in Inkscape 1.1, which returns paths etc in user set units (mm etc) but <rect>, <ellipse>, <circle>, <image> in pixels.
If you are just trying to clip against a rectangle of your choice. I wrote a an extension which does this https://inkscape.org/~inklinea/%E2%98%85clip-out
In that extension I insert a rectangle the same dimensions as the image, then create an inverse clipping path ( a hole in the rectangle ). Then apply the clip.
I could waffle on more.
If you are just using command line calls which return information - then a temp file is not required. Anything else, a temp file is required.
Some of my other extensions create and insert objects before using --query-all, to minimise the number of command calls.
Digging into this now. It looks like your script does almost exactly what I need.
In my code I’m iterating through all paths that start with clip.. doing the bounding square on each.
is there a way to do that on the command line with your script?
Do you do any work on commission?
I also need the reverse script
- reinsert the exported image, place in the correct position and re-clip with the original mask.
You can call any extension from the command line, by using its verb as defined in the .inx file. For example inkscape.org.my_script.noprefs
However it is not possible to pass parameters to extensions from the command line.
I'm only a hobby programmer, there are coders on here who may take commissions.
I'm not sure about reinserting an exported image ? Any png or jpeg image can be inserted by encoding it to base64 and constructing an <image> tag.
In Inkscape 1.1+ python PIL ( pillow ) can open a wide variety of image formats which can then be coded to png, and then to base64 and inserted.