testing / index.html
Buck3tHead's picture
Add 2 files
a354a98 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Photo Visual Enhancer Pro</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary-color: #4361ee;
--secondary-color: #3a0ca3;
--accent-color: #f72585;
--light-color: #f8f9fa;
--dark-color: #212529;
--success-color: #2ecc71;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background-color: #f0f2f5;
color: var(--dark-color);
line-height: 1.6;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
header {
text-align: center;
margin-bottom: 30px;
padding: 20px 0;
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
color: white;
border-radius: 10px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
}
h1 {
font-size: 2.5rem;
margin-bottom: 10px;
}
.description {
font-size: 1.1rem;
opacity: 0.9;
}
.app-container {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.image-section {
flex: 3;
min-width: 300px;
background-color: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.08);
}
.controls-section {
flex: 2;
min-width: 300px;
background-color: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.08);
}
.image-container {
width: 100%;
aspect-ratio: 1;
margin-bottom: 20px;
position: relative;
border: 2px dashed #ddd;
border-radius: 8px;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
}
#uploaded-image {
max-width: 100%;
max-height: 100%;
display: none;
object-fit: contain;
}
.upload-area {
text-align: center;
padding: 40px 20px;
cursor: pointer;
}
.upload-icon {
font-size: 3rem;
color: var(--primary-color);
margin-bottom: 15px;
}
.upload-text {
font-size: 1.2rem;
color: #666;
}
.btn {
display: inline-block;
padding: 10px 20px;
background-color: var(--primary-color);
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 1rem;
transition: all 0.3s ease;
margin-right: 10px;
margin-bottom: 10px;
}
.btn:hover {
background-color: var(--secondary-color);
transform: translateY(-2px);
}
.btn-secondary {
background-color: #6c757d;
}
.btn-secondary:hover {
background-color: #5a6268;
}
.btn-accent {
background-color: var(--accent-color);
}
.btn-accent:hover {
background-color: #c91867;
}
.btn-group {
margin-bottom: 20px;
}
.control-group {
margin-bottom: 25px;
}
.control-title {
font-weight: 600;
margin-bottom: 10px;
display: flex;
align-items: center;
}
.control-title i {
margin-right: 10px;
color: var(--primary-color);
}
.filter-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
gap: 10px;
}
.filter-btn {
background-color: white;
border: 1px solid #ddd;
border-radius: 5px;
padding: 10px;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
}
.filter-btn:hover {
background-color: #f0f8ff;
transform: translateY(-2px);
border-color: var(--primary-color);
}
.filter-preview {
width: 80px;
height: 80px;
margin: 0 auto 5px;
border-radius: 5px;
overflow: hidden;
}
.filter-name {
font-size: 0.9rem;
}
.slider-group {
margin-top: 15px;
}
.slider-label {
display: flex;
justify-content: space-between;
margin-bottom: 5px;
}
.slider-container {
width: 100%;
}
input[type="range"] {
width: 100%;
height: 8px;
border-radius: 5px;
-webkit-appearance: none;
background: #ddd;
outline: none;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--primary-color);
cursor: pointer;
}
.result-value {
font-weight: bold;
color: var(--primary-color);
}
.download-section {
margin-top: 30px;
text-align: center;
}
.canvas-container {
display: none;
}
.status-message {
padding: 10px;
border-radius: 5px;
margin-bottom: 20px;
text-align: center;
display: none;
}
.success {
background-color: rgba(46, 204, 113, 0.2);
color: var(--success-color);
border: 1px solid var(--success-color);
}
.error {
background-color: rgba(231, 76, 60, 0.2);
color: #e74c3c;
border: 1px solid #e74c3c;
}
@media (max-width: 768px) {
.app-container {
flex-direction: column;
}
.filter-grid {
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1><i class="fas fa-magic"></i> Photo Visual Enhancer Pro</h1>
<p class="description">Transform your images with powerful enhancement tools and filters</p>
</header>
<div class="app-container">
<div class="image-section">
<div class="image-container" id="image-container">
<div class="upload-area" id="upload-area">
<div class="upload-icon">
<i class="fas fa-cloud-upload-alt"></i>
</div>
<p class="upload-text">Drag & Drop your image here or click to browse</p>
<input type="file" id="file-input" accept="image/*" style="display: none;">
</div>
<img id="uploaded-image" alt="Uploaded Photo">
</div>
<div class="status-message" id="status-message"></div>
<div class="btn-group">
<button class="btn" id="enhance-btn"><i class="fas fa-star"></i> Auto Enhance</button>
<button class="btn btn-secondary" id="reset-btn"><i class="fas fa-redo"></i> Reset</button>
<button class="btn btn-accent" id="save-preset-btn"><i class="fas fa-save"></i> Save Preset</button>
</div>
<div class="canvas-container">
<canvas id="canvas"></canvas>
</div>
</div>
<div class="controls-section">
<div class="control-group">
<h3 class="control-title"><i class="fas fa-sliders-h"></i> Basic Adjustments</h3>
<div class="slider-group">
<div class="slider-label">
<span>Brightness</span>
<span class="result-value" id="brightness-value">0%</span>
</div>
<div class="slider-container">
<input type="range" id="brightness" min="-100" max="100" value="0" step="1">
</div>
</div>
<div class="slider-group">
<div class="slider-label">
<span>Contrast</span>
<span class="result-value" id="contrast-value">100%</span>
</div>
<div class="slider-container">
<input type="range" id="contrast" min="0" max="200" value="100" step="1">
</div>
</div>
<div class="slider-group">
<div class="slider-label">
<span>Saturation</span>
<span class="result-value" id="saturation-value">100%</span>
</div>
<div class="slider-container">
<input type="range" id="saturation" min="0" max="200" value="100" step="1">
</div>
</div>
</div>
<div class="control-group">
<h3 class="control-title"><i class="fas fa-filter"></i> Creative Filters</h3>
<div class="filter-grid">
<div class="filter-btn" data-filter="none">
<div class="filter-preview" style="background: #f8f9fa;"></div>
<div class="filter-name">None</div>
</div>
<div class="filter-btn" data-filter="vintage">
<div class="filter-preview" style="background: #e6dbc9;"></div>
<div class="filter-name">Vintage</div>
</div>
<div class="filter-btn" data-filter="blackWhite">
<div class="filter-preview" style="background: linear-gradient(to right, #000, #fff);"></div>
<div class="filter-name">B&W</div>
</div>
<div class="filter-btn" data-filter="sepia">
<div class="filter-preview" style="background: #704214;"></div>
<div class="filter-name">Sepia</div>
</div>
<div class="filter-btn" data-filter="clarendon">
<div class="filter-preview" style="background: linear-gradient(135deg, #4361ee, #f72585);"></div>
<div class="filter-name">Clarendon</div>
</div>
<div class="filter-btn" data-filter="lark">
<div class="filter-preview" style="background: linear-gradient(135deg, #3a0ca3, #2ec4b6);"></div>
<div class="filter-name">Lark</div>
</div>
<div class="filter-btn" data-filter="moon">
<div class="filter-preview" style="background: linear-gradient(135deg, #0c1a3a, #4cc9f0);"></div>
<div class="filter-name">Moon</div>
</div>
<div class="filter-btn" data-filter="willow">
<div class="filter-preview" style="background: linear-gradient(135deg, #3a5a40, #a3b18a);"></div>
<div class="filter-name">Willow</div>
</div>
</div>
</div>
<div class="control-group">
<h3 class="control-title"><i class="fas fa-tint"></i> Color Balance</h3>
<div class="slider-group">
<div class="slider-label">
<span>Red</span>
<span class="result-value" id="red-value">0</span>
</div>
<div class="slider-container">
<input type="range" id="red" min="-100" max="100" value="0" step="1">
</div>
</div>
<div class="slider-group">
<div class="slider-label">
<span>Green</span>
<span class="result-value" id="green-value">0</span>
</div>
<div class="slider-container">
<input type="range" id="green" min="-100" max="100" value="0" step="1">
</div>
</div>
<div class="slider-group">
<div class="slider-label">
<span>Blue</span>
<span class="result-value" id="blue-value">0</span>
</div>
<div class="slider-container">
<input type="range" id="blue" min="-100" max="100" value="0" step="1">
</div>
</div>
</div>
<div class="control-group">
<h3 class="control-title"><i class="fas fa-crop"></i> Transform</h3>
<div class="slider-group">
<div class="slider-label">
<span>Rotate</span>
<span class="result-value" id="rotate-value"></span>
</div>
<div class="slider-container">
<input type="range" id="rotate" min="0" max="360" value="0" step="1">
</div>
</div>
<div class="btn-group">
<button class="btn" id="flip-h"><i class="fas fa-arrows-alt-h"></i> Flip H</button>
<button class="btn" id="flip-v"><i class="fas fa-arrows-alt-v"></i> Flip V</button>
</div>
</div>
<div class="download-section">
<button class="btn btn-accent" id="download-btn"><i class="fas fa-download"></i> Download Enhanced Image</button>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// DOM Elements
const fileInput = document.getElementById('file-input');
const uploadArea = document.getElementById('upload-area');
const uploadedImage = document.getElementById('uploaded-image');
const imageContainer = document.getElementById('image-container');
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// Controls
const brightnessSlider = document.getElementById('brightness');
const contrastSlider = document.getElementById('contrast');
const saturationSlider = document.getElementById('saturation');
const redSlider = document.getElementById('red');
const greenSlider = document.getElementById('green');
const blueSlider = document.getElementById('blue');
const rotateSlider = document.getElementById('rotate');
// Buttons
const enhanceBtn = document.getElementById('enhance-btn');
const resetBtn = document.getElementById('reset-btn');
const savePresetBtn = document.getElementById('save-preset-btn');
const downloadBtn = document.getElementById('download-btn');
const flipHBtn = document.getElementById('flip-h');
const flipVBtn = document.getElementById('flip-v');
// Value displays
const brightnessValue = document.getElementById('brightness-value');
const contrastValue = document.getElementById('contrast-value');
const saturationValue = document.getElementById('saturation-value');
const redValue = document.getElementById('red-value');
const greenValue = document.getElementById('green-value');
const blueValue = document.getElementById('blue-value');
const rotateValue = document.getElementById('rotate-value');
// Status message
const statusMessage = document.getElementById('status-message');
// Global variables
let originalImageData = null;
let flipHorizontal = false;
let flipVertical = false;
// Event listeners for drag and drop
uploadArea.addEventListener('click', () => fileInput.click());
uploadArea.addEventListener('dragover', (e) => {
e.preventDefault();
imageContainer.style.borderColor = var(--primary-color);
});
uploadArea.addEventListener('dragleave', () => {
imageContainer.style.borderColor = '#ddd';
});
uploadArea.addEventListener('drop', (e) => {
e.preventDefault();
imageContainer.style.borderColor = '#ddd';
if (e.dataTransfer.files.length) {
fileInput.files = e.dataTransfer.files;
handleImageUpload();
}
});
fileInput.addEventListener('change', handleImageUpload);
// Slider event listeners
brightnessSlider.addEventListener('input', updateSliderValues);
contrastSlider.addEventListener('input', updateSliderValues);
saturationSlider.addEventListener('input', updateSliderValues);
redSlider.addEventListener('input', updateSliderValues);
greenSlider.addEventListener('input', updateSliderValues);
blueSlider.addEventListener('input', updateSliderValues);
rotateSlider.addEventListener('input', updateSliderValues);
// Button event listeners
document.querySelectorAll('.filter-btn').forEach(btn => {
btn.addEventListener('click', applyFilter);
});
enhanceBtn.addEventListener('click', autoEnhance);
resetBtn.addEventListener('click', resetImage);
downloadBtn.addEventListener('click', downloadImage);
flipHBtn.addEventListener('click', () => {
flipHorizontal = !flipHorizontal;
applyChanges();
});
flipVBtn.addEventListener('click', () => {
flipVertical = !flipVertical;
applyChanges();
});
// Handle image upload
function handleImageUpload() {
const file = fileInput.files[0];
if (!file) return;
if (!file.type.match('image.*')) {
showStatus('Please select an image file', 'error');
return;
}
const reader = new FileReader();
reader.onload = function(e) {
uploadedImage.src = e.target.result;
uploadedImage.onload = function() {
uploadArea.style.display = 'none';
uploadedImage.style.display = 'block';
// Set canvas size to match image
canvas.width = uploadedImage.naturalWidth;
canvas.height = uploadedImage.naturalHeight;
// Draw original image to canvas and save original data
ctx.drawImage(uploadedImage, 0, 0);
originalImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
showStatus('Image uploaded successfully!', 'success');
};
};
reader.readAsDataURL(file);
}
// Update slider value displays
function updateSliderValues() {
brightnessValue.textContent = brightnessSlider.value + '%';
contrastValue.textContent = contrastSlider.value + '%';
saturationValue.textContent = saturationSlider.value + '%';
redValue.textContent = redSlider.value;
greenValue.textContent = greenSlider.value;
blueValue.textContent = blueSlider.value;
rotateValue.textContent = rotateSlider.value + '°';
applyChanges();
}
// Apply all adjustments to the image
function applyChanges() {
if (!originalImageData) return;
// Restore original image data
ctx.putImageData(originalImageData, 0, 0);
// Apply filters
applyBrightnessContrast();
applyColorBalance();
applySaturation();
// Simple rotation (for demo purposes - would need more complex transformation for better quality)
if (rotateSlider.value != 0 || flipHorizontal || flipVertical) {
rotateImage();
}
}
// Apply brightness and contrast
function applyBrightnessContrast() {
const brightness = parseInt(brightnessSlider.value);
const contrast = parseInt(contrastSlider.value) / 100;
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
// Apply brightness and contrast
const factor = (259 * (contrast * 255 + 255)) / (255 * (259 - contrast * 255));
for (let i = 0; i < data.length; i += 4) {
// Contrast
data[i] = factor * (data[i] - 128) + 128;
data[i+1] = factor * (data[i+1] - 128) + 128;
data[i+2] = factor * (data[i+2] - 128) + 128;
// Brightness
data[i] += brightness * 2.55;
data[i+1] += brightness * 2.55;
data[i+2] += brightness * 2.55;
}
ctx.putImageData(imageData, 0, 0);
}
// Apply color balance (red, green, blue)
function applyColorBalance() {
const red = parseInt(redSlider.value) / 100;
const green = parseInt(greenSlider.value) / 100;
const blue = parseInt(blueSlider.value) / 100;
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
// Red channel
data[i] = data[i] + (255 - data[i]) * red;
// Green channel
data[i+1] = data[i+1] + (255 - data[i+1]) * green;
// Blue channel
data[i+2] = data[i+2] + (255 - data[i+2]) * blue;
}
ctx.putImageData(imageData, 0, 0);
}
// Apply saturation
function applySaturation() {
const saturation = parseInt(saturationSlider.value) / 100;
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i+1];
const b = data[i+2];
// Calculate grayscale value
const gray = 0.299 * r + 0.587 * g + 0.114 * b;
// Apply saturation
data[i] = gray + (r - gray) * saturation;
data[i+1] = gray + (g - gray) * saturation;
data[i+2] = gray + (b - gray) * saturation;
}
ctx.putImageData(imageData, 0, 0);
}
// Rotate and flip image
function rotateImage() {
const angle = parseInt(rotateSlider.value);
// Save current canvas content
const tempCanvas = document.createElement('canvas');
tempCanvas.width = canvas.width;
tempCanvas.height = canvas.height;
const tempCtx = tempCanvas.getContext('2d');
tempCtx.drawImage(canvas, 0, 0);
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Save context
ctx.save();
// Move to center of canvas
ctx.translate(canvas.width / 2, canvas.height / 2);
// Apply rotation
if (angle !== 0) {
ctx.rotate(angle * Math.PI / 180);
}
// Apply flips
let scaleX = 1;
let scaleY = 1;
if (flipHorizontal) scaleX = -1;
if (flipVertical) scaleY = -1;
ctx.scale(scaleX, scaleY);
// Draw image
ctx.drawImage(tempCanvas, -tempCanvas.width / 2, -tempCanvas.height / 2);
// Restore context
ctx.restore();
}
// Apply filter preset
function applyFilter(e) {
const filter = e.currentTarget.getAttribute('data-filter');
switch(filter) {
case 'vintage':
brightnessSlider.value = 10;
contrastSlider.value = 90;
saturationSlider.value = 60;
redSlider.value = 30;
greenSlider.value = -10;
blueSlider.value = -20;
break;
case 'blackWhite':
brightnessSlider.value = 5;
contrastSlider.value = 120;
saturationSlider.value = 0;
break;
case 'sepia':
brightnessSlider.value = 10;
contrastSlider.value = 90;
saturationSlider.value = 60;
redSlider.value = 40;
greenSlider.value = 20;
blueSlider.value = -40;
break;
case 'clarendon':
brightnessSlider.value = 5;
contrastSlider.value = 120;
saturationSlider.value = 110;
redSlider.value = 10;
greenSlider.value = 0;
blueSlider.value = 10;
break;
case 'lark':
brightnessSlider.value = 15;
contrastSlider.value = 110;
saturationSlider.value = 120;
redSlider.value = -10;
greenSlider.value = 5;
blueSlider.value = 25;
break;
case 'moon':
brightnessSlider.value = 0;
contrastSlider.value = 130;
saturationSlider.value = 0;
redSlider.value = 0;
greenSlider.value = 0;
blueSlider.value = 30;
break;
case 'willow':
brightnessSlider.value = 10;
contrastSlider.value = 90;
saturationSlider.value = 80;
redSlider.value = -15;
greenSlider.value = 20;
blueSlider.value = -20;
break;
case 'none':
default:
brightnessSlider.value = 0;
contrastSlider.value = 100;
saturationSlider.value = 100;
redSlider.value = 0;
greenSlider.value = 0;
blueSlider.value = 0;
}
updateSliderValues();
applyChanges();
// Highlight selected filter
document.querySelectorAll('.filter-btn').forEach(btn => {
btn.style.borderColor = btn === e.currentTarget ? var(--primary-color) : '#ddd';
});
}
// Auto enhance image
function autoEnhance() {
brightnessSlider.value = 15;
contrastSlider.value = 115;
saturationSlider.value = 110;
redSlider.value = 5;
greenSlider.value = 0;
blueSlider.value = 0;
updateSliderValues();
applyChanges();
showStatus('Image auto-enhanced!', 'success');
}
// Reset image to original
function resetImage() {
brightnessSlider.value = 0;
contrastSlider.value = 100;
saturationSlider.value = 100;
redSlider.value = 0;
greenSlider.value = 0;
blueSlider.value = 0;
rotateSlider.value = 0;
flipHorizontal = false;
flipVertical = false;
updateSliderValues();
if (originalImageData) {
ctx.putImageData(originalImageData, 0, 0);
}
// Reset filter selection
document.querySelectorAll('.filter-btn').forEach(btn => {
btn.style.borderColor = '#ddd';
});
showStatus('Image reset to original', 'success');
}
// Download enhanced image
function downloadImage() {
if (!originalImageData) {
showStatus('No image to download', 'error');
return;
}
// Create a temporary canvas for final processing
const tempCanvas = document.createElement('canvas');
tempCanvas.width = canvas.width;
tempCanvas.height = canvas.height;
const tempCtx = tempCanvas.getContext('2d');
tempCtx.drawImage(canvas, 0, 0);
// Convert to data URL and create download link
const dataURL = tempCanvas.toDataURL('image/jpeg', 0.9);
const link = document.createElement('a');
link.download = 'enhanced-photo.jpg';
link.href = dataURL;
link.click();
showStatus('Image downloaded successfully!', 'success');
}
// Show status message
function showStatus(message, type) {
statusMessage.textContent = message;
statusMessage.className = 'status-message ' + type;
statusMessage.style.display = 'block';
// Hide after 3 seconds
setTimeout(() => {
statusMessage.style.display = 'none';
}, 3000);
}
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body>
</html>