-
Notifications
You must be signed in to change notification settings - Fork 700
Expand file tree
/
Copy pathpicture.py
More file actions
203 lines (154 loc) · 6.71 KB
/
picture.py
File metadata and controls
203 lines (154 loc) · 6.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
"""Shapes based on the `p:pic` element, including Picture and Movie."""
from __future__ import annotations
from typing import TYPE_CHECKING
from pptx.dml.line import LineFormat
from pptx.enum.shapes import MSO_SHAPE, MSO_SHAPE_TYPE, PP_MEDIA_TYPE
from pptx.shapes.base import BaseShape
from pptx.shared import ParentedElementProxy
from pptx.util import lazyproperty
if TYPE_CHECKING:
from pptx.oxml.shapes.picture import CT_Picture
from pptx.oxml.shapes.shared import CT_LineProperties
from pptx.types import ProvidesPart
class _BasePicture(BaseShape):
"""Base class for shapes based on a `p:pic` element."""
def __init__(self, pic: CT_Picture, parent: ProvidesPart):
super(_BasePicture, self).__init__(pic, parent)
self._pic = pic
@property
def crop_bottom(self) -> float:
"""|float| representing relative portion cropped from shape bottom.
Read/write. 1.0 represents 100%. For example, 25% is represented by 0.25. Negative values
are valid as are values greater than 1.0.
"""
return self._pic.srcRect_b
@crop_bottom.setter
def crop_bottom(self, value: float):
self._pic.srcRect_b = value
@property
def crop_left(self) -> float:
"""|float| representing relative portion cropped from left of shape.
Read/write. 1.0 represents 100%. A negative value extends the side beyond the image
boundary.
"""
return self._pic.srcRect_l
@crop_left.setter
def crop_left(self, value: float):
self._pic.srcRect_l = value
@property
def crop_right(self) -> float:
"""|float| representing relative portion cropped from right of shape.
Read/write. 1.0 represents 100%.
"""
return self._pic.srcRect_r
@crop_right.setter
def crop_right(self, value: float):
self._pic.srcRect_r = value
@property
def crop_top(self) -> float:
"""|float| representing relative portion cropped from shape top.
Read/write. 1.0 represents 100%.
"""
return self._pic.srcRect_t
@crop_top.setter
def crop_top(self, value: float):
self._pic.srcRect_t = value
def get_or_add_ln(self):
"""Return the `a:ln` element for this `p:pic`-based image.
The `a:ln` element contains the line format properties XML.
"""
return self._pic.get_or_add_ln()
@lazyproperty
def line(self) -> LineFormat:
"""Provides access to properties of the picture outline, such as its color and width."""
return LineFormat(self)
@property
def ln(self) -> CT_LineProperties | None:
"""The `a:ln` element for this `p:pic`.
Contains the line format properties such as line color and width. |None| if no `a:ln`
element is present.
"""
return self._pic.ln
class Movie(_BasePicture):
"""A movie shape, one that places a video on a slide.
Like |Picture|, a movie shape is based on the `p:pic` element. A movie is composed of a video
and a *poster frame*, the placeholder image that represents the video before it is played.
"""
@lazyproperty
def media_format(self) -> _MediaFormat:
"""The |_MediaFormat| object for this movie.
The |_MediaFormat| object provides access to formatting properties for the movie.
"""
return _MediaFormat(self._pic, self)
@property
def media_type(self) -> PP_MEDIA_TYPE:
"""Member of :ref:`PpMediaType` describing this shape.
The return value is unconditionally `PP_MEDIA_TYPE.MOVIE` in this case.
"""
return PP_MEDIA_TYPE.MOVIE
@property
def poster_frame(self):
"""Return |Image| object containing poster frame for this movie.
Returns |None| if this movie has no poster frame (uncommon).
"""
slide_part, rId = self.part, self._pic.blip_rId
if rId is None:
return None
return slide_part.get_image(rId)
@property
def shape_type(self) -> MSO_SHAPE_TYPE:
"""Return member of :ref:`MsoShapeType` describing this shape.
The return value is unconditionally `MSO_SHAPE_TYPE.MEDIA` in this
case.
"""
return MSO_SHAPE_TYPE.MEDIA
class Picture(_BasePicture):
"""A picture shape, one that places an image on a slide.
Based on the `p:pic` element.
"""
@property
def auto_shape_type(self) -> MSO_SHAPE | None:
"""Member of MSO_SHAPE indicating masking shape.
A picture can be masked by any of the so-called "auto-shapes" available in PowerPoint,
such as an ellipse or triangle. When a picture is masked by a shape, the shape assumes the
same dimensions as the picture and the portion of the picture outside the shape boundaries
does not appear. Note the default value for a newly-inserted picture is
`MSO_AUTO_SHAPE_TYPE.RECTANGLE`, which performs no cropping because the extents of the
rectangle exactly correspond to the extents of the picture.
The available shapes correspond to the members of :ref:`MsoAutoShapeType`.
The return value can also be |None|, indicating the picture either has no geometry (not
expected) or has custom geometry, like a freeform shape. A picture with no geometry will
have no visible representation on the slide, although it can be selected. This is because
without geometry, there is no "inside-the-shape" for it to appear in.
"""
prstGeom = self._pic.spPr.prstGeom
if prstGeom is None: # ---generally means cropped with freeform---
return None
return prstGeom.prst
@auto_shape_type.setter
def auto_shape_type(self, member: MSO_SHAPE):
MSO_SHAPE.validate(member)
spPr = self._pic.spPr
prstGeom = spPr.prstGeom
if prstGeom is None:
spPr._remove_custGeom() # pyright: ignore[reportPrivateUsage]
prstGeom = spPr._add_prstGeom() # pyright: ignore[reportPrivateUsage]
prstGeom.prst = member
@property
def image(self):
"""The |Image| object for this picture.
Provides access to the properties and bytes of the image in this picture shape.
"""
slide_part, rId = self.part, self._pic.svg_rId or self._pic.blip_rId
if rId is None:
raise ValueError("no embedded image")
return slide_part.get_image(rId)
@property
def shape_type(self) -> MSO_SHAPE_TYPE:
"""Unconditionally `MSO_SHAPE_TYPE.PICTURE` in this case."""
return MSO_SHAPE_TYPE.PICTURE
class _MediaFormat(ParentedElementProxy):
"""Provides access to formatting properties for a Media object.
Media format properties are things like start point, volume, and
compression type.
"""