Skip to content

Commit 158a78e

Browse files
author
Steve Canny
committed
doc: refactor Document.add_picture()
Use Run.add_picture() to do the heavy lifting.
1 parent d7001ed commit 158a78e

File tree

2 files changed

+34
-51
lines changed

2 files changed

+34
-51
lines changed

docx/api.py

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -78,31 +78,19 @@ def add_paragraph(self, text='', style=None):
7878

7979
def add_picture(self, image_path_or_stream, width=None, height=None):
8080
"""
81-
Add the image at *image_path_or_stream* in a new paragraph at the end
82-
of the document. If neither width nor height is specified, the
83-
picture appears at its native size. If only one is specified, it is
84-
used to compute a scaling factor that is then applied to the
85-
unspecified dimension, preserving the aspect ratio of the image. The
86-
native size of the picture is calculated using the dots-per-inch
87-
(dpi) value specified in the image file, defaulting to 72 dpi if no
88-
value is specified, as is often the case.
81+
Return a new picture shape added in its own paragraph at the end of
82+
the document. The picture contains the image at
83+
*image_path_or_stream*, scaled based on *width* and *height*. If
84+
neither width nor height is specified, the picture appears at its
85+
native size. If only one is specified, it is used to compute
86+
a scaling factor that is then applied to the unspecified dimension,
87+
preserving the aspect ratio of the image. The native size of the
88+
picture is calculated using the dots-per-inch (dpi) value specified
89+
in the image file, defaulting to 72 dpi if no value is specified, as
90+
is often the case.
8991
"""
9092
run = self.add_paragraph().add_run()
91-
picture = self.inline_shapes.add_picture(image_path_or_stream, run)
92-
93-
# scale picture dimensions if width and/or height provided
94-
if width is not None or height is not None:
95-
native_width, native_height = picture.width, picture.height
96-
if width is None:
97-
scaling_factor = float(height) / float(native_height)
98-
width = int(round(native_width * scaling_factor))
99-
elif height is None:
100-
scaling_factor = float(width) / float(native_width)
101-
height = int(round(native_height * scaling_factor))
102-
# set picture to scaled dimensions
103-
picture.width = width
104-
picture.height = height
105-
93+
picture = run.add_picture(image_path_or_stream, width, height)
10694
return picture
10795

10896
def add_section(self, start_type=WD_SECTION.NEW_PAGE):

tests/test_api.py

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@
1818
from docx.parts.numbering import NumberingPart
1919
from docx.parts.styles import StylesPart
2020
from docx.section import Section
21+
from docx.shape import InlineShape
2122
from docx.table import Table
2223
from docx.text import Paragraph, Run
2324

2425
from .unitutil.mock import (
25-
ANY, instance_mock, class_mock, method_mock, property_mock, var_mock
26+
instance_mock, class_mock, method_mock, property_mock, var_mock
2627
)
2728

2829

@@ -90,12 +91,11 @@ def it_can_add_a_page_break(self, add_page_break_fixture):
9091
assert paragraph is paragraph_
9192

9293
def it_can_add_a_picture(self, add_picture_fixture):
93-
(document, image_path, width, height, inline_shapes_, expected_width,
94-
expected_height, picture_) = add_picture_fixture
95-
picture = document.add_picture(image_path, width, height)
96-
inline_shapes_.add_picture.assert_called_once_with(image_path, ANY)
97-
assert picture.width == expected_width
98-
assert picture.height == expected_height
94+
document, image_path_, width, height, run_, picture_ = (
95+
add_picture_fixture
96+
)
97+
picture = document.add_picture(image_path_, width, height)
98+
run_.add_picture.assert_called_once_with(image_path_, width, height)
9999
assert picture is picture_
100100

101101
def it_can_add_a_section(self, add_section_fixture):
@@ -195,23 +195,14 @@ def add_page_break_fixture(
195195
self, document, document_part_, paragraph_, run_):
196196
return document, document_part_, paragraph_, run_
197197

198-
@pytest.fixture(params=[
199-
(None, None, 200, 100),
200-
(1000, 500, 1000, 500),
201-
(2000, None, 2000, 1000),
202-
(None, 2000, 4000, 2000),
203-
])
204-
def add_picture_fixture(
205-
self, request, Document_inline_shapes_, inline_shapes_):
206-
width, height, expected_width, expected_height = request.param
198+
@pytest.fixture
199+
def add_picture_fixture(self, request, run_, picture_):
207200
document = Document()
208201
image_path_ = instance_mock(request, str, name='image_path_')
209-
picture_ = inline_shapes_.add_picture.return_value
210-
picture_.width, picture_.height = 200, 100
211-
return (
212-
document, image_path_, width, height, inline_shapes_,
213-
expected_width, expected_height, picture_
214-
)
202+
width, height = 100, 200
203+
class_mock(request, 'docx.text.Run', return_value=run_)
204+
run_.add_picture.return_value = picture_
205+
return (document, image_path_, width, height, run_, picture_)
215206

216207
@pytest.fixture
217208
def add_section_fixture(self, document, start_type_, section_):
@@ -330,12 +321,6 @@ def open_(self, request, document_part_, package_):
330321
return_value=(document_part_, package_)
331322
)
332323

333-
@pytest.fixture
334-
def paragraph_(self, request, run_):
335-
paragraph_ = instance_mock(request, Paragraph)
336-
paragraph_.add_run.return_value = run_
337-
return paragraph_
338-
339324
@pytest.fixture
340325
def Package_(self, request, package_):
341326
Package_ = class_mock(request, 'docx.api.Package')
@@ -348,10 +333,20 @@ def package_(self, request, document_part_):
348333
package_.main_document = document_part_
349334
return package_
350335

336+
@pytest.fixture
337+
def paragraph_(self, request, run_):
338+
paragraph_ = instance_mock(request, Paragraph)
339+
paragraph_.add_run.return_value = run_
340+
return paragraph_
341+
351342
@pytest.fixture
352343
def paragraphs_(self, request):
353344
return instance_mock(request, list)
354345

346+
@pytest.fixture
347+
def picture_(self, request):
348+
return instance_mock(request, InlineShape)
349+
355350
@pytest.fixture
356351
def run_(self, request):
357352
return instance_mock(request, Run)

0 commit comments

Comments
 (0)