File size: 5,985 Bytes
5752a28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
"""Generate synthetic fintech UI screenshots containing dark-pattern copy.

The screenshots are plain rendered UI with real text so Tesseract can read
them and the classifier has something genuine to detect. Run once:

    python generate_samples.py

Outputs PNGs into ./samples/ (served by Flask at /api/samples/<name>).
"""
from PIL import Image, ImageDraw, ImageFont
import os

OUT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "samples")
os.makedirs(OUT_DIR, exist_ok=True)

W, H = 900, 640
BG = (248, 249, 252)
CARD = (255, 255, 255)
INK = (24, 28, 40)
MUTED = (110, 118, 135)
ACCENT = (79, 70, 229)
DANGER = (220, 53, 69)
WARN_BG = (255, 243, 205)
WARN_INK = (133, 100, 4)
GREEN = (25, 135, 84)


def font(size, bold=False):
    names = ["arialbd.ttf"] if bold else ["arial.ttf"]
    for name in names + ["DejaVuSans-Bold.ttf" if bold else "DejaVuSans.ttf"]:
        try:
            return ImageFont.truetype(name, size)
        except OSError:
            continue
    return ImageFont.load_default()


def card(d, x0, y0, x1, y1, fill=CARD, outline=(225, 228, 235)):
    d.rounded_rectangle([x0, y0, x1, y1], radius=12, fill=fill, outline=outline, width=1)


def button(d, x0, y0, x1, y1, label, fill=ACCENT, ink=(255, 255, 255), size=20, bold=True):
    d.rounded_rectangle([x0, y0, x1, y1], radius=8, fill=fill)
    f = font(size, bold)
    tw = d.textlength(label, font=f)
    d.text(((x0 + x1 - tw) / 2, (y0 + y1) / 2 - size / 2 - 2), label, font=f, fill=ink)


def make_checkout():
    img = Image.new("RGB", (W, H), BG)
    d = ImageDraw.Draw(img)
    d.rectangle([0, 0, W, 64], fill=(30, 34, 50))
    d.text((30, 20), "PayVault  |  Secure Checkout", font=font(22, True), fill=(255, 255, 255))

    card(d, 30, 90, 560, 600)
    d.text((55, 110), "Premium Trading Plan", font=font(26, True), fill=INK)
    d.text((55, 150), "$29.99 / month", font=font(22), fill=MUTED)

    d.rounded_rectangle([55, 195, 535, 245], radius=8, fill=WARN_BG)
    d.text((70, 207), "Hurry! Offer expires in 04:59 minutes", font=font(20, True), fill=WARN_INK)

    d.rounded_rectangle([55, 260, 535, 310], radius=8, fill=(253, 232, 232))
    d.text((70, 272), "Only 2 spots left at this price!", font=font(20, True), fill=DANGER)

    d.text((55, 335), "17 people are viewing this offer right now", font=font(18), fill=MUTED)
    d.text((55, 370), "1,358 traders upgraded this week", font=font(18), fill=MUTED)

    button(d, 55, 430, 535, 485, "CLAIM MY DISCOUNT NOW")
    d.text((150, 510), "No thanks, I prefer losing money", font=font(15), fill=(180, 184, 195))

    card(d, 590, 90, 870, 600)
    d.text((615, 110), "Order Summary", font=font(20, True), fill=INK)
    d.text((615, 155), "Plan", font=font(16), fill=MUTED)
    d.text((800, 155), "$29.99", font=font(16), fill=INK)
    d.text((615, 185), "Priority support", font=font(16), fill=MUTED)
    d.text((800, 185), "$4.99", font=font(16), fill=INK)
    d.line([615, 225, 845, 225], fill=(225, 228, 235), width=1)
    d.text((615, 240), "Total today", font=font(18, True), fill=INK)
    d.text((790, 240), "$34.98", font=font(18, True), fill=INK)
    img.save(os.path.join(OUT_DIR, "checkout_urgency.png"))


def make_cancellation():
    img = Image.new("RGB", (W, H), BG)
    d = ImageDraw.Draw(img)
    d.rectangle([0, 0, W, 64], fill=(30, 34, 50))
    d.text((30, 20), "CoinNest  |  Account Settings", font=font(22, True), fill=(255, 255, 255))

    card(d, 150, 110, 750, 560)
    d.text((185, 140), "Wait! Before you go...", font=font(28, True), fill=INK)
    d.text((185, 195), "Are you sure you want to cancel? You will lose all", font=font(19), fill=INK)
    d.text((185, 225), "your rewards and your exclusive member benefits", font=font(19), fill=INK)
    d.text((185, 255), "will be gone forever.", font=font(19), fill=INK)

    d.text((185, 305), "93% of members regret cancelling within a month", font=font(17), fill=MUTED)

    button(d, 185, 360, 715, 415, "KEEP MY BENEFITS", fill=GREEN)
    button(d, 185, 430, 715, 480, "Remind me later", fill=(235, 237, 242), ink=MUTED, bold=False)
    d.text((340, 505), "continue to cancellation step 1 of 6", font=font(13), fill=(195, 198, 207))
    img.save(os.path.join(OUT_DIR, "cancel_confirmshaming.png"))


def make_signup():
    img = Image.new("RGB", (W, H), BG)
    d = ImageDraw.Draw(img)
    d.rectangle([0, 0, W, 64], fill=(30, 34, 50))
    d.text((30, 20), "LoanLeap  |  Create Account", font=font(22, True), fill=(255, 255, 255))

    card(d, 120, 100, 780, 580)
    d.text((155, 125), "You're almost done!", font=font(26, True), fill=INK)

    def checkbox(y, label, sub, checked=True):
        d.rounded_rectangle([155, y, 179, y + 24], radius=5,
                            fill=ACCENT if checked else CARD,
                            outline=(200, 203, 212), width=1)
        if checked:
            d.line([160, y + 12, 166, y + 18], fill=(255, 255, 255), width=3)
            d.line([166, y + 18, 175, y + 6], fill=(255, 255, 255), width=3)
        d.text((195, y), label, font=font(18, True), fill=INK)
        d.text((195, y + 28), sub, font=font(15), fill=MUTED)

    checkbox(180, "Add Payment Protection Plus  (+$9.99/mo)",
             "Automatically added to protect your transactions")
    checkbox(255, "Enroll in Premium Credit Monitoring  (+$14.99/mo)",
             "Free trial converts to paid plan after 7 days")
    checkbox(330, "Share my data with trusted marketing partners",
             "By continuing you agree to receive personalised offers")

    d.text((155, 410), "By clicking Continue you accept the Terms, the Fee Schedule,", font=font(14), fill=MUTED)
    d.text((155, 432), "and authorise recurring charges to your saved card.", font=font(14), fill=MUTED)

    button(d, 155, 475, 745, 530, "CONTINUE")
    img.save(os.path.join(OUT_DIR, "signup_sneaking.png"))


if __name__ == "__main__":
    make_checkout()
    make_cancellation()
    make_signup()
    print(f"Saved 3 sample screenshots to {OUT_DIR}")