Многие помнят проект place, запущенный однажды на Reddit и собравший вокруг себя немало поклонников. Суть предельно проста: раз в пять минут можно закрасить один пиксель на поле 1000×1000 пикселей в свой цвет. Я решил попробовать создать бота в телеграмм с точно такой же функцией, а также что-нибудь порисовать…
Статья носит познавательно-обучающий характер, и вот то, что можно из неё извлечь:
Для бота я буду использовать библиотеки (некоторые из них необходимо установить через pip install)(telebot, pillow):
import telebot # для бота import pickle # для открытия файла с цветами поля from pathlib import Path # для удаления неугодного файла from PIL import Image # для отправки холста пользователю import time # для высчитывания времени межу изменениями цвета
Зададим значение переменных:
st = time.time() — 100 # переменная измерения времени и его ограничения l = 100 # ширина и высота поля h = 7 # размер пикселя на изображении
Запишем в data данные из файла, который мы потом создадим (содержит цвета пикселей):
data = [] try: with open(«data.pickle», «rb») as f: data = pickle.load(f) except Exception as ex: print(«Error during unpickling object (Possibly unsupported):», ex)
Запишем токен бота сюда:
bot = telebot.TeleBot(‘токен’)
Как его получить.
Теперь сделаем объяснение работы бота и отправку текущего изображения поля по команде start:
@bot.message_handler(commands=[‘start’]) # отслеживание команды def start(message): # пояснения: bot.send_message(message.chat.id, text=»Вы находитесь в боте для группового рисования картины. В этом боте вы можете внести свой вклад в сетевой холст, на котором рисуют и другие люди. Вы можете изменить цвет одного из пикселей раз в 10 секунд. Так вы можете рисовать свои шедеврыы, но учтите, что их могут изменять другие люди.») bot.send_message(message.chat.id, text = «Чтобы провести все вышеописанные операции, необходимо отправить мне цвет пикселя в формате: x, y, красный, зелёный, синий (через запятую, без пробелов). Причём ширина поля 0-99, длина 0-99, максимальное значение каждого из цветов 255, минимальное 0. Например:») bot.send_message(message.chat.id, text = «0,0,255,255,255») bot.send_message(message.chat.id, text = «Отправь ‘к’ чтобы увидеть полученное изображение.») # берём данные из файла try: with open(«data.pickle», «rb») as f: data = pickle.load(f) except Exception as ex: print(«Error during unpickling object (Possibly unsupported):», ex) # создаём изображение с pillow img = Image.new(«RGB», (l*h, l*h), ‘black’) for i in range(l): # для каждого пикселя поля for j in range(l): # если data[i*l + j] является не нулём try: # рисуем квадрат hхh for i1 in range(h): for j1 in range(h): img.putpixel((i*h +i1, j*h +j1), tuple(data[i*l + j])) # иначе ничего не делаем (имитация бурной деятельности): except TypeError: if j // 2000 == 3: print(«0») bot.send_photo(message.chat.id, img) # отправляем полученное изображение
Далее отслеживаем любой текст от пользователя и в случае необходимости отправляем картинку:
@bot.message_handler(content_types=[‘text’]) # отслеживаем текст def func(message): # если пользователь просит изображение поля if message.text == «к» or message.text == «k» or message.text == «К»: # берём данные из файла (обновляем) try: with open(«data.pickle», «rb») as f: data = pickle.load(f) except Exception as ex: print(«Error during unpickling object (Possibly unsupported):», ex) # создаём изображение с pillow img = Image.new(«RGB», (l*h, l*h), ‘black’) for i in range(l): # для каждого пикселя поля for j in range(l): # если data[i*l + j] является не нулём (изменялся хоть раз) try: # рисуем квадрат hхh for i1 in range(h): for j1 in range(h): img.putpixel((i*h +i1, j*h +j1), tuple(data[i*l + j])) # иначе ничего не делаем (имитация бурной деятельности): except TypeError: if j // 2000 == 3: print(«0») bot.send_photo(message.chat.id, img) # отправляем полученное изображение
Если пользователь отправил сообщение не меньше минимальной длины запроса на рисование (минимальный — 0,0,0,0,0 — длина 9), проверяем на ошибки:
else: # если длиннее минимального if len(message.text) >= 9: # переменная таймера — глобальная global st # Если с прошлого изменения пикселя прошло не меньше 20 секунд if time.time() — st < 20: bot.send_message(message.chat.id, text = «слишком часто. Промежуток между сообщениями — 20 секунд») else: # преобразуем текст сообщения в массив с координатами и цветом t = message.text x = [] n = «» # с учётом разделителей for i in t: if i != «,»: n += i else: x.append n = «» x.append n = «» # просматриваем корректность цветов и координат: # не вышли ли за край поля, и т.п. a = 0 n = 0 # в случае нарушений n = 1 (флаг) while a <= len(x)-1: try: x[a] = int(x[a]) if a < 2: if x[a] > l: n = 1 else: if x[a] > 255 or x[a] < 0: n = 1 except Exception: n = 1 a += 1
Если не нашли ошибку — отслеживаем координаты рисования и красим пиксель в необходимый цвет, оповещаем пользователя, обновляем таймер:
import pickle # создаём массив data = [] data = [0] * (100 * 100) # сохраняем try: with open(«data.pickle», «wb») as f: pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL) except Exception as ex: print(«Error during pickling object (Possibly unsupported):», ex)
Не забудим запустить работу бота:
bot.polling(none_stop=True)
Вот и весь код!
Не забудем создать «data.pickle» с помощью другого кода. Он нужен единожды и запускается первым. Указываем размер поля и сохраняем (после тот же размер нужно указать в программе бота):
import pickle # создаём массив data = [] data = [0] * (100 * 100) # сохраняем try: with open(«data.pickle», «wb») as f: pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL) except Exception as ex: print(«Error during pickling object (Possibly unsupported):», ex)
Все файлы вы можете найти на GitHub.
Далее запускаем хостинг бота на pythonAnywhere (инструкция). Не забудьте установить необходимые библиотеки. Это делается с помощью обычного pip install в консоли на сайте (в инструкции описана установка библиотеки telebot, вам нужна ещё pillow (pip install pillow))
Бот успешно работает, вы можете опробовать его в телеграмме по ссылке.
После написания основного кода я решил автоматизировать скорее не запросы, а преобразование картинки в запросы.
Начнём с импорта библиотеки pillow и создания текстового файла с координатами:
from PIL import Image f = open(«result.txt», «w+»)
Далее откроем изображение (лучше пиксельарт) и спросим у пользователя координаты размещения:
img = Image.open(‘img.jpg’) print(«X:») x = int(input()) print(«Y:») y = int(input())
Для каждого пикселя изображения нужно узнать его будущее местоположение и цвет:
data = [] for i in range(img.size[0]): for j in range(img.size[1]): col = img.getpixel((i, j)) data.append(str(i+x) + «,» + str(j+y) + «,» + str(col[0]) + «,» + str(col[1]) + «,» + str(col[2]))
Записываем полученные координаты в файл:
for i in data: f.write(i + «n») f.close()
Всё! После запуска получаем то, что необходимо отправлять боту.
Так как цель тут — скорее изучение Python, то почему бы не использовать библиотеку pyautoGUI (pip install PyAutoGUI)?
Благо, нам необходимо только вписать текст и нажать Enter:
import pyautogui from time import sleep # открываем файл с координатами f = open(«result.txt») # читаем его data = f.readlines() # убираем переходы на следущую строку diction = [] for i in data: a = str(i) diction.append(a[0:len(i)-1]) # вписываем запрос в телеграм и отправляем боту for i in diction: sleep(22) pyautogui.typewrite(i, interval=0.0) pyautogui.press(‘enter’)
После запуска вышеописанного кода в течение 22 секунд необходимо перейти на вкладку telegram с открытым чатом бота и кликнуть в поле ввода сообщения.
Таким образом мы можем почти автоматически рисовать различные изображения на всем доступном холсте!
Я запустил своего бота с полем 300*300, можно попробовать его.
Все программы находятся на github.
Удачных компиляций!
Вступление
Статья носит познавательно-обучающий характер, и вот то, что можно из неё извлечь:
- Библиотека telebot даёт возможность создания телеграм бота а также отслеживания команд с использованием @bot.message_handler(commands=[]) и текста с использованием @bot.message_handler(content_types=[‘text’]).
- Библиотека telebot даёт возможность отправки сообщений с использованием bot.send_message(message.chat.id, text = «») и фото с помощью bot.send_photo(message.chat.id, img).
- Библиотека pickle позволяет просто сохранять данные в файле с помощью pickle.dump() и извлекать оттуда используя pickle.load().
- С помощью pillow можно создавать изображения используя Image.new() и изменять цвет отдельных пикселей используя img.putpixel().
- Как писать текст с помощью PyAutoGUI.
- Статья также позволяет изучить работу time.time() и создание простого таймера с её использованием.
Код бота
Для бота я буду использовать библиотеки (некоторые из них необходимо установить через pip install)(telebot, pillow):
import telebot # для бота import pickle # для открытия файла с цветами поля from pathlib import Path # для удаления неугодного файла from PIL import Image # для отправки холста пользователю import time # для высчитывания времени межу изменениями цвета
Зададим значение переменных:
st = time.time() — 100 # переменная измерения времени и его ограничения l = 100 # ширина и высота поля h = 7 # размер пикселя на изображении
Запишем в data данные из файла, который мы потом создадим (содержит цвета пикселей):
data = [] try: with open(«data.pickle», «rb») as f: data = pickle.load(f) except Exception as ex: print(«Error during unpickling object (Possibly unsupported):», ex)
Запишем токен бота сюда:
bot = telebot.TeleBot(‘токен’)
Как его получить.
Теперь сделаем объяснение работы бота и отправку текущего изображения поля по команде start:
@bot.message_handler(commands=[‘start’]) # отслеживание команды def start(message): # пояснения: bot.send_message(message.chat.id, text=»Вы находитесь в боте для группового рисования картины. В этом боте вы можете внести свой вклад в сетевой холст, на котором рисуют и другие люди. Вы можете изменить цвет одного из пикселей раз в 10 секунд. Так вы можете рисовать свои шедеврыы, но учтите, что их могут изменять другие люди.») bot.send_message(message.chat.id, text = «Чтобы провести все вышеописанные операции, необходимо отправить мне цвет пикселя в формате: x, y, красный, зелёный, синий (через запятую, без пробелов). Причём ширина поля 0-99, длина 0-99, максимальное значение каждого из цветов 255, минимальное 0. Например:») bot.send_message(message.chat.id, text = «0,0,255,255,255») bot.send_message(message.chat.id, text = «Отправь ‘к’ чтобы увидеть полученное изображение.») # берём данные из файла try: with open(«data.pickle», «rb») as f: data = pickle.load(f) except Exception as ex: print(«Error during unpickling object (Possibly unsupported):», ex) # создаём изображение с pillow img = Image.new(«RGB», (l*h, l*h), ‘black’) for i in range(l): # для каждого пикселя поля for j in range(l): # если data[i*l + j] является не нулём try: # рисуем квадрат hхh for i1 in range(h): for j1 in range(h): img.putpixel((i*h +i1, j*h +j1), tuple(data[i*l + j])) # иначе ничего не делаем (имитация бурной деятельности): except TypeError: if j // 2000 == 3: print(«0») bot.send_photo(message.chat.id, img) # отправляем полученное изображение
Далее отслеживаем любой текст от пользователя и в случае необходимости отправляем картинку:
@bot.message_handler(content_types=[‘text’]) # отслеживаем текст def func(message): # если пользователь просит изображение поля if message.text == «к» or message.text == «k» or message.text == «К»: # берём данные из файла (обновляем) try: with open(«data.pickle», «rb») as f: data = pickle.load(f) except Exception as ex: print(«Error during unpickling object (Possibly unsupported):», ex) # создаём изображение с pillow img = Image.new(«RGB», (l*h, l*h), ‘black’) for i in range(l): # для каждого пикселя поля for j in range(l): # если data[i*l + j] является не нулём (изменялся хоть раз) try: # рисуем квадрат hхh for i1 in range(h): for j1 in range(h): img.putpixel((i*h +i1, j*h +j1), tuple(data[i*l + j])) # иначе ничего не делаем (имитация бурной деятельности): except TypeError: if j // 2000 == 3: print(«0») bot.send_photo(message.chat.id, img) # отправляем полученное изображение
Если пользователь отправил сообщение не меньше минимальной длины запроса на рисование (минимальный — 0,0,0,0,0 — длина 9), проверяем на ошибки:
else: # если длиннее минимального if len(message.text) >= 9: # переменная таймера — глобальная global st # Если с прошлого изменения пикселя прошло не меньше 20 секунд if time.time() — st < 20: bot.send_message(message.chat.id, text = «слишком часто. Промежуток между сообщениями — 20 секунд») else: # преобразуем текст сообщения в массив с координатами и цветом t = message.text x = [] n = «» # с учётом разделителей for i in t: if i != «,»: n += i else: x.append n = «» x.append n = «» # просматриваем корректность цветов и координат: # не вышли ли за край поля, и т.п. a = 0 n = 0 # в случае нарушений n = 1 (флаг) while a <= len(x)-1: try: x[a] = int(x[a]) if a < 2: if x[a] > l: n = 1 else: if x[a] > 255 or x[a] < 0: n = 1 except Exception: n = 1 a += 1
Если не нашли ошибку — отслеживаем координаты рисования и красим пиксель в необходимый цвет, оповещаем пользователя, обновляем таймер:
import pickle # создаём массив data = [] data = [0] * (100 * 100) # сохраняем try: with open(«data.pickle», «wb») as f: pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL) except Exception as ex: print(«Error during pickling object (Possibly unsupported):», ex)
Не забудим запустить работу бота:
bot.polling(none_stop=True)
Вот и весь код!
Не забудем создать «data.pickle» с помощью другого кода. Он нужен единожды и запускается первым. Указываем размер поля и сохраняем (после тот же размер нужно указать в программе бота):
import pickle # создаём массив data = [] data = [0] * (100 * 100) # сохраняем try: with open(«data.pickle», «wb») as f: pickle.dump(data, f, protocol=pickle.HIGHEST_PROTOCOL) except Exception as ex: print(«Error during pickling object (Possibly unsupported):», ex)
Все файлы вы можете найти на GitHub.
Далее запускаем хостинг бота на pythonAnywhere (инструкция). Не забудьте установить необходимые библиотеки. Это делается с помощью обычного pip install в консоли на сайте (в инструкции описана установка библиотеки telebot, вам нужна ещё pillow (pip install pillow))
Бот успешно работает, вы можете опробовать его в телеграмме по ссылке.
Автоматизация
После написания основного кода я решил автоматизировать скорее не запросы, а преобразование картинки в запросы.
Начнём с импорта библиотеки pillow и создания текстового файла с координатами:
from PIL import Image f = open(«result.txt», «w+»)
Далее откроем изображение (лучше пиксельарт) и спросим у пользователя координаты размещения:
img = Image.open(‘img.jpg’) print(«X:») x = int(input()) print(«Y:») y = int(input())
Для каждого пикселя изображения нужно узнать его будущее местоположение и цвет:
data = [] for i in range(img.size[0]): for j in range(img.size[1]): col = img.getpixel((i, j)) data.append(str(i+x) + «,» + str(j+y) + «,» + str(col[0]) + «,» + str(col[1]) + «,» + str(col[2]))
Записываем полученные координаты в файл:
for i in data: f.write(i + «n») f.close()
Всё! После запуска получаем то, что необходимо отправлять боту.
Автоматизация отправки
Так как цель тут — скорее изучение Python, то почему бы не использовать библиотеку pyautoGUI (pip install PyAutoGUI)?
Благо, нам необходимо только вписать текст и нажать Enter:
import pyautogui from time import sleep # открываем файл с координатами f = open(«result.txt») # читаем его data = f.readlines() # убираем переходы на следущую строку diction = [] for i in data: a = str(i) diction.append(a[0:len(i)-1]) # вписываем запрос в телеграм и отправляем боту for i in diction: sleep(22) pyautogui.typewrite(i, interval=0.0) pyautogui.press(‘enter’)
После запуска вышеописанного кода в течение 22 секунд необходимо перейти на вкладку telegram с открытым чатом бота и кликнуть в поле ввода сообщения.
Таким образом мы можем почти автоматически рисовать различные изображения на всем доступном холсте!
Я запустил своего бота с полем 300*300, можно попробовать его.
Все программы находятся на github.
Удачных компиляций!