File size: 3,587 Bytes
6dfbcaa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ae1988a
6dfbcaa
 
 
 
 
 
 
 
 
 
 
 
 
ae1988a
6dfbcaa
 
ae1988a
6dfbcaa
 
ae1988a
6dfbcaa
ae1988a
6dfbcaa
 
 
ae1988a
6dfbcaa
 
ae1988a
6dfbcaa
 
ae1988a
6dfbcaa
ae1988a
6dfbcaa
 
 
ae1988a
6dfbcaa
 
 
ae1988a
 
 
 
 
 
 
6dfbcaa
 
 
ae1988a
6dfbcaa
 
 
 
 
 
ae1988a
6dfbcaa
ae1988a
 
6dfbcaa
 
 
 
 
 
ae1988a
 
6dfbcaa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import io
import datetime

import gradio as gr
from PIL import Image, ImageFilter, ImageDraw, ImageFont
import numpy as np


def modern_to_nokia_pil(
    img,
    jpeg_quality=15,
    noise_std=12,
    color_levels=32,
    blur_radius=0.6,
    gamma=1.3,
    add_date_stamp=True,
):
    img = img.convert("RGB")

    # --- Crop to 4:3 ---
    w, h = img.size
    target_ratio = 4 / 3
    current_ratio = w / h

    if current_ratio > target_ratio:
        new_w = int(h * target_ratio)
        left = (w - new_w) // 2
        img = img.crop((left, 0, left + new_w, h))
    else:
        new_h = int(w / target_ratio)
        top = (h - new_h) // 2
        img = img.crop((0, top, w, top + new_h))

    # --- Resize to 640×480 ---
    img = img.resize((640, 480), resample=Image.BILINEAR)

    # --- Blur ---
    img = img.filter(ImageFilter.GaussianBlur(radius=blur_radius))

    # --- Posterize (reduce color depth) ---
    arr = np.array(img, dtype=np.uint8)
    step = max(1, 256 // int(color_levels))
    arr = (arr // step) * step
    img = Image.fromarray(arr, mode="RGB")

    # --- Noise ---
    arr = np.array(img, dtype=np.int16)
    noise = np.random.normal(0, noise_std, arr.shape)
    arr = np.clip(arr + noise, 0, 255).astype(np.uint8)
    img = Image.fromarray(arr, mode="RGB")

    # --- Gamma curve ---
    arr = np.array(img, dtype=np.float32) / 255.0
    arr = np.power(arr, gamma)
    arr = np.clip(arr * 255, 0, 255).astype(np.uint8)
    img = Image.fromarray(arr, mode="RGB")

    # --- Date stamp (fixed for Pillow >= 10) ---
    if add_date_stamp:
        draw = ImageDraw.Draw(img)
        font = ImageFont.load_default()
        text = datetime.datetime.now().strftime("%d-%m-%y %H:%M")

        # NEW SAFE SIZE METHOD
        bbox = draw.textbbox((0, 0), text, font=font)
        text_w = bbox[2] - bbox[0]
        text_h = bbox[3] - bbox[1]

        margin = 4
        x = img.width - text_w - margin
        y = img.height - text_h - margin

        draw.rectangle(
            [x - 2, y - 2, x + text_w + 2, y + text_h + 2],
            fill=(0, 0, 0),
        )
        draw.text((x, y), text, font=font, fill=(255, 255, 0))

    # --- JPEG compression ---
    buffer = io.BytesIO()
    img.save(buffer, format="JPEG", quality=int(jpeg_quality),
             optimize=False, progressive=False)
    buffer.seek(0)
    img = Image.open(buffer)

    return img


def convert_fn(image, jpeg_quality, noise_std, color_levels,
               blur_radius, gamma, add_date_stamp):
    if image is None:
        return None
    return modern_to_nokia_pil(
        image,
        jpeg_quality=jpeg_quality,
        noise_std=noise_std,
        color_levels=color_levels,
        blur_radius=blur_radius,
        gamma=gamma,
        add_date_stamp=add_date_stamp,
    )


demo = gr.Interface(
    fn=convert_fn,
    inputs=[
        gr.Image(type="pil", label="Input image"),
        gr.Slider(5, 40, value=15, step=1, label="JPEG quality (lower = more Nokia)"),
        gr.Slider(0, 40, value=12, step=1, label="Noise amount"),
        gr.Slider(2, 64, value=32, step=2, label="Color levels per channel"),
        gr.Slider(0.0, 3.0, value=0.6, step=0.1, label="Blur radius"),
        gr.Slider(0.5, 2.5, value=1.3, step=0.1, label="Gamma (contrast curve)"),
        gr.Checkbox(True, label="Add date stamp"),
    ],
    outputs=gr.Image(type="pil", label="Nokia-style image"),
    title="0.3 MP Nokia Camera Filter",
    description="Upload a modern photo and turn it into an old-school 0.3 MP Nokia-style photo.",
)

if __name__ == "__main__":
    demo.launch()