Add Python script to batch process Schnappix photos with enhanced saturation and contrast

This commit is contained in:
Jannik committed 2026-09-21 22:09:30 +02:00
1 parent bede07e949
commit eb7fbf20c0
4 files changed
+154

No files matched your search

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

+53
View File
@@ -0,0 +1,53 @@
import os
from PIL import Image, ImageEnhance
# Pfade
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
INPUT_DIR = os.path.join(BASE_DIR, 'media', 'Schnappix')
OUTPUT_DIR = os.path.join(BASE_DIR, 'media', 'Schnappix_Bearbeitet')
# Einstellungen zur Bildverbesserung
# 1.0 ist das Originalbild. 1.3 bedeutet 30% mehr Sättigung.
SATURATION_FACTOR = 1.4
CONTRAST_FACTOR = 1.15 # Etwas mehr Kontrast hilft oft bei "blassen" Bildern
def process_images():
if not os.path.exists(OUTPUT_DIR):
os.makedirs(OUTPUT_DIR)
print(f"Ordner erstellt: {OUTPUT_DIR}")
processed_count = 0
# Alle Dateien im Eingangsordner durchlaufen
for filename in os.listdir(INPUT_DIR):
if filename.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif')):
input_path = os.path.join(INPUT_DIR, filename)
output_path = os.path.join(OUTPUT_DIR, filename)
# Überspringen, falls das Bild schon im Zielordner existiert
if os.path.exists(output_path):
continue
try:
with Image.open(input_path) as img:
# 1. Sättigung anpassen
enhancer_color = ImageEnhance.Color(img)
img_enhanced = enhancer_color.enhance(SATURATION_FACTOR)
# 2. Kontrast anpassen
enhancer_contrast = ImageEnhance.Contrast(img_enhanced)
img_final = enhancer_contrast.enhance(CONTRAST_FACTOR)
# Speichern (mit hoher Qualität)
img_final.save(output_path, quality=95)
print(f"Bearbeitet: {filename}")
processed_count += 1
except Exception as e:
print(f"Fehler bei {filename}: {e}")
print(f"\nFertig! {processed_count} neue Bilder wurden bearbeitet.")
print(f"Du findest sie hier: {OUTPUT_DIR}")
if __name__ == '__main__':
print("Starte Bildbearbeitung...")
process_images()
Binary file not shown.

After

Width:  |  Height:  |  Size: 731 KiB

+101
View File
@@ -0,0 +1,101 @@
const fs = require('fs');
// 1. Update globals.css
let css = fs.readFileSync('src/app/globals.css', 'utf8');
// Replace media-wall and queries
const oldCssMatch = css.match(/\.media-wall\s*\{[^}]+\}(?:\s*@media[^}]+\{\s*\.media-wall\s*\{[^}]+\}\s*\}){4}/s);
if (oldCssMatch) {
const newCss = `.media-wall {
column-count: 2;
column-gap: 10px;
padding: 80px 10px 20px;
max-width: 1920px;
margin: 0 auto;
}
@media (min-width: 480px) {
.media-wall {
column-count: 3;
}
}
@media (min-width: 768px) {
.media-wall {
column-count: 4;
column-gap: 15px;
padding: 80px 15px 20px;
}
}
@media (min-width: 1024px) {
.media-wall {
column-count: 5;
column-gap: 20px;
padding: 90px 20px 30px;
}
}
@media (min-width: 1440px) {
.media-wall {
column-count: 6;
}
}`;
css = css.replace(oldCssMatch[0], newCss);
}
// Replace media-tile and images
const tileMatch = css.match(/\.media-tile\s*\{[^}]+\}\s*\.media-tile:hover\s*\{[^}]+\}\s*\.media-tile img,\s*\.media-tile video\s*\{[^}]+\}/s);
if (tileMatch) {
const newTile = `.media-tile {
break-inside: avoid;
margin-bottom: 10px;
position: relative;
overflow: hidden;
border-radius: var(--radius);
background: var(--color-border);
cursor: pointer;
transition: transform var(--transition), box-shadow var(--transition);
}
@media (min-width: 768px) {
.media-tile { margin-bottom: 15px; }
}
@media (min-width: 1024px) {
.media-tile { margin-bottom: 20px; }
}
.media-tile:hover {
transform: translateY(-2px);
box-shadow: var(--shadow);
z-index: 1;
}
.media-tile img,
.media-tile video {
display: block;
width: 100%;
height: 100%; /* Filled by parent aspect-ratio */
object-fit: cover;
}`;
css = css.replace(tileMatch[0], newTile);
}
fs.writeFileSync('src/app/globals.css', css, 'utf8');
// 2. Update MediaTile.tsx
let tile = fs.readFileSync('src/components/MediaTile.tsx', 'utf8');
tile = tile.replace(
` const style: React.CSSProperties = {
gridColumn: \`span \${item.gridWidth || 1}\`,
gridRow: \`span \${item.gridHeight || 1}\`,
aspectRatio,
};`,
` const style: React.CSSProperties = {
aspectRatio,
};`
);
// Make sure featured items span all columns if needed (optional)
// Actually we'll just let them be normal items in the masonry flow
fs.writeFileSync('src/components/MediaTile.tsx', tile, 'utf8');