← back to Resize It
server.py
298 lines
#!/usr/bin/env python3
"""
Simple Flask server for Spoonflower image resizer web interface
"""
from flask import Flask, request, jsonify, send_file, send_from_directory
from werkzeug.utils import secure_filename
import os
import subprocess
import json
from PIL import Image
import tempfile
from pathlib import Path
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024 # 100MB max file size
PROJECT_ROOT = Path(__file__).resolve().parent
UPLOAD_FOLDER = '/tmp/resize-uploads'
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
# Spoonflower credentials
SPOONFLOWER_EMAIL = os.getenv('SPOONFLOWER_EMAIL')
SPOONFLOWER_PASSWORD = os.getenv('SPOONFLOWER_PASSWORD')
def missing_spoonflower_env():
return [
name for name, value in {
'SPOONFLOWER_EMAIL': SPOONFLOWER_EMAIL,
'SPOONFLOWER_PASSWORD': SPOONFLOWER_PASSWORD,
}.items()
if not value
]
@app.route('/')
def index():
"""Serve the web interface"""
return send_from_directory('.', 'web-interface.html')
@app.route('/api/resize', methods=['POST'])
def resize_image():
"""Handle local file upload and resize"""
try:
if 'file' not in request.files:
return jsonify({'error': 'No file provided'}), 400
file = request.files['file']
if file.filename == '':
return jsonify({'error': 'No file selected'}), 400
# Save uploaded file
filename = secure_filename(file.filename)
input_path = os.path.join(UPLOAD_FOLDER, filename)
file.save(input_path)
# Get original image info
with Image.open(input_path) as img:
original_width, original_height = img.size
# Resize using the script
result = subprocess.run(
['python3', 'scripts/resize_image.py', input_path],
capture_output=True,
text=True,
cwd=PROJECT_ROOT
)
if result.returncode != 0:
return jsonify({'error': f'Resize failed: {result.stderr}'}), 500
# Find the output file
output_filename = filename.rsplit('.', 1)[0] + '_24x*_150dpi.*'
import glob
output_files = glob.glob(os.path.join(UPLOAD_FOLDER, output_filename))
if not output_files:
return jsonify({'error': 'Could not find resized image'}), 500
output_path = output_files[0]
# Get resized image info
with Image.open(output_path) as img:
resized_width, resized_height = img.size
# Calculate stats
scale_factor = resized_width / original_width
height_inches = resized_height / 150
warning = None
if scale_factor > 1.2:
warning = "Image upscaled significantly - may have quality loss"
elif scale_factor < 0.5:
warning = "Image downscaled significantly - some detail will be lost"
return jsonify({
'success': True,
'original': {
'width': original_width,
'height': original_height
},
'resized': {
'width': resized_width,
'height': resized_height,
'heightInches': round(height_inches, 2)
},
'scaleFactor': round(scale_factor, 2),
'warning': warning,
'downloadUrl': f'/api/download/{os.path.basename(output_path)}'
})
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/api/upload-to-spoonflower', methods=['POST'])
def upload_to_spoonflower():
"""Upload resized image back to Spoonflower"""
try:
data = request.get_json(silent=True)
if data is None:
return jsonify({'error': 'Invalid or missing JSON body'}), 400
missing_env = missing_spoonflower_env()
if missing_env:
return jsonify({'error': f"Missing required environment variables: {', '.join(missing_env)}"}), 500
design_url = data.get('designUrl')
resized_image_path = data.get('resizedImagePath')
if not design_url or not resized_image_path:
return jsonify({'error': 'Missing designUrl or resizedImagePath'}), 400
# Extract filename from download URL
filename = os.path.basename(resized_image_path.replace('/api/download/', ''))
# Find actual file path
actual_path = None
for directory in ['/tmp', UPLOAD_FOLDER]:
filepath = os.path.join(directory, filename)
if os.path.exists(filepath):
actual_path = filepath
break
if not actual_path:
return jsonify({'error': 'Resized file not found'}), 404
# Run the upload workflow
result = subprocess.run(
[
'python3', 'scripts/spoonflower_full_workflow.py',
design_url,
SPOONFLOWER_EMAIL,
SPOONFLOWER_PASSWORD,
actual_path
],
capture_output=True,
text=True,
cwd=PROJECT_ROOT
)
if result.returncode != 0:
error_msg = result.stderr or result.stdout
return jsonify({'error': f'Upload failed: {error_msg}'}), 500
return jsonify({
'success': True,
'message': 'Image uploaded successfully to Spoonflower',
'designUrl': design_url
})
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/api/spoonflower', methods=['POST'])
def process_spoonflower():
"""Handle Spoonflower URL download and resize"""
try:
data = request.get_json(silent=True)
if data is None:
return jsonify({'error': 'Invalid or missing JSON body'}), 400
missing_env = missing_spoonflower_env()
if missing_env:
return jsonify({'error': f"Missing required environment variables: {', '.join(missing_env)}"}), 500
url = data.get('url')
if not url:
return jsonify({'error': 'No URL provided'}), 400
# Validate URL format
if 'spoonflower.com' not in url:
return jsonify({'error': 'Invalid Spoonflower URL'}), 400
# Download from Spoonflower
result = subprocess.run(
[
'python3', 'scripts/download_spoonflower.py',
url,
SPOONFLOWER_EMAIL,
SPOONFLOWER_PASSWORD
],
capture_output=True,
text=True,
cwd=PROJECT_ROOT
)
if result.returncode != 0:
error_msg = result.stderr or result.stdout
if '404' in error_msg or 'wrong turn' in error_msg.lower():
return jsonify({
'error': 'Design not found. Please verify the URL and that you own this design.'
}), 404
return jsonify({'error': f'Download failed: {error_msg}'}), 500
# Find downloaded file in /tmp/
import glob
downloaded_files = glob.glob('/tmp/*.png') + glob.glob('/tmp/*.jpg') + glob.glob('/tmp/*.jpeg')
if not downloaded_files:
return jsonify({'error': 'No file was downloaded'}), 500
# Get the most recent file
downloaded_file = max(downloaded_files, key=os.path.getctime)
# Get original image info
with Image.open(downloaded_file) as img:
original_width, original_height = img.size
# Resize
result = subprocess.run(
['python3', 'scripts/resize_image.py', downloaded_file],
capture_output=True,
text=True,
cwd=PROJECT_ROOT
)
if result.returncode != 0:
return jsonify({'error': f'Resize failed: {result.stderr}'}), 500
# Find resized file
base_name = os.path.basename(downloaded_file).rsplit('.', 1)[0]
output_pattern = f'/tmp/{base_name}_24x*_150dpi.*'
output_files = glob.glob(output_pattern)
if not output_files:
return jsonify({'error': 'Could not find resized image'}), 500
output_path = output_files[0]
# Get resized image info
with Image.open(output_path) as img:
resized_width, resized_height = img.size
# Calculate stats
scale_factor = resized_width / original_width
height_inches = resized_height / 150
warning = None
if scale_factor > 1.2:
warning = "Image upscaled significantly - may have quality loss"
elif scale_factor < 0.5:
warning = "Image downscaled significantly - some detail will be lost"
return jsonify({
'success': True,
'original': {
'width': original_width,
'height': original_height
},
'resized': {
'width': resized_width,
'height': resized_height,
'heightInches': round(height_inches, 2)
},
'scaleFactor': round(scale_factor, 2),
'warning': warning,
'downloadUrl': f'/api/download/{os.path.basename(output_path)}',
'spoonflowerUrl': url,
'resizedFilePath': output_path
})
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/api/download/<filename>')
def download_file(filename):
"""Serve the resized file for download"""
# Check both /tmp and upload folder
for directory in ['/tmp', UPLOAD_FOLDER]:
filepath = os.path.join(directory, filename)
if os.path.exists(filepath):
return send_file(filepath, as_attachment=True)
return jsonify({'error': 'File not found'}), 404
if __name__ == '__main__':
PORT = 9876
print('Starting Spoonflower Image Resizer server...')
print(f'Access the web interface at: http://127.0.0.1:{PORT}')
app.run(host='127.0.0.1', port=PORT, debug=False)