3 from typing
import Tuple
, Optional
5 from PIL
import Image
as PilImage
, ImageChops
, ImageFile
7 from PIL
import UnidentifiedImageError
8 except (ModuleNotFoundError
, ImportError):
9 UnidentifiedImageError
= OSError
12 __all__
= ['MangaImage']
15 def _pil_fmt(_
) -> Optional
[str]:
17 with PilImage
.open(_
) as img
:
18 return img
.format
.lower()
19 except UnidentifiedImageError
:
24 _image
= None # type: PilImage.Image
25 src_path
= None # type: str
27 def __init__(self
, src_path
):
31 if not path
.isfile(src_path
):
32 raise AttributeError('Image not found')
34 self
.src_path
= src_path
36 self
._image
= PilImage
.open(src_path
)
37 except UnidentifiedImageError
:
38 if not ImageFile
.LOAD_TRUNCATED_IMAGES
:
39 ImageFile
.LOAD_TRUNCATED_IMAGES
= True
40 self
._image
= PilImage
.open(src_path
)
43 def new(mode
: str, size
: Tuple
[int, int]):
44 return PilImage
.new(mode
, size
)
47 def image(self
) -> PilImage
.Image
:
49 :rtype: PilImage.Image
55 def image(self
, image
: PilImage
.Image
):
58 def gray(self
, dest_path
: str):
64 image
= self
.image
.convert('LA')
65 except (ValueError, OSError):
66 image
= self
.image
.convert('L')
67 if dest_path
is not None:
71 def convert(self
, dest_path
: str, quality
: int = 95):
73 see http://pillow.readthedocs.io/en/3.4.x/handbook/image-file-formats.html
78 self
.image
.save(dest_path
, quality
=quality
)
81 def crop_manual_with_offsets(self
, offsets
, dest_path
: str):
87 left
, upper
, right
, lower
= offsets
88 width
, height
= self
.image
.size
89 image
= self
.image
.crop((
97 def crop_manual(self
, sizes
: tuple, dest_path
: str):
99 :param sizes: The crop rectangle, as a (left, upper, right, lower)-tuple.
103 self
.image
.crop(sizes
).save(dest_path
)
105 def crop_auto(self
, dest_path
: str):
113 self
.image
.getpixel((0, 0))
115 diff
= ImageChops
.difference(self
.image
, bg
)
116 diff
= ImageChops
.add(diff
, diff
, 2.0, -100)
117 bbox
= diff
.getbbox()
119 crop
= self
.image
.crop(bbox
)
124 self
.image
is not None and self
.image
.close()
127 def real_extension(_path
):
128 ext
= imghdr
.what(_path
)
130 ext
= _pil_fmt(_path
)
136 def is_image(_path
) -> bool:
137 return (imghdr
.what(_path
) or _pil_fmt(_path
)) is not None