diff --git a/Generator.md b/Generator.md new file mode 100644 index 0000000..cef2bf1 --- /dev/null +++ b/Generator.md @@ -0,0 +1,115 @@ +# SillyBubble Image Generator - Design Document + +## Component Architecture + +The SillyBubble image generator creates comic-style chat visualizations with a modular component system. The final image has a 5:1 width-to-height ratio, composed of layered elements. + +### Core Components + +1. **Background Layer** + - Full 5:1 ratio base image for setting style/mood + - Can be themed (e.g., fantasy, sci-fi, cozy, etc.) + - Provides consistent canvas for all other elements + +2. **Character Layer (Chibi)** + - Positioned on the left side of the image + - Various character images with different expressions/poses + - Takes approximately 20% of the total width + - Named by character (e.g., "bianca.png", "ruby.png") + +3. **Bubble Layer** + - Semi-transparent speech bubble + - Positioned to the right of the character + - Includes a pointer/tail connecting to the character + - Takes approximately 70% of the total width + - Various styles (rounded, square, cloud, thought, etc.) + +4. **Text Layer** + - Dynamically rendered text content + - Positioned within the bubble boundaries + - Supports word-wrapping and styling + - Font options compatible with the overall theme + +## Implementation Approach + +### File Structure and Naming Convention +``` +/characters/ - Main directory for all characters + /Example/ - Example character (fallback) + background.png - Background image + character.png - Character image + speech.png - Speech bubble + thought.png - Thought bubble + /Bianca/ - Another character + background.png - Background image + character.png - Character image + speech.png - Speech bubble + thought.png - Thought bubble +/fonts/*.ttf - Font files +``` + +Each character has their own directory containing all assets. If a specific character's asset is missing, the system will fall back to the Example character's corresponding asset. + +### Image Dimensions +- Total Image: 2000×400px (5:1 ratio) +- Background: Full 2000×400px canvas +- Character: ~400×400px (20% of width) +- Bubble: ~1400×300px (70% of width) +- Text Area: ~1300×250px (inside bubble) +- Remaining 10% (200px width) for margins and spacing + +### Parameter System +The enhanced image.php will accept: +- `q`: Text content (required) +- `character`: Character to use (e.g., "bianca") - if not provided, defaults to "Example" +- `bubble_type`: "speech" or "thought" (defaults to "speech") +- `style`: Legacy parameter, can be used instead of character parameter + +**Backward Compatibility**: +- If only `style` is provided (no `character`), the script will use the style value as the character name +- This ensures the SillyTavern extension doesn't need modification + +### Image Composition Process +1. Load or create background layer (full canvas) +2. Check if character exists and overlay on left side +3. Position and overlay appropriate bubble template +4. Calculate text boundaries within bubble +5. Render text with proper wrapping and styling +6. Output final composed image + +### Dynamic Bubble Generation +- If no bubble template exists, dynamically draw a bubble +- Support both template-based and on-the-fly bubble generation +- Ensure proper connection between character and bubble + +## Visual Representation + +``` +FINAL COMPOSITION (5:1 ratio): ++--------------------------------------------------------------------------------------+ +| | +| +--------+ +--------------------------------------------------------------+ | +| | | | | | +| | CHIBI |<---+ TEXT CONTENT | | +| | | | | | +| +--------+ +--------------------------------------------------------------+ | +| | ++--------------------------------------------------------------------------------------+ +``` + +## Feature Roadmap + +1. **Basic Implementation** + - Support for character-based styling + - Simple bubble positioning + - Proper text wrapping + +2. **Enhanced Features** + - Multiple character positions (left/right) + - Various bubble styles + - Expression selection for characters + +3. **Advanced Features** + - Multiple characters in one image + - Animated GIF output option + - Theme-based text styling \ No newline at end of file diff --git a/characters/Example/background.png b/characters/Example/background.png new file mode 100644 index 0000000..eb8fc06 Binary files /dev/null and b/characters/Example/background.png differ diff --git a/characters/Example/character.png b/characters/Example/character.png new file mode 100644 index 0000000..275f536 Binary files /dev/null and b/characters/Example/character.png differ diff --git a/characters/Example/speech.png b/characters/Example/speech.png new file mode 100644 index 0000000..da88c17 Binary files /dev/null and b/characters/Example/speech.png differ diff --git a/characters/Example/thought.png b/characters/Example/thought.png new file mode 100644 index 0000000..b82e343 Binary files /dev/null and b/characters/Example/thought.png differ diff --git a/image.php b/image.php index 5a5cdf4..aeebeca 100644 --- a/image.php +++ b/image.php @@ -2,12 +2,14 @@ /** * SillyBubble Image Generator * - * This script generates chat bubble images from text. - * It takes a 'q' parameter for the text content and an optional 'style' parameter. + * This script generates comic-style chat bubble images with characters. + * It supports character-based styling with speech or thought bubbles. * * Usage: * image.php?q=Hello+World - * image.php?q=Hello+World&style=modern + * image.php?q=Hello+World&character=Example + * image.php?q=Hello+World&character=Example&bubble_type=thought + * image.php?q=Hello+World&style=Example (legacy style parameter maps to character) */ // Set content type to PNG image @@ -15,97 +17,301 @@ header('Content-Type: image/png'); // Get parameters $text = isset($_GET['q']) ? urldecode($_GET['q']) : 'No text provided'; +$character = isset($_GET['character']) ? $_GET['character'] : 'Example'; +$bubble_type = isset($_GET['bubble_type']) ? $_GET['bubble_type'] : 'speech'; $style = isset($_GET['style']) ? $_GET['style'] : 'default'; -// Define styles +// If style parameter is used but no character is specified, use style as character name +if (!isset($_GET['character']) && isset($_GET['style']) && $style != 'default') { + $character = $style; +} + +// Validate bubble_type - only 'speech' or 'thought' allowed +if ($bubble_type != 'speech' && $bubble_type != 'thought') { + $bubble_type = 'speech'; +} + +// Define canvas dimensions (5:1 ratio) +$canvasWidth = 2000; +$canvasHeight = 400; +$charWidth = 400; // 20% of canvas width +$bubbleWidth = 1400; // 70% of canvas width +$bubbleMargin = 100; // 5% margin on each side +$bubblePadding = 50; // Padding inside the bubble + +// Define legacy styles for backward compatibility $styles = [ 'default' => [ 'bg_color' => [245, 245, 245], 'text_color' => [50, 50, 50], 'border_color' => [200, 200, 200], - 'padding' => 20, - 'rounded' => 15, - 'font_size' => 14, - 'max_width' => 600, - 'line_height' => 20, - 'font' => __DIR__ . '/fonts/arial.ttf', // Adjust path as needed + 'font_size' => 24, // Increased for higher resolution + 'line_height' => 30, + 'font' => __DIR__ . '/fonts/NotoSans-Regular.ttf', ], 'modern' => [ 'bg_color' => [66, 133, 244], 'text_color' => [255, 255, 255], 'border_color' => [59, 120, 220], - 'padding' => 20, - 'rounded' => 20, - 'font_size' => 14, - 'max_width' => 600, - 'line_height' => 20, - 'font' => __DIR__ . '/fonts/arial.ttf', // Adjust path as needed + 'font_size' => 24, + 'line_height' => 30, + 'font' => __DIR__ . '/fonts/NotoSans-Regular.ttf', ], 'retro' => [ 'bg_color' => [255, 204, 102], 'text_color' => [51, 51, 51], 'border_color' => [204, 153, 0], - 'padding' => 20, - 'rounded' => 5, - 'font_size' => 14, - 'max_width' => 600, - 'line_height' => 20, - 'font' => __DIR__ . '/fonts/arial.ttf', // Adjust path as needed + 'font_size' => 24, + 'line_height' => 30, + 'font' => __DIR__ . '/fonts/NotoSans-Regular.ttf', ], 'minimal' => [ 'bg_color' => [255, 255, 255], 'text_color' => [0, 0, 0], 'border_color' => [220, 220, 220], - 'padding' => 15, - 'rounded' => 0, - 'font_size' => 14, - 'max_width' => 600, - 'line_height' => 20, - 'font' => __DIR__ . '/fonts/arial.ttf', // Adjust path as needed + 'font_size' => 24, + 'line_height' => 30, + 'font' => __DIR__ . '/fonts/NotoSans-Regular.ttf', ], ]; -// Use default style if specified style doesn't exist -if (!isset($styles[$style])) { - $style = 'default'; -} +// Set default styling +$config = [ + 'bg_color' => [245, 245, 245], + 'text_color' => [50, 50, 50], + 'border_color' => [200, 200, 200], + 'font_size' => 24, + 'line_height' => 30, + 'font' => __DIR__ . '/fonts/NotoSans-Regular.ttf', +]; -// Get style settings -$config = $styles[$style]; +// Ensure required directories exist +$dirs = [ + __DIR__ . '/characters/Example', + __DIR__ . '/fonts' +]; -// Check for fonts directory and create if it doesn't exist -$fontsDir = __DIR__ . '/fonts'; -if (!is_dir($fontsDir)) { - mkdir($fontsDir, 0755, true); +foreach ($dirs as $dir) { + if (!is_dir($dir)) { + mkdir($dir, 0755, true); + } } // Fallback to a built-in font if the specified font file doesn't exist if (!file_exists($config['font'])) { // Try to find any TTF font in the fonts directory - $foundFont = false; - if (is_dir($fontsDir)) { - $fontFiles = glob($fontsDir . '/*.ttf'); - if (!empty($fontFiles)) { - $config['font'] = $fontFiles[0]; - $foundFont = true; - } - } - - // If no TTF font found, use built-in font - if (!$foundFont) { + $fontFiles = glob(__DIR__ . '/fonts/*.ttf'); + if (!empty($fontFiles)) { + $config['font'] = $fontFiles[0]; + } else { $config['use_builtin_font'] = true; } } -// Create a temporary image to calculate text dimensions -$tempImage = imagecreatetruecolor(100, 100); -$textColor = imagecolorallocate($tempImage, $config['text_color'][0], $config['text_color'][1], $config['text_color'][2]); +// Create the canvas +$canvas = imagecreatetruecolor($canvasWidth, $canvasHeight); + +// Set default white background +$whiteColor = imagecolorallocate($canvas, 255, 255, 255); +imagefill($canvas, 0, 0, $whiteColor); + +// Set text color +$textColor = imagecolorallocate($canvas, $config['text_color'][0], $config['text_color'][1], $config['text_color'][2]); + +// Function to get image path with fallback to Example +function getAssetPath($assetType, $character) { + // Primary path in character's directory + $primaryPath = __DIR__ . '/characters/' . $character . '/' . $assetType . '.png'; + + // Fallback to Example character + $fallbackPath = __DIR__ . '/characters/Example/' . $assetType . '.png'; + + return file_exists($primaryPath) ? $primaryPath : $fallbackPath; +} + +// Check for and load the background image +$backgroundPath = getAssetPath('background', $character); +$backgroundLoaded = false; + +if (file_exists($backgroundPath)) { + $backgroundImage = imagecreatefrompng($backgroundPath); + if ($backgroundImage) { + // Resize if needed + $bgWidth = imagesx($backgroundImage); + $bgHeight = imagesy($backgroundImage); + + // Copy background to canvas, resizing if necessary + imagecopyresampled($canvas, $backgroundImage, 0, 0, 0, 0, $canvasWidth, $canvasHeight, $bgWidth, $bgHeight); + imagedestroy($backgroundImage); + $backgroundLoaded = true; + } +} + +// If no background was loaded, use a solid color background +if (!$backgroundLoaded) { + // Use legacy style background color if it exists + if (isset($styles[$style])) { + $bgColor = imagecolorallocate($canvas, + $styles[$style]['bg_color'][0], + $styles[$style]['bg_color'][1], + $styles[$style]['bg_color'][2] + ); + } else { + $bgColor = imagecolorallocate($canvas, 245, 245, 245); // Default light gray + } + imagefilledrectangle($canvas, 0, 0, $canvasWidth-1, $canvasHeight-1, $bgColor); +} + +// Check for and load the character image +$characterPath = getAssetPath('character', $character); +$characterLoaded = false; + +if (file_exists($characterPath)) { + $characterImage = imagecreatefrompng($characterPath); + if ($characterImage) { + // Enable alpha blending + imagesavealpha($characterImage, true); + + // Calculate position (center vertically, align left) + $charWidth = imagesx($characterImage); + $charHeight = imagesy($characterImage); + $charX = $bubbleMargin; + $charY = ($canvasHeight - $charHeight) / 2; + + // Copy character to canvas + imagecopy($canvas, $characterImage, $charX, $charY, 0, 0, $charWidth, $charHeight); + imagedestroy($characterImage); + $characterLoaded = true; + } +} + +// Check for and load the bubble image +$bubblePath = getAssetPath($bubble_type, $character); +$bubbleLoaded = false; + +if (file_exists($bubblePath)) { + $bubbleImage = imagecreatefrompng($bubblePath); + if ($bubbleImage) { + // Enable alpha blending + imagesavealpha($bubbleImage, true); + + // Calculate position (center vertically, align right of character) + $bubbleWidth = imagesx($bubbleImage); + $bubbleHeight = imagesy($bubbleImage); + $bubbleX = $charWidth + $bubbleMargin * 2; + $bubbleY = ($canvasHeight - $bubbleHeight) / 2; + + // Copy bubble to canvas + imagecopy($canvas, $bubbleImage, $bubbleX, $bubbleY, 0, 0, $bubbleWidth, $bubbleHeight); + imagedestroy($bubbleImage); + $bubbleLoaded = true; + } +} + +// If no bubble was loaded, draw a simple bubble +if (!$bubbleLoaded) { + // Calculate bubble dimensions and position + $bubbleX = $charWidth + $bubbleMargin * 2; + $bubbleY = $canvasHeight * 0.1; + $bubbleWidth = $canvasWidth - $bubbleX - $bubbleMargin; + $bubbleHeight = $canvasHeight * 0.8; + + // Determine bubble style based on legacy styles if available + if (isset($styles[$style])) { + $bubbleBgColor = imagecolorallocate($canvas, + $styles[$style]['bg_color'][0], + $styles[$style]['bg_color'][1], + $styles[$style]['bg_color'][2] + ); + $bubbleBorderColor = imagecolorallocate($canvas, + $styles[$style]['border_color'][0], + $styles[$style]['border_color'][1], + $styles[$style]['border_color'][2] + ); + } else { + $bubbleBgColor = imagecolorallocate($canvas, 245, 245, 245); // Default light gray + $bubbleBorderColor = imagecolorallocate($canvas, 200, 200, 200); // Default gray border + } + + // Draw bubble based on type + if ($bubble_type == 'thought') { + // Draw a thought bubble (rounded rectangle with smaller circles) + $radius = 40; + + // Main bubble + imagefilledrectangle($canvas, $bubbleX + $radius, $bubbleY, $bubbleX + $bubbleWidth - $radius, $bubbleY + $bubbleHeight, $bubbleBgColor); + imagefilledrectangle($canvas, $bubbleX, $bubbleY + $radius, $bubbleX + $bubbleWidth, $bubbleY + $bubbleHeight - $radius, $bubbleBgColor); + + // Corners + imagefilledarc($canvas, $bubbleX + $radius, $bubbleY + $radius, $radius * 2, $radius * 2, 180, 270, $bubbleBgColor, IMG_ARC_PIE); + imagefilledarc($canvas, $bubbleX + $bubbleWidth - $radius, $bubbleY + $radius, $radius * 2, $radius * 2, 270, 360, $bubbleBgColor, IMG_ARC_PIE); + imagefilledarc($canvas, $bubbleX + $radius, $bubbleY + $bubbleHeight - $radius, $radius * 2, $radius * 2, 90, 180, $bubbleBgColor, IMG_ARC_PIE); + imagefilledarc($canvas, $bubbleX + $bubbleWidth - $radius, $bubbleY + $bubbleHeight - $radius, $radius * 2, $radius * 2, 0, 90, $bubbleBgColor, IMG_ARC_PIE); + + // Draw small circles leading to character + $circleCount = 3; + $startX = $bubbleX - 20; + $startY = $bubbleY + $bubbleHeight/2 + 20; + + for ($i = 0; $i < $circleCount; $i++) { + $circleRadius = 15 - ($i * 4); + $circleX = $startX - ($i * 30); + $circleY = $startY + ($i * 20); + imagefilledellipse($canvas, $circleX, $circleY, $circleRadius*2, $circleRadius*2, $bubbleBgColor); + imageellipse($canvas, $circleX, $circleY, $circleRadius*2, $circleRadius*2, $bubbleBorderColor); + } + + // Border + imagerectangle($canvas, $bubbleX + $radius, $bubbleY, $bubbleX + $bubbleWidth - $radius, $bubbleY + $bubbleHeight, $bubbleBorderColor); + imagerectangle($canvas, $bubbleX, $bubbleY + $radius, $bubbleX + $bubbleWidth, $bubbleY + $bubbleHeight - $radius, $bubbleBorderColor); + imagearc($canvas, $bubbleX + $radius, $bubbleY + $radius, $radius * 2, $radius * 2, 180, 270, $bubbleBorderColor); + imagearc($canvas, $bubbleX + $bubbleWidth - $radius, $bubbleY + $radius, $radius * 2, $radius * 2, 270, 360, $bubbleBorderColor); + imagearc($canvas, $bubbleX + $radius, $bubbleY + $bubbleHeight - $radius, $radius * 2, $radius * 2, 90, 180, $bubbleBorderColor); + imagearc($canvas, $bubbleX + $bubbleWidth - $radius, $bubbleY + $bubbleHeight - $radius, $radius * 2, $radius * 2, 0, 90, $bubbleBorderColor); + + } else { + // Draw a speech bubble (rounded rectangle with a pointer) + $radius = 40; + + // Main bubble + imagefilledrectangle($canvas, $bubbleX + $radius, $bubbleY, $bubbleX + $bubbleWidth - $radius, $bubbleY + $bubbleHeight, $bubbleBgColor); + imagefilledrectangle($canvas, $bubbleX, $bubbleY + $radius, $bubbleX + $bubbleWidth, $bubbleY + $bubbleHeight - $radius, $bubbleBgColor); + + // Corners + imagefilledarc($canvas, $bubbleX + $radius, $bubbleY + $radius, $radius * 2, $radius * 2, 180, 270, $bubbleBgColor, IMG_ARC_PIE); + imagefilledarc($canvas, $bubbleX + $bubbleWidth - $radius, $bubbleY + $radius, $radius * 2, $radius * 2, 270, 360, $bubbleBgColor, IMG_ARC_PIE); + imagefilledarc($canvas, $bubbleX + $radius, $bubbleY + $bubbleHeight - $radius, $radius * 2, $radius * 2, 90, 180, $bubbleBgColor, IMG_ARC_PIE); + imagefilledarc($canvas, $bubbleX + $bubbleWidth - $radius, $bubbleY + $bubbleHeight - $radius, $radius * 2, $radius * 2, 0, 90, $bubbleBgColor, IMG_ARC_PIE); + + // Draw pointer + $pointerX = [$bubbleX, $bubbleX - 40, $bubbleX]; + $pointerY = [$bubbleY + $bubbleHeight/2 - 40, $bubbleY + $bubbleHeight/2, $bubbleY + $bubbleHeight/2 + 40]; + imagefilledpolygon($canvas, $pointerX, $pointerY, 3, $bubbleBgColor); + + // Border + imagerectangle($canvas, $bubbleX + $radius, $bubbleY, $bubbleX + $bubbleWidth - $radius, $bubbleY + $bubbleHeight, $bubbleBorderColor); + imagerectangle($canvas, $bubbleX, $bubbleY + $radius, $bubbleX + $bubbleWidth, $bubbleY + $bubbleHeight - $radius, $bubbleBorderColor); + imagearc($canvas, $bubbleX + $radius, $bubbleY + $radius, $radius * 2, $radius * 2, 180, 270, $bubbleBorderColor); + imagearc($canvas, $bubbleX + $bubbleWidth - $radius, $bubbleY + $radius, $radius * 2, $radius * 2, 270, 360, $bubbleBorderColor); + imagearc($canvas, $bubbleX + $radius, $bubbleY + $bubbleHeight - $radius, $radius * 2, $radius * 2, 90, 180, $bubbleBorderColor); + imagearc($canvas, $bubbleX + $bubbleWidth - $radius, $bubbleY + $bubbleHeight - $radius, $radius * 2, $radius * 2, 0, 90, $bubbleBorderColor); + + // Pointer border + imagepolygon($canvas, $pointerX, $pointerY, 3, $bubbleBorderColor); + } +} + +// Set text area dimensions +$textAreaX = $bubbleX + $bubblePadding; +$textAreaY = $bubbleY + $bubblePadding; +$textAreaWidth = $bubbleWidth - ($bubblePadding * 2); +$textAreaHeight = $bubbleHeight - ($bubblePadding * 2); // Word wrap the text $words = explode(' ', $text); $lines = []; $currentLine = ''; -$maxWidth = $config['max_width'] - (2 * $config['padding']); +$maxWidth = $textAreaWidth; foreach ($words as $word) { $testLine = $currentLine . ' ' . $word; @@ -130,92 +336,22 @@ if ($currentLine !== '') { $lines[] = $currentLine; } -// Calculate image dimensions -$lineCount = count($lines); -if (isset($config['use_builtin_font'])) { - $lineHeight = imagefontheight(5); - $textHeight = $lineHeight * $lineCount; - - // Find the longest line to determine width - $textWidth = 0; - foreach ($lines as $line) { - $lineWidth = imagefontwidth(5) * strlen($line); - $textWidth = max($textWidth, $lineWidth); - } -} else { - $lineHeight = $config['line_height']; - $textHeight = $lineHeight * $lineCount; - - // Find the longest line to determine width - $textWidth = 0; - foreach ($lines as $line) { - $bbox = imagettfbbox($config['font_size'], 0, $config['font'], $line); - $lineWidth = $bbox[2] - $bbox[0]; - $textWidth = max($textWidth, $lineWidth); - } -} - -// Add padding to dimensions -$imgWidth = min($config['max_width'], $textWidth + (2 * $config['padding'])); -$imgHeight = $textHeight + (2 * $config['padding']); - -// Create the bubble image -$image = imagecreatetruecolor($imgWidth, $imgHeight); - -// Allocate colors -$bgColor = imagecolorallocate($image, $config['bg_color'][0], $config['bg_color'][1], $config['bg_color'][2]); -$borderColor = imagecolorallocate($image, $config['border_color'][0], $config['border_color'][1], $config['border_color'][2]); -$textColor = imagecolorallocate($image, $config['text_color'][0], $config['text_color'][1], $config['text_color'][2]); - -// Fill background -imagefill($image, 0, 0, $bgColor); - -// Draw rounded rectangle (if rounded corners are requested) -if ($config['rounded'] > 0) { - // Draw filled rectangle - imagefilledrectangle($image, 0, 0, $imgWidth - 1, $imgHeight - 1, $bgColor); - - // Draw rounded corners - basic simulation for rounded corners - // This could be improved with proper arc drawing - $r = $config['rounded']; - - // Top left corner - imagefilledarc($image, $r, $r, $r * 2, $r * 2, 180, 270, $bgColor, IMG_ARC_PIE); - - // Top right corner - imagefilledarc($image, $imgWidth - $r - 1, $r, $r * 2, $r * 2, 270, 360, $bgColor, IMG_ARC_PIE); - - // Bottom left corner - imagefilledarc($image, $r, $imgHeight - $r - 1, $r * 2, $r * 2, 90, 180, $bgColor, IMG_ARC_PIE); - - // Bottom right corner - imagefilledarc($image, $imgWidth - $r - 1, $imgHeight - $r - 1, $r * 2, $r * 2, 0, 90, $bgColor, IMG_ARC_PIE); - - // Draw border - imagerectangle($image, 0, 0, $imgWidth - 1, $imgHeight - 1, $borderColor); -} else { - // Draw simple rectangle - imagefilledrectangle($image, 0, 0, $imgWidth - 1, $imgHeight - 1, $bgColor); - imagerectangle($image, 0, 0, $imgWidth - 1, $imgHeight - 1, $borderColor); -} - // Draw text -$y = $config['padding']; +$y = $textAreaY + $config['font_size']; // Start position for text foreach ($lines as $line) { if (isset($config['use_builtin_font'])) { // Use built-in font (less nice but always available) - imagestring($image, 5, $config['padding'], $y, $line, $textColor); + imagestring($canvas, 5, $textAreaX, $y, $line, $textColor); $y += imagefontheight(5); } else { // Use TrueType font (nicer but requires font file) - imagettftext($image, $config['font_size'], 0, $config['padding'], $y + $config['font_size'], $textColor, $config['font'], $line); - $y += $lineHeight; + imagettftext($canvas, $config['font_size'], 0, $textAreaX, $y, $textColor, $config['font'], $line); + $y += $config['line_height']; } } // Output the image -imagepng($image); +imagepng($canvas); // Clean up -imagedestroy($image); -imagedestroy($tempImage); \ No newline at end of file +imagedestroy($canvas); \ No newline at end of file