Skip to content

Commit c8e0a4f

Browse files
author
Steve Canny
committed
img: add _PngParser.horz_dpi and .vert_dpi
1 parent b196d4b commit c8e0a4f

2 files changed

Lines changed: 56 additions & 32 deletions

File tree

docx/image/png.py

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -40,36 +40,6 @@ def from_stream(cls, stream):
4040

4141
return cls(px_width, px_height, horz_dpi, vert_dpi)
4242

43-
@property
44-
def horz_dpi(self):
45-
"""
46-
Integer dots per inch for the width of this image. Defaults to 72
47-
when not present in the file, as is often the case.
48-
"""
49-
units_specifier = self._attrs.get(TAG.UNITS_SPECIFIER)
50-
horz_px_per_unit = self._attrs.get(TAG.HORZ_PX_PER_UNIT)
51-
return self._dpi(units_specifier, horz_px_per_unit)
52-
53-
@property
54-
def vert_dpi(self):
55-
"""
56-
Integer dots per inch for the height of this image. Defaults to 72
57-
when not present in the file, as is often the case.
58-
"""
59-
units_specifier = self._attrs.get(TAG.UNITS_SPECIFIER)
60-
vert_px_per_unit = self._attrs.get(TAG.VERT_PX_PER_UNIT)
61-
return self._dpi(units_specifier, vert_px_per_unit)
62-
63-
@staticmethod
64-
def _dpi(units_specifier, px_per_unit):
65-
"""
66-
Return dots per inch value calculated from *units_specifier* and
67-
*px_per_unit*.
68-
"""
69-
if units_specifier == 1 and px_per_unit is not None:
70-
return int(round(px_per_unit * 0.0254))
71-
return 72
72-
7343
@classmethod
7444
def _parse_png_headers(cls, stream):
7545
"""
@@ -202,15 +172,31 @@ def horz_dpi(self):
202172
Integer dots per inch for the width of this image. Defaults to 72
203173
when not present in the file, as is often the case.
204174
"""
205-
raise NotImplementedError
175+
pHYs = self._chunks.pHYs
176+
if pHYs is None:
177+
return 72
178+
return self._dpi(pHYs.units_specifier, pHYs.horz_px_per_unit)
206179

207180
@property
208181
def vert_dpi(self):
209182
"""
210183
Integer dots per inch for the height of this image. Defaults to 72
211184
when not present in the file, as is often the case.
212185
"""
213-
raise NotImplementedError
186+
pHYs = self._chunks.pHYs
187+
if pHYs is None:
188+
return 72
189+
return self._dpi(pHYs.units_specifier, pHYs.vert_px_per_unit)
190+
191+
@staticmethod
192+
def _dpi(units_specifier, px_per_unit):
193+
"""
194+
Return dots per inch value calculated from *units_specifier* and
195+
*px_per_unit*.
196+
"""
197+
if units_specifier == 1 and px_per_unit:
198+
return int(round(px_per_unit * 0.0254))
199+
return 72
214200

215201

216202
class _Chunks(object):

tests/image/test_png.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,16 @@ def it_knows_the_image_width_and_height(self, dimensions_fixture):
271271
assert png_parser.px_width == px_width
272272
assert png_parser.px_height == px_height
273273

274+
def it_knows_the_image_dpi(self, dpi_fixture):
275+
png_parser, horz_dpi, vert_dpi = dpi_fixture
276+
assert png_parser.horz_dpi == horz_dpi
277+
assert png_parser.vert_dpi == vert_dpi
278+
279+
def it_defaults_image_dpi_to_72(self, no_dpi_fixture):
280+
png_parser = no_dpi_fixture
281+
assert png_parser.horz_dpi == 72
282+
assert png_parser.vert_dpi == 72
283+
274284
# fixtures -------------------------------------------------------
275285

276286
@pytest.fixture
@@ -291,6 +301,34 @@ def dimensions_fixture(self, chunks_):
291301
png_parser = _PngParser(chunks_)
292302
return png_parser, px_width, px_height
293303

304+
@pytest.fixture
305+
def dpi_fixture(self, chunks_):
306+
horz_px_per_unit, vert_px_per_unit, units_specifier = 1654, 945, 1
307+
horz_dpi, vert_dpi = 42, 24
308+
chunks_.pHYs.horz_px_per_unit = horz_px_per_unit
309+
chunks_.pHYs.vert_px_per_unit = vert_px_per_unit
310+
chunks_.pHYs.units_specifier = units_specifier
311+
png_parser = _PngParser(chunks_)
312+
return png_parser, horz_dpi, vert_dpi
313+
314+
@pytest.fixture(params=[
315+
(-1, -1), (0, 1000), (None, 1000), (1, 0), (1, None)
316+
])
317+
def no_dpi_fixture(self, request, chunks_):
318+
"""
319+
Scenarios are: 1) no pHYs chunk in PNG stream, 2) units specifier
320+
other than 1; 3) px_per_unit is 0; 4) px_per_unit is None
321+
"""
322+
units_specifier, px_per_unit = request.param
323+
if units_specifier == -1:
324+
chunks_.pHYs = None
325+
else:
326+
chunks_.pHYs.horz_px_per_unit = px_per_unit
327+
chunks_.pHYs.vert_px_per_unit = px_per_unit
328+
chunks_.pHYs.units_specifier = units_specifier
329+
png_parser = _PngParser(chunks_)
330+
return png_parser
331+
294332
@pytest.fixture
295333
def parse_fixture(self, stream_, _Chunks_, _PngParser__init_, chunks_):
296334
return stream_, _Chunks_, _PngParser__init_, chunks_

0 commit comments

Comments
 (0)