Initial
This commit is contained in:
@@ -0,0 +1,476 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user