Skip to content

Commit 2b6497b

Browse files
author
Steve Canny
committed
img: add _TiffParser.parse()
1 parent fadb89d commit 2b6497b

2 files changed

Lines changed: 97 additions & 3 deletions

File tree

docx/image/tiff.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,20 @@ class _TiffParser(object):
2929
Parses a TIFF image stream to extract the image properties found in its
3030
main image file directory (IFD)
3131
"""
32+
def __init__(self, ifd):
33+
super(_TiffParser, self).__init__()
34+
self._ifd = ifd
35+
3236
@classmethod
3337
def parse(cls, stream):
3438
"""
3539
Return an instance of |_TiffParser| containing the properties parsed
3640
from the TIFF image in *stream*.
3741
"""
38-
raise NotImplementedError
42+
stream_rdr = cls._make_stream_reader(stream)
43+
ifd0_offset = stream_rdr.read_long(4)
44+
ifd_entries = _IfdEntries.from_stream(stream_rdr, ifd0_offset)
45+
return cls(ifd_entries)
3946

4047
@property
4148
def horz_dpi(self):
@@ -72,3 +79,26 @@ def vert_dpi(self):
7279
present.
7380
"""
7481
raise NotImplementedError
82+
83+
@classmethod
84+
def _make_stream_reader(cls, stream):
85+
"""
86+
Return a |StreamReader| instance with wrapping *stream* and having
87+
"endian-ness" determined by the 'MM' or 'II' indicator in the TIFF
88+
stream header.
89+
"""
90+
raise NotImplementedError
91+
92+
93+
class _IfdEntries(object):
94+
"""
95+
Image File Directory for a TIFF image, having mapping (dict) semantics
96+
allowing "tag" values to be retrieved by tag code.
97+
"""
98+
@classmethod
99+
def from_stream(cls, stream, offset):
100+
"""
101+
Return a new |_IfdEntries| instance parsed from *stream* starting at
102+
*offset*.
103+
"""
104+
raise NotImplementedError

tests/image/test_tiff.py

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@
99
import pytest
1010

1111
from docx.compat import BytesIO
12-
from docx.image.tiff import Tiff, _TiffParser
12+
from docx.image.helpers import StreamReader
13+
from docx.image.tiff import _IfdEntries, Tiff, _TiffParser
1314

14-
from ..unitutil import class_mock, initializer_mock, instance_mock
15+
from ..unitutil import (
16+
initializer_mock, class_mock, instance_mock, method_mock
17+
)
1518

1619

1720
class DescribeTiff(object):
@@ -68,3 +71,64 @@ def tiff_parser_(self, request):
6871
@pytest.fixture
6972
def stream_(self, request):
7073
return instance_mock(request, BytesIO)
74+
75+
76+
class Describe_TiffParser(object):
77+
78+
def it_can_parse_the_properties_from_a_tiff_stream(
79+
self, from_stream_fixture):
80+
(stream_, _make_stream_reader_, _IfdEntries_, ifd0_offset_,
81+
stream_rdr_, _TiffParser__init_, ifd_entries_) = from_stream_fixture
82+
tiff_parser = _TiffParser.parse(stream_)
83+
_make_stream_reader_.assert_called_once_with(stream_)
84+
_IfdEntries_.from_stream.assert_called_once_with(
85+
stream_rdr_, ifd0_offset_
86+
)
87+
_TiffParser__init_.assert_called_once_with(ifd_entries_)
88+
assert isinstance(tiff_parser, _TiffParser)
89+
90+
# fixtures -------------------------------------------------------
91+
92+
@pytest.fixture
93+
def from_stream_fixture(
94+
self, stream_, _make_stream_reader_, _IfdEntries_, ifd0_offset_,
95+
stream_rdr_, _TiffParser__init_, ifd_entries_):
96+
return (
97+
stream_, _make_stream_reader_, _IfdEntries_, ifd0_offset_,
98+
stream_rdr_, _TiffParser__init_, ifd_entries_
99+
)
100+
101+
@pytest.fixture
102+
def _IfdEntries_(self, request, ifd_entries_):
103+
_IfdEntries_ = class_mock(request, 'docx.image.tiff._IfdEntries')
104+
_IfdEntries_.from_stream.return_value = ifd_entries_
105+
return _IfdEntries_
106+
107+
@pytest.fixture
108+
def ifd_entries_(self, request):
109+
return instance_mock(request, _IfdEntries)
110+
111+
@pytest.fixture
112+
def ifd0_offset_(self, request):
113+
return instance_mock(request, int)
114+
115+
@pytest.fixture
116+
def _make_stream_reader_(self, request, stream_rdr_):
117+
return method_mock(
118+
request, _TiffParser, '_make_stream_reader',
119+
return_value=stream_rdr_
120+
)
121+
122+
@pytest.fixture
123+
def stream_(self, request):
124+
return instance_mock(request, BytesIO)
125+
126+
@pytest.fixture
127+
def stream_rdr_(self, request, ifd0_offset_):
128+
stream_rdr_ = instance_mock(request, StreamReader)
129+
stream_rdr_.read_long.return_value = ifd0_offset_
130+
return stream_rdr_
131+
132+
@pytest.fixture
133+
def _TiffParser__init_(self, request):
134+
return initializer_mock(request, _TiffParser)

0 commit comments

Comments
 (0)