// Theme toggle functionality
document.addEventListener('DOMContentLoaded', () => {
const themeToggle = document.getElementById('themeToggle');
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)');
// Check for saved theme preference or use system preference
const currentTheme = localStorage.getItem('theme') ||
(prefersDarkScheme.matches ? 'dark' : 'light');
// Apply the current theme
if (currentTheme === 'dark') {
document.documentElement.classList.add('dark');
themeToggle.innerHTML = ' Light Mode';
} else {
document.documentElement.classList.remove('dark');
themeToggle.innerHTML = ' Dark Mode';
}
// Set up the toggle button
themeToggle.addEventListener('click', () => {
const isDark = document.documentElement.classList.contains('dark');
if (isDark) {
document.documentElement.classList.remove('dark');
localStorage.setItem('theme', 'light');
themeToggle.innerHTML = ' Dark Mode';
} else {
document.documentElement.classList.add('dark');
localStorage.setItem('theme', 'dark');
themeToggle.innerHTML = ' Light Mode';
}
feather.replace();
});
// Watch for system theme changes
prefersDarkScheme.addEventListener('change', e => {
if (localStorage.getItem('theme') === null) {
if (e.matches) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}
});
// MediaPipe Selfie Segmentation setup
let selfieSegmentation;
let segmentationActive = false;
async function setupSegmentation() {
selfieSegmentation = new SelfieSegmentation({
locateFile: (file) => {
return `https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation/${file}`;
}
});
selfieSegmentation.setOptions({
modelSelection: 1, // 0 for general segmentation, 1 for landscape (better for full body)
selfieMode: false
});
await selfieSegmentation.initialize();
}
// Image upload and clothing selection functionality
const imageUpload = document.getElementById('imageUpload');
const imagePreview = document.getElementById('imagePreview');
const previewImage = document.getElementById('previewImage');
const toolsPanel = document.getElementById('toolsPanel');
const selectClothesBtn = document.getElementById('selectClothes');
const clearSelectionBtn = document.getElementById('clearSelection');
const downloadSelectionBtn = document.getElementById('downloadSelection');
const selectionCanvas = document.getElementById('selectionCanvas');
const ctx = selectionCanvas.getContext('2d');
let imageLoaded = false;
let selectionMode = false;
let selectionPoints = [];
imageUpload.addEventListener('change', function(e) {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(event) {
previewImage.onload = function() {
// Set canvas dimensions to match image
selectionCanvas.width = previewImage.width;
selectionCanvas.height = previewImage.height;
imageLoaded = true;
toolsPanel.classList.remove('hidden');
};
previewImage.src = event.target.result;
imagePreview.classList.remove('hidden');
selectionPoints = [];
ctx.clearRect(0, 0, selectionCanvas.width, selectionCanvas.height);
}
reader.readAsDataURL(file);
}
});
// Initialize clothing selection
selectClothesBtn.addEventListener('click', async function() {
if (!selfieSegmentation) {
await setupSegmentation();
}
selectionMode = true;
segmentationActive = true;
selectionPoints = [];
ctx.clearRect(0, 0, selectionCanvas.width, selectionCanvas.height);
previewImage.style.cursor = 'crosshair';
// Process image with segmentation model
if (imageLoaded) {
await processSegmentation();
}
});
// Clear selection
clearSelectionBtn.addEventListener('click', function() {
selectionPoints = [];
ctx.clearRect(0, 0, selectionCanvas.width, selectionCanvas.height);
previewImage.style.cursor = 'default';
selectionMode = false;
segmentationActive = false;
});
// Download selection
downloadSelectionBtn.addEventListener('click', function() {
if (selectionPoints.length > 0) {
const tempCanvas = document.createElement('canvas');
const tempCtx = tempCanvas.getContext('2d');
tempCanvas.width = previewImage.width;
tempCanvas.height = previewImage.height;
// Draw the selected area
tempCtx.drawImage(previewImage, 0, 0);
// Create mask for selection
tempCtx.globalCompositeOperation = 'destination-in';
tempCtx.fillStyle = 'black';
tempCtx.beginPath();
tempCtx.moveTo(selectionPoints[0].x, selectionPoints[0].y);
for (let i = 1; i < selectionPoints.length; i++) {
tempCtx.lineTo(selectionPoints[i].x, selectionPoints[i].y);
}
tempCtx.closePath();
tempCtx.fill();
// Create download link
const link = document.createElement('a');
link.download = 'selected-clothing.png';
link.href = tempCanvas.toDataURL('image/png');
link.click();
}
});
// Process image with segmentation model
async function processSegmentation() {
if (!selfieSegmentation || !imageLoaded) return;
try {
const result = await selfieSegmentation.send({image: previewImage});
const mask = result.segmentationMask;
// Draw the segmentation mask
ctx.clearRect(0, 0, selectionCanvas.width, selectionCanvas.height);
ctx.drawImage(mask, 0, 0, selectionCanvas.width, selectionCanvas.height);
// Apply the mask to highlight clothing
ctx.globalCompositeOperation = 'source-in';
ctx.fillStyle = 'rgba(59, 130, 246, 0.5)';
ctx.fillRect(0, 0, selectionCanvas.width, selectionCanvas.height);
ctx.globalCompositeOperation = 'source-over';
} catch (error) {
console.error('Segmentation error:', error);
}
}
// Handle selection drawing
imagePreview.addEventListener('click', function(e) {
if (!selectionMode || !imageLoaded) return;
const rect = previewImage.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
selectionPoints.push({x, y});
// Draw selection
ctx.clearRect(0, 0, selectionCanvas.width, selectionCanvas.height);
ctx.strokeStyle = '#3B82F6';
ctx.lineWidth = 2;
ctx.fillStyle = 'rgba(59, 130, 246, 0.2)';
if (selectionPoints.length > 0) {
ctx.beginPath();
ctx.moveTo(selectionPoints[0].x, selectionPoints[0].y);
for (let i = 1; i < selectionPoints.length; i++) {
ctx.lineTo(selectionPoints[i].x, selectionPoints[i].y);
}
if (selectionPoints.length > 2) {
ctx.closePath();
ctx.fill();
}
ctx.stroke();
}
});
});