Загрузка данных
import os
from PIL import Image, ImageDraw, ImageFont
import telebot
from telebot import types
PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))
CONFIG = {
"Impact": {
"image_path": "IMG_9517.png",
"font": "arialbd.ttf",
"text_settings": {
"name": {"pos": (342, 788), "size": 23, "color": (0, 0, 0, 215)},
"doc": {"pos": (547, 1084), "size": 23, "color": (0, 0, 0, 215)},
"card": {"pos": (707, 1234), "size": 23, "color": (0, 0, 0, 215)}
}
},
"Urban": {
"image_path": "IMG_9541.png",
"font": "arialbd.ttf",
"text_settings": {
"name": {"pos": (292, 785), "size": 24, "color": (0, 0, 0, 215)},
"doc": {"pos": (510, 1118), "size": 25, "color": (0, 0, 0, 215)},
"card": {"pos": (530, 1283), "size": 25, "color": (0, 0, 0, 215)}
}
},
"Progress": {
"image_path": "IMG_9536.png",
"font": "arialbd.ttf",
"text_settings": {
"name": {"pos": (268, 819), "size": 25, "color": (0, 0, 0, 215)},
"doc": {"pos": (485, 1142), "size": 26, "color": (0, 0, 0, 215)},
"card": {"pos": (660, 1305), "size": 26, "color": (0, 0, 0, 215)}
}
},
"Barakat": {
"image_path": "IMG_9539.png",
"font": "arialbd.ttf",
"text_settings": {
"name": {"pos": (301, 768), "size": 30, "color": (0, 0, 0, 215)},
"doc": {"pos": (595, 1210), "size": 30, "color": (0, 0, 0, 215)},
"card": {"pos": (895, 1295), "size": 30, "color": (0, 0, 0, 215)}
}
},
"Senim": {
"image_path": "document.png",
"font": os.path.join(PROJECT_DIR, "times.ttf"),
"input_fields": ["doc", "amount", "card", "name"],
"input_prompt": "номер документа, сумма, номер карты, имя",
"text_settings": {
"name": {"pos": (490, 515), "size": 24, "angle": 0.80, "max_width": 440, "color": (22, 30, 47, 255)},
"doc": {"pos": (206, 551), "size": 24, "angle": 0.88, "max_width": 116, "color": (24, 31, 45, 255)},
"amount": {"pos": (378, 793), "size": 24, "angle": 0.60, "max_width": 115, "color": (21, 29, 57, 255)},
"card": {"pos": (524, 854), "size": 24, "angle": 0.70, "max_width": 245, "color": (26, 36, 57, 255)}
}
},
"Muras": {
"image_path": "Мурас.png",
"font": "arialbd.ttf",
"text_settings": {
"name": {"pos": (135, 520), "size": 23, "color": (0, 0, 0, 220)},
"doc": {"pos": (345, 868), "size": 26, "color": (0, 0, 0, 220)},
"card": {"pos": (560, 1007), "size": 26, "color": (0, 0, 0, 220)}
}
},
"Ganj Moliya": {
"image_path": "IMG_0980.PNG",
"font": "arialbd.ttf",
"text_settings": {
"name": {"pos": (135, 520), "size": 23, "color": (0, 0, 0, 220)},
"doc": {"pos": (370, 868), "size": 26, "color": (0, 0, 0, 220)},
"card": {"pos": (610, 938), "size": 26, "color": (0, 0, 0, 220)}
}
},
"Freedom": {
"image_path": "IMG_0022.JPG",
"font": "arialbd.ttf",
"text_settings": {
"name": {"pos": (600, 1510), "size": 56, "color": (0, 0, 0, 190)},
"doc": {"pos": (1165, 2381), "size": 56, "color": (0, 0, 0, 190)},
"card": {"pos": (1777, 2557), "size": 56, "color": (0, 0, 0, 190)}
}
}
}
bot = telebot.TeleBot('8294680849:AAFs-f6v56Kj8uDwCkNtGlQQpkV_XmDQtM4')
def compress_image(image_path, max_size_mb=9):
"""
Сжимает изображение до указанного размера в МБ
"""
max_size_bytes = max_size_mb * 1024 * 1024
# Проверяем текущий размер файла
if os.path.getsize(image_path) <= max_size_bytes:
return image_path
# Открываем изображение
img = Image.open(image_path)
# Конвертируем в RGB если необходимо
if img.mode in ('RGBA', 'LA', 'P'):
img = img.convert('RGB')
# Начинаем с качества 85%
quality = 85
temp_path = f"temp_{os.path.basename(image_path)}"
while quality > 10:
img.save(temp_path, format='JPEG', quality=quality, optimize=True)
if os.path.getsize(temp_path) <= max_size_bytes:
return temp_path
quality -= 5
# Если даже с минимальным качеством размер большой, уменьшаем разрешение
scale_factor = 0.9
while os.path.getsize(temp_path) > max_size_bytes and scale_factor > 0.3:
new_width = int(img.width * scale_factor)
new_height = int(img.height * scale_factor)
resized_img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
resized_img.save(temp_path, format='JPEG', quality=70, optimize=True)
scale_factor -= 0.1
return temp_path
@bot.message_handler(commands=['start'])
def start(message):
markup = types.ReplyKeyboardRemove()
text = (
"Выберите одну из кнопок\n"
"После выбора бот подскажет формат данных.\n"
)
bot.send_message(message.chat.id, text, reply_markup=markup)
markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
markup.add("Impact", "Urban", "Progress", "Barakat", "Senim", "Freedom", "Ganj Moliya", "Muras")
bot.send_message(message.chat.id, "Выберите проблему:", reply_markup=markup)
@bot.message_handler(func=lambda message: message.text in ["Impact", "Urban", "Progress", "Barakat", "Senim", "Freedom", "Ganj Moliya", "Muras"])
def request_data(message):
config = CONFIG[message.text]
input_prompt = config.get("input_prompt", "номер документа, сумма, номер карты")
bot.send_message(message.chat.id, f"Хорошо, отправьте через запятую: {input_prompt}")
# Передаем выбор экрана (название проблемы) в функцию handle_data_input
bot.register_next_step_handler(message, handle_data_input, message.text)
def handle_data_input(message, screen_choice):
data = [x.strip() for x in message.text.split(',')]
user_data = {}
try:
# Проверяем, что screen_choice есть в конфиге
if screen_choice in CONFIG.keys():
input_fields = CONFIG[screen_choice].get("input_fields", ["name", "doc", "card"])
if len(data) != len(input_fields):
input_prompt = CONFIG[screen_choice].get(
"input_prompt", "номер документа, сумма, номер карты"
)
raise ValueError(f"нужно ввести: {input_prompt}")
user_data = dict(zip(input_fields, data))
screen_key = screen_choice # Используем screen_choice как ключ для выбора экрана
else:
raise ValueError("Неверный выбор экрана.")
# Генерация и отправка изображения с правильными параметрами
generate_and_send_image(message, screen_key, user_data)
except Exception as e:
bot.send_message(message.chat.id, f"Ошибка: {str(e)}. Попробуйте снова.")
def fit_font(draw, text, font_path, size, max_width=None):
font = ImageFont.truetype(font_path, size)
while max_width and size > 14:
bbox = draw.textbbox((0, 0), text, font=font)
if bbox[2] - bbox[0] <= max_width:
break
size -= 1
font = ImageFont.truetype(font_path, size)
return font
def render_image(screen_key, user_data):
config = CONFIG[screen_key]
base = Image.open(config['image_path']).convert("RGBA")
txt_layer = Image.new("RGBA", base.size, (255, 255, 255, 0))
measure_draw = ImageDraw.Draw(txt_layer)
font_path = config['font']
for key, value in user_data.items():
if key in config['text_settings']:
setting = config['text_settings'][key]
font = fit_font(
measure_draw,
value,
font_path,
setting['size'],
setting.get('max_width'),
)
field_layer = Image.new("RGBA", base.size, (255, 255, 255, 0))
field_draw = ImageDraw.Draw(field_layer)
field_draw.text(setting['pos'], value, font=font, fill=setting['color'])
angle = setting.get('angle', 0)
if angle:
field_layer = field_layer.rotate(
angle,
resample=Image.Resampling.BICUBIC,
center=setting['pos'],
)
txt_layer = Image.alpha_composite(txt_layer, field_layer)
return Image.alpha_composite(base, txt_layer)
def generate_and_send_image(message, screen_key, user_data):
try:
image_path = CONFIG[screen_key]['image_path']
if not os.path.exists(image_path):
bot.send_message(message.chat.id, f"Файл {image_path} не найден.")
return
combined = render_image(screen_key, user_data)
# Сохраняем временный файл
temp_output_path = f"temp_output_{message.chat.id}.png"
combined.save(temp_output_path)
# Сжимаем изображение если необходимо
compressed_path = compress_image(temp_output_path)
# Отправляем изображение
with open(compressed_path, 'rb') as photo:
bot.send_photo(message.chat.id, photo)
# Удаляем временные файлы
if os.path.exists(temp_output_path):
os.remove(temp_output_path)
if compressed_path != temp_output_path and os.path.exists(compressed_path):
os.remove(compressed_path)
except Exception as e:
bot.send_message(message.chat.id, f"Ошибка: {str(e)}")
if __name__ == '__main__':
print("Бот запущен @garantia_screens_bot...")
bot.infinity_polling()