исправь код он считает мое загруженное фото 40x40 всем полотном и я не могу рисовать где угодно например на 200, 1, иначе скажет что я ушел за пределы, но полотно загружаемое с сервера размером 255 255.  Алгоритм исправь  он не правильный import tkinter as tk
from tkinter import ttk, filedialog, messagebox, simpledialog
import requests
from PIL import Image, ImageTk
import threading
import time
import io
import random
import queue

class PixelBattleApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Pixel Battle Manager")

        # Управление токенами с использованием очереди
        self.tokens = [
            "28862a05a3f84141b50828b6dbd78884.0d8b887f5b744531a4d51b9d3ef07f62.m2rl7z0l",
            "c2b44bf252b4459ea753dbff0dca94a6.9e374c5481af4395b6c95dbced6b979b.m2utx942",
            "0bdc81e3e4c7496da4f0ebf25e0dcdc6.b91387eb9246476f972a8e75fee4d3ab.m2rkw5so",
            "15f33cad6f824c7ca8437ab42c2fb6b0.0a9428d4a2a94afca7ae2b401d1eb79a.m2uuxcz0",
            "b3c635a83a2145c6b298e626e5f1768a.0fc91a85fcb84ef3987aaa1f20da8e34.m2uv21iv",
            "13ef609edbe3404fb113c835e7282ec8.75bdb429646848a4b6feacd703962fda.m2uv2z2a",
            "364a2bfea0584a81828104727ada7fd6.01a948b01c4c475d8fbce8656750bc8b.m2uv3tw3",
            "9f08fd41a7ef48f2b06e11c40ac0ea20.0395268728804e8e81d3939c52597a9c.m2uv4t8q",
        ]
        self.token_lock = threading.Lock()
        self.token_queue = queue.Queue()
        for token in self.tokens:
            self.token_queue.put(token)

        # Масштаб и пикселизация
        self.scale_factor = 1
        self.pixel_size = 1

        # Изображение и позиция для рисования
        self.original_image = None
        self.pixelated_image = None
        self.start_position = (0, 0)
        self.setting_start_position = False

        # Авто-рисование
        self.auto_drawing = False
        self.auto_draw_thread = None

        # Автоматическая проверка и восстановление пикселей
        self.auto_check = False
        self.auto_check_thread = None

        # Кеш для fetch_current_pixels
        self.cached_pixels = None
        self.last_fetch_time = 0
        self.fetch_lock = threading.Lock()

        # Флаг для игнорирования черного цвета
        self.ignore_black = False

        # Настройка UI и холста
        self.setup_ui()
        self.setup_canvas()

    def setup_ui(self):
        # Фрейм для управления токенами
        token_frame = ttk.LabelFrame(self.root, text="Управление токенами")
        token_frame.pack(padx=5, pady=5, fill="x")

        ttk.Button(token_frame, text="Добавить токен", command=self.add_token).pack(side="left", padx=5)
        ttk.Button(token_frame, text="Удалить токен", command=self.remove_token).pack(side="left", padx=5)
        self.token_label = ttk.Label(token_frame, text=f"Всего токенов: {len(self.tokens)}")
        self.token_label.pack(side="left", padx=10)

        # Фрейм для управления изображением
        image_frame = ttk.LabelFrame(self.root, text="Управление изображением")
        image_frame.pack(padx=5, pady=5, fill="x")

        ttk.Button(image_frame, text="Загрузить изображение", command=self.load_image).pack(side="left", padx=5)
        ttk.Button(image_frame, text="Показать оригинал", command=self.show_original_image).pack(side="left", padx=5)
        ttk.Button(image_frame, text="Начать авто-рисование", command=self.start_auto_draw).pack(side="left", padx=5)
        ttk.Button(image_frame, text="Остановить авто-рисование", command=self.stop_auto_draw).pack(side="left", padx=5)

        # Фрейм для управления масштабом и пикселизацией
        control_frame = ttk.LabelFrame(self.root, text="Настройки")
        control_frame.pack(padx=5, pady=5, fill="x")

        # Масштаб
        ttk.Label(control_frame, text="Масштаб:").pack(side="left", padx=5)
        self.scale_entry = ttk.Entry(control_frame, width=5)
        self.scale_entry.insert(0, "1")
        self.scale_entry.pack(side="left", padx=5)
        ttk.Button(control_frame, text="Применить", command=self.apply_scale).pack(side="left", padx=5)

        # Размер пикселя
        ttk.Label(control_frame, text="Размер пикселя:").pack(side="left", padx=5)
        self.pixel_size_entry = ttk.Entry(control_frame, width=5)
        self.pixel_size_entry.insert(0, "1")
        self.pixel_size_entry.pack(side="left", padx=5)
        ttk.Button(control_frame, text="Применить", command=self.apply_pixel_size).pack(side="left", padx=5)

        # Кнопка установки начальной позиции вручную
        manual_position_frame = ttk.LabelFrame(self.root, text="Начальная позиция")
        manual_position_frame.pack(padx=5, pady=5, fill="x")

        ttk.Button(manual_position_frame, text="Ввести координаты", command=self.set_start_position_manual).pack(side="left", padx=5)
        ttk.Button(manual_position_frame, text="Сбросить позицию", command=self.reset_start_position).pack(side="left", padx=5)

        # Фрейм для управления цветом
        color_frame = ttk.LabelFrame(self.root, text="Цвет пикселя")
        color_frame.pack(padx=5, pady=5, fill="x")

        ttk.Label(color_frame, text="Цвет:").pack(side="left", padx=5)
        self.color_entry = ttk.Entry(color_frame)
        self.color_entry.insert(0, "#000000")
        self.color_entry.pack(side="left", padx=5)

        # Фрейм для дополнительных настроек
        additional_frame = ttk.LabelFrame(self.root, text="Дополнительно")
        additional_frame.pack(padx=5, pady=5, fill="x")

        self.black_var = tk.BooleanVar()
        self.black_var.set(False)
        ttk.Checkbutton(additional_frame, text="Игнорировать черный цвет", variable=self.black_var).pack(side="left", padx=5)

        # Кнопки для автоматической проверки
        ttk.Button(additional_frame, text="Начать автоматическую проверку", command=self.start_auto_check).pack(side="left", padx=5)
        ttk.Button(additional_frame, text="Остановить автоматическую проверку", command=self.stop_auto_check).pack(side="left", padx=5)

    def setup_canvas(self):
        self.canvas = tk.Canvas(self.root, width=800, height=600, bg="white")
        self.canvas.pack(padx=5, pady=5)
        # Убираем привязку кликов, так как начальная позиция теперь вводится вручную

        # Хранение объектов на холсте
        self.canvas_current_image = None  # Текущее состояние пикселей с сервера
        self.canvas_loaded_image = None  # Загруженное пикселизированное изображение
        self.canvas_start_position_marker = None  # Маркер начальной позиции

    def add_token(self):
        token = simpledialog.askstring("Добавить токен", "Введите Bearer токен:")
        if token:
            with self.token_lock:
                self.tokens.append(token)
                self.token_queue.put(token)
                self.token_label.config(text=f"Всего токенов: {len(self.tokens)}")

    def remove_token(self):
        with self.token_lock:
            if self.tokens:
                removed = self.tokens.pop()
                # Перестраиваем очередь без удаленного токена
                remaining_tokens = list(self.token_queue.queue)
                remaining_tokens = [t for t in remaining_tokens if t != removed]
                self.token_queue = queue.Queue()
                for token in remaining_tokens:
                    self.token_queue.put(token)
                self.token_label.config(text=f"Всего токенов: {len(self.tokens)}")
                messagebox.showinfo("Токен удалён", f"Токен {removed} удалён.")
            else:
                messagebox.showwarning("Предупреждение", "Нет токенов для удаления.")

    def apply_scale(self):
        try:
            scale = float(self.scale_entry.get())
            if scale <= 0:
                raise ValueError
            self.scale_factor = scale
            if self.original_image:
                self.pixelize_image()
                self.update_canvas()
        except ValueError:
            messagebox.showerror("Ошибка", "Неверный коэффициент масштаба.")

    def apply_pixel_size(self):
        try:
            size = int(self.pixel_size_entry.get())
            if size <= 0:
                raise ValueError
            self.pixel_size = size
            if self.original_image:
                self.pixelize_image()
                self.update_canvas()
        except ValueError:
            messagebox.showerror("Ошибка", "Неверный размер пикселя.")

    def set_start_position_manual(self):
        try:
            x = int(simpledialog.askstring("Начальная позиция", "Введите X координату:"))
            y = int(simpledialog.askstring("Начальная позиция", "Введите Y координату:"))
            if x < 0 or y < 0:
                raise ValueError("Координаты не могут быть отрицательными.")
            self.start_position = (x, y)
            messagebox.showinfo("Позиция установлена", f"Начальная позиция установлена на ({x}, {y})")
            self.update_canvas()
        except (TypeError, ValueError) as e:
            messagebox.showerror("Ошибка", f"Неверные координаты. {e}")

    def reset_start_position(self):
        self.start_position = None
        if self.canvas_start_position_marker:
            self.canvas.delete(self.canvas_start_position_marker)
            self.canvas_start_position_marker = None
        messagebox.showinfo("Позиция сброшена", "Начальная позиция сброшена.")
        self.update_canvas()

    def pixelize_image(self):
        if self.original_image:
            width, height = self.original_image.size
            px_size = self.pixel_size
            # Пикселизация
            self.pixelated_image = self.original_image.resize(
                (width // px_size, height // px_size),
                Image.NEAREST
            ).resize((width, height), Image.NEAREST)
            # Применение масштаба
            if self.scale_factor != 1:
                new_size = (int(self.pixelated_image.width * self.scale_factor), int(self.pixelated_image.height * self.scale_factor))
                self.pixelated_image = self.pixelated_image.resize(new_size, Image.NEAREST)

    def load_image(self):
        file_path = filedialog.askopenfilename(
            filetypes=[("Файлы изображений", "*.png *.jpg *.jpeg *.bmp *.gif")]
        )
        if file_path:
            try:
                self.original_image = Image.open(file_path).convert("RGB")
                # Проверка размера и автоматическое изменение
                max_size = 40  # Максимальная ширина или высота
                if self.original_image.width > max_size or self.original_image.height > max_size:
                    self.original_image.thumbnail((max_size, max_size), Image.LANCZOS)
                    messagebox.showinfo("Изменение размера", f"Изображение было изменено до {self.original_image.size}")
                self.pixelize_image()
                # Создание изображения для отображения на холсте
                self.canvas_loaded_image = ImageTk.PhotoImage(self.pixelated_image)
                self.update_canvas()
            except Exception as e:
                messagebox.showerror("Ошибка", f"Не удалось загрузить изображение: {e}")

    def show_original_image(self):
        if self.original_image:
            original_window = tk.Toplevel(self.root)
            original_window.title("Оригинальное изображение")
            original_photo = ImageTk.PhotoImage(self.original_image)
            label = tk.Label(original_window, image=original_photo)
            label.image = original_photo  # Сохраняем ссылку
            label.pack()
        else:
            messagebox.showwarning("Предупреждение", "Нет загруженного изображения.")

    def update_canvas(self):
        def task():
            if self.pixelated_image:
                try:
                    self.fetch_current_pixels()
                except Exception as e:
                    print(f"Ошибка обновления холста: {e}")

        threading.Thread(target=task, daemon=True).start()

    def fetch_current_pixels(self):
        with self.fetch_lock:
            current_time = time.time()
            if self.cached_pixels and (current_time - self.last_fetch_time) < 10:
                print("Используем кешированные данные пикселей.")
                return  # Используем кешированные данные
            else:
                url = f"https://3years.aeza.net/api/pixels.png?{random.random()}"
                headers = {
                    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36",
                    "Accept": "*/*",
                    "Accept-Language": "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3",
                    "Accept-Encoding": "gzip, deflate, br, zstd",
                    "Referer": "https://3years.aeza.net/",
                    "Sec-Fetch-Dest": "empty",
                    "Sec-Fetch-Mode": "cors",
                    "Sec-Fetch-Site": "same-origin",
                    "Connection": "keep-alive",
                }

                try:
                    response = requests.get(url, headers=headers)
                    if response.status_code == 200:
                        self.cached_pixels = Image.open(io.BytesIO(response.content)).convert("RGB")
                        self.last_fetch_time = current_time
                        print("Получены новые данные пикселей с сервера.")
                        # Применение масштаба
                        if self.scale_factor != 1:
                            new_size = (int(self.cached_pixels.width * self.scale_factor), int(self.cached_pixels.height * self.scale_factor))
                            self.cached_pixels = self.cached_pixels.resize(new_size, Image.NEAREST)
                        photo = ImageTk.PhotoImage(self.cached_pixels)
                        self.canvas_current_image = photo  # Сохраняем ссылку
                        self.canvas.delete("all")  # Очистить холст
                        self.canvas.create_image(0, 0, anchor="nw", image=self.canvas_current_image)

                        # Отображение пикселизированного изображения, если задана начальная позиция
                        if self.start_position and self.pixelated_image:
                            # Обрезка изображения, если оно выходит за пределы холста
                            start_x, start_y = self.start_position
                            px_width, px_height = self.pixelated_image.size
                            canvas_width, canvas_height = self.cached_pixels.size

                            # Определяем область, где изображение будет отображаться
                            display_width = min(px_width, canvas_width - start_x)
                            display_height = min(px_height, canvas_height - start_y)

                            if display_width <= 0 or display_height <= 0:
                                messagebox.showerror("Ошибка", "Изображение полностью выходит за пределы холста.")
                                return

                            # Обрезаем изображение, если оно выходит за пределы
                            cropped_image = self.pixelated_image.crop((0, 0, display_width, display_height))
                            self.canvas_loaded_image = ImageTk.PhotoImage(cropped_image)
                            self.canvas.create_image(start_x, start_y, anchor="nw", image=self.canvas_loaded_image)

                            # Отображение маркера начальной позиции
                            if not self.canvas_start_position_marker:
                                self.canvas_start_position_marker = self.canvas.create_rectangle(
                                    start_x,
                                    start_y,
                                    start_x + display_width,
                                    start_y + display_height,
                                    outline="red",
                                    width=2
                                )
                        else:
                            # Если позиция не установлена, просто отображаем загруженное изображение на холсте
                            if self.pixelated_image:
                                self.canvas_loaded_image = ImageTk.PhotoImage(self.pixelated_image)
                                self.canvas.create_image(0, 0, anchor="nw", image=self.canvas_loaded_image)

                    else:
                        print(f"Не удалось получить карту пикселей: статус {response.status_code}")
                except Exception as e:
                    print(f"Ошибка при получении карты пикселей: {e}")

    def canvas_click(self, event):
        # Убрали обработку кликов, так как позиция вводится вручную
        pass

    def place_pixel(self, x, y, color):
        threading.Thread(target=self.use_token_and_place_pixel, args=(x, y, color), daemon=True).start()

    def use_token_and_place_pixel(self, x, y, color):
        if self.ignore_black and color.lower() == "#000000":
            print(f"Игнорирование рисования черного цвета на ({x},{y}).")
            return
        if self.cached_pixels:
            # Корректируем координаты с учетом масштаба
            scaled_x = int(x / self.scale_factor) if self.scale_factor != 0 else x
            scaled_y = int(y / self.scale_factor) if self.scale_factor != 0 else y
            if 0 <= scaled_x < self.cached_pixels.width and 0 <= scaled_y < self.cached_pixels.height:
                current_color = self.cached_pixels.getpixel((scaled_x, scaled_y))
                current_hex = "#%02x%02x%02x" % current_color
            else:
                print(f"Координаты пикселя ({x},{y}) вне границ изображения.")
                return
        else:
            print("Нет кешированных данных пикселей.")
            return

        if current_hex.lower() == color.lower():
            print(f"Пиксель ({x},{y}) уже нужного цвета.")
            return
        try:
            token = self.token_queue.get(block=True)
        except queue.Empty:
            print("Нет доступных токенов.")
            return

        headers = {
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36",
            "Accept": "*/*",
            "Accept-Language": "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3",
            "Accept-Encoding": "gzip, deflate, br, zstd",
            "Referer": "https://3years.aeza.net/",
            "Sec-Fetch-Dest": "empty",
            "Sec-Fetch-Mode": "cors",
            "Sec-Fetch-Site": "same-origin",
            "Connection": "keep-alive",
        }
        try:
            # Установка нового цвета пикселя
            data = {"color": color, "x": x, "y": y}
            put_response = requests.put('https://3years.aeza.net/api/pixels', headers=headers, json=data)
            if put_response.status_code == 200:
                print(f"Пиксель ({x},{y}) установлен на {color}.")
                # Обновление локального изображения
                if self.pixelated_image:
                    try:
                        # Учитываем масштаб при обновлении
                        px_x = int(x / self.scale_factor)
                        px_y = int(y / self.scale_factor)
                        if 0 <= px_x < self.pixelated_image.width and 0 <= px_y < self.pixelated_image.height:
                            self.pixelated_image.putpixel((px_x, px_y), self.hex_to_rgb(color))
                            self.update_canvas()
                        else:
                            print(f"Локальное обновление пикселя ({px_x}, {px_y}) вне границ изображения.")
                    except Exception as e:
                        print(f"Ошибка при обновлении локального изображения: {e}")
            else:
                print(f"Не удалось установить пиксель ({x},{y}): статус {put_response.status_code}")
        except Exception as e:
            print(f"Ошибка при установке пикселя ({x},{y}): {e}")
        finally:
            # Возврат токена в очередь через 5 секунд
            threading.Timer(5, self.token_queue.put, args=(token,)).start()

    def hex_to_rgb(self, hex_color):
        hex_color = hex_color.lstrip('#')
        if len(hex_color) != 6:
            raise ValueError("Неверный формат цвета.")
        r, g, b = tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))
        return (r, g, b)

    def start_auto_draw(self):
        if not self.pixelated_image:
            messagebox.showerror("Ошибка", "Нет загруженного изображения для рисования.")
            return
        if self.auto_drawing:
            messagebox.showinfo("Информация", "Авто-рисование уже запущено.")
            return
        if not self.start_position:
            messagebox.showerror("Ошибка", "Начальная позиция не установлена.")
            return
        self.auto_drawing = True
        self.auto_draw_thread = threading.Thread(target=self.auto_draw, daemon=True)
        self.auto_draw_thread.start()
        messagebox.showinfo("Информация", "Авто-рисование запущено.")

    def stop_auto_draw(self):
        if self.auto_drawing:
            self.auto_drawing = False
            messagebox.showinfo("Информация", "Авто-рисование остановлено.")
        else:
            messagebox.showinfo("Информация", "Авто-рисование не запущено.")

    def auto_draw(self):
        px_size = self.pixel_size
        width, height = self.pixelated_image.size

        # Определяем область для рисования
        start_x, start_y = self.start_position
        end_x = start_x + width
        end_y = start_y + height

        # Создаем список всех пикселей и перемешиваем его для рандомизации
        pixel_positions = [(x, y) for y in range(height) for x in range(width)]
        random.shuffle(pixel_positions)

        for idx, (x, y) in enumerate(pixel_positions):
            if not self.auto_drawing:
                print("Авто-рисование остановлено пользователем.")
                return

            color = self.pixelated_image.getpixel((x, y))
            desired_hex = "#%02x%02x%02x" % color

            if self.ignore_black and desired_hex.lower() == "#000000":
                continue  # Игнорируем черный цвет

            canvas_x = start_x + x
            canvas_y = start_y + y

            # Проверяем, находится ли координата внутри холста
            if 0 <= canvas_x < self.cached_pixels.width and 0 <= canvas_y < self.cached_pixels.height:
                self.place_pixel(canvas_x, canvas_y, desired_hex)
            else:
                # Если пиксель выходит за пределы холста, пропускаем его
                continue

            # Регулируем скорость: каждые 10 пикселей делаем паузу
            if (idx + 1) % 10 == 0:
                time.sleep(0.1)

        print("Авто-рисование завершено.")
        self.auto_drawing = False

    def start_periodic_update(self):
        # Метод больше не используется, так как мы кешируем fetch_current_pixels
        pass

    def start_auto_check(self):
        if not self.auto_check:
            self.auto_check = True
            self.auto_check_thread = threading.Thread(target=self.auto_check_pixels, daemon=True)
            self.auto_check_thread.start()
            messagebox.showinfo("Информация", "Автоматическая проверка запущена.")
        else:
            messagebox.showinfo("Информация", "Автоматическая проверка уже запущена.")

    def stop_auto_check(self):
        if self.auto_check:
            self.auto_check = False
            messagebox.showinfo("Информация", "Автоматическая проверка остановлена.")
        else:
            messagebox.showinfo("Информация", "Автоматическая проверка не запущена.")

    def auto_check_pixels(self):
        while self.auto_check:
            try:
                self.fetch_current_pixels()
                if self.pixelated_image and self.start_position:
                    start_x, start_y = self.start_position
                    width, height = self.pixelated_image.size
                    for y in range(height):
                        for x in range(width):
                            color = self.pixelated_image.getpixel((x, y))
                            desired_hex = "#%02x%02x%02x" % color
                            
                            if self.ignore_black and desired_hex.lower() == "#000000":
                                continue
                            
                            canvas_x = start_x + x
                            canvas_y = start_y + y

                            if 0 <= canvas_x < self.cached_pixels.width and 0 <= canvas_y < self.cached_pixels.height:
                                # Получаем текущий цвет пикселя с сервера
                                current_color = self.cached_pixels.getpixel((canvas_x, canvas_y))
                                current_hex = "#%02x%02x%02x" % current_color

                                if current_hex.lower() != desired_hex.lower():
                                    print(f"Пиксель ({canvas_x},{canvas_y}) изменен на {current_hex}. Восстанавливается до {desired_hex}.")
                                    self.place_pixel(canvas_x, canvas_y, desired_hex)
                # Ждем некоторое время перед следующей проверкой
                time.sleep(30)  # Проверка каждые 30 секунд
            except Exception as e:
                print(f"Ошибка в автоматической проверке: {e}")
                time.sleep(30)

    def run(self):
        # Запускаем основное окно без авто-обновления
        self.root.mainloop()

def main():
    root = tk.Tk()
    app = PixelBattleApp(root)
    app.run()

if __name__ == "__main__":
    main()