project/map_styler.py

82 lines
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import numpy as np
from PIL import Image, ImageOps, ImageFilter, ImageDraw, ImageEnhance
import random
class MapStyler:
@staticmethod
def apply_parchment_effect(pil_image, output_path=None):
"""
Применяет эффект старинного свитка к изображению PIL
Args:
pil_image: PIL Image object
output_path: необязательный путь для сохранения
Returns:
PIL Image с эффектом
"""
# Текстура пергамента
width, height = pil_image.size
parchment = MapStyler._create_parchment_texture(width, height)
# Эффект старения
result_img = Image.blend(parchment, pil_image, 0.6)
# Эффекты старения
result_img = result_img.filter(ImageFilter.SMOOTH_MORE)
result_img = ImageEnhance.Contrast(result_img).enhance(1.2)
result_img = ImageEnhance.Color(result_img).enhance(0.9)
# Декоративные элементы
result_img = MapStyler._add_decorations(result_img)
if output_path:
result_img.save(output_path, quality=95)
return result_img
@staticmethod
def _create_parchment_texture(width, height):
"""Создает текстуру пергамента"""
# Цвет пергамента
base = Image.new('RGB', (width, height), color=(240, 230, 200))
# Добавляем шум и неравномерность
noise = np.random.normal(0, 0.1, (height, width, 3)) * 255
noise = np.clip(noise, -30, 30)
noise_img = Image.fromarray(noise.astype(np.uint8), 'RGB')
return Image.blend(base, noise_img, 0.3)
@staticmethod
def _add_decorations(img):
"""Добавляет декоративные элементы"""
draw = ImageDraw.Draw(img)
width, height = img.size
# Рамка в стиле старинной книги
border_color = (139, 69, 19) # Коричневый
border_width = max(width, height) // 100
draw.rectangle([(0, 0), (width-1, height-1)], outline=border_color, width=border_width)
# Угловые узоры
corner_size = min(width, height) // 8
corners = [(0, 0, 180, 270),(width-corner_size, 0, 270, 360),(0, height-corner_size, 90, 180),(width-corner_size, height-corner_size, 0, 90)]
for x, y, start, end in corners:
draw.arc([x, y, x+corner_size, y+corner_size], start, end, fill=border_color, width=2)
# Эффект потертости по краям
mask = Image.new('L', (width, height), 255)
edge_width = min(width, height) // 15
for i in range(edge_width):
alpha = int(255 * (i / edge_width) ** 0.5)
for side in ['top', 'bottom', 'left', 'right']:
if side in ['top', 'bottom']:
box = [0, i if side == 'top' else height-1-i,
width, i+1 if side == 'top' else height-i]
else:
box = [i if side == 'left' else width-1-i, 0,
i+1 if side == 'left' else width-i, height]
mask_draw = ImageDraw.Draw(mask)
mask_draw.rectangle(box, fill=alpha)
return Image.composite(img, Image.new('RGB', img.size, (220, 210, 180)), mask)