| <!DOCTYPE html> |
| <html lang="zh-CN"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>图片优化大师 | 压缩图片 & 去除水印</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| .dropzone { |
| border: 2px dashed #cbd5e0; |
| transition: all 0.3s ease; |
| } |
| .dropzone.active { |
| border-color: #4f46e5; |
| background-color: #f0f4ff; |
| } |
| .progress-bar { |
| transition: width 0.3s ease; |
| } |
| .watermark-preview { |
| position: relative; |
| overflow: hidden; |
| } |
| .watermark-box { |
| position: absolute; |
| border: 2px dashed red; |
| background-color: rgba(255, 0, 0, 0.2); |
| } |
| .settings-panel { |
| transition: all 0.3s ease; |
| overflow: hidden; |
| } |
| .settings-panel.closed { |
| max-height: 0; |
| } |
| .settings-panel.open { |
| max-height: 500px; |
| } |
| .tooltip { |
| position: relative; |
| } |
| .tooltip-text { |
| visibility: hidden; |
| width: 200px; |
| background-color: #333; |
| color: #fff; |
| text-align: center; |
| border-radius: 6px; |
| padding: 5px; |
| position: absolute; |
| z-index: 1; |
| bottom: 125%; |
| left: 50%; |
| transform: translateX(-50%); |
| opacity: 0; |
| transition: opacity 0.3s; |
| } |
| .tooltip:hover .tooltip-text { |
| visibility: visible; |
| opacity: 1; |
| } |
| </style> |
| </head> |
| <body class="bg-gray-50 min-h-screen"> |
| <div class="container mx-auto px-4 py-8"> |
| |
| <header class="flex justify-between items-center mb-8"> |
| <div> |
| <h1 class="text-3xl font-bold text-indigo-600">图片优化大师</h1> |
| <p class="text-gray-600">轻松压缩图片并去除水印</p> |
| </div> |
| <button id="premium-btn" class="bg-gradient-to-r from-purple-500 to-indigo-600 text-white px-4 py-2 rounded-lg shadow-md hover:shadow-lg transition-all flex items-center"> |
| <i class="fas fa-crown mr-2"></i> |
| 升级专业版 |
| </button> |
| </header> |
|
|
| <div class="grid grid-cols-1 lg:grid-cols-2 gap-8"> |
| |
| <div class="bg-white rounded-xl shadow-md p-6"> |
| <div id="dropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer mb-6"> |
| <div class="flex flex-col items-center justify-center"> |
| <i class="fas fa-cloud-upload-alt text-4xl text-indigo-500 mb-4"></i> |
| <h3 class="text-xl font-semibold mb-2">拖放图片到此处</h3> |
| <p class="text-gray-500 mb-4">或点击选择文件</p> |
| <input type="file" id="fileInput" class="hidden" accept="image/*" multiple> |
| <button id="browseBtn" class="bg-indigo-500 text-white px-6 py-2 rounded-lg hover:bg-indigo-600 transition"> |
| 选择图片 |
| </button> |
| </div> |
| </div> |
|
|
| <div id="fileInfo" class="hidden mb-6"> |
| <div class="flex justify-between items-center mb-2"> |
| <span class="font-medium">已选文件:</span> |
| <span id="fileCount" class="text-gray-600">0 个文件</span> |
| </div> |
| <div id="fileList" class="border rounded-lg p-3 max-h-40 overflow-y-auto"></div> |
| </div> |
|
|
| |
| <div class="mb-6"> |
| <button id="settingsToggle" class="flex justify-between items-center w-full bg-gray-100 hover:bg-gray-200 px-4 py-3 rounded-lg transition"> |
| <span class="font-medium">高级设置</span> |
| <i class="fas fa-chevron-up transition-transform"></i> |
| </button> |
| <div id="settingsPanel" class="settings-panel open bg-gray-50 rounded-lg mt-2 px-4 py-3"> |
| <div class="mb-4"> |
| <label class="block text-gray-700 mb-2">压缩级别</label> |
| <div class="flex items-center"> |
| <input type="range" id="compressionLevel" min="0" max="100" value="70" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer"> |
| <span id="compressionValue" class="ml-3 text-gray-700 w-12 text-center">70%</span> |
| </div> |
| </div> |
| <div class="mb-4"> |
| <label class="block text-gray-700 mb-2">输出格式</label> |
| <select id="outputFormat" class="w-full border rounded-lg px-3 py-2"> |
| <option value="original">保持原格式</option> |
| <option value="jpeg">JPEG</option> |
| <option value="png">PNG</option> |
| <option value="webp">WebP</option> |
| </select> |
| </div> |
| <div class="flex items-center mb-4"> |
| <input type="checkbox" id="removeMetadata" class="mr-2" checked> |
| <label for="removeMetadata" class="text-gray-700">移除元数据</label> |
| </div> |
| <div class="flex items-center"> |
| <input type="checkbox" id="removeWatermark" class="mr-2" checked> |
| <label for="removeWatermark" class="text-gray-700">去除水印</label> |
| </div> |
| </div> |
| </div> |
|
|
| <button id="processBtn" class="w-full bg-green-500 hover:bg-green-600 text-white py-3 rounded-lg font-medium transition flex items-center justify-center hidden"> |
| <i class="fas fa-magic mr-2"></i> |
| 处理图片 |
| </button> |
|
|
| <div id="progressContainer" class="hidden mt-6"> |
| <div class="flex justify-between mb-1"> |
| <span>处理中...</span> |
| <span id="progressPercent">0%</span> |
| </div> |
| <div class="w-full bg-gray-200 rounded-full h-2.5"> |
| <div id="progressBar" class="progress-bar bg-indigo-600 h-2.5 rounded-full" style="width: 0%"></div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="bg-white rounded-xl shadow-md p-6"> |
| <h2 class="text-xl font-semibold mb-4">水印去除工具</h2> |
| <div id="watermarkPreviewContainer" class="hidden"> |
| <div class="watermark-preview mb-4 border rounded-lg overflow-hidden relative" style="height: 300px;"> |
| <img id="watermarkPreview" src="#" alt="预览" class="w-full h-full object-contain"> |
| <div id="watermarkBox" class="watermark-box hidden"></div> |
| </div> |
| <div class="flex justify-between mb-4"> |
| <div> |
| <label class="block text-gray-700 mb-2">选择水印区域</label> |
| <div class="flex space-x-2"> |
| <button id="selectBtn" class="bg-indigo-500 text-white px-3 py-1 rounded hover:bg-indigo-600"> |
| <i class="fas fa-vector-square mr-1"></i> 选择 |
| </button> |
| <button id="clearSelectionBtn" class="bg-gray-200 text-gray-700 px-3 py-1 rounded hover:bg-gray-300"> |
| <i class="fas fa-eraser mr-1"></i> 清除 |
| </button> |
| </div> |
| </div> |
| <div class="tooltip"> |
| <button id="autoDetectBtn" class="bg-purple-500 text-white px-3 py-1 rounded hover:bg-purple-600"> |
| <i class="fas fa-robot mr-1"></i> 自动检测 |
| </button> |
| <span class="tooltip-text">我们的AI将尝试自动检测常见水印模式</span> |
| </div> |
| </div> |
| <div class="mb-4"> |
| <label class="block text-gray-700 mb-2">去除强度</label> |
| <div class="flex items-center"> |
| <input type="range" id="removalStrength" min="1" max="10" value="5" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer"> |
| <span id="removalStrengthValue" class="ml-3 text-gray-700 w-12 text-center">5</span> |
| </div> |
| </div> |
| <button id="removeWatermarkBtn" class="w-full bg-red-500 hover:bg-red-600 text-white py-3 rounded-lg font-medium transition flex items-center justify-center"> |
| <i class="fas fa-trash-alt mr-2"></i> |
| 去除水印 |
| </button> |
| </div> |
| <div id="noImageSelected" class="text-center py-12 text-gray-500"> |
| <i class="fas fa-image fa-3x mb-4"></i> |
| <p>未选择用于去除水印的图片。</p> |
| <p>请先上传图片以使用此工具。</p> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="resultsSection" class="hidden mt-8 bg-white rounded-xl shadow-md p-6"> |
| <h2 class="text-xl font-semibold mb-4">处理结果</h2> |
| <div class="flex justify-between items-center mb-4"> |
| <div> |
| <span class="text-gray-600">原始大小:</span> |
| <span id="originalSize" class="font-medium ml-2">-</span> |
| </div> |
| <div> |
| <span class="text-gray-600">压缩后大小:</span> |
| <span id="compressedSize" class="font-medium ml-2">-</span> |
| </div> |
| <div> |
| <span class="text-gray-600">节省空间:</span> |
| <span id="savings" class="font-medium ml-2">-</span> |
| </div> |
| <button id="downloadAllBtn" class="bg-indigo-500 text-white px-4 py-2 rounded-lg hover:bg-indigo-600 transition flex items-center"> |
| <i class="fas fa-download mr-2"></i> |
| 全部下载 |
| </button> |
| </div> |
| <div id="resultsGrid" class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4"></div> |
| </div> |
| </div> |
|
|
| <script> |
| |
| const dropzone = document.getElementById('dropzone'); |
| const fileInput = document.getElementById('fileInput'); |
| const browseBtn = document.getElementById('browseBtn'); |
| const fileInfo = document.getElementById('fileInfo'); |
| const fileList = document.getElementById('fileList'); |
| const fileCount = document.getElementById('fileCount'); |
| const processBtn = document.getElementById('processBtn'); |
| const progressContainer = document.getElementById('progressContainer'); |
| const progressBar = document.getElementById('progressBar'); |
| const progressPercent = document.getElementById('progressPercent'); |
| const compressionLevel = document.getElementById('compressionLevel'); |
| const compressionValue = document.getElementById('compressionValue'); |
| const outputFormat = document.getElementById('outputFormat'); |
| const removeMetadata = document.getElementById('removeMetadata'); |
| const removeWatermark = document.getElementById('removeWatermark'); |
| const settingsToggle = document.getElementById('settingsToggle'); |
| const settingsPanel = document.getElementById('settingsPanel'); |
| const watermarkPreviewContainer = document.getElementById('watermarkPreviewContainer'); |
| const watermarkPreview = document.getElementById('watermarkPreview'); |
| const noImageSelected = document.getElementById('noImageSelected'); |
| const selectBtn = document.getElementById('selectBtn'); |
| const clearSelectionBtn = document.getElementById('clearSelectionBtn'); |
| const autoDetectBtn = document.getElementById('autoDetectBtn'); |
| const removalStrength = document.getElementById('removalStrength'); |
| const removalStrengthValue = document.getElementById('removalStrengthValue'); |
| const removeWatermarkBtn = document.getElementById('removeWatermarkBtn'); |
| const watermarkBox = document.getElementById('watermarkBox'); |
| const resultsSection = document.getElementById('resultsSection'); |
| const resultsGrid = document.getElementById('resultsGrid'); |
| const originalSize = document.getElementById('originalSize'); |
| const compressedSize = document.getElementById('compressedSize'); |
| const savings = document.getElementById('savings'); |
| const downloadAllBtn = document.getElementById('downloadAllBtn'); |
| const premiumBtn = document.getElementById('premium-btn'); |
| |
| |
| let selectedFiles = []; |
| let isSelectingWatermark = false; |
| let selectionStart = { x: 0, y: 0 }; |
| let currentImageForWatermark = null; |
| let processedFiles = []; |
| |
| |
| browseBtn.addEventListener('click', () => fileInput.click()); |
| fileInput.addEventListener('change', handleFileSelect); |
| dropzone.addEventListener('dragover', handleDragOver); |
| dropzone.addEventListener('dragleave', handleDragLeave); |
| dropzone.addEventListener('drop', handleDrop); |
| processBtn.addEventListener('click', processImages); |
| compressionLevel.addEventListener('input', updateCompressionValue); |
| settingsToggle.addEventListener('click', toggleSettingsPanel); |
| removalStrength.addEventListener('input', updateRemovalStrengthValue); |
| selectBtn.addEventListener('click', startWatermarkSelection); |
| clearSelectionBtn.addEventListener('click', clearWatermarkSelection); |
| autoDetectBtn.addEventListener('click', autoDetectWatermark); |
| removeWatermarkBtn.addEventListener('click', processWatermarkRemoval); |
| downloadAllBtn.addEventListener('click', downloadAllProcessedFiles); |
| premiumBtn.addEventListener('click', showPremiumModal); |
| |
| |
| watermarkPreview.addEventListener('mousedown', startSelection); |
| document.addEventListener('mousemove', updateSelection); |
| document.addEventListener('mouseup', endSelection); |
| |
| |
| function handleFileSelect(e) { |
| const files = e.target.files || e.dataTransfer.files; |
| addFilesToSelection(files); |
| } |
| |
| function handleDragOver(e) { |
| e.preventDefault(); |
| dropzone.classList.add('active'); |
| } |
| |
| function handleDragLeave() { |
| dropzone.classList.remove('active'); |
| } |
| |
| function handleDrop(e) { |
| e.preventDefault(); |
| dropzone.classList.remove('active'); |
| const files = e.dataTransfer.files; |
| addFilesToSelection(files); |
| } |
| |
| function addFilesToSelection(files) { |
| for (let i = 0; i < files.length; i++) { |
| if (files[i].type.match('image.*')) { |
| selectedFiles.push(files[i]); |
| } |
| } |
| |
| updateFileList(); |
| |
| if (selectedFiles.length > 0) { |
| fileInfo.classList.remove('hidden'); |
| processBtn.classList.remove('hidden'); |
| fileCount.textContent = `${selectedFiles.length} 个文件`; |
| |
| |
| if (!currentImageForWatermark) { |
| setImageForWatermarkRemoval(selectedFiles[0]); |
| } |
| } |
| } |
| |
| function updateFileList() { |
| fileList.innerHTML = ''; |
| selectedFiles.forEach((file, index) => { |
| const div = document.createElement('div'); |
| div.className = 'flex justify-between items-center py-2 border-b last:border-b-0'; |
| |
| const fileName = document.createElement('span'); |
| fileName.className = 'truncate'; |
| fileName.textContent = file.name; |
| |
| const fileSize = document.createElement('span'); |
| fileSize.className = 'text-gray-500 text-sm'; |
| fileSize.textContent = formatFileSize(file.size); |
| |
| const removeBtn = document.createElement('button'); |
| removeBtn.className = 'text-red-500 hover:text-red-700 ml-2'; |
| removeBtn.innerHTML = '<i class="fas fa-times"></i>'; |
| removeBtn.addEventListener('click', () => removeFile(index)); |
| |
| div.appendChild(fileName); |
| div.appendChild(fileSize); |
| div.appendChild(removeBtn); |
| fileList.appendChild(div); |
| }); |
| } |
| |
| function removeFile(index) { |
| selectedFiles.splice(index, 1); |
| updateFileList(); |
| fileCount.textContent = `${selectedFiles.length} 个文件`; |
| |
| if (selectedFiles.length === 0) { |
| fileInfo.classList.add('hidden'); |
| processBtn.classList.add('hidden'); |
| watermarkPreviewContainer.classList.add('hidden'); |
| noImageSelected.classList.remove('hidden'); |
| currentImageForWatermark = null; |
| } else if (index === 0) { |
| setImageForWatermarkRemoval(selectedFiles[0]); |
| } |
| } |
| |
| function formatFileSize(bytes) { |
| if (bytes === 0) return '0 字节'; |
| const k = 1024; |
| const sizes = ['字节', 'KB', 'MB', 'GB']; |
| const i = Math.floor(Math.log(bytes) / Math.log(k)); |
| return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; |
| } |
| |
| function updateCompressionValue() { |
| compressionValue.textContent = `${compressionLevel.value}%`; |
| } |
| |
| function updateRemovalStrengthValue() { |
| removalStrengthValue.textContent = removalStrength.value; |
| } |
| |
| function toggleSettingsPanel() { |
| settingsPanel.classList.toggle('open'); |
| const icon = settingsToggle.querySelector('i'); |
| icon.classList.toggle('fa-chevron-down'); |
| icon.classList.toggle('fa-chevron-up'); |
| } |
| |
| function processImages() { |
| if (selectedFiles.length === 0) return; |
| |
| progressContainer.classList.remove('hidden'); |
| processBtn.classList.add('hidden'); |
| |
| let processedCount = 0; |
| processedFiles = []; |
| |
| |
| selectedFiles.forEach((file, index) => { |
| setTimeout(() => { |
| |
| simulateProgress(index, () => { |
| processedCount++; |
| |
| |
| const originalSize = file.size; |
| const compressionRatio = parseInt(compressionLevel.value) / 100; |
| const compressedSize = Math.max(1000, originalSize * compressionRatio); |
| |
| |
| const result = { |
| originalFile: file, |
| compressedFile: new File([file], `压缩_${file.name}`, { type: file.type }), |
| originalSize, |
| compressedSize, |
| downloadUrl: URL.createObjectURL(file) |
| }; |
| |
| processedFiles.push(result); |
| |
| |
| const progress = Math.round((processedCount / selectedFiles.length) * 100); |
| progressBar.style.width = `${progress}%`; |
| progressPercent.textContent = `${progress}%`; |
| |
| |
| if (processedCount === selectedFiles.length) { |
| setTimeout(showResults, 500); |
| } |
| }); |
| }, index * 500); |
| }); |
| } |
| |
| function simulateProgress(index, callback) { |
| let progress = 0; |
| const interval = setInterval(() => { |
| progress += 5; |
| const overallProgress = Math.min(100, ((index * 100) + progress) / selectedFiles.length); |
| progressBar.style.width = `${overallProgress}%`; |
| progressPercent.textContent = `${Math.round(overallProgress)}%`; |
| |
| if (progress >= 100) { |
| clearInterval(interval); |
| callback(); |
| } |
| }, 100); |
| } |
| |
| function showResults() { |
| progressContainer.classList.add('hidden'); |
| resultsSection.classList.remove('hidden'); |
| |
| |
| const totalOriginal = processedFiles.reduce((sum, file) => sum + file.originalSize, 0); |
| const totalCompressed = processedFiles.reduce((sum, file) => sum + file.compressedSize, 0); |
| const savingsPercentage = ((totalOriginal - totalCompressed) / totalOriginal * 100).toFixed(1); |
| |
| originalSize.textContent = formatFileSize(totalOriginal); |
| compressedSize.textContent = formatFileSize(totalCompressed); |
| savings.textContent = `${savingsPercentage}% (${formatFileSize(totalOriginal - totalCompressed)})`; |
| |
| |
| resultsGrid.innerHTML = ''; |
| processedFiles.forEach((file, index) => { |
| const reader = new FileReader(); |
| reader.onload = (e) => { |
| const resultCard = document.createElement('div'); |
| resultCard.className = 'bg-gray-50 rounded-lg overflow-hidden border'; |
| |
| const imgContainer = document.createElement('div'); |
| imgContainer.className = 'relative pt-[100%]'; |
| |
| const img = document.createElement('img'); |
| img.src = e.target.result; |
| img.className = 'absolute top-0 left-0 w-full h-full object-cover'; |
| |
| const infoContainer = document.createElement('div'); |
| infoContainer.className = 'p-3'; |
| |
| const fileName = document.createElement('div'); |
| fileName.className = 'font-medium truncate mb-1'; |
| fileName.textContent = file.originalFile.name; |
| |
| const sizeInfo = document.createElement('div'); |
| sizeInfo.className = 'flex justify-between text-sm text-gray-600 mb-2'; |
| |
| const originalSizeSpan = document.createElement('span'); |
| originalSizeSpan.textContent = formatFileSize(file.originalSize); |
| |
| const compressedSizeSpan = document.createElement('span'); |
| compressedSizeSpan.className = 'text-green-600 font-medium'; |
| compressedSizeSpan.textContent = formatFileSize(file.compressedSize); |
| |
| sizeInfo.appendChild(originalSizeSpan); |
| sizeInfo.appendChild(compressedSizeSpan); |
| |
| const downloadBtn = document.createElement('button'); |
| downloadBtn.className = 'w-full bg-indigo-500 hover:bg-indigo-600 text-white py-2 rounded text-sm transition flex items-center justify-center'; |
| downloadBtn.innerHTML = '<i class="fas fa-download mr-2"></i> 下载'; |
| downloadBtn.addEventListener('click', () => downloadFile(file)); |
| |
| infoContainer.appendChild(fileName); |
| infoContainer.appendChild(sizeInfo); |
| infoContainer.appendChild(downloadBtn); |
| |
| imgContainer.appendChild(img); |
| resultCard.appendChild(imgContainer); |
| resultCard.appendChild(infoContainer); |
| |
| resultsGrid.appendChild(resultCard); |
| }; |
| reader.readAsDataURL(file.originalFile); |
| }); |
| } |
| |
| function downloadFile(file) { |
| const a = document.createElement('a'); |
| a.href = file.downloadUrl; |
| a.download = file.compressedFile.name; |
| document.body.appendChild(a); |
| a.click(); |
| document.body.removeChild(a); |
| } |
| |
| function downloadAllProcessedFiles() { |
| processedFiles.forEach((file, index) => { |
| setTimeout(() => { |
| downloadFile(file); |
| }, index * 500); |
| }); |
| } |
| |
| function setImageForWatermarkRemoval(file) { |
| const reader = new FileReader(); |
| reader.onload = (e) => { |
| watermarkPreview.src = e.target.result; |
| watermarkPreviewContainer.classList.remove('hidden'); |
| noImageSelected.classList.add('hidden'); |
| currentImageForWatermark = file; |
| clearWatermarkSelection(); |
| }; |
| reader.readAsDataURL(file); |
| } |
| |
| function startWatermarkSelection() { |
| isSelectingWatermark = true; |
| watermarkBox.classList.remove('hidden'); |
| selectBtn.classList.add('bg-indigo-600'); |
| } |
| |
| function clearWatermarkSelection() { |
| watermarkBox.classList.add('hidden'); |
| watermarkBox.style.width = '0'; |
| watermarkBox.style.height = '0'; |
| selectBtn.classList.remove('bg-indigo-600'); |
| isSelectingWatermark = false; |
| } |
| |
| function startSelection(e) { |
| if (!isSelectingWatermark) return; |
| |
| e.preventDefault(); |
| const rect = watermarkPreview.getBoundingClientRect(); |
| selectionStart = { |
| x: e.clientX - rect.left, |
| y: e.clientY - rect.top |
| }; |
| |
| watermarkBox.style.left = `${selectionStart.x}px`; |
| watermarkBox.style.top = `${selectionStart.y}px`; |
| watermarkBox.style.width = '0'; |
| watermarkBox.style.height = '0'; |
| } |
| |
| function updateSelection(e) { |
| if (!isSelectingWatermark || !selectionStart) return; |
| |
| const rect = watermarkPreview.getBoundingClientRect(); |
| const currentX = e.clientX - rect.left; |
| const currentY = e.clientY - rect.top; |
| |
| const width = currentX - selectionStart.x; |
| const height = currentY - selectionStart.y; |
| |
| watermarkBox.style.width = `${Math.abs(width)}px`; |
| watermarkBox.style.height = `${Math.abs(height)}px`; |
| |
| if (width < 0) { |
| watermarkBox.style.left = `${currentX}px`; |
| } |
| if (height < 0) { |
| watermarkBox.style.top = `${currentY}px`; |
| } |
| } |
| |
| function endSelection() { |
| if (!isSelectingWatermark) return; |
| isSelectingWatermark = false; |
| selectBtn.classList.remove('bg-indigo-600'); |
| } |
| |
| function autoDetectWatermark() { |
| |
| watermarkBox.classList.remove('hidden'); |
| |
| |
| const rect = watermarkPreview.getBoundingClientRect(); |
| const width = Math.min(100, rect.width * 0.3); |
| const height = Math.min(50, rect.height * 0.1); |
| const left = Math.random() * (rect.width - width); |
| const top = rect.height - height - 10; |
| |
| watermarkBox.style.left = `${left}px`; |
| watermarkBox.style.top = `${top}px`; |
| watermarkBox.style.width = `${width}px`; |
| watermarkBox.style.height = `${height}px`; |
| |
| |
| const originalText = autoDetectBtn.innerHTML; |
| autoDetectBtn.innerHTML = '<i class="fas fa-check mr-1"></i> 已检测!'; |
| autoDetectBtn.classList.remove('bg-purple-500'); |
| autoDetectBtn.classList.add('bg-green-500'); |
| |
| setTimeout(() => { |
| autoDetectBtn.innerHTML = originalText; |
| autoDetectBtn.classList.add('bg-purple-500'); |
| autoDetectBtn.classList.remove('bg-green-500'); |
| }, 2000); |
| } |
| |
| function processWatermarkRemoval() { |
| if (!watermarkBox || watermarkBox.classList.contains('hidden')) { |
| alert('请先选择水印区域'); |
| return; |
| } |
| |
| |
| removeWatermarkBtn.disabled = true; |
| removeWatermarkBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> 处理中...'; |
| |
| setTimeout(() => { |
| |
| |
| removeWatermarkBtn.innerHTML = '<i class="fas fa-check mr-2"></i> 水印已去除!'; |
| removeWatermarkBtn.classList.remove('bg-red-500'); |
| removeWatermarkBtn.classList.add('bg-green-500'); |
| |
| setTimeout(() => { |
| removeWatermarkBtn.innerHTML = '<i class="fas fa-trash-alt mr-2"></i> 去除水印'; |
| removeWatermarkBtn.classList.add('bg-red-500'); |
| removeWatermarkBtn.classList.remove('bg-green-500'); |
| removeWatermarkBtn.disabled = false; |
| }, 2000); |
| }, 2000); |
| } |
| |
| function showPremiumModal() { |
| |
| const modal = document.createElement('div'); |
| modal.className = 'fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50'; |
| modal.innerHTML = ` |
| <div class="bg-white rounded-xl p-6 max-w-md w-full mx-4"> |
| <div class="flex justify-between items-center mb-4"> |
| <h3 class="text-xl font-bold text-indigo-600">升级专业版</h3> |
| <button id="closeModal" class="text-gray-500 hover:text-gray-700"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| <div class="mb-6"> |
| <div class="bg-indigo-50 rounded-lg p-4 mb-4"> |
| <div class="flex items-center mb-2"> |
| <i class="fas fa-check-circle text-green-500 mr-2"></i> |
| <span>自动去除所有水印</span> |
| </div> |
| <div class="flex items-center mb-2"> |
| <i class="fas fa-check-circle text-green-500 mr-2"></i> |
| <span>批量处理无限图片</span> |
| </div> |
| <div class="flex items-center"> |
| <i class="fas fa-check-circle text-green-500 mr-2"></i> |
| <span>优先技术支持</span> |
| </div> |
| </div> |
| <div class="text-center py-4"> |
| <p class="text-3xl font-bold text-gray-800 mb-2">¥9.99<span class="text-lg text-gray-600">/月</span></p> |
| <p class="text-gray-600">或 ¥99.99/年 (节省20%)</p> |
| </div> |
| </div> |
| <button id="upgradeBtn" class="w-full bg-gradient-to-r from-purple-500 to-indigo-600 text-white py-3 rounded-lg font-medium hover:opacity-90 transition flex items-center justify-center"> |
| <i class="fas fa-crown mr-2"></i> |
| 立即升级 |
| </button> |
| </div> |
| `; |
| |
| document.body.appendChild(modal); |
| |
| |
| modal.querySelector('#closeModal').addEventListener('click', () => { |
| modal.remove(); |
| }); |
| |
| modal.querySelector('#upgradeBtn').addEventListener('click', () => { |
| alert('感谢选择专业版! 正在跳转支付...'); |
| modal.remove(); |
| }); |
| |
| |
| modal.addEventListener('click', (e) => { |
| if (e.target === modal) { |
| modal.remove(); |
| } |
| }); |
| } |
| |
| |
| updateCompressionValue(); |
| updateRemovalStrengthValue(); |
| </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 <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=raineye/ds" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |