diff options
Diffstat (limited to '.venv/lib/python3.12/site-packages/pptx/oxml/shapes/picture.py')
-rw-r--r-- | .venv/lib/python3.12/site-packages/pptx/oxml/shapes/picture.py | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/pptx/oxml/shapes/picture.py b/.venv/lib/python3.12/site-packages/pptx/oxml/shapes/picture.py new file mode 100644 index 00000000..bacc9719 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/pptx/oxml/shapes/picture.py @@ -0,0 +1,270 @@ +"""lxml custom element classes for picture-related XML elements.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, cast +from xml.sax.saxutils import escape + +from pptx.oxml import parse_xml +from pptx.oxml.ns import nsdecls +from pptx.oxml.shapes.shared import BaseShapeElement +from pptx.oxml.xmlchemy import BaseOxmlElement, OneAndOnlyOne + +if TYPE_CHECKING: + from pptx.oxml.shapes.shared import CT_ShapeProperties + from pptx.util import Length + + +class CT_Picture(BaseShapeElement): + """`p:pic` element. + + Represents a picture shape (an image placement on a slide). + """ + + nvPicPr = OneAndOnlyOne("p:nvPicPr") + blipFill = OneAndOnlyOne("p:blipFill") + spPr: CT_ShapeProperties = OneAndOnlyOne("p:spPr") # pyright: ignore[reportAssignmentType] + + @property + def blip_rId(self) -> str | None: + """Value of `p:blipFill/a:blip/@r:embed`. + + Returns |None| if not present. + """ + blip = self.blipFill.blip + if blip is not None and blip.rEmbed is not None: + return blip.rEmbed + return None + + def crop_to_fit(self, image_size, view_size): + """ + Set cropping values in `p:blipFill/a:srcRect` such that an image of + *image_size* will stretch to exactly fit *view_size* when its aspect + ratio is preserved. + """ + self.blipFill.crop(self._fill_cropping(image_size, view_size)) + + def get_or_add_ln(self): + """ + Return the <a:ln> grandchild element, newly added if not present. + """ + return self.spPr.get_or_add_ln() + + @property + def ln(self): + """ + ``<a:ln>`` grand-child element or |None| if not present + """ + return self.spPr.ln + + @classmethod + def new_ph_pic(cls, id_, name, desc, rId): + """ + Return a new `p:pic` placeholder element populated with the supplied + parameters. + """ + return parse_xml(cls._pic_ph_tmpl() % (id_, name, desc, rId)) + + @classmethod + def new_pic(cls, shape_id, name, desc, rId, x, y, cx, cy): + """Return new `<p:pic>` element tree configured with supplied parameters.""" + return parse_xml(cls._pic_tmpl() % (shape_id, name, escape(desc), rId, x, y, cx, cy)) + + @classmethod + def new_video_pic( + cls, + shape_id: int, + shape_name: str, + video_rId: str, + media_rId: str, + poster_frame_rId: str, + x: Length, + y: Length, + cx: Length, + cy: Length, + ) -> CT_Picture: + """Return a new `p:pic` populated with the specified video.""" + return cast( + CT_Picture, + parse_xml( + cls._pic_video_tmpl() + % ( + shape_id, + shape_name, + video_rId, + media_rId, + poster_frame_rId, + x, + y, + cx, + cy, + ) + ), + ) + + @property + def srcRect_b(self): + """Value of `p:blipFill/a:srcRect/@b` or 0.0 if not present.""" + return self._srcRect_x("b") + + @srcRect_b.setter + def srcRect_b(self, value): + self.blipFill.get_or_add_srcRect().b = value + + @property + def srcRect_l(self): + """Value of `p:blipFill/a:srcRect/@l` or 0.0 if not present.""" + return self._srcRect_x("l") + + @srcRect_l.setter + def srcRect_l(self, value): + self.blipFill.get_or_add_srcRect().l = value # noqa + + @property + def srcRect_r(self): + """Value of `p:blipFill/a:srcRect/@r` or 0.0 if not present.""" + return self._srcRect_x("r") + + @srcRect_r.setter + def srcRect_r(self, value): + self.blipFill.get_or_add_srcRect().r = value + + @property + def srcRect_t(self): + """Value of `p:blipFill/a:srcRect/@t` or 0.0 if not present.""" + return self._srcRect_x("t") + + @srcRect_t.setter + def srcRect_t(self, value): + self.blipFill.get_or_add_srcRect().t = value + + def _fill_cropping(self, image_size, view_size): + """ + Return a (left, top, right, bottom) 4-tuple containing the cropping + values required to display an image of *image_size* in *view_size* + when stretched proportionately. Each value is a percentage expressed + as a fraction of 1.0, e.g. 0.425 represents 42.5%. *image_size* and + *view_size* are each (width, height) pairs. + """ + + def aspect_ratio(width, height): + return width / height + + ar_view = aspect_ratio(*view_size) + ar_image = aspect_ratio(*image_size) + + if ar_view < ar_image: # image too wide + crop = (1.0 - (ar_view / ar_image)) / 2.0 + return (crop, 0.0, crop, 0.0) + if ar_view > ar_image: # image too tall + crop = (1.0 - (ar_image / ar_view)) / 2.0 + return (0.0, crop, 0.0, crop) + return (0.0, 0.0, 0.0, 0.0) + + @classmethod + def _pic_ph_tmpl(cls): + return ( + "<p:pic %s>\n" + " <p:nvPicPr>\n" + ' <p:cNvPr id="%%d" name="%%s" descr="%%s"/>\n' + " <p:cNvPicPr>\n" + ' <a:picLocks noGrp="1" noChangeAspect="1"/>\n' + " </p:cNvPicPr>\n" + " <p:nvPr/>\n" + " </p:nvPicPr>\n" + " <p:blipFill>\n" + ' <a:blip r:embed="%%s"/>\n' + " <a:stretch>\n" + " <a:fillRect/>\n" + " </a:stretch>\n" + " </p:blipFill>\n" + " <p:spPr/>\n" + "</p:pic>" % nsdecls("p", "a", "r") + ) + + @classmethod + def _pic_tmpl(cls): + return ( + "<p:pic %s>\n" + " <p:nvPicPr>\n" + ' <p:cNvPr id="%%d" name="%%s" descr="%%s"/>\n' + " <p:cNvPicPr>\n" + ' <a:picLocks noChangeAspect="1"/>\n' + " </p:cNvPicPr>\n" + " <p:nvPr/>\n" + " </p:nvPicPr>\n" + " <p:blipFill>\n" + ' <a:blip r:embed="%%s"/>\n' + " <a:stretch>\n" + " <a:fillRect/>\n" + " </a:stretch>\n" + " </p:blipFill>\n" + " <p:spPr>\n" + " <a:xfrm>\n" + ' <a:off x="%%d" y="%%d"/>\n' + ' <a:ext cx="%%d" cy="%%d"/>\n' + " </a:xfrm>\n" + ' <a:prstGeom prst="rect">\n' + " <a:avLst/>\n" + " </a:prstGeom>\n" + " </p:spPr>\n" + "</p:pic>" % nsdecls("a", "p", "r") + ) + + @classmethod + def _pic_video_tmpl(cls): + return ( + "<p:pic %s>\n" + " <p:nvPicPr>\n" + ' <p:cNvPr id="%%d" name="%%s">\n' + ' <a:hlinkClick r:id="" action="ppaction://media"/>\n' + " </p:cNvPr>\n" + " <p:cNvPicPr>\n" + ' <a:picLocks noChangeAspect="1"/>\n' + " </p:cNvPicPr>\n" + " <p:nvPr>\n" + ' <a:videoFile r:link="%%s"/>\n' + " <p:extLst>\n" + ' <p:ext uri="{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}">\n' + ' <p14:media xmlns:p14="http://schemas.microsoft.com/of' + 'fice/powerpoint/2010/main" r:embed="%%s"/>\n' + " </p:ext>\n" + " </p:extLst>\n" + " </p:nvPr>\n" + " </p:nvPicPr>\n" + " <p:blipFill>\n" + ' <a:blip r:embed="%%s"/>\n' + " <a:stretch>\n" + " <a:fillRect/>\n" + " </a:stretch>\n" + " </p:blipFill>\n" + " <p:spPr>\n" + " <a:xfrm>\n" + ' <a:off x="%%d" y="%%d"/>\n' + ' <a:ext cx="%%d" cy="%%d"/>\n' + " </a:xfrm>\n" + ' <a:prstGeom prst="rect">\n' + " <a:avLst/>\n" + " </a:prstGeom>\n" + " </p:spPr>\n" + "</p:pic>" % nsdecls("a", "p", "r") + ) + + def _srcRect_x(self, attr_name): + """ + Value of `p:blipFill/a:srcRect/@{attr_name}` or 0.0 if not present. + """ + srcRect = self.blipFill.srcRect + if srcRect is None: + return 0.0 + return getattr(srcRect, attr_name) + + +class CT_PictureNonVisual(BaseOxmlElement): + """ + ``<p:nvPicPr>`` element, containing non-visual properties for a picture + shape. + """ + + cNvPr = OneAndOnlyOne("p:cNvPr") + nvPr = OneAndOnlyOne("p:nvPr") |