diff --git a/optimize_all.py b/optimize_all.py new file mode 100644 index 0000000..ca249ab --- /dev/null +++ b/optimize_all.py @@ -0,0 +1,97 @@ +import os +from PIL import Image +from pathlib import Path + +BASE_DIR = Path("/home/andre/coden/Orchestrator/privat/CV/andreknie.de") +DIRS_TO_PROCESS = [ + BASE_DIR / "public/images", + BASE_DIR / "public/logos" +] + +def optimize_images(): + for img_dir in DIRS_TO_PROCESS: + if not img_dir.exists(): + continue + + # Process files directly in this directory (not recursive to avoid processing kniepunkt again) + for img_path in img_dir.iterdir(): + if img_path.is_file() and img_path.suffix.lower() in [".png", ".jpg", ".jpeg"]: + if img_path.name == "favicon.png": + continue + + try: + with Image.open(img_path) as img: + # Convert to RGB if necessary + if img.mode in ("RGBA", "P"): + img = img.convert("RGBA") + elif img.mode != "RGB": + img = img.convert("RGB") + + # Resize if overly large + if img.width > 2000: + ratio = 2000 / img.width + new_size = (2000, int(img.height * ratio)) + img = img.resize(new_size, Image.Resampling.LANCZOS) + + webp_path = img_path.with_suffix(".webp") + img.save(webp_path, "WEBP", quality=80) + + img_path.unlink() + print(f"Optimized: {img_path.name} -> {webp_path.name}") + except Exception as e: + print(f"Error processing {img_path}: {e}") + +def update_references(): + import glob + + # Search all jsx, css, yaml, md files + extensions = ["jsx", "css", "yaml", "yml", "md"] + + search_dirs = [ + BASE_DIR / "src", + BASE_DIR / "content" + ] + + # Also update index.html if needed (though favicon.png is excluded from conversion) + + for d in search_dirs: + for root, _, files in os.walk(d): + for file in files: + ext = file.split('.')[-1].lower() + if ext in extensions: + filepath = Path(root) / file + try: + content = filepath.read_text(encoding="utf-8") + + # Replace .png, .jpg, .jpeg with .webp + # But be careful not to replace favicon.png if it's there + if "favicon.png" not in content: + new_content = content.replace(".png", ".webp").replace(".jpg", ".webp").replace(".jpeg", ".webp") + if new_content != content: + filepath.write_text(new_content, encoding="utf-8") + print(f"Updated references in: {filepath.name}") + else: + # Do a safe replace (not touching favicon.png) + lines = content.split('\n') + new_lines = [] + changed = False + for line in lines: + if "favicon.png" not in line: + nl = line.replace(".png", ".webp").replace(".jpg", ".webp").replace(".jpeg", ".webp") + if nl != line: + changed = True + new_lines.append(nl) + else: + new_lines.append(line) + + if changed: + filepath.write_text('\n'.join(new_lines), encoding="utf-8") + print(f"Updated references in: {filepath.name} (safe mode)") + + except Exception as e: + pass + +if __name__ == "__main__": + optimize_images() + update_references() + print("Optimization complete!") diff --git a/privat/CV/andreknie.de/content/meta/logos.yaml b/privat/CV/andreknie.de/content/meta/logos.yaml index 6ee69cb..8decc75 100644 --- a/privat/CV/andreknie.de/content/meta/logos.yaml +++ b/privat/CV/andreknie.de/content/meta/logos.yaml @@ -6,13 +6,13 @@ light: - name: "Universität Kassel" src: "/logos/uni-kassel.svg" - name: "Universität zu Köln" - src: "/logos/uni-koeln.jpg" + src: "/logos/uni-koeln.webp" - name: "Hessian.AI" src: "/logos/hessian-ai.svg" - name: "Science Park Kassel" - src: "/logos/science-park-kassel.png" + src: "/logos/science-park-kassel.webp" - name: "Hübner Group" - src: "/logos/huebner-group.jpg" + src: "/logos/huebner-group.webp" - name: "Deutsche Bahn" src: "/logos/deutsche-bahn.svg" - name: "eoda" @@ -24,17 +24,17 @@ light: - name: "Hochschule Fresenius" src: "/logos/hochschule-fresenius.svg" - name: "Studierendenwerk Kassel" - src: "/logos/studierendenwerk-kassel.png" + src: "/logos/studierendenwerk-kassel.webp" - name: "ÖkoVision" - src: "/logos/oekovision.jpg" + src: "/logos/oekovision.webp" - name: "Arvos" src: "/logos/arvos.svg" - name: "MTO" - src: "/logos/mto.png" + src: "/logos/mto.webp" dark: - name: "Auteba" - src: "/logos/auteba.png" + src: "/logos/auteba.webp" - name: "Esterer" src: "/logos/esterer.svg" - name: "VSB" @@ -42,12 +42,12 @@ dark: - name: "Schlachthof Kassel" src: "/logos/schlachthof-kassel.svg" - name: "Veli" - src: "/logos/veli.png" + src: "/logos/veli.webp" - name: "Hexagon Purus" src: "/logos/hexagon-purus.svg" - name: "Paul Beier" - src: "/logos/paul-beier.png" + src: "/logos/paul-beier.webp" - name: "Sika" - src: "/logos/sika.png" + src: "/logos/sika.webp" - name: "KI Bundesverband" - src: "/logos/ki-bundesverband.png" + src: "/logos/ki-bundesverband.webp" diff --git a/privat/CV/andreknie.de/content/meta/profile.yaml b/privat/CV/andreknie.de/content/meta/profile.yaml index 4b2b4a9..d61056a 100644 --- a/privat/CV/andreknie.de/content/meta/profile.yaml +++ b/privat/CV/andreknie.de/content/meta/profile.yaml @@ -6,7 +6,7 @@ roles: - "Content-Autor" - "Geschäftsführer, Data Hive Cassel" summary: "Technologie begeistert mich. Menschen noch mehr. Ich verbinde Welten, die selten zusammenkommen: Grundlagenforschung und Shopfloor. Konzernsteuerung und Startup-Garage. Algorithmen und Ängste." -photo: "/images/andre-knie.png" +photo: "/images/andre-knie.webp" positioning: sovereignty: "Unabhängig von US-Hyperscalern. KI-Lösungen aus und für Deutschland." data_sovereignty: "100% DSGVO- und AI-Act-konform, EU-Hosting." diff --git a/privat/CV/andreknie.de/content/meta/speaking.yaml b/privat/CV/andreknie.de/content/meta/speaking.yaml index 6b16312..1063edd 100644 --- a/privat/CV/andreknie.de/content/meta/speaking.yaml +++ b/privat/CV/andreknie.de/content/meta/speaking.yaml @@ -17,7 +17,7 @@ style: sections: - format: keynote heading: "Keynotes" - image: "/images/keynote-1.jpg" + image: "/images/keynote-1.webp" topics: - "KI im Mittelstand — Chancen ohne Hype" - "Digitale Souveränität: Pilot statt Passagier" @@ -26,7 +26,7 @@ sections: - format: workshop heading: "Workshops" - image: "/images/workshop-1.jpg" + image: "/images/workshop-1.webp" topics: - "KI-Rollout in Organisationen: vom Pilot zur Einführung" - "KI in HR und Verwaltung: Use Cases entwickeln" @@ -35,7 +35,7 @@ sections: - format: panel heading: "Panels & Diskussionen" - image: "/images/panel-1.jpg" + image: "/images/panel-1.webp" topics: - "KI-Regulierung und Datensouveränität" - "KI in Gesellschaft, Bildung und öffentlichem Sektor" diff --git a/privat/CV/andreknie.de/public/images/andre-knie.png b/privat/CV/andreknie.de/public/images/andre-knie.png deleted file mode 100644 index f97d15b..0000000 Binary files a/privat/CV/andreknie.de/public/images/andre-knie.png and /dev/null differ diff --git a/privat/CV/andreknie.de/public/images/andre-knie.webp b/privat/CV/andreknie.de/public/images/andre-knie.webp new file mode 100644 index 0000000..60217ff Binary files /dev/null and b/privat/CV/andreknie.de/public/images/andre-knie.webp differ diff --git a/privat/CV/andreknie.de/public/images/germany-outline.png b/privat/CV/andreknie.de/public/images/germany-outline.png deleted file mode 100644 index e345530..0000000 Binary files a/privat/CV/andreknie.de/public/images/germany-outline.png and /dev/null differ diff --git a/privat/CV/andreknie.de/public/images/germany-outline.webp b/privat/CV/andreknie.de/public/images/germany-outline.webp new file mode 100644 index 0000000..c35a601 Binary files /dev/null and b/privat/CV/andreknie.de/public/images/germany-outline.webp differ diff --git a/privat/CV/andreknie.de/public/images/keynote-1.jpg b/privat/CV/andreknie.de/public/images/keynote-1.jpg deleted file mode 100644 index 8aaa005..0000000 Binary files a/privat/CV/andreknie.de/public/images/keynote-1.jpg and /dev/null differ diff --git a/privat/CV/andreknie.de/public/images/keynote-1.webp b/privat/CV/andreknie.de/public/images/keynote-1.webp new file mode 100644 index 0000000..2a4db7a Binary files /dev/null and b/privat/CV/andreknie.de/public/images/keynote-1.webp differ diff --git a/privat/CV/andreknie.de/public/images/panel-1.jpg b/privat/CV/andreknie.de/public/images/panel-1.jpg deleted file mode 100644 index a628901..0000000 Binary files a/privat/CV/andreknie.de/public/images/panel-1.jpg and /dev/null differ diff --git a/privat/CV/andreknie.de/public/images/panel-1.webp b/privat/CV/andreknie.de/public/images/panel-1.webp new file mode 100644 index 0000000..4999b96 Binary files /dev/null and b/privat/CV/andreknie.de/public/images/panel-1.webp differ diff --git a/privat/CV/andreknie.de/public/images/shield-gear.png b/privat/CV/andreknie.de/public/images/shield-gear.png deleted file mode 100644 index 10f3275..0000000 Binary files a/privat/CV/andreknie.de/public/images/shield-gear.png and /dev/null differ diff --git a/privat/CV/andreknie.de/public/images/shield-gear.webp b/privat/CV/andreknie.de/public/images/shield-gear.webp new file mode 100644 index 0000000..e28a81c Binary files /dev/null and b/privat/CV/andreknie.de/public/images/shield-gear.webp differ diff --git a/privat/CV/andreknie.de/public/images/tools.jpg b/privat/CV/andreknie.de/public/images/tools.jpg deleted file mode 100644 index 74f8945..0000000 Binary files a/privat/CV/andreknie.de/public/images/tools.jpg and /dev/null differ diff --git a/privat/CV/andreknie.de/public/images/tools.webp b/privat/CV/andreknie.de/public/images/tools.webp new file mode 100644 index 0000000..c81f5ad Binary files /dev/null and b/privat/CV/andreknie.de/public/images/tools.webp differ diff --git a/privat/CV/andreknie.de/public/images/workshop-1.jpg b/privat/CV/andreknie.de/public/images/workshop-1.jpg deleted file mode 100644 index 24686c9..0000000 Binary files a/privat/CV/andreknie.de/public/images/workshop-1.jpg and /dev/null differ diff --git a/privat/CV/andreknie.de/public/images/workshop-1.webp b/privat/CV/andreknie.de/public/images/workshop-1.webp new file mode 100644 index 0000000..3049cf8 Binary files /dev/null and b/privat/CV/andreknie.de/public/images/workshop-1.webp differ diff --git a/privat/CV/andreknie.de/public/images/workshop-2.jpg b/privat/CV/andreknie.de/public/images/workshop-2.jpg deleted file mode 100644 index 90de2ab..0000000 Binary files a/privat/CV/andreknie.de/public/images/workshop-2.jpg and /dev/null differ diff --git a/privat/CV/andreknie.de/public/images/workshop-2.webp b/privat/CV/andreknie.de/public/images/workshop-2.webp new file mode 100644 index 0000000..0264783 Binary files /dev/null and b/privat/CV/andreknie.de/public/images/workshop-2.webp differ diff --git a/privat/CV/andreknie.de/public/images/workshop-3.jpg b/privat/CV/andreknie.de/public/images/workshop-3.jpg deleted file mode 100644 index d8be656..0000000 Binary files a/privat/CV/andreknie.de/public/images/workshop-3.jpg and /dev/null differ diff --git a/privat/CV/andreknie.de/public/images/workshop-3.webp b/privat/CV/andreknie.de/public/images/workshop-3.webp new file mode 100644 index 0000000..374ec2d Binary files /dev/null and b/privat/CV/andreknie.de/public/images/workshop-3.webp differ diff --git a/privat/CV/andreknie.de/public/logos/auteba.png b/privat/CV/andreknie.de/public/logos/auteba.png deleted file mode 100644 index dbfaf44..0000000 Binary files a/privat/CV/andreknie.de/public/logos/auteba.png and /dev/null differ diff --git a/privat/CV/andreknie.de/public/logos/auteba.webp b/privat/CV/andreknie.de/public/logos/auteba.webp new file mode 100644 index 0000000..9484f9a Binary files /dev/null and b/privat/CV/andreknie.de/public/logos/auteba.webp differ diff --git a/privat/CV/andreknie.de/public/logos/huebner-group.jpg b/privat/CV/andreknie.de/public/logos/huebner-group.jpg deleted file mode 100644 index 0a6cfa9..0000000 Binary files a/privat/CV/andreknie.de/public/logos/huebner-group.jpg and /dev/null differ diff --git a/privat/CV/andreknie.de/public/logos/huebner-group.webp b/privat/CV/andreknie.de/public/logos/huebner-group.webp new file mode 100644 index 0000000..ba60047 Binary files /dev/null and b/privat/CV/andreknie.de/public/logos/huebner-group.webp differ diff --git a/privat/CV/andreknie.de/public/logos/ki-bundesverband.png b/privat/CV/andreknie.de/public/logos/ki-bundesverband.png deleted file mode 100644 index 0414548..0000000 Binary files a/privat/CV/andreknie.de/public/logos/ki-bundesverband.png and /dev/null differ diff --git a/privat/CV/andreknie.de/public/logos/ki-bundesverband.webp b/privat/CV/andreknie.de/public/logos/ki-bundesverband.webp new file mode 100644 index 0000000..e360508 Binary files /dev/null and b/privat/CV/andreknie.de/public/logos/ki-bundesverband.webp differ diff --git a/privat/CV/andreknie.de/public/logos/mto.png b/privat/CV/andreknie.de/public/logos/mto.png deleted file mode 100644 index 4c51eec..0000000 Binary files a/privat/CV/andreknie.de/public/logos/mto.png and /dev/null differ diff --git a/privat/CV/andreknie.de/public/logos/mto.webp b/privat/CV/andreknie.de/public/logos/mto.webp new file mode 100644 index 0000000..e303e1a Binary files /dev/null and b/privat/CV/andreknie.de/public/logos/mto.webp differ diff --git a/privat/CV/andreknie.de/public/logos/oekovision.jpg b/privat/CV/andreknie.de/public/logos/oekovision.jpg deleted file mode 100644 index 16d434d..0000000 Binary files a/privat/CV/andreknie.de/public/logos/oekovision.jpg and /dev/null differ diff --git a/privat/CV/andreknie.de/public/logos/oekovision.webp b/privat/CV/andreknie.de/public/logos/oekovision.webp new file mode 100644 index 0000000..beca1f0 Binary files /dev/null and b/privat/CV/andreknie.de/public/logos/oekovision.webp differ diff --git a/privat/CV/andreknie.de/public/logos/paul-beier.png b/privat/CV/andreknie.de/public/logos/paul-beier.png deleted file mode 100644 index f12a754..0000000 Binary files a/privat/CV/andreknie.de/public/logos/paul-beier.png and /dev/null differ diff --git a/privat/CV/andreknie.de/public/logos/paul-beier.webp b/privat/CV/andreknie.de/public/logos/paul-beier.webp new file mode 100644 index 0000000..e599ba7 Binary files /dev/null and b/privat/CV/andreknie.de/public/logos/paul-beier.webp differ diff --git a/privat/CV/andreknie.de/public/logos/science-park-kassel.png b/privat/CV/andreknie.de/public/logos/science-park-kassel.png deleted file mode 100644 index a498da1..0000000 Binary files a/privat/CV/andreknie.de/public/logos/science-park-kassel.png and /dev/null differ diff --git a/privat/CV/andreknie.de/public/logos/science-park-kassel.webp b/privat/CV/andreknie.de/public/logos/science-park-kassel.webp new file mode 100644 index 0000000..c34eafb Binary files /dev/null and b/privat/CV/andreknie.de/public/logos/science-park-kassel.webp differ diff --git a/privat/CV/andreknie.de/public/logos/sika.png b/privat/CV/andreknie.de/public/logos/sika.png deleted file mode 100644 index b60a148..0000000 Binary files a/privat/CV/andreknie.de/public/logos/sika.png and /dev/null differ diff --git a/privat/CV/andreknie.de/public/logos/sika.webp b/privat/CV/andreknie.de/public/logos/sika.webp new file mode 100644 index 0000000..a6e8d98 Binary files /dev/null and b/privat/CV/andreknie.de/public/logos/sika.webp differ diff --git a/privat/CV/andreknie.de/public/logos/studierendenwerk-kassel.png b/privat/CV/andreknie.de/public/logos/studierendenwerk-kassel.png deleted file mode 100644 index 08780eb..0000000 Binary files a/privat/CV/andreknie.de/public/logos/studierendenwerk-kassel.png and /dev/null differ diff --git a/privat/CV/andreknie.de/public/logos/studierendenwerk-kassel.webp b/privat/CV/andreknie.de/public/logos/studierendenwerk-kassel.webp new file mode 100644 index 0000000..6e3e997 Binary files /dev/null and b/privat/CV/andreknie.de/public/logos/studierendenwerk-kassel.webp differ diff --git a/privat/CV/andreknie.de/public/logos/uni-koeln.jpg b/privat/CV/andreknie.de/public/logos/uni-koeln.jpg deleted file mode 100644 index 3b9cd18..0000000 Binary files a/privat/CV/andreknie.de/public/logos/uni-koeln.jpg and /dev/null differ diff --git a/privat/CV/andreknie.de/public/logos/uni-koeln.webp b/privat/CV/andreknie.de/public/logos/uni-koeln.webp new file mode 100644 index 0000000..e9a114e Binary files /dev/null and b/privat/CV/andreknie.de/public/logos/uni-koeln.webp differ diff --git a/privat/CV/andreknie.de/public/logos/veli.png b/privat/CV/andreknie.de/public/logos/veli.png deleted file mode 100644 index 1f5cdf8..0000000 Binary files a/privat/CV/andreknie.de/public/logos/veli.png and /dev/null differ diff --git a/privat/CV/andreknie.de/public/logos/veli.webp b/privat/CV/andreknie.de/public/logos/veli.webp new file mode 100644 index 0000000..af9199e Binary files /dev/null and b/privat/CV/andreknie.de/public/logos/veli.webp differ diff --git a/privat/CV/andreknie.de/src/components/DotCloudIcon.jsx b/privat/CV/andreknie.de/src/components/DotCloudIcon.jsx index 2ef19b6..bfec818 100644 --- a/privat/CV/andreknie.de/src/components/DotCloudIcon.jsx +++ b/privat/CV/andreknie.de/src/components/DotCloudIcon.jsx @@ -6,7 +6,7 @@ import React, { useRef, useEffect } from 'react' * - Samples dark pixels → places dots * - Dots are STATIC until mouse hovers, then they scatter and spring back * - * For germany: uses /images/germany-outline.png + * For germany: uses /images/germany-outline.webp * For shield/tools: draws shape on offscreen canvas then samples */ export default function DotCloudIcon({ shape = 'germany', size = 140 }) { @@ -181,7 +181,7 @@ function sampleGermany(size) { resolve(points) } img.onerror = () => { console.error('[DotCloudIcon] Failed to load germany image'); resolve([]) } - img.src = '/images/germany-outline.png' + img.src = '/images/germany-outline.webp' }) } @@ -320,6 +320,6 @@ function sampleToolsRightHalf(size) { resolve(points) } img.onerror = () => resolve([]) - img.src = '/images/tools.jpg' + img.src = '/images/tools.webp' }) } diff --git a/privat/CV/andreknie.de/src/components/PhotoBand.test.jsx b/privat/CV/andreknie.de/src/components/PhotoBand.test.jsx index 7190edc..24ca909 100644 --- a/privat/CV/andreknie.de/src/components/PhotoBand.test.jsx +++ b/privat/CV/andreknie.de/src/components/PhotoBand.test.jsx @@ -16,7 +16,7 @@ describe('PhotoBand', () => { // The CSS animation translates the track by -50%. If the sequence is not // rendered exactly twice, the loop "jumps" instead of being seamless. it('renders the image sequence exactly twice for a seamless loop', () => { - const images = ['/a.jpg', '/b.jpg', '/c.jpg'] + const images = ['/a.webp', '/b.webp', '/c.webp'] const { container } = render() const rendered = [...container.querySelectorAll('.photo-band-track img')].map(img => img.getAttribute('src') @@ -30,7 +30,7 @@ describe('PhotoBand', () => { it('keeps the duplication invariant for any non-empty image list', () => { for (const n of [1, 2, 4, 7]) { - const images = Array.from({ length: n }, (_, i) => `/img-${i}.jpg`) + const images = Array.from({ length: n }, (_, i) => `/img-${i}.webp`) const { container } = render() const count = container.querySelectorAll('.photo-band-track img').length expect(count).toBe(n * 2) diff --git a/privat/CV/andreknie.de/src/components/SEOHead.jsx b/privat/CV/andreknie.de/src/components/SEOHead.jsx index b6bffa3..5fee4af 100644 --- a/privat/CV/andreknie.de/src/components/SEOHead.jsx +++ b/privat/CV/andreknie.de/src/components/SEOHead.jsx @@ -8,7 +8,7 @@ export default function SEOHead({ title, description, url, image, type = 'websit const siteTitle = title ? `${title} | Dr. André Knie` : defaultTitle const siteDesc = description || defaultDescription const siteUrl = url ? `https://andreknie.de${url}` : "https://andreknie.de" - const siteImage = image || "https://andreknie.de/images/og-image.jpg" + const siteImage = image || "https://andreknie.de/images/og-image.webp" return ( diff --git a/privat/CV/andreknie.de/src/pages/About.jsx b/privat/CV/andreknie.de/src/pages/About.jsx index cc18f61..88bd122 100644 --- a/privat/CV/andreknie.de/src/pages/About.jsx +++ b/privat/CV/andreknie.de/src/pages/About.jsx @@ -19,7 +19,7 @@ export default function About() { {/* Profile Card */}
- Dr. André Knie + Dr. André Knie

{profile?.name || 'Dr. André Knie'}

diff --git a/privat/CV/andreknie.de/src/pages/Home.jsx b/privat/CV/andreknie.de/src/pages/Home.jsx index 3eb675a..7be3a38 100644 --- a/privat/CV/andreknie.de/src/pages/Home.jsx +++ b/privat/CV/andreknie.de/src/pages/Home.jsx @@ -9,11 +9,11 @@ import PhotoBand from '../components/PhotoBand' import './Home.css' const PHOTO_BAND_IMAGES = [ - '/images/workshop-1.jpg', - '/images/keynote-1.jpg', - '/images/workshop-2.jpg', - '/images/panel-1.jpg', - '/images/workshop-3.jpg', + '/images/workshop-1.webp', + '/images/keynote-1.webp', + '/images/workshop-2.webp', + '/images/panel-1.webp', + '/images/workshop-3.webp', ] export default function Home() { @@ -24,7 +24,7 @@ export default function Home() { {/* Hero */}

- Dr. André Knie + Dr. André Knie

{profile?.name || 'Dr. André Knie'}

diff --git a/privat/CV/andreknie.de/src/pages/Speaking.jsx b/privat/CV/andreknie.de/src/pages/Speaking.jsx index 23862b2..c55e19d 100644 --- a/privat/CV/andreknie.de/src/pages/Speaking.jsx +++ b/privat/CV/andreknie.de/src/pages/Speaking.jsx @@ -18,7 +18,7 @@ export default function Speaking() { {/* Speaker Bio */} {speaking?.bio && (
- Dr. André Knie + Dr. André Knie

{speaking.bio}

{speaking.style && (