Можешь убрать артефакты с фото точнее в тексте сни...
创建于:2026年3月24日
使用 GPT-5.4 Thinking 回答 Chat01
创建于:2026年3月24日
使用 GPT-5.4 Thinking 回答 Chat01
Можешь убрать артефакты с фото точнее в тексте снизу где три фото и проверить правильно и что самое важное грамотно написан текст это надо сделать и показать результат
pythonfrom PIL import Image img=Image.open('/mnt/data/ca616bef-783e-4d47-9d5c-9d8c912f1d81.webp') img.size (1024, 1536)
pythonfrom PIL import Image img=Image.open('/mnt/data/ca616bef-783e-4d47-9d5c-9d8c912f1d81.webp') # crop lower section regions = { 'captions': (0, 1050, 1024, 1300), 'bottom_text': (150, 1200, 900, 1500), 'full_lower': (0, 950, 1024, 1536), } for name, box in regions.items(): crop=img.crop(box) path=f'/mnt/data/{name}.png' crop.save(path) print(path, crop.size)
pythonfrom PIL import Image, ImageDraw, ImageFont, ImageFilter import cv2, numpy as np, os, textwrap, math img = cv2.imread('/mnt/data/ca616bef-783e-4d47-9d5c-9d8c912f1d81.webp') img.shape (1536, 1024, 3)
pythonfrom PIL import Image, ImageDraw, ImageFont img=Image.open('/mnt/data/ca616bef-783e-4d47-9d5c-9d8c912f1d81.webp').convert('RGBA') ann=img.copy() d=ImageDraw.Draw(ann) # grid every 100 pixels for x in range(0,ann.width,100): d.line((x,0,x,ann.height), fill=(255,0,0,80), width=1) d.text((x+2,2), str(x), fill='red') for y in range(0,ann.height,100): d.line((0,y,ann.width,y), fill=(255,0,0,80), width=1) d.text((2,y+2), str(y), fill='red') ann.save('/mnt/data/grid.png') print('/mnt/data/grid.png')
pythonfrom PIL import Image, ImageDraw, ImageFont img=Image.open('/mnt/data/ca616bef-783e-4d47-9d5c-9d8c912f1d81.webp').convert('RGBA') ann=img.copy() d=ImageDraw.Draw(ann) # grid every 100 pixels for x in range(0,ann.width,100): d.line((x,0,x,ann.height), fill=(255,0,0,80), width=1) d.text((x+2,2), str(x), fill='red') for y in range(0,ann.height,100): d.line((0,y,ann.width,y), fill=(255,0,0,80), width=1) d.text((2,y+2), str(y), fill='red') ann.save('/mnt/data/grid.png') print('/mnt/data/grid.png') <<ImageDisplayed>>
pythonfrom PIL import Image, ImageDraw, ImageFont, ImageFilter import cv2, numpy as np, os, math, textwrap src_path='/mnt/data/ca616bef-783e-4d47-9d5c-9d8c912f1d81.webp' img_cv=cv2.imread(src_path) mask=np.zeros(img_cv.shape[:2], dtype=np.uint8) # rectangles to remove existing text rects = [ (18, 1112, 314, 1178), # left caption (370, 1110, 690, 1182), # center caption (690, 1110, 1022, 1182), # right caption (10, 1278, 865, 1398), # bottom script text ] for x1,y1,x2,y2 in rects: cv2.rectangle(mask, (x1,y1), (x2,y2), 255, -1) # maybe soften mask edges slightly mask = cv2.GaussianBlur(mask, (9,9), 0) # threshold to preserve solid mask _, mask_bin = cv2.threshold(mask, 10, 255, cv2.THRESH_BINARY) inpainted = cv2.inpaint(img_cv, mask_bin, 5, cv2.INPAINT_TELEA) img = Image.fromarray(cv2.cvtColor(inpainted, cv2.COLOR_BGR2RGB)).convert('RGBA') draw = ImageDraw.Draw(img) # fonts f_caption = ImageFont.truetype('/usr/share/fonts/truetype/freefont/FreeSerifItalic.ttf', 54) f_caption_small = ImageFont.truetype('/usr/share/fonts/truetype/freefont/FreeSerifItalic.ttf', 46) f_script = ImageFont.truetype('/usr/share/fonts/truetype/freefont/FreeSerifItalic.ttf', 70) # helper to fit def fit_font(text, font_path, max_size, min_size, box, multiline=False, spacing=0): x1,y1,x2,y2 = box for size in range(max_size, min_size-1, -1): f=ImageFont.truetype(font_path,size) bbox=draw.multiline_textbbox((0,0), text, font=f, spacing=spacing, align='center') if multiline else draw.textbbox((0,0), text, font=f) w=bbox[2]-bbox[0]; h=bbox[3]-bbox[1] if w <= (x2-x1) and h <= (y2-y1): return f, w, h f=ImageFont.truetype(font_path,min_size) bbox=draw.multiline_textbbox((0,0), text, font=f, spacing=spacing, align='center') if multiline else draw.textbbox((0,0), text, font=f) return f, bbox[2]-bbox[0], bbox[3]-bbox[1] # captions captions = [ ("Потрясающие виды", (20, 1116, 316, 1178), 50), ("Бассейн с панорамным видом", (360, 1112, 700, 1180), 48), ("Закаты, которые запомнятся", (680, 1112, 1018, 1180), 44), ] for text, box, start in captions: font, w, h = fit_font(text, '/usr/share/fonts/truetype/freefont/FreeSerifItalic.ttf', start, 34, box) x1,y1,x2,y2 = box x = x1 + ((x2-x1)-w)/2 y = y1 + ((y2-y1)-h)/2 - 3 draw.text((x,y), text, font=font, fill=(20,20,20,255)) # bottom script script = "Подарите себе лето, о котором будете\nвспоминать с улыбкой!" box=(20,1278,860,1395) font, w, h = fit_font(script, '/usr/share/fonts/truetype/freefont/FreeSerifItalic.ttf', 78, 48, box, multiline=True, spacing=-2) x1,y1,x2,y2=box x = x1 + (x2-x1)/2 y = y1 + ((y2-y1)-h)/2 - 5 # shadow draw.multiline_text((x+3,y+3), script, font=font, fill=(40,25,15,120), anchor='ma', align='center', spacing=-2) draw.multiline_text((x,y), script, font=font, fill=(228,195,157,255), anchor='ma', align='center', spacing=-2) out='/mnt/data/edited_poster_v1.png' img.save(out) out '/mnt/data/edited_poster_v1.png'
pythonfrom PIL import Image, ImageDraw, ImageFont, ImageFilter import cv2, numpy as np, os, math, textwrap src_path='/mnt/data/ca616bef-783e-4d47-9d5c-9d8c912f1d81.webp' img_cv=cv2.imread(src_path) mask=np.zeros(img_cv.shape[:2], dtype=np.uint8) # rectangles to remove existing text rects = [ (18, 1112, 314, 1178), # left caption (370, 1110, 690, 1182), # center caption (690, 1110, 1022, 1182), # right caption (10, 1278, 865, 1398), # bottom script text ] for x1,y1,x2,y2 in rects: cv2.rectangle(mask, (x1,y1), (x2,y2), 255, -1) # maybe soften mask edges slightly mask = cv2.GaussianBlur(mask, (9,9), 0) # threshold to preserve solid mask _, mask_bin = cv2.threshold(mask, 10, 255, cv2.THRESH_BINARY) inpainted = cv2.inpaint(img_cv, mask_bin, 5, cv2.INPAINT_TELEA) img = Image.fromarray(cv2.cvtColor(inpainted, cv2.COLOR_BGR2RGB)).convert('RGBA') draw = ImageDraw.Draw(img) # fonts f_caption = ImageFont.truetype('/usr/share/fonts/truetype/freefont/FreeSerifItalic.ttf', 54) f_caption_small = ImageFont.truetype('/usr/share/fonts/truetype/freefont/FreeSerifItalic.ttf', 46) f_script = ImageFont.truetype('/usr/share/fonts/truetype/freefont/FreeSerifItalic.ttf', 70) # helper to fit def fit_font(text, font_path, max_size, min_size, box, multiline=False, spacing=0): x1,y1,x2,y2 = box for size in range(max_size, min_size-1, -1): f=ImageFont.truetype(font_path,size) bbox=draw.multiline_textbbox((0,0), text, font=f, spacing=spacing, align='center') if multiline else draw.textbbox((0,0), text, font=f) w=bbox[2]-bbox[0]; h=bbox[3]-bbox[1] if w <= (x2-x1) and h <= (y2-y1): return f, w, h f=ImageFont.truetype(font_path,min_size) bbox=draw.multiline_textbbox((0,0), text, font=f, spacing=spacing, align='center') if multiline else draw.textbbox((0,0), text, font=f) return f, bbox[2]-bbox[0], bbox[3]-bbox[1] # captions captions = [ ("Потрясающие виды", (20, 1116, 316, 1178), 50), ("Бассейн с панорамным видом", (360, 1112, 700, 1180), 48), ("Закаты, которые запомнятся", (680, 1112, 1018, 1180), 44), ] for text, box, start in captions: font, w, h = fit_font(text, '/usr/share/fonts/truetype/freefont/FreeSerifItalic.ttf', start, 34, box) x1,y1,x2,y2 = box x = x1 + ((x2-x1)-w)/2 y = y1 + ((y2-y1)-h)/2 - 3 draw.text((x,y), text, font=font, fill=(20,20,20,255)) # bottom script script = "Подарите себе лето, о котором будете\nвспоминать с улыбкой!" box=(20,1278,860,1395) font, w, h = fit_font(script, '/usr/share/fonts/truetype/freefont/FreeSerifItalic.ttf', 78, 48, box, multiline=True, spacing=-2) x1,y1,x2,y2=box x = x1 + (x2-x1)/2 y = y1 + ((y2-y1)-h)/2 - 5 # shadow draw.multiline_text((x+3,y+3), script, font=font, fill=(40,25,15,120), anchor='ma', align='center', spacing=-2) draw.multiline_text((x,y), script, font=font, fill=(228,195,157,255), anchor='ma', align='center', spacing=-2) out='/mnt/data/edited_poster_v1.png' img.save(out) out '/mnt/data/edited_poster_v1.png' <<ImageDisplayed>>
pythonfrom PIL import Image, ImageDraw, ImageFont import cv2, numpy as np, os, math src = cv2.imread('/mnt/data/ca616bef-783e-4d47-9d5c-9d8c912f1d81.webp') mask=np.zeros(src.shape[:2], dtype=np.uint8) # Caption boxes caption_boxes=[(10,1105,325,1185),(355,1105,700,1185),(675,1105,1024,1185)] for (x1,y1,x2,y2) in caption_boxes: roi=src[y1:y2,x1:x2] gray=cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY) # dark text threshold m=(gray<120).astype(np.uint8)*255 # maybe exclude very dark outside ribbon? but ROI mostly ribbon+below water. Let's confine to ribbon by requiring brightness of surrounding background? maybe y top of ribbon. # Use morphological opening to focus on text strokes kernel=np.ones((3,3),np.uint8) m=cv2.morphologyEx(m, cv2.MORPH_OPEN, kernel) m=cv2.dilate(m, kernel, iterations=1) mask[y1:y2,x1:x2]=np.maximum(mask[y1:y2,x1:x2], m) # script box x1,y1,x2,y2=(0,1270,840,1405) roi=src[y1:y2,x1:x2] hsv=cv2.cvtColor(roi, cv2.COLOR_BGR2HSV) # gold-ish text threshold: saturation >30, value>120 maybe, hue 5-35 m=((hsv[:,:,0] < 35) & (hsv[:,:,1] > 40) & (hsv[:,:,2] > 100)).astype(np.uint8)*255 kernel=np.ones((3,3),np.uint8) m=cv2.morphologyEx(m, cv2.MORPH_OPEN, kernel) m=cv2.dilate(m, kernel, iterations=1) mask[y1:y2,x1:x2]=np.maximum(mask[y1:y2,x1:x2], m) # maybe manual cleanup include the strange "ие" in same threshold should be included cv2.imwrite('/mnt/data/mask_text.png', mask) inpaint=cv2.inpaint(src, mask, 3, cv2.INPAINT_TELEA) cv2.imwrite('/mnt/data/inpaint_text.png', inpaint) print('saved')
pythonfrom PIL import Image, ImageDraw, ImageFont import cv2, numpy as np, os, math src = cv2.imread('/mnt/data/ca616bef-783e-4d47-9d5c-9d8c912f1d81.webp') mask=np.zeros(src.shape[:2], dtype=np.uint8) # Caption boxes caption_boxes=[(10,1105,325,1185),(355,1105,700,1185),(675,1105,1024,1185)] for (x1,y1,x2,y2) in caption_boxes: roi=src[y1:y2,x1:x2] gray=cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY) # dark text threshold m=(gray<120).astype(np.uint8)*255 # maybe exclude very dark outside ribbon? but ROI mostly ribbon+below water. Let's confine to ribbon by requiring brightness of surrounding background? maybe y top of ribbon. # Use morphological opening to focus on text strokes kernel=np.ones((3,3),np.uint8) m=cv2.morphologyEx(m, cv2.MORPH_OPEN, kernel) m=cv2.dilate(m, kernel, iterations=1) mask[y1:y2,x1:x2]=np.maximum(mask[y1:y2,x1:x2], m) # script box x1,y1,x2,y2=(0,1270,840,1405) roi=src[y1:y2,x1:x2] hsv=cv2.cvtColor(roi, cv2.COLOR_BGR2HSV) # gold-ish text threshold: saturation >30, value>120 maybe, hue 5-35 m=((hsv[:,:,0] < 35) & (hsv[:,:,1] > 40) & (hsv[:,:,2] > 100)).astype(np.uint8)*255 kernel=np.ones((3,3),np.uint8) m=cv2.morphologyEx(m, cv2.MORPH_OPEN, kernel) m=cv2.dilate(m, kernel, iterations=1) mask[y1:y2,x1:x2]=np.maximum(mask[y1:y2,x1:x2], m) # maybe manual cleanup include the strange "ие" in same threshold should be included cv2.imwrite('/mnt/data/mask_text.png', mask) inpaint=cv2.inpaint(src, mask, 3, cv2.INPAINT_TELEA) cv2.imwrite('/mnt/data/inpaint_text.png', inpaint) print('saved') <<ImageDisplayed>>
pythonfrom PIL import Image, ImageDraw, ImageFont, ImageFilter import numpy as np, random, math, os random.seed(1) src = Image.open('/mnt/data/ca616bef-783e-4d47-9d5c-9d8c912f1d81.webp').convert('RGBA') img = src.copy() def rough_ribbon(size, fill=(235,216,187,235), blur=4, taper=18, rough=8, angle=0): w,h=size mask=Image.new('L', size, 0) d=ImageDraw.Draw(mask) # generate top and bottom edges xs=list(range(0,w+1, max(12, w//20))) top=[(x, max(0, taper//3 + random.randint(-rough, rough))) for x in xs] bottom=[(x, h - taper//3 + random.randint(-rough, rough)) for x in reversed(xs)] pts=top+bottom d.polygon(pts, fill=255) mask=mask.filter(ImageFilter.GaussianBlur(blur)) ribbon=Image.new('RGBA', size, fill) # add subtle texture stripes arr=np.array(ribbon) yy,xx=np.mgrid[0:h,0:w] noise=(np.sin(xx/9.0)+np.sin((xx+yy)/17.0)+np.sin(yy/13.0))*3 for c in range(3): arr[:,:,c]=np.clip(arr[:,:,c]+noise,0,255) ribbon=Image.fromarray(arr.astype('uint8'),'RGBA') ribbon.putalpha(mask) if angle: ribbon=ribbon.rotate(angle, resample=Image.Resampling.BICUBIC, expand=True) return ribbon # overlay ribbons ribbons=[ ((18,1115), (300,54), -1), ((368,1112), (320,56), -1), ((682,1112), (330,56), 1), ] for (x,y), size, ang in ribbons: rib=rough_ribbon(size, angle=ang) img.alpha_composite(rib, (x,y)) draw=ImageDraw.Draw(img) def fit_text_center(box, text, font_path, max_size, min_size, fill, stroke_fill=None, stroke_width=0, multiline=False, spacing=0): x1,y1,x2,y2=box for s in range(max_size, min_size-1, -1): font=ImageFont.truetype(font_path, s) bbox=(draw.multiline_textbbox((0,0), text, font=font, align='center', spacing=spacing) if multiline else draw.textbbox((0,0), text, font=font)) w,h=bbox[2]-bbox[0], bbox[3]-bbox[1] if w <= x2-x1-10 and h <= y2-y1-6: break else: font=ImageFont.truetype(font_path, min_size) bbox=(draw.multiline_textbbox((0,0), text, font=font, align='center', spacing=spacing) if multiline else draw.textbbox((0,0), text, font=font)) w,h=bbox[2]-bbox[0], bbox[3]-bbox[1] x=x1+(x2-x1-w)/2 y=y1+(y2-y1-h)/2-2 if multiline: draw.multiline_text((x1+(x2-x1)/2,y), text, font=font, fill=fill, align='center', anchor='ma', spacing=spacing, stroke_width=stroke_width, stroke_fill=stroke_fill) else: draw.text((x,y), text, font=font, fill=fill, stroke_width=stroke_width, stroke_fill=stroke_fill) cap_font='/usr/share/fonts/truetype/dejavu/DejaVuSerif-Italic.ttf' text_fill=(28,22,18,255) fit_text_center((22,1118,314,1170),"Потрясающие виды",cap_font,42,28,text_fill) fit_text_center((374,1115,684,1172),"Панорамный бассейн",cap_font,42,28,text_fill) fit_text_center((690,1114,1008,1174),"Закаты, которые запомнятся",cap_font,37,24,text_fill) # bottom patch def feather_rect(size, radius=20, fill=(8,41,69,160), blur=18): w,h=size mask=Image.new('L', size, 0) d=ImageDraw.Draw(mask) d.rounded_rectangle((8,8,w-8,h-8), radius=radius, fill=255) mask=mask.filter(ImageFilter.GaussianBlur(blur)) patch=Image.new('RGBA', size, fill) patch.putalpha(mask) return patch patch=feather_rect((820,125), fill=(9,44,70,175), blur=16) img.alpha_composite(patch, (16,1278)) script_font='/usr/share/fonts/truetype/freefont/FreeSerifItalic.ttf' script="Подарите себе лето, о котором будете\nвспоминать с улыбкой!" # center in box x1,y1,x2,y2=(20,1280,835,1390) for s in range(72,44,-1): font=ImageFont.truetype(script_font,s) bbox=draw.multiline_textbbox((0,0),script,font=font,align='center',spacing=-6) w,h=bbox[2]-bbox[0],bbox[3]-bbox[1] if w <= x2-x1-20 and h <= y2-y1: break gold=(229,197,158,255) shadow=(39,24,16,140) cx=x1+(x2-x1)/2 y=y1+((y2-y1)-h)/2-4 draw.multiline_text((cx+3,y+3),script,font=font,fill=shadow,anchor='ma',align='center',spacing=-6) draw.multiline_text((cx,y),script,font=font,fill=gold,anchor='ma',align='center',spacing=-6) out='/mnt/data/edited_poster_v2.png' img.save(out) out '/mnt/data/edited_poster_v2.png'
pythonfrom PIL import Image, ImageDraw, ImageFont, ImageFilter import numpy as np, random, math, os random.seed(1) src = Image.open('/mnt/data/ca616bef-783e-4d47-9d5c-9d8c912f1d81.webp').convert('RGBA') img = src.copy() def rough_ribbon(size, fill=(235,216,187,235), blur=4, taper=18, rough=8, angle=0): w,h=size mask=Image.new('L', size, 0) d=ImageDraw.Draw(mask) # generate top and bottom edges xs=list(range(0,w+1, max(12, w//20))) top=[(x, max(0, taper//3 + random.randint(-rough, rough))) for x in xs] bottom=[(x, h - taper//3 + random.randint(-rough, rough)) for x in reversed(xs)] pts=top+bottom d.polygon(pts, fill=255) mask=mask.filter(ImageFilter.GaussianBlur(blur)) ribbon=Image.new('RGBA', size, fill) # add subtle texture stripes arr=np.array(ribbon) yy,xx=np.mgrid[0:h,0:w] noise=(np.sin(xx/9.0)+np.sin((xx+yy)/17.0)+np.sin(yy/13.0))*3 for c in range(3): arr[:,:,c]=np.clip(arr[:,:,c]+noise,0,255) ribbon=Image.fromarray(arr.astype('uint8'),'RGBA') ribbon.putalpha(mask) if angle: ribbon=ribbon.rotate(angle, resample=Image.Resampling.BICUBIC, expand=True) return ribbon # overlay ribbons ribbons=[ ((18,1115), (300,54), -1), ((368,1112), (320,56), -1), ((682,1112), (330,56), 1), ] for (x,y), size, ang in ribbons: rib=rough_ribbon(size, angle=ang) img.alpha_composite(rib, (x,y)) draw=ImageDraw.Draw(img) def fit_text_center(box, text, font_path, max_size, min_size, fill, stroke_fill=None, stroke_width=0, multiline=False, spacing=0): x1,y1,x2,y2=box for s in range(max_size, min_size-1, -1): font=ImageFont.truetype(font_path, s) bbox=(draw.multiline_textbbox((0,0), text, font=font, align='center', spacing=spacing) if multiline else draw.textbbox((0,0), text, font=font)) w,h=bbox[2]-bbox[0], bbox[3]-bbox[1] if w <= x2-x1-10 and h <= y2-y1-6: break else: font=ImageFont.truetype(font_path, min_size) bbox=(draw.multiline_textbbox((0,0), text, font=font, align='center', spacing=spacing) if multiline else draw.textbbox((0,0), text, font=font)) w,h=bbox[2]-bbox[0], bbox[3]-bbox[1] x=x1+(x2-x1-w)/2 y=y1+(y2-y1-h)/2-2 if multiline: draw.multiline_text((x1+(x2-x1)/2,y), text, font=font, fill=fill, align='center', anchor='ma', spacing=spacing, stroke_width=stroke_width, stroke_fill=stroke_fill) else: draw.text((x,y), text, font=font, fill=fill, stroke_width=stroke_width, stroke_fill=stroke_fill) cap_font='/usr/share/fonts/truetype/dejavu/DejaVuSerif-Italic.ttf' text_fill=(28,22,18,255) fit_text_center((22,1118,314,1170),"Потрясающие виды",cap_font,42,28,text_fill) fit_text_center((374,1115,684,1172),"Панорамный бассейн",cap_font,42,28,text_fill) fit_text_center((690,1114,1008,1174),"Закаты, которые запомнятся",cap_font,37,24,text_fill) # bottom patch def feather_rect(size, radius=20, fill=(8,41,69,160), blur=18): w,h=size mask=Image.new('L', size, 0) d=ImageDraw.Draw(mask) d.rounded_rectangle((8,8,w-8,h-8), radius=radius, fill=255) mask=mask.filter(ImageFilter.GaussianBlur(blur)) patch=Image.new('RGBA', size, fill) patch.putalpha(mask) return patch patch=feather_rect((820,125), fill=(9,44,70,175), blur=16) img.alpha_composite(patch, (16,1278)) script_font='/usr/share/fonts/truetype/freefont/FreeSerifItalic.ttf' script="Подарите себе лето, о котором будете\nвспоминать с улыбкой!" # center in box x1,y1,x2,y2=(20,1280,835,1390) for s in range(72,44,-1): font=ImageFont.truetype(script_font,s) bbox=draw.multiline_textbbox((0,0),script,font=font,align='center',spacing=-6) w,h=bbox[2]-bbox[0],bbox[3]-bbox[1] if w <= x2-x1-20 and h <= y2-y1: break gold=(229,197,158,255) shadow=(39,24,16,140) cx=x1+(x2-x1)/2 y=y1+((y2-y1)-h)/2-4 draw.multiline_text((cx+3,y+3),script,font=font,fill=shadow,anchor='ma',align='center',spacing=-6) draw.multiline_text((cx,y),script,font=font,fill=gold,anchor='ma',align='center',spacing=-6) out='/mnt/data/edited_poster_v2.png' img.save(out) out '/mnt/data/edited_poster_v2.png' <<ImageDisplayed>>
pythonfrom PIL import Image, ImageDraw, ImageFont, ImageFilter import numpy as np, random, math random.seed(2) src = Image.open('/mnt/data/ca616bef-783e-4d47-9d5c-9d8c912f1d81.webp').convert('RGBA') img = src.copy() def brush_patch(size, fill=(236,217,188,255), blur=3, rough=10): w,h=size mask=Image.new('L', size, 0) d=ImageDraw.Draw(mask) step=max(10,w//18) xs=list(range(0,w+step,step)) top=[(x, max(0, 8+random.randint(-rough, rough))) for x in xs] bottom=[(x, h-8+random.randint(-rough, rough)) for x in reversed(xs)] d.polygon(top+bottom, fill=255) # add side bristle effects for y in range(8,h-8,8): if random.random() < 0.4: d.line((0,y, random.randint(4,18), y+random.randint(-2,2)), fill=255, width=random.randint(1,3)) if random.random() < 0.4: d.line((w-random.randint(4,18), y+random.randint(-2,2), w,y), fill=255, width=random.randint(1,3)) mask=mask.filter(ImageFilter.GaussianBlur(blur)) patch=Image.new('RGBA', size, fill) # subtle texture arr=np.array(patch).astype(np.int16) yy,xx=np.mgrid[0:h,0:w] noise=(np.sin(xx/8)+np.sin((xx+yy)/19)+np.sin(yy/11))*2 arr[:,:,:3]=np.clip(arr[:,:,:3]+noise[:,:,None],0,255) patch=Image.fromarray(arr.astype('uint8'),'RGBA') patch.putalpha(mask) return patch # More opaque ribbons larger placements=[ ((10,1104),(315,78),-2), ((350,1104),(360,80),-1), ((676,1106),(348,80),1), ] for (x,y), size, angle in placements: rib=brush_patch(size) rib=rib.rotate(angle, resample=Image.Resampling.BICUBIC, expand=True) img.alpha_composite(rib,(x,y)) draw=ImageDraw.Draw(img) cap_font='/usr/share/fonts/truetype/dejavu/DejaVuSerif-Italic.ttf' def draw_center(text, box, max_size, min_size=24, fill=(25,20,18,255)): x1,y1,x2,y2=box for s in range(max_size,min_size-1,-1): f=ImageFont.truetype(cap_font,s) bbox=draw.textbbox((0,0),text,font=f) w,h=bbox[2]-bbox[0],bbox[3]-bbox[1] if w<=x2-x1-18 and h<=y2-y1-8: break x=x1+(x2-x1-w)/2 y=y1+(y2-y1-h)/2-3 draw.text((x,y),text,font=f,fill=fill) draw_center("Потрясающие виды",(15,1110,315,1178),42) draw_center("Панорамный бассейн",(360,1110,690,1178),40) draw_center("Незабываемые закаты",(690,1110,1008,1178),38) # bottom opaque patch larger def soft_patch(size, fill=(8,43,70,230), radius=18, blur=16): w,h=size mask=Image.new('L',size,0) d=ImageDraw.Draw(mask) d.rounded_rectangle((10,10,w-10,h-10),radius=radius,fill=255) mask=mask.filter(ImageFilter.GaussianBlur(blur)) patch=Image.new('RGBA', size, fill) # slight texture arr=np.array(patch).astype(np.int16) yy,xx=np.mgrid[0:h,0:w] noise=(np.sin(xx/9)+np.sin((xx+yy)/15)+np.sin(yy/7))*3 arr[:,:,:3]=np.clip(arr[:,:,:3]+noise[:,:,None],0,255) patch=Image.fromarray(arr.astype('uint8'),'RGBA') patch.putalpha(mask) return patch img.alpha_composite(soft_patch((840,145)), (8,1268)) draw=ImageDraw.Draw(img) script="Подарите себе лето, о котором будете\nвспоминать с улыбкой!" script_font='/usr/share/fonts/truetype/freefont/FreeSerifItalic.ttf' x1,y1,x2,y2=(20,1276,836,1392) for s in range(70,46,-1): f=ImageFont.truetype(script_font,s) bbox=draw.multiline_textbbox((0,0),script,font=f,align='center',spacing=-8) w,h=bbox[2]-bbox[0],bbox[3]-bbox[1] if w <= x2-x1-20 and h <= y2-y1-10: break cx=(x1+x2)/2 y=y1+((y2-y1)-h)/2-4 gold=(229,196,158,255); shadow=(30,20,12,150) draw.multiline_text((cx+3,y+3),script,font=f,fill=shadow,anchor='ma',align='center',spacing=-8) draw.multiline_text((cx,y),script,font=f,fill=gold,anchor='ma',align='center',spacing=-8) out='/mnt/data/edited_poster_v3.png' img.save(out) out '/mnt/data/edited_poster_v3.png'
pythonfrom PIL import Image, ImageDraw, ImageFont, ImageFilter import numpy as np, random, math random.seed(2) src = Image.open('/mnt/data/ca616bef-783e-4d47-9d5c-9d8c912f1d81.webp').convert('RGBA') img = src.copy() def brush_patch(size, fill=(236,217,188,255), blur=3, rough=10): w,h=size mask=Image.new('L', size, 0) d=ImageDraw.Draw(mask) step=max(10,w//18) xs=list(range(0,w+step,step)) top=[(x, max(0, 8+random.randint(-rough, rough))) for x in xs] bottom=[(x, h-8+random.randint(-rough, rough)) for x in reversed(xs)] d.polygon(top+bottom, fill=255) # add side bristle effects for y in range(8,h-8,8): if random.random() < 0.4: d.line((0,y, random.randint(4,18), y+random.randint(-2,2)), fill=255, width=random.randint(1,3)) if random.random() < 0.4: d.line((w-random.randint(4,18), y+random.randint(-2,2), w,y), fill=255, width=random.randint(1,3)) mask=mask.filter(ImageFilter.GaussianBlur(blur)) patch=Image.new('RGBA', size, fill) # subtle texture arr=np.array(patch).astype(np.int16) yy,xx=np.mgrid[0:h,0:w] noise=(np.sin(xx/8)+np.sin((xx+yy)/19)+np.sin(yy/11))*2 arr[:,:,:3]=np.clip(arr[:,:,:3]+noise[:,:,None],0,255) patch=Image.fromarray(arr.astype('uint8'),'RGBA') patch.putalpha(mask) return patch # More opaque ribbons larger placements=[ ((10,1104),(315,78),-2), ((350,1104),(360,80),-1), ((676,1106),(348,80),1), ] for (x,y), size, angle in placements: rib=brush_patch(size) rib=rib.rotate(angle, resample=Image.Resampling.BICUBIC, expand=True) img.alpha_composite(rib,(x,y)) draw=ImageDraw.Draw(img) cap_font='/usr/share/fonts/truetype/dejavu/DejaVuSerif-Italic.ttf' def draw_center(text, box, max_size, min_size=24, fill=(25,20,18,255)): x1,y1,x2,y2=box for s in range(max_size,min_size-1,-1): f=ImageFont.truetype(cap_font,s) bbox=draw.textbbox((0,0),text,font=f) w,h=bbox[2]-bbox[0],bbox[3]-bbox[1] if w<=x2-x1-18 and h<=y2-y1-8: break x=x1+(x2-x1-w)/2 y=y1+(y2-y1-h)/2-3 draw.text((x,y),text,font=f,fill=fill) draw_center("Потрясающие виды",(15,1110,315,1178),42) draw_center("Панорамный бассейн",(360,1110,690,1178),40) draw_center("Незабываемые закаты",(690,1110,1008,1178),38) # bottom opaque patch larger def soft_patch(size, fill=(8,43,70,230), radius=18, blur=16): w,h=size mask=Image.new('L',size,0) d=ImageDraw.Draw(mask) d.rounded_rectangle((10,10,w-10,h-10),radius=radius,fill=255) mask=mask.filter(ImageFilter.GaussianBlur(blur)) patch=Image.new('RGBA', size, fill) # slight texture arr=np.array(patch).astype(np.int16) yy,xx=np.mgrid[0:h,0:w] noise=(np.sin(xx/9)+np.sin((xx+yy)/15)+np.sin(yy/7))*3 arr[:,:,:3]=np.clip(arr[:,:,:3]+noise[:,:,None],0,255) patch=Image.fromarray(arr.astype('uint8'),'RGBA') patch.putalpha(mask) return patch img.alpha_composite(soft_patch((840,145)), (8,1268)) draw=ImageDraw.Draw(img) script="Подарите себе лето, о котором будете\nвспоминать с улыбкой!" script_font='/usr/share/fonts/truetype/freefont/FreeSerifItalic.ttf' x1,y1,x2,y2=(20,1276,836,1392) for s in range(70,46,-1): f=ImageFont.truetype(script_font,s) bbox=draw.multiline_textbbox((0,0),script,font=f,align='center',spacing=-8) w,h=bbox[2]-bbox[0],bbox[3]-bbox[1] if w <= x2-x1-20 and h <= y2-y1-10: break cx=(x1+x2)/2 y=y1+((y2-y1)-h)/2-4 gold=(229,196,158,255); shadow=(30,20,12,150) draw.multiline_text((cx+3,y+3),script,font=f,fill=shadow,anchor='ma',align='center',spacing=-8) draw.multiline_text((cx,y),script,font=f,fill=gold,anchor='ma',align='center',spacing=-8) out='/mnt/data/edited_poster_v3.png' img.save(out) out '/mnt/data/edited_poster_v3.png' <<ImageDisplayed>>
pythonfrom PIL import Image, ImageDraw, ImageFont, ImageFilter import numpy as np, random, math random.seed(3) src = Image.open('/mnt/data/ca616bef-783e-4d47-9d5c-9d8c912f1d81.webp').convert('RGBA') img = src.copy() def brush_patch(size, fill=(236,217,188,255), blur=2, rough=8): w,h=size mask=Image.new('L', size, 0) d=ImageDraw.Draw(mask) step=max(10,w//20) xs=list(range(0,w+step,step)) top=[(x, max(0, 6+random.randint(-rough, rough))) for x in xs] bottom=[(x, h-6+random.randint(-rough, rough)) for x in reversed(xs)] d.polygon(top+bottom, fill=255) for y in range(5,h-5 '/mnt/data/edited_poster_v4.png'
pythonfrom PIL import Image, ImageDraw, ImageFont, ImageFilter import numpy as np, random, math random.seed(3) src = Image.open('/mnt/data/ca616bef-783e-4d47-9d5c-9d8c912f1d81.webp').convert('RGBA') img = src.copy() def brush_patch(size, fill=(236,217,188,255), blur=2, rough=8): w,h=size mask=Image.new('L', size, 0) d=ImageDraw.Draw(mask) step=max(10,w//20) xs=list(range(0,w+step,step)) top=[(x, max(0, 6+random.randint(-rough, rough))) for x in xs] bottom=[(x, h-6+random.randint(-rough, rough)) for x in reversed(xs)] d.polygon(top+bottom, fill=255) for y in range(5,h-5 '/mnt/data/edited_poster_v4.png' <<ImageDisplayed>>
pythonfrom PIL import Image, ImageDraw, ImageFont, ImageFilter import numpy as np, random random.seed(3) src = Image.open('/mnt/data/ca616bef-783e-4d47-9d5c-9d8c912f1d81.webp').convert('RGBA') img = src.copy() def brush_patch(size, fill=(236,217,188,255), blur=2, rough=8): w,h=size mask=Image.new('L', size, 0) d=ImageDraw.Draw(mask) step=max(10,w//20) xs=list(range(0,w+step,step)) top=[(x, max(0, 6+random.randint(-rough, rough))) for x in xs] bottom=[(x, h-6+random.randint(-rough, rough)) for x in reversed(xs)] d.polygon(top+bottom, fill=255) for y in range(5,h-5,7): if random.random() < 0 '/mnt/data/aitodor_poster_fixed.png'
pythonfrom PIL import Image, ImageDraw, ImageFont, ImageFilter import numpy as np, random random.seed(3) src = Image.open('/mnt/data/ca616bef-783e-4d47-9d5c-9d8c912f1d81.webp').convert('RGBA') img = src.copy() def brush_patch(size, fill=(236,217,188,255), blur=2, rough=8): w,h=size mask=Image.new('L', size, 0) d=ImageDraw.Draw(mask) step=max(10,w//20) xs=list(range(0,w+step,step)) top=[(x, max(0, 6+random.randint(-rough, rough))) for x in xs] bottom=[(x, h-6+random.randint(-rough, rough)) for x in reversed(xs)] d.polygon(top+bottom, fill=255) for y in range(5,h-5,7): if random.random() < 0 '/mnt/data/aitodor_poster_fixed.png' <<ImageDisplayed>>
Готово.
Исправил артефакты в нижнем блоке и вычистил текст. Заодно поправил формулировки, чтобы звучало естественнее по-русски:
Файлы:
Могу сделать ещё одну версию, где сохраню исходные фразы максимально близко к оригиналу, но без ошибок и артефактов.