File size: 3,505 Bytes
346533a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
from typing import List, Literal

from pil_utils import BuildImage
from pydantic import Field

from meme_generator import MemeArgsModel, MemeArgsParser, MemeArgsType, add_meme
from meme_generator.utils import (
    FrameAlignPolicy,
    Maker,
    make_gif_or_combined_gif,
    make_jpg_or_gif,
)

help = "生成模式"

parser = MemeArgsParser(prefix_chars="-/")
group = parser.add_mutually_exclusive_group()
group.add_argument(
    "--mode",
    type=str,
    choices=["normal", "circle", "loop"],
    default="normal",
    help=help,
)
group.add_argument("--circle", "/套娃", action="store_const", const="circle", dest="mode")
group.add_argument("--loop", "/循环", action="store_const", const="loop", dest="mode")


class Model(MemeArgsModel):
    mode: Literal["normal", "loop", "circle"] = Field("normal", description=help)


def always_normal(img: BuildImage):
    def make(img: BuildImage) -> BuildImage:
        img_big = img.convert("RGBA").resize_width(500)
        img_small = img.convert("RGBA").resize_width(100)
        h1 = img_big.height
        h2 = max(img_small.height, 80)
        frame = BuildImage.new("RGBA", (500, h1 + h2 + 10), "white")
        frame.paste(img_big, alpha=True).paste(
            img_small, (290, h1 + 5 + (h2 - img_small.height) // 2), alpha=True
        )
        frame.draw_text(
            (20, h1 + 5, 280, h1 + h2 + 5), "要我一直", halign="right", max_fontsize=60
        )
        frame.draw_text(
            (400, h1 + 5, 480, h1 + h2 + 5), "吗", halign="left", max_fontsize=60
        )
        return frame

    return make_jpg_or_gif(img, make)


def always_always(img: BuildImage, loop: bool = False):
    tmp_img = img.convert("RGBA").resize_width(500)
    img_h = tmp_img.height
    text_h = tmp_img.resize_width(100).height + tmp_img.resize_width(20).height + 10
    text_h = max(text_h, 80)
    frame_h = img_h + text_h
    text_frame = BuildImage.new("RGBA", (500, frame_h), "white")
    text_frame.draw_text(
        (0, img_h, 280, frame_h), "要我一直", halign="right", max_fontsize=60
    ).draw_text((400, img_h, 500, frame_h), "吗", halign="left", max_fontsize=60)

    frame_num = 20
    coeff = 5 ** (1 / frame_num)

    def maker(i: int) -> Maker:
        def make(img: BuildImage) -> BuildImage:
            img = img.convert("RGBA").resize_width(500)
            base_frame = text_frame.copy().paste(img, alpha=True)
            frame = BuildImage.new("RGBA", base_frame.size, "white")
            r = coeff**i
            for _ in range(4):
                x = round(358 * (1 - r))
                y = round(frame_h * (1 - r))
                w = round(500 * r)
                h = round(frame_h * r)
                frame.paste(base_frame.resize((w, h)), (x, y))
                r /= 5
            return frame

        return make

    if not loop:
        return make_jpg_or_gif(img, maker(0))

    return make_gif_or_combined_gif(
        img, maker, frame_num, 0.1, FrameAlignPolicy.extend_loop
    )


def always(images: List[BuildImage], texts, args: Model):
    img = images[0]
    mode = args.mode

    if mode == "normal":
        return always_normal(img)
    elif mode == "circle":
        return always_always(img, loop=False)
    else:
        return always_always(img, loop=True)


add_meme(
    "always",
    always,
    min_images=1,
    max_images=1,
    args_type=MemeArgsType(
        parser, Model, [Model(mode="normal"), Model(mode="circle"), Model(mode="loop")]
    ),
    keywords=["一直"],
)