embedingHF commited on
Commit
a9eb679
·
verified ·
1 Parent(s): e989bcf

Update converters/image_converter.py

Browse files
Files changed (1) hide show
  1. converters/image_converter.py +231 -57
converters/image_converter.py CHANGED
@@ -1,105 +1,279 @@
1
- from PIL import Image
 
 
 
 
 
 
2
  from pathlib import Path
3
  from typing import Callable, Dict, Any
 
4
  import traceback
5
  import os
6
 
7
 
8
  class ImageConverter:
 
 
 
 
 
 
 
 
 
 
9
  def __init__(self):
10
- pass
11
 
12
- def convert(self, input_path: str, output_path: str,
13
- options: Dict[str, Any], progress_callback: Callable = None) -> bool:
14
- """Convert image files"""
 
 
 
 
 
 
 
 
 
 
15
  try:
16
- # Update progress safely
17
- self._update_progress(progress_callback, 10)
18
 
19
- # Check if input file exists
 
 
 
 
 
20
  if not os.path.exists(input_path):
21
- print(f"Input file not found: {input_path}")
22
- return False
23
 
24
- # Open image
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  img = Image.open(input_path)
26
 
27
- self._update_progress(progress_callback, 30)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
- # Apply AI enhancement if requested
30
- if options.get("ai_enhancement", False):
31
  img = self.enhance_image(img)
32
 
33
- self._update_progress(progress_callback, 50)
 
 
 
34
 
35
- # Get quality settings
36
- quality_settings = options.get("quality_settings", {})
37
- quality = quality_settings.get("image", 85)
 
 
38
 
39
- # Create output directory if needed
40
- Path(output_path).parent.mkdir(parents=True, exist_ok=True)
 
 
 
 
41
 
42
- # Convert and save based on output format
43
- output_ext = Path(output_path).suffix.lower()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
- self._update_progress(progress_callback, 70)
46
 
47
- # Handle different formats
48
- if output_ext in ['.jpg', '.jpeg']:
49
- # Convert RGBA to RGB for JPEG
50
- if img.mode in ('RGBA', 'P'):
51
- img = img.convert('RGB')
52
- img.save(output_path, 'JPEG', quality=quality, optimize=True)
53
 
54
- elif output_ext == '.png':
55
- # PNG uses compression level (0-9)
56
- compression = 6 if quality < 90 else 3
57
- img.save(output_path, 'PNG', compress_level=compression, optimize=True)
58
 
59
- elif output_ext == '.webp':
60
- img.save(output_path, 'WEBP', quality=quality, method=6)
61
 
62
- elif output_ext == '.bmp':
63
- img.save(output_path, 'BMP')
 
 
 
 
64
 
65
- elif output_ext == '.tiff':
66
- img.save(output_path, 'TIFF', compression='tiff_lzw')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
  else:
 
69
  img.save(output_path)
70
 
71
- self._update_progress(progress_callback, 100)
 
 
 
 
 
 
 
 
 
72
 
73
- print(f"✓ Successfully converted: {os.path.basename(input_path)} → {output_ext}")
74
  return True
75
 
76
  except Exception as e:
77
- print(f"Image conversion error for {input_path}: {str(e)}")
 
 
 
 
78
  traceback.print_exc()
 
79
  return False
80
 
81
- def _update_progress(self, callback, value):
82
- """Safely update progress"""
83
- if callback is not None:
84
- try:
 
 
 
 
 
85
  callback(value)
86
- except Exception as e:
87
- # If callback fails (e.g., Qt signal issue), just continue
88
- pass
89
 
90
- def enhance_image(self, img):
91
- """Basic image enhancement"""
 
 
 
 
 
 
 
 
 
92
  try:
93
- from PIL import ImageEnhance, ImageFilter
94
 
95
- # Enhance contrast slightly
96
  enhancer = ImageEnhance.Contrast(img)
97
- img = enhancer.enhance(1.1)
98
 
99
- # Enhance sharpness
 
 
100
  enhancer = ImageEnhance.Sharpness(img)
101
- img = enhancer.enhance(1.05)
 
 
 
 
 
 
 
 
 
 
 
102
 
103
  return img
104
- except:
 
 
 
 
 
 
105
  return img
 
1
+ from PIL import (
2
+ Image,
3
+ ImageEnhance,
4
+ ImageFilter,
5
+ ImageOps
6
+ )
7
+
8
  from pathlib import Path
9
  from typing import Callable, Dict, Any
10
+
11
  import traceback
12
  import os
13
 
14
 
15
  class ImageConverter:
16
+
17
+ SUPPORTED_FORMATS = {
18
+ ".png",
19
+ ".jpg",
20
+ ".jpeg",
21
+ ".webp",
22
+ ".bmp",
23
+ ".tiff"
24
+ }
25
+
26
  def __init__(self):
 
27
 
28
+ # Prevent PIL decompression bomb crash
29
+ Image.MAX_IMAGE_PIXELS = None
30
+
31
+ def convert(
32
+ self,
33
+ input_path: str,
34
+ output_path: str,
35
+ options: Dict[str, Any] | None = None,
36
+ progress_callback: Callable = None
37
+ ) -> bool:
38
+
39
+ options = options or {}
40
+
41
  try:
 
 
42
 
43
+ self._update_progress(
44
+ progress_callback,
45
+ 10
46
+ )
47
+
48
+ # Validate input
49
  if not os.path.exists(input_path):
 
 
50
 
51
+ raise FileNotFoundError(
52
+ input_path
53
+ )
54
+
55
+ input_ext = Path(input_path).suffix.lower()
56
+ output_ext = Path(output_path).suffix.lower()
57
+
58
+ # Validate output format
59
+ if output_ext not in self.SUPPORTED_FORMATS:
60
+
61
+ raise ValueError(
62
+ f"Unsupported format: {output_ext}"
63
+ )
64
+
65
+ # Open image safely
66
  img = Image.open(input_path)
67
 
68
+ # Fix EXIF rotation
69
+ img = ImageOps.exif_transpose(img)
70
+
71
+ self._update_progress(
72
+ progress_callback,
73
+ 25
74
+ )
75
+
76
+ # Convert palette images safely
77
+ if img.mode == "P":
78
+ img = img.convert("RGBA")
79
+
80
+ # Optional resize
81
+ max_size = options.get("max_size")
82
+
83
+ if max_size:
84
+
85
+ img.thumbnail(
86
+ (max_size, max_size)
87
+ )
88
+
89
+ self._update_progress(
90
+ progress_callback,
91
+ 40
92
+ )
93
+
94
+ # AI enhancement
95
+ if options.get(
96
+ "ai_enhancement",
97
+ False
98
+ ):
99
 
 
 
100
  img = self.enhance_image(img)
101
 
102
+ self._update_progress(
103
+ progress_callback,
104
+ 60
105
+ )
106
 
107
+ # Quality
108
+ quality_settings = options.get(
109
+ "quality_settings",
110
+ {}
111
+ )
112
 
113
+ quality = int(
114
+ quality_settings.get(
115
+ "image",
116
+ 85
117
+ )
118
+ )
119
 
120
+ # Create output folder
121
+ Path(output_path).parent.mkdir(
122
+ parents=True,
123
+ exist_ok=True
124
+ )
125
+
126
+ # Format handling
127
+ if output_ext in [".jpg", ".jpeg"]:
128
+
129
+ # JPEG does not support transparency
130
+ if img.mode in ("RGBA", "LA"):
131
+
132
+ background = Image.new(
133
+ "RGB",
134
+ img.size,
135
+ (255, 255, 255)
136
+ )
137
+
138
+ background.paste(
139
+ img,
140
+ mask=img.split()[-1]
141
+ )
142
+
143
+ img = background
144
+
145
+ else:
146
+
147
+ img = img.convert("RGB")
148
+
149
+ img.save(
150
+ output_path,
151
+ "JPEG",
152
+ quality=quality,
153
+ optimize=True
154
+ )
155
 
156
+ elif output_ext == ".png":
157
 
158
+ compress_level = 9
 
 
 
 
 
159
 
160
+ if quality >= 90:
161
+ compress_level = 2
 
 
162
 
163
+ elif quality >= 75:
164
+ compress_level = 5
165
 
166
+ img.save(
167
+ output_path,
168
+ "PNG",
169
+ optimize=True,
170
+ compress_level=compress_level
171
+ )
172
 
173
+ elif output_ext == ".webp":
174
+
175
+ img.save(
176
+ output_path,
177
+ "WEBP",
178
+ quality=quality,
179
+ method=6
180
+ )
181
+
182
+ elif output_ext == ".bmp":
183
+
184
+ if img.mode == "RGBA":
185
+ img = img.convert("RGB")
186
+
187
+ img.save(
188
+ output_path,
189
+ "BMP"
190
+ )
191
+
192
+ elif output_ext == ".tiff":
193
+
194
+ img.save(
195
+ output_path,
196
+ "TIFF",
197
+ compression="tiff_lzw"
198
+ )
199
 
200
  else:
201
+
202
  img.save(output_path)
203
 
204
+ self._update_progress(
205
+ progress_callback,
206
+ 100
207
+ )
208
+
209
+ print(
210
+ f"✓ Converted: "
211
+ f"{os.path.basename(input_path)} "
212
+ f"→ {output_ext}"
213
+ )
214
 
 
215
  return True
216
 
217
  except Exception as e:
218
+
219
+ print(
220
+ f"Image conversion error: {e}"
221
+ )
222
+
223
  traceback.print_exc()
224
+
225
  return False
226
 
227
+ def _update_progress(
228
+ self,
229
+ callback,
230
+ value
231
+ ):
232
+
233
+ try:
234
+
235
+ if callback:
236
  callback(value)
 
 
 
237
 
238
+ except Exception as e:
239
+
240
+ print(
241
+ f"Progress callback error: {e}"
242
+ )
243
+
244
+ def enhance_image(
245
+ self,
246
+ img
247
+ ):
248
+
249
  try:
 
250
 
251
+ # Contrast
252
  enhancer = ImageEnhance.Contrast(img)
 
253
 
254
+ img = enhancer.enhance(1.08)
255
+
256
+ # Sharpness
257
  enhancer = ImageEnhance.Sharpness(img)
258
+
259
+ img = enhancer.enhance(1.1)
260
+
261
+ # Slight color boost
262
+ enhancer = ImageEnhance.Color(img)
263
+
264
+ img = enhancer.enhance(1.03)
265
+
266
+ # Optional smooth sharpen
267
+ img = img.filter(
268
+ ImageFilter.SHARPEN
269
+ )
270
 
271
  return img
272
+
273
+ except Exception as e:
274
+
275
+ print(
276
+ f"Enhancement error: {e}"
277
+ )
278
+
279
  return img