🔍 Code Extractor

function create_signature_image

Maturity: 50

Generates a synthetic signature image for a given name, either as stylized text or as a random hand-drawn curve, and saves it as a PNG file with transparent background.

File:
/tf/active/vicechatdev/document_auditor/generate_sample_signatures.py
Lines:
17 - 140
Complexity:
moderate

Purpose

This function creates realistic-looking signature images programmatically for use in document generation, testing, or mock data scenarios. It attempts to use handwriting-style fonts from the system and can generate either text-based signatures (with optional underlines or slant) or curve-based signatures that mimic hand-drawn signatures with random flourishes and loops.

Source Code

def create_signature_image(name, output_path, width=400, height=150, bg_color=(255, 255, 255, 0)):
    """
    Create a signature image for the given name
    
    Args:
        name (str): Name of the person
        output_path (str): Path to save the signature image
        width (int): Width of the signature image
        height (int): Height of the signature image
        bg_color (tuple): Background color (RGBA)
    
    Returns:
        str: Path to the created signature image
    """
    # Create a transparent image
    image = Image.new('RGBA', (width, height), bg_color)
    draw = ImageDraw.Draw(image)
    
    # Try to load a font for the signature
    try:
        # Try to find a handwriting-like font
        font_paths = [
            '/usr/share/fonts/truetype/dejavu/DejaVuSans-Oblique.ttf',  # Common in Linux
            '/usr/share/fonts/truetype/liberation/LiberationSans-Italic.ttf',  # Another Linux option
            '/Library/Fonts/Apple Chancery.ttf',  # Mac
            'C:\\Windows\\Fonts\\BRUSHSCI.TTF',  # Windows
            'C:\\Windows\\Fonts\\PALSCRI.TTF',  # Windows
        ]
        
        font = None
        for font_path in font_paths:
            if os.path.exists(font_path):
                font = ImageFont.truetype(font_path, 45)
                logger.info(f"Using font: {font_path}")
                break
        
        if font is None:
            # Fall back to default font
            logger.warning("No handwriting fonts found, using default font")
            font = ImageFont.load_default()
    except Exception as e:
        logger.warning(f"Error loading font: {e}")
        font = ImageFont.load_default()
    
    # Generate signature - either use the font or draw a random curve
    if random.choice([True, False]) and font != ImageFont.load_default():
        # Text-based signature
        text_color = (0, 0, 128, 255)  # Dark blue with full opacity
        
        # Format the name nicely
        name_parts = name.split()
        if len(name_parts) > 1:
            # Use first initial and last name
            formatted_name = f"{name_parts[0][0]}. {name_parts[-1]}"
        else:
            formatted_name = name
        
        # Add some random variation to the signature
        if random.choice([True, False]):
            # Underline
            text_width = draw.textlength(formatted_name, font=font)
            y_pos = height // 2
            draw.text((width//2 - text_width//2, y_pos - 30), formatted_name, fill=text_color, font=font)
            # Add underline
            underline_y = y_pos + 10
            underline_start = width//2 - text_width//2 - 10
            underline_end = width//2 + text_width//2 + 10
            
            # Random wavy underline
            for x in range(int(underline_start), int(underline_end), 2):
                y = underline_y + random.randint(-2, 2)
                draw.line([(x, y), (x+2, y)], fill=text_color, width=2)
        else:
            # Slanted text
            draw.text((width//2 - 100, height//2 - 20), formatted_name, fill=text_color, font=font)
    else:
        # Draw a random signature-like curve
        curve_color = (0, 0, 0, 255)  # Black with full opacity
        points = []
        
        # Create a random starting point in the left third of the image
        x = random.randint(width // 6, width // 3)
        y = random.randint(height // 3, 2 * height // 3)
        
        # Add a series of connected points moving right
        points.append((x, y))
        
        # Number of segments in the signature
        num_segments = random.randint(5, 15)
        
        for _ in range(num_segments):
            # Move right with some random up/down movement
            x += random.randint(10, 40)
            y += random.randint(-20, 20)
            # Keep y within the image
            y = max(10, min(height - 10, y))
            # Keep x within the image
            x = min(width - 10, x)
            points.append((x, y))
        
        # Draw connected lines
        for i in range(len(points) - 1):
            draw.line([points[i], points[i+1]], fill=curve_color, width=random.randint(2, 4))
        
        # Add some random loops or flourishes
        if random.choice([True, False]):
            # Add a loop
            loop_center_x = random.randint(width // 3, 2 * width // 3)
            loop_center_y = random.randint(height // 3, 2 * height // 3)
            loop_width = random.randint(30, 70)
            loop_height = random.randint(20, 50)
            
            # Draw an ellipse
            draw.ellipse(
                [(loop_center_x - loop_width//2, loop_center_y - loop_height//2),
                 (loop_center_x + loop_width//2, loop_center_y + loop_height//2)],
                outline=curve_color, width=2
            )
    
    # Save the image
    image.save(output_path, 'PNG')
    logger.info(f"Created signature image: {output_path}")
    
    return output_path

Parameters

Name Type Default Kind
name - - positional_or_keyword
output_path - - positional_or_keyword
width - 400 positional_or_keyword
height - 150 positional_or_keyword
bg_color - (255, 255, 255, 0) positional_or_keyword

Parameter Details

name: String containing the person's name. If multiple words are provided, the function may format it as an initial and last name (e.g., 'John Doe' becomes 'J. Doe'). Required parameter.

output_path: String specifying the file path where the signature image will be saved. Must be a valid path with write permissions. The image is saved in PNG format. Required parameter.

width: Integer specifying the width of the signature image in pixels. Default is 400. Must be positive.

height: Integer specifying the height of the signature image in pixels. Default is 150. Must be positive.

bg_color: Tuple of 4 integers (RGBA) specifying the background color. Default is (255, 255, 255, 0) which creates a transparent white background. Values should be in range 0-255.

Return Value

Returns a string containing the path to the created signature image file (same as the output_path parameter). The file is saved as a PNG with RGBA color mode before returning.

Dependencies

  • PIL
  • os
  • logging
  • random

Required Imports

import os
import random
from PIL import Image, ImageDraw, ImageFont

Conditional/Optional Imports

These imports are only needed under specific conditions:

import logging

Condition: Required for logger.info() and logger.warning() calls within the function

Required (conditional)

Usage Example

import os
import logging
import random
from PIL import Image, ImageDraw, ImageFont

# Setup logger
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)

# Create signature image
name = "John Doe"
output_path = "signature.png"
signature_path = create_signature_image(
    name=name,
    output_path=output_path,
    width=400,
    height=150,
    bg_color=(255, 255, 255, 0)
)

print(f"Signature saved to: {signature_path}")

# Custom size with white background
signature_path = create_signature_image(
    name="Jane Smith",
    output_path="signature_custom.png",
    width=600,
    height=200,
    bg_color=(255, 255, 255, 255)
)

Best Practices

  • Ensure a logger object is configured before calling this function to avoid NameError
  • Verify that the output directory exists and has write permissions before calling
  • The function uses randomization, so signatures will vary between calls even with the same name
  • For production use, consider adding error handling around the image.save() call
  • The function attempts to find handwriting fonts on multiple platforms (Linux, Mac, Windows) but falls back to default font if none are found
  • The generated signatures are synthetic and should not be used for legal or authentication purposes
  • Consider setting a random seed if reproducible signatures are needed for testing

Similar Components

AI-powered semantic similarity - components with related functionality:

  • class SignatureGenerator 67.3% similar

    A class that generates signature-like images from text names using italic fonts and decorative flourishes.

    From: /tf/active/vicechatdev/document_auditor/src/utils/signature_generator.py
  • function main_v32 61.1% similar

    Generates sample signature images (PNG files) for a predefined list of names and saves them to a 'signatures' directory.

    From: /tf/active/vicechatdev/document_auditor/generate_sample_signatures.py
  • class SignatureImage 44.1% similar

    A ReportLab Flowable subclass for embedding signature images in PDFs with automatic fallback to placeholder text when images are unavailable or cannot be loaded.

    From: /tf/active/vicechatdev/CDocs/utils/pdf_utils.py
  • class SignatureImage_v1 43.7% similar

    A custom ReportLab Flowable class that renders signature images in PDF documents with automatic fallback to placeholder text when images are unavailable or cannot be loaded.

    From: /tf/active/vicechatdev/document_auditor/src/audit_page_generator.py
  • function add_watermark 42.1% similar

    A wrapper function that adds a customizable text watermark to every page of a PDF document with configurable opacity and color.

    From: /tf/active/vicechatdev/CDocs/utils/pdf_utils.py
← Back to Browse