Files
2026-04-11 00:04:09 -05:00

477 lines
12 KiB
Markdown

# 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