@@ -156,23 +156,24 @@ def _get_transformed_image_cached(self, zoom_level, scale, rotation, flip_h, fli
156156 else :
157157 return Image .new ("RGBA" , (10 , 10 ), (255 , 0 , 0 , 128 ))
158158
159- # ПРИМЕНЯЕМ МАСШТАБ К ОРИГИНАЛЬНОМУ ИЗОБРАЖЕНИЮ
159+ # ПРАВИЛЬНЫЙ ПОРЯДОК ТРАНСФОРМАЦИЙ:
160+ # 1. Масштаб элемента
160161 if scale != 1.0 :
161162 new_width = max (1 , int (img .width * scale ))
162163 new_height = max (1 , int (img .height * scale ))
163164 img = img .resize ((new_width , new_height ), Image .LANCZOS )
164165
165- # Отражение (применяется после масштабирования)
166+ # 2. Отражение
166167 if flip_h :
167168 img = img .transpose (Image .FLIP_LEFT_RIGHT )
168169 if flip_v :
169170 img = img .transpose (Image .FLIP_TOP_BOTTOM )
170171
171- # Поворот
172+ # 3. Поворот
172173 if rotation != 0 :
173174 img = img .rotate (rotation , expand = True , resample = Image .BICUBIC )
174175
175- # Масштаб зума ( для отображения в редакторе )
176+ # 4. Зум для отображения (только для редактора )
176177 if zoom_level != 1.0 :
177178 final_width = max (1 , int (img .width * zoom_level ))
178179 final_height = max (1 , int (img .height * zoom_level ))
@@ -182,6 +183,9 @@ def _get_transformed_image_cached(self, zoom_level, scale, rotation, flip_h, fli
182183
183184 def _get_transformed_image (self , zoom_level = 1.0 ):
184185 """Получает трансформированное изображение для заданного уровня зума"""
186+ logger .debug (f"Getting transformed image: scale={ self .scale } , rotation={ self .rotation } , "
187+ f"flip_h={ self .flip_horizontal } , flip_v={ self .flip_vertical } , zoom={ zoom_level } " )
188+
185189 # Для GIF сначала обновляем текущий кадр
186190 if self .is_gif and self .gif_frames :
187191 self ._update_gif_frame ()
@@ -210,23 +214,24 @@ def _get_transformed_image(self, zoom_level=1.0):
210214 else :
211215 img = self ._original_image .copy ()
212216
213- # ПРИМЕНЯЕМ МАСШТАБ К ОРИГИНАЛЬНОМУ ИЗОБРАЖЕНИЮ
217+ # ПРАВИЛЬНЫЙ ПОРЯДОК ТРАНСФОРМАЦИЙ:
218+ # 1. Масштаб элемента
214219 if self .scale != 1.0 :
215220 new_width = max (1 , int (img .width * self .scale ))
216221 new_height = max (1 , int (img .height * self .scale ))
217222 img = img .resize ((new_width , new_height ), Image .LANCZOS )
218223
219- # Отражение (применяется после масштабирования)
224+ # 2. Отражение
220225 if self .flip_horizontal :
221226 img = img .transpose (Image .FLIP_LEFT_RIGHT )
222227 if self .flip_vertical :
223228 img = img .transpose (Image .FLIP_TOP_BOTTOM )
224229
225- # Поворот
230+ # 3. Поворот
226231 if self .rotation != 0 :
227232 img = img .rotate (self .rotation , expand = True , resample = Image .BICUBIC )
228233
229- # Масштаб зума ( для отображения в редакторе )
234+ # 4. Зум для отображения (только для редактора )
230235 if zoom_level != 1.0 :
231236 final_width = max (1 , int (img .width * zoom_level ))
232237 final_height = max (1 , int (img .height * zoom_level ))
@@ -256,6 +261,10 @@ def clear_cache(self):
256261 """Очищает кэш изображений"""
257262 self ._get_transformed_image_cached .cache_clear ()
258263 self ._zoom_cache .clear ()
264+
265+ # Также очищаем Tkinter PhotoImage кэш
266+ if hasattr (self , '_tk_images' ):
267+ self ._tk_images .clear ()
259268
260269class ModelEditor (tk .Toplevel ):
261270 def __init__ (self , master , on_save = None , device = 'По умолчанию' , noise_gate_threshold = 0.01 , sensitivity = 1.0 , thresholds = None , current_slot = None ):
@@ -1131,20 +1140,20 @@ def _create_preview_for_export(self, temp_dir, preview_path):
11311140 try :
11321141 img = Image .open (ci .image_path ).convert ("RGBA" )
11331142
1134- # Применяем трансформации
1143+ # Применяем трансформации в ПРАВИЛЬНОМ ПОРЯДКЕ (как в редакторе)
11351144 if ci .scale != 1.0 :
11361145 new_width = max (1 , int (img .width * ci .scale ))
11371146 new_height = max (1 , int (img .height * ci .scale ))
11381147 img = img .resize ((new_width , new_height ), Image .LANCZOS )
11391148
1140- if ci .rotation != 0 :
1141- img = img .rotate (ci .rotation , expand = True , resample = Image .BICUBIC )
1142-
11431149 if ci .flip_horizontal :
11441150 img = img .transpose (Image .FLIP_LEFT_RIGHT )
11451151 if ci .flip_vertical :
11461152 img = img .transpose (Image .FLIP_TOP_BOTTOM )
11471153
1154+ if ci .rotation != 0 :
1155+ img = img .rotate (ci .rotation , expand = True , resample = Image .BICUBIC )
1156+
11481157 px = center_x - img .size [0 ] // 2 + int (ci .x )
11491158 py = center_y - img .size [1 ] // 2 + int (ci .y )
11501159
@@ -1297,16 +1306,20 @@ def _fast_render_canvas(self, level=0.0, mode="none"):
12971306 scaled_width = int (self .canvas_width * self .zoom_level )
12981307 scaled_height = int (self .canvas_height * self .zoom_level )
12991308
1309+ # Убедитесь, что scaled_width и scaled_height не отрицательные
1310+ scaled_width = max (10 , scaled_width )
1311+ scaled_height = max (10 , scaled_height )
1312+
13001313 center_x = canvas_width // 2 + self .offset_x
13011314 center_y = canvas_height // 2 + self .offset_y
13021315
13031316 canvas_x1 = center_x - scaled_width // 2
13041317 canvas_y1 = center_y - scaled_height // 2
13051318
1306- # Рисуем фон холста
1319+ # Рисуем фон холста с учетом границ
13071320 self .canvas .create_rectangle (
1308- canvas_x1 , canvas_y1 ,
1309- canvas_x1 + scaled_width , canvas_y1 + scaled_height ,
1321+ max ( 0 , canvas_x1 ), max ( 0 , canvas_y1 ),
1322+ min ( canvas_width , canvas_x1 + scaled_width ), min ( canvas_height , canvas_y1 + scaled_height ) ,
13101323 outline = "#666" , width = 2 , fill = "#333"
13111324 )
13121325
@@ -1341,11 +1354,15 @@ def _fast_render_canvas(self, level=0.0, mode="none"):
13411354 continue
13421355
13431356 # Рассчитываем позицию на холсте
1344- img_center_x = scaled_width // 2
1345- img_center_y = scaled_height // 2
1357+ center_x_scaled = scaled_width // 2
1358+ center_y_scaled = scaled_height // 2
13461359
1347- pos_x = canvas_x1 + img_center_x - img .width // 2 + int (ci .x * self .zoom_level )
1348- pos_y = canvas_x1 + img_center_y - img .height // 2 + int (ci .y * self .zoom_level )
1360+ # Координаты относительно центра с учетом зума
1361+ offset_x = int (ci .x * self .zoom_level )
1362+ offset_y = int (ci .y * self .zoom_level )
1363+
1364+ pos_x = canvas_x1 + center_x_scaled - img .width // 2 + offset_x
1365+ pos_y = canvas_y1 + center_y_scaled - img .height // 2 + offset_y
13491366
13501367 # Используем кэшированные PhotoImage, но для GIF не кэшируем
13511368 if ci .is_gif :
@@ -1840,6 +1857,8 @@ def on_mirror_change(self):
18401857 ci .flip_vertical = self .flip_v_var .get ()
18411858 ci .clear_cache () # Очищаем кэш
18421859
1860+ # Очищаем кэш редактора
1861+ self ._photo_images .clear ()
18431862 self ._canvas_cache_valid = False
18441863 self .redraw_canvas ()
18451864 self .save_to_history ("Изменение отражения" )
@@ -1853,6 +1872,8 @@ def on_visible_change(self):
18531872 ci .visible = self .visible_var .get ()
18541873 ci .clear_cache () # Очищаем кэш
18551874
1875+ # Очищаем кэш редактора
1876+ self ._photo_images .clear ()
18561877 self ._canvas_cache_valid = False
18571878 self .redraw_canvas ()
18581879 self .save_to_history ("Изменение видимости" )
@@ -2444,19 +2465,20 @@ def create_preview(self):
24442465 try :
24452466 img = Image .open (ci .image_path ).convert ("RGBA" )
24462467
2447- # Применяем масштаб ПЕРВЫМ (как в рендерере)
2468+ # ПРАВИЛЬНЫЙ ПОРЯДОК ТРАНСФОРМАЦИЙ (такой же как в редакторе):
2469+ # 1. Масштаб элемента
24482470 if ci .scale != 1.0 :
24492471 new_width = max (1 , int (img .width * ci .scale ))
24502472 new_height = max (1 , int (img .height * ci .scale ))
24512473 img = img .resize ((new_width , new_height ), Image .LANCZOS )
24522474
2453- # Затем отражение
2475+ # 2. Отражение
24542476 if ci .flip_horizontal :
24552477 img = img .transpose (Image .FLIP_LEFT_RIGHT )
24562478 if ci .flip_vertical :
24572479 img = img .transpose (Image .FLIP_TOP_BOTTOM )
24582480
2459- # Затем поворот
2481+ # 3. Поворот
24602482 if ci .rotation != 0 :
24612483 img = img .rotate (ci .rotation , expand = True , resample = Image .BICUBIC )
24622484
@@ -2637,14 +2659,17 @@ def apply_props(self):
26372659 ci .flip_horizontal = self .flip_h_var .get ()
26382660 ci .flip_vertical = self .flip_v_var .get ()
26392661
2640- # Очищаем кэш
2662+ # Очищаем кэш изображения
26412663 ci .clear_cache ()
26422664
2665+ # Очищаем кэш редактора
2666+ self ._photo_images .clear ()
2667+ self ._canvas_cache_valid = False
2668+
26432669 self ._save_tree_state ()
26442670 self .tree_state ["preserve_selection" ] = True
26452671
26462672 self .refresh_tree ()
2647- self ._canvas_cache_valid = False
26482673 self .redraw_canvas ()
26492674 self .last_autosave = time .time ()
26502675
@@ -2843,22 +2868,25 @@ def on_canvas_mouse_down(self, event):
28432868 continue
28442869
28452870 # Позиция элемента
2846- img_center_x = scaled_width // 2
2847- img_center_y = scaled_height // 2
2871+ center_x_scaled = scaled_width // 2
2872+ center_y_scaled = scaled_height // 2
2873+
2874+ offset_x = int (ci .x * self .zoom_level )
2875+ offset_y = int (ci .y * self .zoom_level )
28482876
2849- pos_x = img_center_x - img .width // 2 + int ( ci . x * self . zoom_level )
2850- pos_y = img_center_y - img .height // 2 + int ( ci . y * self . zoom_level )
2877+ pos_x = canvas_x1 + center_x_scaled - img .width // 2 + offset_x
2878+ pos_y = canvas_y1 + center_y_scaled - img .height // 2 + offset_y
28512879
28522880 # Проверяем попадание
2853- if (pos_x <= event .x - canvas_x1 <= pos_x + img .width and
2854- pos_y <= event .y - canvas_y1 <= pos_y + img .height ):
2881+ if (pos_x <= event .x <= pos_x + img .width and
2882+ pos_y <= event .y <= pos_y + img .height ):
28552883
28562884 # Проверяем прозрачность пикселя
28572885 try :
28582886 is_opaque = False
28592887 if img .mode == 'RGBA' :
2860- pixel_x = int (( event .x - canvas_x1 ) - pos_x )
2861- pixel_y = int (( event .y - canvas_y1 ) - pos_y )
2888+ pixel_x = int (event .x - pos_x )
2889+ pixel_y = int (event .y - pos_y )
28622890
28632891 if 0 <= pixel_x < img .width and 0 <= pixel_y < img .height :
28642892 pixel = img .getpixel ((pixel_x , pixel_y ))
0 commit comments