33"""Adaptive color average image filtering.
44-------------------------------------------
55
6- Average image colors in a pixel row until difference between averaged and next pixel in row reach threshold. Then repeat the same in column. Thus filter changes smooth image areas to completely flat colored, with detailed edges between them.
6+ Average image colors in a pixel row until difference between averaged and next pixel in a row reach threshold. Then repeat the same in column. Thus filter changes smooth image areas to completely flat colored, with detailed edges between them.
77
88Input: PNG, PPM, PGM, PBM.
99
3838__copyright__ = '(c) 2024-2025 Ilya Razmanov'
3939__credits__ = 'Ilya Razmanov'
4040__license__ = 'unlicense'
41- __version__ = '3.22.11.11 '
41+ __version__ = '3.22.18.8 '
4242__maintainer__ = 'Ilya Razmanov'
4343__email__ = 'ilyarazmanov@gmail.com'
4444__status__ = 'Production'
@@ -81,7 +81,7 @@ def ShowInfo(event=None) -> None:
8181 showinfo (
8282 title = 'Image information' ,
8383 message = f'File properties:\n Location: { sourcefilename } \n Size: { file_size_str } \n Last modified: { ctime (Path (sourcefilename ).stat ().st_mtime )} ' ,
84- detail = f'Image properties, as represented internally:\n Width: { X } px\n Height: { Y } px\n Channels: { Z } channel{ "s" if Z > 1 else "" } \n Color depth: { maxcolors + 1 } gradations/channel' ,
84+ detail = f'Image properties, as represented internally:\n Status: { is_filtered = } , { is_saved = } \ n Width: { X } px\n Height: { Y } px\n Channels: { Z } channel{ "s" if Z > 1 else "" } \n Color depth: { maxcolors + 1 } gradations/channel' ,
8585 )
8686
8787
@@ -142,7 +142,8 @@ def GetSource(event=None) -> None:
142142
143143 zoom_factor = 0
144144 view_src = True
145- is_filtered = is_saved = False
145+ is_filtered = False
146+ is_saved = True
146147
147148 sourcefilename = askopenfilename (title = 'Open image file' , filetypes = [('Supported formats' , '.png .ppm .pgm .pbm .pnm' ), ('Portable network graphics' , '.png' ), ('Portable any map' , '.ppm .pgm .pbm .pnm' )])
148149 if sourcefilename == '' :
@@ -158,11 +159,11 @@ def GetSource(event=None) -> None:
158159
159160 if Path (sourcefilename ).suffix == '.png' :
160161 # ↓ Reading PNG image as list
161- X , Y , Z , maxcolors , image3D , info = png2list (sourcefilename )
162+ X , Y , Z , maxcolors , source_image3D , info = png2list (sourcefilename )
162163
163164 elif Path (sourcefilename ).suffix in ('.ppm' , '.pgm' , '.pbm' , '.pnm' ):
164165 # ↓ Reading PNM image as list
165- X , Y , Z , maxcolors , image3D = pnm2list (sourcefilename )
166+ X , Y , Z , maxcolors , source_image3D = pnm2list (sourcefilename )
166167 # ↓ Creating dummy info required to correctly Save As PNG later.
167168 # Fixing color mode, the rest is fixed with pnglpng v. 25.01.07.
168169 info = {'bitdepth' : 16 } if maxcolors > 255 else {'bitdepth' : 8 }
@@ -174,7 +175,7 @@ def GetSource(event=None) -> None:
174175 │ Creating deep copy of source 3D list │
175176 │ to avoid accumulating repetitive filtering │
176177 └────────────────────────────────────────────┘ """
177- source_image3D = deepcopy (image3D )
178+ image3D = deepcopy (source_image3D )
178179
179180 """ ┌───────────────┐
180181 │ Viewing image │
@@ -200,8 +201,13 @@ def GetSource(event=None) -> None:
200201 # ↓ binding on preview click
201202 zanyato .bind ('<Control-Button-1>' , zoomIn ) # Ctrl + left click
202203 zanyato .bind ('<Double-Control-Button-1>' , zoomIn ) # Ctrl + left click too fast
204+ zanyato .bind ('<Control-+>' , zoomIn )
205+ zanyato .bind ('<Control-=>' , zoomIn )
203206 zanyato .bind ('<Alt-Button-1>' , zoomOut ) # Alt + left click
204207 zanyato .bind ('<Double-Alt-Button-1>' , zoomOut ) # Alt + left click too fast
208+ zanyato .bind ('<Control-minus>' , zoomOut )
209+ zanyato .bind ('<Control-Key-1>' , zoomOne )
210+ zanyato .bind ('<Control-Alt-Key-0>' , zoomOne )
205211 sortir .bind_all ('<MouseWheel>' , zoomWheel ) # Wheel scroll
206212 sortir .bind_all ('<Control-i>' , ShowInfo )
207213 menu02 .entryconfig ('Image Info...' , state = 'normal' )
@@ -231,7 +237,7 @@ def GetSource(event=None) -> None:
231237 butt_filter .bind ('<Leave>' , lambda event = None : butt_filter .config (foreground = butt ['foreground' ], background = butt ['background' ]))
232238 UINormal ()
233239 sortir .geometry (f'+{ (sortir .winfo_screenwidth () - sortir .winfo_width ()) // 2 } +{ (sortir .winfo_screenheight () - sortir .winfo_height ()) // 2 - 32 } ' )
234- butt_filter .focus_set () # moving focus to "Filter"
240+ zanyato .focus_set ()
235241
236242
237243def RunFilter (event = None ) -> None :
@@ -317,6 +323,22 @@ def zoomOut(event=None) -> None:
317323 butt_minus .config (state = 'normal' , cursor = 'hand2' )
318324
319325
326+ def zoomOne (event = None ) -> None :
327+ """Zoom 1:1."""
328+
329+ global zoom_factor , view_src , preview
330+ zoom_factor = 0
331+
332+ if view_src :
333+ ShowPreview (preview_src , 'Source' )
334+ else :
335+ ShowPreview (preview_filtered , 'Result' )
336+
337+ # ↓ reenabling +/- buttons
338+ butt_plus .config (state = 'normal' , cursor = 'hand2' )
339+ butt_minus .config (state = 'normal' , cursor = 'hand2' )
340+
341+
320342def zoomWheel (event ) -> None :
321343 """zoomIn or zoomOut by mouse wheel."""
322344
@@ -535,15 +557,15 @@ def SaveAs(event=None) -> None:
535557info01 .grid (row = 0 , column = 2 )
536558
537559ini_threshold_x = IntVar (value = 16 )
538- spin01 = Spinbox (frame_top , from_ = 0 , to = 256 , increment = 1 , textvariable = ini_threshold_x , state = 'disabled' , width = 3 , font = ('helvetica' , 11 ))
560+ spin01 = Spinbox (frame_top , from_ = 0 , to = 255 , increment = 1 , textvariable = ini_threshold_x , state = 'disabled' , width = 3 , font = ('helvetica' , 11 ))
539561spin01 .grid (row = 0 , column = 3 )
540562
541563# ↓ Y-pass threshold control
542564info02 = Label (frame_top , text = 'Y:' , font = ('helvetica' , 11 ), state = 'disabled' )
543565info02 .grid (row = 0 , column = 4 )
544566
545567ini_threshold_y = IntVar (value = 8 )
546- spin02 = Spinbox (frame_top , from_ = 0 , to = 256 , increment = 1 , textvariable = ini_threshold_y , state = 'disabled' , width = 3 , font = ('helvetica' , 11 ))
568+ spin02 = Spinbox (frame_top , from_ = 0 , to = 255 , increment = 1 , textvariable = ini_threshold_y , state = 'disabled' , width = 3 , font = ('helvetica' , 11 ))
547569spin02 .grid (row = 0 , column = 5 )
548570
549571# ↓ Wrap around control
0 commit comments