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)