Skip to content

Commit ee8cbe5

Browse files
author
Steve Canny
committed
img: add _Marker.from_stream()
1 parent 79efb67 commit ee8cbe5

File tree

3 files changed

+48
-3
lines changed

3 files changed

+48
-3
lines changed

docx/image/helpers.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ def read_long(self, base=None, offset=0):
5050
fmt = '<L' if self._byte_order is LITTLE_ENDIAN else '>L'
5151
return self._read_int(fmt, base, offset)
5252

53+
def read_short(self, base=None, offset=0):
54+
"""
55+
Return the int value of the two bytes at the file position determined
56+
by *base* and *offset*, similarly to ``read_long()`` above.
57+
"""
58+
fmt = b'<H' if self._byte_order is LITTLE_ENDIAN else b'>H'
59+
return self._read_int(fmt, base, offset)
60+
5361
def read_str(self, char_count, base, offset=0):
5462
"""
5563
Return a string containing the *char_count* bytes at the file

docx/image/jpeg.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -228,28 +228,38 @@ class _Marker(object):
228228
Base class for JFIF marker classes. Represents a marker and its segment
229229
occuring in a JPEG byte stream.
230230
"""
231+
def __init__(self, marker_code, offset, segment_length):
232+
super(_Marker, self).__init__()
233+
self._marker_code = marker_code
234+
self._offset = offset
235+
self._segment_length = segment_length
236+
231237
@classmethod
232238
def from_stream(cls, stream, marker_code, offset):
233239
"""
234240
Return a generic |_Marker| instance for the marker at *offset* in
235241
*stream* having *marker_code*.
236242
"""
237-
raise NotImplementedError
243+
if JPEG_MARKER_CODE.is_standalone(marker_code):
244+
segment_length = 0
245+
else:
246+
segment_length = stream.read_short(offset)
247+
return cls(marker_code, offset, segment_length)
238248

239249
@property
240250
def marker_code(self):
241251
"""
242252
The single-byte code that identifies the type of this marker, e.g.
243253
``'\xE0'`` for start of image (SOI).
244254
"""
245-
raise NotImplementedError
255+
return self._marker_code
246256

247257
@property
248258
def segment_length(self):
249259
"""
250260
The length in bytes of this marker's segment
251261
"""
252-
raise NotImplementedError
262+
return self._segment_length
253263

254264

255265
class _App0Marker(_Marker):

tests/image/test_jpeg.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,33 @@ def stream_(self, request):
151151
return instance_mock(request, BytesIO)
152152

153153

154+
class Describe_Marker(object):
155+
156+
def it_can_construct_from_a_stream_and_offset(self, from_stream_fixture):
157+
stream, marker_code, offset, _Marker__init_, length = (
158+
from_stream_fixture
159+
)
160+
marker = _Marker.from_stream(stream, marker_code, offset)
161+
_Marker__init_.assert_called_once_with(marker_code, offset, length)
162+
assert isinstance(marker, _Marker)
163+
164+
# fixtures -------------------------------------------------------
165+
166+
@pytest.fixture(params=[
167+
(JPEG_MARKER_CODE.SOI, 2, 0),
168+
(JPEG_MARKER_CODE.APP0, 4, 16),
169+
])
170+
def from_stream_fixture(self, request, _Marker__init_):
171+
marker_code, offset, length = request.param
172+
bytes_ = b'\xFF\xD8\xFF\xE0\x00\x10'
173+
stream_reader = StreamReader(BytesIO(bytes_), BIG_ENDIAN)
174+
return stream_reader, marker_code, offset, _Marker__init_, length
175+
176+
@pytest.fixture
177+
def _Marker__init_(self, request):
178+
return initializer_mock(request, _Marker)
179+
180+
154181
class Describe_MarkerFactory(object):
155182

156183
def it_constructs_the_appropriate_marker_object(self, call_fixture):

0 commit comments

Comments
 (0)