Skip to content

Commit 8f3e5d4

Browse files
author
Steve Canny
committed
img: add _ChunkFactory()
1 parent f4d93b2 commit 8f3e5d4

File tree

2 files changed

+106
-3
lines changed

2 files changed

+106
-3
lines changed

docx/image/png.py

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from __future__ import absolute_import, division, print_function
44

5-
from .constants import MIME_TYPE, TAG
5+
from .constants import MIME_TYPE, PNG_CHUNK_TYPE, TAG
66
from .exceptions import InvalidImageStreamError
77
from .helpers import BIG_ENDIAN, StreamReader
88
from .image import BaseImageHeader
@@ -270,11 +270,48 @@ def _ChunkFactory(chunk_type, stream_rdr, offset):
270270
Return a |_Chunk| subclass instance appropriate to *chunk_type* parsed
271271
from *stream_rdr* at *offset*.
272272
"""
273-
raise NotImplementedError
273+
chunk_cls_map = {
274+
PNG_CHUNK_TYPE.IHDR: _IHDRChunk,
275+
PNG_CHUNK_TYPE.pHYs: _pHYsChunk,
276+
}
277+
chunk_cls = chunk_cls_map.get(chunk_type, _Chunk)
278+
return chunk_cls.from_offset(chunk_type, stream_rdr, offset)
274279

275280

276281
class _Chunk(object):
277282
"""
278283
Base class for specific chunk types. Also serves as the default chunk
279284
type.
280285
"""
286+
@classmethod
287+
def from_offset(cls, chunk_type, stream_rdr, offset):
288+
"""
289+
Return a default _Chunk instance that only knows its chunk type.
290+
"""
291+
raise NotImplementedError
292+
293+
294+
class _IHDRChunk(_Chunk):
295+
"""
296+
IHDR chunk, contains the image dimensions
297+
"""
298+
@classmethod
299+
def from_offset(cls, chunk_type, stream_rdr, offset):
300+
"""
301+
Return an _IHDRChunk instance containing the image dimensions
302+
extracted from the IHDR chunk in *stream* at *offset*.
303+
"""
304+
raise NotImplementedError
305+
306+
307+
class _pHYsChunk(_Chunk):
308+
"""
309+
pYHs chunk, contains the image dpi information
310+
"""
311+
@classmethod
312+
def from_offset(cls, chunk_type, stream_rdr, offset):
313+
"""
314+
Return a _pHYsChunk instance containing the image resolution
315+
extracted from the pHYs chunk in *stream* at *offset*.
316+
"""
317+
raise NotImplementedError

tests/image/test_png.py

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@
1414
from docx.image.constants import MIME_TYPE, PNG_CHUNK_TYPE, TAG
1515
from docx.image.exceptions import InvalidImageStreamError
1616
from docx.image.helpers import BIG_ENDIAN, StreamReader
17-
from docx.image.png import _Chunk, _Chunks, _ChunkParser, Png, _PngParser
17+
from docx.image.png import (
18+
_Chunk, _Chunks, _ChunkFactory, _ChunkParser, _IHDRChunk, _pHYsChunk,
19+
Png, _PngParser
20+
)
1821

1922
from ..unitutil import (
2023
function_mock, class_mock, initializer_mock, instance_mock, method_mock,
@@ -438,3 +441,66 @@ def stream_(self, request):
438441
@pytest.fixture
439442
def stream_rdr_(self, request):
440443
return instance_mock(request, StreamReader)
444+
445+
446+
class Describe_ChunkFactory(object):
447+
448+
def it_constructs_the_appropriate_Chunk_subclass(self, call_fixture):
449+
chunk_type, stream_rdr_, offset, chunk_cls_ = call_fixture
450+
chunk = _ChunkFactory(chunk_type, stream_rdr_, offset)
451+
chunk_cls_.from_offset.assert_called_once_with(
452+
chunk_type, stream_rdr_, offset
453+
)
454+
assert isinstance(chunk, _Chunk)
455+
456+
# fixtures -------------------------------------------------------
457+
458+
@pytest.fixture(params=[
459+
PNG_CHUNK_TYPE.IHDR,
460+
PNG_CHUNK_TYPE.pHYs,
461+
PNG_CHUNK_TYPE.IEND,
462+
])
463+
def call_fixture(
464+
self, request, _IHDRChunk_, _pHYsChunk_, _Chunk_, stream_rdr_):
465+
chunk_type = request.param
466+
chunk_cls_ = {
467+
PNG_CHUNK_TYPE.IHDR: _IHDRChunk_,
468+
PNG_CHUNK_TYPE.pHYs: _pHYsChunk_,
469+
PNG_CHUNK_TYPE.IEND: _Chunk_,
470+
}[chunk_type]
471+
offset = 999
472+
return chunk_type, stream_rdr_, offset, chunk_cls_
473+
474+
@pytest.fixture
475+
def _Chunk_(self, request, chunk_):
476+
_Chunk_ = class_mock(request, 'docx.image.png._Chunk')
477+
_Chunk_.from_offset.return_value = chunk_
478+
return _Chunk_
479+
480+
@pytest.fixture
481+
def chunk_(self, request):
482+
return instance_mock(request, _Chunk)
483+
484+
@pytest.fixture
485+
def _IHDRChunk_(self, request, ihdr_chunk_):
486+
_IHDRChunk_ = class_mock(request, 'docx.image.png._IHDRChunk')
487+
_IHDRChunk_.from_offset.return_value = ihdr_chunk_
488+
return _IHDRChunk_
489+
490+
@pytest.fixture
491+
def ihdr_chunk_(self, request):
492+
return instance_mock(request, _IHDRChunk)
493+
494+
@pytest.fixture
495+
def _pHYsChunk_(self, request, phys_chunk_):
496+
_pHYsChunk_ = class_mock(request, 'docx.image.png._pHYsChunk')
497+
_pHYsChunk_.from_offset.return_value = phys_chunk_
498+
return _pHYsChunk_
499+
500+
@pytest.fixture
501+
def phys_chunk_(self, request):
502+
return instance_mock(request, _pHYsChunk)
503+
504+
@pytest.fixture
505+
def stream_rdr_(self, request):
506+
return instance_mock(request, StreamReader)

0 commit comments

Comments
 (0)