image-flipper / index.html
DigiP-AI's picture
Update index.html
55b7535 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Image Flipper App</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
.image-container {
transition: transform 0.3s ease;
}
.flip-btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.file-input-label {
cursor: pointer;
transition: all 0.3s ease;
}
.file-input-label:hover {
background-color: #f3f4f6;
}
.flip-animation {
animation: flip 0.5s ease;
}
@keyframes flip {
0% { transform: scaleX(1); }
50% { transform: scaleX(0); }
100% { transform: scaleX(1); }
}
</style>
</head>
<body class="bg-gray-100 min-h-screen flex flex-col items-center py-12">
<div class="w-full max-w-4xl bg-white rounded-xl shadow-lg overflow-hidden">
<!-- Header -->
<div class="bg-indigo-600 py-6 px-8 text-white">
<h1 class="text-3xl font-bold">Image Flipper</h1>
<p class="mt-2 opacity-90">Upload an image and flip it horizontally or vertically</p>
</div>
<!-- Main Content -->
<div class="p-8">
<!-- File Upload Section -->
<div class="mb-8">
<label class="file-input-label flex flex-col items-center justify-center border-2 border-dashed border-gray-300 rounded-lg p-12 text-center cursor-pointer hover:border-indigo-400 transition-colors duration-300" id="drop-area">
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 text-indigo-500 mb-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" />
</svg>
<span class="text-xl font-medium text-gray-700">Drag & drop your image here</span>
<span class="text-gray-500 mt-2">or click to browse files</span>
<input type="file" id="file-input" accept="image/*" class="hidden">
</label>
</div>
<!-- Image Display Section -->
<div class="flex flex-col items-center">
<div class="relative mb-8 w-full max-w-md" id="image-wrapper">
<div class="image-container bg-gray-100 rounded-lg overflow-hidden shadow-md" id="image-container">
<img id="preview-image" class="w-full h-auto object-contain max-h-96" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%239C92AC'%3E%3Cpath d='M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z'/%3E%3C/svg%3E" alt="Preview will appear here">
</div>
<div class="absolute -bottom-5 left-0 right-0 flex justify-center space-x-4">
<button id="reset-btn" class="bg-gray-200 hover:bg-gray-300 text-gray-800 font-medium py-2 px-4 rounded-full transition-all duration-200 opacity-0 pointer-events-none">
Reset
</button>
</div>
</div>
<!-- Flip Controls -->
<div class="flex flex-wrap justify-center gap-4 mb-8" id="flip-controls">
<button id="flip-horizontal" class="flip-btn bg-indigo-600 hover:bg-indigo-700 text-white font-medium py-3 px-6 rounded-lg flex items-center transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed" disabled>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" />
</svg>
Flip Horizontal
</button>
<button id="flip-vertical" class="flip-btn bg-indigo-600 hover:bg-indigo-700 text-white font-medium py-3 px-6 rounded-lg flex items-center transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed" disabled>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 17V7m0 10l-4 4m4-4l4 4M8 7v10m0-10l4-4m-4 4l-4 4" />
</svg>
Flip Vertical
</button>
</div>
<!-- Download Button -->
<div class="w-full flex justify-center">
<button id="download-btn" class="bg-green-600 hover:bg-green-700 text-white font-medium py-3 px-6 rounded-lg flex items-center transition-all duration-200 opacity-0 pointer-events-none">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
</svg>
Download Flipped Image
</button>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const fileInput = document.getElementById('file-input');
const dropArea = document.getElementById('drop-area');
const previewImage = document.getElementById('preview-image');
const flipHorizontalBtn = document.getElementById('flip-horizontal');
const flipVerticalBtn = document.getElementById('flip-vertical');
const resetBtn = document.getElementById('reset-btn');
const downloadBtn = document.getElementById('download-btn');
const imageContainer = document.getElementById('image-container');
let originalImageSrc = null;
let currentImageSrc = null;
let canvas = null;
// Handle file selection
fileInput.addEventListener('change', function(e) {
if (e.target.files.length) {
const file = e.target.files[0];
processImage(file);
}
});
// Handle drag and drop
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropArea.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
['dragenter', 'dragover'].forEach(eventName => {
dropArea.addEventListener(eventName, highlight, false);
});
['dragleave', 'drop'].forEach(eventName => {
dropArea.addEventListener(eventName, unhighlight, false);
});
function highlight() {
dropArea.classList.add('border-indigo-500', 'bg-indigo-50');
}
function unhighlight() {
dropArea.classList.remove('border-indigo-500', 'bg-indigo-50');
}
dropArea.addEventListener('drop', function(e) {
const dt = e.dataTransfer;
const file = dt.files[0];
if (file && file.type.match('image.*')) {
processImage(file);
}
});
// Process the uploaded image
function processImage(file) {
const reader = new FileReader();
reader.onload = function(e) {
originalImageSrc = e.target.result;
currentImageSrc = originalImageSrc;
previewImage.src = originalImageSrc;
// Enable buttons
flipHorizontalBtn.disabled = false;
flipVerticalBtn.disabled = false;
// Show reset button
resetBtn.classList.remove('opacity-0', 'pointer-events-none');
resetBtn.classList.add('opacity-100', 'pointer-events-auto');
// Hide download button until flip
downloadBtn.classList.add('opacity-0', 'pointer-events-none');
downloadBtn.classList.remove('opacity-100', 'pointer-events-auto');
// Create canvas for manipulation
createCanvas(originalImageSrc);
};
reader.readAsDataURL(file);
}
// Create canvas for image manipulation
function createCanvas(imageSrc) {
const img = new Image();
img.onload = function() {
if (canvas) {
document.body.removeChild(canvas);
}
canvas = document.createElement('canvas');
canvas.style.display = 'none';
document.body.appendChild(canvas);
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
};
img.src = imageSrc;
}
// Flip image horizontally
flipHorizontalBtn.addEventListener('click', function() {
flipImage('horizontal');
});
// Flip image vertically
flipVerticalBtn.addEventListener('click', function() {
flipImage('vertical');
});
// Reset image to original
resetBtn.addEventListener('click', function() {
previewImage.src = originalImageSrc;
currentImageSrc = originalImageSrc;
createCanvas(originalImageSrc);
// Hide download button
downloadBtn.classList.add('opacity-0', 'pointer-events-none');
downloadBtn.classList.remove('opacity-100', 'pointer-events-auto');
// Add animation
imageContainer.classList.add('flip-animation');
setTimeout(() => {
imageContainer.classList.remove('flip-animation');
}, 500);
});
// Flip the image
function flipImage(direction) {
if (!canvas) return;
const img = new Image();
img.onload = function() {
const ctx = canvas.getContext('2d');
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Save the current context
ctx.save();
if (direction === 'horizontal') {
// Flip horizontally
ctx.translate(canvas.width, 0);
ctx.scale(-1, 1);
} else {
// Flip vertically
ctx.translate(0, canvas.height);
ctx.scale(1, -1);
}
// Draw the image
ctx.drawImage(img, 0, 0);
// Restore the context
ctx.restore();
// Update the preview
currentImageSrc = canvas.toDataURL('image/png');
previewImage.src = currentImageSrc;
// Show download button
downloadBtn.classList.remove('opacity-0', 'pointer-events-none');
downloadBtn.classList.add('opacity-100', 'pointer-events-auto');
// Add animation
imageContainer.classList.add('flip-animation');
setTimeout(() => {
imageContainer.classList.remove('flip-animation');
}, 500);
};
img.src = currentImageSrc;
}
// Download the flipped image
downloadBtn.addEventListener('click', function() {
if (!currentImageSrc) return;
const link = document.createElement('a');
link.download = 'flipped-image.png';
link.href = currentImageSrc;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
});
});
</script>
</html>