Skip to content

Commit d5abe8c

Browse files
committed
0.1.6
1 parent 58a9b3a commit d5abe8c

19 files changed

+389
-346
lines changed

.github/workflows/create-release-draft.yml

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
env:
2424
CIBW_BUILD: "cp37-* cp38-* cp39-* cp310-*"
2525
CIBW_ARCHS_WINDOWS: "AMD64"
26-
CIBW_BUILD_VERBOSITY: 1
26+
CIBW_BUILD_VERBOSITY: 2
2727
CIBW_BEFORE_BUILD_WINDOWS: "pip install delvewheel"
2828
CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "delvewheel repair -v -w {dest_dir} {wheel} --add-path ${{ env.VCPKG_PREFIX }}/bin"
2929
CIBW_BEFORE_TEST: pip install -r requirements_dev.txt
@@ -61,7 +61,7 @@ jobs:
6161
DYLD_LIBRARY_PATH=$REPAIR_LIBRARY_PATH delocate-wheel -v --require-archs {delocate_archs} -w {dest_dir} {wheel}
6262
CIBW_BEFORE_TEST: pip3 install -r requirements_dev.txt
6363
CIBW_TEST_COMMAND: "pytest -s {project}"
64-
CIBW_BUILD_VERBOSITY: 1
64+
CIBW_BUILD_VERBOSITY: 2
6565

6666
- name: Check built wheels
6767
run: twine check wheelhouse/*
@@ -114,6 +114,7 @@ jobs:
114114
run: |
115115
echo BUILD_COMMAND="apk --no-cache add -q $OS_PACKAGES && set -ex && cd $SCRIPTS $BUILD_STUFF_CMD" >> $GITHUB_ENV
116116
echo LDCONFIG_ARG="/usr/lib" >> $GITHUB_ENV
117+
echo CIBW_SKIP="cp36-*" >> $GITHUB_ENV
117118
env:
118119
OS_PACKAGES: "sudo py3-pip python3-dev libtool git \
119120
freetype-dev fribidi-dev harfbuzz-dev jpeg-dev lcms2-dev openjpeg-dev tiff-dev zlib-dev"
@@ -164,12 +165,13 @@ jobs:
164165
run: cibuildwheel
165166
env:
166167
CIBW_BUILD: ${{ format('cp3*-{0}*', matrix.cibw_buildlinux) }}
167-
CIBW_SKIP: "cp36-*"
168+
# CIBW_SKIP: "cp36-*"
168169
CIBW_ARCHS: ${{ matrix.cibw_arch }}
169170
CIBW_BEFORE_BUILD_LINUX: ${{ env.BUILD_COMMAND }}
170171
CIBW_ENVIRONMENT_PASS_LINUX: BUILD_STUFF LDCONFIG_ARG
171172
CIBW_BEFORE_TEST: pip3 install -r requirements_dev.txt
172173
CIBW_TEST_COMMAND: "pytest -s {project}"
174+
CIBW_BUILD_VERBOSITY: 2
173175

174176
- name: Check builded wheels
175177
run: twine check wheelhouse/*
@@ -182,6 +184,7 @@ jobs:
182184
if-no-files-found: error
183185

184186
sdist:
187+
needs: [wheels_linux, wheels_macos]
185188
name: Source distribution
186189
runs-on: macos-11
187190

@@ -196,7 +199,7 @@ jobs:
196199
- name: Install brew
197200
run: |
198201
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
199-
brew install libffi libheif
202+
brew install x265 libjpeg libde265 libheif
200203
201204
- name: Build sdist
202205
run: |
@@ -210,14 +213,26 @@ jobs:
210213
pip3 install --user wheelhouse/*.tar.gz
211214
python3 -m twine check wheelhouse/*
212215
216+
- name: Generate coverage report
217+
run: |
218+
cd .. && coverage run --rcfile=pillow_heif/pyproject.toml -m pytest pillow_heif
219+
cd - && coverage xml --data-file=../.coverage
220+
221+
- name: Upload report to Codecov
222+
uses: codecov/codecov-action@v2
223+
with:
224+
file: ./coverage.xml
225+
fail_ci_if_error: true
226+
verbose: true
227+
213228
- name: Upload sdist
214229
uses: actions/upload-artifact@v2
215230
with:
216231
name: wheels
217232
path: wheelhouse/*.tar.gz
218233

219234
draft_release:
220-
needs: [sdist, wheels_linux, wheels_macos]
235+
needs: [sdist]
221236
runs-on: ubuntu-20.04
222237
name: Build and create release
223238

pillow_heif/__init__.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
1+
"""
2+
Import all possible stuff that can be used.
3+
"""
4+
5+
16
# pylint: disable=unused-import
7+
# pylint: disable=redefined-builtin
28
from .constants import * # pylint: disable=unused-wildcard-import
3-
from .reader import HeifFile, UndecodedHeifFile, check, read, open # pylint: disable=redefined-builtin
4-
from .writer import write
9+
from .reader import (
10+
HeifFile,
11+
UndecodedHeifFile,
12+
check_heif,
13+
read_heif,
14+
open_heif,
15+
check,
16+
read,
17+
open,
18+
)
19+
from .writer import write_heif
520
from .error import HeifError
621
from .as_opener import register_heif_opener, check_heif_magic
7-
from . import _libheif # pylint: disable=import-self
8-
from . import _version
9-
10-
11-
__version__ = _version.__version__
12-
13-
14-
def libheif_version():
15-
return _libheif.ffi.string(_libheif.lib.heif_get_version()).decode()
22+
from ._version import __version__
23+
from ._lib_version import libheif_version

pillow_heif/_lib_version.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"""
2+
Functions to get version of embedded C libraries.
3+
"""
4+
5+
6+
from pillow_heif.libheif import ffi, lib # pylint: disable=import-error, no-name-in-module
7+
8+
9+
def libheif_version():
10+
return ffi.string(lib.heif_get_version()).decode()

pillow_heif/as_opener.py

Lines changed: 31 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,60 @@
1+
"""
2+
Opener for Pillow library.
3+
"""
4+
15
from PIL import Image, ImageFile
26

3-
from .reader import read
7+
from .constants import heif_filetype_no
8+
from .reader import open_heif, check_heif
49
from .error import HeifError
510

611

712
class HeifImageFile(ImageFile.ImageFile):
8-
format = 'HEIF'
9-
format_description = 'HEIF/HEIC image'
13+
format = "HEIF"
14+
format_description = "HEIF/HEIC image"
1015
color_profile = None
16+
heif_file = None
1117

1218
def _open(self):
13-
data = self.fp.read(16)
14-
if not check_heif_magic(data):
15-
raise SyntaxError('not a HEIF file')
16-
self.fp.seek(0)
1719
try:
18-
heif_file = read(self.fp)
20+
heif_file = open_heif(self.fp)
1921
except HeifError as e:
2022
raise SyntaxError(str(e)) from None
21-
22-
# size in pixels (width, height)
23+
if getattr(self, "_exclusive_fp", False):
24+
if hasattr(self, "fp") and self.fp is not None:
25+
self.fp.close()
26+
self.fp = None
2327
self._size = heif_file.size
24-
25-
# mode setting
2628
self.mode = heif_file.mode
2729

28-
# Add Exif
2930
if heif_file.metadata:
3031
for data in heif_file.metadata:
31-
if data['type'] == 'Exif':
32-
self.info['exif'] = data['data']
32+
if data["type"] == "Exif":
33+
self.info["exif"] = data["data"]
3334
break
3435

35-
# Add Color Profile
3636
if heif_file.color_profile:
37-
if heif_file.color_profile['type'] != 'unknown':
37+
if heif_file.color_profile["type"] != "unknown":
3838
self.color_profile = heif_file.color_profile
39-
offset = self.fp.tell()
40-
self.tile = [('heif', (0, 0) + self.size, offset, (heif_file,))]
41-
42-
43-
class HeifDecoder(ImageFile.PyDecoder):
44-
_pulls_fd = True
39+
if heif_file.color_profile["type"] in ("rICC", "prof"):
40+
self.info["icc_profile"] = heif_file.color_profile["data"]
41+
self.tile = []
42+
self.heif_file = heif_file
4543

46-
def decode(self, buffer):
47-
heif_file = self.args[0]
48-
mode = heif_file.mode
49-
raw_decoder = Image._getdecoder(mode, 'raw', (mode, heif_file.stride))
50-
raw_decoder.setimage(self.im)
51-
return raw_decoder.decode(heif_file.data)
44+
def load(self):
45+
if self.heif_file is not None and self.heif_file:
46+
heif_file = self.heif_file.load()
47+
self.load_prepare()
48+
self.frombytes(heif_file.data, "raw", (self.mode, heif_file.stride))
49+
self.heif_file.data = None
50+
self.heif_file = None
51+
return super().load()
5252

5353

5454
def check_heif_magic(data) -> bool:
55-
# according to HEIF standard ISO/IEC 23008-12:2017
56-
# https://standards.iso.org/ittf/PubliclyAvailableStandards/c066067_ISO_IEC_23008-12_2017.zip
57-
if len(data) < 12:
58-
return False
59-
magic1 = data[4:8]
60-
if magic1 != b"ftyp":
61-
return False
62-
magic2 = data[8:12]
63-
code_list = [
64-
b"heic", # the usual HEIF images
65-
b"heix", # 10bit images, or anything that uses h265 with range extension
66-
b"hevc", # image sequences
67-
b"hevx", # image sequences
68-
b"heim", # multiview
69-
b"heis", # scalable
70-
b"hevm", # multiview sequence
71-
b"hevs", # scalable sequence
72-
b"mif1", # image, any coding algorithm
73-
b"msf1", # sequence, any coding algorithm
74-
# avif
75-
# avis
76-
]
77-
return magic2 in code_list
55+
return check_heif(data) != heif_filetype_no
7856

7957

8058
def register_heif_opener():
8159
Image.register_open(HeifImageFile.format, HeifImageFile, check_heif_magic)
82-
Image.register_decoder('heif', HeifDecoder)
83-
Image.register_extensions(HeifImageFile.format, ['.heic', '.heif'])
84-
Image.register_mime(HeifImageFile.format, 'image/heif')
60+
Image.register_mime(HeifImageFile.format, "image/heif")

pillow_heif/constants.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
"""
2+
Constants from libheif that is used by pillow_heif.
3+
"""
4+
5+
16
# pylint: disable=invalid-name
27
heif_chroma_undefined = 99
38
heif_chroma_monochrome = 0
@@ -27,12 +32,7 @@
2732

2833

2934
def encode_fourcc(fourcc):
30-
encoded = (
31-
ord(fourcc[0]) << 24
32-
| ord(fourcc[1]) << 16
33-
| ord(fourcc[2]) << 8
34-
| ord(fourcc[3])
35-
)
35+
encoded = ord(fourcc[0]) << 24 | ord(fourcc[1]) << 16 | ord(fourcc[2]) << 8 | ord(fourcc[3])
3636
return encoded
3737

3838

pillow_heif/error.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1+
"""
2+
Exceptions that can be raised during library calls.
3+
"""
4+
5+
16
class HeifError(Exception):
2-
def __init__(self, *, code, subcode, message): # pylint: disable=super-init-not-called
7+
def __init__(self, *, code, subcode, message):
8+
super().__init__(code, subcode, message)
39
self.code = code
410
self.subcode = subcode
511
self.message = message

0 commit comments

Comments
 (0)