-
-
Notifications
You must be signed in to change notification settings - Fork 64
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
resize page to drawing feature? #25
Comments
This would solve a problem I have now where I draw a bunch of geometry, then I rotate it and now it's annoying to figure out how big the canvas should be to just fit everything in. |
This could be solved for simple geometry but I don't think drawSvg is well suited to solve this for many cases. The main problem is you are allowed to add arbitrary SVG attributes that this package doesn't understand (like Are there specific use cases you think could be solved well in drawSvg? Maybe shrink-to-fit a specific top-level |
Maybe you're right that this must be solved at a higher level. But maybe also my canvas size calculation problem can be solved by understanding the SVG spec better. Do you know if there's any way around having to specify those fixed x and y canvas dimensions at the beginning? As for solving this at a higher level, I'm trying that route too.
The problem I have is that the rsvg drawing output I get always seems to have the x and y dims that I give to |
You have a good point that an SVG rendering library could be used to determine the bounding box. After a quick search, I found the |
Hm. Not really so useful maybe? It doesn't seem to understand rotations.
|
I do get a useful result from Rsvg though:
|
It looks like Cairo can do this too but it may not be supported in CairoSVG. |
Solution using CairoNow you got me interested in the problem... Here is a mostly complete solution. The constants may need to be tweaked to get good results for different drawing sizes. import cairosvg, cairocffi
import drawSvg as draw
# Contribute this to CairoSVG? This wrapper was missing.
class RecordingSurface(cairosvg.surface.Surface):
"""A surface that records draw commands."""
def _create_surface(self, width, height):
cairo_surface = cairocffi.RecordingSurface(
cairocffi.CONTENT_COLOR_ALPHA, None)
return cairo_surface, width, height
def get_bounding_box(d, pad=0, resolution=1/256, max_size=10000):
rbox = (-max_size, -max_size, 2*max_size, 2*max_size)
# Hack, add an argument to asSvg instead
svg_lines = d.asSvg().split('\n')
svg_lines[2] = f'viewBox="{rbox[0]}, {rbox[1]}, {rbox[2]}, {rbox[3]}">'
svg_code = '\n'.join(svg_lines)
t = cairosvg.parser.Tree(bytestring=svg_code)
s = RecordingSurface(t, None, 72, scale=1/resolution)
b = s.cairo.ink_extents()
return (
rbox[0] + b[0]*resolution - pad,
-(rbox[1]+b[1]*resolution)-b[3]*resolution - pad,
b[2]*resolution + pad*2,
b[3]*resolution + pad*2,
)
def fit_to_contents(d, pad=0, resolution=1/256, max_size=10000):
bb = get_bounding_box(d, pad=pad, resolution=resolution, max_size=max_size)
d.viewBox = (bb[0], -bb[1]-bb[3], bb[2], bb[3])
d.width, d.height = bb[2], bb[3]
# Debug: Draw bounding rectangle
d.append(draw.Rectangle(*bb, fill='none', stroke_width=2,
stroke='red', stroke_dasharray='5 2')) d = draw.Drawing(0, 0, displayInline=False)
angle = 35
rot = f"rotate({angle},0,0)"
d.append(draw.Rectangle(0,0,40,70,transform=rot), z=1)
fit_to_contents(d, pad=0)
d |
I'm a little dissappointed that all the solutions we have look like they require the vector art to be rendered and then something comes along and counts some pixels in the rendered image. This means all the results we get are approximations which depend on the details of the how the rasterizaion was done. I was kind of hoping for a pure math/geometry solution, but I think maybe there is nothing that keeps track of the geometry to be able to answer the geometry extents quesion for us. |
That said, I think having the ability to auto-size the canvas to the content is a cool feature to add even though it might be an approximation! |
Would you still like to add the feature to do the auto-resize automatically? It should be easy to replace the current resize solution if you find a better one in the future. |
I don't think any of this should be automatic. I'd say the user should need to express their desire to have this type of auto canvas sizing done for them somehow. explicitly calling I'd say pretty much exactly what you have a few comments up would already be quite useful, though the only thing I'm a bit unsure of is that |
I agree the user should express it. I liked your idea of doing it automatically when the user doesn't specify dimensions (or maybe a special flag like 'auto') when creating the drawing. The 72 is to cancel out a unit conversion CairoSVG does for some reason. |
The solution proposed by @greyltc using |
I appreciate the feedback @shrx. I currently have no plans to work on a feature like this unless someone finds a more accurate and faster method. |
Is it possible to add a feature that shrinks the canvas so that it's just big enough to hold the objects in it?
I was thinking of a workflow of something like this:
The ability to initialize the drawing's width and height to None and have the canvas size be autocalculated on output would be cool:
d = draw.Drawing(None, None, origin='center', displayInline=False)
The text was updated successfully, but these errors were encountered: