class SignatureGenerator
A class that generates signature-like images from text names using italic fonts and decorative flourishes.
/tf/active/vicechatdev/document_auditor/src/utils/signature_generator.py
10 - 134
moderate
Purpose
The SignatureGenerator class creates realistic signature images from text input. It searches for available italic fonts on the system, renders the provided name in a signature-style font, and adds a flowing Bezier curve line beneath the text to simulate a handwritten signature. The generated images have transparent backgrounds and are saved as temporary PNG files. This is useful for creating signature placeholders, document signing interfaces, or personalized graphics.
Source Code
class SignatureGenerator:
"""Generate signature-like text images from names"""
def __init__(self):
# Try to find signature-style fonts
self.signature_fonts = []
self.font_paths = [
"/usr/share/fonts/truetype/dejavu/DejaVuSerif-Italic.ttf",
"/usr/share/fonts/truetype/liberation/LiberationSerif-Italic.ttf",
"/usr/share/fonts/truetype/liberation/LiberationSerif-BoldItalic.ttf",
"/usr/share/fonts/truetype/freefont/FreeSerifItalic.ttf",
"/usr/share/fonts/truetype/freefont/FreeSerifBoldItalic.ttf"
]
# Load available fonts
for font_path in self.font_paths:
if os.path.exists(font_path):
self.signature_fonts.append(font_path)
# Set default signature parameters
self.base_font_size = 32
self.line_variations = [(0, 0, 0, 5), (0, 5, 0, 0), (0, -2, 0, 2)] # Slight y-variations for characters
def generate_signature_image(self, name, width=300, height=120):
"""
Generate a signature-like image from a name
Args:
name (str): Name to convert to signature
width (int): Width in pixels
height (int): Height in pixels
Returns:
str: Path to temporary image file with signature
"""
try:
# Create a temporary file for the signature image
temp_file = tempfile.NamedTemporaryFile(suffix='.png', delete=False)
temp_path = temp_file.name
temp_file.close()
# Create transparent background image
img = Image.new('RGBA', (width, height), (255, 255, 255, 0))
draw = ImageDraw.Draw(img)
# Select a font - use random from available ones for variety
if self.signature_fonts:
font_path = random.choice(self.signature_fonts)
font_size = self.base_font_size
font = ImageFont.truetype(font_path, font_size)
else:
# Fall back to default font
font = None
font_size = 24
# Calculate text dimensions and position
if font:
try:
# For newer versions of PIL with textbbox
left, top, right, bottom = draw.textbbox((0, 0), name, font=font)
text_width = right - left
text_height = bottom - top
except AttributeError:
# Fallback for older PIL versions
text_width, text_height = draw.textsize(name, font=font)
else:
# Rough estimate for default font
text_width = len(name) * (font_size * 0.6)
text_height = font_size * 1.2
# Center horizontally, but place slightly above center vertically
x = (width - text_width) / 2
y = (height - text_height) / 2 - 10 # Slight upward adjustment
# Draw the signature text
if font:
draw.text((x, y), name, fill=(0, 0, 0, 255), font=font)
else:
draw.text((x, y), name, fill=(0, 0, 0, 255))
# Add a fluid signature line below the text
self._add_signature_line(draw, x, y, text_width, text_height)
# Save the image
img.save(temp_path, 'PNG')
return temp_path
except Exception as e:
logger.error(f"Error generating signature image: {e}")
return None
def _add_signature_line(self, draw, x, y, text_width, text_height):
"""Add a realistic flowing line below the signature text"""
# Start point is slightly below and to the right of text start
start_x = x + (text_width * 0.1)
start_y = y + text_height + 5
# End point is below and slightly beyond text end
end_x = x + text_width + (text_width * 0.1)
end_y = start_y + random.randint(-5, 5)
# Create control points for the bezier curve
control1_x = x + (text_width * 0.4)
control1_y = start_y + random.randint(5, 15)
control2_x = x + (text_width * 0.7)
control2_y = start_y + random.randint(-5, 5)
# Draw the line with slight thickness variation
line_width = random.uniform(1.5, 2.5)
# Create points for the bezier curve
points = []
steps = 50
for i in range(steps + 1):
t = i / steps
# Cubic Bezier formula
px = (1-t)**3 * start_x + 3*(1-t)**2*t * control1_x + 3*(1-t)*t**2 * control2_x + t**3 * end_x
py = (1-t)**3 * start_y + 3*(1-t)**2*t * control1_y + 3*(1-t)*t**2 * control2_y + t**3 * end_y
points.append((px, py))
# Draw the line
if len(points) > 1:
for i in range(len(points) - 1):
draw.line([points[i], points[i+1]], fill=(0, 0, 0, 255), width=int(line_width))
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
bases |
- | - |
Parameter Details
__init__: No parameters required. The constructor automatically searches for available signature-style fonts on the system and initializes default signature parameters.
generate_signature_image.name: The text string to render as a signature. Typically a person's name or initials.
generate_signature_image.width: The width of the output image in pixels. Default is 300. The signature will be centered within this width.
generate_signature_image.height: The height of the output image in pixels. Default is 120. The signature will be vertically centered (slightly above center) within this height.
_add_signature_line.draw: The PIL ImageDraw object used to draw on the image.
_add_signature_line.x: The x-coordinate of the text's left edge.
_add_signature_line.y: The y-coordinate of the text's top edge.
_add_signature_line.text_width: The width of the rendered text in pixels.
_add_signature_line.text_height: The height of the rendered text in pixels.
Return Value
The generate_signature_image method returns a string containing the file path to a temporary PNG file with the generated signature image. The image has a transparent background (RGBA mode) with black signature text and line. Returns None if an error occurs during generation. The _add_signature_line method is a private helper that returns None and modifies the draw object in place.
Class Interface
Methods
__init__(self) -> None
Purpose: Initializes the SignatureGenerator by searching for available signature-style fonts on the system and setting default parameters
Returns: None. Initializes instance attributes: signature_fonts (list of available font paths), font_paths (list of paths to search), base_font_size (default 32), and line_variations (list of y-coordinate variations for character positioning)
generate_signature_image(self, name: str, width: int = 300, height: int = 120) -> str | None
Purpose: Generates a signature-like image from the provided name text and saves it to a temporary PNG file
Parameters:
name: The text string to render as a signaturewidth: Width of the output image in pixels (default: 300)height: Height of the output image in pixels (default: 120)
Returns: String path to the temporary PNG file containing the signature image, or None if an error occurs. The image has a transparent background with black signature text and decorative line
_add_signature_line(self, draw: ImageDraw.Draw, x: float, y: float, text_width: float, text_height: float) -> None
Purpose: Private helper method that adds a flowing Bezier curve line below the signature text to simulate a handwritten flourish
Parameters:
draw: PIL ImageDraw object to draw onx: X-coordinate of the text's left edgey: Y-coordinate of the text's top edgetext_width: Width of the rendered text in pixelstext_height: Height of the rendered text in pixels
Returns: None. Modifies the draw object in place by adding a cubic Bezier curve line with randomized control points and thickness
Attributes
| Name | Type | Description | Scope |
|---|---|---|---|
signature_fonts |
list[str] | List of file paths to available signature-style italic fonts found on the system. Populated during __init__ by checking font_paths | instance |
font_paths |
list[str] | List of potential font file paths to search for signature-style fonts. Contains paths to DejaVu, Liberation, and FreeFont italic fonts in standard Linux locations | instance |
base_font_size |
int | Default font size in points for rendering signature text. Set to 32 by default | instance |
line_variations |
list[tuple[int, int, int, int]] | List of tuples representing slight y-coordinate variations for character positioning to create a more natural handwritten appearance. Currently defined but not actively used in the implementation | instance |
Dependencies
osiotempfileloggingPILrandom
Required Imports
import os
import io
import tempfile
import logging
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
import random
Usage Example
import os
import tempfile
import logging
from PIL import Image, ImageDraw, ImageFont
import random
# Setup logger
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
# Instantiate the signature generator
sig_gen = SignatureGenerator()
# Generate a signature image
signature_path = sig_gen.generate_signature_image(
name="John Doe",
width=400,
height=150
)
if signature_path:
print(f"Signature saved to: {signature_path}")
# Use the signature image
img = Image.open(signature_path)
img.show()
# Clean up when done
os.unlink(signature_path)
else:
print("Failed to generate signature")
Best Practices
- Always clean up temporary files: The generate_signature_image method creates temporary PNG files that are not automatically deleted. Use os.unlink() to remove them when done.
- Font availability: The class searches for fonts in Linux-specific paths. On other operating systems, modify the font_paths list in __init__ to include appropriate font directories.
- Logger configuration: Ensure a logger named 'logger' is configured before using this class, as error messages are logged via logger.error().
- Error handling: Always check if generate_signature_image returns None before using the result, as it returns None on errors.
- Thread safety: The class uses random.choice() and random.randint() which are thread-safe, but if you need deterministic output, seed the random number generator before use.
- Font fallback: If no signature fonts are found, the class falls back to PIL's default font, which may not look signature-like.
- Image dimensions: Ensure width and height parameters are large enough to accommodate the text. Very small dimensions may result in clipped signatures.
- Stateless usage: Each call to generate_signature_image is independent. The class maintains no state between calls except for the loaded font paths.
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function create_signature_image 67.3% similar
-
function main_v32 63.7% similar
-
class SignatureImage_v1 60.9% similar
-
class SignatureImage 59.8% similar
-
class SignatureManager 57.7% similar