anycoder-31930346 / index.html
Lee6x's picture
Upload folder using huggingface_hub
3795476 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>AI Image Editor - Text Prompt Magic</title>
<meta name="theme-color" content="#6366f1">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<link rel="manifest" href="data:application/json;base64,eyJuYW1lIjoiQUkgSW1hZ2UgRWRpdG9yIiwic2hvcnRfbmFtZSI6IkltYWdlRWRpdCIsInN0YXJ0X3VybCI6Ii8iLCJkaXNwbGF5Ijoic3RhbmRhbG9uZSIsImJhY2tncm91bmRfY29sb3IiOiIjMWUxYjI0IiwidGhlbWVfY29sb3IiOiIjNjM2NmYxIn0=">
<link rel="icon" type="image/png" sizes="192x192" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAYAAABS3GwHAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAHKSURBVHic7cExAQAAAMKg9U9tCF+gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOL/AP8gBMEBVEiBQwABmWWL6QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIDFPgAAFfEJdQAAAAASUVORK5CYII=">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--primary: #6366f1;
--primary-dark: #4f46e5;
--secondary: #ec4899;
--surface: #1e1b2e;
--surface-light: #2d2a3e;
--surface-lighter: #3a3652;
--text-primary: #ffffff;
--text-secondary: #a8a3b8;
--accent: #22d3ee;
--success: #10b981;
--warning: #f59e0b;
--error: #ef4444;
--gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
--gradient-2: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
background: linear-gradient(135deg, #0f0c29, #302b63, #24243e);
color: var(--text-primary);
min-height: 100vh;
overflow-x: hidden;
position: relative;
}
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background:
radial-gradient(circle at 20% 80%, rgba(99, 102, 241, 0.2) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(236, 72, 153, 0.2) 0%, transparent 50%),
radial-gradient(circle at 40% 40%, rgba(34, 211, 238, 0.1) 0%, transparent 50%);
pointer-events: none;
z-index: 1;
}
.app-container {
position: relative;
z-index: 2;
max-width: 100vw;
min-height: 100vh;
display: flex;
flex-direction: column;
}
.status-bar {
background: rgba(30, 27, 46, 0.95);
backdrop-filter: blur(20px);
padding: 0.5rem 1rem;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 0.85rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.status-bar-left {
display: flex;
align-items: center;
gap: 0.5rem;
}
.status-bar-right {
display: flex;
align-items: center;
gap: 0.5rem;
}
.main-header {
background: rgba(30, 27, 46, 0.9);
backdrop-filter: blur(20px);
padding: 1rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.header-content {
display: flex;
justify-content: space-between;
align-items: center;
max-width: 1200px;
margin: 0 auto;
}
.logo {
display: flex;
align-items: center;
gap: 0.75rem;
}
.logo-icon {
width: 40px;
height: 40px;
background: var(--gradient);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
}
.logo-text {
font-size: 1.25rem;
font-weight: 700;
background: var(--gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.main-content {
flex: 1;
padding: 1rem;
max-width: 1200px;
margin: 0 auto;
width: 100%;
}
.editor-workspace {
display: grid;
grid-template-columns: 1fr;
gap: 1rem;
margin-bottom: 1rem;
}
@media (min-width: 768px) {
.editor-workspace {
grid-template-columns: 2fr 1fr;
}
}
.canvas-section {
background: var(--surface-light);
border-radius: 20px;
padding: 1.5rem;
border: 1px solid rgba(255, 255, 255, 0.1);
min-height: 400px;
display: flex;
flex-direction: column;
}
.canvas-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.canvas-title {
font-size: 1.1rem;
font-weight: 600;
display: flex;
align-items: center;
gap: 0.5rem;
}
.canvas-actions {
display: flex;
gap: 0.5rem;
}
.icon-btn {
width: 36px;
height: 36px;
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.1);
background: rgba(255, 255, 255, 0.05);
color: var(--text-secondary);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s;
}
.icon-btn:hover {
background: rgba(255, 255, 255, 0.1);
color: var(--text-primary);
transform: translateY(-2px);
}
.canvas-container {
flex: 1;
background: rgba(0, 0, 0, 0.3);
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
min-height: 300px;
}
#imageCanvas {
max-width: 100%;
max-height: 100%;
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
}
.upload-prompt {
text-align: center;
color: var(--text-secondary);
}
.upload-icon {
font-size: 4rem;
margin-bottom: 1rem;
opacity: 0.5;
}
.prompt-section {
background: var(--surface-light);
border-radius: 20px;
padding: 1.5rem;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.prompt-header {
font-size: 1.1rem;
font-weight: 600;
margin-bottom: 1rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.prompt-input-group {
margin-bottom: 1rem;
}
.prompt-label {
display: block;
margin-bottom: 0.5rem;
color: var(--text-secondary);
font-size: 0.9rem;
}
.prompt-input {
width: 100%;
padding: 0.75rem;
background: rgba(255, 255, 255, 0.05);
border: 2px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
color: var(--text-primary);
font-size: 1rem;
transition: all 0.3s;
}
.prompt-input:focus {
outline: none;
border-color: var(--primary);
background: rgba(255, 255, 255, 0.08);
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
}
.prompt-suggestions {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 1rem;
}
.suggestion-chip {
padding: 0.5rem 1rem;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 20px;
font-size: 0.85rem;
cursor: pointer;
transition: all 0.3s;
}
.suggestion-chip:hover {
background: var(--primary);
border-color: var(--primary);
transform: translateY(-2px);
}
.action-btn {
width: 100%;
padding: 1rem;
background: var(--gradient);
border: none;
border-radius: 12px;
color: white;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
position: relative;
overflow: hidden;
}
.action-btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transition: left 0.5s;
}
.action-btn:hover::before {
left: 100%;
}
.action-btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(99, 102, 241, 0.3);
}
.action-btn:active {
transform: translateY(0);
}
.action-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.adjustments-section {
background: var(--surface-light);
border-radius: 20px;
padding: 1.5rem;
border: 1px solid rgba(255, 255, 255, 0.1);
margin-top: 1rem;
}
.adjustment-slider {
margin-bottom: 1.5rem;
}
.slider-header {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
}
.slider-label {
color: var(--text-secondary);
font-size: 0.9rem;
}
.slider-value {
color: var(--primary);
font-weight: 600;
}
.slider {
width: 100%;
height: 6px;
border-radius: 3px;
background: rgba(255, 255, 255, 0.1);
outline: none;
-webkit-appearance: none;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--primary);
cursor: pointer;
transition: all 0.3s;
}
.slider::-webkit-slider-thumb:hover {
transform: scale(1.2);
box-shadow: 0 0 10px rgba(99, 102, 241, 0.5);
}
.slider::-moz-range-thumb {
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--primary);
cursor: pointer;
transition: all 0.3s;
}
.bottom-nav {
background: rgba(30, 27, 46, 0.95);
backdrop-filter: blur(20px);
border-top: 1px solid rgba(255, 255, 255, 0.1);
display: flex;
justify-content: space-around;
padding: 0.5rem 0;
}
.nav-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 0.5rem 1rem;
color: var(--text-secondary);
cursor: pointer;
transition: all 0.3s;
border-radius: 12px;
}
.nav-item:hover {
color: var(--text-primary);
background: rgba(255, 255, 255, 0.05);
}
.nav-item.active {
color: var(--primary);
}
.nav-icon {
font-size: 1.5rem;
margin-bottom: 0.25rem;
}
.nav-label {
font-size: 0.75rem;
}
.hidden {
display: none !important;
}
.file-input {
display: none;
}
.loading-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
backdrop-filter: blur(5px);
}
.loading-content {
text-align: center;
}
.loading-spinner {
width: 60px;
height: 60px;
border: 4px solid rgba(255, 255, 255, 0.1);
border-top: 4px solid var(--primary);
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 1rem;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading-text {
color: var(--text-secondary);
}
.toast {
position: fixed;
bottom: 5rem;
left: 50%;
transform: translateX(-50%) translateY(100px);
background: var(--surface-light);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 12px;
padding: 1rem 1.5rem;
backdrop-filter: blur(10px);
transition: transform 0.3s;
z-index: 2000;
}
.toast.show {
transform: translateX(-50%) translateY(0);
}
.toast.success {
border-color: var(--success);
background: rgba(16, 185, 129, 0.1);
}
.toast.error {
border-color: var(--error);
background: rgba(239, 68, 68, 0.1);
}
.gallery-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 1rem;
padding: 1rem;
}
.gallery-item {
aspect-ratio: 1;
background: var(--surface-light);
border-radius: 12px;
overflow: hidden;
cursor: pointer;
transition: all 0.3s;
position: relative;
}
.gallery-item:hover {
transform: scale(1.05);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3);
}
.gallery-item img {
width: 100%;
height: 100%;
object-fit: cover;
}
.gallery-item-overlay {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);
padding: 0.5rem;
color: white;
font-size: 0.75rem;
}
.credit {
position: fixed;
bottom: 1rem;
left: 1rem;
font-size: 0.75rem;
color: var(--text-secondary);
z-index: 10;
}
.credit a {
color: var(--primary);
text-decoration: none;
}
.credit a:hover {
text-decoration: underline;
}
@media (max-width: 768px) {
.logo-text {
display: none;
}
.canvas-section {
padding: 1rem;
}
.prompt-section {
padding: 1rem;
}
.adjustments-section {
padding: 1rem;
}
}
</style>
</head>
<body>
<div class="app-container">
<!-- Status Bar -->
<div class="status-bar">
<div class="status-bar-left">
<span id="time">9:41 AM</span>
</div>
<div class="status-bar-right">
<span>📶</span>
<span>📶</span>
<span>🔋 100%</span>
</div>
</div>
<!-- Main Header -->
<header class="main-header">
<div class="header-content">
<div class="logo">
<div class="logo-icon">🎨</div>
<div class="logo-text">AI Image Editor</div>
</div>
<button class="icon-btn" onclick="showInfo()">
<span>ℹ️</span>
</button>
</div>
</header>
<!-- Main Content -->
<main class="main-content">
<!-- Editor Tab -->
<div id="editorTab" class="tab-content">
<div class="editor-workspace">
<!-- Canvas Section -->
<div class="canvas-section">
<div class="canvas-header">
<div class="canvas-title">
<span>📸</span>
<span>Canvas</span>
</div>
<div class="canvas-actions">
<button class="icon-btn" onclick="resetImage()">
<span>🔄</span>
</button>
<button class="icon-btn" onclick="saveImage()">
<span>💾</span>
</button>
</div>
</div>
<div class="canvas-container">
<div id="uploadPrompt" class="upload-prompt">
<div class="upload-icon">📷</div>
<p>Upload an image to start editing</p>
<button class="action-btn" style="margin-top: 1rem; max-width: 200px;" onclick="document.getElementById('fileInput').click()">
Choose Image
</button>
</div>
<canvas id="imageCanvas" class="hidden"></canvas>
</div>
</div>
<!-- Prompt Section -->
<div class="prompt-section">
<div class="prompt-header">
<span></span>
<span>AI Magic Prompt</span>
</div>
<div class="prompt-input-group">
<label class="prompt-label">Describe your edit:</label>
<input type="text" id="promptInput" class="prompt-input" placeholder="e.g., make it look like a painting...">
</div>
<div class="prompt-suggestions">
<div class="suggestion-chip" onclick="setPrompt('make it vintage')">🎞️ Vintage</div>
<div class="suggestion-chip" onclick="setPrompt('add neon lights')">💫 Neon</div>
<div class="suggestion-chip" onclick="setPrompt('cartoon style')">🎨 Cartoon</div>
<div class="suggestion-chip" onclick="setPrompt('cyberpunk')">🤖 Cyberpunk</div>
<div class="suggestion-chip" onclick="setPrompt('black and white')">⚫ B&W</div>
</div>
<button class="action-btn" id="applyBtn" onclick="applyPrompt()" disabled>
Apply Magic ✨
</button>
</div>
</div>
<!-- Adjustments Section -->
<div class="adjustments-section">
<div class="prompt-header">
<span>🎛️</span>
<span>Quick Adjustments</span>
</div>
<div class="adjustment-slider">
<div class="slider-header">
<span class="slider-label">Brightness</span>
<span class="slider-value" id="brightnessValue">100%</span>
</div>
<input type="range" class="slider" id="brightnessSlider" min="0" max="200" value="100" oninput="adjustImage()">
</div>
<div class="adjustment-slider">
<div class="slider-header">
<span class="slider-label">Contrast</span>
<span class="slider-value" id="contrastValue">100%</span>
</div>
<input type="range" class="slider" id="contrastSlider" min="0" max="200" value="100" oninput="adjustImage()">
</div>
<div class="adjustment-slider">
<div class="slider-header">
<span class="slider-label">Saturation</span>
<span class="slider-value" id="saturationValue">100%</span>
</div>
<input type="range" class="slider" id="saturationSlider" min="0" max="200" value="100" oninput="adjustImage()">
</div>
<div class="adjustment-slider">
<div class="slider-header">
<span class="slider-label">Blur</span>
<span class="slider-value" id="blurValue">0px</span>
</div>
<input type="range" class="slider" id="blurSlider" min="0" max="10" value="0" oninput="adjustImage()">
</div>
</div>
</div>
<!-- Gallery Tab -->
<div id="galleryTab" class="tab-content hidden">
<div class="gallery-grid" id="galleryGrid">
<!-- Gallery items will be added dynamically -->
</div>
</div>
</main>
<!-- Bottom Navigation -->
<nav class="bottom-nav">
<div class="nav-item active" onclick="switchTab('editor')">
<span class="nav-icon">🎨</span>
<span class="nav-label">Edit</span>
</div>
<div class="nav-item" onclick="switchTab('gallery')">
<span class="nav-icon">🖼️</span>
<span class="nav-label">Gallery</span>
</div>
<div class="nav-item" onclick="switchTab('templates')">
<span class="nav-icon">📋</span>
<span class="nav-label">Templates</span>
</div>
<div class="nav-item" onclick="switchTab('settings')">
<span class="nav-icon">⚙️</span>
<span class="nav-label">Settings</span>
</div>
</nav>
</div>
<!-- Hidden File Input -->
<input type="file" id="fileInput" class="file-input" accept="image/*" onchange="handleImageUpload(event)">
<!-- Loading Overlay -->
<div id="loadingOverlay" class="loading-overlay hidden">
<div class="loading-content">
<div class="loading-spinner"></div>
<div class="loading-text">Applying magic...</div>
</div>
</div>
<!-- Toast Notification -->
<div id="toast" class="toast"></div>
<!-- Credit -->
<div class="credit">
Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder">anycoder</a>
</div>
<script>
// Global variables
let currentImage = null;
let originalImageData = null;
let galleryImages = [];
// Initialize app
document.addEventListener('DOMContentLoaded', function() {
updateTime();
setInterval(updateTime, 60000);
loadGallery();
initializeCanvas();
});
// Update time in status bar
function updateTime() {
const now = new Date();
const time = now.toLocaleTimeString('en-US', {
hour: 'numeric',
minute: '2-digit',
hour12: true
});
document.getElementById('time').textContent = time;
}
// Initialize canvas
function initializeCanvas() {
const canvas = document.getElementById('imageCanvas');
const ctx = canvas.getContext('2d');
ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = 'high';
}
// Handle image upload
function handleImageUpload(event) {
const file = event.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(e) {
const img = new Image();
img.onload = function() {
currentImage = img;
displayImage(img);
document.getElementById('uploadPrompt').classList.add('hidden');
document.getElementById('imageCanvas').classList.remove('hidden');
document.getElementById('applyBtn').disabled = false;
showToast('Image loaded successfully!', 'success');
};
img.src = e.target.result;
};
reader.readAsDataURL(file);
}
// Display image on canvas
function displayImage(img) {
const canvas = document.getElementById('imageCanvas');
const container = canvas.parentElement;
const ctx = canvas.getContext('2d');
// Calculate size to fit container
const maxWidth = container.clientWidth - 40;
const maxHeight = container.clientHeight - 40;
let width = img.width;
let height = img.height;
if (width > maxWidth || height > maxHeight) {
const ratio = Math.min(maxWidth / width, maxHeight / height);
width *= ratio;
height *= ratio;
}
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0, width, height);
// Store original image data
originalImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
}
// Apply text prompt (simulated)
function applyPrompt() {
if (!currentImage) {
showToast('Please upload an image first', 'error');
return;
}
const prompt = document.getElementById('promptInput').value.trim();
if (!prompt) {
showToast('Please enter a prompt', 'error');
return;
}
showLoading(true);
// Simulate AI processing
setTimeout(() => {
applyFilter(prompt);
showLoading(false);
showToast('Magic applied successfully!', 'success');
}, 2000);
}
// Apply filter based on prompt
function applyFilter(prompt) {
const canvas = document.getElementById('imageCanvas');
const ctx = canvas.getContext('2d');
// Reset to original
ctx.putImageData(originalImageData, 0, 0);
const lowerPrompt = prompt.toLowerCase();
if (lowerPrompt.includes('vintage') || lowerPrompt.includes('old')) {
applyVintageFilter(ctx, canvas);
} else if (lowerPrompt.includes('neon') || lowerPrompt.includes('glow')) {
applyNeonFilter(ctx, canvas);
} else if (lowerPrompt.includes('cartoon') || lowerPrompt.includes('anime')) {
applyCartoonFilter(ctx, canvas);
} else if (lowerPrompt.includes('cyberpunk')) {
applyCyberpunkFilter(ctx, canvas);
} else if (lowerPrompt.includes('black and white') || lowerPrompt.includes('bw')) {
applyBlackWhiteFilter(ctx, canvas);
} else {
// Apply random filter
const filters = [applyVintageFilter, applyNeonFilter, applyCartoonFilter, applyCyberpunkFilter];
filters[Math.floor(Math.random() * filters.length)](ctx, canvas);
}
}
// Filter implementations
function applyVintageFilter(ctx, canvas) {
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
data[i] = Math.min(255, data[i] * 1.2); // Red
data[i + 1] = Math.min(255, data[i + 1] * 0.8); // Green
data[i + 2] = Math.min(255, data[i + 2] * 0.5); // Blue
}
ctx.putImageData(imageData, 0, 0);
ctx.globalCompositeOperation = 'overlay';
ctx.fillStyle = 'rgba(139, 69, 19, 0.1)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = 'source-over';
}
function applyNeonFilter(ctx, canvas) {
ctx.filter = 'contrast(2) saturate(2) brightness(1.2)';
ctx.drawImage(canvas, 0, 0);
ctx.filter = 'none';
// Add glow effect
ctx.shadowBlur = 20;
ctx.shadowColor = '#00ffff';
ctx.globalCompositeOperation = 'screen';
ctx.drawImage(canvas, 0, 0);
ctx.globalCompositeOperation = 'source-over';
ctx.shadowBlur = 0;
}
function applyCartoonFilter(ctx, canvas) {
ctx.filter = 'contrast(1.5) saturate(1.5)';
ctx.drawImage(canvas, 0, 0);
// Simplify colors
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
data[i] = Math.round(data[i] / 50) * 50;
data[i + 1] = Math.round(data[i + 1] / 50) * 50;
data[i + 2] = Math.round(data[i + 2] / 50) * 50;
}
ctx.putImageData(imageData, 0, 0);
ctx.filter = 'none';
}
function applyCyberpunkFilter(ctx, canvas) {
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
data[i] = data[i] * 0.5; // Reduce red
data[i + 1] = data[i + 1] * 0.3; // Reduce green
data[i + 2] = data[i + 2] * 1.5; // Enhance blue
}
ctx.putImageData(imageData, 0, 0);
// Add scan lines
ctx.strokeStyle = 'rgba(0, 255, 255, 0.1)';
ctx.lineWidth = 1;
for (let y = 0; y < canvas.height; y += 4) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(canvas.width, y);
ctx.stroke();
}
}
function applyBlackWhiteFilter(ctx, canvas) {
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
const gray = data[i] * 0.299 + data[i + 1] * 0.587 + data[i + 2] * 0.114;
data[i] = gray;
data[i + 1] = gray;
data[i + 2] = gray;
}
ctx.putImageData(imageData, 0, 0);
}
// Adjust image with sliders
function adjustImage() {
if (!currentImage) return;
const brightness = document.getElementById('brightnessSlider').value;
const contrast = document.getElementById('contrastSlider').value;
const saturation = document.getElementById('saturationSlider').value;
const blur = document.getElementById('blurSlider').value;
document.getElementById('brightnessValue').textContent = brightness + '%';
document.getElementById('contrastValue').textContent = contrast + '%';
document.getElementById('saturationValue').textContent = saturation + '%';
document.getElementById('blurValue').textContent = blur + 'px';
const canvas = document.getElementById('imageCanvas');
const ctx = canvas.getContext('2d');
// Reset to original
ctx.putImageData(originalImageData, 0, 0);
// Apply filters
ctx.filter = `brightness(${brightness}%) contrast(${contrast}%) saturate(${saturation}%) blur(${blur}px)`;
ctx.drawImage(canvas, 0, 0);
ctx.filter = 'none';
}
// Reset image
function resetImage() {
if (!currentImage) return;
const canvas = document.getElementById('imageCanvas');
const ctx = canvas.getContext('2d');
ctx.putImageData(originalImageData, 0, 0);
// Reset sliders
document.getElementById('brightnessSlider').value = 100;
document.getElementById('contrastSlider').value = 100;