-
Notifications
You must be signed in to change notification settings - Fork 0
/
IMGquant.py
204 lines (171 loc) · 5.04 KB
/
IMGquant.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
import logging
log = logging.getLogger(__name__)
import imagequant
import inspect
from pathlib import Path
from PIL import Image
from rich import print
from rich.prompt import Confirm
import typer
import warnings
warnings.filterwarnings("ignore", category=Image.DecompressionBombWarning)
from IMGsqueeze import IMGsqueeze
from IMGimage import IMGimage
import configure
from helpers import msgs
class IMGquant(IMGsqueeze):
'''Quantize for JPEG, PNG and TIFF with Zlib compression
'''
def __init__(self, directory, colors, dither, zlib):
super().__init__()
log.debug('Start')
self.task = f'{configure.QUANT_MACH}_colors-{str(colors)}_dither-{str(dither)}_zlib-{str(zlib)}'
self.dir_proc = directory
self.colors = colors
self.dither = dither
self.zlib = zlib
self.run()
log.debug('End')
def run(self):
'''The primary controller method for this class.
'''
log.debug('Start')
try:
if not self.preflight():
self.goodbye()
return
self.process_images()
self.postlfight()
self.goodbye()
except KeyboardInterrupt:
self.stopped()
return
except Exception as e:
self.error(repr(e))
log.debug('End: Error')
log.error(e)
return
def process_images(self):
'''Compress images in self.files.
'''
log.debug('Start')
print(msgs.hr)
print(msgs.proc_start)
print(f'[yellow]{msgs.task_stop}')
f_on = 0
for f in self.files:
f_on += 1
print(msgs.hr)
print(f'Processing {f_on} of {len(self.files)}: {f}')
this = IMGimage(f)
this.path_in = Path(self.dir_proc.joinpath(f))
this.path_out = Path(self.dir_save.joinpath(f))
if not this.check_is_file():
self.files_results.append(this.__dict__)
this.print_results()
continue
if not this.check_max_mb():
self.files_results.append(this.__dict__)
this.print_results()
continue
try:
with Image.open(this.path_in) as opened:
if not this.check_format(opened):
self.files_results.append(this.__dict__)
this.print_results()
continue
if not this.check_max_pixels(opened):
self.files_results.append(this.__dict__)
this.print_results()
continue
# Quantize the image
new = imagequant.quantize_pil_image(opened, max_colors=self.colors,
dithering_level=self.dither)
if this.format_in == 'JPEG':
new = new.convert('RGB')
new.save(this.path_out, compress_level=self.zlib)
# If we've made it this far, check the saved file
this.check_saved()
this.print_results()
self.files_results.append(this.__dict__)
log.debug('End')
# In case file makes it past find_files()
except Image.UnidentifiedImageError:
this.proc_result = configure.PROC_ERROR
this.proc_msg = configure.PROC_MSG_NOT_IMAGE
this.print_results()
self.files_results.append(this.__dict__)
log.debug('End: Not an image')
except Exception as e:
this.proc_result = configure.PROC_ERROR
this.proc_msg = configure.PROC_MSG_SOURCE_ERROR
print(repr(e))
this.print_results()
self.files_results.append(this.__dict__)
log.debug('End: Error')
log.error(e)
#
# Run this puppy :)
def hello():
'''Prints the app banner to console.
'''
print(f'[blue]{msgs.div}')
print(f'[white]{inspect.cleandoc(configure.QUANT_ASCII)}')
print(f'[blue]{msgs.div}')
print(configure.QUANT_DESC)
print(f'{configure.APP_NAME}: {configure.APP_REPO}')
print(msgs.hr)
def main(
directory: Path = typer.Argument(
...,
exists=True,
file_okay=False,
dir_okay=True,
writable=True,
readable=True,
resolve_path=True,
help=configure.DIR_HELP
),
colors: int = typer.Option(
default=configure.QUANT_DEFAULT_COLORS,
min=1,
max=256,
help=configure.QUANT_HELP_COLORS
),
dither: float = typer.Option(
default=configure.QUANT_DEFAULT_DITHER,
min=0,
max=1,
help=configure.QUANT_HELP_DITHER
),
zlib: int = typer.Option(
default=configure.ZLIB_DEFAULT,
min=0,
max=9,
help=configure.ZLIB_HELP
)
):
'''Quantize JPEG, PNG, and TIFF. Optional Zlib compression.
'''
# Logging
import logging
from helpers import logger
logger.setup_logging()
log = logging.getLogger(__name__)
# Hello + confirm
hello()
typer.echo(f"directory {directory}")
typer.echo(f"--colors {colors}")
typer.echo(f"--dither {dither}")
typer.echo(f"--zlib {zlib}")
typer.echo(msgs.hr)
conf = Confirm.ask(configure.TASK_CONF, default=True)
if not conf:
print(f'[red]{msgs.task_stopped}')
print(msgs.hr)
raise typer.Exit()
# Start
print(f'Starting task. [red]{msgs.task_stop}')
task = IMGquant(directory, colors, dither, zlib)
if __name__ == "__main__":
typer.run(main)