import io import math from PIL import Image, ImageDraw from lama_cleaner.helper import load_img from lama_cleaner.plugins.base_plugin import BasePlugin def keep_ratio_resize(img, size, resample=Image.BILINEAR): if img.width > img.height: w = size h = int(img.height * size / img.width) else: h = size w = int(img.width * size / img.height) return img.resize((w, h), resample) def cubic_bezier(p1, p2, duration: int, frames: int): """ Args: p1: p2: duration: Total duration of the curve frames: Returns: """ x0, y0 = (0, 0) x1, y1 = p1 x2, y2 = p2 x3, y3 = (1, 1) def cal_y(t): return ( math.pow(1 - t, 3) * y0 + 3 * math.pow(1 - t, 2) * t * y1 + 3 * (1 - t) * math.pow(t, 2) * y2 + math.pow(t, 3) * y3 ) def cal_x(t): return ( math.pow(1 - t, 3) * x0 + 3 * math.pow(1 - t, 2) * t * x1 + 3 * (1 - t) * math.pow(t, 2) * x2 + math.pow(t, 3) * x3 ) res = [] for t in range(0, 1 * frames, duration): t = t / frames res.append((cal_x(t), cal_y(t))) res.append((1, 0)) return res def make_compare_gif( clean_img: Image.Image, src_img: Image.Image, max_side_length: int = 600, splitter_width: int = 5, splitter_color=(255, 203, 0, int(255 * 0.73)), ): if clean_img.size != src_img.size: clean_img = clean_img.resize(src_img.size, Image.BILINEAR) duration_per_frame = 20 num_frames = 50 # erase-in-out cubic_bezier_points = cubic_bezier((0.33, 0), (0.66, 1), 1, num_frames) cubic_bezier_points.reverse() max_side_length = min(max_side_length, max(clean_img.size)) src_img = keep_ratio_resize(src_img, max_side_length) clean_img = keep_ratio_resize(clean_img, max_side_length) width, height = src_img.size # Generate images to make Gif from right to left images = [] for i in range(num_frames): new_frame = Image.new("RGB", (width, height)) new_frame.paste(clean_img, (0, 0)) left = int(cubic_bezier_points[i][0] * width) cropped_src_img = src_img.crop((left, 0, width, height)) new_frame.paste(cropped_src_img, (left, 0, width, height)) if i != num_frames - 1: # draw a yellow splitter on the edge of the cropped image draw = ImageDraw.Draw(new_frame) draw.line( [(left, 0), (left, height)], width=splitter_width, fill=splitter_color ) images.append(new_frame) for i in range(30): images.append(src_img) cubic_bezier_points.reverse() # Generate images to make Gif from left to right for i in range(num_frames): new_frame = Image.new("RGB", (width, height)) new_frame.paste(src_img, (0, 0)) right = int(cubic_bezier_points[i][0] * width) cropped_src_img = clean_img.crop((0, 0, right, height)) new_frame.paste(cropped_src_img, (0, 0, right, height)) if i != num_frames - 1: # draw a yellow splitter on the edge of the cropped image draw = ImageDraw.Draw(new_frame) draw.line( [(right, 0), (right, height)], width=splitter_width, fill=splitter_color ) images.append(new_frame) for _ in range(30): images.append(clean_img) img_byte_arr = io.BytesIO() clean_img.save( img_byte_arr, format="GIF", save_all=True, include_color_table=True, append_images=images, optimize=False, duration=duration_per_frame, loop=0, ) return img_byte_arr.getvalue() class MakeGIF(BasePlugin): name = "MakeGIF" def __call__(self, rgb_np_img, files, form): origin_image = rgb_np_img clean_image_bytes = files["clean_img"].read() clean_image, _ = load_img(clean_image_bytes) gif_bytes = make_compare_gif( Image.fromarray(origin_image), Image.fromarray(clean_image) ) return gif_bytes