📐 Responsive Photo Gallery
CSS techniques for responsive image lay-outs
🎨 Web Development Assets
Icons, graphics, and visual elements library
🏖️ Holiday Photography
Travel photos and vacation memories

Celebrity Downloads

Celebrity Download Link Description
Pamela Anderson Download Pamela Anderson Pictures Picture collection
Pat Benatar Download Pat Benatar Pictures Music artist photos
Cameron Diaz Download Cameron Diaz Pictures Actress photos
Celebrity External Link Type
Madonna Madonna Homepage Official Website
Lucy Lawless Lucy Lawless Homepage Official Website

External Links

If You Don't Like Girls, Go To The Financial World

Advanced Image Processing & Gallery Management Systems

Deze pagina behandelt advanced image processing, gallery management systems, en visual content optimization voor web applications. Modern image galleries require responsive design, lazy loading, progressive enhancement, en accessibility features voor optimal user experience. Image processing includes format optimization, automatic resizing, CDN integration, en metadata extraction voor comprehensive media management.

Image Processing & Optimization

Contemporary image processing implements automatic format conversion (WebP, AVIF), intelligent compression algorithms, en responsive image generation voor different viewport sizes. Server-side processing tools like Sharp, ImageMagick, en cloud-based solutions provide scalable image transformation capabilities. Progressive JPEG encoding, blur-up placeholders, en adaptive bitrate streaming ensure optimal loading performance across different network conditions.

Gallery Architecture & User Experience

Modern gallery systems feature infinite scroll, masonry layouts, full-screen lightbox experiences, en touch gesture support voor mobile devices. Virtual scrolling techniques handle large image collections efficiently, preventing memory exhaustion en maintaining smooth performance. Integration with content delivery networks enables global image distribution, automatic format negotiation, en edge caching voor reduced latency worldwide.

Advanced Gallery Implementation

// React Image Gallery with Advanced Features
import React, { useState, useEffect, useCallback, useRef } from 'react';
import { useIntersectionObserver } from './hooks/useIntersectionObserver';
import { useVirtualScroll } from './hooks/useVirtualScroll';

interface ImageItem {
  id: string;
  src: string;
  thumbnail: string;
  alt: string;
  width: number;
  height: number;
  blurhash?: string;
  metadata?: {
    camera?: string;
    lens?: string;
    settings?: string;
    location?: string;
    capturedAt?: Date;
  };
}

interface GalleryProps {
  images: ImageItem[];
  columns?: number;
  gap?: number;
  lazy?: boolean;
  lightbox?: boolean;
  infiniteScroll?: boolean;
  onImageLoad?: (image: ImageItem) => void;
}

const AdvancedImageGallery: React.FC<GalleryProps> = ({
  images,
  columns = 3,
  gap = 16,
  lazy = true,
  lightbox = true,
  infiniteScroll = false,
  onImageLoad
}) => {
  const [selectedImage, setSelectedImage] = useState<ImageItem | null>(null);
  const [loadedImages, setLoadedImages] = useState<Set<string>>(new Set());
  const [visibleRange, setVisibleRange] = useState({ start: 0, end: 20 });
  const containerRef = useRef<HTMLDivElement>(null);
  
  // Virtual scrolling for large galleries
  const { containerHeight, itemHeight } = useVirtualScroll({
    items: images,
    containerRef,
    itemHeight: 300,
    enabled: infiniteScroll && images.length > 100
  });
  
  // Intersection Observer for lazy loading
  const { observe, unobserve } = useIntersectionObserver({
    callback: (entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const imageId = entry.target.getAttribute('data-image-id');
          if (imageId) {
            handleImageVisible(imageId);
          }
        }
      });
    },
    options: {
      rootMargin: '100px 0px',
      threshold: 0.1
    }
  });
  
  const handleImageVisible = useCallback((imageId: string) => {
    if (!loadedImages.has(imageId)) {
      setLoadedImages(prev => new Set([...prev, imageId]));
      const image = images.find(img => img.id === imageId);
      if (image && onImageLoad) {
        onImageLoad(image);
      }
    }
  }, [images, loadedImages, onImageLoad]);
  
  const handleImageClick = useCallback((image: ImageItem) => {
    if (lightbox) {
      setSelectedImage(image);
    }
  }, [lightbox]);
  
  const closeLightbox = useCallback(() => {
    setSelectedImage(null);
  }, []);
  
  // Keyboard navigation
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (!selectedImage) return;
      
      const currentIndex = images.findIndex(img => img.id === selectedImage.id);
      
      switch (e.key) {
        case 'Escape':
          closeLightbox();
          break;
        case 'ArrowLeft':
          if (currentIndex > 0) {
            setSelectedImage(images[currentIndex - 1]);
          }
          break;
        case 'ArrowRight':
          if (currentIndex < images.length - 1) {
            setSelectedImage(images[currentIndex + 1]);
          }
          break;
      }
    };
    
    if (selectedImage) {
      document.addEventListener('keydown', handleKeyDown);
      document.body.style.overflow = 'hidden';
    }
    
    return () => {
      document.removeEventListener('keydown', handleKeyDown);
      document.body.style.overflow = '';
    };
  }, [selectedImage, images, closeLightbox]);
  
  const renderImage = useCallback((image: ImageItem, index: number) => {
    const shouldLoad = !lazy || loadedImages.has(image.id);
    
    return (
      <div
        key={image.id}
        className="gallery-item"
        style={{
          aspectRatio: `${image.width} / ${image.height}`,
          cursor: lightbox ? 'pointer' : 'default'
        }}
        onClick={() => handleImageClick(image)}
        data-image-id={image.id}
        ref={node => {
          if (node && lazy && !loadedImages.has(image.id)) {
            observe(node);
          }
        }}
      >
        {shouldLoad ? (
          <img
            src={image.thumbnail}
            alt={image.alt}
            loading="lazy"
            onLoad={() => handleImageVisible(image.id)}
            style={{
              width: '100%',
              height: '100%',
              objectFit: 'cover',
              transition: 'opacity 0.3s ease'
            }}
          />
        ) : (
          <div
            className="image-placeholder"
            style={{
              width: '100%',
              height: '100%',
              background: image.blurhash 
                ? `url("data:image/svg+xml;base64,${btoa(generateBlurSVG(image.blurhash))}")` 
                : '#f0f0f0',
              backgroundSize: 'cover'
            }}
          />
        )}
        
        {image.metadata && (
          <div className="image-overlay">
            <div className="image-info">
              {image.metadata.camera && (
                <span className="camera">{image.metadata.camera}</span>
              )}
              {image.metadata.settings && (
                <span className="settings">{image.metadata.settings}</span>
              )}
            </div>
          </div>
        )}
      </div>
    );
  }, [lazy, loadedImages, lightbox, handleImageClick, observe, handleImageVisible]);
  
  return (
    <div className="advanced-gallery" ref={containerRef}>
      <div
        className="gallery-grid"
        style={{
          display: 'grid',
          gridTemplateColumns: `repeat(${columns}, 1fr)`,
          gap: `${gap}px`,
          height: infiniteScroll ? containerHeight : 'auto'
        }}
      >
        {images
          .slice(visibleRange.start, visibleRange.end)
          .map((image, index) => renderImage(image, index))}
      </div>
      
      {selectedImage && lightbox && (
        <LightboxModal
          image={selectedImage}
          images={images}
          onClose={closeLightbox}
          onNavigate={setSelectedImage}
        />
      )}
    </div>
  );
};

// Lightbox Modal Component
const LightboxModal: React.FC<{
  image: ImageItem;
  images: ImageItem[];
  onClose: () => void;
  onNavigate: (image: ImageItem) => void;
}> = ({ image, images, onClose, onNavigate }) => {
  const [isLoading, setIsLoading] = useState(true);
  const [imageError, setImageError] = useState(false);
  
  const currentIndex = images.findIndex(img => img.id === image.id);
  const hasNext = currentIndex < images.length - 1;
  const hasPrev = currentIndex > 0;
  
  const handleImageLoad = () => setIsLoading(false);
  const handleImageError = () => {
    setIsLoading(false);
    setImageError(true);
  };
  
  const navigateNext = () => {
    if (hasNext) {
      onNavigate(images[currentIndex + 1]);
      setIsLoading(true);
      setImageError(false);
    }
  };
  
  const navigatePrev = () => {
    if (hasPrev) {
      onNavigate(images[currentIndex - 1]);
      setIsLoading(true);
      setImageError(false);
    }
  };
  
  return (
    <div className="lightbox-overlay" onClick={onClose}>
      <div className="lightbox-container" onClick={e => e.stopPropagation()}>
        <button className="lightbox-close" onClick={onClose}>
          ✕
        </button>
        
        {hasPrev && (
          <button className="lightbox-nav prev" onClick={navigatePrev}>
            ‹
          </button>
        )}
        
        {hasNext && (
          <button className="lightbox-nav next" onClick={navigateNext}>
            ›
          </button>
        )}
        
        <div className="lightbox-content">
          {isLoading && (
            <div className="lightbox-loading">
              Loading...
            </div>
          )}
          
          {imageError ? (
            <div className="lightbox-error">
              Failed to load image
            </div>
          ) : (
            <img
              src={image.src}
              alt={image.alt}
              onLoad={handleImageLoad}
              onError={handleImageError}
              style={{
                maxWidth: '100%',
                maxHeight: '100%',
                objectFit: 'contain',
                opacity: isLoading ? 0 : 1,
                transition: 'opacity 0.3s ease'
              }}
            />
          )}
          
          {image.metadata && (
            <div className="lightbox-metadata">
              <h3>{image.alt}</h3>
              {image.metadata.camera && <p>Camera: {image.metadata.camera}</p>}
              {image.metadata.lens && <p>Lens: {image.metadata.lens}</p>}
              {image.metadata.settings && <p>Settings: {image.metadata.settings}</p>}
              {image.metadata.location && <p>Location: {image.metadata.location}</p>}
              {image.metadata.capturedAt && (
                <p>Captured: {image.metadata.capturedAt.toLocaleDateString()}</p>
              )}
            </div>
          )}
        </div>
        
        <div className="lightbox-counter">
          {currentIndex + 1} / {images.length}
        </div>
      </div>
    </div>
  );
};

// Helper function for blur placeholder
const generateBlurSVG = (blurhash: string): string => {
  // Simplified blurhash to SVG conversion
  return `<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40">
    <filter id="blur"><feGaussianBlur stdDeviation="2"/></filter>
    <rect width="100%" height="100%" fill="${blurhash.slice(0, 7)}" filter="url(#blur)"/>
  </svg>`;
};
# Server-side Image Processing
import asyncio
import aiofiles
from PIL import Image, ImageOps, ImageFilter
from pillow_heif import register_heif_opener
import numpy as np
from typing import List, Dict, Optional, Tuple
import hashlib
import json
from pathlib import Path

register_heif_opener()

class ImageProcessor:
    def __init__(self, cache_dir: str = "./cache", max_size: int = 2048):
        self.cache_dir = Path(cache_dir)
        self.cache_dir.mkdir(exist_ok=True)
        self.max_size = max_size
        
        # Supported formats
        self.input_formats = {'.jpg', '.jpeg', '.png', '.webp', '.tiff', '.heic', '.heif'}
        self.output_formats = ['webp', 'jpeg', 'png']
        
    async def process_image(
        self,
        input_path: str,
        output_formats: Optional[List[str]] = None,
        sizes: Optional[List[int]] = None,
        quality: int = 85,
        progressive: bool = True
    ) -> Dict[str, List[str]]:
        """Process image into multiple formats and sizes."""
        input_path = Path(input_path)
        
        if not input_path.exists():
            raise FileNotFoundError(f"Image not found: {input_path}")
            
        if input_path.suffix.lower() not in self.input_formats:
            raise ValueError(f"Unsupported format: {input_path.suffix}")
        
        # Generate cache key
        cache_key = self.generate_cache_key(input_path, output_formats, sizes, quality)
        cache_file = self.cache_dir / f"{cache_key}.json"
        
        # Check cache
        if cache_file.exists():
            async with aiofiles.open(cache_file, 'r') as f:
                cached_result = json.loads(await f.read())
                # Verify all files still exist
                if self.validate_cached_files(cached_result):
                    return cached_result
        
        # Load and analyze image
        with Image.open(input_path) as img:
            # Fix orientation
            img = ImageOps.exif_transpose(img)
            
            original_width, original_height = img.size
            aspect_ratio = original_width / original_height
            
            # Default sizes if not specified
            if sizes is None:
                sizes = self.calculate_responsive_sizes(original_width)
            
            if output_formats is None:
                output_formats = ['webp', 'jpeg']
            
            results = {}
            
            for fmt in output_formats:
                results[fmt] = []
                
                for size in sizes:
                    # Skip if size is larger than original
                    if size > max(original_width, original_height):
                        continue
                    
                    # Calculate dimensions maintaining aspect ratio
                    if original_width > original_height:
                        new_width = min(size, original_width)
                        new_height = int(new_width / aspect_ratio)
                    else:
                        new_height = min(size, original_height)
                        new_width = int(new_height * aspect_ratio)
                    
                    # Generate output filename
                    output_name = f"{input_path.stem}_{new_width}x{new_height}.{fmt}"
                    output_path = self.cache_dir / output_name
                    
                    # Resize and save
                    await self.resize_and_save(
                        img, output_path, (new_width, new_height), fmt, quality, progressive
                    )
                    
                    results[fmt].append({
                        'path': str(output_path),
                        'width': new_width,
                        'height': new_height,
                        'size_bytes': output_path.stat().st_size
                    })
        
        # Cache results
        async with aiofiles.open(cache_file, 'w') as f:
            await f.write(json.dumps(results, indent=2))
        
        return results
    
    async def resize_and_save(
        self,
        img: Image.Image,
        output_path: Path,
        size: Tuple[int, int],
        fmt: str,
        quality: int,
        progressive: bool
    ):
        """Resize and save image with optimization."""
        # Resize with high-quality resampling
        resized = img.resize(size, Image.Resampling.LANCZOS)
        
        # Apply sharpening for small images
        if max(size) < 800:
            resized = resized.filter(ImageFilter.UnsharpMask(radius=1, percent=150, threshold=3))
        
        # Save with format-specific optimizations
        save_kwargs = {'optimize': True}
        
        if fmt == 'webp':
            save_kwargs.update({
                'format': 'WebP',
                'quality': quality,
                'method': 6,  # Best compression
                'lossless': quality == 100
            })
        elif fmt == 'jpeg':
            save_kwargs.update({
                'format': 'JPEG',
                'quality': quality,
                'progressive': progressive,
                'optimize': True
            })
            # Convert to RGB if necessary
            if resized.mode in ('RGBA', 'P'):
                background = Image.new('RGB', resized.size, (255, 255, 255))
                if resized.mode == 'P':
                    resized = resized.convert('RGBA')
                background.paste(resized, mask=resized.split()[-1] if resized.mode == 'RGBA' else None)
                resized = background
        elif fmt == 'png':
            save_kwargs.update({
                'format': 'PNG',
                'optimize': True,
                'compress_level': 9
            })
        
        # Save in a separate thread to avoid blocking
        loop = asyncio.get_event_loop()
        await loop.run_in_executor(None, resized.save, output_path, **save_kwargs)
    
    def calculate_responsive_sizes(self, original_width: int) -> List[int]:
        """Calculate responsive image sizes."""
        breakpoints = [320, 640, 768, 1024, 1366, 1920, 2560]
        
        # Only include sizes smaller than or equal to original
        relevant_sizes = [size for size in breakpoints if size <= original_width]
        
        # Always include original size
        if original_width not in relevant_sizes:
            relevant_sizes.append(original_width)
        
        return sorted(relevant_sizes)
    
    async def extract_metadata(self, image_path: str) -> Dict:
        """Extract comprehensive image metadata."""
        with Image.open(image_path) as img:
            # Basic info
            metadata = {
                'filename': Path(image_path).name,
                'format': img.format,
                'mode': img.mode,
                'size': img.size,
                'file_size': Path(image_path).stat().st_size
            }
            
            # EXIF data
            if hasattr(img, '_getexif') and img._getexif():
                exif = img._getexif()
                if exif:
                    # Extract common EXIF tags
                    exif_tags = {
                        'DateTime': exif.get(306),
                        'Camera': exif.get(272),  # Make
                        'Model': exif.get(271),   # Model
                        'Lens': exif.get(42036),  # LensModel
                        'ISO': exif.get(34855),
                        'FNumber': exif.get(33437),
                        'ExposureTime': exif.get(33434),
                        'FocalLength': exif.get(37386),
                        'GPS': self.extract_gps_data(exif)
                    }
                    metadata['exif'] = {k: v for k, v in exif_tags.items() if v is not None}
            
            # Color analysis
            metadata['colors'] = await self.analyze_colors(img)
            
            # Generate blurhash placeholder
            metadata['blurhash'] = await self.generate_blurhash(img)
            
            return metadata
    
    async def analyze_colors(self, img: Image.Image) -> Dict:
        """Analyze dominant colors in the image."""
        # Resize for faster processing
        small_img = img.resize((50, 50))
        
        # Convert to RGB
        if small_img.mode != 'RGB':
            small_img = small_img.convert('RGB')
        
        # Get pixel data
        pixels = np.array(small_img)
        pixels = pixels.reshape(-1, 3)
        
        # Find dominant colors using k-means clustering
        from sklearn.cluster import KMeans
        
        kmeans = KMeans(n_clusters=5, random_state=42)
        kmeans.fit(pixels)
        
        colors = []
        for i, color in enumerate(kmeans.cluster_centers_):
            color_count = np.sum(kmeans.labels_ == i)
            percentage = color_count / len(pixels) * 100
            
            colors.append({
                'rgb': [int(c) for c in color],
                'hex': '#{:02x}{:02x}{:02x}'.format(*[int(c) for c in color]),
                'percentage': round(percentage, 2)
            })
        
        # Sort by percentage
        colors.sort(key=lambda x: x['percentage'], reverse=True)
        
        return {
            'dominant': colors[0]['hex'],
            'palette': colors,
            'average_brightness': np.mean(pixels) / 255
        }
    
    async def generate_blurhash(self, img: Image.Image) -> str:
        """Generate blurhash for progressive loading placeholder."""
        # Simple blurhash approximation
        # In production, use the blurhash library
        
        # Resize to small size
        small = img.resize((4, 3))
        if small.mode != 'RGB':
            small = small.convert('RGB')
        
        # Get average color as simple hash
        pixels = np.array(small)
        avg_color = np.mean(pixels.reshape(-1, 3), axis=0)
        
        # Create a simple hash representation
        hash_str = ''.join([f'{int(c):02x}' for c in avg_color])
        return f"L{hash_str[:6]}"
    
    def extract_gps_data(self, exif: Dict) -> Optional[Dict]:
        """Extract GPS coordinates from EXIF data."""
        gps_tags = {
            'GPSLatitude': 2,
            'GPSLatitudeRef': 1,
            'GPSLongitude': 4,
            'GPSLongitudeRef': 3
        }
        
        gps_data = {}
        for tag, key in gps_tags.items():
            if key in exif:
                gps_data[tag] = exif[key]
        
        if len(gps_data) >= 4:
            # Convert to decimal degrees
            lat = self.convert_to_degrees(gps_data['GPSLatitude'])
            if gps_data['GPSLatitudeRef'] == 'S':
                lat = -lat
                
            lon = self.convert_to_degrees(gps_data['GPSLongitude'])
            if gps_data['GPSLongitudeRef'] == 'W':
                lon = -lon
                
            return {'latitude': lat, 'longitude': lon}
        
        return None
    
    def convert_to_degrees(self, value) -> float:
        """Convert GPS coordinates to decimal degrees."""
        d, m, s = value
        return d + (m / 60.0) + (s / 3600.0)
    
    def generate_cache_key(self, input_path: Path, formats: List[str], sizes: List[int], quality: int) -> str:
        """Generate cache key for processed images."""
        # Include file modification time in cache key
        mtime = input_path.stat().st_mtime
        key_data = f"{input_path}_{formats}_{sizes}_{quality}_{mtime}"
        return hashlib.md5(key_data.encode()).hexdigest()
    
    def validate_cached_files(self, cached_result: Dict) -> bool:
        """Validate that all cached files still exist."""
        for format_files in cached_result.values():
            for file_info in format_files:
                if not Path(file_info['path']).exists():
                    return False
        return True

Performance Optimization & Accessibility

Modern gallery systems implement performance optimization strategies including image compression, CDN delivery, en progressive loading techniques. Accessibility features include keyboard navigation, screen reader support, alt text management, en color contrast optimization voor inclusive user experiences. Analytics integration tracks user engagement, image performance metrics, en conversion rates voor data-driven gallery optimization.

Implementeer moderne ontwikkelmethodes met focus op gebruikerservaring, prestaties en onderhoudbaarheid. Zorg voor complete test coverage en gebruik continuous integration pipelines voor automated image processing, quality validation, en deployment workflows.

-->