File size: 6,036 Bytes
8b1c497
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import os
import zipfile
import io
from flask import Flask, render_template, request, send_file, after_this_request
from PIL import Image, ImageDraw, ImageFont, ImageOps
import tempfile
import shutil
import time

app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 50 * 1024 * 1024  # 50MB limit

def process_image(img, options):
    # 1. Strip EXIF (by creating a new image)
    if options.get('strip_exif'):
        data = list(img.getdata())
        image_without_exif = Image.new(img.mode, img.size)
        image_without_exif.putdata(data)
        img = image_without_exif

    # 2. Resize
    resize_mode = options.get('resize_mode')
    if resize_mode == 'percentage':
        scale = int(options.get('resize_value', 100)) / 100.0
        if scale != 1.0:
            new_size = (int(img.width * scale), int(img.height * scale))
            img = img.resize(new_size, Image.Resampling.LANCZOS)
    elif resize_mode == 'width':
        target_width = int(options.get('resize_value', img.width))
        if target_width != img.width:
            ratio = target_width / img.width
            new_size = (target_width, int(img.height * ratio))
            img = img.resize(new_size, Image.Resampling.LANCZOS)

    # 3. Watermark
    watermark_text = options.get('watermark_text')
    if watermark_text:
        # Create a transparent layer
        txt_layer = Image.new('RGBA', img.size, (255, 255, 255, 0))
        draw = ImageDraw.Draw(txt_layer)
        
        # Calculate font size (relative to image width)
        fontsize = int(img.width / 20)
        if fontsize < 10: fontsize = 10
        
        try:
            # Try to load a default font, otherwise load default
            # On Linux/Docker, paths might differ. 
            # We'll use default bitmap font if TTF not found or just try-except
            font = ImageFont.truetype("DejaVuSans.ttf", fontsize)
        except IOError:
            font = ImageFont.load_default()
            
        # Position: Bottom Right with padding
        # Get text size
        bbox = draw.textbbox((0, 0), watermark_text, font=font)
        textwidth = bbox[2] - bbox[0]
        textheight = bbox[3] - bbox[1]
        
        padding = 10
        x = img.width - textwidth - padding
        y = img.height - textheight - padding
        
        # Draw semi-transparent text
        draw.text((x, y), watermark_text, font=font, fill=(255, 255, 255, 128))
        
        if img.mode != 'RGBA':
            img = img.convert('RGBA')
            
        img = Image.alpha_composite(img, txt_layer)

    # 4. Format Conversion handled during save
    return img

@app.route('/', methods=['GET'])
def index():
    return render_template('index.html')

@app.route('/process', methods=['POST'])
def process():
    if 'files' not in request.files:
        return "No files uploaded", 400
    
    files = request.files.getlist('files')
    if not files or files[0].filename == '':
        return "No files selected", 400

    # Get options
    target_format = request.form.get('target_format', 'original')
    resize_mode = request.form.get('resize_mode', 'none') # none, percentage, width
    resize_value = request.form.get('resize_value', 0)
    watermark_text = request.form.get('watermark_text', '').strip()
    strip_exif = 'strip_exif' in request.form
    
    options = {
        'resize_mode': resize_mode,
        'resize_value': resize_value,
        'watermark_text': watermark_text,
        'strip_exif': strip_exif
    }

    # Create a temporary directory for processing
    temp_dir = tempfile.mkdtemp()
    
    try:
        zip_buffer = io.BytesIO()
        with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
            for file in files:
                if not file.filename:
                    continue
                
                try:
                    img = Image.open(file.stream)
                    
                    # Process
                    img = process_image(img, options)
                    
                    # Determine output filename and format
                    original_name = os.path.splitext(file.filename)[0]
                    ext = os.path.splitext(file.filename)[1].lower()
                    
                    if target_format != 'original':
                        ext = '.' + target_format.lower()
                        if target_format.lower() == 'jpeg':
                            img = img.convert('RGB')
                        elif target_format.lower() == 'png':
                            # Keep RGBA if possible, or convert if needed
                            pass
                    
                    # Save to temp buffer
                    img_byte_arr = io.BytesIO()
                    save_format = ext.strip('.').upper()
                    if save_format == 'JPG': save_format = 'JPEG'
                    
                    # Handle WEBP/JPEG quality if needed (using default for now)
                    img.save(img_byte_arr, format=save_format)
                    
                    # Add to ZIP
                    zip_file.writestr(f"processed/{original_name}{ext}", img_byte_arr.getvalue())
                    
                except Exception as e:
                    print(f"Error processing {file.filename}: {e}")
                    # Optionally add an error log to the zip
                    zip_file.writestr(f"processed/errors/{file.filename}.txt", str(e))

        zip_buffer.seek(0)
        
        # Cleanup temp dir (we didn't actually write files to disk, just memory, 
        # but if we did, we'd clean here. The `img_byte_arr` approach avoids disk IO)
        
        return send_file(
            zip_buffer,
            mimetype='application/zip',
            as_attachment=True,
            download_name=f'processed_images_{int(time.time())}.zip'
        )

    finally:
        shutil.rmtree(temp_dir)

if __name__ == '__main__':
    port = int(os.environ.get('PORT', 7860))
    app.run(host='0.0.0.0', port=port)