Add Python script to batch process Schnappix photos with enhanced saturation and contrast
This commit is contained in:
1 parent
bede07e949
commit
eb7fbf20c0
4 files changed
+154
No files matched your search
@@ -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 |
@@ -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');
|
||||
Reference in new issue
Block a user