spectra/main.py
2024-11-05 13:55:44 -05:00

146 lines
4.9 KiB
Python

from flask import Flask, jsonify, request, send_from_directory, render_template
import os
from PIL import Image, ExifTags
from apscheduler.schedulers.background import BackgroundScheduler
from datetime import datetime, timedelta
import piexif
import io
import random
from colorthief import ColorThief
import colorsys
app = Flask(__name__)
IMAGE_FOLDER = '/home/dubey/projects/photoportfolio/pythonserver/images/'
THUMBS_FOLDER = '/home/dubey/projects/photoportfolio/pythonserver/thumbs/'
IMAGES_PER_PAGE = 5
THUMBNAIL_SIZES = [256, 512, 768, 1024, 1536, 2048]
scheduler = BackgroundScheduler()
scheduler.start()
def generate_thumbnails():
for filename in os.listdir(IMAGE_FOLDER):
if filename.lower().endswith(('.png', '.jpg', '.jpeg', '.gif')):
original_path = os.path.join(IMAGE_FOLDER, filename)
for size in THUMBNAIL_SIZES:
thumb_path = os.path.join(THUMBS_FOLDER, f"{size}_{filename}")
if not os.path.exists(thumb_path):
with Image.open(original_path) as img:
# Extract EXIF data
exif_data = None
if "exif" in img.info:
exif_data = img.info["exif"]
# Resize image
img.thumbnail((size, size), Image.LANCZOS)
# Save image with EXIF data
if exif_data:
img.save(thumb_path, exif=exif_data, optimize=True, quality=85)
else:
img.save(thumb_path, optimize=True, quality=85)
scheduler.add_job(generate_thumbnails, 'interval', minutes=5)
scheduler.add_job(generate_thumbnails, 'date', run_date=datetime.now() + timedelta(seconds=1)) # Run once at startup
def get_highlight_color(image_path):
color_thief = ColorThief(image_path)
palette = color_thief.get_palette(color_count=6, quality=1)
# Convert RGB to HSV and find the color with the highest saturation
highlight_color = max(palette, key=lambda rgb: colorsys.rgb_to_hsv(*rgb)[1])
return '#{:02x}{:02x}{:02x}'.format(*highlight_color)
def get_image_info(filename):
path = os.path.join(IMAGE_FOLDER, filename)
thumb_path = os.path.join(THUMBS_FOLDER, f"256_{filename}")
exif = None
with Image.open(path) as img:
width, height = img.size
exif = {
ExifTags.TAGS[k]: v
for k, v in img._getexif().items()
if k in ExifTags.TAGS
}
if str(exif['Orientation']) == "6" or str(exif['Orientation']) == "8":
width, height = height, width
exposure_time = exif['ExposureTime']
if isinstance(exposure_time, tuple):
exposure_fraction = f"{exposure_time[0]}/{exposure_time[1]}"
else:
exposure_fraction = f"1/{int(1/float(exposure_time))}"
date_obj = datetime.strptime(exif['DateTime'], '%Y:%m:%d %H:%M:%S')
date = date_obj.strftime('%y %m %d') # Format: YY MM DD
technical_info = f"{exif['FocalLengthIn35mmFilm']}MM | F/{exif['FNumber']} | {exposure_fraction} | ISO{exif['ISOSpeedRatings']}"
factor = random.randint(2, 3)
if height < 4000 or width < 4000:
factor = 1
highlight_color = get_highlight_color(thumb_path)
return {
'imgSrc': f'/thumbs/1536_{filename}',
'fullSizeImgSrc': f'/images/{filename}',
'date': date,
'technicalInfo': technical_info,
'width': width/factor,
'height': height/factor,
'highlightColor': highlight_color
}
def get_image_taken_date(filename):
path = os.path.join(IMAGE_FOLDER, filename)
with Image.open(path) as img:
exif = {
ExifTags.TAGS[k]: v
for k, v in img._getexif().items()
if k in ExifTags.TAGS
}
date_str = exif.get('DateTime', exif.get('DateTimeOriginal', ''))
if date_str:
return datetime.strptime(date_str, '%Y:%m:%d %H:%M:%S')
return datetime.fromtimestamp(os.path.getmtime(path)) # Fallback to file modification time
@app.route('/api/images')
def get_images():
page = int(request.args.get('page', 1))
all_images = sorted(
[f for f in os.listdir(IMAGE_FOLDER) if f.lower().endswith(('.png', '.jpg', '.jpeg', '.gif'))],
key=get_image_taken_date,
reverse=True
)
start = (page - 1) * IMAGES_PER_PAGE
end = start + IMAGES_PER_PAGE
page_images = all_images[start:end]
return jsonify({
'images': [get_image_info(img) for img in page_images],
'hasMore': end < len(all_images)
})
@app.route('/images/<path:filename>')
def serve_image(filename):
return send_from_directory(IMAGE_FOLDER, filename)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/thumbs/<path:filename>')
def serve_thumbnail(filename):
return send_from_directory(THUMBS_FOLDER, filename)
if __name__ == '__main__':
app.run(debug=True, port=5001, host='0.0.0.0')