ppt function to replace images

This commit is contained in:
2026-01-29 15:36:34 +01:00
parent bc12df28a5
commit 3ee25f9e33
6 changed files with 326 additions and 96 deletions

View File

@@ -8,6 +8,89 @@ from plots import JPMCPlotsMixin
import marimo as mo
from pptx import Presentation
from pptx.enum.shapes import MSO_SHAPE_TYPE
def pptx_replace_named_image(presentation_path, target_tag, new_image_path, save_path):
"""
Finds and replaces specific images in a PowerPoint presentation while
preserving their original position, size, and aspect ratio.
This function performs a 'surgical' replacement: it records the coordinates
of the existing image, removes it from the slide's XML, and inserts a
new image into the exact same bounding box. It identifies the target
image by searching for a specific string within the Shape Name
(Selection Pane) or Alt Text.
Args:
presentation_path (str): The file path to the source .pptx file.
target_tag (str): The unique identifier to look for (e.g., 'HERO_IMAGE').
This is case-sensitive and checks both the shape name and alt text.
new_image_path (str): The file path to the new image (PNG, JPG, etc.).
save_path (str): The file path where the modified presentation will be saved.
Returns:
None: Saves the file directly to the provided save_path.
Raises:
FileNotFoundError: If the source presentation or new image is not found.
PermissionError: If the save_path is currently open or locked.
"""
prs = Presentation(presentation_path)
for i, slide in enumerate(prs.slides):
# Iterate over a list copy of shapes to safely modify the slide during iteration
print(f"Processing Slide {i + 1}...")
print(f"Total Shapes: {len(slide.shapes)} shapes")
for shape in list(slide.shapes):
print(f"Checking shape: {shape.name} of type {shape.shape_type}...")
shape_name = shape.name or ""
alt_text = ""
# More robust strategy: Check for alt text in ANY valid element property
# This allows replacing Pictures, Placeholders, GraphicFrames, etc.
try:
# Check for common property names used by python-pptx elements to store non-visual props
# nvPicPr (Picture), nvSpPr (Shape/Placeholder), nvGrpSpPr (Group),
# nvGraphicFramePr (GraphicFrame), nvCxnSpPr (Connector)
nvPr = None
for attr in ['nvPicPr', 'nvSpPr', 'nvGrpSpPr', 'nvGraphicFramePr', 'nvCxnSpPr']:
if hasattr(shape._element, attr):
nvPr = getattr(shape._element, attr)
break
if nvPr is not None and hasattr(nvPr, 'cNvPr'):
alt_text = nvPr.cNvPr.get("descr", "")
except Exception:
pass
print(f"Alt Text for shape '{shape_name}': {alt_text}")
if target_tag in shape_name or target_tag in alt_text:
print(f"Found it! Replacing {shape_name}...")
try:
# Record coordinates
left, top, width, height = shape.left, shape.top, shape.width, shape.height
# Remove old shape
old_element = shape._element
old_element.getparent().remove(old_element)
# Add new image at the same spot
slide.shapes.add_picture(str(new_image_path), left, top, width, height)
except AttributeError:
print(f"Could not replace {shape_name} - might be missing dimensions.")
else:
print(f"Skipping shape '{shape_name}' with alt text '{alt_text}'")
prs.save(save_path)
print(f"Successfully saved to {save_path}")
def extract_voice_label(html_str: str) -> str:
"""
Extract voice label from HTML string and convert to short format.