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

12 KiB

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

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):

{
  "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:

{
  "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):

{
  "productCode": "cobrai"
}

Response:

{
  "status": "success",
  "message": "Cache cleared for cobrai"
}

Configuration File Format

Location: app/data/image_configs.json

Structure:

{
  "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

<img src="/api/product-image/cobrai?color=black&hinge=left" alt="Storm Door">

Option 2: JavaScript with Base64

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

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

# 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:

curl http://localhost:8080/api/product-image/cobrai?color=black > test_black.png

Test with different configurations:

curl http://localhost:8080/api/product-image/cobrai?color=bronze&hinge=left > test_bronze_left.png

Get JSON response:

curl http://localhost:8080/api/product-image/cobrai?color=white&format=json

Get configuration:

curl http://localhost:8080/api/product-config/cobrai

Clear cache:

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

// 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:

{
  "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

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

  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

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"

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