Skip to content

Commit b196d4b

Browse files
author
Steve Canny
committed
img: add _Chunks.IHDR and .pHYs
1 parent 70e0948 commit b196d4b

File tree

2 files changed

+74
-5
lines changed

2 files changed

+74
-5
lines changed

docx/image/png.py

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -217,25 +217,47 @@ class _Chunks(object):
217217
"""
218218
Collection of the chunks parsed from a PNG image stream
219219
"""
220-
def __init__(self, chunk_lst):
220+
def __init__(self, chunk_iterable):
221221
super(_Chunks, self).__init__()
222-
self._chunks = chunk_lst
222+
self._chunks = list(chunk_iterable)
223223

224224
@classmethod
225225
def from_stream(cls, stream):
226226
"""
227227
Return a |_Chunks| instance containing the PNG chunks in *stream*.
228228
"""
229229
chunk_parser = _ChunkParser.from_stream(stream)
230-
chunk_lst = [chunk for chunk in chunk_parser.iter_chunks()]
231-
return cls(chunk_lst)
230+
chunks = [chunk for chunk in chunk_parser.iter_chunks()]
231+
return cls(chunks)
232232

233233
@property
234234
def IHDR(self):
235235
"""
236236
IHDR chunk in PNG image
237237
"""
238-
raise NotImplementedError
238+
match = lambda chunk: chunk.type_name == PNG_CHUNK_TYPE.IHDR
239+
IHDR = self._find_first(match)
240+
if IHDR is None:
241+
raise InvalidImageStreamError('no IHDR chunk in PNG image')
242+
return IHDR
243+
244+
@property
245+
def pHYs(self):
246+
"""
247+
pHYs chunk in PNG image, or |None| if not present
248+
"""
249+
match = lambda chunk: chunk.type_name == PNG_CHUNK_TYPE.pHYs
250+
return self._find_first(match)
251+
252+
def _find_first(self, match):
253+
"""
254+
Return first chunk in stream order returning True for function
255+
*match*.
256+
"""
257+
for chunk in self._chunks:
258+
if match(chunk):
259+
return chunk
260+
return None
239261

240262

241263
class _ChunkParser(object):

tests/image/test_png.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,19 @@ def it_can_construct_from_a_stream(self, from_stream_fixture):
316316
_Chunks__init_.assert_called_once_with(chunk_lst)
317317
assert isinstance(chunks, _Chunks)
318318

319+
def it_provides_access_to_the_IHDR_chunk(self, IHDR_fixture):
320+
chunks, IHDR_chunk_ = IHDR_fixture
321+
assert chunks.IHDR == IHDR_chunk_
322+
323+
def it_provides_access_to_the_pHYs_chunk(self, pHYs_fixture):
324+
chunks, expected_chunk = pHYs_fixture
325+
assert chunks.pHYs == expected_chunk
326+
327+
def it_raises_if_theres_no_IHDR_chunk(self, no_IHDR_fixture):
328+
chunks = no_IHDR_fixture
329+
with pytest.raises(InvalidImageStreamError):
330+
chunks.IHDR
331+
319332
# fixtures -------------------------------------------------------
320333

321334
@pytest.fixture
@@ -341,6 +354,40 @@ def chunk_parser_(self, request):
341354
def _Chunks__init_(self, request):
342355
return initializer_mock(request, _Chunks)
343356

357+
@pytest.fixture
358+
def IHDR_fixture(self, IHDR_chunk_, pHYs_chunk_):
359+
chunks = (IHDR_chunk_, pHYs_chunk_)
360+
chunks = _Chunks(chunks)
361+
return chunks, IHDR_chunk_
362+
363+
@pytest.fixture
364+
def IHDR_chunk_(self, request):
365+
return instance_mock(
366+
request, _IHDRChunk, type_name=PNG_CHUNK_TYPE.IHDR
367+
)
368+
369+
@pytest.fixture
370+
def no_IHDR_fixture(self, pHYs_chunk_):
371+
chunks = (pHYs_chunk_,)
372+
chunks = _Chunks(chunks)
373+
return chunks
374+
375+
@pytest.fixture
376+
def pHYs_chunk_(self, request):
377+
return instance_mock(
378+
request, _pHYsChunk, type_name=PNG_CHUNK_TYPE.pHYs
379+
)
380+
381+
@pytest.fixture(params=[True, False])
382+
def pHYs_fixture(self, request, IHDR_chunk_, pHYs_chunk_):
383+
has_pHYs_chunk = request.param
384+
chunks = [IHDR_chunk_]
385+
if has_pHYs_chunk:
386+
chunks.append(pHYs_chunk_)
387+
expected_chunk = pHYs_chunk_ if has_pHYs_chunk else None
388+
chunks = _Chunks(chunks)
389+
return chunks, expected_chunk
390+
344391
@pytest.fixture
345392
def stream_(self, request):
346393
return instance_mock(request, BytesIO)

0 commit comments

Comments
 (0)