# Image Optimization Guide for GengSewa

This guide explains how to optimize images for faster page loading and better performance.

## Table of Contents
1. [Automatic Optimization](#automatic-optimization)
2. [Manual Optimization](#manual-optimization)
3. [Lazy Loading Implementation](#lazy-loading-implementation)
4. [Image Storage Strategy](#image-storage-strategy)

---

## 1. Automatic Optimization

### A. Install Optimization Tools

**Ubuntu/Debian:**
```bash
sudo apt-get update
sudo apt-get install -y jpegoptim optipng pngquant gifsicle webp
```

**Windows (via Scoop):**
```powershell
scoop install jpegoptim
scoop install optipng
scoop install pngquant
scoop install gifsicle
```

### B. Optimize Existing Images

**JPEG Optimization:**
```bash
# Single file
jpegoptim --max=85 --strip-all image.jpg

# All JPEG files in directory
find public/images/listings -name "*.jpg" -exec jpegoptim --max=85 --strip-all {} \;

# Or using Windows
for /r "public\images\listings" %i in (*.jpg) do jpegoptim --max=85 --strip-all "%i"
```

**PNG Optimization:**
```bash
# Single file
optipng -o5 image.png

# All PNG files
find public/images/listings -name "*.png" -exec optipng -o5 {} \;

# Windows
for /r "public\images\listings" %i in (*.png) do optipng -o5 "%i"
```

**Convert to WebP (Modern Format):**
```bash
# JPEG to WebP
cwebp -q 85 input.jpg -o output.webp

# PNG to WebP
cwebp -lossless input.png -o output.webp

# Batch convert all JPEGs
find public/images/listings -name "*.jpg" -exec sh -c 'cwebp -q 85 "$1" -o "${1%.jpg}.webp"' _ {} \;
```

### C. Automatic Optimization Script

Create `optimize-images.sh`:
```bash
#!/bin/bash

# GengSewa Image Optimization Script

IMAGES_DIR="public/images/listings"

echo "Optimizing images in $IMAGES_DIR..."

# Optimize JPEGs
find "$IMAGES_DIR" -name "*.jpg" -o -name "*.jpeg" | while read file; do
    echo "Optimizing: $file"
    jpegoptim --max=85 --strip-all "$file"

    # Convert to WebP
    cwebp -q 85 "$file" -o "${file%.*}.webp"
done

# Optimize PNGs
find "$IMAGES_DIR" -name "*.png" | while read file; do
    echo "Optimizing: $file"
    optipng -o5 "$file"

    # Convert to WebP
    cwebp -lossless "$file" -o "${file%.*}.webp"
done

echo "Optimization complete!"
echo "Before/After comparison:"
du -sh "$IMAGES_DIR"
```

Make executable and run:
```bash
chmod +x optimize-images.sh
./optimize-images.sh
```

---

## 2. Manual Optimization

### Recommended Image Sizes

**Listing Images:**
- Thumbnail: 300x200px (for listing cards)
- Medium: 800x600px (for listing details)
- Large: 1200x800px (for full-screen gallery)
- Maximum file size: 500KB per image

**Profile Images:**
- Avatar: 150x150px
- Profile photo: 400x400px
- Maximum file size: 200KB

### Optimization Settings

**JPEG Quality:**
- High quality: 90-95 (for hero images)
- Standard quality: 80-85 (for most images)
- Thumbnail quality: 70-75

**PNG Optimization:**
- Use PNG-8 for simple graphics
- Use PNG-24 for photos (or convert to JPEG)
- Compress with pngquant for smaller sizes

**WebP Conversion:**
- Quality: 80-85 for photos
- Lossless for graphics/logos

---

## 3. Lazy Loading Implementation

### Current Implementation
The listing detail page already uses natural height images. To add lazy loading:

**Update Blade Templates:**
```blade
<!-- Example: listing-details.blade.php -->
<img
    src="{{ $listing->images[0] }}"
    alt="{{ $listing->title }}"
    class="w-full h-auto"
    loading="lazy"
    decoding="async"
>
```

**For Multiple Images:**
```blade
@foreach($listing->images as $index => $image)
    <img
        src="{{ $image }}"
        alt="{{ $listing->title }} - Image {{ $index + 1 }}"
        class="w-full object-cover"
        loading="{{ $index === 0 ? 'eager' : 'lazy' }}"
        decoding="async"
    >
@endforeach
```

### Advanced Lazy Loading with JavaScript

Create `resources/js/lazy-load.js`:
```javascript
// Intersection Observer API for lazy loading
document.addEventListener('DOMContentLoaded', function() {
    const lazyImages = document.querySelectorAll('img[data-src]');

    if ('IntersectionObserver' in window) {
        const imageObserver = new IntersectionObserver((entries, observer) => {
            entries.forEach(entry => {
                if (entry.isIntersecting) {
                    const img = entry.target;
                    img.src = img.dataset.src;
                    img.classList.add('loaded');
                    imageObserver.unobserve(img);
                }
            });
        });

        lazyImages.forEach(img => imageObserver.observe(img));
    } else {
        // Fallback for older browsers
        lazyImages.forEach(img => {
            img.src = img.dataset.src;
        });
    }
});
```

---

## 4. Image Storage Strategy

### A. Local Storage Structure
```
public/images/
├── listings/
│   ├── {timestamp}_{hash}.jpg
│   ├── {timestamp}_{hash}.webp
│   └── thumbnails/
│       └── {timestamp}_{hash}_thumb.jpg
├── profiles/
│   └── {user_id}_{timestamp}.jpg
└── system/
    ├── logo.png
    └── favicon.ico
```

### B. Image Upload Best Practices

**In Controllers/Livewire Components:**
```php
use Intervention\Image\Facades\Image;

public function uploadImage($file)
{
    // Validate
    $this->validate([
        'image' => 'required|image|mimes:jpeg,png,jpg|max:2048'
    ]);

    // Generate unique filename
    $filename = time() . '_' . uniqid() . '.' . $file->extension();

    // Optimize and save
    $image = Image::make($file);

    // Resize if too large
    if ($image->width() > 1200) {
        $image->resize(1200, null, function ($constraint) {
            $constraint->aspectRatio();
            $constraint->upsize();
        });
    }

    // Save with quality
    $image->save(public_path('images/listings/' . $filename), 85);

    // Create thumbnail
    $thumbnail = Image::make($file);
    $thumbnail->fit(300, 200);
    $thumbnail->save(public_path('images/listings/thumbnails/' . $filename), 75);

    // Generate WebP version (if extension available)
    if (extension_loaded('gd') && function_exists('imagewebp')) {
        $webpFilename = pathinfo($filename, PATHINFO_FILENAME) . '.webp';
        imagewebp(imagecreatefromstring($image->encode()), public_path('images/listings/' . $webpFilename), 85);
    }

    return $filename;
}
```

### C. Serve Images with Correct Format

**In Blade Templates:**
```blade
<picture>
    <source srcset="{{ asset('images/listings/' . pathinfo($image, PATHINFO_FILENAME) . '.webp') }}" type="image/webp">
    <img src="{{ asset('images/listings/' . $image) }}" alt="{{ $alt }}" class="w-full h-auto" loading="lazy">
</picture>
```

### D. CDN Integration (Optional)

For high traffic, consider using a CDN:

**Popular Options:**
- Cloudflare (Free tier available)
- Amazon CloudFront
- BunnyCDN
- KeyCDN

**Configuration:**
Update `.env`:
```
CDN_ENABLED=true
CDN_URL=https://cdn.yoursite.com
```

Update `config/app.php`:
```php
'asset_url' => env('CDN_ENABLED', false) ? env('CDN_URL') : null,
```

---

## 5. Performance Metrics

### Expected Improvements
After optimization:
- **Image size reduction:** 60-80%
- **Page load time:** Improve by 30-50%
- **Bandwidth savings:** 50-70%
- **Lighthouse score:** +20-30 points

### Monitoring
```bash
# Check total image size
du -sh public/images/

# Check average file size
find public/images/listings -name "*.jpg" -exec ls -lh {} \; | awk '{print $5}' | sort -h

# Test page speed
curl -o /dev/null -s -w "Time: %{time_total}s\nSize: %{size_download} bytes\n" https://yoursite.com
```

---

## 6. Automated Optimization in Production

### Option 1: On Upload (Recommended)
Integrate optimization into the upload process using Intervention Image or similar packages.

### Option 2: Cron Job
Add to crontab:
```bash
# Optimize new images daily at 2 AM
0 2 * * * /path/to/gengsewa/optimize-images.sh >> /var/log/image-optimization.log 2>&1
```

### Option 3: Queue Job
Create a Laravel queue job for image optimization:
```bash
php artisan make:job OptimizeImage
```

---

## 7. Cleanup Old Images

Script to remove unused images:
```bash
#!/bin/bash

# Find images not referenced in database
cd public/images/listings

for file in *; do
    if ! grep -r "$file" ../../database >/dev/null; then
        echo "Unused image: $file"
        # Uncomment to delete
        # rm "$file"
    fi
done
```

---

## Summary Checklist

- [ ] Install optimization tools (jpegoptim, optipng, cwebp)
- [ ] Run optimization on existing images
- [ ] Add lazy loading to image tags
- [ ] Implement WebP format support
- [ ] Set up CDN (optional)
- [ ] Configure automatic optimization on upload
- [ ] Set up monitoring for image sizes
- [ ] Schedule regular optimization tasks

---

**Last Updated:** 2025-10-17
