Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
1.8.13 (2019-04-05)
-------------------

- fix engine_data unknown tag format;
- fix compose for extra alpha channels;
- workaround for pillow 6.0.0 bug.

1.8.12 (2019-03-25)
-------------------

Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ def get_version():
),
license='MIT License',
install_requires=[
'docopt >= 0.5',
'docopt>=0.5',
'packbits',
'attrs',
'Pillow',
'Pillow!=6.0.0',
'enum34;python_version<"3.4"',
],
keywords="photoshop psd pil pillow",
Expand Down
29 changes: 22 additions & 7 deletions src/psd_tools/api/pil_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,29 @@ def get_pil_mode(value, alpha=False):
return name


def extract_pil_mode(psd):
"""Extract PIL mode from PSD."""
alpha = _get_alpha_use(psd)
return get_pil_mode(psd.header.color_mode, alpha)
def get_pil_channels(pil_mode):
"""Get the number of channels for PIL modes."""
return {
'1': 1,
'L': 1,
'P': 1,
'P': 1,
'RGB': 3,
'CMYK': 4,
'YCbCr': 3,
'LAB': 3,
'HSV': 3,
'I': 1,
'F': 1,
}.get(pil_mode, 3)


def convert_image_data_to_pil(psd, apply_icc=True, **kwargs):
"""Convert ImageData to PIL Image."""
"""Convert ImageData to PIL Image.

.. note:: Image resources contain extra alpha channels in these keys:
`ALPHA_NAMES_UNICODE`, `ALPHA_NAMES_PASCAL`, `ALPHA_IDENTIFIERS`.
"""
from PIL import Image, ImageOps
header = psd.header
size = (header.width, header.height)
Expand All @@ -49,12 +64,12 @@ def convert_image_data_to_pil(psd, apply_icc=True, **kwargs):
alpha = _get_alpha_use(psd)
mode = get_pil_mode(header.color_mode.name)
if mode == 'P':
image = Image.merge('L', channels[:(len(channels) - alpha)])
image = Image.merge('L', channels[:get_pil_channels(mode)])
image.putpalette(psd.color_mode_data.interleave())
elif mode == 'MULTICHANNEL':
image = channels[0] # Multi-channel mode is a collection of alpha.
else:
image = Image.merge(mode, channels[:(len(channels) - alpha)])
image = Image.merge(mode, channels[:get_pil_channels(mode)])
if mode == 'CMYK':
image = image.point(lambda x: 255 - x)
if apply_icc and 'ICC_PROFILE' in psd.image_resources:
Expand Down
2 changes: 1 addition & 1 deletion src/psd_tools/psd/engine_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class EngineToken(Enum):
PROPERTY = compile_re(r'^\/[a-zA-Z0-9]+$')
STRING = compile_re(r'^\((\xfe\xff([^\)]|\\\))*)\)$')
# Unknown tags: b'(hwid)', b'(fwid)', b'(aalt)'
UNKNOWN_TAG = compile_re(r'^\([a-zA-Z0-9]+\)$')
UNKNOWN_TAG = compile_re(r'^\([a-zA-Z0-9]*\)$')


class Tokenizer(object):
Expand Down
3 changes: 2 additions & 1 deletion src/psd_tools/psd/header.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ class FileHeader(BaseElement):

.. py:attribute:: channels

The number of channels in the image, including any alpha channels.
The number of channels in the image, including any user-defined alpha
channel.

.. py:attribute:: height

Expand Down
2 changes: 1 addition & 1 deletion src/psd_tools/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.8.12'
__version__ = '1.8.13'
Binary file added tests/engine_data/Txt2_3.dat
Binary file not shown.
Binary file added tests/psd_files/colormodes/4x4_8bit_rgba.psd
Binary file not shown.
1 change: 1 addition & 0 deletions tests/psd_tools/api/test_composer.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ def test_compose_minimal(filename):
('grayscale', 8),
('index_color', 8),
('rgb', 8),
('rgba', 8),
('lab', 8),
('cmyk', 16),
('grayscale', 16),
Expand Down
1 change: 1 addition & 0 deletions tests/psd_tools/psd/test_engine_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def test_tokenizer_item(fixture, token_type):
('TySh_1.dat', 0, True),
('Txt2_1.dat', None, False),
('Txt2_2.dat', None, False),
('Txt2_3.dat', None, False),
])
def test_engine_data(filename, indent, write):
filepath = os.path.join(TEST_ROOT, 'engine_data', filename)
Expand Down