Skip to content

Commit fadb89d

Browse files
author
Steve Canny
committed
img: add Tiff.from_stream()
1 parent 0c647d3 commit fadb89d

File tree

2 files changed

+132
-0
lines changed

2 files changed

+132
-0
lines changed

docx/image/tiff.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,65 @@ class Tiff(Image):
1010
Image header parser for TIFF images. Handles both big and little endian
1111
byte ordering.
1212
"""
13+
@classmethod
14+
def from_stream(cls, stream, blob, filename):
15+
"""
16+
Return a |Tiff| instance containing the properties of the TIFF image
17+
in *stream*.
18+
"""
19+
parser = _TiffParser.parse(stream)
20+
px_width = parser.px_width
21+
px_height = parser.px_height
22+
horz_dpi = parser.horz_dpi
23+
vert_dpi = parser.vert_dpi
24+
return cls(blob, filename, px_width, px_height, horz_dpi, vert_dpi)
25+
26+
27+
class _TiffParser(object):
28+
"""
29+
Parses a TIFF image stream to extract the image properties found in its
30+
main image file directory (IFD)
31+
"""
32+
@classmethod
33+
def parse(cls, stream):
34+
"""
35+
Return an instance of |_TiffParser| containing the properties parsed
36+
from the TIFF image in *stream*.
37+
"""
38+
raise NotImplementedError
39+
40+
@property
41+
def horz_dpi(self):
42+
"""
43+
The horizontal dots per inch value calculated from the XResolution
44+
and ResolutionUnit tags of the IFD; defaults to 72 if those tags are
45+
not present.
46+
"""
47+
raise NotImplementedError
48+
49+
@property
50+
def px_height(self):
51+
"""
52+
The number of stacked rows of pixels in the image, |None| if the IFD
53+
contains no ``ImageLength`` tag, the expected case when the TIFF is
54+
embeded in an Exif image.
55+
"""
56+
raise NotImplementedError
57+
58+
@property
59+
def px_width(self):
60+
"""
61+
The number of pixels in each row in the image, |None| if the IFD
62+
contains no ``ImageWidth`` tag, the expected case when the TIFF is
63+
embeded in an Exif image.
64+
"""
65+
raise NotImplementedError
66+
67+
@property
68+
def vert_dpi(self):
69+
"""
70+
The vertical dots per inch value calculated from the XResolution and
71+
ResolutionUnit tags of the IFD; defaults to 72 if those tags are not
72+
present.
73+
"""
74+
raise NotImplementedError

tests/image/test_tiff.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# encoding: utf-8
2+
3+
"""
4+
Test suite for docx.image.tiff module
5+
"""
6+
7+
from __future__ import absolute_import, print_function
8+
9+
import pytest
10+
11+
from docx.compat import BytesIO
12+
from docx.image.tiff import Tiff, _TiffParser
13+
14+
from ..unitutil import class_mock, initializer_mock, instance_mock
15+
16+
17+
class DescribeTiff(object):
18+
19+
def it_can_construct_from_a_tiff_stream(self, from_stream_fixture):
20+
(stream_, blob_, filename_, _TiffParser_, Tiff__init_, px_width,
21+
px_height, horz_dpi, vert_dpi) = from_stream_fixture
22+
tiff = Tiff.from_stream(stream_, blob_, filename_)
23+
_TiffParser_.parse.assert_called_once_with(stream_)
24+
Tiff__init_.assert_called_once_with(
25+
blob_, filename_, px_width, px_height, horz_dpi, vert_dpi
26+
)
27+
assert isinstance(tiff, Tiff)
28+
29+
# fixtures -------------------------------------------------------
30+
31+
@pytest.fixture
32+
def blob_(self, request):
33+
return instance_mock(request, bytes)
34+
35+
@pytest.fixture
36+
def filename_(self, request):
37+
return instance_mock(request, str)
38+
39+
@pytest.fixture
40+
def from_stream_fixture(
41+
self, stream_, blob_, filename_, _TiffParser_, tiff_parser_,
42+
Tiff__init_):
43+
px_width, px_height = 111, 222
44+
horz_dpi, vert_dpi = 333, 444
45+
tiff_parser_.px_width = px_width
46+
tiff_parser_.px_height = px_height
47+
tiff_parser_.horz_dpi = horz_dpi
48+
tiff_parser_.vert_dpi = vert_dpi
49+
return (
50+
stream_, blob_, filename_, _TiffParser_, Tiff__init_, px_width,
51+
px_height, horz_dpi, vert_dpi
52+
)
53+
54+
@pytest.fixture
55+
def Tiff__init_(self, request):
56+
return initializer_mock(request, Tiff)
57+
58+
@pytest.fixture
59+
def _TiffParser_(self, request, tiff_parser_):
60+
_TiffParser_ = class_mock(request, 'docx.image.tiff._TiffParser')
61+
_TiffParser_.parse.return_value = tiff_parser_
62+
return _TiffParser_
63+
64+
@pytest.fixture
65+
def tiff_parser_(self, request):
66+
return instance_mock(request, _TiffParser)
67+
68+
@pytest.fixture
69+
def stream_(self, request):
70+
return instance_mock(request, BytesIO)

0 commit comments

Comments
 (0)