477 lines
12 KiB
Markdown
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
|