-
Notifications
You must be signed in to change notification settings - Fork 493
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
Ability to duplicate a shape #533
Comments
Note I'd quite like to help with implementing this if it's seen as appropriate, although I've never contributed to an open source project before so may need some help! |
This would be a great feature to have. Looks like someone tried to implement a 'shape_clone()' method in the past. No idea if it works. #307 Might be a good starting point? |
I think a key first question would be whether the shape is free-form or just selected from one of the 168-or-so preset shapes like rectangle and star. If it's a free-form shape with only straight-line segments, you could just store vertices and use the existing free-form shape API. Also, each autoshape (i.e. rect or star or whatever but not picture or line) has its own textframe, so you may not need to have a separate textbox shape. You may need to do some hacking to get the text to show outside the shape bounds though. Copying a shape is generally easily done with a import copy
from pptx.shapes.autoshape import Shape
def clone_shape(shape):
"""Add a duplicate of `shape` to the slide on which it appears."""
# ---access required XML elements---
sp = shape._sp
spTree = sp.getparent()
# ---clone shape element---
new_sp = copy.deepcopy(sp)
# ---add it to slide---
spTree.append(new_sp)
# ---create a proxy object for the new sp element---
new_shape = Shape(new_sp, None)
# ---give it a unique shape-id---
new_shape.shape_id = shape.shape_id + 1000
# ---return the new proxy object---
return new_shape The key thing is to maintain unique shape-ids for each shape, otherwise you get a repair error. Hyperlinks on shapes or embedded in shape text can also be a problem requiring more sophisticated solutions, but as long as you avoid those a solution like this should work. Also, if the shape is a child of a group-shape you'll need something more sophisticated. |
@scanny : i wanted to duplicate |
@scanny : also, https://sourcegraph.com/github.com/scanny/python-pptx/-/blob/pptx/shapes/base.py#L180 |
never mind, i modified the above function like this and it worked def clone_shape(shape, left, top, width, height):
"""Add a duplicate of `shape` to the slide on which it appears."""
shape_obj = shape.element
sp_tree = shape_obj.getparent()
new_sp = copy.deepcopy(shape_obj)
sp_tree.append(new_sp)
new_shape = (
GraphicFrame(new_sp, None)
if isinstance(shape, GraphicFrame)
else Shape(new_sp, None)
)
new_shape.left = left
new_shape.top = top
new_shape.width = width
new_shape.height = height
return new_shape |
@scanny : my above code throwing repair error, is there any way to add shape_id to new_shape ?? i tried to set by also referring to your code above, |
@scanny : i am assuming that setting shape_id is not possible as there might have some design issues hence it was set as read-only attribute. Is there a way to add a table to the slide using the same properties of existing table so that new table should look exactly like the previous one ??? something like this existing_table = slide_obj.shapes[2]
properties = get_properties(existing_table) # some imaginary function
new_table = slide_obj.shapes.add_table(**properties) |
to sum-up my issue, i have a table in a slide, i want to add a copy of that table adjacent to it... i tried above so, now i came up with this code import copy
import Renderer
# Renderer is my class which has text renderer,
# table renderer etc and also it has some utility
# methods such as _get_slide_by_id etc...
obj = Renderer("/path/to/my/template.pptx")
slide = obj._get_slide_by_id(317)
shape = obj._get_shape_by_id(slide, 13)
new_shape = slide.shapes.add_table(
len(shape.table.rows),
len(shape.table.columns),
shape.width + shape.left,
shape.top,
shape.width,
shape.height,
)
new_shape._element = copy.deepcopy(shape._element)
obj.save("/tmp/sample.pptx") but the table properties are not copied to the new shape, i even tried new_shape.table._tbl = copy.deepcopy(shape.table._tbl)
new_shape.table._graphic_frame = copy.deepcopy(shape.table._graphic_frame) can anyone help |
#589 i forked this repo and did these changes, with this it's working |
My use case is that I want to use a shape created by the user as a template for other shapes created programmatically. Specifically I am generating a timeline from a spreadsheet and each point in the timeline comprises a milestone shape, a text box and a line which drops down to the date.
I want the user to design and format each of the template shapes and then my programme will duplicate the shapes for each point on the timeline, so retaining all the color, size, shape type and other attributes.
I am having to explicitly read all the formatting information from the shape, store it and then create a brand new shape and then apply all the attributes, so I am probably duplicating quite a lot of the work that would need to be done in duplicating a shape.
The text was updated successfully, but these errors were encountered: