# Dynamic Image Generation API

## Overview
This system generates product images on-the-fly with configurable colors, hardware positions, and other options. It uses server-side image processing with PIL/Pillow to composite and recolor product images dynamically.

## Setup

### 1. Install Dependencies
```bash
pip install -r requirements.txt
```

This will install:
- Flask (web framework)
- Pillow (image processing)
- Other dependencies

### 2. Prepare Product Images

For the COBRAI demo product:
1. Save the white storm door image as `app/images/cobrai.jpg`
2. The configuration is already in `app/data/image_configs.json`

### 3. Create Cache Directory
The cache directory will be created automatically when the app runs:
```
app/cache/product_images/
```

## API Endpoints

### 1. Generate Product Image

**Endpoint:** `GET /api/product-image/<product_code>`

**Parameters:**
- `color` - Color name (default: 'white')
  - Options: white, black, bronze, sandstone
- `hinge` - Hinge side (default: 'right')
  - Options: left, right
- `material` - Material type (default: 'aluminum')
  - For future use
- `format` - Return format (default: 'image')
  - Options: image, json
- `cache` - Use caching (default: 'true')
  - Options: true, false

**Examples:**

Return image directly (for use in `<img>` tags):
```
GET http://localhost:8080/api/product-image/cobrai?color=black&hinge=right
GET http://localhost:8080/api/product-image/cobrai?color=bronze&hinge=left
```

Return JSON with base64 image:
```
GET http://localhost:8080/api/product-image/cobrai?color=white&hinge=right&format=json
```

**Response (format=image):**
Raw PNG image file

**Response (format=json):**
```json
{
  "status": "success",
  "productCode": "cobrai",
  "color": "black",
  "hinge": "left",
  "material": "aluminum",
  "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
  "format": "base64"
}
```

### 2. Get Product Configuration

**Endpoint:** `GET /api/product-config/<product_code>`

Returns the complete configuration for a product including available colors, colorable regions, hardware positions, etc.

**Example:**
```
GET http://localhost:8080/api/product-config/cobrai
```

**Response:**
```json
{
  "status": "success",
  "productCode": "cobrai",
  "config": {
    "sourceImage": "images/cobrai.jpg",
    "productCode": "COBRAI",
    "availableColors": {
      "white": {"rgb": [255, 255, 255], "name": "White"},
      "black": {"rgb": [30, 30, 30], "name": "Black"},
      "bronze": {"rgb": [110, 80, 50], "name": "Bronze"}
    },
    "colorableRegions": [...],
    "hardwarePositions": {...},
    "metadata": {...}
  }
}
```

### 3. Clear Image Cache

**Endpoint:** `POST /api/clear-image-cache`

Clears cached images. Useful when updating source images or configurations.

**Request Body (Optional):**
```json
{
  "productCode": "cobrai"
}
```

**Response:**
```json
{
  "status": "success",
  "message": "Cache cleared for cobrai"
}
```

## Configuration File Format

Location: `app/data/image_configs.json`

### Structure:

```json
{
  "product_code": {
    "sourceImage": "path/to/source.jpg",
    "productCode": "PRODUCT_CODE",
    "description": "Product description",
    
    "availableColors": {
      "color_name": {
        "rgb": [R, G, B],
        "name": "Display Name"
      }
    },
    
    "colorableRegions": [
      {
        "name": "region_identifier",
        "topLeft": [x, y],
        "bottomRight": [x, y],
        "description": "What this region is"
      }
    ],
    
    "hardwarePositions": {
      "handle_right": {
        "x": 580,
        "y": 730,
        "image": "path/to/hardware.png",
        "flip": false
      }
    },
    
    "glassRegions": [
      {
        "name": "glass_area",
        "topLeft": [x, y],
        "bottomRight": [x, y],
        "description": "Glass/screen area"
      }
    ],
    
    "metadata": {
      "imageWidth": 720,
      "imageHeight": 1450,
      "defaultColor": "white",
      "defaultHinge": "right"
    },
    
    "cache": {
      "enabled": true,
      "directory": "cache/product_images",
      "maxAge": 86400
    }
  }
}
```

### Key Concepts:

#### Colorable Regions
Define rectangular areas to be recolored. The algorithm:
1. Preserves brightness/luminosity
2. Applies target color
3. Maintains shadows and highlights

Coordinates are `[x, y]` where:
- `topLeft`: Upper-left corner
- `bottomRight`: Lower-right corner

#### Hardware Positions
Define where handles, locks, etc. should be placed:
- `x, y`: Position to place hardware image
- `image`: Path to hardware PNG (with transparency)
- `flip`: Whether to flip horizontally (for left hinge)

#### Glass Regions
Define areas that should remain unchanged (glass, screens).
Currently for documentation purposes; future feature.

## Frontend Integration

### Option 1: Direct Image URL
```html
<img src="/api/product-image/cobrai?color=black&hinge=left" alt="Storm Door">
```

### Option 2: JavaScript with Base64
```javascript
async function loadProductImage(productCode, color, hinge) {
  const response = await fetch(
    `/api/product-image/${productCode}?color=${color}&hinge=${hinge}&format=json`
  );
  const data = await response.json();
  
  if (data.status === 'success') {
    document.getElementById('product-img').src = data.image;
  }
}

// Usage
loadProductImage('cobrai', 'black', 'left');
```

### Option 3: Dynamic URL Switching
```javascript
function updateProductImage(color, hinge) {
  const img = document.getElementById('product-img');
  img.src = `/api/product-image/cobrai?color=${color}&hinge=${hinge}`;
}

// On color change
document.getElementById('color-select').addEventListener('change', (e) => {
  const color = e.target.value;
  const hinge = document.querySelector('[name="hinge"]:checked').value;
  updateProductImage(color, hinge);
});
```

## How Image Processing Works

### Color Application
1. **Load base image** - White or neutral colored product photo
2. **Define regions** - Specify rectangles for frame, panels, etc.
3. **Calculate brightness** - For each pixel, determine relative brightness
4. **Apply target color** - Colorize while preserving brightness variations
5. **Result** - Natural-looking colored product with preserved shadows/highlights

### Brightness Preservation
```python
# For each pixel in region:
original_brightness = (r + g + b) / 3
brightness_factor = original_brightness / 255.0

new_r = target_color_r * brightness_factor
new_g = target_color_g * brightness_factor  
new_b = target_color_b * brightness_factor
```

This maintains shadows (darker pixels stay darker) and highlights (lighter pixels stay lighter).

### Hardware Application
1. Load hardware PNG with transparency
2. Optionally flip horizontally for left hinge
3. Composite onto product image at specified position

### Caching
- Generated images are cached using MD5 hash of parameters
- Cache key: `{product_code}_{color}_{hinge}_{material}`
- Stored as PNG in `cache/product_images/`
- Subsequent requests return cached version instantly

## Testing the Endpoints

### Using cURL

Test basic image generation:
```bash
curl http://localhost:8080/api/product-image/cobrai?color=black > test_black.png
```

Test with different configurations:
```bash
curl http://localhost:8080/api/product-image/cobrai?color=bronze&hinge=left > test_bronze_left.png
```

Get JSON response:
```bash
curl http://localhost:8080/api/product-image/cobrai?color=white&format=json
```

Get configuration:
```bash
curl http://localhost:8080/api/product-config/cobrai
```

Clear cache:
```bash
curl -X POST http://localhost:8080/api/clear-image-cache -H "Content-Type: application/json" -d '{"productCode":"cobrai"}'
```

### Using Browser
Simply visit:
```
http://localhost:8080/api/product-image/cobrai?color=black&hinge=left
```

### Using JavaScript Fetch
```javascript
// Get image as blob
fetch('/api/product-image/cobrai?color=bronze&hinge=left')
  .then(response => response.blob())
  .then(blob => {
    const url = URL.createObjectURL(blob);
    document.getElementById('img').src = url;
  });

// Get as JSON
fetch('/api/product-image/cobrai?color=black&format=json')
  .then(response => response.json())
  .then(data => {
    document.getElementById('img').src = data.image;
  });
```

## Adding New Products

### Step 1: Prepare Source Image
- Photograph product in white or neutral color
- Clean background
- Good lighting
- High resolution (will be resized)
- Save as JPG in `app/images/`

### Step 2: Determine Regions
Open image in image editor and note pixel coordinates:
- Frame edges (left, right, top, bottom)
- Panels/kickplates
- Rails/dividers

Record as `topLeft [x, y]` and `bottomRight [x, y]`

### Step 3: Add to Configuration
Add entry to `image_configs.json`:
```json
{
  "your_product": {
    "sourceImage": "images/your_product.jpg",
    "productCode": "YOUR-PRODUCT",
    "availableColors": {
      "white": {"rgb": [255, 255, 255], "name": "White"},
      "black": {"rgb": [30, 30, 30], "name": "Black"}
    },
    "colorableRegions": [
      {
        "name": "frame",
        "topLeft": [0, 0],
        "bottomRight": [100, 1450]
      }
    ],
    "metadata": {
      "imageWidth": 720,
      "imageHeight": 1450,
      "defaultColor": "white"
    }
  }
}
```

### Step 4: Test
```bash
curl http://localhost:8080/api/product-image/your_product?color=black > test.png
```

## Performance Notes

### First Request
- ~100-500ms (depending on image size and region count)
- Includes image loading, processing, and caching

### Cached Requests
- ~10-50ms
- Just file system read and serve

### Memory Usage
- Base image kept in memory during processing
- Minimal memory footprint when served from cache

### Optimization Tips
1. **Use caching** - Enabled by default
2. **Smaller source images** - 1000x1600px is usually sufficient
3. **Fewer regions** - Combine adjacent areas when possible
4. **CDN** - Serve cached images from CDN in production

## Production Deployment

### Recommended Setup
1. **Pre-generate** common combinations on deploy
2. **CDN** to serve cached images
3. **Redis cache** instead of filesystem (optional)
4. **Image optimization** - Use WebP format where supported
5. **Rate limiting** on generation endpoint

### Pre-generation Script
```python
from image_generator import ProductImageGenerator

generator = ProductImageGenerator()
products = ['cobrai', 'product2']
colors = ['white', 'black', 'bronze']
hinges = ['left', 'right']

for product in products:
    for color in colors:
        for hinge in hinges:
            img = generator.generate_product_image(product, color, hinge)
            print(f'Generated: {product} {color} {hinge}')
```

## Troubleshooting

### "PIL/Pillow not installed"
```bash
pip install Pillow
```

### "Product not found in configuration"
Check that product code in URL matches key in `image_configs.json`

### "Could not load base image"
Verify `sourceImage` path in config and that file exists

### Colors look wrong
Adjust RGB values in `availableColors` section

### Regions not coloring
1. Verify coordinates are within image bounds
2. Check that region isn't transparent
3. Ensure topLeft is actually top-left of bottomRight

### Cache not working
Check that `cache/product_images/` directory is writable

## Future Enhancements

### Planned Features
- [ ] Material textures (wood grain, brushed metal)
- [ ] Glass tinting/color
- [ ] Shadow/lighting adjustments based on color
- [ ] Multiple hardware styles
- [ ] Size variations
- [ ] Decorative glass patterns
- [ ] WebP format support
- [ ] Batch generation CLI tool
- [ ] Admin UI for region configuration
- [ ] Automatic region detection (AI/ML)

### Integration Ideas
- Direct integration with product configurator
- Real-time preview as user selects options
- Download high-res configured images
- Email configured image to customer
- Social media sharing with custom image
