Skip to content
This repository was archived by the owner on Jan 7, 2024. It is now read-only.

Commit 35e98da

Browse files
author
Steve Canny
committed
shp: add InlineShape.new_picture()
1 parent 422c504 commit 35e98da

File tree

8 files changed

+519
-78
lines changed

8 files changed

+519
-78
lines changed

docs/dev/analysis/features/picture.rst

Lines changed: 85 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -114,22 +114,10 @@ Schema definitions
114114
</xsd:sequence>
115115
</xsd:complexType>
116116

117-
<xsd:complexType name="CT_PictureNonVisual">
118-
<xsd:sequence>
119-
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps"/>
120-
<xsd:element name="cNvPicPr" type="a:CT_NonVisualPictureProperties"/>
121-
</xsd:sequence>
122-
</xsd:complexType>
123-
124-
<xsd:complexType name="CT_BlipFillProperties">
125-
<xsd:sequence>
126-
<xsd:element name="blip" type="CT_Blip" minOccurs="0"/>
127-
<xsd:element name="srcRect" type="CT_RelativeRect" minOccurs="0"/>
128-
<xsd:group ref="EG_FillModeProperties" minOccurs="0"/>
129-
</xsd:sequence>
130-
<xsd:attribute name="dpi" type="xsd:unsignedInt" use="optional"/>
131-
<xsd:attribute name="rotWithShape" type="xsd:boolean" use="optional"/>
132-
</xsd:complexType>
117+
<xsd:attributeGroup name="AG_Blob">
118+
<xsd:attribute ref="r:embed" use="optional" default=""/>
119+
<xsd:attribute ref="r:link" use="optional" default=""/>
120+
</xsd:attributeGroup>
133121

134122
<xsd:complexType name="CT_Blip">
135123
<xsd:sequence>
@@ -158,44 +146,14 @@ Schema definitions
158146
<xsd:attribute name="cstate" type="ST_BlipCompression" use="optional" default="none"/>
159147
</xsd:complexType>
160148

161-
<xsd:attributeGroup name="AG_Blob">
162-
<xsd:attribute ref="r:embed" use="optional" default=""/>
163-
<xsd:attribute ref="r:link" use="optional" default=""/>
164-
</xsd:attributeGroup>
165-
166-
<xsd:group name="EG_FillModeProperties">
167-
<xsd:choice>
168-
<xsd:element name="tile" type="CT_TileInfoProperties"/>
169-
<xsd:element name="stretch" type="CT_StretchInfoProperties"/>
170-
</xsd:choice>
171-
</xsd:group>
172-
173-
<xsd:complexType name="CT_ShapeProperties">
174-
<xsd:sequence>
175-
<xsd:element name="xfrm" type="CT_Transform2D" minOccurs="0"/>
176-
<xsd:group ref="EG_Geometry" minOccurs="0"/>
177-
<xsd:group ref="EG_FillProperties" minOccurs="0"/>
178-
<xsd:element name="ln" type="CT_LineProperties" minOccurs="0"/>
179-
<xsd:group ref="EG_EffectProperties" minOccurs="0"/>
180-
<xsd:element name="scene3d" type="CT_Scene3D" minOccurs="0"/>
181-
<xsd:element name="sp3d" type="CT_Shape3D" minOccurs="0"/>
182-
<xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0"/>
183-
</xsd:sequence>
184-
<xsd:attribute name="bwMode" type="ST_BlackWhiteMode" use="optional"/>
185-
</xsd:complexType>
186-
187-
<xsd:group name="EG_Geometry">
188-
<xsd:choice>
189-
<xsd:element name="custGeom" type="CT_CustomGeometry2D"/>
190-
<xsd:element name="prstGeom" type="CT_PresetGeometry2D"/>
191-
</xsd:choice>
192-
</xsd:group>
193-
194-
<xsd:complexType name="CT_PresetGeometry2D">
149+
<xsd:complexType name="CT_BlipFillProperties">
195150
<xsd:sequence>
196-
<xsd:element name="avLst" type="CT_GeomGuideList" minOccurs="0"/>
151+
<xsd:element name="blip" type="CT_Blip" minOccurs="0"/>
152+
<xsd:element name="srcRect" type="CT_RelativeRect" minOccurs="0"/>
153+
<xsd:group ref="EG_FillModeProperties" minOccurs="0"/>
197154
</xsd:sequence>
198-
<xsd:attribute name="prst" type="ST_ShapeType" use="required"/>
155+
<xsd:attribute name="dpi" type="xsd:unsignedInt" use="optional"/>
156+
<xsd:attribute name="rotWithShape" type="xsd:boolean" use="optional"/>
199157
</xsd:complexType>
200158

201159
<xsd:complexType name="CT_NonVisualDrawingProps">
@@ -218,3 +176,78 @@ Schema definitions
218176
</xsd:sequence>
219177
<xsd:attribute name="preferRelativeResize" type="xsd:boolean" use="optional" default="true"/>
220178
</xsd:complexType>
179+
180+
<xsd:complexType name="CT_PictureNonVisual">
181+
<xsd:sequence>
182+
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps"/>
183+
<xsd:element name="cNvPicPr" type="a:CT_NonVisualPictureProperties"/>
184+
</xsd:sequence>
185+
</xsd:complexType>
186+
187+
<xsd:complexType name="CT_Point2D">
188+
<xsd:attribute name="x" type="ST_Coordinate" use="required"/>
189+
<xsd:attribute name="y" type="ST_Coordinate" use="required"/>
190+
</xsd:complexType>
191+
192+
<xsd:complexType name="CT_PositiveSize2D">
193+
<xsd:attribute name="cx" type="ST_PositiveCoordinate" use="required"/>
194+
<xsd:attribute name="cy" type="ST_PositiveCoordinate" use="required"/>
195+
</xsd:complexType>
196+
197+
<xsd:complexType name="CT_PresetGeometry2D">
198+
<xsd:sequence>
199+
<xsd:element name="avLst" type="CT_GeomGuideList" minOccurs="0"/>
200+
</xsd:sequence>
201+
<xsd:attribute name="prst" type="ST_ShapeType" use="required"/>
202+
</xsd:complexType>
203+
204+
<xsd:complexType name="CT_RelativeRect">
205+
<xsd:attribute name="l" type="ST_Percentage" use="optional" default="0%"/>
206+
<xsd:attribute name="t" type="ST_Percentage" use="optional" default="0%"/>
207+
<xsd:attribute name="r" type="ST_Percentage" use="optional" default="0%"/>
208+
<xsd:attribute name="b" type="ST_Percentage" use="optional" default="0%"/>
209+
</xsd:complexType>
210+
211+
<xsd:complexType name="CT_ShapeProperties">
212+
<xsd:sequence>
213+
<xsd:element name="xfrm" type="CT_Transform2D" minOccurs="0"/>
214+
<xsd:group ref="EG_Geometry" minOccurs="0"/>
215+
<xsd:group ref="EG_FillProperties" minOccurs="0"/>
216+
<xsd:element name="ln" type="CT_LineProperties" minOccurs="0"/>
217+
<xsd:group ref="EG_EffectProperties" minOccurs="0"/>
218+
<xsd:element name="scene3d" type="CT_Scene3D" minOccurs="0"/>
219+
<xsd:element name="sp3d" type="CT_Shape3D" minOccurs="0"/>
220+
<xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0"/>
221+
</xsd:sequence>
222+
<xsd:attribute name="bwMode" type="ST_BlackWhiteMode" use="optional"/>
223+
</xsd:complexType>
224+
225+
<xsd:complexType name="CT_StretchInfoProperties">
226+
<xsd:sequence>
227+
<xsd:element name="fillRect" type="CT_RelativeRect" minOccurs="0"/>
228+
</xsd:sequence>
229+
</xsd:complexType>
230+
231+
<xsd:complexType name="CT_Transform2D">
232+
<xsd:sequence>
233+
<xsd:element name="off" type="CT_Point2D" minOccurs="0"/>
234+
<xsd:element name="ext" type="CT_PositiveSize2D" minOccurs="0"/>
235+
</xsd:sequence>
236+
<xsd:attribute name="rot" type="ST_Angle" use="optional" default="0"/>
237+
<xsd:attribute name="flipH" type="xsd:boolean" use="optional" default="false"/>
238+
<xsd:attribute name="flipV" type="xsd:boolean" use="optional" default="false"/>
239+
</xsd:complexType>
240+
241+
<xsd:group name="EG_FillModeProperties">
242+
<xsd:choice>
243+
<xsd:element name="tile" type="CT_TileInfoProperties"/>
244+
<xsd:element name="stretch" type="CT_StretchInfoProperties"/>
245+
</xsd:choice>
246+
</xsd:group>
247+
248+
<xsd:group name="EG_Geometry">
249+
<xsd:choice>
250+
<xsd:element name="custGeom" type="CT_CustomGeometry2D"/>
251+
<xsd:element name="prstGeom" type="CT_PresetGeometry2D"/>
252+
</xsd:choice>
253+
</xsd:group>

docx/oxml/shape.py

Lines changed: 180 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
Custom element classes for shape-related elements like ``<w:inline>``
55
"""
66

7-
from docx.oxml.shared import OxmlBaseElement, qn
7+
from docx.oxml.shared import (
8+
nsmap, nspfxmap, OxmlBaseElement, OxmlElement, qn
9+
)
810

911

1012
class CT_Blip(OxmlBaseElement):
@@ -16,6 +18,12 @@ class CT_Blip(OxmlBaseElement):
1618
def link(self):
1719
return self.get(qn('r:link'))
1820

21+
@classmethod
22+
def new(cls, rId):
23+
blip = OxmlElement('a:blip')
24+
blip.set(qn('r:embed'), rId)
25+
return blip
26+
1927

2028
class CT_BlipFillProperties(OxmlBaseElement):
2129
"""
@@ -25,6 +33,13 @@ class CT_BlipFillProperties(OxmlBaseElement):
2533
def blip(self):
2634
return self.find(qn('a:blip'))
2735

36+
@classmethod
37+
def new(cls, rId):
38+
blipFill = OxmlElement('pic:blipFill')
39+
blipFill.append(CT_Blip.new(rId))
40+
blipFill.append(CT_StretchInfoProperties.new())
41+
return blipFill
42+
2843

2944
class CT_GraphicalObject(OxmlBaseElement):
3045
"""
@@ -34,11 +49,24 @@ class CT_GraphicalObject(OxmlBaseElement):
3449
def graphicData(self):
3550
return self.find(qn('a:graphicData'))
3651

52+
@classmethod
53+
def new(cls, uri, pic):
54+
graphic = OxmlElement('a:graphic')
55+
graphic.append(CT_GraphicalObjectData.new(uri, pic))
56+
return graphic
57+
3758

3859
class CT_GraphicalObjectData(OxmlBaseElement):
3960
"""
4061
``<a:graphicData>`` element, container for the XML of a DrawingML object
4162
"""
63+
@classmethod
64+
def new(cls, uri, pic):
65+
graphicData = OxmlElement('a:graphicData')
66+
graphicData.set('uri', uri)
67+
graphicData.append(pic)
68+
return graphicData
69+
4270
@property
4371
def pic(self):
4472
return self.find(qn('pic:pic'))
@@ -56,6 +84,46 @@ class CT_Inline(OxmlBaseElement):
5684
def graphic(self):
5785
return self.find(qn('a:graphic'))
5886

87+
@classmethod
88+
def new(cls, width, height, shape_id, pic):
89+
"""
90+
Return a new ``<wp:inline>`` element populated with the values passed
91+
as parameters.
92+
"""
93+
name = 'Picture %d' % shape_id
94+
uri = nsmap['pic']
95+
96+
inline = OxmlElement('wp:inline', nsmap=nspfxmap('wp', 'r'))
97+
inline.append(CT_PositiveSize2D.new('wp:extent', width, height))
98+
inline.append(CT_NonVisualDrawingProps.new(
99+
'wp:docPr', shape_id, name
100+
))
101+
inline.append(CT_GraphicalObject.new(uri, pic))
102+
return inline
103+
104+
105+
class CT_NonVisualDrawingProps(OxmlBaseElement):
106+
"""
107+
Used for ``<wp:docPr>`` element, and perhaps others. Specifies the id and
108+
name of a DrawingML drawing.
109+
"""
110+
@classmethod
111+
def new(cls, nsptagname_str, shape_id, name):
112+
elt = OxmlElement(nsptagname_str)
113+
elt.set('id', str(shape_id))
114+
elt.set('name', name)
115+
return elt
116+
117+
118+
class CT_NonVisualPictureProperties(OxmlBaseElement):
119+
"""
120+
``<pic:cNvPicPr>`` element, specifies picture locking and resize
121+
behaviors.
122+
"""
123+
@classmethod
124+
def new(cls):
125+
return OxmlElement('pic:cNvPicPr')
126+
59127

60128
class CT_Picture(OxmlBaseElement):
61129
"""
@@ -64,3 +132,114 @@ class CT_Picture(OxmlBaseElement):
64132
@property
65133
def blipFill(self):
66134
return self.find(qn('pic:blipFill'))
135+
136+
@classmethod
137+
def new(cls, pic_id, filename, rId, cx, cy):
138+
"""
139+
Return a new ``<pic:pic>`` element populated with the minimal
140+
contents required to define a viable picture element, based on the
141+
values passed as parameters.
142+
"""
143+
pic = OxmlElement('pic:pic', nsmap=nspfxmap('pic', 'r'))
144+
pic.append(CT_PictureNonVisual.new(pic_id, filename))
145+
pic.append(CT_BlipFillProperties.new(rId))
146+
pic.append(CT_ShapeProperties.new(cx, cy))
147+
return pic
148+
149+
150+
class CT_PictureNonVisual(OxmlBaseElement):
151+
"""
152+
``<pic:nvPicPr>`` element, non-visual picture properties
153+
"""
154+
@classmethod
155+
def new(cls, pic_id, image_filename):
156+
nvPicPr = OxmlElement('pic:nvPicPr')
157+
nvPicPr.append(CT_NonVisualDrawingProps.new(
158+
'pic:cNvPr', pic_id, image_filename
159+
))
160+
nvPicPr.append(CT_NonVisualPictureProperties.new())
161+
return nvPicPr
162+
163+
164+
class CT_Point2D(OxmlBaseElement):
165+
"""
166+
Used for ``<a:off>`` element, and perhaps others. Specifies an x, y
167+
coordinate (point).
168+
"""
169+
@classmethod
170+
def new(cls, nsptagname_str, x, y):
171+
elm = OxmlElement(nsptagname_str)
172+
elm.set('x', str(x))
173+
elm.set('y', str(y))
174+
return elm
175+
176+
177+
class CT_PositiveSize2D(OxmlBaseElement):
178+
"""
179+
Used for ``<wp:extent>`` element, and perhaps others later. Specifies the
180+
size of a DrawingML drawing.
181+
"""
182+
@classmethod
183+
def new(cls, nsptagname_str, cx, cy):
184+
elt = OxmlElement(nsptagname_str)
185+
elt.set('cx', str(cx))
186+
elt.set('cy', str(cy))
187+
return elt
188+
189+
190+
class CT_PresetGeometry2D(OxmlBaseElement):
191+
"""
192+
``<a:prstGeom>`` element, specifies an preset autoshape geometry, such
193+
as ``rect``.
194+
"""
195+
@classmethod
196+
def new(cls, prst):
197+
prstGeom = OxmlElement('a:prstGeom')
198+
prstGeom.set('prst', prst)
199+
return prstGeom
200+
201+
202+
class CT_RelativeRect(OxmlBaseElement):
203+
"""
204+
``<a:fillRect>`` element, specifying picture should fill containing
205+
rectangle shape.
206+
"""
207+
@classmethod
208+
def new(cls):
209+
return OxmlElement('a:fillRect')
210+
211+
212+
class CT_ShapeProperties(OxmlBaseElement):
213+
"""
214+
``<pic:spPr>`` element, specifies size and shape of picture container.
215+
"""
216+
@classmethod
217+
def new(cls, cx, cy):
218+
spPr = OxmlElement('pic:spPr')
219+
spPr.append(CT_Transform2D.new(cx, cy))
220+
spPr.append(CT_PresetGeometry2D.new('rect'))
221+
return spPr
222+
223+
224+
class CT_StretchInfoProperties(OxmlBaseElement):
225+
"""
226+
``<a:stretch>`` element, specifies how picture should fill its containing
227+
shape.
228+
"""
229+
@classmethod
230+
def new(cls):
231+
stretch = OxmlElement('a:stretch')
232+
stretch.append(CT_RelativeRect.new())
233+
return stretch
234+
235+
236+
class CT_Transform2D(OxmlBaseElement):
237+
"""
238+
``<a:xfrm>`` element, specifies size and shape of picture container.
239+
"""
240+
@classmethod
241+
def new(cls, cx, cy):
242+
spPr = OxmlElement('a:xfrm')
243+
spPr.append(CT_Point2D.new('a:off', 0, 0))
244+
spPr.append(CT_PositiveSize2D.new('a:ext', cx, cy))
245+
return spPr

docx/oxml/shared.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@ def nsdecls(*prefixes):
8484
return ' '.join(['xmlns:%s="%s"' % (pfx, nsmap[pfx]) for pfx in prefixes])
8585

8686

87+
def nspfxmap(*nspfxs):
88+
"""
89+
Return a dict containing the subset namespace prefix mappings specified by
90+
*nspfxs*. Any number of namespace prefixes can be supplied, e.g.
91+
namespaces('a', 'r', 'p').
92+
"""
93+
return dict((pfx, nsmap[pfx]) for pfx in nspfxs)
94+
95+
8796
def OxmlElement(nsptag_str, attrs=None, nsmap=None):
8897
"""
8998
Return a 'loose' lxml element having the tag specified by *nsptag_str*.

0 commit comments

Comments
 (0)